ffmpeg之H265解码

本文详细介绍如何使用ffmpeg把H265解码成YUV420P格式格式的数据。

首先由于采用VS2017开发,禁用了一个4996的错误:

#pragma error(disable:4996) //全部禁用
#pragma warning(disable:4996)

ffmpeg接收H265的数据,之能一帧一帧发送,不能接收步全的数据,所以需要先把H265解析成一帧数据。

这里我的思路是先建一个大大的缓存,把H265数据保存进来,然后再通过nul头(0x00 0x00 0x00 0x01)来区分每一帧数据。

这里和H264的解析基本完全一样,每一帧的开头4个字节一定是nul头。

	char H265Buf[1024 * 512];
	int H265Lenth = 0;
	while (true)
	{
		int iReadSize = fread(frame_buf, 1, 512, InFile);
		if (iReadSize <= 0)
		{
			break;
		}
		memcpy(H265Buf+ H265Lenth, frame_buf, iReadSize);
		H265Lenth = H265Lenth + iReadSize;
		//获取一帧数据
		while (true)
		{
			bool OneFrame = false;
			if (H265Lenth<=8)
			{
				break;
			}
			for (int i = 4; i < H265Lenth-4; i++)
			{
				if (H265Buf[i] == 0x00 && H265Buf[i+1] == 0x00&& H265Buf[i+2] == 0x00&& H265Buf[i+3] == 0x01)
				{
					
					H265Lenth = H265Lenth - i;
					memcpy(H265Buf, H265Buf+i, H265Lenth);
					OneFrame = true;
					break;
				}
			}
			if (OneFrame)
			{
				continue;
			}
			else
			{
				break;
			}
		}
		
		
 
 
	}

下面重点介绍使用ffmpeg解析H265

首先各种初始化:

	codec = avcodec_find_decoder(AV_CODEC_ID_H265);
	c = avcodec_alloc_context3(codec);
	if (avcodec_open2(c, codec, NULL) < 0) {
		fprintf(stderr, "Could not open codec\n");
		return false;
	}

 丢入H265数据

	ret = avcodec_send_packet(c, packet);

 获取Yuv420P数据

int ret = avcodec_receive_frame(c, frame);

这里获取到的数据,是保存在AVFrame结构体里 面的,这里我琢磨了好久。

AVFrame有一个成员变量如下,来保存数据,其实使用到了data[0],data[1],data[2]

    uint8_t *data[AV_NUM_DATA_POINTERS];

本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击领取↓↓

 data[0] 保存Y信息

data[1] 保存U信息

data[2] 保存V信息。

但是,不要简单的认为把数据直接写入文件,就是YUV420P的文件了,其实是不对的。这里有富余数据,每一行的Y信息,举个例子,是480,但是他保存所使用的大小为512大小,

可能是为了更快的计算吧,他的每一行的信息,不是绝对信息,而是2的多少次方的放大信息,我们在保存的时候,需要把多余的数据剔除掉。

其中每一行他使用的大小,在linesize里面标识,linesize[0],linesize[1],linesize[2]

    int linesize[AV_NUM_DATA_POINTERS];

linesize[0] 保存Y的一行的大小

linesize[1] 保存U的一行的大小

linesize[2] 保存V的一行的大小

想要得到正确的YUV420P的数据,需要进行转换:

	int a = 0, i;
	for (i = 0; iheight; i++)
	{
		memcpy(m_YuvBuf + a, frame->data[0] + i * frame->linesize[0], frame->width);
		a += frame->width;
	}
	for (i = 0; iheight / 2; i++)
	{
		memcpy(m_YuvBuf + a, frame->data[1] + i * frame->linesize[1], frame->width / 2);
		a += frame->width / 2;
	}
	for (i = 0; iheight / 2; i++)
	{
		memcpy(m_YuvBuf + a, frame->data[2] + i * frame->linesize[2], frame->width / 2);
		a += frame->width / 2;
	}

***********************每个Y,U,V的大小,在buf里面可以看到

ffmpeg之H265解码_第1张图片

YUV420P里面,Y的大小是U和V的4被,可以理解为一帧图像:

YYYYYYYYUUVV

先是8个Y值,在2个U,在2个V,顺序排列。

至此,H265保存为YUV420P搞定。

为了便于大家学习和交流,把工程demo上传如下:

采用VS2017开发 C++开发。

本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击领取↓↓

你可能感兴趣的:(音视频开发进阶,webrtc,视频编解码,实时音视频,音视频,c++)