封装格式:将视频数据和音频数据打包成一个文件的规范(avi\rmvb\mp4\flv\mkv)

视频播放器播放一个互联网上的视频文件:

(1)解协议(将流媒体协议数据,解析为标准的相应的封装格式,包括http\rtmp,输出为flv封装格式的数据)

(2)解封装(将输入的封装格式的数据,分离为音频流压缩编码数据和视频流压缩编码数据,H.264编码的视频码流和ACC编码的音频码流)

(3)解码视音频(将视频/音频压缩编码数据,解码为非压缩的视频/音频原始数据,H.264->YUV420P,RGB,ACC->PCM)

(4)视音同步(将同步解码出来的视频和音频数据播放)

视频播放器 架构 视频播放器的作用_封装格式

流媒体协议:

RTSP+RTP经常用于IPTV领域。因为其采用UDP传输视音频,支持组播,效率较高。但其缺点是网络不好的情况下可能会丢包,影响视频观看质量。

 

1、一个YUV/RGB播放器:

视频播放器 架构 视频播放器的作用_码流_02

yuv文件格式是一种图片格式,是由Y,U,V三种部分组成,Y表示亮度,U、V表示颜色的色度,这种模式比RGB存储颜色信息要更加准确,通常也写做YUV。

yuv视频格式就简单一些了,其实就是YUV格式图片组成的图像序列,可以保存为YUV 4:2:0,4:2:2,4:4:4等格式,有些YUV视频格式文件可以通过MPEG-4 and H.264解码器解码。

yuv文件可以用一些专用的播放器来打开。

2、简单音频操作:

(1)分离YUV420P像素数据中的Y、U、V分量,相当于三通道的分为三张单通道的

 

 

(2)变灰度图,将U\V分量设置为128(色度分量在偏置前的取值范围为-128-127,无色对应0;偏置后为0-255,无色为128)

/**
 * Convert YUV420P file to gray picture
 * @param url     Location of Input YUV file.
 * @param w       Width of Input YUV file.
 * @param h       Height of Input YUV file.
 * @param num     Number of frames to process.
 */
int simplest_yuv420_gray(char *url, int w, int h,int num){
	FILE *fp=fopen(url,"rb+");
	FILE *fp1=fopen("output_gray.yuv","wb+");
	unsigned char *pic=(unsigned char *)malloc(w*h*3/2);

	for(int i=0;i<num;i++){
		fread(pic,1,w*h*3/2,fp);
		//Gray
		memset(pic+w*h,128,w*h/2);
		fwrite(pic,1,w*h*3/2,fp1);
	}

	free(pic);
	fclose(fp);
	fclose(fp1);
	return 0;
}

3、音频软件:Audacity

视频播放器 架构 视频播放器的作用_封装格式_03

3、H.264视频流解析

原理

H.264原始码流(又称为“裸流”)是由一个一个的NALU组成的。他们的结构如下图所示。

视频播放器 架构 视频播放器的作用_数据_04

其中每个NALU之间通过startcode(起始码)进行分隔,起始码分成两种:0x000001(3Byte)或者0x00000001(4Byte)。如果NALU对应的Slice为一帧的开始就用0x00000001,否则就用0x000001。

H.264码流解析的步骤就是首先从码流中搜索0x000001和0x00000001,分离出NALU;然后再分析NALU的各个字段。本文的程序即实现了上述的两个步骤。

 

输入为一个H.264原始码流(裸流)的文件路径,输出为该码流的NALU统计数据:

视频播放器 架构 视频播放器的作用_视频播放器 架构_05

NALU字段意义参考:

1、调用simplest_h264_parser("sintel.h264")进行NALU分离,分离过程主要循环调用GetAnnexbNALU(n):

GetAnnexbNALU(n)

步骤一:确定起始码类型

步骤二:确定起始码类型之后,循环得到nalu的长度、类型等信息,直到读到下一个start code

步骤三:确定当前NALU信息

4、AAC音频码流解析

原理AAC原始码流(又称为“裸流”)是由一个一个的ADTS frame组成的。他们的结构如下图所示。

视频播放器 架构 视频播放器的作用_封装格式_06

其中每个ADTS frame之间通过syncword(同步字)进行分隔。同步字为0xFFF(二进制“111111111111”)。AAC码流解析的步骤就是首先从码流中搜索0x0FFF,分离出ADTS frame;然后再分析ADTS frame的首部各个字段。本文的程序即实现了上述的两个步骤。

5、FLV封装格式解析

原理FLV封装格式是由一个FLV Header文件头和一个一个的Tag组成的。Tag中包含了音频数据以及视频数据。FLV的结构如下图所示。

视频播放器 架构 视频播放器的作用_数据_07

 

5、UDP-RTP协议解析

原理:

MPEG-TS封装格式数据打包为RTP/UDP协议然后发送出去的流程如下图所示。

视频播放器 架构 视频播放器的作用_码流_08

图中首先每7个MPEG-TS Packet打包为一个RTP,然后每个RTP再打包为一个UDP。其中打包RTP的方法就是在MPEG-TS数据前面加上RTP Header,而打包RTP的方法就是在RTP数据前面加上UDP Header。

编译simplest_ffmpeg_decoder

1、被声明为已否决

严重性	代码	说明	项目	文件	行	禁止显示状态
错误	C4996	'avcodec_decode_video2': 被声明为已否决	ffmpeg_decoder	f:\player\player2\ffmpeg_decoder\simplest_ffmpeg_decoder.cpp	145

FFmpeg中所谓的“被声明为已否决”就是因为函数或者结构体属性被标示为attribute_deprecated,很有可能在未来的版本中就删除了。

最好的解决方案就是使用新的被推荐使用的函数、结构体等。
如果在不想改变代码的情况下编译通过,需要关闭VS中的SDL检查,打开项目属性->配置属性->c/c++ ->SDL检查,选择否。这样编译的时候,error就会变成了warning。(参考:)