H264 encode and decode

http://www.chinavideo.org/archiver/?tid-14008.html

 

 

关于实时编码解码问题  请教  分享一个编码代码 H264

首先分享一个编码代码使用的是X264  core 122版本 [code]
H264EncWrapper::~H264EncWrapper()
{
        Destroy();
}

int H264EncWrapper::Initialize(int iWidth, int iHeight, int iRateBit, int iFps)
{
    m_param.i_fps_num = iFps;
    m_param.i_fps_den = 1;
    m_param.rc.i_bitrate = iRateBit;
        m_param.rc.i_vbv_max_bitrate=128;
        m_param.i_threads = X264_THREADS_AUTO;
        m_param.i_width = iWidth;
        m_param.i_height = iHeight;
        m_param.i_bframe=0;
        m_param.i_frame_reference=3;
        m_param.rc.i_rc_method=X264_RC_ABR;//X264_RC_CQP ;
        m_param.i_csp = X264_CSP_I420;
        m_param.b_visualize=1;

        m_param.b_cabac =0;    
        m_param.b_interlaced=0;
        m_param.i_level_idc=21;
        m_param.i_keyint_max=m_param.i_fps_num*1.5;
        m_param.i_keyint_min=1;

        m_param.pf_log = NULL; //x264log;
        m_param.p_log_private = NULL;
        m_param.i_log_level=X264_LOG_NONE;



    //m_param.i_keyint_max = 8;
    //m_param.i_keyint_min = 4;

    /* 根据输入参数param初始化总结构 x264_t *h     */
    if( ( m_h = x264_encoder_open( &m_param) ) == NULL )
    {
        fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" );
        return -1;
    }

       
        int i_nal;
        if(x264_encoder_headers( m_h, &m_headers, &i_nal )<0)
        {
                fprintf( stderr, "x264 [error]: x264_encoder_headers failed\n" );
                return -1;
        }

    x264_picture_alloc( &m_pic, X264_CSP_I420, m_param.i_width, m_param.i_height );
    m_pic.i_type = X264_TYPE_AUTO;
    m_pic.i_qpplus1 = 0;
   
    return 0;
}

int H264EncWrapper::Destroy()
{
        x264_picture_clean( &m_pic );
        x264_encoder_close(m_h);

   return 0;
}

//编码
int H264EncWrapper::Encode(unsigned char* szYUVFrame, unsigned char * pOutputBuffer)
{
        m_pic.img.i_plane = 3;
        m_pic.img.plane[0] = szYUVFrame;
        m_pic.img.plane[1] = szYUVFrame + m_param.i_width * m_param.i_height;
        m_pic.img.plane[2] = (unsigned char *)m_pic.img.plane[1] +  m_param.i_width * m_param.i_height / 4;
        m_pic.img.plane[3] = 0;
   
    m_pic.i_pts = (int64_t)m_iFrameNum * m_param.i_fps_den;

    x264_picture_t pic_out;
    x264_nal_t *nal;
    int i_nal, i; // nal的个数

    if( x264_encoder_encode( m_h, &nal, &i_nal, &m_pic, &pic_out ) < 0 )
    {
        fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" );
        return -1;
    }

        if(i_nal==0)
        {
                //m_iFrameNum++;
                return 0;
        }

        int result=0;
  

        for( i = 0; i < i_nal; i++ )
        {
                memcpy(pOutputBuffer, nal[i].p_payload, nal[i].i_payload);
                pOutputBuffer += nal[i].i_payload;
                result += nal[i].i_payload;
        }

    m_iFrameNum++;
    return result;
}
[/code]



编码出来可以用播放器播放 也可以用ffplay 播放 和 ffmpeg解码




请教一个问题  在我解码的时候 解码几针后出现 avcodec_decode_video2 函数崩溃了
[attach]1780[/attach]

而且出现了这个提示
[attach]1781[/attach]

但我通过软件查看数据流发现有PPS 和 SPS帧   
[attach]1782[/attach]

我用的是最新的ffmpeg库 

