音视频编码文档.docx
- 文档编号:28392383
- 上传时间:2023-07-13
- 格式:DOCX
- 页数:13
- 大小:146.84KB
音视频编码文档.docx
《音视频编码文档.docx》由会员分享,可在线阅读,更多相关《音视频编码文档.docx(13页珍藏版)》请在冰豆网上搜索。
音视频编码文档
音视频编码说明
1音视频编码参数
1.1音频编码参数
音频编码格式采用AAC格式,其参数设置比较简单,主要设置参数如下:
(1)音频样本格式的设置
c->sample_fmt=AV_SAMPLE_FMT_S16;
sample_fmt是一个enum类型,包含了多种样本格式,样本格式的设置应保持与Android应用层音频采样格式一致。
此处,我们设置为AV_SAMPLE_FMT_S16,Android应用层采样格式也是16位的ENCODING_PCM_16BIT格式。
(2)音频码率设置
c->bit_rate=64000;
此参数为应用层提供参数接口,由应用层根据编码效果来设定。
此处参考值为64000。
(3)音频采样率设置
c->sample_rate=44100;
此参数为应用层提供参数接口,由应用层获取实际机型可用的采样率来决定。
采样率越低,音频效果越差,反之,越好。
音频采样率一般有8000,44100,47250,48000,47250,32000,11025,16000,22050等值,此处参考值为44100HZ,现在基本所有机器都支持44100采样,而且音频效果也很好。
(4)音频通道设置
c->channels=2;
此参数为应用层提供参数接口,根据应用层需求来设置。
当设置1时为单声道模式,设置2时为立体声道模式。
此处参考值为2.
1.2视频编码参数
视频编码参数相对音频编码参数复杂,其中一些参数关系到视频编码的质量和编码速度,为此需要设置一套最优的参数以确保质量和速度达到一个平衡点。
(1)视频编码基本参数设置
<1>DEC_ID_H264;
视频编码格式采用H264格式。
<2>c->width=480;
c->height=480;
width和height两个参数为应用层提供参数接口,根据具体需求来设置编码后视频的大小,即最终视频的width和height。
应用层也可以考虑通过调节width和height的大小来改变视频编码的速度,例如480*320的大小比480*480的大小编码速度快很多。
此处默认是480*480大小。
<3>c->time_base.den=15;
c->time_base.num=1;
这两个参数决定视频播放帧率,即每秒播放多少帧的视频,time_base.num固定为1,time_base.den为应用层提供参数接口。
一般应用层录取视频帧率和播放视频帧率一致。
此参数的设置需要考虑到编码速度的问题,经过反复测试,15帧/s是一个比较合适的值。
<4>c->pix_fmt=AV_PIX_FMT_YUV420P;
视频像素格式,采用AV_PIX_FMT_YUV420P格式。
(2)重要参数设置
以上视频参数是必须设置的基本参数,以下介绍的参数将会直接影响到视频的质量和编码速度。
详细如下:
<1>c->thread_count
编码线程数,将帧分块,由不同的线程去完成。
此参数为应用层提供参数接口,大小需要根据设备CPU核心数来动态设定。
经过反复测试,此处大小设置为thread_count=CPU核心数*1.5时编码速度达到比较好的水平。
<2>opt_set_funcs系列函数的利用
opt_set_funcs系列函数有以下10个:
intav_opt_set(void*obj,constchar*name,constchar*val,intsearch_flags);
intav_opt_set_int(void*obj,constchar*name,int64_tval,intsearch_flags);
intav_opt_set_double(void*obj,constchar*name,doubleval,intsearch_flags);
intav_opt_set_q(void*obj,constchar*name,AVRationalval,intsearch_flags);
intav_opt_set_bin(void*obj,constchar*name,constuint8_t*val,intsize,intsearch_flags);
intav_opt_set_image_size(void*obj,constchar*name,intw,inth,intsearch_flags);
intav_opt_set_pixel_fmt(void*obj,constchar*name,enumAVPixelFormatfmt,intsearch_flags);
intav_opt_set_sample_fmt(void*obj,constchar*name,enumAVSampleFormatfmt,intsearch_flags);
intav_opt_set_video_rate(void*obj,constchar*name,AVRationalval,intsearch_flags);
intav_opt_set_channel_layout(void*obj,constchar*name,int64_tch_layout,intsearch_flags);
我们可以在ffmpeg源码库libavutil\opt.h查看函数的声明,目前只用到前两个av_opt_set、av_opt_set_int来设置x264里的一些编码参数。
✧av_opt_set(c->priv_data,"preset","ultrafast",0);
通过preset参数可以设置编码速度的等级,preset的级别有ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo,从快到慢。
其实,这里的每个参数都是由一组x264参数设置组合而成。
例如ultrafast参数是由以下参数设置组合的:
-ultrafast:
\n"
"--no-8x8dct--aq-mode0--b-adapt0\n"
"--bframes0--no-cabac--no-deblock\n"
"--no-mbtree--media--no-mixed-refs\n"
"--partitionsnone--rc-lookahead0--ref1\n"
"--scenecut0--subme0--trellis0\n"
"--no-weightb--weightp0\n"
这些参数可以在x264源码库里x264.c文件中查看到。
大部分参数的含义可以参看或者.
preset参数为应用层也提供了参数接口,应用层根据编码速度和质量的进行选取合适的等级。
经过反复测试,设置为ultrafast这个值,再配合其他参数参考值能达到最优效果。
✧av_opt_set(c->priv_data,"x264opts","force-cfr",0);
设置force_crf参数,此参数是设置tune参数zerolatency值中挖掘出来的。
Zerolatency参数也是由一组参数组合而成,能起到的作用是解决延迟问题,实现实时编码。
其组合参数如下:
-zerolatency:
\n"
"--bframes0--force-cfr--no-mbtree\n"
"--sync-lookahead0--sliced-threads\n"
"--rc-lookahead0\n"
其中有的参数与ultrafast中的参数重复,经过反复测试,设置force_crf和设置tune值为zerolatency效果是一样的。
✧av_opt_set_int(c->priv_data,"qp",qpValue,0);
其中qpValue是一个int类型的值,qp表示固定量化因子,取值范围0到51。
经常取值在20-40之间,越小质量越好,要求的码率越高,0表示无损压缩。
此参数为应用层提供了参数接口,应用层根据视频质量和编码速度来选取合适的大小。
经过反复测试,取值25能达到质量和速度的平衡。
码率控制的方法有三种,出了qp控制方法外还有bitrate及crf方法。
三种码率控制方法见下表1.
控制方法
qp
bitrate
crf
默认值
无
无
23
说明
设置x264使用固定量化参数模式。
给定的数量将被作为P帧的量化参数,I帧和B帧的量化参数由–ipratioand–pbratio参数进一步算出。
QP模式适用固定的量化参数,这意味着最终的文件大小是不可知的(可以通过一些其他方法预测)。
设置为0将产出无损的输出。
相同视觉质量时,QP模式产出的文件比crf模式大。
QP模式将关闭自适应量化器,因为它是固定QP的。
这个选项和–bitrate和–crf是互斥的,三者只能选一个。
一般而言crf都能代替QP模式,不过QP因为完全不需要预测所以它会运行地更快些。
设置x264使用固定目标比特率模式。
固定目标比特率意味着最终文件的大小是可知的,但是目标的质量是不可知的。
x264会试图让最终文件的整体码率与给定的码率相等。
通常这个选项和–pass选项配合进行2趟编码。
这个选项和–qp和–crf是互斥的,三者只能选一个。
固定ratefactor。
QP是固定量化器,bitrate是固定文件大小,crf则是固定“质量”。
crf可以提供跟QP一样的视觉的质量,但是文件更小。
crf的单位是ratefactor。
crf是通过降低那些“不那么重要”的帧的质量做到这一切的。
“不那么重要”意思是过于耗费码率又难以用肉眼察觉的帧,比如复杂或者超高速运行的场景。
省下来的码率会用在其它更有效的帧里。
crf编码比2趟编码快,因为它相当于省略了第1趟编码。
所以crf的最终码率也是不可预测的。
项目中参考值
25
W*h*15*2*0.07
无
表1.三种码率控制方法对比
说明:
起初使用的码率控制方法是bitrate固定码率的方法,其取值为W*h*15*2*0.07是参考doubango计算方法,其中w是视频图像的宽,h是视频图像的高,15是帧率,2是中等质量等级,0.07一个权重系数,经过反复测试取此值达到速度与质量平衡时的速度并不是非常满意,为了寻求更快的编码速度,测试了qp方法和crf方法。
测试crf方法采用默认值23时,速度比较慢,取值增大时质量也变得很差,因此没有找打一个好的平衡点,舍弃了此种方法。
最终选取了qp控制方法,当取值为25时,在1.2GHZ双核CPU测试手机(本文中提到的测试都是基于此设备的)上速度和质量达到预想效果,速度接近15帧/s。
在开发中,这三种码率控制的方法应该根据实际需求来选取。
1.3编码参数设置总结
对于音频参数的设置比较简单,视频参数的设置比较难,主要是因为要考虑到视频编码速度的问题。
虽然之后的编码处理方面也会有些问题会影响编码速度,但是设置好了编码参数也就成功了一大半了。
这些参数的设置都要根据实际的需求来设置,在没有经验的情况下需要反复的测试,找到最合适的参数值。
2编码
设置完编码参数和初始化其他工作后,就可以把采集的音视频数据进行编码了。
音频编码比较简单,在此不用介绍,下面主要介绍视频的编码工作。
2.1视频编码的需求
视频编码的需求如下:
a.将移动设备采集来的视频数据像素格式转变为AV_PIX_FMT_YUV420P类型的格式;
b.对视频图像大小进行裁剪成目标图片大小;
c.当设备由横屏变为竖屏录像时,需要对视频图像进行旋转操作;
d.最后对处理好的视频数据进行真正的编码,并写入文件。
2.2像素格式转换
(1)YUV420格式简介
YUV主要用于优化彩色视频信号的传输,使其向后相容老式黑白电视。
与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。
其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。
如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。
其主要的采样格式有YCbCr4:
2:
0、YCbCr4:
2:
2、YCbCr4:
1:
1和YCbCr4:
4:
4。
,在此,只介绍项目用到的YCbCr4:
2:
0。
4:
2:
0表示2:
1的水平取样,没有垂直采样。
现以图1来直观地表示描述YUV420的采样方式,其中以黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量例。
图1.YUV420采样图
由图可见,YUV4:
2:
0采样,每四个Y共用一组UV分量。
由此可计算出YUV420的存储大小,如640*480大小的图像其存储大小为(640*480*3)>>1字节,即1.5倍的width*height。
其中,Y分量:
(640*480)个字节;U(Cb)分量:
(640*480>>2)个字节;V(Cr)分量:
(640*480>>2)个字节。
(2)YUV420SP格式转YUV420P格式
YUV420SP格式与YUV420P格式都是属于YUV420的格式,它们所占存储空间大小都是width*height*1.5,所不同的是UV两个分量的存储结构。
例如一个分辨率为8*4的YUV图像,其存储结构分别如图2、图3所示。
图2.YUV420SP格式存储结构图
图3.YUV420P格式存储结构图
由图2、图3可以清楚的看到,Y分量的存储方式是一样的,但UV两个分量在420SP格式和420P格式中存储方式完全不一样。
在420SP中,UV是交替出现的,而在420P中UV是U分量存储完后再存储V分量。
分析清楚了不同之处,然后将420SP转换为420P格式将会很简单。
其转换算法代码如下:
voidYUV420SPToYUV420P(uint8_t*yuv420sp,uint8_t*yuv420,intwidth,intheight)
{
intPixelsCount=width*height;
inti=0,j=0;
if(yuv420sp==NULL||yuv420==NULL)
{
return;
}
//copyY
for(i=0;i { *(yuv420+i)=*(yuv420sp+i); } //copyCb(U) i=0; for(j=0;j { *(yuv420+(i+PixelsCount*5/4))=*(yuv420sp+(j+PixelsCount)); i++; } //copyCr(V) i=0; for(j=1;j { *(yuv420+(i+PixelsCount))=*(yuv420sp+(j+PixelsCount)); i++; } } (3)项目中的应用 在Android移动设备中,默认的像素采样格式为YCbCr_420_SP即YUV420SP格式,不过在APIlevel8时用NV21格式来代替了。 NV21也属于YUV420格式,经过测试,其采样结构与YUV420SP是一致的。 Android设备摄像头采样还有其他像素格式,如RGB等。 但是最通用的采样格式还是420SP,经过测试,其他格式的采样图像会出现不兼容情况。 因此本项目android应用层中采用的是YUV420SP格式。 然而,查看ffmpeg源码库里像素支持的格式时发现,并没有与YUV420SP对应的格式,只有YUV420P格式与其最接近,存储大小一致,这样格式转换也比较容易。 Ffmpeg库提供了一个通用的图像格式转换大小转换的方法,如下: intsws_scale(structSwsContext*c,constuint8_t*constsrcSlice[], constintsrcStride[],intsrcSliceY,intsrcSliceH, uint8_t*constdst[],constintdstStride[]); 第一个参数是是由sws_getContext方法获得,第二个参数和第六个参数分别是指向转换前与转换后的buffer,第三个参数和第七个参数分别是转换前与转换后的linesize大小,第四个参数设置为0,第五个参数是原图像的高度。 调用此方法可以很方便的进行像素格式的转换以及图片大小的转换,通过查看ffmpeg源码库里swscale.c文件中sws_scale方法的定义,正如前面所说,它是一个通用的格式转换方法,为了保证通用,因此设计比较复杂,考虑比较全面,然而在此项目中我们仅仅只需要将YUV420SP转换为YUV420P格式。 为了提高性能和整个编码速度必须为YUV420SP转换YUV420P提供一个专门的转换方法,即 (2)中提出的方法。 经过测试,使用专门的转换方法比调用ffmpeg库里的sws_scale方法150帧的视频时间上节约了近2秒。 当图片大小更大时,sws_scale方法时间将会花费更久。 因此本项目最终选择 (2)中的转换方法。 2.3视频裁剪 在2.2节中提到了sws_scale方法可以转换图像的大小,但当采样图像大小比较大而最终生成的大小比较小时,生成的图像很明显被压缩了。 为了保证生成的图像不失真,必须用裁剪的方法而不能采样压缩的方法。 查看ffmpeg库,发现av_picture_crop方法可以满足需求。 intav_picture_crop(AVPicture*dst,constAVPicture*src, enumAVPixelFormatpix_fmt,inttop_band,intleft_band); 其中top_band、left_band两个参数表示裁剪时从图像左上角进行多少像素的裁剪。 top_band是高度从上减少多少,left_band是宽度从左减少多少。 为了裁剪出图像中间的部分top_band=(src_heigth-dst_height)/2,left_band=(src_width-dst_width)/2.例如,640*480的图像要裁剪成320*320的图像,其裁剪效果如图4所示。 图4.视频裁剪示意图 2.4视频旋转 Android设备视频采样时是按照宽频来采样的,即设备默认横屏采样的。 后置摄像头横屏采样时图像正常不需旋转,当后置摄像头竖屏录像时,生成的图像需要逆时针旋转90度;前置摄像头横屏时生成的图像正常,竖屏时生成的图像需要逆时针旋转270度,即顺时针旋转90度。 经过测试发现,如果以被拍摄物的角度看前置和后置生成的图像都是顺时针旋转90,因为前置摄像头拍摄的图片是镜像的。 在数据存储上,后置竖屏顺时针旋转90度,前置竖屏逆时针旋转90度。 其旋转示意图分别如图5、图6所示。 图5.后置摄像头生成图片顺时针旋转90度示意图 图6.前置摄像头生成图片逆时针旋转90度示意图 由以上旋转示意图可以得出后置竖屏旋转方法如下所示: for(i=0;i<(int)(srcw);i++){ for(j=srch-1;j>=0;j--){ (dstdata)[newx++]=(srcdata)[j*(srcw)+i]; } } 前置竖屏旋转方法如下所示: for(i=1;i<=(int)(srcw);i++){ for(j=1;j<=(int)(srch);j++){ (dstdata)[newx++]=(srcdata)[j*(srcw)-i]; } } 在项目中,为了与用户的视觉角度一致,后置竖屏旋转方法名为rot90_video,前置竖屏旋转方法名为rot270_video. 2.5编码 前面所有工作完成后,就是真正的调用ffmpeg库里的avcodec_encode_video2方法来编码了。 但是要看整个编码效率必须得计算像素格式转换时间、裁剪时间、旋转时间、avcodec_encode_video2编码时间、视频数据写入文件时间以及其他时间,其他时间是正在编码时CPU消耗的其他时间,例如线程等待等。 因此,计算编码效率的公式为: 总共时间即为项目中是write_video_frame方法从开始到结束的时间。 2.6编码小结 在编码这部分,特别是视频编码这部分,它是整个项目的核心,判断编码效率的好坏也在此部分。 因此,在此部分必须进行各种优化以提高编码的效率。 例如,像素格式转换不用通用的sws_scale方法而是换用专门针对YUV420SP转YUV420P的方法,代码上去掉没必要的判断等等。 当然,这些优化还需要有一套好的编码参数为基础,这样才能从整体提高编码的效率。 目前经过反复测试,本项目基本达到一定的编码要求。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 视频 编码 文档
![提示](https://static.bdocx.com/images/bang_tan.gif)