需求:


运营有若干批次的视频。有上千个,视频文件,有mp4格式的,有ts格式的

现在有需要去掉视频文件片头和片尾的批量操作需求。

比如

文件夹A下面的视频去掉片尾10秒

文件夹B下面的视频去掉片头6秒,去掉片尾60秒

文件夹C下面的视频去掉片头15秒

而每个文件夹下面视频存在时间长度不一样的情况

而且一个周末必须搞定(MMP,周五下班时找我求助)

嗯~~

开始我的研究


首先想到的是网上搜索视频处理模块

网上搜到的大多都是ffmpeg工具。就准备从它切入

网上搜索了解了大概的用法之后,下下载下来测试

免费开源的软件

登录官网下载

http://ffmpeg.org/download.html
下载win10版本软件

64位和32位的版本都下载了,好在不用安装。解压即用

可以看到32位和64位的

因为可以再命令行对视频操作。可以使用python调用它。前提是你先命令行执行没问题才可以

解压后把文件夹重命名了下。让cmd里面显示的路径短一点。好看

bin目录下有3个工具

其中ffmpeg就可以对视频截取操作

想着3个工具肯定都有自己的用处,就去搜索了下ffprobe,搜索到它可以取元数据信息等

把一个视频拷贝过去

视频的一些信息可以看下

使用ffprobe操作下视频。可以看到视频元数据信息,时长正式我需要的

想着把它输出为json格式的最好。正好搜到了一些可用的参数

参考链接https://blog.csdn.net/u012040869/article/details/70224964

使用如下,其中的时长是duration这个key

E:\tools\ffmpeg-win64\bin>ffprobe -v quiet -print_format json -show_format 1.mp4
{
"format": {
"filename": "1.mp4",
"nb_streams": 2,
"nb_programs": 0,
"format_name": "mov,mp4,m4a,3gp,3g2,mj2",
"format_long_name": "QuickTime / MOV",
"start_time": "0.000000",
"duration": "965.810600",
"size": "26227952",
"bit_rate": "217251",
"probe_score": 100,
"tags": {
"major_brand": "mp42",
"minor_version": "1",
"compatible_brands": "M4V mp42isom",
"creation_time": "2017-08-28T05:07:05.000000Z"
}
}
} E:\tools\ffmpeg-win64\bin>

  

使用python调用此工具,输出为json格式,然后获取时长的简单测试

import subprocess,json
pname='e:\\tools\\ffmpeg-win32\\bin\\ffprobe.exe -v quiet -print_format json -show_format "1.MP4"'
result=subprocess.Popen(pname,shell=False,stdout=subprocess.PIPE).stdout
list_std=result.readlines()
print(list_std)
print('list--------------------')
str_tmp=''
for item in list_std:
str_tmp+=bytes.decode(item.strip())
json_data=json.loads(str_tmp)
print('json_data---------------')
print(json_data)
dura_time = json_data['format']['duration']
print(dura_time)

  

运行如下

接下来是使用ffmpeg工具对视频切割,看看能否满足要求

视频时长是965秒,那么切掉最后10秒,命令行测试下

参数解释下

-i接文件名,指的是输入文件名

-ss是视频的起始位置,这里是0的话,就表示从低0秒开始截取

-t是持续时间。

-codec copy 表示将拷贝所有的流,而不会对它们重新编码,(也可以写为-c copy,测试过一样。仅仅剪切,不转码)不加这个参数CPU会急剧飙升。100%占用率,而且视频不是很快的截取完毕

更多参数请参考https://blog.csdn.net/stone_wzf/article/details/45378759

或者搜索ffmpeg参数

