zoukankan      html  css  js  c++  java
  • 关于使用ffmpeg的一些牢骚

    一、啰嗦几句

    好几年不写博客了,一是工作计算机都加密了没法编辑提交;二是各种语言混用,什么都会就是什么都不会,delphi、c#、vb、python、c++要说我精通啥,啥也不精,所以不敢乱写。

    最近做一个关于视频处理的项目,用到ffmpeg,实在是憋不住,在此记录一下摸索的过程。可以毫不夸张的说,网上关于ffmpeg的使用,大部分用命令行方式,调用api方式的很少,而且盲目抄袭甚盛,斗胆妄言,罪过罪过。

    二、感谢

    我是通过学习雷神的博客逐渐掌握了ffmpeg的一些东西,好歹把项目做完了,效果很好,在此向雷神由衷的表示感谢。雷神由浅入深的介绍了ffmpeg的使用方法,有理论有实践,可以说网上的很多文章很难与雷神媲美,而且国内这方面的文章太少了,这么多做视频方面的,怎么就没有这方面的优质文章,在此是个疑点。可惜的是雷神花费了大量时间开放自己的学习探索的心得,当逐步的到达核心地带时,戛然而止,雷神去世了,天妒英才呐。在此沉痛缅怀并致以崇高的敬意!

    在本文中,没有直接可运行的代码,一是加密,无法拷贝;二是提倡动手实践,先把雷神的实例代码挨个学习调试,自会有极大的提高;

    三、项目背景

    核心一句话:接收高清视频流(H264+mp3 TS流),每30分钟存储一个mp4文件,相邻两个文件的播放要顺畅不能丢帧。为啥说是高清呢,30分钟文件就有5个G。

    编程语言c++

    四、踩过的坑

    4.1进程方式

    网上很多文章都是用命令行的,这种方式只能说测试还行,真正项目应用差点意思了,因为你要管理这个进程,他是个什么状态,你不知,但你又不能不管,关键做不到前后两个视频无缝衔接,咋整,鸡肋啊,做个测试、验证等可以,做项目不行。用api吧,资料太少,项目组意见不一,最后举个例子达成一致了,前面有个碉堡,我们明知道用手榴弹不行,还坚持让大家扔手榴弹,这是瞎耽误工夫;拿zha yao肯定行,但是有人得牺牲(扔手榴弹站在远处扔就行,zha yao包得有人扛到跟前),要想彻底解决就得用彻底的办法。所以很多时候我们缺少的就是沉下心的耐力和扛zha yao包的勇气,溃痈虽痛胜于养毒,把雷神用api的例子全部从头调试一遍,总结出流程,都需要哪些要素,时间基、采样率、音视频流是啥用来做啥,搞明白就完事了。

    4.2 ffmpeg rtp

    ffmpeg可以直接接收RTP,也有提供转换MP4的方法,要注意的是接收和处理放在一个线程中有问题,容易丢帧,因为UDP通信必须设置缓存大小,但是一旦处理堵住了,数据绝对会丢失。程序在现场长时间不间断运行,很难保证不出现丢帧的情况,经简单测试,直接抛弃该方式。

    五、我的实现方法

    1、使用UDP方式接收组播视频流,并写入文件中,文件按时间命名。

    2、当检测到够30分钟时,停止写入当前文件,开始写入另一个文件。

    3、通知视频转换线程,处理当前写完的文件。

    4、视频转换线程,读取文件,

    打开输入文件流(avformat_open_input),

    创建输出上下文(avformat_alloc_output_context2),我们要根据文件转成mp4。

    查找视频信息(avformat_find_stream_info),查找输入的码流:视频流、音频流、字幕流。

    根据输入码流创建输出码流,流的参数拷贝就行(avcodec_parameters_copy),特别要注意的是输入输出流的时间基(time_base)。

    打开输出流,写入文件头,设定一个文件结尾的阈值,当输入流剩余字节数小于该值时并且找到最后一个关键帧,则写入到输出流后,将剩余输入文件的结尾置换到下一个文件的开头中,这样前后两个文件无缝衔接,第一个文件最后一个关键帧是第二个文件开头的第一帧,所以无缝衔接了。

    循环读取输入流(av_read_frame)根据流索引确定是音频还是视频流,如果是视频流写入文件的第一帧必须是关键帧。写入时特别注意音频和视频的pkt的时间(pts、dts、duration)需要根据自己的时间基重新换算(av_rescale_q_rnd),并记录第一帧的时间戳pts,换算后的pts和dts要减去第一帧的pts,这样每个文件播放就是从头开始了。写入输出流用av_interleaved_write_frame。

    读取文件转换成mp4,在现场机器(高速缓存设备)上总共需要不到15秒钟。

    六、最终效果

    项目部署5个多月,内存(103M左右,峰值180M)、cpu(3%--8%),非常稳定,无异常崩溃退出,视频无马赛克、前后视频衔接很棒。

    七、总结

    坚持实践就是硬道理,无论什么职位、角色都不能眼高手低。

    抄别人代码一千遍不如自己动手调一遍。

  • 相关阅读:
    HDU4628+状态压缩DP
    Javascript 去掉字符串前后空格的五种方法
    Javascript 数组之判断取值和数组取值
    ASP.NET MVC 出现错误 “The view 'XXX' or its master was not found or no view engine support”
    ASP.NET MVC 页面调整并传递参数
    ASP.NET MV3 部署网站 报"Could not load file or assembly ' System.Web.Helpers “ 错的解决方法
    ASP.NET MVC 控制器向View传值的三种方法
    CSharp 如何通过拼接XML调用存储过程来查询数据
    SQLServer : EXEC和sp_executesql的区别
    关于SQLServer2005的学习笔记—异常捕获及处理
  • 原文地址:https://www.cnblogs.com/shelwinnee/p/12849798.html
Copyright © 2011-2022 走看看