在这里我们主要用到三个函数实现解码过程,首先是H264解码初期化,其次是进行H264解码,最后 H264解码销毁,具体代码实现如下。
H264Decoder.h
#pragma once
extern "C"{
#include <libavformat\avformat.h>
#include <libavutil\pixfmt.h>
#include <libavcodec\avcodec.h>
}
#define X264_DECODER_H long
typedef struct
{
struct AVCodec *codec;// Codec
struct AVCodecContext *c;// Codec Context
AVCodecParserContext *pCodecParserCtx;
int frame_count;
struct AVFrame *picture;// Frame
AVPacket avpkt;
int iWidth;
int iHeight;
int comsumedSize;
int got_picture;
} X264_Decoder_Handle;
class H264Decoder
{
public:
H264Decoder(void);
~H264Decoder(void);
public:
// H264解码初期化
X264_DECODER_H X264Decoder_Init();
/*
H264数据解码,解码后的数据为yuv420格式
dwHandle:初期化时返回的句柄
pDataIn:待解码数据
nInSize:待解码数据长度
pDataOut:解码后的数据,存储空间由调用者申请
nOutSize:存储空间大小
nWidth:解码后的图像宽度
nHeight:解码后的图像高度
*/
int X264Decoder_Decode(X264_DECODER_H dwHandle, uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int *nOutSize, int *nWidth,int *nHeight);
/*
H264解码销毁
dwHandle:初期化时返回的句柄
*/
void X264Decoder_UnInit(X264_DECODER_H dwHandle);
protected:
void pgm_save2(unsigned char *buf, int wrap, int xsize, int ysize, uint8_t *pDataOut)
{
int i;
for(i = 0; i < ysize; i++)
{
memcpy(pDataOut+i*xsize, buf + /*(ysize-i)*/i * wrap, xsize);
}
}
};
H264Decoder.cpp
#include "stdafx.h"
#include "H264Decoder.h"
H264Decoder::H264Decoder(void)
{
}
H264Decoder::~H264Decoder(void)
{
}
X264_DECODER_H H264Decoder::X264Decoder_Init()
{
X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)malloc(sizeof(X264_Decoder_Handle));
if (pHandle == NULL)
{
return -1;
}
avcodec_register_all();
pHandle->codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!pHandle->codec)
{
return -2;
}
pHandle->c = avcodec_alloc_context3(pHandle->codec);
if (!pHandle->c)
{
return -3;
}
pHandle->c->codec_type = AVMEDIA_TYPE_VIDEO;
pHandle->c->pix_fmt =AV_PIX_FMT_YUV420P;
pHandle->c->flags2|=AV_CODEC_FLAG2_CHUNKS;
pHandle->pCodecParserCtx=av_parser_init(AV_CODEC_ID_H264);
if (!pHandle->pCodecParserCtx){
printf("Could not allocate video parser context\n");
return -6;
}
if (avcodec_open2(pHandle->c, pHandle->codec, NULL) < 0)
{
return -4;
}
pHandle->picture =av_frame_alloc();
if (!pHandle->picture)
{
return -5;
}
pHandle->frame_count = 0;
return (X264_DECODER_H)pHandle;
}
void H264Decoder::X264Decoder_UnInit(X264_DECODER_H dwHandle)
{
if (dwHandle <= 0)
{
return;
}
X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)dwHandle;
avcodec_close(pHandle->c);
av_free(pHandle->c);
av_free(pHandle->picture->data[0]);
av_free(pHandle->picture);
free(pHandle);
}
int H264Decoder::X264Decoder_Decode(X264_DECODER_H dwHandle, uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int *nOutSize, int *nWidth, int *nHeight)
{
if (dwHandle <= 0)
{
return -1;
}
unsigned char buf[20*1024]={0};
X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)dwHandle;
av_init_packet(&(pHandle->avpkt));
pHandle->avpkt.size = nInSize;
pHandle->avpkt.data = pDataIn;
while (pHandle->avpkt.size > 0)
{
pHandle->comsumedSize = avcodec_decode_video2(pHandle->c, pHandle->picture, &pHandle->got_picture, &(pHandle->avpkt));
if (pHandle->comsumedSize < 0)
{
return -2;
}
if (pHandle->got_picture)
{
*nWidth = pHandle->c->width;
*nHeight = pHandle->c->height;
if(pHandle->c->width!=0 && pHandle->c->height!=0)
{*nOutSize=pHandle->c->width*pHandle->c->height*3/2;}
else
{*nOutSize=0;}
pgm_save2(pHandle->picture->data[0],
pHandle->picture->linesize[0],
pHandle->c->width,
pHandle->c->height,pDataOut);
pgm_save2(pHandle->picture->data[1],
pHandle->picture->linesize[1],
pHandle->c->width/2,
pHandle->c->height/2,
pDataOut +pHandle->c->width * pHandle->c->height);
pgm_save2(pHandle->picture->data[2],
pHandle->picture->linesize[2],
pHandle->c->width/2,
pHandle->c->height/2,
pDataOut +pHandle->c->width * pHandle->c->height*5/4);
}
if (pHandle->avpkt.data)
{
pHandle->avpkt.size -= pHandle->comsumedSize;
pHandle->avpkt.data += pHandle->comsumedSize;
}
}
return 0;
}