5 Classes derived from BaseTranscoder and BaseThumbExtractor for transcoding of
6 videos and thumbnail extraction from videos using FFmpeg CLI program.
15 class FFmpegTranscoder(base.BaseTranscoder):
17 FFmpeg CLI API for video transcoding.
22 log_file = 'log/FFmpegTranscoder.log'
38 "theora": "libtheora",
42 def _transcode(self, container, a_codec=None, v_codec=None,
43 a_bitrate=None, a_samplingrate=None, a_channels=None,
44 v_bitrate=None, v_framerate=None, v_resolution=None, v_dar=None):
46 args = self.prog_bin + ' -y -i "' + self.input_file + '" -f ' + container
50 args += ' -acodec ' + a_codec
52 args += ' -ab ' + str(a_bitrate)
53 if a_samplingrate != None:
54 args += ' -ar ' + str(a_samplingrate)
55 if a_channels != None:
56 args += ' -ac ' + str(a_channels)
60 args += ' -vcodec ' + v_codec
61 # Video codec specific options.
62 if v_codec == 'libx264':
63 args += ' -vpre normal'
65 args += ' -b ' + str(v_bitrate)
66 if v_framerate != None:
67 args += ' -r ' + str(v_framerate)
68 if v_resolution != None:
69 args += ' -s ' + v_resolution
71 args += ' -aspect ' + v_dar
74 args += ' "' + self.output_file + '"'
76 # READ handler for process's output.
77 p = subprocess.Popen(args, shell=True,
78 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
81 # WRITE handler for logging.
82 log = open(self.log_file, 'w')
83 log.write(args + '\n')
86 line = pipe.readline()
93 raise cis_exceptions.TranscodingException( \
94 'FFmpeg exited with code ' + str(exit_code) + '.')
99 class FFmpegThumbExtractor(base.BaseThumbExtractor):
101 FFmpeg CLI API for video thumbnail extraction.
105 info_prog_bin = "ffprobe"
107 log_file = 'log/FFmpegThumbExtractor.log'
109 def extract_thumb(self, seek_pos, resolution="120x90", index=0):
110 output_file = self.get_output_file_name(index)
112 args = self.prog_bin + ' -y -i "' + self.input_file \
113 + '" -f rawvideo -vcodec mjpeg' + (' -ss ' + str(seek_pos)) \
114 + " -vframes 1 -an -s " + resolution + ' "' \
117 # READ handler for process's output.
118 p = subprocess.Popen(args, shell=True,
119 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
122 # WRITE handler for logging.
123 log = open(self.log_file, 'w')
124 log.write(args + '\n')
127 line = pipe.readline()
134 raise cis_exceptions.ThumbExtractionException( \
135 'FFmpeg exited with code ' + str(exit_code) + '.')
137 # FFmpeg bug: when no key frame is found from seek_pos to the
138 # end of file an empty image file is created.
139 if os.path.getsize(output_file) == 0L:
140 os.unlink(output_file)
141 raise cis_exceptions.ThumbExtractionException( \
142 'FFmpeg created an empty file.')
144 def get_video_duration(self):
145 args = self.info_prog_bin + ' -show_format "' \
146 + self.input_file + '"'
148 # READ handler for process's output.
149 p = subprocess.Popen(args, shell=True,
150 stdout=subprocess.PIPE, stderr=open(os.devnull, 'w'))
153 # Parse ffprobe's output.
155 line = pipe.readline()
159 # Search for the line which contains duration information.
160 m = re.match(r"duration=([\d\.]+)", line)
162 return float(m.group(1))
166 raise cis_exceptions.ThumbExtractionException( \
167 'FFmpeg exited with code ' + str(exit_code) + '.')