转:ffmpeg编码h264

使用的是FFMpeg SDKv3的库。
使用步骤很简单:(不含对象创建/释放)
1、初始化
2、编码/解码
3、释放资源
希望熟悉H264的高手提供一下建议设置,公网传输10%的丢包率下,在QCIF的分辨率下我的Bitrate、GOP、MaxBFrames、FrameRate是否合理?
BTW:编译不过的问题请自己解决吧

[XVCodecObj.h]
#include "stdafx.h"

class CXVEncodeObj
{
private:
    AVCodec * m_Codec;
    AVCodecContext * m_CodecCtx;
    int m_inbufMaxSize;
    void * m_OutBuffer;
    AVFrame * m_YUVFrame;
    AVFrame * m_RGBFrame;
    SwsContext * m_ConvertCtx;
public:
    CXVEncodeObj():
      m_Codec(NULL),
      m_CodecCtx(NULL),
      m_inbufMaxSize(0),
      m_OutBuffer(NULL),
      m_YUVFrame(NULL),
      m_RGBFrame(NULL),
      m_ConvertCtx(NULL)
    {
        //构造函数
    }

    ~CXVEncodeObj()
    {
        //析构函数
    }

    int InitCodec();

    int EncodeYUV420P(void * inbuf, int inbufsize, void * outbuf, int outbufsize);

    int EncodeRGB24(void * inbuf, int inbufsize, void * outbuf, int outbufsize, int * IsKey);

    void FinalCodec();

};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CXVDecodeObj
{
private:
    AVCodec * m_Codec;
    AVCodecContext * m_CodecCtx;
    AVFrame * m_DecodeFrame;
    AVFrame * m_RGBFrame;
    SwsContext * m_ConvertCtx;
public:
    CXVDecodeObj():
      m_Codec(NULL),
      m_CodecCtx(NULL),
      m_DecodeFrame(NULL),
      m_RGBFrame(NULL),
      m_ConvertCtx(NULL)
    {
        //
    }

    ~CXVDecodeObj()
    {

    }

    int InitCodec();

    int DecodeVideo(void * inbuf, int inbufsize, void * outbuf, int outbufsize);

    void FinalCodec();

};

[XVCodecObj.cpp]
#include "stdafx.h"
#include "XVCodecObj.h"

#define CVIDEO_BITRATE 5000
#define CVIDEO_WIDTH 176
#define CVIDEO_HEIGHT 144
#define CVIDEO_FRAMERATE 15
#define CVIDEO_GOP 10
#define CVIDEO_MAXBFRAME 0
#define CVIDEO_OUTBUFFERSIZE 100000
#define CVIDEO_CODEC CODEC_ID_H264

static AVFrame *alloc_picture(int pix_fmt, int width, int height)
{
    AVFrame *picture;
    uint8_t *picture_buf;
    int size;

    picture = avcodec_alloc_frame();
    if (!picture)
        return NULL;
    size = avpicture_get_size(pix_fmt, width, height);
    picture_buf = (uint8_t *)av_malloc(size);
    if (!picture_buf) {
        av_free(picture);
        return NULL;
    }
    avpicture_fill((AVPicture *)picture, picture_buf,
                   pix_fmt, width, height);
    return picture;
}

int CXVEncodeObj::InitCodec()
{
    m_Codec = avcodec_find_encoder(CVIDEO_CODEC);
    if (!m_Codec)
        return 1;//not support this codec

    m_CodecCtx = avcodec_alloc_context();
    if (!m_CodecCtx)
        return 2;//maybe not enough memory

    m_CodecCtx->bit_rate = CVIDEO_BITRATE;
    m_CodecCtx->width = CVIDEO_WIDTH;
    m_CodecCtx->height = CVIDEO_HEIGHT;
    m_CodecCtx->time_base.den = CVIDEO_FRAMERATE;
    m_CodecCtx->time_base.num = 1;
    m_CodecCtx->gop_size = CVIDEO_GOP;
    m_CodecCtx->max_b_frames = CVIDEO_MAXBFRAME;
    m_CodecCtx->pix_fmt = PIX_FMT_YUV420P;

    if (avcodec_open(m_CodecCtx,m_Codec)<0)
        return 3;//codec open failed

    m_inbufMaxSize = (m_CodecCtx->width * m_CodecCtx->height * 3) / 2;
   
    m_OutBuffer  = av_malloc(CVIDEO_OUTBUFFERSIZE);
    if (!m_OutBuffer)
        return 4;//maybe not enough memory

    m_YUVFrame = alloc_picture(m_CodecCtx->pix_fmt,m_CodecCtx->width,m_CodecCtx->height);
    if (!m_YUVFrame)
        return 5;//maybe not enough memory

    m_RGBFrame = alloc_picture(PIX_FMT_BGR24,m_CodecCtx->width,m_CodecCtx->height);
    if (!m_RGBFrame)
        return 6;//maybe not enough memory

    m_ConvertCtx = sws_getContext(m_CodecCtx->width,m_CodecCtx->height,PIX_FMT_BGR24,
                    m_CodecCtx->width,m_CodecCtx->height,PIX_FMT_YUV420P,SWS_BICUBIC,NULL,
                    NULL,NULL);
    if (!m_ConvertCtx)
        return 7;//error

    return 0;

}

