ffmpeg编码之RGB通过H264编码并封装成mp4

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hb707934728/article/details/81476756

原始rgb文件

h264编码成功,并封装成MP4文件

运行截图

日志信息

实现方式

extern "C"
{
   #include <libavformat/avformat.h>
   #include <libswscale/swscale.h>
}

#include <iostream>
using namespace std;
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")

int main()
{
	char infile[] = "out.rgb";
	char outfile[] = "rgb.mp4";

	//注册封装,解封装,格式
	av_register_all();
	//注册解码器
	avcodec_register_all();

	FILE *fp = fopen(infile,"rb");
	if (!fp)
	{
		cout << infile << " open failed!" << endl;
		getchar();
		return -1;
	}
	int width = 848;
	int height = 480;
	int fps = 25;

	//1 创建编码器 
	AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (!codec)
	{
		cout << " avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl;
		getchar();
		return -1;
	}
	//编码器上下文
	AVCodecContext *c = avcodec_alloc_context3(codec);
	if (!c)
	{
		cout << " avcodec_alloc_context3  failed!" << endl;
		getchar();
		return -1;
	}
	//设置视频编码相关参数
	//比特率
	c->bit_rate = 400000000;

	c->width = width;
	c->height = height;
	//把1秒钟分成fps个单位 
	c->time_base = { 1,fps };
	c->framerate = { fps,1 };

	//画面组大小,就是多少帧出现一个关键帧
	//GOP 介绍  见   https://blog.csdn.net/xiangjai/article/details/44238005
	c->gop_size = 50;

	c->max_b_frames = 0;
	c->pix_fmt = AV_PIX_FMT_YUV420P;
	c->codec_id = AV_CODEC_ID_H264;
	c->thread_count = 8;

	//全局的编码信息
	c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	//打开编码器
	int ret = avcodec_open2(c,codec,NULL);
	if (ret < 0)
	{
		cout << " avcodec_open2  failed!" << endl;
		getchar();
		return -1;
	}
	cout << "avcodec_open2 success!" << endl;

	//2 create out context
	AVFormatContext *oc = NULL;
	avformat_alloc_output_context2(&oc, 0, 0, outfile);

	//3 add video stream
	AVStream *st = avformat_new_stream(oc,NULL);
	st->id = 0;
	st->codecpar->codec_tag = 0;
	avcodec_parameters_from_context(st->codecpar,c);

	cout << "===============================================" << endl;
	av_dump_format(oc, 0, outfile, 1);
	cout << "===============================================" << endl;

	//4 rgb to yuv
	//改变视频尺寸
	SwsContext *ctx= NULL;
	ctx = sws_getCachedContext(ctx,
		width,height,AV_PIX_FMT_BGRA,
		width,height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,
		NULL,NULL,NULL);
	//输入空间
	unsigned char *rgb = new unsigned char[width*height*4];


	//输出空间
	AVFrame *yuv = av_frame_alloc();
	yuv->format = AV_PIX_FMT_YUV420P;
	yuv->width = width;
	yuv->height = height;
	//分配空间
	ret = av_frame_get_buffer(yuv,32);

	if (ret < 0)
	{
		cout << " av_frame_get_buffer  failed!" << endl;
		getchar();
		return -1;
	}

	//5 write mp4 head
	ret = avio_open(&oc->pb,outfile,AVIO_FLAG_WRITE);
	if (ret < 0)
	{
		cout << " avio_open  failed!" << endl;
		getchar();
		return -1;
	}
	ret = avformat_write_header(oc, NULL);
	if (ret < 0)
	{
		cout << " avformat_write_header  failed!" << endl;
		getchar();
		return -1;
	}
	int p = 0;
	for (;;)
	{
		//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
		//ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
		//size -- 这是要读取的每个元素的大小,以字节为单位。
		//nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
		//stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
		int len = fread(rgb,1,width*height*4,fp);
		if (len<=0)
		{
			break;
		}
		uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
		indata[0] = rgb;
		int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };
		inlinesize[0] = width * 4;

		int h = sws_scale(ctx,indata,inlinesize,0,height,yuv->data,yuv->linesize);
		if (h<=0)
		{
			break;
		}
		//6 encode frame
		yuv->pts = p;
		p = p + 3600;
		//发送到编码器
		ret = avcodec_send_frame(c,yuv);
		if (ret != 0)
		{
			continue;
		}
		AVPacket pkt;
		av_init_packet(&pkt);
		//接收编码结果
		ret = avcodec_receive_packet(c,&pkt);
		if (ret != 0)
			continue;
		//将编码后的帧写入文件
		av_interleaved_write_frame(oc,&pkt);
		cout << "<" << pkt.size << ">";
	}

	//写文件尾
	av_write_trailer(oc);

	//关闭视频输出IO
	avio_close(oc->pb);

	//清理封装输出上下文
	avformat_free_context(oc);

	//关闭编码器
	avcodec_close(c);

	//清理编码器上下文
	avcodec_free_context(&c);

	//清理视频重采样上下文
	sws_freeContext(ctx);
	cout << "======================end=========================" << endl;
	delete rgb;
	getchar();
	return 0;
}

 

展开阅读全文

没有更多推荐了,返回首页