4 Base classes for the external programs API.
14 Abstraction of the API class for the transcoder program.
23 # Recommended formats.
32 # File extensions by container. First value is for audio files and the
33 # second one is for (audio-)video files.
35 "avi": ["avi", "avi"],
36 "flv": ["flv", "flv"],
37 "mp4": ["mp4", "mp4"],
38 "ogg": ["oga", "ogv"],
39 "webm": ["webm", "webm"],
40 "mpegts": ["mts", "mts"]
52 def __init__(self, input_file, name=None, prog_bin=None):
53 self.input_file = input_file
54 if prog_bin is not None:
55 self.prog_bin = prog_bin
58 name = cis_util.get_name(input_file)
62 def transcode(self, container, a_codec=None, v_codec=None,
63 a_bitrate=None, a_samplingrate=None, a_channels=None,
64 v_bitrate=None, v_framerate=None, v_resolution=None, v_dar=None):
66 Transcodes the input file to an audio-video file.
68 container: possible values are listed in containers member as keys
69 a_codec: possible values are listed in a_codecs member as keys
70 v_codec: possible values are listed in v_codecs member as keys
71 a_bitrate: (numeric) audio bit rate
72 a_samplingrate: (numeric) audio sampling rate in Hz
73 a_channels: (numeric) number of audio channels
74 v_bitrate: (numeric) video bit rate
75 v_framerate: (numeric) number of frames per second for a video
76 v_resolution: (string) video image size as <width>x<height>
77 v_dar: video display aspect ratio as <den>x<num> or float
81 if a_codec is None and v_codec is None:
82 raise ValueError('No audio or video codec specified.')
84 if a_codec is not None and type(a_codec) is not str:
85 raise TypeError('Audio codec must be string.')
87 if v_codec is not None and type(v_codec) is not str:
88 raise TypeError('Video codec must be string.')
90 if a_samplingrate is not None and type(a_samplingrate) is not int:
91 raise TypeError('Audio sampling rate must be an integer.')
93 if a_channels is not None and type(a_channels) is not int:
94 raise TypeError('Audio channels parameter must be an integer.')
96 if v_framerate is not None and type(v_framerate) is not int:
97 raise TypeError('Video frate rate must be an integer.')
99 if v_resolution is not None \
100 and re.match('[\d]+x[\d]+', v_resolution) is None:
101 raise ValueError('Video resolution must be a string like <width>x<height>.')
103 if v_dar is not None and (type(v_dar) is not float \
104 and re.match('[\d]+:[\d]+', v_dar) is None):
105 raise ValueError('Video display aspect ratio must be a float or a string like <den>:<num>.')
107 self.output_file = self.dest_path + self.name
108 if v_resolution is not None:
109 self.output_file += '_'
110 self.output_file += v_resolution[(v_resolution.rindex('x')+1):]
111 self.output_file += 'p'
112 ext = self.tr_extension(container, (v_codec is not None))
114 self.output_file += '.' + ext
116 self._transcode(self.tr_container(container),
117 self.tr_a_codec(a_codec), self.tr_v_codec(v_codec),
118 a_bitrate, a_samplingrate, a_channels,
119 v_bitrate, v_framerate, v_resolution, v_dar)
121 def _transcode(self, container, a_codec=None, v_codec=None,
122 a_bitrate=None, a_samplingrate=None, a_channels=None,
123 v_bitrate=None, v_framerate=None, v_resolution=None, v_dar=None):
125 Called by transcode; must be overridden by a child class which
126 effectively transcodes the input file.
130 def tr_container(self, name):
131 """ Translates container API name into external program identifier."""
133 if not self.containers.has_key(name) or self.containers[name] is None:
134 raise cis_exceptions.NotImplementedException("Container " + name)
136 return self.containers[name]
138 def tr_extension(self, name, video=True):
139 """ Translates container API name into file extension."""
146 if not self.extensions.has_key(name) or self.extensions[name] is None:
149 return self.extensions[name][i]
151 def tr_a_codec(self, name):
152 """ Translates audio codec API name into external program identifier."""
154 if not self.a_codecs.has_key(name) or self.a_codecs[name] is None:
155 raise cis_exceptions.NotImplementedException("Audio Codec " + name)
157 return self.a_codecs[name]
159 def tr_v_codec(self, name):
160 """ Translates video codec API name into external program identifier."""
162 if not self.v_codecs.has_key(name) or self.v_codecs[name] is None:
163 raise cis_exceptions.NotImplementedException("Video Codec " + name)
165 return self.v_codecs[name]
168 class BaseThumbExtractor:
170 Abstraction of the API class for the thumbnail extraction program.
172 Thumbnail extracted are in JPEG format.
180 def __init__(self, input_file, name=None, prog_bin=None):
181 self.input_file = input_file
182 if prog_bin is not None:
183 self.prog_bin = prog_bin
186 name = cis_util.get_name(input_file)
190 def extract_thumb(self, seek_pos, resolution="120x90", index=0):
192 Extracts a thumbnail from the video from a specified position
193 expressed in seconds (int/float).
195 index: an index appended to the image name in order to avoid
200 def extract_random_thumb(self, resolution="120x90", index=0):
202 Extracts a thumbnail from the video from a random position.
204 duration = self.get_video_duration()
205 seek_pos = random.random() * duration
206 self.extract_thumb(seek_pos, resolution, index)
208 def extract_summary_thumbs(self, count, resolution="120x90"):
210 Extracts a series of thumbnails from a video by taking several
213 The snapshots are taken from equally spaced positions such that
214 `count` thumbs are extracted.
216 duration = self.get_video_duration()
217 interval = duration / (count + 1)
219 n_thumbs_extracted = 0
221 for index in range (0, count):
222 thumb_extracted = True
224 self.extract_thumb(seek_pos, resolution, index)
225 except cis_exceptions.ThumbExtractionException as e:
226 thumb_extracted = False
229 n_thumbs_extracted += 1
233 return n_thumbs_extracted
235 def get_video_duration(self):
237 Returns the number of seconds of a video (int/float).
241 def get_output_file_name(self, index):
242 """ Returns the name required as output file name based on index. """
243 output_file_name = self.dest_path + self.name \
244 + '_t' + ("%02d" % index) + '.jpg'
245 return output_file_name