附上解码部分代码
主函数中:
[code]        avcodec_register_all(); 
        av_register_all();
       
        m_pCodec=avcodec_find_decoder(CODEC_ID_H264); 
        if(m_pCodec==NULL)
        {
                printf("Error avcodec_find_decoder");
                return -1;
        }
       
        m_pCodecContext=avcodec_alloc_context();
        if(m_pCodecContext==NULL)
        {
                printf("Error avcodec_alloc_context");
                return -1;
        }

        m_pCodecContext->width = 320;
        m_pCodecContext->height = 240;
        //m_pCodecContext->pix_fmt = PIX_FMT_YUV420P;
        //m_pCodecContext->codec_id  = CODEC_ID_H264;
        m_pCodecContext->pix_fmt = PIX_FMT_YUV420P;
        int iRet = avcodec_open(m_pCodecContext,m_pCodec);

        if(iRet<0)
        {
                printf("Error avcodec_open");
                return -1;
        }

        m_pFrame=avcodec_alloc_frame();
        if(m_pFrame==NULL)
        {
                printf("Error avcodec_alloc_frame");
                return -1;
        }

        m_pFormatCtx=avformat_alloc_context();

        if (!m_pFormatCtx)//分配内存失败
        {
                printf("avformat_alloc_context error\n");      
                return -1;    
        }
        m_parser = av_parser_init(CODEC_ID_H264);
        if(!m_parser)
                return -1; [/code]

解码函数:
[code]VCodecContext* m_pCodecContext; 
AVFrame * m_pFrame;
AVFormatContext *m_pFormatCtx;
AVCodecParserContext * m_parser;

static int DecodeFrame(uint8_t *data , int size)
{
        int got_picture=0;
        AVPacket avp;
        av_init_packet(&avp);

        int right=0;
        avp.data=data;
        avp.size=size;

        int iRet = avcodec_decode_video2(m_pCodecContext,m_pFrame,&got_picture,&avp);

        if(iRet>=0)
        {
                if(got_picture)
                {

                        right++;
                }
        }
       
        return got_picture;
}

static void DecodeVideo(uint8_t * pInBuffer, int size)
{
        int pos=0;
        int64_t pts=AV_NOPTS_VALUE;
        int64_t dts=AV_NOPTS_VALUE;
        do
        {
                uint8_t *pout;
                int pout_len;
                int len= av_parser_parse2(m_parser,m_pCodecContext,&pout,&pout_len,
                        pInBuffer+pos,size-pos,pts,dts,AV_NOPTS_VALUE);

                pos +=len;

                if(pout_len >0 )
                {
                        DecodeFrame(pout,pout_len);
                }
        } while (pos<size);


        if(size<=0)
        {
                while(DecodeFrame(NULL,0));

        }

}
[/code]



希望大家能帮帮忙  ,  任何回复都十分感谢  !

louyily 发表于 2012-3-22 02:24 PM

你的数据来源 能不能保证 传入 解码器的 是一个个完整的 nal 单元,我之前做实时编码的时候 发现传入数据如果不是完整帧就有可能出错的,判断一下 nal的头吧

lovesxw 发表于 2012-3-22 02:36 PM

av_parser_parse2 函数不是校验完整吗? 如果完整的话 就会有返回 不完整就会等待输入 ?

louyily 发表于 2012-3-22 03:13 PM

我之前一直没有用 这个parser,是自己对nal 头做下了判断 因为解的数据是udp发过来的,会出现一些错误的包数据

lovesxw 发表于 2012-3-22 04:00 PM

[i=s] 本帖最后由 lovesxw 于 2012-3-22 04:26 PM 编辑 [/i]

我加了一个判断这回 不过还是不对

[code]
/*the return value is the head offset*/
static int findheader(unsigned char* databuf, int len)
{
       
        char aa[320*240*3]={0};
        CopyMemory(aa,databuf,len);
        int offset = 0;
        bool bFind=false;
        for(; offset< len -4; offset++,databuf++)
        {
                if(databuf[0] == 0x00 && databuf[1] == 0x00 && databuf[2] == 0x00 && databuf[3] == 0x01 && databuf[4] == 0x67)
                {       
                        bFind=true;
                        return offset;
                }
                if(databuf[0] == 0x00 && databuf[1] == 0x00 && databuf[2] == 0x00 && databuf[3] == 0x01 && databuf[4] == 0x65)
                {       
                        bFind=true;
                        return offset;
                }
                if(databuf[0] == 0x00 && databuf[1] == 0x00 && databuf[2] == 0x00 && databuf[3] == 0x01 && databuf[4] == 0x68)
                {       
                        bFind=true;
                        return offset;
                }
        }

        if(!bFind)
        {
                return -1;
        }
        return offset;
}

