一、啰嗦几句

好几年不写博客了,一是工作计算机都加密了没法编辑提交;二是各种语言混用,什么都会就是什么都不会,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%),非常稳定,无异常崩溃退出,视频无马赛克、前后视频衔接很棒。

七、总结

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

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

关于使用ffmpeg的一些牢骚的更多相关文章

  1. FFmpeg学习6:视音频同步

    在上一篇文章中,视频和音频是各自独立播放的,并不同步.本文主要描述了如何以音频的播放时长为基准,将视频同步到音频上以实现视音频的同步播放的.主要有以下几个方面的内容 视音频同步的简单介绍 DTS 和 ...

  2. FFmpeg 中AVPacket的使用

    AVPacket保存的是解码前的数据,也就是压缩后的数据.该结构本身不直接包含数据,其有一个指向数据域的指针,FFmpeg中很多的数据结构都使用这种方法来管理数据. AVPacket的使用通常离不开下 ...

  3. FFmpeg + SoundTouch实现音频的变调变速

    本文使用FFmpeg + SoundTouch实现将音频解码后,进行变调变速处理,并将处理后的结果保存为WAV文件. 主要有以下内容: 实现一个FFmpeg的工具类,保存多媒体文件所需的解码信息 将解 ...

  4. 用ffmpeg快速剪切和合并视频

    如果直接找视频剪切和合并视频的软件,通常出来的都是大的视频编辑软件或者是有图形界面的剪切软件,大型一点的功能太多安装麻烦,小型一点的功能可能不齐全. 只是简单的剪切或者一下合并一下,还是ffmpeg这 ...

  5. ffmpeg用法及如何使用fluent-ffmpeg

    http://ffmpeg.org/ 官网 ffmpeg(命令行工具) 是一个快速的音视频转换工具. 1.分离视频音频流 ffmpeg -i input_file -vcodec copy -an o ...

  6. FFmpeg学习4:音频格式转换

    前段时间,在学习试用FFmpeg播放音频的时候总是有杂音,网上的很多教程是基于之前版本的FFmpeg的,而新的FFmepg3中audio增加了平面(planar)格式,而SDL播放音频是不支持平面格式 ...

  7. FFmpeg学习5:多线程播放视音频

    在前面的学习中,视频和音频的播放是分开进行的.这主要是为了学习的方便,经过一段时间的学习,对FFmpeg的也有了一定的了解,本文就介绍了 如何使用多线程同时播放音频和视频(未实现同步),并对前面的学习 ...

  8. FFmpeg数据结构:AVPacket解析

    本文主要从以下几个方面对AVPacket做解析: AVPacket在FFmpeg中的作用 字段说明 AVPacket中的内存管理 AVPacket相关函数的说明 结合AVPacket队列说明下AVPa ...

  9. FFmpeg学习3:播放音频

    参考dranger tutorial,本文将介绍如何使用FFmpeg解码音频数据,并使用SDL将解码后的数据输出. 本文主要包含以下几方面的内容: 关于播放音频的需要的一些基础知识介绍 使用SDL2播 ...

随机推荐

  1. 多线程设置flag标志位实现同步

    信号灯解决同步问题 我尽量注释了代码,可以很容易理解了. package Thread; /** * 信号灯 * 借助标志位 */ public class FlagThread { public s ...

  2. 最近遇到adb connection 问题,总结一下

    最近eclipse总是遇到adb connection问题,网上搜索了一些解决方法,在cmd tool工具下adb kill-server ,adb start-server ,甚至重启都无效.然后我 ...

  3. GeoGebra案例(傅里叶级数的方波)

    傅里叶级数介绍:请移步参见这位马大佬的博文 https://www.matongxue.com/madocs/619.html 马大佬中的gif图在我看来是非常直观且有趣的,奈何本人本领实在有限,学习 ...

  4. mvc传递json数据到view简单实例

    基于extjs4.2 controller //存储数据的类 public class DataLink { public string Name { get; set; } public strin ...

  5. 空间小姐姐生活照,我用python破解加密压缩包,无忧查看

    事情的经过是这样的: 又是奶茶,行吧行吧. 快点开工,争取李大伟回来之前搞定. 李大伟说是6位数字密码 那么我们可以利用python生成全部的六位数字密码 #生成从000000到99999的密码表f ...

  6. 从Generator入手读懂co模块源码

    这篇文章是讲JS异步原理和实现方式的第四篇文章,前面三篇是: setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop 从发布订阅模式入手读懂Node.js的E ...

  7. js输入框练习

    这个就是一个输入框的小练习(也是第一次写这个东西) <!DOCTYPE html> <html lang="en"> <head> <me ...

  8. ES6中对象的扩展

    ES6不仅为字符串.数值和数组带来了扩展,也为对象带来了很多新特性.这一节,我们来一起学习一下对象的扩展. 对象的传统表示法 我们回顾一下,对象的传统表示法: let person = { " ...

  9. 0day堆(1)堆的管理策略

    基本概念 堆块:堆区内存的基本单位 包括两个部分:块首,块身 块首:标识这个堆块自身的信息:如大小,是否被占用等 块身:分配给用户使用的数据区 堆表:一般位于堆区的起始位置,用于索引堆区所有堆块的信息 ...

  10. 异常:由 spring-session pom 引发

    错误异常 Correct the classpath of your application so that it contains a single, compatible version of o ...