FFmpeg4.1——H264裸流解码为YUV420P原像素

一、流程图

在这里插入图片描述

二、代码

#include 
using namespace std;

extern "C"
{
#include 
#include 
#include
#include 
#include 
}

AVFormatContext* AFCtx_p;//解封装上下文
AVCodecContext* ACCtx_p;//解码器上下文
AVCodec* codec_p;//解码器
AVFrame* pFrame;
AVFrame* pFrameyuv;
AVPacket* packet;
struct SwsContext* img_convert_ctx;

int videoindex = -1;
int ret, got_picture = 0;
int y_size;

const char path[] = "./res/5min.h264";

int main(int argc, char* argv[])
{

	//打开H264文件,将文件信息存入解封装上下文
	if (avformat_open_input(&AFCtx_p, path, NULL, NULL) != 0)
	{
		cout << "open failed\n" << endl;
		return -1;
	}
	//寻找视频流信息
	if (avformat_find_stream_info(AFCtx_p, NULL) < 0)
	{
		cout << "dtream find failed\n" << endl;
		return -1;
	}

	//dump调试信息
	av_dump_format(AFCtx_p, -1, path, NULL);

	//打开视频并且获取了视频流,设置视频索引默认值
	for (int i = 0; inb_streams; i++)
	{
		if (AFCtx_p->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			videoindex = i;
		}
	}
	//如果没有找到视频索引,说明不是一个视频文件
	if (videoindex == -1)
	{
		cout << "not a video\n" << endl;
		return -1;
	}
	//分配解码器上下文空间
	ACCtx_p = avcodec_alloc_context3(NULL);
	//获取编解码器上下文信息
	if (avcodec_parameters_to_context(ACCtx_p, AFCtx_p->streams[videoindex]->codecpar) < 0)
	{
		cout << "copy stream failed\n" << endl;
		return -1;
	}

	//查找解码器
	codec_p = avcodec_find_decoder(ACCtx_p->codec_id);
	if (!codec_p)
	{
		cout << "find decoder error\n" << endl;
		return -1;
	}
	//打开解码器
	if (avcodec_open2(ACCtx_p, codec_p, NULL) != 0)
	{
		cout << "open codec failed" << endl;
		return -1;
	}
	//裁剪图像
	img_convert_ctx = sws_getContext(ACCtx_p->width, ACCtx_p->height,
		ACCtx_p->pix_fmt,
		ACCtx_p->width, ACCtx_p->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);
	if (!img_convert_ctx)
	{
		cout << "get swscale context failed\n" << endl;
		return -1;
	}
	packet = av_packet_alloc();
	pFrame = av_frame_alloc();
	pFrameyuv = av_frame_alloc();
	//获取转换后YUV数据的大小
	int video_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, ACCtx_p->width,
		ACCtx_p->height, 1);
	uint8_t* buf = (uint8_t*)av_malloc(video_size);
	av_image_fill_arrays(pFrameyuv->data, pFrameyuv->linesize,
		buf, AV_PIX_FMT_YUV420P, ACCtx_p->width, ACCtx_p->height, 1);
	char errbuf[256] = { 0 };
	FILE* fp_yuv = fopen("out.yuv", "wb+");

	//循环读取帧数据并转换写入
	while (av_read_frame(AFCtx_p, packet) >= 0)
	{
		if (packet->stream_index == videoindex)
		{
			if (avcodec_send_packet(ACCtx_p, packet) != 0)
			{
				cout << "send video stream packet failed\n" << endl;
				return -1;
			}
			if (avcodec_receive_frame(ACCtx_p, pFrame) != 0)
			{
				cout << "receive video frame failed\n" << endl;
				return -1;
			}
			cout << "decoding frame" << ACCtx_p->frame_number << endl;

			sws_scale(img_convert_ctx,
				pFrame->data, pFrame->linesize,
				0, ACCtx_p->height, pFrameyuv->data, pFrameyuv->linesize);

			y_size = ACCtx_p->width * ACCtx_p->height;
			fwrite(pFrameyuv->data[0], 1, y_size, fp_yuv);//Y
			fwrite(pFrameyuv->data[1], 1, y_size/4, fp_yuv);//U
			fwrite(pFrameyuv->data[2], 1, y_size/4, fp_yuv);//V
		}
	}
	fclose(fp_yuv);
	av_free(buf);
	av_frame_free(&pFrame);
	av_frame_free(&pFrameyuv);
	av_packet_free(&packet);
	sws_freeContext(img_convert_ctx);
	avcodec_free_context(&ACCtx_p);
	avformat_close_input(&AFCtx_p);
	avformat_free_context(AFCtx_p);
	return 1;
}

更多文章请关注嵌入式机器人公众号
在这里插入图片描述

你可能感兴趣的:(FFmpeg,FFmpeg开发)