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 api_exceptions.TranscodingException( \
94 'FFmpeg exited with code ' + str(exit_code) + '.')
99 class FFmpegThumbExtractor(base.BaseThumbExtractor):
101 FFmpeg CLI API for video thumbnail extraction.
106 log_file = 'log/FFmpegThumbExtractor.log'
108 def extract_thumb(self, seek_pos, resolution="120x90", index=0):
109 output_file = self.get_output_file_name(index)
111 args = self.prog_bin + ' -y -i "' + self.input_file \
112 + '" -f rawvideo -vcodec mjpeg' + (' -ss ' + str(seek_pos)) \
113 + " -vframes 1 -an -s " + resolution + ' "' \
116 # READ handler for process's output.
117 p = subprocess.Popen(args, shell=True,
118 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
121 # WRITE handler for logging.
122 log = open(self.log_file, 'w')
123 log.write(args + '\n')
126 line = pipe.readline()
133 raise api_exceptions.ThumbExtractionException( \
134 'FFmpeg exited with code ' + str(exit_code) + '.')
136 # FFmpeg bug: when no key frame is found from seek_pos to the
137 # end of file an empty image file is created.
138 if os.path.getsize(output_file) == 0L:
139 os.unlink(output_file)
140 raise api_exceptions.ThumbExtractionException( \
141 'FFmpeg created an empty file.')
143 def get_video_duration(self):
144 return FFmpegAVInfo.get_video_duration(self.input_file)
147 class FFmpegAVInfo(base.BaseAVInfo):
152 def get_video_duration(input_file):
153 args = FFmpegAVInfo.prog_bin + ' -show_format "' \
156 # READ handler for process's output.
157 p = subprocess.Popen(args, shell=True,
158 stdout=subprocess.PIPE, stderr=open(os.devnull, 'w'))
161 # Parse ffprobe's output.
163 line = pipe.readline()
167 # Search for the line which contains duration information.
168 m = re.match(r"duration=([\d\.]+)", line)
170 return float(m.group(1))
174 raise api_exceptions.ThumbExtractionException( \
175 'FFmpeg exited with code ' + str(exit_code) + '.')