Python实现多个视频合成一个视频的功能
作者:剑客阿良_ALiang 发布时间:2021-10-31 12:57:44
标签:Python,视频,合成
前言
本文提供将多个视频拼接为一个视频的Python工具代码,其中有一些限制条件,下面的代码说明会提到。
环境依赖
ffmpeg环境安装,可以参考:windows ffmpeg安装部署
本文主要使用到的不是ffmpeg,而是ffprobe也在上面这篇文章中的zip包中。
ffmpy安装:
pip install ffmpy -i https://pypi.douban.com/simple
代码
不废话了,上代码。
#!/user/bin/env python
# coding=utf-8
"""
@project : csdn
@author : 剑客阿良_ALiang
@file : concat_video.py
@ide : PyCharm
@time : 2021-12-23 15:23:16
"""
from ffmpy import FFmpeg
import os
import uuid
import subprocess
# 视频拼接
def concat(video_list: list, output_dir: str):
if len(video_list) == 0:
raise Exception('video_list can not empty')
_ext = check_format(video_list)
_fps = check_fps(video_list)
_result_path = os.path.join(
output_dir, '{}{}'.format(
uuid.uuid1().hex, _ext))
_tmp_config = make_tmp_concat_config(video_list, output_dir)
ff = FFmpeg(inputs={'{}'.format(_tmp_config): '-f concat -safe 0 -y'}, outputs={
_result_path: '-c copy'})
print(ff.cmd)
ff.run()
os.remove(_tmp_config)
return _result_path
# 构造拼接所需临时文件
def make_tmp_concat_config(video_list: list, output_dir: str):
_tmp_concat_config_path = os.path.join(output_dir, '{}.txt'.format(uuid.uuid1().hex))
with open(_tmp_concat_config_path, mode='w', encoding='utf-8') as f:
f.writelines(list(map(lambda x: 'file {}\n'.format(x), video_list)))
return _tmp_concat_config_path
# 校验每个视频的格式
def check_format(video_list: list):
_video_format = ''
for x in video_list:
_ext = os.path.splitext(x)[-1]
if _video_format == '' and _ext != '':
_video_format = _ext
continue
if _video_format != '' and _ext == _video_format:
continue
if _video_format != '' and _ext != _video_format:
raise Exception('Inconsistent video format')
return _video_format
# 校验每个视频的fps
def check_fps(video_list: list):
_video_fps = 0
for x in video_list:
_fps = get_video_fps(x)
if _video_fps == 0 and _fps:
_video_fps = _fps
continue
if _video_fps != 0 and _fps == _video_fps:
continue
if _video_fps != '' and _fps != _video_fps:
raise Exception('Inconsistent video fps')
if _video_fps == 0:
raise Exception('video fps error')
return _video_fps
# 获取视频fps
def get_video_fps(video_path: str):
ext = os.path.splitext(video_path)[-1]
if ext != '.mp4' and ext != '.avi' and ext != '.flv':
raise Exception('format not support')
ffprobe_cmd = 'ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate {}'
p = subprocess.Popen(
ffprobe_cmd.format(video_path),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
out, err = p.communicate()
print("subprocess 执行结果:out:{} err:{}".format(out, err))
fps_info = str(out, 'utf-8').strip()
if fps_info:
if fps_info.find("/") > 0:
video_fps_str = fps_info.split('/', 1)
fps_result = int(int(video_fps_str[0]) / int(video_fps_str[1]))
else:
fps_result = int(fps_info)
else:
raise Exception('get fps error')
return fps_result
if __name__ == '__main__':
print(concat(['D:/tmp/100.mp4', 'D:/tmp/101.mp4'], 'C:/Users/huyi/Desktop'))
代码说明
1、主要拼接方法为concat,入参分别为:视频列表、输出目录。
2、该视频拼接命令对视频本身有所限制,需要保证都是相同格式的视频,其次是每个视频的fps得一致,不然最终合成的视频会无法打开或者出现花屏现象。
3、临时的拼接文件会在使用后删除。
4、最终输出的文件名为了保证唯一使用uuid。
验证一下
下面是我准备的两个视频:
执行结果
PyDev console: starting.
Python 3.6.13 |Anaconda, Inc.| (default, Mar 16 2021, 11:37:27) [MSC v.1916 64 bit (AMD64)] on win32
runfile('D:/spyder/csdn/tool/concat_video.py', wdir='D:/spyder/csdn/tool')
subprocess 执行结果:out:b'25/1\r\n' err:b''
subprocess 执行结果:out:b'25/1\r\n' err:b''
ffmpeg -f concat -safe 0 -y -i C:/Users/huyi/Desktop\6d02df4b63d111eca6eee454e8bf1461.txt -c copy C:/Users/huyi/Desktop\6d02df4a63d111ec9dbbe454e8bf1461.mp4
ffmpeg version n4.3.1-20-g8a2acdc6da Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 9.3-win32 (GCC) 20200320
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-iconv --enable-zlib --enable-libxml2 --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvmaf --disable-vulkan --enable-libvorbis --enable-amf --enable-libaom --enable-avisynth --enable-libdav1d --enable-ffnvcodec --enable-cuda-llvm --disable-libglslang --enable-libass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvpx --enable-libwebp --enable-libmfx --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librav1e --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libtwolame --enable-libvidstab --enable-libx264 --enable-libx265 --enable-libxvid --enable-libzimg --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-libs=-lgomp
libavutil 56. 51.100 / 56. 51.100
libavcodec 58. 91.100 / 58. 91.100
libavformat 58. 45.100 / 58. 45.100
libavdevice 58. 10.100 / 58. 10.100
libavfilter 7. 85.100 / 7. 85.100
libswscale 5. 7.100 / 5. 7.100
libswresample 3. 7.100 / 3. 7.100
libpostproc 55. 7.100 / 55. 7.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 000001de4a7aebc0] Auto-inserting h264_mp4toannexb bitstream filter
Input #0, concat, from 'C:/Users/huyi/Desktop\6d02df4b63d111eca6eee454e8bf1461.txt':
Duration: N/A, start: -0.064000, bitrate: 1098 kb/s
Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 16000 Hz, mono, fltp, 69 kb/s
Metadata:
handler_name : SoundHandler
Stream #0:1(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1080x1920, 1028 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc
Metadata:
handler_name : VideoHandler
Output #0, mp4, to 'C:/Users/huyi/Desktop\6d02df4a63d111ec9dbbe454e8bf1461.mp4':
Metadata:
encoder : Lavf58.45.100
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1080x1920, q=2-31, 1028 kb/s, 25 fps, 25 tbr, 12800 tbn, 12800 tbc
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 16000 Hz, mono, fltp, 69 kb/s
Metadata:
handler_name : SoundHandler
Stream mapping:
Stream #0:1 -> #0:0 (copy)
Stream #0:0 -> #0:1 (copy)
Press [q] to stop, [?] for help
[mov,mp4,m4a,3gp,3g2,mj2 @ 000001de4a7aebc0] Auto-inserting h264_mp4toannexb bitstream filter
[mp4 @ 000001de4acdabc0] Non-monotonous DTS in output stream 0:1; previous: 6176768, current: 6176608; changing to 6176769. This may result in incorrect timestamps in the output file.
frame=22199 fps=0.0 q=-1.0 Lsize= 119649kB time=00:14:48.05 bitrate=1103.7kbits/s speed=2.41e+03x
video:111571kB audio:7524kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.465183%
C:/Users/huyi/Desktop\6d02df4a63d111ec9dbbe454e8bf1461.mp4
结果验证
来源:https://blog.csdn.net/zhiweihongyan1/article/details/122111988


