~ubuntu-branches/ubuntu/karmic/tovid/karmic

« back to all changes in this revision

Viewing changes to libtovid/stats.py

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev
  • Date: 2008-01-24 22:04:40 UTC
  • Revision ID: james.westby@ubuntu.com-20080124220440-x7cheljduf1rdgnq
Tags: upstream-0.31
ImportĀ upstreamĀ versionĀ 0.31

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
# stats.py
 
3
 
 
4
"""Classes and functions for dealing with video statistics.
 
5
 
 
6
Future interface ideas:
 
7
 
 
8
* Display certain records, or a range of records (records 1-10; last 15 records;
 
9
  records with a certain field (or any field) matching given text/regexp
 
10
* Display formatted output of all records, or a selection of records,
 
11
  with control over which fields are displayed
 
12
 
 
13
"""
 
14
 
 
15
import csv
 
16
import sys
 
17
from copy import copy
 
18
 
 
19
# Order of fields in stats.tovid
 
20
FIELDS = [\
 
21
    'tovid_version',
 
22
    'final_name',
 
23
    'length',          # a.k.a. CUR_LENGTH
 
24
    'format',          # RES
 
25
    'tvsys',
 
26
    'final_size',
 
27
    'tgt_bitrate',
 
28
    'avg_bitrate',
 
29
    'peak_bitrate',
 
30
    'gop_minsize',
 
31
    'gop_maxsize',
 
32
    'encoding_time',   # SCRIPT_TOT_TIME
 
33
    'cpu_model',
 
34
    'cpu_speed',
 
35
    'in_vcodec',
 
36
    'in_acodec',
 
37
    'encoding_mode',
 
38
    'in_md5',
 
39
    'in_width',
 
40
    'in_height',
 
41
    'quant',
 
42
    'kbpm',
 
43
    'enc_time_ratio',
 
44
    'backend'
 
45
    ]
 
46
 
 
47
# Integer numeric fields
 
48
int_fields = [\
 
49
    'length',
 
50
    'avg_bitrate',
 
51
    'tgt_bitrate',
 
52
    'peak_bitrate',
 
53
    'encoding_time',
 
54
    'final_size',
 
55
    'cpu_speed',
 
56
    'in_width',
 
57
    'in_height',
 
58
    'quant',
 
59
    'kbpm'
 
60
    ]
 
61
 
 
62
class Statlist:
 
63
    """A list of statistics that may be queried with a simple database-like
 
64
    interface."""
 
65
    def __init__(self, records=None, filename=''):
 
66
        """Create a Statlist, using the given list of records, or by reading
 
67
        from the given filename (CSV text).
 
68
        """
 
69
        # Use provided records, if any
 
70
        if records:
 
71
            self.records = copy(records)
 
72
        # Otherwise, read from any provided filename
 
73
        else:
 
74
            self.records = []
 
75
            if filename is not '':
 
76
                self.read_csv(filename)
 
77
 
 
78
    def read_csv(self, filename):
 
79
        """Import stats from a CSV (comma-delimited quoted text) file."""
 
80
        self.records = []
 
81
        statfile = open(filename, 'r')
 
82
        csv_reader = csv.DictReader(statfile, FIELDS, skipinitialspace=True)
 
83
        for line in csv_reader:
 
84
            # Convert some string and numeric fields
 
85
            line['format'] = str.lower("%s" % line['format'])
 
86
            line['tvsys'] = str.lower("%s" % line['tvsys'])
 
87
            for field in int_fields:
 
88
                try:
 
89
                    num = int("%s" % line[field])
 
90
                except ValueError, TypeError:
 
91
                    num = 0
 
92
                line[field] = num
 
93
            self.records.append(line)
 
94
 
 
95
        statfile.close()
 
96
        print "Read %s lines from %s" % (len(self.records), filename)
 
97
 
 
98
    def unique(self, field):
 
99
        """Return a list of unique values of the given field."""
 
100
        unique_values = []
 
101
        for record in self.records:
 
102
            if record[field] not in unique_values:
 
103
                unique_values.append(record[field])
 
104
        return unique_values
 
105
 
 
106
    def count_unique(self, field):
 
107
        """Count the occurrences of each unique value of the given field.
 
108
        Return a dictionary of unique values and the number of occurrences
 
109
        of each."""
 
110
        counts = {}
 
111
        # Go through all records and total up occurrences of each value
 
112
        for record in self.records:
 
113
            value = record[field]
 
114
            if value is None or value == '':
 
