《音视频编码文档.docx》由会员分享,可在线阅读,更多相关《音视频编码文档.docx(15页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、音视频编码说明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)
2、音频采样率设置c-sample_rate = 44100;此参数为应用层提供参数接口,由应用层获取实际机型可用的采样率来决定。采样率越低,音频效果越差,反之,越好。音频采样率一般有8000,44100, 47250, 48000, 47250,32000, 11025, 16000, 22050等值,此处参考值为44100HZ,现在基本所有机器都支持44100采样,而且音频效果也很好。(4)音频通道设置c-channels = 2;此参数为应用层提供参数接口,根据应用层需求来设置。当设置1时为单声道模式,设置2时为立体声道模式。此处参考值为2.1.2视频编码参数视频编码参数相对音频编码参数复杂
3、,其中一些参数关系到视频编码的质量和编码速度,为此需要设置一套最优的参数以确保质量和速度达到一个平衡点。(1)视频编码基本参数设置 DEC_ID_H264;视频编码格式采用H264格式。 c-width = 480;c-height = 480;width和height两个参数为应用层提供参数接口,根据具体需求来设置编码后视频的大小,即最终视频的width和height。应用层也可以考虑通过调节width和height的大小来改变视频编码的速度,例如480*320的大小比480*480的大小编码速度快很多。此处默认是480*480大小。 c-time_base.den = 15;c-time_
4、base.num = 1;这两个参数决定视频播放帧率,即每秒播放多少帧的视频,time_base.num固定为1, time_base.den为应用层提供参数接口。一般应用层录取视频帧率和播放视频帧率一致。此参数的设置需要考虑到编码速度的问题,经过反复测试,15帧/s是一个比较合适的值。 c-pix_fmt = AV_PIX_FMT_YUV420P;视频像素格式,采用AV_PIX_FMT_YUV420P格式。(2)重要参数设置以上视频参数是必须设置的基本参数,以下介绍的参数将会直接影响到视频的质量和编码速度。详细如下: c-thread_count编码线程数,将帧分块,由不同的线程去完成。此参
5、数为应用层提供参数接口,大小需要根据设备CPU核心数来动态设定。经过反复测试,此处大小设置为 thread_count=CPU核心数*1.5时编码速度达到比较好的水平。 opt_set_funcs系列函数的利用opt_set_funcs系列函数有以下10个:int av_opt_set (void *obj, const char *name, const char *val, int search_flags);int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags);int av_opt_s
6、et_double(void *obj, const char *name,double val,int search_flags);int av_opt_set_q(void *obj, const char *name, AVRational val, int search_flags);int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags);int av_opt_set_image_size(void *obj, const char *name, i
7、nt w, int h, int search_flags);int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags);int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags);int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int
8、 search_flags);int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags);我们可以在ffmpeg源码库libavutilopt.h查看函数的声明,目前只用到前两个av_opt_set、av_opt_set_int来设置x264里的一些编码参数。 av_opt_set(c-priv_data, preset, ultrafast, 0);通过preset参数可以设置编码速度的等级,preset的级别有ultrafast、superfast、veryf
9、ast、faster、fast、medium、slow、slower、veryslow、placebo,从快到慢。其实,这里的每个参数都是由一组x264参数设置组合而成。例如ultrafast参数是由以下参数设置组合的:- ultrafast:n -no-8x8dct -aq-mode 0 -b-adapt 0n -bframes 0 -no-cabac -no-deblockn -no-mbtree -me dia -no-mixed-refsn -partitions none -rc-lookahead 0 -ref 1n -scenecut 0 -subme 0 -trellis 0n
10、 -no-weightb -weightp 0n这些参数可以在x264源码库里x264.c文件中查看到。大部分参数的含义可以参看http:/x264-preset参数为应用层也提供了参数接口,应用层根据编码速度和质量的进行选取合适的等级。经过反复测试,设置为ultrafast这个值,再配合其他参数参考值能达到最优效果。 av_opt_set(c-priv_data, x264opts, force-cfr, 0);设置force_crf参数,此参数是设置tune参数zerolatency值中挖掘出来的。Zerolatency参数也是由一组参数组合而成,能起到的作用是解决延迟问题,实现实时编码。
11、其组合参数如下: - zerolatency:n -bframes 0 -force-cfr -no-mbtreen -sync-lookahead 0 -sliced-threadsn -rc-lookahead 0n其中有的参数与ultrafast中的参数重复,经过反复测试,设置force_crf和设置tune值为zerolatency效果是一样的。 av_opt_set_int(c-priv_data, qp, qpValue, 0);其中qpValue是一个int类型的值,qp表示固定量化因子,取值范围0到51。经常取值在20-40之间,越小质量越好,要求的码率越高,0表示无损压缩。此
12、参数为应用层提供了参数接口,应用层根据视频质量和编码速度来选取合适的大小。经过反复测试,取值25能达到质量和速度的平衡。码率控制的方法有三种,出了qp控制方法外还有bitrate及crf方法。三种码率控制方法见下表1.控制方法qpbitratecrf默认值无无23说明设置x264使用固定量化参数模式。给定的数量将被作为P帧的量化参数,I帧和B帧的量化参数由ipratio and pbratio参数进一步算出。QP模式适用固定的量化参数,这意味着最终的文件大小是不可知的(可以通过一些其他方法预测)。设置为0将产出无损的输出。相同视觉质量时,QP模式产出的文件比crf模式大。QP模式将关闭自适应量
13、化器,因为它是固定QP的。这个选项和 bitrate和crf是互斥的,三者只能选一个。一般而言crf都能代替QP模式,不过QP因为完全不需要预测所以它会运行地更快些。设置x264使用固定目标比特率模式。固定目标比特率意味着最终文件的大小是可知的,但是目标的质量是不可知的。 x264会试图让最终文件的整体码率与给定的码率相等。通常这个选项和pass选项配合进行2趟编码。这个选项和 qp和crf是互斥的,三者只能选一个。固定ratefactor。QP是固定量化器,bitrate是固定文件大小,crf则是固定“质量”。crf可以提供跟QP一样的视觉的质量,但是文件更小。crf的单位是ratefact
14、or。crf是通过降低那些“不那么重要”的帧的质量做到这一切的。“不那么重要”意思是过于耗费码率又难以用肉眼察觉的帧,比如复杂或者超高速运行的场景。省下来的码率会用在其它更有效的帧里。crf编码比2趟编码快,因为它相当于省略了第1趟编码。所以crf的最终码率也是不可预测的。项目中参考值25W*h*15*2*0.07无表1.三种码率控制方法对比说明:起初使用的码率控制方法是bitrate固定码率的方法,其取值为W*h*15*2*0.07是参考doubango计算方法,其中w是视频图像的宽,h是视频图像的高,15是帧率,2是中等质量等级,0.07一个权重系数,经过反复测试取此值达到速度与质量平衡时
15、的速度并不是非常满意,为了寻求更快的编码速度,测试了qp方法和crf方法。测试crf方法采用默认值23时,速度比较慢,取值增大时质量也变得很差,因此没有找打一个好的平衡点,舍弃了此种方法。最终选取了qp控制方法,当取值为25时,在1.2GHZ双核CPU测试手机(本文中提到的测试都是基于此设备的)上速度和质量达到预想效果,速度接近15帧/s。在开发中,这三种码率控制的方法应该根据实际需求来选取。1.3编码参数设置总结对于音频参数的设置比较简单,视频参数的设置比较难,主要是因为要考虑到视频编码速度的问题。虽然之后的编码处理方面也会有些问题会影响编码速度,但是设置好了编码参数也就成功了一大半了。这些
16、参数的设置都要根据实际的需求来设置,在没有经验的情况下需要反复的测试,找到最合适的参数值。2编码设置完编码参数和初始化其他工作后,就可以把采集的音视频数据进行编码了。音频编码比较简单,在此不用介绍,下面主要介绍视频的编码工作。2.1视频编码的需求视频编码的需求如下:a. 将移动设备采集来的视频数据像素格式转变为AV_PIX_FMT_YUV420P类型的格式;b. 对视频图像大小进行裁剪成目标图片大小;c. 当设备由横屏变为竖屏录像时,需要对视频图像进行旋转操作;d. 最后对处理好的视频数据进行真正的编码,并写入文件。2.2像素格式转换(1)YUV420格式简介YUV主要用于优化彩色视频信号的传
17、输,使其向后相容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。其主要的采样格式有YCbCr 4:2:0、YCbCr 4:2:2、YCbCr 4:1:1和 YCbCr 4:4:4。,在此,只介绍项目用到
18、的YCbCr 4:2:0。4:2:0表示2:1的水平取样,没有垂直采样。现以图1来直观地表示描述YUV420的采样方式,其中以黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量例。图1. YUV420采样图由图可见,YUV 4:2:0采样,每四个Y共用一组UV分量。由此可计算出YUV420的存储大小,如640*480大小的图像其存储大小为(640*480*3)1字节,即1.5倍的width*height。其中,Y分量:(640*480)个字节;U(Cb)分量:(640*4802)个字节;V(Cr)分量:(640*4802)个字节。(2)YUV420SP格式转YUV420P格式Y
19、UV420SP格式与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格式将会很简单。其转换算法代码如下:void Y
20、UV420SPToYUV420P ( uint8_t * yuv420sp, uint8_t * yuv420, int width, int height ) int PixelsCount = width * height; int i = 0, j= 0; if (yuv420sp= NULL | yuv420 = NULL) return; /copy Y for (i = 0; i PixelsCount; i+) *(yuv420 +i) = *(yuv420sp + i); /copy Cb(U) i = 0; for(j = 0; j PixelsCount/2; j+=2)
21、*(yuv420 +(i+PixelsCount * 5/4) = *(yuv420sp + (j + PixelsCount); i+; /copy Cr(V) i = 0; for (j = 1; j PixelsCount / 2; j+=2) *(yuv420 + (i + PixelsCount) = *(yuv420sp + (j + PixelsCount); i+; (3)项目中的应用在Android移动设备中,默认的像素采样格式为YCbCr_420_SP即YUV420SP格式,不过在API level 8 时用NV21格式来代替了。NV21也属于YUV420格式,经过测试,其
22、采样结构与YUV420SP是一致的。Android设备摄像头采样还有其他像素格式,如RGB等。但是最通用的采样格式还是420SP,经过测试,其他格式的采样图像会出现不兼容情况。因此本项目android应用层中采用的是YUV420SP格式。然而,查看ffmpeg源码库里像素支持的格式时发现,并没有与YUV420SP对应的格式,只有YUV420P格式与其最接近,存储大小一致,这样格式转换也比较容易。Ffmpeg库提供了一个通用的图像格式转换大小转换的方法,如下:int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice, co
23、nst int srcStride, int srcSliceY, int srcSliceH, uint8_t *const dst, const int dstStride);第一个参数是是由sws_getContext方法获得,第二个参数和第六个参数分别是指向转换前与转换后的buffer,第三个参数和第七个参数分别是转换前与转换后的linesize大小,第四个参数设置为0,第五个参数是原图像的高度。调用此方法可以很方便的进行像素格式的转换以及图片大小的转换,通过查看ffmpeg源码库里swscale.c文件中sws_scale方法的定义,正如前面所说,它是一个通用的格式转换方法,为了保证
24、通用,因此设计比较复杂,考虑比较全面,然而在此项目中我们仅仅只需要将YUV420SP转换为YUV420P格式。为了提高性能和整个编码速度必须为YUV420SP转换YUV420P提供一个专门的转换方法,即(2)中提出的方法。经过测试,使用专门的转换方法比调用ffmpeg库里的sws_scale方法150帧的视频时间上节约了近2秒。当图片大小更大时,sws_scale方法时间将会花费更久。因此本项目最终选择(2)中的转换方法。2.3视频裁剪在2.2节中提到了sws_scale方法可以转换图像的大小,但当采样图像大小比较大而最终生成的大小比较小时,生成的图像很明显被压缩了。为了保证生成的图像不失真,
25、必须用裁剪的方法而不能采样压缩的方法。查看ffmpeg库,发现av_picture_crop方法可以满足需求。int av_picture_crop(AVPicture *dst, const AVPicture *src, enum AVPixelFormat pix_fmt, int top_band, int left_band);其中top_band、left_band两个参数表示裁剪时从图像左上角进行多少像素的裁剪。top_band是高度从上减少多少,left_band是宽度从左减少多少。为了裁剪出图像中间的部分top_band=(src_heigth-dst_height)/2,l
26、eft_band=(src_width-dst_width)/2.例如,640*480的图像要裁剪成320*320的图像,其裁剪效果如图4所示。图4. 视频裁剪示意图2.4视频旋转Android设备视频采样时是按照宽频来采样的,即设备默认横屏采样的。后置摄像头横屏采样时图像正常不需旋转,当后置摄像头竖屏录像时,生成的图像需要逆时针旋转90度;前置摄像头横屏时生成的图像正常,竖屏时生成的图像需要逆时针旋转270度,即顺时针旋转90度。经过测试发现,如果以被拍摄物的角度看前置和后置生成的图像都是顺时针旋转90,因为前置摄像头拍摄的图片是镜像的。在数据存储上,后置竖屏顺时针旋转90度,前置竖屏逆时针
27、旋转90度。其旋转示意图分别如图5、图6所示。图5. 后置摄像头生成图片顺时针旋转90度示意图图6. 前置摄像头生成图片逆时针旋转90度示意图由以上旋转示意图可以得出后置竖屏旋转方法如下所示:for (i = 0; i =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; 在项目中,为了与用户的视觉角度
28、一致,后置竖屏旋转方法名为rot90_video,前置竖屏旋转方法名为rot270_video.2.5编码前面所有工作完成后,就是真正的调用ffmpeg库里的avcodec_encode_video2方法来编码了。但是要看整个编码效率必须得计算像素格式转换时间、裁剪时间、旋转时间、avcodec_encode_video2编码时间、视频数据写入文件时间以及其他时间,其他时间是正在编码时CPU消耗的其他时间,例如线程等待等。因此,计算编码效率的公式为:总共时间即为项目中是write_video_frame方法从开始到结束的时间。2.6编码小结在编码这部分,特别是视频编码这部分,它是整个项目的核心,判断编码效率的好坏也在此部分。因此,在此部分必须进行各种优化以提高编码的效率。例如,像素格式转换不用通用的sws_scale方法而是换用专门针对YUV420SP转YUV420P的方法,代码上去掉没必要的判断等等。当然,这些优化还需要有一套好的编码参数为基础,这样才能从整体提高编码的效率。目前经过反复测试,本项目基本达到一定的编码要求。