猜你喜欢
- 前言不要在用手敲生成Excel数据报表了,用Python自动生成Excel数据报表!废话不多说让我们愉快地开始吧~开发工具Python版本:
- 本文细致的为大家分享了Bootstrap轮播插件简单实例,供大家参考,具体内容如下使用Bootstrap的轮播插件可以向站点添加滑块,内容可
- 一:从版本3.23升级到4.104.10新特性:支持事务处理和存储过程升级过程的注意事项:1:升级采用直接复制安装文件的方法,简单实用,但要
- Python批量替换文件内容,支持嵌套文件夹import ospath="./"for root,dirs,files
- 作为抛砖引玉,用python3实现百度云语音解析,首先需要模拟Post请求把音频压缩文件丢给百度解析。但是遇到一个问题客户端怎麽丢数据都是返
- 前言今天笔者想和大家来聊聊python接口自动化如何使用requests库发送http请求,废话呢笔者就不多说了,直接进入正题。一、requ
- 最近心血来潮加上有点闲情,动手写了第一个JavaScript版的俄罗斯方块Easy Tetris.先上Easy Tetris俄罗斯方块游戏截
- 异常是指因为程序出现了错误而在正常控制流以外采取的行动,其分为两个阶段,第一阶段是引发异常的错误,当系统检测到错误并且意识到异常条件,解释器
- git config --global设置用户名和邮件安装好git后,在命令行或终端中使用下面的命令可以设置git自己的名字和电子邮件。这是
- 一 过滤器写法{{ message | Filter}}二 Vue自带的过滤器:capitalize功能:首字母大写<!DOCTYPE
- 有的时候需要对python程序内存占用进行监控,这个时候可以用到psutil库,Anaconda中是自带的,如果import出错,可以用pi
- 1. 递归1.1 定义函数作为一种代码封装, 可以被其他程序调用,当然,也可以被函数内部代码调用。这种函数定义中调用函数自身的方式称为递归。
- 二进制核心思想:冯诺依曼 + 图灵机电如何表示状态,才能稳定?计算机开始设计的时候并不是考虑简单,而是考虑能自动完成任务与结果的可靠性,简单
- 你是怎么把密码储存到数据库里?是以纯文字的方式?你可知道这对安全的危险性?当攻击你网站的人能开启数据库浏览,以纯文字方式存在数据库里的密码一
- Python中常用到的两种标准化输入方式:分别sys.stdin和input,两者使用方式大致相同,但是总的来说sys.stdin使用方式更
- 目录1、简单循环 Simple loops2、简单循环但是使用了线程Simple loops but threaded3、定时调度库 Sch
- 任何编程语言开发的项目代码都是需要考虑内存问题的,有时候当项目体量比较庞大以后若是出现内存泄漏等问题分析起来更是哦力不从心的。因此,平时建议
- 本文介绍了使用Application来统计访问网站的在线人数的方法,并介绍了使用Application时应该注意的事项。首先讲明白,用ASP
- 1. 时间的表示Go 语言中时间的表示方式是通过 time.Time 结构体来表示的。time.Time 类型代表了一个时刻,它包含了年月日
- 本文实例讲述了Symfony模板的快捷变量用法。分享给大家供大家参考,具体如下:在模板里,有一些symfony变量可以直接使用。通过这些快捷