E:\tools\ffmpeg-win64\bin>ffmpeg  -i 1.mp4 -ss 0 -t 955 -codec copy cut.mp4
ffmpeg version N-91378-g3f953379e1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 7.3.0 (GCC)
configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-bzlib --enable-fontconfig --enable-gnutls --enabl
e-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-
libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-l
ibtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --en
able-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-l
ibvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enabl
e-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth
libavutil 56. 18.102 / 56. 18.102
libavcodec 58. 20.104 / 58. 20.104
libavformat 58. 17.101 / 58. 17.101
libavdevice 58. 4.101 / 58. 4.101
libavfilter 7. 25.100 / 7. 25.100
libswscale 5. 2.100 / 5. 2.100
libswresample 3. 2.100 / 3. 2.100
libpostproc 55. 2.100 / 55. 2.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '1.mp4':
Metadata:
major_brand : mp42
minor_version : 1
compatible_brands: M4V mp42isom
creation_time : 2017-08-28T05:07:05.000000Z
Duration: 00:16:05.81, start: 0.000000, bitrate: 217 kb/s
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x768 [SAR 1:1 DAR 5:3], 161 kb/s,
15 fps, 15 tbr, 15k tbn, 30 tbc (default)
Metadata:
creation_time : 2017-08-28T05:07:05.000000Z
handler_name : Video Media Handler
encoder : AVC Coding
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, stereo, fltp, 54 kb/s (default)
Metadata:
creation_time : 2017-08-28T05:07:05.000000Z
handler_name : Sound Media Handler
Output #0, mp4, to 'cut.mp4':
Metadata:
major_brand : mp42
minor_version : 1
compatible_brands: M4V mp42isom
encoder : Lavf58.17.101
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x768 [SAR 1:1 DAR 5:3], q=2-31, 16
1 kb/s, 15 fps, 15 tbr, 15k tbn, 15k tbc (default)
Metadata:
creation_time : 2017-08-28T05:07:05.000000Z
handler_name : Video Media Handler
encoder : AVC Coding
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, stereo, fltp, 54 kb/s (default)
Metadata:
creation_time : 2017-08-28T05:07:05.000000Z
handler_name : Sound Media Handler
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame=14325 fps=0.0 q=-1.0 Lsize= 25506kB time=00:15:54.99 bitrate= 218.8kbits/s speed=8.98e+003x
video:18721kB audio:6388kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.579203% E:\tools\ffmpeg-win64\bin>

  

切割出来的视频文件

使用mediainfo打开这2个文件,导出json信息。

使用比较工具比较下元数据信息

差别不是很大

接下来写python脚本批量操作,有些模块用不到。之前别的脚本拷贝过来的。

这里使用pycharm执行。需要手动对每个文件夹操作,pycharm实际是调用成功ffmpeg之后,就退出了。ffmpeg作为子进程还在运行

底层系统进程里可以看到实际是ffmpeg运行呢、一个目录有30个视频。可能会同时有30个ffmpeg进程在运行。后期再优化吧。看看能不能串行或者并行10个左右

因为如果100个视频文件在同一个目录。那么此脚本会同时启动100个ffmpeg子进程,普通磁盘读写太慢,影响效率

下面的文件是用双引号引起来的"%s",是因为之前遇到视频文件名带空格。导致传入文件名时,参数个数增加了,导致报错

import os,subprocess,json,re,locale,sys
import xlwt,time,shutil #定义个列表存放每个文件路径,便于后期操作
file_list=[]
#源文件目录
dir_path='E:\\0630\\3'
#输出截取之后的文件目录
put_path='E:\\0630\\33\\'
#创建个方法,统计每个文件路径,并追加列表中。用到了递归,列表中的是每个文件的绝对路径
def get_all_file(dir_path):
for file in os.listdir(dir_path):
# print(file)
filepath=os.path.join(dir_path,file)
# print(filepath)
if os.path.isdir(filepath):
get_all_file(filepath)
else:
file_list.append(filepath)
return file_list file_list=get_all_file(dir_path)
print(file_list) #设置从什么时间开始截取,单位是秒
start_time=10
#设置去掉多久的无用时长(比如片头去掉10秒,片尾去掉15秒,总共去掉25秒)
cut_time=25 #定义方法,传入文件和截取的时间信息,输出路径。对每个文件操作
def cut_media_time(file,start_time,cut_time,put_path):
#获取文件元数据,输出为json,这里把命令写好。总之为了获取时长
pname='e:\\tools\\ffmpeg-win32\\bin\\ffprobe.exe -v quiet -print_format json -show_format "%s"'%(file)
#调用执行命令
result=subprocess.Popen(pname,shell=False,stdout=subprocess.PIPE).stdout
list_std=result.readlines()
str_tmp=''
for item in list_std:
str_tmp+=bytes.decode(item.strip())
json_data=json.loads(str_tmp)
# print(json_data)
#获取时长,格式是str
dura_time = json_data['format']['duration']
print(dura_time)
print(type(dura_time))
#因为时长精确到毫秒,是str格式,转成float类型
dura_time_float=float(dura_time)
print(type(dura_time_float))
print('------')
# dura_time=int(dura_time)
#也转成float类型
cut_time=float(cut_time)
print(type(cut_time))
#float类型的数据计算
end_time=dura_time_float-cut_time
print('end_time-------')
print(type(end_time))
#获取文件名,去掉路径
filename=os.path.split(file)[1]
#根据输出目录组合成输出的绝对路径文件名
put_file_path=os.path.join(put_path,filename)
#ffmpeg的字符串切割命令字符串
pfile='E:\\tools\\ffmpeg-win32\\bin\\ffmpeg.exe -i "%s" -ss %s -t %s -codec copy "%s"'%(file,start_time,end_time,put_file_path)
#执行切割操作
subprocess.Popen(pfile)
#对列表中的文件批量执行
for file in file_list:
cut_media_time(file,start_time,cut_time,put_path)

  

