利用ffmpeg将H264解码为RGB

利用ffmpeg将H264解码为RGB由于公司买到了一个不提供解码器的设备,我不得已还要做解码的工作。在网上找了一圈,H264解码比较方便的也就是ffmpeg一系列的函数库了,原本设备中也是用这套函数库解码,但厂家不给提供,没办法,只得自己搞了。

大家好,又见面了,我是你们的朋友全栈君。

由于公司买到了一个不提供解码器的设备,我不得已还要做解码的工作。在网上找了一圈,H264解码比较方便的也就是ffmpeg一系列的函数库了,原本设备中也是用这套函数库解码,但厂家不给提供,没办法,只得自己搞了。

利用H264解码分为几个步骤:

 

注意一点在添加头文件的时候要添加extern “C”,不然会出现错误

extern "C"
{
#include <avcodec.h>
#include <avformat.h>
#include <avutil.h>
#include <swscale.h>
};

 

 

这里申明了几个全局变量

AVCodec         *pCodec = NULL;
AVCodecContext  *pCodecCtx = NULL;
SwsContext      *img_convert_ctx = NULL;
AVFrame         *pFrame = NULL;
AVFrame         *pFrameRGB = NULL;

 

1. 初始化

int H264_Init(void)
{
	/* must be called before using avcodec lib*/
	avcodec_init();
	/* register all the codecs */
	avcodec_register_all();

	/* find the h264 video decoder */
	pCodec = avcodec_find_decoder(CODEC_ID_H264);
	if (!pCodec) {
		fprintf(stderr, "codec not found\n");
	}
	pCodecCtx = avcodec_alloc_context();

	/* open the coderc */
	if (avcodec_open(pCodecCtx, pCodec) < 0) {
		fprintf(stderr, "could not open codec\n");
	}
	// Allocate video frame
	pFrame = avcodec_alloc_frame();
	if(pFrame == NULL)
		return -1;
	// Allocate an AVFrame structure
	pFrameRGB=avcodec_alloc_frame();
	if(pFrameRGB == NULL)
		return -1;


	
	return 0;

}

在最早使用的时候没有使用全局变量,初始化中也就只有init和regisger这两个函数,而这样做的下场是,非关键帧全部无法解码,只有关键帧才有办法解码。

2. 解码

解码的时候avcodec_decode_video函数是进行解码操作,在外部定义outputbuf的大小时,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。

 

在解码的时候这几句话的意义是将YUV420P的数据倒置。在原先使用中,发现解出来的图像居然是中心旋转图,后面在网上找了些办法,觉得这个比较实用。解码实时是很重要的,图像转化完之后也可以讲RGB图再次转化,那样也能成为一个正的图,但是那样效率就明显低了。

	pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
	pFrame->linesize[0] *= -1;
	pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
	pFrame->linesize[1] *= -1;
	pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
	pFrame->linesize[2] *= -1;

 

 

int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)
{
	
	int             decode_size;
	int             numBytes;
	int             av_result;
	uint8_t         *buffer = NULL;

	printf("Video decoding\n");

	av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);
	if (av_result < 0)
	{
		fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);
		return -1;
	}

	// Determine required buffer size and allocate buffer
	numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,
		pCodecCtx->height);
	buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));
	// Assign appropriate parts of buffer to image planes in pFrameRGB
	avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,
		pCodecCtx->width, pCodecCtx->height);

	img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,
		//PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
		pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,
		SWS_X ,NULL,NULL,NULL) ;
	if (img_convert_ctx == NULL) 
	{

		printf("can't init convert context!\n") ;
		return -1;
	}
	pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
	pFrame->linesize[0] *= -1;
	pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
	pFrame->linesize[1] *= -1;
	pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
	pFrame->linesize[2] *= -1;
	sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
		0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);
	
	if (decode_size)
	{
		*outsize = pCodecCtx->width * pCodecCtx->height * 3;
		memcpy(outputbuf, pFrameRGB->data[0], *outsize);
	}	


	free(buffer);
	return 0;
}

3. 释放资源

资源的回收。

void H264_Release(void)
{
	avcodec_close(pCodecCtx);
	av_free(pCodecCtx);
	av_free(pFrame);
	av_free(pFrameRGB);
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149784.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Codeforces Round #296 (Div. 2) A. Playing with Paper[通俗易懂]

    Codeforces Round #296 (Div. 2) A. Playing with Paper

    2022年1月22日
    52
  • 用斐波那契数列来说明递归和迭代的区别「建议收藏」

    用斐波那契数列来说明递归和迭代的区别「建议收藏」递归:自己调用自己迭代:反复替换的意思递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。递归与迭代都涉及重复:迭代显式使用重复结构,而递归通过重复函数调用实现重复。递归与迭代都涉及终止测试:迭代在循环条件失败时终止,递归在遇到基本情况时终止。使用计数器控制重复的迭代和递归都逐渐到达终止点:迭代一直修改计数器,直到计数器值使循环条件失败;递归不断产生最初问题的简化副本

    2022年6月3日
    44
  • 设计测试用例的方法

    设计测试用例的方法如果测试的时间有限,如何保证在有限的时间内让产品上线?(1)有限的时间内测试,保证用户经常使用(使用频率比较高,主要的,核心的功能)功能的质量(2)如果有限的时间所有的功能不能完全测完,可以和产品经理开发商量,把没有通过测试的,有风险的功能把用户的入口,屏蔽掉(让用户无法使用),产生错误风险就会降低(3)本次测试,测试报告写清楚,这次上线,哪些功能测试了,哪些功能没有测试,上线风险分析清楚。百度云盘的测试用例太多了,如何去写?(1)用户经常使用的功能有哪些?文件的存储(长传,接受)下载分享

    2022年6月20日
    25
  • sql 左连接数据出现重复[通俗易懂]

    目录一、简化举例二、查询结果一、简化举例1、表aa2、表bb二、查询结果1、无条件查询2、左链接查询右表数据有重复时,连接关系如下所以查询数据会出现重复,所以要保证右表所关联唯一…

    2022年4月9日
    352
  • Vue学习笔记——Vue-router「建议收藏」

    Vue学习笔记——Vue-router「建议收藏」第1节:Vue-router入门1、解读router/index.js文件importVuefrom’vue’//引入VueimportRouterfrom’vue-router’//引入vue-routerimportHellofrom’@/components/Hello’//引入根目录下的Hello.vue组件Vue.use(Route…

    2022年7月11日
    21
  • 报告上集 | 《认文识字·中文字信息精准化》报告「建议收藏」

    您好,欢迎关注《认文识字——中文字信息精准化》报告。我是安秀。这里说的“中文字”,是“中国文字”的简称,也就是我们常说的“汉字”。【认文识字】是以“中文字信息精准化”为导向,而沉淀出的一整个“从文到字”脉络关系大网和相应的信息数据。今天发表出来,跟您分享。壹○中文字信息精准化研究与分享中文字,是人类文明进程的全息存储;同时,也是人类智能的载体之一。它以多维多元的编码方式,将人脑多维智力运行过程、全息呈现。使用【认文识字】的信息数据,可以在包括人工智能领域的各行各业各领域中,做

    2022年4月7日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号