转载地址:http://blog.csdn.net/bikeytang/article/details/51491139

利用FFMPEG命令进行文件分割

ffmpeg -ss 00:00:00 -i input.mp4 -c copy -t 60 output.mp4

-ss 表示视频分割的起始时间,-t 表示分割时长,同时也可以用 00:01:00表示

注意 :-ss 要放在 -i 之前

对于普通的视频分割这个命令可能够用了

但是

如果你想要连续风格一段视频,简单的使用此命令就会发现一个问题:连续分割的视频之间存在细微的交集

原因:

视频的开始都是一个关键帧,如果视频的第一帧不是关键帧就会导致视频播放的前面简短画面模糊不清,所以为了让视频不会出现开始画面模糊的情况,就会从所开始时间定位到其对应帧,如果该帧不是关键帧,则在其位置附近找关键帧的位置,然后从该关键帧处开始复制视频帧。

  • 根据起始时间定位到的帧不是关键帧,而是位于两个关键帧中间的B帧或P帧上,那么是从前一个关键帧开始还是后一个关键帧开始呢?

  • 截至时间定位的帧同样可能处于非关键帧处,这时候不一定要向两边找关键帧?

这时候起始帧如果找前面的关键帧作为起始帧开始复制,就会导致本段视频的和前面视频有重复帧:重复帧数为起始关键帧和上一段截至帧之间的帧数。

如果起始帧找后面的关键帧开始复制,就会导致两段连续分割的视频可能出现跳帧现象


利用ffmpeg提供的库自己实现不重复不跳帧分割


利用上述分析,我们在分割的时候自己统一设置分割视频的截止帧为截止时间对应帧(假设此帧为非关键帧,否则为此帧的前一帧)附近前面关键帧的前一帧,而下一段分割视频就从该关键帧开始。

关键代码

