zoukankan      html  css  js  c++  java
  • H.264编码算法的实现

    H.264编码算法的实现

             在H.264编码具体实现过程中,采用了目前国际上应用最广泛的开源编码器X.264作为实现的基础。X.264和JM系列编码器、T.264编码器相比 有着优秀的性能和出色效果。由于X.264没有提供直接的开发API,所以在本系统中的编码部分重新封装了X.264的编码API,便于软件系统的设计和 使用。以下是本系统中H.264编码的具体实现过程:

    1)      RGB和YUV颜色空间的转换

             在系统中通过Logitech摄像头获得的视频数据为RGB24格式,但是X.264的输入流为标准的YUV(4:2:0)的图像子采样格式。因此,在编 码前需要将RGB颜色空间转换为YUV的颜色空间。实现的函数调用有InitLookupTable()用于初始化色彩空间转换;

    RGB2YUV420(int x_dim, int y_dim, unsigned char *bmp, unsigned char *yuv, int flip);用于实际的转换。由于人眼的生理特性,经过图像子采样后,实际的图像大小已经减小为采样前的1.5个样本点,即减小了一半的数据量。

    2)      设置H.264编码参数

             使用x264_param_default(x264_param_t *param)对当前需要编码的图像参数进行设置。包括数据帧数量(param .i_frame_total)、采样图像的长宽度和高度(param .i_width,param .i_height)、视频数据比特率(param .rc.i_bitrate) 、视频数据帧率(param .i_fps_num)等参数进行设置,以完成编码前预设置。

    3)      初始化编码器

             将上步中的设置作为编码器初始化的参数,x264_t *x264_encoder_open   ( x264_param_t *param )。如果初始化失败将返回NULL,在这里需要对编码器初始化结果进行处理。

    4)      分配编码空间

             如果编码器初始化成功,则需要为本次处理分配内存空间

    Void x264_picture_alloc(x264_picture_t *pic, int i_csp, int i_width, int i_height)。

    5)      图像编码

             将以上步骤初始化后的数据作为编码输入,使用下面的方法进行编码:

    int x264_encoder_encode( x264_t *h,x264_nal_t **pp_nal, int *pi_nal,x264_picture_t *pic_in,x264_picture_t *pic_out );

    6)      资源回收

             编码完成后,需要回收系统资源和关闭编码器,使用以下函数调用实现回收。

    void x264_picture_clean( x264_picture_t *pic );

    void x264_encoder_close( x264_t *h );

    至此,完成了H.264编码,编码后的数据量将大大减小。我们可以对编码后的数据做相关的进一步处理。

    H.264编码算法的完整源代码

    文件:VideoEncoderX264.h

    class CVideoEncoderX264 : 
    {
    public:
     CVideoEncoderX264(void);
     ~CVideoEncoderX264(void);

     virtual bool Connect(CVideoEnDecodeNotify* pNotify, const CVideoEnDecodeItem& Item);
     virtual void Release(void);
     virtual void Encode(BYTE* pInData, int nLen, BYTE* pOutBuf, int& nOutLen, int& nKeyFrame);

    private:
      x264_picture_t m_Pic;
      x264_t *h;
      x264_param_t param;

      void Flush(void);
    };

    文件:VideoEncoderX264.cpp

    bool CVideoEncoderX264::Connect(CVideoEnDecodeNotify* pNotify, const CVideoEnDecodeItem& Item)
    {
     CBase::Connect(pNotify, Item);

     ParseSize(Item.m_stSize);

     x264_param_default( &param );

     param.i_threads = 1;

     param.i_frame_total = 0;

     param.i_width  = m_nWidth;
     param.i_height = m_nHeight;

     param.i_keyint_min = Item.m_nKeyInterval;
     param.i_keyint_max = Item.m_nKeyInterval * 10;

     param.i_fps_num = Item.m_nFps;*/
     param.i_log_level = X264_LOG_NONE;

    if( ( h = x264_encoder_open( &param ) ) == NULL )
        {
            return false;
        }

        /* Create a new pic */
        x264_picture_alloc( &m_Pic, X264_CSP_I420, param.i_width, param.i_height );

     return true;
    }

    void CVideoEncoderX264::Release(void)
    {
     Flush();

     x264_picture_clean( &m_Pic );
        x264_encoder_close( h );

     CBase::Release();
    }

    void CVideoEncoderX264::Encode(BYTE* pInData, int nLen, BYTE* pOutBuf, int& nOutLen, int& nKeyFrame)
    {
     if(nLen != param.i_width * param.i_height * 3)
      return;

     param.i_frame_total ++;

     memcpy(m_Pic.img.plane[0], pInData, param.i_width * param.i_height);
     memcpy(m_Pic.img.plane[1], pInData + param.i_width * param.i_height, param.i_width * param.i_height / 4);
     memcpy(m_Pic.img.plane[2], pInData + param.i_width * param.i_height * 5 / 4, param.i_width * param.i_height / 4);  

     m_Pic.i_pts = (int64_t)param.i_frame_total * param.i_fps_den;

     static x264_picture_t pic_out;
        x264_nal_t *nal = NULL;
        int i_nal, i;

        if( &m_Pic )
        {
            m_Pic.i_type = X264_TYPE_AUTO;
            m_Pic.i_qpplus1 = 0;
        }

     //TraceTime("x264_encoder_encode begin");

        if( x264_encoder_encode( h, &nal, &i_nal, &m_Pic, &pic_out ) < 0 )   {
      return;
        }

     //TraceTime("x264_encoder_encode   end");

     int nOutCanUse = nOutLen;
     nOutLen = 0;
        for( i = 0; i < i_nal; i++ )
        {
      int i_size = 0;

      if( ( i_size = x264_nal_encode( pOutBuf + nOutLen, &nOutCanUse, 1, &nal[i] ) ) > 0 )
      {
       nOutLen += i_size;
       nOutCanUse -= i_size;
      } 
     }

     nKeyFrame = pic_out.i_type==X264_TYPE_IDR;// || (pic_out.i_type==X264_TYPE_I && coCfg->x264_max_ref_frames==1);
    }


    void CVideoEncoderX264::Flush(void)
    {
     x264_picture_t pic_out;
        x264_nal_t *nal;
        int i_nal, i;
        int i_file = 0;

        if( x264_encoder_encode( h, &nal, &i_nal, NULL, &pic_out ) < 0 ){

        }
    }

  • 相关阅读:
    不平衡数据集的处理方法
    爬楼梯问题
    Tensorflow object detection API 搭建物体识别模型(四)
    基于jieba,TfidfVectorizer,LogisticRegression进行搜狐新闻文本分类
    利用jieba,word2vec,LR进行搜狐新闻文本分类
    Arthas协助排查线上skywalking不可用问题
    springboot集成jpa操作mybatis数据库
    es性能调优---写优化操作
    Skywalking的存储配置与调优
    docer
  • 原文地址:https://www.cnblogs.com/shulianghe/p/3724155.html
Copyright © 2011-2022 走看看