目录

  • 1. 安装ffmpeg
  • 2. 安装ffmpy
  • 3. ffmpy简单的命令,在系统环境下执行:
  • 4. ffmpy的简单使用
  • 5. python 使用ffmpy 结合ffmpeg
  • 5.编码格式的转换

1. 安装ffmpeg

sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next 
sudo apt-get update 
sudo apt-get install ffmpeg

2. 安装ffmpy

pip install ffmpy==0.2.2  # 需要权限就添加sudo

3. ffmpy简单的命令,在系统环境下执行:

# 获取video/vvvv.mp4的视频时间
$ ffmpeg -i video/vvvv.mp4 2>&1| grep 'Duration'| cut -d ' '-f 4| sed s/,//# 生成缩略图, 其中out%d.png 表示生成多张图片%d表示占位符
$ ffmpeg -i video/vvvv.mp4 -f image2 -vf fps=fps=1 out%d.png
# 生成10*10的缩略图 fps=fps=1 表示每一帧抓取一次 -y 表示同意覆盖
$ ffmpeg -i video/vvvv.mp4 -y -f image2 -vf "fps=fps=1,scale=180*75,tile=10x10" out%d.png
# 切TS流 video/playlist.m3u8 video/cat_output%03d.ts  ts流的存储路径,他们要在同一个文件夹下
$ ffmpeg -i video/vvvv.mp4  -c copy -map0-y -f segment -segment_list video/playlist.m3u8 -segment_time 1-bsf:v h264_mp4toannexb   video/cat_output%03d.ts

4. ffmpy的简单使用

ffmpy文档

其实就是将ffmpeg命令直接放入到ffmpy中, 并在命令行中执行代码

5. python 使用ffmpy 结合ffmpeg

import os
import re
import logging
from django.conf import settings
from django.core.cache import cache
from ffmpy import FFmpeg
from course.constant import VIDEOSTATE
logger = logging.getLogger(__name__)

def cut_change(video_path, out_path, out_path2, out_path3, base_path, fps_r):
    """
    操作ffmpeg执行
    :param video_path: 处理输入流视频
    :param out_path: 合成缩略图 10×10
    :param out_path2: 封面图路径
    :param out_path3: 合成Ts流和 *.m3u8文件
    :param fps_r: 对视频帧截取速度
    """
    ff = FFmpeg(inputs={video_path: None},
                outputs={out_path: '-f image2 -vf fps=fps={},scale=180*75,tile=10x10'.format(fps_r),
                         out_path2: '-y -f mjpeg -ss 0 -t 0.001',
                         None: '-c copy -map 0 -y -f segment -segment_list {0} -segment_time 1  -bsf:v h264_mp4toannexb  {1}/cat_output%03d.ts'.format(
                             out_path3, base_path),
                         })
    print(ff.cmd)
    ff.run()


def execCmd(cmd):
    """
    执行计算命令时间
    """
    r = os.popen(cmd)
    text = r.read().strip()
    r.close()
    return text


# 获取完整的上传文件路径
def has_video(video_path):
    MEDIA_DIR = settings.MEDIA_ROOT
    FULL_PATH = os.path.join(MEDIA_DIR, video_path)
    flag = False
    if os.path.exists(FULL_PATH):
        flag = True
    return flag, FULL_PATH, MEDIA_DIR


def handle_video_cut(instance):
    video_path = instance.video.name
    video_name = os.path.splitext(video_path.split('/')[-1])[0][:5]
    flag, full_path, media_path = has_video(video_path)

    base_preview_path = os.path.join(media_path, 'video_trans/preview')
    base_poster_path = os.path.join(media_path, 'video_trans/poster')
    base_path = os.path.join(media_path, 'video_trans/video_change', str(instance.id))
    # 必须先创建路径, ffmpeg不会自己创建
    if not os.path.exists(base_path):
        os.makedirs(base_path)
    if not os.path.exists(base_poster_path):
        os.makedirs(base_poster_path)
    if not os.path.exists(base_preview_path):
        os.makedirs(base_preview_path)
    preview_path = os.path.join(base_preview_path, video_name + '{}_out.png'.format(str(instance.id)))
    poster_path = os.path.join(base_poster_path, video_name + '{}_poster.jpeg'.format(str(instance.id)))
    video_change = os.path.join(base_path, 'playlist.m3u8')

    if not flag:
        logger.info('this video_path({}) is not exists'.format(full_path))
        return None
    cmd = "ffmpeg -i {} 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//".format(full_path)
    text = execCmd(cmd)
    search_group = re.search('(\d+):(\d+):(\d+)', text)
    if search_group:
        time_hours = int(search_group.group(1))
        time_minutes = int(search_group.group(2))
        time_seconds = int(search_group.group(3))
        all_count_seconds = time_hours * 60 * 60 + time_minutes * 60 + time_seconds
        # print(all_count_seconds)
    else:
        logger.info('this video({}) is no time'.format(full_path))
        return None

    # 因无法精确分配100分压缩图片,存在误差, 以下函数会有错误但是并不会影响结果, 会有exception
    try:
        cut_change(full_path, preview_path, poster_path, video_change, base_path, r)
    except:
        pass
    # print('change video code success')
    logger.info('change video code success and clean cache')

5.编码格式的转换

有的mp4格式编码不同, ts流切出来的视频卡顿无法播放, 需要将mp4视频的编码格式转换成 H264, 因为ffmpeg有对应的编码解析器h264_mp4toannexb,其它的编码格式例如:MPEG1, MPEG2, MPEG4等等,目前没有发现ffmpeg相对应的编码解析器,所以建议把.mp4的视频转换成h264的编解码器

# 比如一个视频的编码是MPEG4,想用H264编码,咋办? 
ffmpeg -i input.mp4 -strict -2 -vcodec h264 output.mp4  
#input.mp4是指要转换视频的地址;output.mp4是转化后视频的存放路径
# 相反也一样 
ffmpeg -i input.mp4 -strict -2 -vcodec mpeg4 output.mp4

转换前

ffmpeg python库 ffmpegpython库文档_ffmpeg python库


转换后

ffmpeg python库 ffmpegpython库文档_ffmpeg python库_02