115
                pass
 
116
            elif value not in counts:
 
117
                counts[value] = 1
 
118
            else:
 
119
                counts[value] += 1
 
120
        return counts
 
121
        
 
122
    def average(self, attribute):
 
123
        """Calculate the average value for a given numeric VidStat attribute.
 
124
        For example, average('bitrate') returns the average overall bitrate of
 
125
        all videos in the list."""
 
126
        # Error if attribute is non-numeric
 
127
        if attribute not in int_fields:
 
128
            print "Can't average %s: not defined as a numeric field"
 
129
            sys.exit()
 
130
            
 
131
        values = []
 
132
        for record in self.records:
 
133
            # Only append non-zero values
 
134
            if record[attribute] != 0:
 
135
                values.append(record[attribute])
 
136
        if len(values) > 0:
 
137
            return float(sum(values) / len(values))
 
138
        else:
 
139
            return 0
 
140
 
 
141
    def average_by(self, attribute, by_attribute):
 
142
        """Return a dictionary of averages of an attribute, indexed by another
 
143
        attribute. For example, average_by('bitrate', 'format') returns average
 
144
        bitrates for each format."""
 
145
        # Error if attribute is non-numeric
 
146
        if attribute not in int_fields:
 
147
            print "Can't average %s: not defined as a numeric field"
 
148
            sys.exit()
 
149
 
 
150
        values_by = self.list_by(attribute, by_attribute)
 
151
        # Calculate averages for each value-list
 
152
        averages = {}
 
153
        if len(values_by) > 0:
 
154
            for key, samples in values_by.iteritems():
 
155
                try:
 
156
                    averages[key] = float(sum(samples) / len(samples))
 
157
                except ZeroDivisionError:
 
158
                    averages[key] = 0.0
 
159
        return averages
 
160
 
 
161
    def list_by(self, attribute, by_attribute, sort_lists=False):
 
162
        """Return a dictionary of lists of values of the given attribute,
 
163
        indexed by another attribute. If sort_lists is True, sort all lists."""
 
164
        # Create a dictionary of value-lists, indexed by by_attribute
 
165
        values_by = {}        
 
166
        for record in self.records:
 
167
            byval = record[by_attribute]
 
168
            if not values_by.has_key(byval):
 
169
                values_by[byval] = []
 
170
            # Only include non-zero values
 
171
            if record[attribute] != 0:
 
172
                values_by[byval].append(record[attribute])
 
173
        if sort_lists:
 
174
            for index in values_by.iterkeys():
 
175
                values_by[index].sort()
 
176
        return values_by
 
177
    
 
178
    def get_matching(self, attribute, value):
 
179
        """Return a list of records where the given attribute equals the given
 
180
        value. Records are field-indexed dictionaries of values.
 
181
        """
 
182
        # List of matching records
 
183
        matches = []
 
184
        for record in self.records:
 
185
            if record[attribute] == value:
 
186
                matches.append(record)
 
187
        return matches
 
188
    
 
189
    def length(self, field):
 
190
        """Return the length of the longest record in the given field, or the
 
191
        width of the field name itself, whichever is greater."""
 
192
        longest = len(field)
 
193
        for record in self.records:
 
194
            cur_len = len(str(record[field]))
 
195
            if cur_len > longest:
 
196
                longest = cur_len
 
197
        return longest
 
198
    
 
199
    def show(self, show_records='all', show_fields=FIELDS):
 
200
        """Print records matching given criteria, showing only the given fields.
 
201
        
 
202
            show_records:   Number of record to show, or range of numbers
 
203
            show_fields:    List of fields, by name as shown in FIELDS
 
204
        """
 
205
        # Remember field sizes (character widths)
 
206
        size = {}
 
207
        # Create field headings
 
208
        heading = ''
 
209
        for field in show_fields:
 
210
            if field in FIELDS:
 
211
                size[field] = self.length(field)
 
212
                heading += "%s " % str.ljust(field, size[field])
 
213
            else:
 
214
                print "Error: field '%s' does not exist" % field
 
215
                sys.exit()
 
216
        print heading
 
217
        # Print fields from matching records
 
218
        for record in self.records:
 
219
            # TODO: support show_records
 
220
            line = ''
 
221
            for field in show_fields:
 
222
                line += "%s " % str.ljust(str(record[field]), size[field])
 
223
            print line
 
224
        # Print heading at end too
 
225
        print heading
 
226
 
 
 
b'\\ No newline at end of file'