音视频处理之FFmpeg+SDL视频播放器( 二 )


sample_fmt:采样格式(只针对音频)
AVCodec
name:编解码器名称
long_name:编解码器长名称
type:编解码器类型
id:编解码器ID
一些编解码的接口函数
AVPacket
pts:显示时间戳
dts :解码时间戳
data :压缩编码数据
size :压缩编码数据大小
stream_index :所属的AVStream
AVFrame
data:解码后的图像像素数据(音频采样数据) 。
linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小 。
width, height:图像的宽高(只针对视频) 。
key_frame:是否为关键帧(只针对视频)。
pict_type:帧类型(只针对视频)。例如I,P,B 。
III、注意事项
裸流文件,即如h264文件,是没有时长等信息的,封装格式的才有
数据结构第一层为封装格式相关的,下面层为编解码相关的
其中
AVStream中的time_base 表示该流的时基,也就是时间的基数,简单可理解为时间的单位,比如时间数是2,时基是1s,则时间为2s
AVPacket:可以理解为h264中的数据包,编码后的包
其中,pts:显示时间戳,表示该视频帧几分几秒的时候放到屏幕上 。这个值只是一个整数 没有单位,所以要得到具体的几分几秒需要和前面的time_base时基参数相乘得到 。
dts:解码时间戳
stream_index:标识,表示该流属于音频流还是视频流 。
data:压缩编码的数据,如h264的编码,就可以取出该数据保存起来形成的文件就是h264文件 。
通过av_read_frame可从大的数据结构指针中读取到AVPacket数据
注意播放的顺序不一定按照存储的顺序来 。即有一个显示的顺序和一个解码的顺序 。
AVFrame
data:解码后的图像像素数据,如YUV等,可形成yuv文件(依次存储的是y、u、v分量,其中u 宽和高都只有y一半,整个数据量就y的四分之一,v的也一样) 。data是一个指针数组,其中一个分量对应一个数组
数据先通过解码函数avcodec_decode_video2进行解码,然后由于解码出来的数据由于是有黑边(多出一块多余的数据),所以还需用sws_scale函数把这块多余的裁了 。
4).解码后的数据要经过sws_scale()函数处理
解码后YUV格式的视频像素数据保存在AVFrame的data[0]、data[1]、data[2]中 。但是这些像素值并不是连续存储的,每行有效像素之后存储了一些无效像素 。
以亮度Y数据为例,data[0]中一共包含了linesize[0]*height个数据 。但是出于优化等方面的考虑,linesize[0]实际上并不等于宽度width,而是一个比宽度大一些的值 。
因此需要使用sws_scale()进行转换 。转换后去除了无效数据,width和linesize[0] 取值相等 。如下图3:

音视频处理之FFmpeg+SDL视频播放器

文章插图
其中,sws_scale()函数需要用到的转换信息,即第一个参数,是由sws_getContext函数获得的
转换后保存在一个新的帧数据结构体,由于使用的转换函数而不是解码函数,所以这个结构体还需要填充其内部的缓冲区,用于存储像素数据,填充的方法使用avpicture_fill函数:
int avpicture_fill(AVPicture *picture, uint8_t *ptr,int pix_fmt, int width, int height);
这个函数的使用本质上是为已经分配的空间的结构体(AVPicture *)ptFrame挂上一段用于保存数据的空间,
这个结构体中有一个指针数组data[AV_NUM_DATA_POINTERS],挂在这个数组里 。一般我们这么使用:
I、pFrameRGB=avcodec_alloc_frame(); II、numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height); buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); III、avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);以上就是为pFrameRGB挂上buffer 。这个buffer是用于存缓冲数据的 。
ptFrame为什么不用fill空间 。主要是下面这句:
avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,packet.data, packet.size);很可能是ptFrame已经挂上了packet.data,所以就不用fill了 。
二、SDL视频显示
SDL(Simple DirectMedia Layer)库的作用说白了就是封装了复杂的视音频底层交互工作,简化了视音频处理的难度 。
主要用来做游戏,现在只用到其视频显示部分 。
特点:跨平台,开源
1.库的结构图见图:
音视频处理之FFmpeg+SDL视频播放器

文章插图
实际上它调用了底层api完成了和硬件的交互,比如linux下,就操作了framebuffer.
2.配置vc工程和之前ffmpeg的配置几乎都是一样的:
1).新建控制台工程


推荐阅读