利用ffmpeg将H264解码为RGB

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

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

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

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

代码语言:javascript代码运行次数:0运行复制extern "C"

{

#include

#include

#include

#include

};这里申明了几个全局变量

代码语言:javascript代码运行次数:0运行复制AVCodec *pCodec = NULL;

AVCodecContext *pCodecCtx = NULL;

SwsContext *img_convert_ctx = NULL;

AVFrame *pFrame = NULL;

AVFrame *pFrameRGB = NULL;1. 初始化

代码语言:javascript代码运行次数:0运行复制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图再次转化,那样也能成为一个正的图,但是那样效率就明显低了。

代码语言:javascript代码运行次数:0运行复制 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;代码语言:javascript代码运行次数:0运行复制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. 释放资源

资源的回收。

代码语言:javascript代码运行次数:0运行复制void H264_Release(void)

{

avcodec_close(pCodecCtx);

av_free(pCodecCtx);

av_free(pFrame);

av_free(pFrameRGB);

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