视频头信息设置

    AVOutputFormat *ofmt = NULL;int ret;ofmt = ofmtCtx->oformat;for (int i = 0; i < ifmtCtx->nb_streams; i++) {//根据输入流创建输出流AVStream *in_stream = ifmtCtx->streams[i];AVStream *out_stream = avformat_new_stream(ofmtCtx, in_stream->codec->codec);if (!out_stream) {return false;}//复制AVCodecContext的设置ret = avcodec_copy_context(out_stream->codec, in_stream->codec);if (ret < 0) {return false;}out_stream->codec->codec_tag = 0;if (ofmtCtx->oformat->flags & AVFMT_GLOBALHEADER)out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;}if (!(ofmt->flags & AVFMT_NOFILE)) {ret = avio_open(&ofmtCtx->pb, out_filename.c_str(), AVIO_FLAG_WRITE);if (ret < 0) {return false;}}ret = avformat_write_header(ofmtCtx, NULL);if (ret < 0){return false;}return true;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

帧拷贝

//param splitSeconds 为视频分割的时长
bool executeSplit(unsigned int splitSeconds)
{AVPacket readPkt, splitKeyPacket;int ret;av_register_all();if ((ret = avformat_open_input(&ifmtCtx, inputFileName.c_str(), 0, 0)) < 0) {return false;}if ((ret = avformat_find_stream_info(ifmtCtx, 0)) < 0) {return false;}for (int i = 0; i < ifmtCtx->nb_streams; i++) {AVStream *in_stream = ifmtCtx->streams[i];if (in_stream->codec->codec_type == AVMEDIA_TYPE_VIDEO){video_index = i;}}int den = ifmtCtx->streams[video_index]->r_frame_rate.den;int num = ifmtCtx->streams[video_index]->r_frame_rate.num;float fps = (float)num / den;unsigned int splitVideoSize = fps*splitSeconds;string save_name;save_name = outputFileName.substr(0, outputFileName.find_last_of("."));string temp_name = save_name + "0"+suffixName;avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, temp_name.c_str());if (!ofmtCtx) {return false;}if (!writeVideoHeader(ifmtCtx, ofmtCtx, temp_name)){return false;}vector<uint64_t> vecKeyFramePos;uint64_t frame_index = 0;uint64_t keyFrame_index = 0;int frameCount = 0;//读取分割点附近的关键帧位置while (1){++frame_index;ret = av_read_frame(ifmtCtx, &readPkt);if (ret < 0){break;}//过滤,只处理视频流if (readPkt.stream_index == video_index){++frameCount;if (readPkt.flags&AV_PKT_FLAG_KEY){keyFrame_index = frame_index;}if (frameCount>splitVideoSize){vecKeyFramePos.push_back(keyFrame_index);frameCount = 0;}}av_packet_unref(&readPkt);}avformat_close_input(&ifmtCtx);ifmtCtx = NULL;//为了重新获取avformatcontextif ((ret = avformat_open_input(&ifmtCtx, inputFileName.c_str(), 0, 0)) < 0) {return -1;}if ((ret = avformat_find_stream_info(ifmtCtx, 0)) < 0) {return -1;}int number = 0;av_init_packet(&splitKeyPacket);splitKeyPacket.data = NULL;splitKeyPacket.size = 0;//时长对应的帧数超过视频的总视频帧数,则拷贝完整视频if (vecKeyFramePos.empty()){vecKeyFramePos.push_back(frame_index);}vector<uint64_t>::iterator keyFrameIter = vecKeyFramePos.begin();keyFrame_index = *keyFrameIter;++keyFrameIter;frame_index = 0;int64_t lastPts = 0;int64_t lastDts = 0;int64_t prePts = 0;int64_t preDts = 0;while (1){++frame_index;ret = av_read_frame(ifmtCtx, &readPkt);if (ret < 0){break;}av_packet_rescale_ts(&readPkt, ifmtCtx->streams[readPkt.stream_index]->time_base, ofmtCtx->streams[readPkt.stream_index]->time_base);prePts = readPkt.pts;preDts = readPkt.dts;readPkt.pts -= lastPts;readPkt.dts -= lastDts;if (readPkt.pts < readPkt.dts){readPkt.pts = readPkt.dts + 1;}//为分割点处的关键帧要进行拷贝if (readPkt.flags&AV_PKT_FLAG_KEY&&frame_index == keyFrame_index){av_copy_packet(&splitKeyPacket, &readPkt);}else{ret = av_interleaved_write_frame(ofmtCtx, &readPkt);if (ret < 0) {//break;}}if (frame_index == keyFrame_index){lastDts = preDts;lastPts = prePts;if (keyFrameIter != vecKeyFramePos.end()){keyFrame_index = *keyFrameIter;++keyFrameIter;}av_write_trailer(ofmtCtx);avio_close(ofmtCtx->pb);avformat_free_context(ofmtCtx);++number;char num[10];_itoa_s(number, num, 10);temp_name = save_name + num + suffixName;avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, temp_name.c_str());if (!ofmtCtx) {return false;}if (!writeVideoHeader(ifmtCtx, ofmtCtx, save_name + num + suffixName)){return false;}splitKeyPacket.pts = 0;splitKeyPacket.dts = 0;//把上一个分片处的关键帧写入到下一个分片的起始处,保证下一个分片的开头为I帧ret = av_interleaved_write_frame(ofmtCtx, &splitKeyPacket);}av_packet_unref(&readPkt);}av_packet_unref(&splitKeyPacket);av_write_trailer(ofmtCtx);avformat_close_input(&ifmtCtx);avio_close(ofmtCtx->pb);avformat_free_context(ofmtCtx);return true;
}

