def get_media_info(filepath): """Takes a file path and returns a dict of information about this media file that it extracted from ffmpeg -i. :param filepath: absolute path to the media file in question :returns: dict of media info possibly containing: height, width, container, audio_codec, video_codec """ ffmpeg_bin = utils.get_ffmpeg_executable_path() retcode, stdout, stderr = util.call_command(ffmpeg_bin, "-i", "%s" % filepath, return_everything=True) if stdout: output = stdout else: output = stderr # logging.info("get_media_info: %s %s", filepath, output) ast = parse_ffmpeg_output(output.splitlines()) return extract_info(ast)
def convert(args): cm = conversions.ConverterManager() cm.load_converters(resources.path('conversions/*.conv')) if len(args) < 2: print USAGE print "Available targets:" for section, converters in cm.get_converters(): print " %s" % section for mem in converters: print " %s - %s" % (mem.identifier, mem.name) return target = args[0] infiles = args[1:] try: converter_info = cm.lookup_converter(target) except KeyError: print "That target doesn't exist." return for mem in infiles: input_file = os.path.abspath(mem) if not os.path.exists(input_file): print "File %s does not exist. Skipping." % input_file continue final_path, temp_path = conversions.build_output_paths( FakeInfo(input_file), os.getcwd(), converter_info) media_info = conversions.get_media_info(input_file) params = conversions.build_parameters( mem, temp_path, converter_info, media_info) if converter_info.executable == "ffmpeg": cmd = utils.get_ffmpeg_executable_path() params = utils.customize_ffmpeg_parameters(params) else: cmd = utils.get_ffmpeg2theora_executable_path() params = utils.customize_ffmpeg2theora_parameters(params) params.insert(0, cmd) print "\nCONVERTING %s -> %s\n" % (mem, final_path) print "ffmpeg command line:" print " ".join(params) print "\n" retcall = subprocess.call(params) if retcall == 0: shutil.move(temp_path, final_path) print "Success! New file at %s." % final_path
def convert(args): cm = conversions.ConverterManager() cm.load_converters(resources.path('conversions/*.conv')) if len(args) < 2: print USAGE print "Available targets:" for section, converters in cm.get_converters(): print " %s" % section for mem in converters: print " %s - %s" % (mem.identifier, mem.name) return target = args[0] infiles = args[1:] try: converter_info = cm.lookup_converter(target) except KeyError: print "That target doesn't exist." return for mem in infiles: input_file = os.path.abspath(mem) if not os.path.exists(input_file): print "File %s does not exist. Skipping." % input_file continue final_path, temp_path = conversions.build_output_paths( FakeInfo(input_file), os.getcwd(), converter_info) media_info = conversions.get_media_info(input_file) params = conversions.build_parameters(mem, temp_path, converter_info, media_info) if converter_info.executable == "ffmpeg": cmd = utils.get_ffmpeg_executable_path() params = utils.customize_ffmpeg_parameters(params) else: cmd = utils.get_ffmpeg2theora_executable_path() params = utils.customize_ffmpeg2theora_parameters(params) params.insert(0, cmd) print "\nCONVERTING %s -> %s\n" % (mem, final_path) print "ffmpeg command line:" print " ".join(params) print "\n" retcall = subprocess.call(params) if retcall == 0: shutil.move(temp_path, final_path) print "Success! New file at %s." % final_path
def get_media_info(filepath): """Takes a file path and returns a dict of information about this media file that it extracted from ffmpeg -i. :param filepath: absolute path to the media file in question :returns: dict of media info possibly containing: height, width, container, audio_codec, video_codec """ ffmpeg_bin = utils.get_ffmpeg_executable_path() retcode, stdout, stderr = util.call_command(ffmpeg_bin, "-i", "%s" % filepath, return_everything=True) if stdout: output = stdout else: output = stderr # logging.info("get_media_info: %s %s", filepath, output) ast = parse_ffmpeg_output(output.splitlines()) return extract_info(ast)
def get_executable(self): return utils.get_ffmpeg_executable_path()
def transcode(self): rc = True try: ffmpeg_exe = get_ffmpeg_executable_path() kwargs = { "stdin": open(os.devnull, 'rb'), "stdout": subprocess.PIPE, "stderr": open(os.devnull, 'wb'), "startupinfo": util.no_console_startupinfo() } if os.name != "nt": kwargs["close_fds"] = True args = [ffmpeg_exe, "-i", self.media_file] if self.time_offset: logging.debug('transcode: start job @ %d' % self.time_offset) args += TranscodeObject.time_offset_args + [ str(self.time_offset) ] video_needs_trancode = False if self.has_video: logging.debug('Video codec: %s', self.video_codec) logging.debug('Video size: %s', self.video_size) if video_can_copy(self.video_codec, self.video_size): args += get_transcode_video_copy_options() else: args += get_transcode_video_options() video_needs_transcode = True if self.has_audio: logging.debug('Audio codec: %s', self.audio_codec) logging.debug('Audio sample rate: %s', self.audio_sample_rate) if (valid_av_combo(self.video_codec, self.audio_codec) and audio_can_copy(self.audio_codec, self.audio_sample_rate)): args += get_transcode_audio_copy_options() else: args += get_transcode_audio_options() else: raise ValueError('no video or audio stream present') args += TranscodeObject.output_args logging.debug('Running command %s' % ' '.join(args)) self.ffmpeg_handle = subprocess.Popen(args, **kwargs) segmenter_exe = get_segmenter_executable_path() args = [segmenter_exe] address, port = self.sink.server_address args += TranscodeObject.segmenter_args + [str(port)] kwargs = { "stdout": open(os.devnull, 'rb'), "stdin": self.ffmpeg_handle.stdout, "stderr": open(os.devnull, 'wb'), "startupinfo": util.no_console_startupinfo() } # XXX Can't use this - need to pass on the child fds #if os.name != "nt": # kwargs["close_fds"] = True logging.debug('Running command %s' % ' '.join(args)) self.segmenter_handle = subprocess.Popen(args, **kwargs) self.sink_thread = threading.Thread(target=thread_body, args=[self.segmenter_consumer], name="Segmenter Consumer") self.sink_thread.daemon = True self.sink_thread.start() except StandardError: (typ, value, tb) = sys.exc_info() logging.error('ERROR: %s %s' % (str(typ), str(value))) rc = False self.transcode_gate.set() return rc
def needs_transcode(media_file): """needs_transcode() Returns (False, None) if no need to transcode. Returns (True, info) if there is a need to transcode. where info is (duration, has_audio, has_video) The duration is transmitted for transcoding purposes because we need to build a m3u8 playlist and what we get out of the Miro database may be unreliable (does not exist). May throw exception if ffmpeg not found. Remember to catch.""" ffmpeg_exe = get_ffmpeg_executable_path() kwargs = { "stdout": subprocess.PIPE, "stderr": subprocess.PIPE, "stdin": subprocess.PIPE, "startupinfo": util.no_console_startupinfo() } if os.name != "nt": kwargs["close_fds"] = True args = [ffmpeg_exe, "-i", media_file] handle = subprocess.Popen(args, **kwargs) # XXX unbounded read here but should be okay, ffmpeg output is finite. # note that we need to read from stderr, since that's what ffmpeg spits # out. text = handle.stderr.read() # Initial determination based on the file type - need to drill down # to see if the resolution, etc are within parameters. if container_regex.search(text): transcode = False else: transcode = True # " Duration: XX:XX:XX.XX, ..." match = duration_regex.search(text) start, end = match.span() duration_start = text[end:] duration = duration_start[:duration_start.index(',')] # Convert to seconds. We can't handle fractions of a second so # skip over those bits. hours, minutes, seconds = duration.split(':') # Strip the fractional seconds. Always round up, then we won't miss # any data. seconds = int(float(seconds) + 0.5) seconds += int(minutes) * 60 seconds += int(hours) * 3600 has_audio = has_audio_regex.search(text) has_video = has_video_regex.search(text) vcodec = acodec = size = sample_rate = None vcopy = acopy = False if has_video: vcodec, size = get_video_parameters(has_video) vcopy = video_can_copy(vcodec, size) if not vcopy: transcode = False if has_audio: acodec, sample_rate = get_audio_parameters(has_audio) acopy = audio_can_copy(acodec, sample_rate) if not acopy: transcode = False return (transcode, (seconds, has_audio, acodec, sample_rate, has_video, vcodec, size))
def transcode(self): rc = True try: ffmpeg_exe = get_ffmpeg_executable_path() kwargs = { "stdin": open(os.devnull, "rb"), "stdout": subprocess.PIPE, "stderr": open(os.devnull, "wb"), "startupinfo": util.no_console_startupinfo(), } if os.name != "nt": kwargs["close_fds"] = True args = [ffmpeg_exe, "-i", self.media_file] if self.time_offset: logging.debug("transcode: start job @ %d" % self.time_offset) args += TranscodeObject.time_offset_args + [str(self.time_offset)] video_needs_trancode = False if self.has_video: logging.debug("Video codec: %s", self.video_codec) logging.debug("Video size: %s", self.video_size) if video_can_copy(self.video_codec, self.video_size): args += get_transcode_video_copy_options() else: args += get_transcode_video_options() video_needs_transcode = True if self.has_audio: logging.debug("Audio codec: %s", self.audio_codec) logging.debug("Audio sample rate: %s", self.audio_sample_rate) if valid_av_combo(self.video_codec, self.audio_codec) and audio_can_copy( self.audio_codec, self.audio_sample_rate ): args += get_transcode_audio_copy_options() else: args += get_transcode_audio_options() else: raise ValueError("no video or audio stream present") args += TranscodeObject.output_args logging.debug("Running command %s" % " ".join(args)) self.ffmpeg_handle = subprocess.Popen(args, **kwargs) segmenter_exe = get_segmenter_executable_path() args = [segmenter_exe] address, port = self.sink.server_address args += TranscodeObject.segmenter_args + [str(port)] kwargs = { "stdout": open(os.devnull, "rb"), "stdin": self.ffmpeg_handle.stdout, "stderr": open(os.devnull, "wb"), "startupinfo": util.no_console_startupinfo(), } # XXX Can't use this - need to pass on the child fds # if os.name != "nt": # kwargs["close_fds"] = True logging.debug("Running command %s" % " ".join(args)) self.segmenter_handle = subprocess.Popen(args, **kwargs) self.sink_thread = threading.Thread( target=thread_body, args=[self.segmenter_consumer], name="Segmenter Consumer" ) self.sink_thread.daemon = True self.sink_thread.start() except StandardError: (typ, value, tb) = sys.exc_info() logging.error("ERROR: %s %s" % (str(typ), str(value))) rc = False self.transcode_gate.set() return rc
def needs_transcode(media_file): """needs_transcode() Returns (False, None) if no need to transcode. Returns (True, info) if there is a need to transcode. where info is (duration, has_audio, has_video) The duration is transmitted for transcoding purposes because we need to build a m3u8 playlist and what we get out of the Miro database may be unreliable (does not exist). May throw exception if ffmpeg not found. Remember to catch.""" ffmpeg_exe = get_ffmpeg_executable_path() kwargs = { "stdout": subprocess.PIPE, "stderr": subprocess.PIPE, "stdin": subprocess.PIPE, "startupinfo": util.no_console_startupinfo(), } if os.name != "nt": kwargs["close_fds"] = True args = [ffmpeg_exe, "-i", media_file] handle = subprocess.Popen(args, **kwargs) # XXX unbounded read here but should be okay, ffmpeg output is finite. # note that we need to read from stderr, since that's what ffmpeg spits # out. text = handle.stderr.read() # Initial determination based on the file type - need to drill down # to see if the resolution, etc are within parameters. if container_regex.search(text): transcode = False else: transcode = True # " Duration: XX:XX:XX.XX, ..." match = duration_regex.search(text) start, end = match.span() duration_start = text[end:] duration = duration_start[: duration_start.index(",")] # Convert to seconds. We can't handle fractions of a second so # skip over those bits. hours, minutes, seconds = duration.split(":") # Strip the fractional seconds. Always round up, then we won't miss # any data. seconds = int(float(seconds) + 0.5) seconds += int(minutes) * 60 seconds += int(hours) * 3600 has_audio = has_audio_regex.search(text) has_video = has_video_regex.search(text) vcodec = acodec = size = sample_rate = None vcopy = acopy = False if has_video: vcodec, size = get_video_parameters(has_video) vcopy = video_can_copy(vcodec, size) if not vcopy: transcode = False if has_audio: acodec, sample_rate = get_audio_parameters(has_audio) acopy = audio_can_copy(acodec, sample_rate) if not acopy: transcode = False return (transcode, (seconds, has_audio, acodec, sample_rate, has_video, vcodec, size))
def get_executable(self): return utils.get_ffmpeg_executable_path()