ffmpeg利用libav库把yuv视频流转换为TS串流
今天到月末了,才发我这个月的第一篇文章,因为这个月前三周一直在看ffmpeg的libavcodec和libavformat两个库源码。实验室要做一个“小传大”的软件,就是android手机或平板电脑的屏幕包括操作等全映射到电脑或电视上去。这个首先想到的就是用TS串流来做,一来是符合标准规范,音视频同步方便;二来是接收端非常简单,普通能播放网络串流的播放器都可以胜任,大大降低开发难度。于是我就开始看ffmpeg的libav库,如下是我的小体会。
ffmpeg库的框架非常漂亮,接口函数在几个主要的头文件中,如avformat.h,avcodec.h等,内部静态函数虽然调用层次非常纷繁复杂,但是命名规范,层次也非常清晰,看起来只要自己不乱,那是非常爽的,这个必须赞一下先哈。如果只是编解码的话,只要调用avcodec.h里面的接口函数就足够了,关于编码有两个结构体,AVCodecContext和AVCodec。AVCodecContext结构体里面的成员是编解码器的一些参数,codec_type,codec_id,width,height,bit_rate,time_base,pix_fmt这些,其中前两个在avcodec_alloc_context3(codec)函数初始化的时候自动赋值,其实也就是用的其参数AVCodec *codec里面设置的值;后面的几个参数要用户自己赋值。AVCodec结构体是由函数avcodec_find_encode(CODEC_ID)来初始化的,这一步通过用户传入的参数CODEC_ID,比如AV_CODEC_ID_MJPEG,不仅把type和id赋了值(这俩就是在AVCodecContext初始化时传入的值),而且把encode等这些函数指针也都赋了值,指向了相应的编解码函数。当做完两个结构体的初始化后,就可以编码了。但是yuv文件和编完码后的码流存在哪里?这就用到ffmpeg的AVFrame和AVPacket两个结构体。有时候也可以用AVPicture来存yuv裸数据,毕竟AVPicture只是AVFrame的子集,我就一直用AVFrame了。AVFrame结构体里面除了width和height以及linesize后,就是一个8个元素的指针数组:data[8],我不知道为啥要给8个,即使是BGRA格式也只用4个哈,这就不管了,现在用YUV420P只占用3个,即data[0]->Y,data[1]->U,data[2]->V。好了,初始化工作完成后,调用avcodec_encode_video2函数就妥了,然后直接从AVPacket结构体里取编成你设置好的格式的码流就行了。
关键要说的不是上面的这些,因为我3个星期才看出这点玩意就太山寨了。我要把yuv编成ts流,当初不知道,直接上面的步骤只是把CODEC_ID设为AV_CODEC_ID_MPEG2TS,结果各种报错,当时我世界观就踏了,到处发贴问,但都石沉大海,木有人回应,不知道是大家都不做TS流编码还是怎么着。当我再回过头仔细看源码并且看TS的标准18030之后,才发现是怎么一回事。TS流就是个容器,可以包mpeg2或h264等ES流,所以如果要编码TS流就要经过两步,第一步是编码成mpeg2或h264,第二步封装成TS流,后者就是libavformat要干的事儿,这就引出了下面的结构体:AVFormatContext,AVOutputFormat和AVStream。AVFormatContext结构体是标准的始祖,太全了,包罗万象,用avformat_alloc_context()初始化,捎带把AVOutputFormat也初始化了,这个结构体里面的write_header,write_packet,interleave_packet这些函数太重要了,但也就是这里出现了大的问题,我后面说明。AVStream结构体就是保存各种流,如果有音频和视频那么就是两个流。
方是时,正当我高兴的以为做出来了的时候,才发现,av_interleaved_write_frame()函数里一个参数是AVIOContext,就是这个结构体太坑了,给TA初始化的时候要添加文件名,也就是说必须是硬盘上的文件才可以,而我要把yuv做成TS流的目的就是要实时打成RTP包发出去,TA让我先存到硬盘上,再从硬盘上读取到内存中打包发送是怎么个意思??还怎么实时性?!我第一个想到的就是直接从AVIOContext结构体里面把那个指向编玩码的流指针找出来,这样就可以解决,但是又当我欣喜的时候,我才发现,这个AVIOContext里面的buffer指针指向的根本就不是封装好的TS流!!!我再一次进去扒代码,才发现,经过了层层的函数调用后,TA的过程我描述如下:
编好的mpeg2或h264 ES流文件存在AVPacket *pkt中,pkt作为输入传入av_interleaved_write_frame()函数,在里面新实例了一个AVPacket *opkt的局部结构体,当调用mpegts_write_packet_internal()函数的时候,输入参数已经是opkt了,写上TS的头,写上opkt的部分长数据,写入文件,free掉buf指针,再写上TS body的数据,再写入部分opkt数据,写入文件,free掉buf指针,。。。不断循环操作,直到写完为止。这样,这个局部TS流文件指针就压根没有!!如果改库的话在AVIOContext结构体里面新建一个TS流指针,把上面的文件操作全部赋给这个指针,我最后也是可以得到的,但是改库的代价和不可预期的错误太大,我稚嫩的肩膀不能hold住。。。。但临近月末,啥都做不出来太没有工作量了,于是我换了一种简单的思路先凑和解决了,就是yuv编码成jpg然后直接udp传,接收端我用QT写了个界面,实时把接到的图片显示出来。虽然做出来了,但是以后音视频同步还是个问题,我还是认为应该用TS流来做,但具体怎么做我要歇几天以后靠灵感了~也期待大家给点灵感~~:-)
转载请注明: 转自http://blog.csdn.net/littlethunder/article/details/9164929
ffmpeg利用libav库把yuv视频流转换为TS串流的更多相关文章
- Python小工具:利用ffmpy3库3秒钟将视频转换为音频
作者 | pk 哥 来源公众号 | Python知识圈(ID:PythonCircle) 最近,有读者微信上私聊我,想让我写一篇视频批量转换成音频的文章,我答应了,周末宅家里把这个小工具做出来了. 这 ...
- c# 利用动态库DllImport("kernel32")读写ini文件(提供Dmo下载)
c# 利用动态库DllImport("kernel32")读写ini文件 自从读了设计模式,真的会改变一个程序员的习惯.我觉得嘛,经验也可以从一个人的习惯看得出来,看他的代码编写习 ...
- php学习笔记:利用gd库生成图片,并实现随机验证码
说明:一些基本的代码我都进行了注释,这里实现的验证码位数.需要用的字符串都可以再设置.有我的注释,大家应该很容易能看得懂. 基本思路: 1.用mt_rand()随机生成数字确定需要获取的字符串,对字符 ...
- CocoaPods的安装及使用/利用开源库Diplomat实现分享及第三方登录/git的使用
<<史上最简洁版本>> 1.gem sources -l查看 当前的源 //1.1 sudo -i..以下都是以管理员的身份来操作的 2.gem sources --remov ...
- python利用selenium库识别点触验证码
利用selenium库和超级鹰识别点触验证码(学习于静谧大大的书,想自己整理一下思路) 一.超级鹰注册:超级鹰入口 1.首先注册一个超级鹰账号,然后在超级鹰免费测试地方可以关注公众号,领取1000积分 ...
- Android开启相机预览获取Yuv视频流数据
自定义SurfaceView 主要步骤: 实现SurfaceHolder.Callback接口,创建SurfaceView的生命周期 实现Camera.PreviewCallback接口,创建预览回调 ...
- 利用OpenSSL库对Socket传输进行安全加密(RSA+AES)
轉自:http://blog.chinaunix.net/uid-9543173-id-3921143.html 利用OpenSSL库对Socket传输进行安全加密(RSA+AES) 1. 利用RSA ...
- 人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型
人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型 经过前面稍显罗嗦的准备工作,现在,我们终于可以尝试训练我们自己的卷积神经网络模型了.CNN擅长图像处理,keras库的te ...
- mysql内置函数,在mysql里面利用str_to_date()把字符串转换为日期格式
mysql内置函数,在mysql里面利用str_to_date()把字符串转换为日期格式 示例:分隔符一致,年月日要用%号 select str_to_date('2008-4-2 15:3:28', ...
随机推荐
- 全局scope与Isolate scope通信
AngularJS 全局scope与Isolate scope通信 在项目开发时,全局scope 和 directive本地scope使用范围不够清晰,全局scope与directive本地scope ...
- java利用poi导出数据到excel
背景: 上一篇写到利用jtds连接数据库获取对应的数据,本篇写怎样用poi将数据到处到excel中,此程序为Application 正文: 第三方poi jar包:poi驱动包下载 代码片段: /** ...
- Spring Resource之ResourceLoader
ResourceLoader接口意味着任何实现的对象都能够返回Resource实例. public interface ResourceLoader { Resource getResource(St ...
- 转载:你需要知道的16个Linux服务器监控命令
源址:http://web.itivy.com/article-653-1.html 如果你想知道你的服务器正在做干什么,你就需要了解一些基本的命令,一旦你精通了这些命令,那你就是一个 专业的 Lin ...
- JSP中获取jstl中的数据
我们在编程JSP时,有时会须要訪问jstl中的数据,或者说是el表达式中的数据. 比方, <c:forEach varStatus="data1" var=" ...
- 安装SQL Server 2005 - 初学者系列 - 学习者系列文章
初学者阶段,建议从数据库为基础入手进行学习. 下面介绍微软的SQL Server 2005数据库的安装. 首先,从下列地址获取SQL Server 2005的安装程序. ed2k://|file|cs ...
- Solr安装(Tomcat)
Solr安装(Tomcat) 安装环境 Windows 7 64bit Apache-tomcat-8.0.9-windows-x64 Solr-4.9.0 JDK 1.8.0_05 64bit ...
- NServiceBus 入门2
NServiceBus官方文档翻译(二)NServiceBus 入门 在这篇教程中我们将学习如何创建一个非常简单的由客户端向服务端发送消息的订单系统.该系统包括三个项目:Client.Server ...
- 如何打造100亿SDK累计覆盖量的大数据系统
作为推送行业领导者,截止目前个推SDK累计安装覆盖量达100亿(含海外),接入应用超过43万,独立终端覆盖超过10亿 (含海外).个推系统每天会产生大量的日志和数据,面临许多数据处理方面的挑战. 首先 ...
- 动画操作 (Applying Animations) ngAnimate12
动画操作 (Applying Animations) ngAnimate step 12 1.切换目录 git checkout step-12 npm start 2.效果图 这里在点击右边的缩略图 ...