--- a/src/pyams_media/ffbase.py Fri Dec 04 16:34:56 2015 +0100
+++ b/src/pyams_media/ffbase.py Fri Dec 04 16:35:28 2015 +0100
@@ -49,64 +49,96 @@
re_videoline = re.compile("^\s*Stream #(\d+:\d+?)\(?([A-Za-z]*)\)?: Video: (.*?), (.*?), (.*?), (.*?)$")
re_audioline = re.compile("^\s*Stream #(\d+:\d+?)\(?([A-Za-z]*)\)?: Audio: (.*?), (\d+?) Hz, (.*?), (.*?), (\d+?) kb\/s$")
- def __init__(self, cmd="ffmpeg"):
+ def __init__(self, cmd="avconv"):
self.__ffmpeg__ = cmd
- def __exec__(self, *args):
+ def __exec__(self, *args, **kwargs):
"""Build and execute a command line"""
+
+ def create_temp_file(arg):
+ suffix = '.tmp'
+ if IFile.providedBy(arg):
+ # IFile object
+ content_type = get_magic_content_type(arg.data)
+ if content_type:
+ suffix = mimetypes.guess_extension(content_type) or suffix
+ output = tempfile.NamedTemporaryFile(prefix='media_', suffix=suffix)
+ output.write(arg.data)
+ elif hasattr(arg, 'read'):
+ # file-like object
+ arg.reset()
+ content_type = get_magic_content_type(arg.read(4096))
+ if content_type:
+ suffix = mimetypes.guess_extension(content_type) or suffix
+ output = tempfile.NamedTemporaryFile(prefix='media_', suffix=suffix)
+ try:
+ arg.reset()
+ except:
+ pass
+ data = arg.read(INPUT_BLOCK_SIZE)
+ while data:
+ output.write(data)
+ data = arg.read(INPUT_BLOCK_SIZE)
+ else:
+ # string or bytes
+ content_type = get_magic_content_type(arg)
+ if content_type:
+ suffix = mimetypes.guess_extension(content_type) or suffix
+ output = tempfile.NamedTemporaryFile(prefix='media_', suffix=suffix)
+ output.write(arg)
+ output.file.flush()
+ return output
+
cmdline = [self.__ffmpeg__]
- if self.__ffmpeg__ == 'ffmpeg':
- cmdline.append('-y')
+ if self.__ffmpeg__ == 'avconv':
+ cmdline.extend(['-y', '-loglevel', 'error'])
+ allow_stdin = kwargs.get('allow_stdin', True)
use_stdin = None
for arg in args:
if IFile.providedBy(arg):
if len(args) == 2:
# FFmpeg can't get media info from an input pipe
# We have to write media content to temporary file
- suffix = '.tmp'
- content_type = get_magic_content_type(arg.data)
- if content_type:
- suffix = mimetypes.guess_extension(content_type) or suffix
- output = tempfile.NamedTemporaryFile(prefix='media_', suffix=suffix)
- output.write(arg.data)
- output.file.flush()
+ output = create_temp_file(arg)
cmdline.append(output.name)
else:
- use_stdin = arg
- cmdline.append('-')
+ if allow_stdin:
+ use_stdin = arg
+ cmdline.append('-')
+ else:
+ output = create_temp_file(arg)
+ cmdline.append(output.name)
elif hasattr(arg, 'read'): # StringIO or any file like object
if len(args) == 2:
# FFmpeg can't get media info from an input pipe
# We have to write media content to temporary file
- arg.reset()
- content_type = get_magic_content_type(arg.read(4096))
- suffix = mimetypes.guess_extension(content_type) if content_type else '.tmp'
- output = tempfile.NamedTemporaryFile(prefix='media_', suffix=suffix)
- try:
- arg.reset()
- except:
- pass
- data = arg.read(INPUT_BLOCK_SIZE)
- while data:
- output.write(data)
- data = arg.read(INPUT_BLOCK_SIZE)
- output.file.flush()
+ output = create_temp_file(arg)
cmdline.append(output.name)
else:
- use_stdin = arg
- cmdline.append('-')
+ if allow_stdin:
+ use_stdin = arg
+ cmdline.append('-')
+ else:
+ output = create_temp_file(arg)
+ cmdline.append(output.name)
else:
cmdline.append(arg)
- logger.debug("Running FFmpeg command line: {0}".format(cmdline))
+ logger.debug("Running libAV command line: {0}".format(cmdline))
p = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE)
if use_stdin is not None:
if IFile.providedBy(use_stdin):
- return p.communicate(use_stdin.data)
+ stdout, stderr = p.communicate(use_stdin.data)
else:
use_stdin.reset()
- return p.communicate(use_stdin.read())
+ stdout, stderr = p.communicate(use_stdin.read())
+ if b'partial file' in stderr:
+ # the video file can't be converted through pipe...
+ logger.debug("Can't use piped conversion. Switch to temporary file...")
+ return self.__exec__(*args, allow_stdin=False)
else:
- return p.communicate()
+ stdout, stderr = p.communicate()
+ logger.debug(stderr)
+ return stdout, stderr
def render(self, effectchain, output):
"""Create a new file by chaining audio/video effects"""
@@ -148,10 +180,11 @@
metadata = []
if IFile.providedBy(input) or isinstance(input, str) or hasattr(input, 'read'):
input = [input, ]
- for i in range(0, len(input) * 2, 2):
- input.insert(i, "-i")
- if self.__ffmpeg__ == 'ffprobe':
- input.extend(['-show_format', '-show_streams', '-print_format', 'json'])
+ if self.__ffmpeg__ == 'avconv':
+ for i in range(0, len(input) * 2, 2):
+ input.insert(i, "-i")
+ if self.__ffmpeg__ == 'avprobe':
+ input.extend(['-show_format', '-show_streams', '-of', 'json'])
probe = self.__exec__(*input)[0] # stdout
metadata = json.loads(probe.decode())
else:
@@ -222,11 +255,14 @@
cmd.append("%s" % value)
return cmd
- def get_output(self, format=None, target='-', get_stderr=False):
+ def get_output(self, format=None, target='-'):
if (format is None) and hasattr(self, '__metadata__'):
format = self.__metadata__.get('vtype')
- stdout, stderr = FFmpeg().__exec__(*self.cmdline() + ['-f', format, target])
- return (stdout, stderr) if get_stderr else stdout
+ cmdline = self.cmdline() + ['-f', format, target]
+ stdout, stderr = FFmpeg().__exec__(*cmdline)
+ return {'output': stdout,
+ 'errors': stderr,
+ 'cmdline': ' '.join(map(str, cmdline))}
def restore(self):
"""
@@ -288,11 +324,11 @@
def bitrate(self, b=None):
""" set video bitrate """
if b:
- self.__effects__["b"] = "%sk" % int(b)
- return self.__effects__.get("b")
+ self.__effects__["b:v"] = "%sk" % int(b)
+ return self.__effects__.get("b:v")
def unset_bitrate(self):
- del self.__effects__["b"]
+ del self.__effects__["b:v"]
def vframes(self, vframes=None):
""" set number of video frames to record """
@@ -577,11 +613,11 @@
def audiobitrate(self, ab=64):
""" set audio bitrate (kbit/s)"""
- self.__effects__["ab"] = int(ab)
- return self.__effects__["ab"]
+ self.__effects__["b:a"] = "%sk" % int(ab)
+ return self.__effects__["b:a"]
def unset_audiobitrate(self):
- del self.__effects__["ab"]
+ del self.__effects__["b:a"]
def audiochannels(self, ac=1):
""" set number of audio channels """