.h:
#pragma once
#include "headers.h"
// #define _SDL_config_win32_h
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libswscale/swscale.h"
}
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swscale.lib")
class CX264Decoder
{
public:
CX264Decoder();
virtual ~CX264Decoder();
public:
bool InitDecoder(int nWidth, int nHeight, int nRate, int nFps);
void UninitDecoder();
void Decode(BYTE* pInBuf, int nInSize, BYTE** ppOutBuf, int* pOutSize, int* pWidth, int* pHeight);
protected:
bool m_bInit;
AVCodec* m_pCodecH264;
AVCodecContext* m_pCodecCtx;
AVFrame* m_pYUVFrame;
AVFrame* m_pRGBFrame;
BYTE* m_pOutBuf;
int m_nOutSize;
};
#include "X264Decoder.h"
CX264Decoder::CX264Decoder()
{
m_bInit = false;
m_pCodecH264 = NULL;
m_pCodecCtx = NULL;
m_pYUVFrame = NULL;
m_pRGBFrame = NULL;
m_pOutBuf = NULL;
m_nOutSize = 0;
}
CX264Decoder::~CX264Decoder()
{
UninitDecoder();
}
bool CX264Decoder::InitDecoder(int nWidth, int nHeight, int nRate, int nFps)
{
if (m_bInit)
return true;
avcodec_init();
av_register_all();
m_pCodecH264 = avcodec_find_decoder(CODEC_ID_H264);
if (!m_pCodecH264)
return false;
m_pCodecCtx = avcodec_alloc_context();
if (!m_pCodecCtx)
return false;
m_pCodecCtx->time_base.num = 1;
m_pCodecCtx->time_base.den = nFps;
m_pCodecCtx->bit_rate = nRate;
m_pCodecCtx->frame_number = 1;
m_pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
m_pCodecCtx->width = nWidth;
m_pCodecCtx->height = nHeight;
//m_pCodecCtx->pix_fmt = PIX_FMT_RGB24;
if (avcodec_open(m_pCodecCtx, m_pCodecH264) < 0)
return false;
m_pYUVFrame = avcodec_alloc_frame();
m_pRGBFrame = avcodec_alloc_frame();
if (!m_pYUVFrame || !m_pRGBFrame)
return false;
m_nOutSize = nWidth * nHeight * 10;
m_pOutBuf = (BYTE*)malloc(m_nOutSize);
if (!m_pOutBuf)
return false;
m_bInit = true;
return true;
}
void CX264Decoder::UninitDecoder()
{
if (m_pOutBuf)
{
free(m_pOutBuf);
m_pOutBuf = NULL;
}
if (m_pYUVFrame)
{
av_free(m_pYUVFrame);
m_pYUVFrame = NULL;
}
if (m_pRGBFrame)
{
av_free(m_pRGBFrame);
m_pRGBFrame = NULL;
}
if (m_pCodecCtx)
{
avcodec_close(m_pCodecCtx);
av_free(m_pCodecCtx);
m_pCodecCtx = NULL;
}
m_bInit = false;
}
void CX264Decoder::Decode(BYTE* pInBuf, int nInSize, BYTE** ppOutBuf, int* pOutSize, int* pWidth, int* pHeight)
{
*ppOutBuf = NULL;
if (!m_bInit) return;
if (!pInBuf || nInSize <= 0)
return;
int nGotSize = 0;
avcodec_decode_video(m_pCodecCtx, m_pYUVFrame, &nGotSize, pInBuf, nInSize);
if (nGotSize <= 0)
return;
int nWidth = m_pCodecCtx->width;
int nHeight = m_pCodecCtx->height;
// calculate size
//int nShift = 0;
//int nOffset = 0;
//int nLen = 0;
//for (int i=0; i<3; ++i)
//{
// nShift = (0 == i) ? 0 : 1;
//
// nOffset = m_pCodecCtx->height >> nShift;
// for (int j=0; j<nOffset; ++j)
// nLen += nOffset;
//}
// make sure that memory is enough
int nNumBytes = avpicture_get_size(/*PIX_FMT_RGB24*/PIX_FMT_BGR24, nWidth, nHeight);
if (nNumBytes > m_nOutSize)
{
if (m_pOutBuf)
{
free(m_pOutBuf);
m_pOutBuf = NULL;
}
m_pOutBuf = (BYTE*)malloc(nNumBytes);
if (!m_pOutBuf) return;
m_nOutSize = nNumBytes;
}
if (!m_pOutBuf) return;
memset(m_pOutBuf, 0, m_nOutSize);
// to RGB24
avpicture_fill((AVPicture*)m_pRGBFrame, m_pOutBuf, /*PIX_FMT_RGB24*/PIX_FMT_BGR24, nWidth, nHeight);
SwsContext* pSwsCtx = sws_getContext(
nWidth, nHeight, m_pCodecCtx->pix_fmt,
nWidth, nHeight, /*PIX_FMT_RGB24*/PIX_FMT_BGR24,
SWS_BICUBIC, NULL, NULL, NULL);
if (!pSwsCtx) return;
sws_scale(pSwsCtx, m_pYUVFrame->data, m_pYUVFrame->linesize, 0, nHeight,
m_pRGBFrame->data, m_pRGBFrame->linesize);
sws_freeContext(pSwsCtx);
*ppOutBuf = m_pOutBuf;
*pOutSize = nNumBytes;
*pWidth = nWidth;
*pHeight = nHeight;
}