static int DecodeFrame(uint8_t *data , int size)
{
        //防止数据错误
        int offset = findheader(data,size);
        if(offset<0)
        {
                printf("Error data \n");
                return 0;
        }
        int got_picture=0;
        AVPacket avp;
        av_init_packet(&avp);

        int right=0;
        avp.data=data+offset;
        avp.size=size-offset;

        int iRet = avcodec_decode_video2(m_pCodecContext,m_pFrame,&got_picture,&avp);

        if(iRet>=0)
        {
                if(got_picture)
                {
                        right++;
                }
        }
       
        return got_picture;
}

static void DecodeVideo(uint8_t * pInBuffer, int size)
{
        int pos=0;
        int64_t pts=AV_NOPTS_VALUE;
        int64_t dts=AV_NOPTS_VALUE;
        do
        {
                uint8_t *pout;
                int pout_len;
                int len= av_parser_parse2(m_parser,m_pCodecContext,&pout,&pout_len,
                        pInBuffer+pos,size-pos,pts,dts,AV_NOPTS_VALUE);

                pos +=len;

                if(pout_len >0 )
                {
                        DecodeFrame(pout,pout_len);
                }
        } while (pos<size);


        if(size<=0)
        {
                while(DecodeFrame(NULL,0));

        }

}[/code]

这种判断可以吧?

louyily 发表于 2012-3-22 05:21 PM