另外路径必须是\\2个斜线。一个斜线会报如下错误

"PermissionError: [WinError 5] Access is denied".

  

因为太仓促,就临时用pycharm帮他们处理了下

使用ssd的速度会比sata硬盘速度快了不止10倍。因为几十个ffmpeg同时随机读写磁盘。ssd效率比sata高多了

后期改造计划


1、把执行改成并行10个,或者串行的

2、加入异常处理

3、打成exe程序交付给运营执行(简单打成exe测试了。把文件名写死了简单测试。执行没问题。中文文件名也没问题,就是执行窗口有部分乱码。暂时不影响)

其它参考


python有moviepy模块。貌似能满足要求。但是因为时间仓促缘故没仔细研究测试
涉及用法

from moviepy.editor import *
#在t = 50s和t = 60s之间选择子剪辑
video = VideoFileClip("my.mp4").subclip(50,60)

  

下面windows软件可能满足要求,操作太多了点

http://www.leawo.cn/space-758990-do-thread-id-37655.html

淘宝有此类软件,但是询问店主,说支持mp4,但是不支持ts格式的视频
https://item.taobao.com/item.htm?spm=a230r.1.14.20.6d386e8fA51UHY&id=563703965309&ns=1&abbucket=14#detail

其它补充


ffmpeg -i ./plutopr.mp4 -vcodec copy -acodec copy -ss 00:00:10 -to 00:00:15 ./cutout1.mp4 -y

-ss time_off set the start time offset 设置从视频的哪个时间点开始截取,上文从视频的第10s开始截取
-to 截到视频的哪个时间点结束。上文到视频的第15s结束。截出的视频共5s.
-t 表示截取多长的时间,如上文-to 换位-t则是截取从视频的第10s开始,截取15s时长的视频。即截出来的视频共15s.

注意的地方是:
如果将-ss放在-i ./plutopr.mp4后面则-to的作用就没了,跟-t一样的效果了,变成了截取多长视频。一定要注意-ss的位置。

参数解析
-vcodec copy表示使用跟原视频一样的视频编解码器。
-acodec copy表示使用跟原视频一样的音频编解码器。

-i 表示源视频文件
-y 表示如果输出文件已存在则覆盖。

ffmpeg工具本身功能非常强大,转码、剪切、截图、视频合成等

https://www.cnblogs.com/gmapapi/archive/2013/01/18/2866405.html

