【python】ffmpeg使用实例

这里写目录标题

  • api&github
  • 实例代码

api&github

官方api
官方github
参数说明

实例代码

import ffmpeg
from pathlib import Path


class VideoEd:
    image_extend = [".jpg", ".jpeg", ".png", ".tif", ".tiff"]

    def extract_video(self, input_file, output_dir, output_ext='png', fps=0):
        '''
        视频每帧截图
        :param input_file:  视频文件
        :param output_dir:  输出目录
        :param output_ext:  截取的图片后缀名称 :'png' or 'jpg'
        :param fps:         每帧的fps
        :return: True
        '''
        input_file_path = Path(input_file)
        output_path = Path(output_dir)
        if not input_file_path.exists():
            raise Exception('input file not find')

        if not output_path.exists():
            output_path.mkdir(exist_ok=True)

        job = ffmpeg.input(str(input_file_path))

        kwargs = {'pix_fmt': 'rgb24'}
        if fps != 0:
            kwargs.update({'r': str(fps)})

        if output_ext == 'jpg':
            kwargs.update({'q:v': '2'})  # highest quality for jpg

        job = job.output(str(output_path / ('%5d.' + output_ext)), **kwargs)
        try:
            job = job.run()
        except:
            raise Exception("ffmpeg fail, job commandline:" + str(job.compile()))

    def cut_video(self, input_file, from_time, to_time, output_file=None, audio_track_id=None, kwargs={}):
        '''
        剪切视频
        :param input_file: 视频文件路径
        :param from_time:  开始时间 格式 00:00:00.000
        :param to_time:    结束时间 格式 00:02:00.000
        :param output_file:保存文件路径
        :param audio_track_id: ?
        :param kwargs:     其他参数
        :return: None
        '''
        input_file = Path(input_file)
        if input_file is None:
            raise Exception("input_file not found.")

        if output_file is None:
            output_file = input_file.parent / (input_file.stem + "_cut" + input_file.suffix)

        if audio_track_id is None:
            audio_track_id = 0

        job = ffmpeg.input(str(input_file), ss=from_time, to=to_time)

        job_v = job['v:0']
        job_a = job['a:' + str(audio_track_id) + '?']

        job = ffmpeg.output(job_v, job_a, str(output_file), **kwargs).overwrite_output()
        try:
            job = job.run()
        except:
            raise Exception("ffmpeg fail, job commandline:" + str(job.compile()))

    def video_from_sequence(self, input_dir, output_file, fps=None, bitrate=None, logo=None, position=(0, 0), kwargs={}):
        '''
        根据图片生成视频文件
        :param input_dir:   图片所在目录
        :param output_file: 生成的视频路径
        :param fps:         每秒帧数
        :param bitrate:     比特率
        :param logo:        是否添加水印
        :param position:    水印位置(x, y)
                                x > 0: 距离左边缘x像素  x < 0: 距离右边缘x像素
                                y > 0: 距离上边缘y像素  y < 0: 距离下边缘y像素
                                例如:
                                 (10,10):    左上各10
                                 (10, -10):  左下各10
                                 (-10, 10):  右上各10
                                 (-10, -10): 右下各10

        :return: None
        '''
        input_path = Path(input_dir)
        output_file_path = Path(output_file)

        if not input_path.exists():
            raise Exception("input path not found.")

        if not output_file_path.parent.exists():
            output_file_path.parent.mkdir(parents=True, exist_ok=True)

        input_image_paths = self._all_input_image_paths(input_path)

        fps = (fps, 25)[fps is None]

        i_in = ffmpeg.input('pipe:', format='image2pipe', r=fps)

        output_args = [i_in]

        output_args += [str(output_file_path)]

        output_kwargs = {}

        output_kwargs.update(self._format_logo_command_param(logo, position))    # 添加水印

        output_kwargs.update({
            "b:v": "%dM" % (max(1, bitrate or 16)),             # 比特率
            "pix_fmt": "yuv420p",                               # ?
            "r": fps,                                           # 每秒帧数 默认25
        })
        output_kwargs.update(kwargs)

        job = (ffmpeg.output(*output_args, **output_kwargs).overwrite_output())
        try:
            job_run = job.run_async(pipe_stdin=True)
            for image_path in input_image_paths:
                with open(image_path, "rb") as f:
                    image_bytes = f.read()
                    job_run.stdin.write(image_bytes)
            job_run.stdin.close()
            job_run.wait()
        except:
            raise Exception("ffmpeg fail, job commandline:" + str(job.compile()))

    def _all_input_image_paths(self, input_path):
        '''
        生成最终视频的每一帧图片(有序)
        :param input_path: 文件路径
        :return: None
        '''
        return sorted([str(i) for i in input_path.iterdir() if i.is_file() and i.suffix in self.image_extend])

    def _format_logo_command_param(self, logopath, position):
        '''
        生成ffmpeg水印命令行参数
        :param logopath: logo路径
        :param position: 水印的相对位置
        :return: None
        '''
        if type(position) != tuple or position.__len__() != 2 or type(position[0]) != int or type(position[1]) != int:
            raise Exception('position error, for example: (0, 0)')
        x = (position[0], 'main_w-overlay_w-{}'.format(abs(position[0])))[position[0] < 0]
        y = (position[1], 'main_h-overlay_h-{}'.format(abs(position[1])))[position[1] < 0]
        return {'vf': 'movie={} [wm];[in][wm]overlay={}:{}[out]'.format(logopath, x, y)}


if __name__ == '__main__':
    # demo1
    # input_path = '/Users/jemes/workspace/simage/huge1.mp4'
    # output_path = '/Users/jemes/workspace/simage/shortcut'
    # VideoEd().extract_video(input_path, output_path)

    # demo2
    # input_path = '/Users/jemes/workspace/simage/huge1.mp4'
    # output_file = '/Users/jemes/workspace/simage/huge_cut.mp4'
    # VideoEd().cut_video(input_path, from_time="00:00:00.000", to_time="00:00:10.000", output_file=output_file)

    # demo3
    # input_path = '/Users/jemes/workspace/simage/shortcut'
    # output_path = '/Users/jemes/workspace/simage/huge2_res.mp4'
    # logo = '/Users/jemes/workspace/simage/logo.png'
    # VideoEd().video_from_sequence(input_path, output_path, logo=logo, position=(-20, -20))
    pass

你可能感兴趣的:(python,ffmpeg)