文档章节

fmpeg利用libav库把yuv视频流转换为TS串流

jane1009
 jane1009
发布于 2017/03/21 17:14
字数 1559
阅读 33
收藏 0

 

 

原文  http://blog.csdn.net/littlethunder/article/details/9164929

 

        今天到月末了,才发我这个月的第一篇文章,因为这个月前三周一直在看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://www.tuicool.com/articles/Z3ia6b

共有 人打赏支持
jane1009
粉丝 0
博文 4
码字总数 0
作品 0
视音频数据处理入门:UDP-RTP协议解析

===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB、YUV像素数据处理 视音频数据处理入门:PCM音频采样数据处理 视音频数据处理...

leixiaohua1020
2016/01/31
0
0
Android NDK开发之旅30--FFmpeg视频播放

1.播放多媒体文件步骤 通常情况下,我们下载的视频文件如MP4,MKV、FLV等都属于封装格式,就是把音视频数据按照相应的规范,打包成一个文本文件。我们可以使用MediaInfo这个工具查看媒体文件...

香沙小熊
2017/12/08
0
0
Android NDK开发之旅28--NDK--音视频基础知识与FFmpeg配置

音视频基础知识 视频播放器原理 一个最简单的视频播放器的过程(不包括视频加密等等过程): 视频播放器原理.jpg 这是一个视频播放的最基本的原理流程图,从这个图可以很整体得看到视频处理的...

香沙小熊
2017/12/04
0
0
007lizhen/摄像头视频采集与存储系统

摄像头视频采集与存储系统 项目介绍 主要利用FFmpeg和Qt实现摄像头视频流的采集与本地存储,将摄像头对的视频流显示到界面上,并存储到本地为.avi格式。 主要转换思路:视频流rtsp--->yuv--...

007lizhen
07/10
0
0
我的开源视音频项目汇总

本文汇总一下自己视音频编解码学习方面的开源项目。这些开源项目大体上可以分成专业领域程序,FFmpeg示例程序,FFmpeg移植程序,多媒体项目示例程序,视音频编解码原理学习工程几个类别。这些...

leixiaohua1020
2015/01/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

这些Spring中的设计模式,你都知道吗?

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。 Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行...

Java填坑之路
31分钟前
1
0
Spring Aop原理之Advisor过滤

在上文(Spring Aop之Advisor解析)中我们讲到,Spring Aop对目标bean的代理主要分为三个步骤:获取所有的Advisor,过滤当前bean可应用的Advisor和使用Advisor为当前bean生成代理对象,并且上文...

爱宝贝丶
42分钟前
0
0
JMockit学习教程

1 JMockit中文网 我觉得如果仅仅是开发自测的话,把JMockit中文网认真看一遍,就可以在项目中使用JMockit了。 http://jmockit.cn/index.htm 2 JMockit中文教程 官方文档中文版。对于不喜欢看...

SuperHeroes
54分钟前
0
0
Linux服务器几乎从不采用Arch Linux?

我们见得多的Linux服务器系统一般都是什么Ubuntu Server啊,什么Cent OS啊,什么Fedora啊,或者企业采用的Red Hat啊,为什么几乎没有Arch Linux呢?下面我将从若干个方面指出Arch Linux在服务...

linux-tao
今天
0
0
js 函数柯里化 闭包

参考 https://mp.weixin.qq.com/s/GEHL3jarDdAAcr5tQGjmDg 一个统计求和的函数 需要知道整个数组的信息,然后遍历求值 function countMoney() { let money = 0 // 温馨提示:arguments...

阿豪boy
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部