Python调用ffpmeg和ffprobe处理视频文件的更多相关文章

  1. python调用mediainfo工具批量提取视频信息

    写了2个脚本,分别是v1版本和v2版本 都是python调用mediainfo工具提取视频元数据信息 v1版本是使用pycharm中测试运行的,指定了视频路径 v2版本是最终交付给运营运行的,会把v2 ...

  2. centos8平台用ffprobe获取视频文件信息(ffmpeg4.2.2)

    一,ffprobe的作用 ffprobe是强大的视频分析工具, 用于从多媒体流中获取相关信息或查看文件格式信息, 并以可读的方式打印 说明:刘宏缔的架构森林是一个专注架构的博客,地址:https:// ...

  3. java调用本地播放器播放视频文件。调用本地播放器不能播放指定文件的说明。

    public class OpenExe extends HttpServlet { //打开本地播放器并播放视频 public static void openExe(String file) { ...

  4. python爬虫:抓取下载视频文件,合并ts文件为完整视频

    1.获取m3u8文件 2.代码 """@author :Eric-chen@contact :sygcrjgx@163.com@time :2019/6/16 15:32 ...

  5. 简单实现python调用c#dll动态链接库

    在python调用c#dll库时要先安装库clr,即安装pythonnet,参考文章:https://www.cnblogs.com/kevin-Y/p/10235125.html(为在python中 ...

  6. python调用c/c++时传递结构体参数

    背景:使用python调用linux的动态库SO文件,并调用里边的c函数,向里边传递结构体参数.直接上代码 //test1.c # include <stdio.h> # include ...

  7. python实现调用摄像头或打开视频文件

    目录: (一)调用摄像头或打开视频文件代码实现 (二)说明和补充 (一)调用摄像头或打开视频文件代码实现 1 # -*- coding=GBK -*- 2 import cv2 as cv 3 4 5 ...

  8. 用Python和FFmpeg查找大码率的视频文件

    用Python和FFmpeg查找大码率的视频文件 本文使用Python2.7, 这个工作分两步 遍历目录下的视频文件 用ffprobe获取是视频文件的码率信息 用ffprobe 获取json格式的视频 ...

  9. Python调用7zip命令实现文件批量解压

    Python调用7zip命令实现文件批量解压 1.输入压缩文件所在的路径 2.可以在代码中修改解压到的文件路径和所需要解压的类型,列入,解压文件夹下面所有的mp4格式的文件 3.cmd 指的就是Pyt ...

随机推荐

  1. _quest_random

    -- 随机任务-- 可以实现玩家随机获取任务-- 小技巧:需要控制物品法防,在_function_menu表配置物品indexID为28 `comment`备注 `questId`任务ID `chan ...

  2. 【转】Angular学习总结--很详细的教程

    *这篇文章是转来的,做了自己的一点修改,排版.原始出处不明,如涉及原博主版权问题,请及时告知,我将会立即删除*. 1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟 ...

  3. 【分布式搜索引擎】初识Elasticsearch

    一.Elasticsearch是什么? Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎. Elasticsearch是一个实时分布式搜索和分析引擎.它让你以前所未 ...

  4. PXE网络启动无人值守自动安装 centos 全程实录

    PXE网络启动无人值守自动安装 centos 全程实录 http://shayi1983.blog.51cto.com/4681835/1549854/ 搭建Pxe服务器无人听应答全自动安装CentO ...

  5. mysql,Jdbc工具类,只需一条sql实现简单查询

    import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import ...

  6. 一个简单的CD/CI流程思考,续

    经过各种优化,最终一个非常简单的pipeline出现了,图中没有包含单元测试及静态代码检查的部分,有时间补上.至少实现了提交即构建,也能迅速反馈给开发者. 但是最大的问题是,研发团队还是习惯依赖于部署 ...

  7. CentOS7下swap分区创建(添加),删除以及相关配置

    在添加swap分区之前我们可以了解下当前系统swap是否存在以及使用情况,可用: 1. free –h 或 swapon –s 了解硬盘使用情况(一般/dev/vda1为挂载硬盘): 1. df –h ...

  8. CentOS卸载通过yum安装的软件

    以erlang为例:rpa -qa|grep erlang 使用:yum -y remove erlang-* 扩展--查看yum安装软件的路径:rpm -ql erlang-cosFileTrans ...

  9. c# 转换成时间类型

    if (rngFound.Value.ToString().Contains("/")) { closingdate = rngFound.Value; } else if (rn ...

  10. ES6学习笔记(二)—— 通过ES6 Module看import和require区别

    前言 说到import和require,大家平时开发中一定不少见,尤其是需要前端工程化的项目现在都已经离不开node了,在node环境下这两者都是大量存在的,大体上来说他们都是为了实现JS代码的模块化 ...