4 Base classes for the external programs API.
16 Abstraction of the API class for the transcoder program.
25 # Recommended formats.
34 # File extensions by container. First value is for audio files and the
35 # second one is for (audio-)video files.
37 "avi": ["avi", "avi"],
38 "flv": ["flv", "flv"],
39 "mp4": ["mp4", "mp4"],
40 "ogg": ["oga", "ogv"],
41 "webm": ["webm", "webm"],
42 "mpegts": ["mts", "mts"]
54 def __init__(self, input_file, name=None, prog_bin=None):
55 self.input_file = input_file
56 if prog_bin is not None:
57 self.prog_bin = prog_bin
60 name = cis_util.get_name(input_file)
64 def transcode(self, container, a_codec=None, v_codec=None,
65 a_bitrate=None, a_samplingrate=None, a_channels=None,
66 v_bitrate=None, v_framerate=None, v_resolution=None, v_dar=None):
68 Transcodes the input file to an audio-video file.
70 @param container: possible values are listed in containers member
72 @param a_codec possible values are listed in a_codecs member as keys
73 @param v_codec possible values are listed in v_codecs member as keys
74 @param a_bitrate (numeric) audio bit rate
75 @param a_samplingrate (numeric) audio sampling rate in Hz
76 @param a_channels (numeric) number of audio channels
77 @param v_bitrate (numeric) video bit rate
78 @param v_framerate (numeric) number of frames per second for a video
79 @param v_resolution (string) video image size as <width>x<height>
80 @param v_dar video display aspect ratio as <den>x<num> or float
81 @return output file name
85 if a_codec is None and v_codec is None:
86 raise ValueError('No audio or video codec specified.')
88 if a_codec is not None and type(a_codec) not in [str, unicode]:
89 raise TypeError('Audio codec must be string.')
91 if v_codec is not None and type(v_codec) not in [str, unicode]:
92 raise TypeError('Video codec must be string.')
94 if a_samplingrate is not None and type(a_samplingrate) is not int:
95 raise TypeError('Audio sampling rate must be an integer.')
97 if a_channels is not None and type(a_channels) is not int:
98 raise TypeError('Audio channels parameter must be an integer.')
100 if v_framerate is not None and type(v_framerate) is not int:
101 raise TypeError('Video frate rate must be an integer.')
103 if v_resolution is not None \
104 and re.match('[\d]+x[\d]+', v_resolution) is None:
105 raise ValueError('Video resolution must be a string like <width>x<height>.')
107 if v_dar is not None and (type(v_dar) is not float \
108 and re.match('[\d]+:[\d]+', v_dar) is None):
109 raise ValueError('Video display aspect ratio must be a float or a string like <den>:<num>.')
111 self.output_file = os.path.join(self.dest_path, self.name)
112 if os.path.exists(self.output_file):
113 raise cis_exceptions.FileAlreadyExistsException( \
114 'file "%s" already exists' % self.output_file)
116 if v_resolution is not None:
117 self.output_file += '_'
118 self.output_file += v_resolution[(v_resolution.rindex('x')+1):]
119 self.output_file += 'p'
120 ext = self.tr_extension(container, (v_codec is not None))
122 self.output_file += '.' + ext
124 return self._transcode(self.tr_container(container),
125 self.tr_a_codec(a_codec), self.tr_v_codec(v_codec),
126 a_bitrate, a_samplingrate, a_channels,
127 v_bitrate, v_framerate, v_resolution, v_dar)
129 def _transcode(self, container, a_codec=None, v_codec=None,
130 a_bitrate=None, a_samplingrate=None, a_channels=None,
131 v_bitrate=None, v_framerate=None, v_resolution=None, v_dar=None):
133 Called by transcode; must be overridden by a child class which
134 effectively transcodes the input file.
136 @return output file name
140 def tr_container(self, name):
141 """ Translates container API name into external program identifier."""
143 if not self.containers.has_key(name) or self.containers[name] is None:
144 raise cis_exceptions.NotImplementedException("Container " + name \
147 return self.containers[name]
149 def tr_extension(self, name, video=True):
150 """ Translates container API name into file extension."""
157 if not self.extensions.has_key(name) or self.extensions[name] is None:
160 return self.extensions[name][i]
162 def tr_a_codec(self, name):
163 """ Translates audio codec API name into external program identifier."""
165 if not self.a_codecs.has_key(name) or self.a_codecs[name] is None:
166 raise cis_exceptions.NotImplementedException("Audio Codec " + name \
169 return self.a_codecs[name]
171 def tr_v_codec(self, name):
172 """ Translates video codec API name into external program identifier."""
174 if not self.v_codecs.has_key(name) or self.v_codecs[name] is None:
175 raise cis_exceptions.NotImplementedException("Video Codec " + name \
178 return self.v_codecs[name]
181 class BaseThumbExtractor:
183 Abstraction of the API class for the thumbnail extraction program.
185 Thumbnail extracted are in JPEG format.
193 def __init__(self, input_file, name=None, prog_bin=None):
194 self.input_file = input_file
195 if prog_bin is not None:
196 self.prog_bin = prog_bin
199 name = cis_util.get_name(input_file)
203 def extract_thumb(self, seek_pos, resolution="120x90", index=0):
205 Extracts a thumbnail from the video from a specified position
206 expressed in seconds (int/float).
208 index: an index appended to the image name in order to avoid
213 def extract_random_thumb(self, resolution="120x90", index=0):
215 Extracts a thumbnail from the video from a random position.
217 duration = self.get_video_duration()
218 seek_pos = random.random() * duration
219 self.extract_thumb(seek_pos, resolution, index)
221 def extract_summary_thumbs(self, count, resolution="120x90"):
223 Extracts a series of thumbnails from a video by taking several
226 The snapshots are taken from equally spaced positions such that
227 `count` thumbs are extracted.
229 duration = self.get_video_duration()
230 interval = duration / (count + 1)
232 n_thumbs_extracted = 0
234 for index in range (0, count):
235 thumb_extracted = True
237 self.extract_thumb(seek_pos, resolution, n_thumbs_extracted)
238 except cis_exceptions.ThumbExtractionException as e:
239 thumb_extracted = False
242 n_thumbs_extracted += 1
246 return n_thumbs_extracted
248 def get_output_file_name(self, index):
249 """ Returns the name required as output file name based on index. """
250 output_file_name = os.path.join(self.dest_path, self.name) \
251 + '_t' + ("%02d" % index) + '.jpg'
253 if os.path.exists(output_file_name):
254 raise cis_exceptions.FileAlreadyExistsException( \
255 'file "%s" already exists' % output_file_name)
257 return output_file_name
259 def get_video_duration(self):
263 class BaseFileTransferer:
265 Ensures file transfer from the Web Server to the CIS (here).
267 Several implementations can be done by extending this class for
268 file transfer protocol such as FTP, SCP, RSYNC, HTTP etc.
274 def __init__(self, local_path='', remote_path=''):
275 """ Initialize by setting local and remote paths for file transfer. """
276 self.local_path = local_path
277 self.remote_path = remote_path
282 def get(self, files):
284 Transfers files locally from the Web Server.
286 files: a list of file name strings
290 def put(self, files):
292 Transfers files from the Web Server locally.
294 files: a list of file name strings
300 This method should be called when the instance is no longer required.
302 Class's destructor calls this method.
309 def get_video_duration(input_file, formated=False):
311 Returns the number of seconds of a video (int/float) if formated is
312 False and a string for duration formated as [HH:]:mm:ss otherwise.