利用FFMPEG进行视频分割相关推荐

  1. ffmpeg 将视频分割为小段

    目录 1. 先看一下分割结果 2. MAC安装ffmpeg 3. ffmpeg视频分割命令介绍 4.编写java程序 (1). 调用: (2). 视频分割的java工具类 5.参考: 1. 先看一下分 ...

  2. 利用FFmpeg制作视频序列

    前言 本文介绍了利用FFmpeg进行视频测试序列制作的方法.所谓测试序列就是将若干个不同场景的视频片段,按照不同的分辨率.码率.编码方法等进行处理,然后拼接成一条长视频,供测试者打分.一般包括以下几个 ...

  3. 利用FFmpeg进行视频文件进行分割

    利用FFMPEG命令进行文件分割 ffmpeg -ss 00:00:00 -i input.mp4 -c copy -t 60 output.mp4 -ss 表示视频分割的起始时间,-t 表示分割时长 ...

  4. 利用ffmpeg对视频文件进行分析几例

    1.将视频文件转换为jpg图片文件序列: ffmpeg -i /home/czl/WorkSpace/ffmpeg/H264_REC.raw -r 1 -q:v 2 -f image2 pic-%03 ...

  5. Mac OS中利用ffmpeg为视频添加字幕

    Mac系统下,利用ffmpeg加字幕 字幕类型 硬字幕,类似视频水印,作为视频的一部分内嵌了. 软字幕,封装字幕,也是内嵌到视频里,不过只是作为渲染,而且需要播放器支持才行. 外挂字幕,就是外部字幕文 ...

  6. 利用ffmpeg替换视频的背景音乐并改变视频标题部分

    这两天又遇到一个朋友的问题,这里跟大家共享一下我利用ffmpeg的解决方法 将一个带音乐的视频的声音,消除其背景音乐,替换为另一个伴奏音乐 同时将将视频前部的15秒标题部分替换为一张标题图片 原料是一 ...

  7. 【.net】利用FFmpeg获取视频截图

    目标及工具 这里使用vb.net结合FFmpeg截取视频中的图片.本文使用的编程工具是Visual Studio Community 2022,这个版本是在官方下载的安装的纯免费使用,而且基本功能都可 ...

  8. 利用FFmpeg将视频格式.avi转换成.yuv形式

    ffmpeg -i 视频名.avi -pix_fmt yuv420p -s 1280x720 -ss 00:00:03 -t 00:00:01 -y 视频名.yuv 其中-pix_fmt yuv420 ...

  9. 利用FFmpeg切割视频

    关键词:FFmpeg,seek,ss,t,to,搜索,定位 介绍 如果你想要从输入文件中切割一部分,需要用到ss选项. 快速定位 需要将ss放在输入文件的前面(即-i的前面) ffmpeg-ss 00 ...

最新文章

  1. springboot自定义jar通过enable配置是否开启
  2. python空值填充为固定值_Python基础:numpy中空值怎样设置
  3. 树莓派远程连接的三种方式总结
  4. python命令提示符窗口在哪里_详解python命令提示符窗口下如何运行python脚本
  5. pythonscrapy爬虫_零基础写python爬虫之使用Scrapy框架编写爬虫
  6. 整合框架过程记录日志
  7. openssl漏洞检查
  8. python实现英文新闻摘要自动提取_Automotive Innovation摘要集系列2:Intelligent and Connected Vehicles...
  9. nginx php 防止跨站,Nginx下多网站单独php-fpm进程目录权限防跨站
  10. 控件进阶 编辑学生的窗体
  11. 跨域iframe高度自适应(兼容IE/FF/OP/Chrome)
  12. ADF12C 一个应用读多个数据库的数据
  13. 斯坦福后空翻机器人设计、代码全开源
  14. 快速了解WordNet
  15. c语言float m1 m2什么意思,M0、M1、M2的涵义及其作用
  16. 如何读懂 MySQL rw-lock 锁的统计信息
  17. 虚拟机教程(一) 启用win10自带虚拟机
  18. 算法-使用双指针遍历删除链表节点
  19. HDU 1870 愚人节的礼物
  20. 数据分析必备 | 逻辑思维分析方法

热门文章

  1. S60 V3手机软件的点点滴滴
  2. Glide 加载网络图片,图片地址不变,图片字段变更时,图片不加载的问题。
  3. ShardingSphere 社区祝大家端午安康
  4. 2008年最经典的局域网聊天视频会议软件(不要错过)
  5. golang美国纽约时间
  6. 【弄nèng - Activiti6】Activiti6入门篇(十)—— 脚本任务
  7. SFTP秘钥的方式登录与LFTP
  8. ZJOI2018二试游记
  9. echarts的legend设置width不生效
  10. 运动会加油稿计算机学院,大学运动会加油稿大全