会不会是av_parser_parse2的用法问题
看了下 我的解码流程 就是比你多了个av_free_packet(&packet);
:(等晚上 让版主来看看吧

lovesxw 发表于 2012-3-22 05:29 PM

o(︶︿︶)o 唉  不知道版主能不能帮忙。。。     这个函数是释放  好像和功能无关  愁啊

lovesxw 发表于 2012-3-22 09:00 PM

自己解决了   希望大家不要走弯路    原因是我自己编译的ffmpeg有问题 可以直接下载官方提供的 。
最终代码
[code]static int DecodeFrame(uint8_t *data , int size)
{
        int got_picture=0;
        AVPacket avp;
        av_init_packet(&avp);

        avp.data=data;
        avp.size=size;

        int iRet = avcodec_decode_video2(m_pCodecContext,m_pFrame,&got_picture,&avp);

        if(iRet>=0)
        {
                if(got_picture)
                {

                        FILE * fp;
                        if((fp=fopen("d:/testout.yuv","ab"))==NULL)
                        {
                                printf("cant open the file");
                                exit(0);
                        }
                        for(int i=0; i<m_pCodecContext->height; i++)
                                fwrite(m_pFrame->data[0] + i * m_pFrame->linesize[0], 1, m_pCodecContext->width, fp);
                        for(int i=0; i<m_pCodecContext->height/2; i++)
                                fwrite(m_pFrame->data[1] + i * m_pFrame->linesize[1], 1, m_pCodecContext->width/2, fp);
                        for(int i=0; i<m_pCodecContext->height/2; i++)
                                fwrite(m_pFrame->data[2] + i * m_pFrame->linesize[2], 1, m_pCodecContext->width/2, fp);

                        fclose(fp);
                }
        }
       
        return got_picture;
}

static void DecodeVideo(uint8_t * pInBuffer, int size)
{
        int pos=0;
        int64_t pts=AV_NOPTS_VALUE;
        int64_t dts=AV_NOPTS_VALUE;
        do
        {
                uint8_t *pout;
                int pout_len;
                int len= av_parser_parse2(m_parser,m_pCodecContext,&pout,&pout_len,
                        pInBuffer+pos,size-pos,pts,dts,AV_NOPTS_VALUE);

                pos +=len;

                if(pout_len >0 )
                {
                        DecodeFrame(pout,pout_len);
                }
        } while (pos<size);


        if(size<=0)
        {
                while(DecodeFrame(NULL,0));

        }

}
[/code]

保存为yuv图像  不需要检测header  以为我那个已经保证是完整的包了

lovesxw 发表于 2012-3-22 09:01 PM

对了 忘了free 我就不补充了

niulei20012001 发表于 2012-3-24 03:03 PM

[i=s] 本帖最后由 niulei20012001 于 2012-3-24 03:07 PM 编辑 [/i]

兄弟,我来给你补充完整[code]AVFrame * m_pFrame;

//AVFormatContext *m_pFormatCtx;

AVCodecParserContext * m_parser;

AVCodec *m_pCodec;
AVCodecContext *m_pCodecContext;

//初始化
bool Decode_init(unsigned int width,unsigned int height)
{
  m_pCodec=avcodec_find_decoder(CODEC_ID_H264); 
        if(m_pCodec==NULL)
        {
                printf("Error avcodec_find_decoder");
                return 0;
        }
        m_pCodecContext=avcodec_alloc_context();
        if(m_pCodecContext==NULL)
        {
                printf("Error avcodec_alloc_context");
                return 0;
        }
        m_pCodecContext->width = width;
        m_pCodecContext->height = height;
        //m_pCodecContext->codec_id  = CODEC_ID_H264;
        m_pCodecContext->pix_fmt = PIX_FMT_YUV420P;
        int iRet = avcodec_open(m_pCodecContext,m_pCodec);
        if(iRet<0)
        {
                printf("Error avcodec_open");
                return 0;
        }
        m_pFrame=avcodec_alloc_frame();
        if(m_pFrame==NULL)
        {
               printf("Error avcodec_alloc_frame");
                return 0;
        }
  //下面的内容,示例中没有
        //m_pFormatCtx=avformat_alloc_context();
        //if (!m_pFormatCtx)//分配内存失败
        //{
        //        printf("avformat_alloc_context error\n");      
        //        return 0;    
        //}
        m_parser = av_parser_init(CODEC_ID_H264);
        if(!m_parser)
                return 0;
return 1;
}
//释放
bool Decode_uninit()
{
av_free(m_pFrame);
avcodec_close(m_pCodecContext);
    av_free(m_pCodecContext);
return 1;
}

static int DecodeFrame(uint8_t *data , int size,unsigned char *yuvOutBuffer)
{
        int got_picture=0;
        AVPacket avp;
        av_init_packet(&avp);

        avp.data=data;
        avp.size=size;

        int iRet = avcodec_decode_video2(m_pCodecContext,m_pFrame,&got_picture,&avp);

        if(iRet>=0)
        {
                if(got_picture)
                {

                    for(int i=0,nDataLen=0;i<3;i++)
                                        {
                                                int nShift=(i==0)?0:1;
                                                PBYTE pYUVData=(PBYTE)m_pFrame->data[i];
                                                for(int j=0;j<(m_pCodecContext->height>>nShift);j++)
                                                {
                                                        memcpy(&yuvOutBuffer[nDataLen],pYUVData,(m_pCodecContext->width>>nShift));
                                                        pYUVData+=m_pFrame->linesize[i];
                                                        nDataLen+=(m_pCodecContext->width>>nShift);
                                                }
                                        }   
                                        /*FILE * fp;
                        if((fp=fopen("d:/testout.yuv","ab"))==NULL)
                        {
                                printf("cant open the file");
                                exit(0);
                        }
                        for(int i=0; i<m_pCodecContext->height; i++)
                                fwrite(m_pFrame->data[0] + i * m_pFrame->linesize[0], 1, m_pCodecContext->width, fp);
                        for(int i=0; i<m_pCodecContext->height/2; i++)
                                fwrite(m_pFrame->data[1] + i * m_pFrame->linesize[1], 1, m_pCodecContext->width/2, fp);
                        for(int i=0; i<m_pCodecContext->height/2; i++)
                                fwrite(m_pFrame->data[2] + i * m_pFrame->linesize[2], 1, m_pCodecContext->width/2, fp);

                        fclose(fp);*/
                }
        }
       
        return got_picture;
}
//调用入口函数
void DecodeVideo(uint8_t * pInBuffer, int size,unsigned char *yuvOutBuffer)
{
        int pos=0;
        int64_t pts=AV_NOPTS_VALUE;
        int64_t dts=AV_NOPTS_VALUE;
        do
        {
                uint8_t *pout;
                int pout_len;
int len= av_parser_parse2(m_parser,m_pCodecContext,&pout,&pout_len, pInBuffer+pos,size-pos,pts,dts,AV_NOPTS_VALUE);

                pos +=len;

                if(pout_len >0 )
                {
                        DecodeFrame(pout,pout_len,yuvOutBuffer);
                }
        } while (pos<size);


        if(size<=0)
        {
                while(DecodeFrame(NULL,0,yuvOutBuffer));

        }

}[/code]

qibo15193 发表于 2012-4-21 04:07 PM

这个代码没问题么?

cbzhaojay 发表于 2012-5-26 03:26 PM

[b]回复 [url=http://bbs.chinavideo.org/redirect.php?goto=findpost&pid=55342&ptid=14008]10#[/url] [i]niulei20012001[/i] [/b]
你好呀,兄弟, DecodeVideo你这个函数入口 传入的 pInBuffer是一个frame数据还是?
我传入了数据格式如下:
h264head sps h264head pps h264head +后面为一帧的数据
解码不成功也 兄弟能帮忙解释下么?

你可能感兴趣的:(h264)