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, extension=None, 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 if extension == None:
121 ext = self.tr_extension(container, (v_codec is not None))
125 self.output_file += '.' + ext
127 return self._transcode(self.tr_container(container), ext,
128 self.tr_a_codec(a_codec), self.tr_v_codec(v_codec),
129 a_bitrate, a_samplingrate, a_channels,
130 v_bitrate, v_framerate, v_resolution, v_dar)
132 def _transcode(self, container, extension=None, a_codec=None, v_codec=None,
133 a_bitrate=None, a_samplingrate=None, a_channels=None,
134 v_bitrate=None, v_framerate=None, v_resolution=None, v_dar=None):
136 Called by transcode; must be overridden by a child class which
137 effectively transcodes the input file.
139 @return output file name
143 def tr_container(self, name):
144 """ Translates container API name into external program identifier."""
146 if not self.containers.has_key(name) or self.containers[name] is None:
147 raise cis_exceptions.NotImplementedException("Container " + name \
150 return self.containers[name]
152 def tr_extension(self, name, video=True):
153 """ Translates container API name into file extension."""
160 if not self.extensions.has_key(name) or self.extensions[name] is None:
163 return self.extensions[name][i]
165 def tr_a_codec(self, name):
166 """ Translates audio codec API name into external program identifier."""
168 if not self.a_codecs.has_key(name) or self.a_codecs[name] is None:
169 raise cis_exceptions.NotImplementedException("Audio Codec " + name \
172 return self.a_codecs[name]
174 def tr_v_codec(self, name):
175 """ Translates video codec API name into external program identifier."""
177 if not self.v_codecs.has_key(name) or self.v_codecs[name] is None:
178 raise cis_exceptions.NotImplementedException("Video Codec " + name \
181 return self.v_codecs[name]
184 class BaseThumbExtractor:
186 Abstraction of the API class for the thumbnail extraction program.
188 Thumbnail extracted are in JPEG format.
196 def __init__(self, input_file, name=None, prog_bin=None):
197 self.input_file = input_file
198 if prog_bin is not None:
199 self.prog_bin = prog_bin
202 name = cis_util.get_name(input_file)
206 def extract_thumb(self, seek_pos, resolution="120x90", index=0):
208 Extracts a thumbnail from the video from a specified position
209 expressed in seconds (int/float).
211 index: an index appended to the image name in order to avoid
216 def extract_random_thumb(self, resolution="120x90", index=0):
218 Extracts a thumbnail from the video from a random position.
220 duration = self.get_video_duration()
221 seek_pos = random.random() * duration
222 self.extract_thumb(seek_pos, resolution, index)
224 def extract_summary_thumbs(self, count, resolution="120x90"):
226 Extracts a series of thumbnails from a video by taking several
229 The snapshots are taken from equally spaced positions such that
230 `count` thumbs are extracted.
232 duration = self.get_video_duration()
233 interval = duration / (count + 1)
235 n_thumbs_extracted = 0
237 for index in range (0, count):
238 thumb_extracted = True
240 self.extract_thumb(seek_pos, resolution, n_thumbs_extracted)
241 except cis_exceptions.ThumbExtractionException as e:
242 thumb_extracted = False
245 n_thumbs_extracted += 1
249 return n_thumbs_extracted
251 def get_output_file_name(self, index):
252 """ Returns the name required as output file name based on index. """
253 output_file_name = os.path.join(self.dest_path, self.name) \
254 + '_t' + ("%02d" % index) + '.jpg'
256 #if os.path.exists(output_file_name):
257 #raise cis_exceptions.FileAlreadyExistsException( \
258 #'file "%s" already exists' % output_file_name)
260 return output_file_name
262 def get_video_duration(self):
266 class BaseFileTransferer:
268 Ensures file transfer from the Web Server to the CIS (here).
270 Several implementations can be done by extending this class for
271 file transfer protocol such as FTP, SCP, RSYNC, HTTP etc.
277 def __init__(self, local_path='', remote_path=''):
278 """ Initialize by setting local and remote paths for file transfer. """
279 self.local_path = local_path
280 self.remote_path = remote_path
285 def get(self, files):
287 Transfers files locally from the Web Server.
289 files: a list of file name strings
293 def put(self, files):
295 Transfers files from the Web Server locally.
297 files: a list of file name strings
303 This method should be called when the instance is no longer required.
305 Class's destructor calls this method.
312 def get_video_duration(input_file, formated=False):
314 Returns the number of seconds of a video (int/float) if formated is
315 False and a string for duration formated as [HH:]:mm:ss otherwise.