def ffprobe(buf, extension=None, flat=True):
    """
    Returns a dict based on the json output of ffprobe. If ``flat`` is ``True``,
    the 'format' key-values are made top-level, as well as the first video stream
    in the file (the rest are discarded). Any 'stream' keys that have the same
    name as a key in 'format' are prefixed with ``stream_``.
    """
    global FFPROBE_PATH

    if FFPROBE_PATH is None:
        FFPROBE_PATH = which('ffprobe')

    if FFPROBE_PATH is None:
        raise FFmpegError("Could not find ffprobe executable")

    with named_tmp_file(data=buf, extension=extension) as input_file:
        command = [
            FFPROBE_PATH, '-hide_banner', '-loglevel', 'fatal', '-show_error',
            '-show_format', '-show_streams', '-print_format', 'json',
            '-i', input_file,
        ]

        proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=PIPE)

        stdout, stderr = proc.communicate()

        try:
            probe_data = json.loads(stdout)
        except ValueError:
            probe_data = None

        if not isinstance(probe_data, dict):
            raise FFmpegError("ffprobe returned invalid data")

        if 'error' in probe_data:
            raise FFmpegError("%(string)s (%(code)s)" % probe_data['error'])

        if 'format' not in probe_data or 'streams' not in probe_data:
            raise FFmpegError("ffprobe returned invalid data")

        if not flat:
            return probe_data

        try:
            video_stream = next(s for s in probe_data['streams'] if s['codec_type'] == 'video')
        except StopIteration:
            raise FFmpegError("File is missing a video stream")

        data = probe_data['format']
        for k, v in six.iteritems(video_stream):
            if k in data:
                k = 'stream_%s' % k
            data[k] = v
        return data
Exemple #2
0
 def run_cmd(self, command):
     logger.debug("Running `%s`" % " ".join(command))
     proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=PIPE)
     proc.command = command
     stdout, stderr = proc.communicate()
     logger.debug(stderr)
     if proc.returncode == 0:
         return stdout
     else:
         err_msg = "%s => %s" % (" ".join(command), proc.returncode)
         err_msg += "\n%s" % stderr
         if self.context.request:
             err_msg += "\n%s" % self.context.request.url
         raise FFmpegError(err_msg)
Exemple #3
0
    def transcode(self, extension):
        if getattr(self.context.request, 'format', None):
            out_format = self.context.request.format
            if out_format in ('hevc', 'h264', 'h265'):
                extension = '.mp4'
                self.context.request.format = 'mp4'
        else:
            out_format = FORMATS[extension]

        with self.make_src_file(extension) as src_file:
            if out_format == 'webp':
                return self.transcode_to_webp(src_file)
            elif out_format in ('webm', 'vp9'):
                return self.transcode_to_vp9(src_file)
            elif out_format in ('mp4', 'h264'):
                return self.transcode_to_h264(src_file)
            elif out_format in ('hevc', 'h265'):
                return self.transcode_to_h265(src_file)
            elif out_format == 'gif':
                return self.transcode_to_gif(src_file)
            else:
                raise FFmpegError("Invalid video format '%s' requested" %
                                  out_format)