利用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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 2-visio使用与卸载「建议收藏」

    2-visio使用与卸载「建议收藏」下载一个工具WindowsInstallerCleanUpUtility_v4.71.1015.0,如果没有可以去这里下载:https://download.csdn.net/download/qq_39451578/10950019(没积分的小伙伴可以私信或者下方留言)然后找到相关信息:…

    2022年8月13日
  • 2020年3月25日阿里笔试题

    2020年3月25日阿里笔试题2020年3月25日阿里笔试题题目描述一python代码题目描述二求公差的python代码  仿佛人生总有一种魔咒,自己做的这场笔试题永远是最难的。不过今天的笔试题,真的难。来看题目。题目描述一给定一个数组n,然后给三个长度为n的数组,可以从这三个数组中选出一个长度为n的数组,第i个位置需要是从给出的三个数组第i个位置选择的,然后要求使这个数组后一项减前一项的绝对值之和最小。输入示例::…

    2022年5月24日
  • 扩展卡尔曼滤波算法及仿真实例[通俗易懂]

    扩展卡尔曼滤波算法及仿真实例[通俗易懂]在阅读本篇博客之前希望读者已经具备线性卡尔曼滤波器的基础,或者提前研读我的前一篇关于线性卡尔曼滤波器的文章:线性卡尔曼滤波算法及示例。下面不说废话,直奔主题了。一、扩展卡尔曼滤波器(EKF)理论基础扩展Kalman滤波器算法实质上是一种在线线性化技术,即安装估计轨道进行线性化处理—-泰勒级数展开,再进行线性的Kalman滤波。实际非线性滤波处理,通常对过程噪声和观测噪声近似为高斯分布,…

    2022年6月22日
  • EventBus使用详解(一)——初步使用EventBus[通俗易懂]

    EventBus使用详解(一)——初步使用EventBus[通俗易懂]前言:EventBus是上周项目中用到的,网上的文章大都一样,或者过时,有用的没几篇,经过琢磨,请教他人,也终于弄清楚点眉目,记录下来分享给大家。相关文章:1、《EventBus使用详解(一)——初步使用EventBus》2、《EventBus使用详解(二)——EventBus使用进阶》一、概述EventBus是一款针对Android优化的发布/订阅事件总线。主要功…

    2022年6月2日
  • ServerTools数据调试记录

    ServerTools数据调试记录【1】版本号:分割线2.9分割线结束【2】更新地址:分割线https://rtb49.lofter.com/post/1d7930e3_1c989d999分割线结束【3】更新信息:分割线99B9C35AC7B55732831404701A2786CB9FC85872279FAEC8041EB6290CCA6E09F8691BC93B96DBA66F5C3C13D20A57786D5E01BF9941D47A68713EECBC94AD7E14E43F4BEA7E22DFA213FF2BA91121C

    2022年7月18日
  • linux配置ntp时间同步客户端(小红帽系统怎么关闭程序)

    NTP网络时间服务器在LINUX系统设置方法(小红帽版)NTP网络时间服务器在LINUX系统设置方法(小红帽版)第一种方法:1.Linux系统使用命令行配置:在Linux上面执行ntpdate:ntpdate1Array2.168.0.1#1Array2.168.0.1是NTP服务器的IP2.使用hwclock命令,把时间写入bioshwclock-w如果想定时进行时间校准,可以使用crond服务来定时执行。编辑/etc/crontab文件加入下面一行:308**

    2022年4月10日

发表回复

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

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