int CXVEncodeObj::EncodeYUV420P(void * inbuf, int inbufsize, void * outbuf, int outbufsize)
{
    if (inbufsize!=m_inbufMaxSize)
        return -1;

    memcpy(m_YUVFrame->data[0],inbuf,inbufsize);
   
    int outsize = avcodec_encode_video(m_CodecCtx,(uint8_t *)m_OutBuffer,CVIDEO_OUTBUFFERSIZE,m_YUVFrame);

    memcpy(outbuf,m_OutBuffer,(outbufsize>outsize ? outsize : outbufsize));

    return outsize;

}

int CXVEncodeObj::EncodeRGB24(void * inbuf, int inbufsize, void * outbuf, int outbufsize, int * IsKey)
{
    if (inbufsize!=m_inbufMaxSize*2)
        return -1;

    memcpy(m_RGBFrame->data[0],inbuf,inbufsize);

    sws_scale(
        m_ConvertCtx,
        m_RGBFrame->data,
        m_RGBFrame->linesize,
        0,
        m_CodecCtx->height,
        m_YUVFrame->data,
        m_YUVFrame->linesize);
   
    int outsize = avcodec_encode_video(m_CodecCtx,(uint8_t *)m_OutBuffer,CVIDEO_OUTBUFFERSIZE,m_YUVFrame);

    memcpy(outbuf,m_OutBuffer,(outbufsize>=outsize ? outsize : outbufsize));

    *IsKey = m_CodecCtx->coded_frame->key_frame;

    return outsize;

}

void CXVEncodeObj::FinalCodec()
{
    if (m_ConvertCtx)
    {
        sws_freeContext(m_ConvertCtx);
        m_ConvertCtx = NULL;
    }

    if (m_RGBFrame)
    {
        av_free(m_RGBFrame->data[0]);
        av_free(m_RGBFrame);
        m_RGBFrame = NULL;
    }

    if (m_YUVFrame)
    {
        av_free(m_YUVFrame->data[0]);
        av_free(m_YUVFrame);
        m_YUVFrame = NULL;
    }

    if (m_OutBuffer)
    {
        av_free(m_OutBuffer);
        m_OutBuffer = NULL;
    }

    if (m_CodecCtx)
    {
        if (m_CodecCtx->codec)
            avcodec_close(m_CodecCtx);
        av_free(m_CodecCtx);
        m_CodecCtx = NULL;
    }
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int CXVDecodeObj::InitCodec()
{
    m_Codec = avcodec_find_decoder(CVIDEO_CODEC);
    if (!m_Codec)
        return 1;//not support this codec

    m_CodecCtx = avcodec_alloc_context();
    if (!m_CodecCtx)
        return 2;//maybe not enough memory

    m_CodecCtx->width = CVIDEO_WIDTH;
    m_CodecCtx->height = CVIDEO_HEIGHT;

    //if(m_Codec->capabilities&CODEC_CAP_TRUNCATED)
    //    m_CodecCtx->flags|= CODEC_FLAG_TRUNCATED;

    if (avcodec_open(m_CodecCtx,m_Codec)<0)
        return 3;//codec open failed

    m_DecodeFrame = avcodec_alloc_frame();
    if (!m_DecodeFrame)
        return 4;//maybe not enough memory

    m_RGBFrame = alloc_picture(PIX_FMT_BGR24,m_CodecCtx->width,m_CodecCtx->height);
    if (!m_RGBFrame)
        return 5;//maybe not enough memory

    m_ConvertCtx = sws_getContext(m_CodecCtx->width,m_CodecCtx->height,PIX_FMT_YUV420P,
                    m_CodecCtx->width,m_CodecCtx->height,PIX_FMT_BGR24,SWS_BICUBIC,NULL,
                    NULL,NULL);
    if (!m_ConvertCtx)
        return 6;//error
   
    return 0;
}

int CXVDecodeObj:ecodeVideo(void * inbuf, int inbufsize, void * outbuf, int outbufsize)
{
    uint8_t * inptr = (uint8_t *)inbuf;
    int size = inbufsize;
    int got_picture = 0;
    while (size>0)
    {
        int len = avcodec_decode_video(m_CodecCtx,m_DecodeFrame,&got_picture,inptr,size);
        if (len<0)
            return -1;//error
        if (got_picture)
        {
            sws_scale(
                m_ConvertCtx,
                m_DecodeFrame->data,
                m_DecodeFrame->linesize,
                0,
                m_CodecCtx->height,
                m_RGBFrame->data,
                m_RGBFrame->linesize);

            int outlen = (m_RGBFrame->linesize[0]*m_CodecCtx->height>=outbufsize ? outbufsize : m_RGBFrame->linesize[0]*m_CodecCtx->height);
            memcpy(outbuf, m_RGBFrame->data[0],outlen);
            return outlen;
        }
        size -= len;
        inptr += len;
    }
    return 0;
}

void CXVDecodeObj::FinalCodec()
{
    if (m_ConvertCtx)
    {
        sws_freeContext(m_ConvertCtx);
        m_ConvertCtx = NULL;
    }

    if (m_RGBFrame)
    {
        av_free(m_RGBFrame->data[0]);
        av_free(m_RGBFrame);
        m_RGBFrame = NULL;
    }

    if (m_DecodeFrame)
    {
        av_free(m_DecodeFrame);
        m_DecodeFrame = NULL;
    }

    if (m_CodecCtx)
    {
        if (m_CodecCtx->codec)
            avcodec_close(m_CodecCtx);
        av_free(m_CodecCtx);
    }
}

posted @ 2012-12-03 16:05  李伯波  阅读(664)  评论(0编辑  收藏  举报