HEVC预测块(PU)模式划分显示

本文介绍了如何改进HEVC解码器,以直观显示每帧的预测模式(PU)划分结果。通过调整代码,包括PU划分的数据结构、mode向量定义以及函数修改,成功实现了对HEVC和MV-HEVC的PU划分显示,使得每一帧的解码结果都能清晰呈现。

最近在做关于3D-HEVC的实验,很想直观显示出最终的预测模式(PU)划分结果。最近看到了一个帖子,动了HEVC解码器部分,能直观显示出PU划分结果,但是,只能显示一帧(即解码的第一帧 I-Slice), 后面的全乱了。对于做帧间的是不够的,必须把每帧的划分结果直观地显示出来。仔细看了他的教程,我在此基础进行了改进,目前能够正常显示出HEVC、MV-HEVC的PU划分结果。在此,感谢网站(程光曦微)的作者。

1. PU模式划分显示效果图

HEVC第一帧划分显示

HEVC帧间PU划分显示

2. HEVC decoder 代码修改

该程序是基于HM 11.0/3D-HTM的,废话不多说了,给出修改代码步骤。

2.1 PU划分数据结构体定义及宏定义

为了不改变源代码程序逻辑,我们所有修改的代码都放在自己定义的预处理命令宏定义中。
在TypeDef.h中,定义自己的条件编译预处理命令。
#define statistics_mode 1//用于统计输出块信息
在TypeDef.h中,定义保存PU划分坐标点结构体。
#if statistics_mode
	struct PtPair
	{
	  unsigned int _pt1x;
	  unsigned int _pt1y;
	  unsigned int _pt2x;
	  unsigned int _pt2y;
	  unsigned char mode;
	};
#endif

2.2 PU划分及mode向量定义

为了保存各帧CU及mode最终划分结果,在TAppDecTop.h文件中定义如下代码:
class TAppDecTop : public TAppDecCfg
{
private:
#if statistics_mode
	std::vector
   
     m_plistPt;//用于保存CU划分及mode结果
	std::vector
    
      flag;//用于保存每帧的mode数量
#endif

    
   

2.3 修改各函数头,将m_plistPt传递进去

在TAppDecTop.cpp文件中, 按照下面的方式替换源代码:
//原来的代码
bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
//修改成如下代码
#if statistics_mode
bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay,m_plistPt);
#else
bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
#endif
编译程序,肯定会出错,因为没有修改相应的函数头。在TDecTop.cpp文件中,按照下面的方式修改decode函数头:
#if statistics_mode
Bool TDecTop::decode(InputNALUnit& nalu, Int& iSkipFrame, Int& iPOCLastDisplay,std::vector
    
     & list)
#else
Bool TDecTop::decode(InputNALUnit& nalu, Int& iSkipFrame, Int& iPOCLastDisplay)
#endif

    
在TDecTop.h中,也需要对应修改decode函数声明,按照以下方式修改该函数声明:
#if statistics_mode
  Bool TDecTop::decode(InputNALUnit& nalu, Int& iSkipFrame, Int& iPOCLastDisplay,std::vector
    
     & list);
#else
  Bool  decode(InputNALUnit& nalu, Int& iSkipFrame, Int& iPOCLastDisplay);
#endif

    
接下来,将m_plistPt传递到xDecodeSlice函数中,将decode函数中的xDecodeSlice(nalu, iSkipFrame, iPOCLastDisplay)修改成xDecodeSlice(nalu, iSkipFrame, iPOCLastDisplay,list);即将m_plistPt传递到xDecodeSlice函数中。同样地,需要修改相应的函数头,在TDecTop.cpp文件中,修改对应的函数头,按照下面方式修改:
#if statistics_mode
Bool TDecTop::xDecodeSlice(InputNALUnit &nalu, Int &iSkipFrame, Int iPOCLastDisplay,std::vector
     
      & list )
#else
Bool TDecTop::xDecodeSlice(InputNALUnit &nalu, Int &iSkipFrame, Int iPOCLastDisplay )
#endif

     
在TDecTop.h中,按照下面方式替换DecodeSlice函数声明:
#if statistics_mode
Bool TDecTop::xDecodeSlice(InputNALUnit &nalu, Int &iSkipFrame, Int iPOCLastDisplay,std::vector
      
       & list );
#else
  Bool      xDecodeSlice(InputNALUnit &nalu, Int &iSkipFrame, Int iPOCLastDisplay);
#endif

      
接下来,在xDecodeSlice函数中,将m_cGopDecoder.decompressSlice(nalu.m_Bitstream, pcPic);替换成如下代码:
//  Decode a picture
#if statistics_mode
  m_cGopDecoder.decompressSlice(nalu.m_Bitstream, pcPic,list);
#else
  m_cGopDecoder.decompressSlice(nalu.m_Bitstream, pcPic);
#endif
不要忘了,修改对应的函数头和声明,按照下面方式修改:
在TDecTop.cpp文件中,
#if statistics_mode
Void TDecGop::decompressSlice(TComInputBitstream* pcBitstream, TComPic*& rpcPic, std::vector
      
       & list)
#else
Void TDecGop::decompressSlice(TComInputBitstream* pcBitstream, TComPic*& rpcPic)
#endif

      
在TDecTop.h文件中,
#if statistics_mode
  Void TDecGop::decompressSlice(TComInputBitstream* pcBitstream, TComPic*& rpcPic, std::vector
      
       & list);
#else
  Void  decompressSlice(TComInputBitstream* pcBitstream, TComPic*& rpcPic );
#endif

      
在decompressSlice函数中,将m_pcSliceDecoder->decompressSlice( ppcSubstreams, rpcPic, m_pcSbacDecoder, m_pcSbacDecoders) 修改成如下代码:
#if statistics_mode
  m_pcSliceDecoder->decompressSlice( ppcSubstreams, rpcPic, m_pcSbacDecoder, m_pcSbacDecoders, list);
#else
  m_pcSliceDecoder->decompressSlice( ppcSubstreams, rpcPic, m_pcSbacDecoder, m_pcSbacDecoders);
#endif
接着,修改相应的函数头函数声明:
在TDecSlice.cpp文件中,
#if statistics_mode
Void TDecSlice::decompressSlice(TComInputBitstream** ppcSubstreams, TComPic*& rpcPic, TDecSbac* pcSbacDecoder, TDecSbac* pcSbacDecoders, std::vector
          
           & list)
#else
Void TDecSlice::decompressSlice(TComInputBitstream** ppcSubstreams, TComPic*& rpcPic, TDecSbac* pcSbacDecoder, TDecSbac* pcSbacDecoders)
#endif

          
在TDecSlice.h文件中,
#if statistics_mode
  Void TDecSlice::decompressSlice(TComInputBitstream** ppcSubstreams, TComPic*& rpcPic, TDecSbac* pcSbacDecoder, TDecSbac* pcSbacDecoders, std::vector
        
         & list);
#else
  Void  decompressSlice   ( TComInputBitstream** ppcSubstreams,   TComPic*& rpcPic, TDecSbac* pcSbacDecoder, TDecSbac* pcSbacDecoders );
#endif

        

接下来,将decompressSlice函数中的m_pcCuDecoder->decompressCU ( pcCU );修改成如下代码:
#if statistics_mode
	m_pcCuDecoder->decodeCU     ( pcCU, uiIsLast, list);
	m_pcCuDecoder->decompressCU ( pcCU , list);
#else
    m_pcCuDecoder->decodeCU     ( pcCU, uiIsLast );
    m_pcCuDecoder->decompressCU ( pcCU );
#endif
当然,也有修改相应的函数头和函数声明:
在TDecCu.cpp文件中,
#if statistics_mode
Void TDecCu::decompressCU( TComDataCU* pcCU,std::vector
         
          & list )
#else
Void TDecCu::decompressCU( TComDataCU* pcCU )
#endif
{
#if statistics_mode
  xDecompressCU( pcCU, 0,  0,list );
#else
  xDecompressCU( pcCU, 0,  0);
#enif
}

         
在TDecCu.h文件中,
/// reconstruct CU information
#if statistics_mode
Void decompressCU( TComDataCU* pcCU,std::vector
         
          & list );
#else
  Void  decompressCU            ( TComDataCU* pcCU );
#endif

#if statistics_mode
Void xDecompressCU( TComDataCU* pcCU, UInt uiAbsPartIdx,  UInt uiDepth,std::vector
          
           & list );
#else
  Void xDecompressCU            ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth );
#endif

          
         

2.4 保存CU划分和mode选择结果

在xDecompressCU函数中,保存每一帧的CU划分结果及mode结果,在if( ( ( uiDepth < pcCU->getDepth( uiAbsPartIdx ) ) && ( uiDepth < g_uiMaxCUDepth - g_uiAddCUDepth ) ) || bBoundary )结束后,添加如下代码保存结果:
//==================================================================================//
  //==================================模式大小统计====================================//
  //==================================================================================//
#if statistics_mode
  struct PtPair tmp;
  tmp._pt1x=uiLPelX; tmp._pt1y=uiTPelY; tmp._pt2x=uiRPelX; tmp._pt2y=uiBPelY;tmp.mode=*pcCU->getPartitionSize();
  list.push_back(tmp);
#endif
接着,修改xDecompressCU函数中的xDecompressCU函数递归调用,
if(binSlice&&( uiLPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
      {
#if statistics_mode
        xDecompressCU(pcCU, uiIdx, uiNextDepth,list );
#else
		xDecompressCU(pcCU, uiIdx, uiNextDepth);
#endif
      }
到目前为止,数据保存完成。接下来,就是怎样把CU划分显示出来。

2.5 PU划分结果显示

在decode()函数中修改xFlushOutput和xWriteOutput函数调用,
#if statistics_mode
        xFlushOutput( pcListPic,m_plistPt,flag );
#else
		xFlushOutput( pcListPic);
#endif

#if statistics_mode
		  unsigned long temp=0;
		  for(int i=0;i
          
接着,修改xFlushOutput和xWriteOutput函数头和声明,
//TAppDecTop.cpp中修改对应的函数头
#if statistics_mode
Void TAppDecTop::xWriteOutput( TComList
           
            * pcListPic, UInt tId,std::vector
            
             & list,std::vector
             
              & flag)
#else
Void TAppDecTop::xWriteOutput( TComList
              
               * pcListPic, UInt tId)
#endif

#if statistics_mode
Void TAppDecTop::xFlushOutput( TComList
               
                * pcListPic,std::vector
                
                 & list,std::vector
                 
                  & flag ) #else Void TAppDecTop::xFlushOutput( TComList
                  
                   * pcListPic ) #endif //TAppDecTop.h中修改对应的函数声明 #if statistics_mode Void TAppDecTop::xWriteOutput( TComList
                   
                    * pcListPic, UInt tId,std::vector
                    
                     & list,std::vector
                     
                      & flag); Void TAppDecTop::xFlushOutput( TComList
                      
                       * pcListPic,std::vector
                       
                        & list,std::vector
                        
                         & flag ); #else Void xWriteOutput ( TComList
                         
                          * pcListPic , UInt tId); ///< write YUV to file Void xFlushOutput ( TComList
                          
                           * pcListPic ); ///< flush all remaining decoded pictures to file #endif 
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
现在到了最后关头,也是最重要的一部分,贴出xWriteOutput和xFlushOutput函数全部代码,不想具体说了,对照代码修改吧!
#if statistics_mode
Void TAppDecTop::xWriteOutput( TComList
           
            * pcListPic, UInt tId,std::vector
            
             & list,std::vector
             
              & flag)
#else
Void TAppDecTop::xWriteOutput( TComList
              
               * pcListPic, UInt tId)
#endif
#endif
{
  TComList
               
                ::iterator iterPic   = pcListPic->begin();
  Int not_displayed = 0;

  while (iterPic != pcListPic->end())
  {
    TComPic* pcPic = *(iterPic);
#if H_MV
    if(pcPic->getOutputMark() && pcPic->getPOC() > m_pocLastDisplay[decIdx])
#else
    if(pcPic->getOutputMark() && pcPic->getPOC() > m_iPOCLastDisplay)
#endif
    {
       not_displayed++;
    }
    iterPic++;
  }
  iterPic   = pcListPic->begin();
  
  while (iterPic != pcListPic->end())
  {
    TComPic* pcPic = *(iterPic);
	

    
#if H_MV
    if ( pcPic->getOutputMark() && (not_displayed >  pcPic->getNumReorderPics(tId) && pcPic->getPOC() > m_pocLastDisplay[decIdx]))
#else
    if ( pcPic->getOutputMark() && (not_displayed >  pcPic->getNumReorderPics(tId) && pcPic->getPOC() > m_iPOCLastDisplay))
#endif
    {
      // write to file
       not_displayed--;

#if statistics_mode
	TComPicYuv *p_dstyuv=new TComPicYuv;
	TComPicYuv *p_orgyuv=pcPic->getPicYuvRec();
	p_dstyuv->create(p_orgyuv->getWidth(),p_orgyuv->getHeight(),1,1,0);
	p_orgyuv->copyToPic(p_dstyuv);
	 Pel *pY=p_dstyuv->getLumaAddr();
		  UInt stride = p_dstyuv->getStride();
		  for(UInt index = 0; index < flag[0]; index++)
		  {
			for(UInt y = list[index]._pt1y; y <= list[index]._pt2y; y++)
			{
			  for(UInt x = list[index]._pt1x; x <= list[index]._pt2x; x++)
			  {
				  switch(list[index].mode)
				  {
				  case SIZE_2Nx2N:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_2NxN:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(y == list[index]._pt1y+(list[index]._pt2y-list[index]._pt1y+1)/2)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_Nx2N:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x+(list[index]._pt2x-list[index]._pt1x+1)/2)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_NxN:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(y == list[index]._pt1y+(list[index]._pt2y-list[index]._pt1y+1)/2)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x+(list[index]._pt2x-list[index]._pt1x+1)/2)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_2NxnU:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(y == list[index]._pt1y+(list[index]._pt2y-list[index]._pt1y+1)/4)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_2NxnD:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(y == list[index]._pt1y+3*(list[index]._pt2y-list[index]._pt1y+1)/4)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_nLx2N:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x+(list[index]._pt2x-list[index]._pt1x+1)/4)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  case SIZE_nRx2N:
					if(y == list[index]._pt1y )
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x+3*(list[index]._pt2x-list[index]._pt1x+1)/4)
					  pY[y*stride + x] = 0;
					if(x == list[index]._pt1x )
					  pY[y*stride + x] = 0;
					break;
				  default:
					break;

				  }
			  }
			}
		  }
	if(flag.size()>1)
	{
		list.erase(list.begin(),list.begin()+flag[0]);
		flag.erase(flag.begin());
	}
#endif

#if H_MV
      if ( m_pchReconFiles[decIdx] )
#else
      if ( m_pchReconFile )
#endif
      {
        const Window &conf = pcPic->getConformanceWindow();
        const Window &defDisp = m_respectDefDispWindow ? pcPic->getDefDisplayWindow() : Window();
#if H_MV
#if H_MV5
        assert( conf   .getScaledFlag() );
        assert( defDisp.getScaledFlag() );
#endif
#if statistics_mode
		m_tVideoIOYuvReconFile[decIdx]->write( p_dstyuv,
#else
        m_tVideoIOYuvReconFile[decIdx]->write( pcPic->getPicYuvRec(),
#endif
#else
#if statistics_mode
		m_cTVideoIOYuvReconFile.write( p_dstyuv,
#else
        m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(),
#endif
#endif
                                       conf.getWindowLeftOffset() + defDisp.getWindowLeftOffset(),
                                       conf.getWindowRightOffset() + defDisp.getWindowRightOffset(),
                                       conf.getWindowTopOffset() + defDisp.getWindowTopOffset(),
                                       conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset() );
      }
      
      // update POC of display order
#if H_MV
      m_pocLastDisplay[decIdx] = pcPic->getPOC();
#else
      m_iPOCLastDisplay = pcPic->getPOC();
#endif
      
      // erase non-referenced picture in the reference picture list after display
      if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
      {
#if !DYN_REF_FREE
        pcPic->setReconMark(false);
        
        // mark it should be extended later
        pcPic->getPicYuvRec()->setBorderExtension( false );
        
#else
        pcPic->destroy();
        pcListPic->erase( iterPic );
        iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
        continue;
#endif
      }
      pcPic->setOutputMark(false);
    }
    
    iterPic++;
  }
}

/** \param pcListPic list of pictures to be written to file
    \todo            DYN_REF_FREE should be revised
 */
#if H_MV
#if statistics_mode
Void TAppDecTop::xFlushOutput( TComList
                
                 * pcListPic, Int decIdx,std::vector
                 
                  & list,std::vector
                  
                   & flag) #else Void TAppDecTop::xFlushOutput( TComList
                   
                    * pcListPic, Int decIdx) #endif #else #if statistics_mode Void TAppDecTop::xFlushOutput( TComList
                    
                     * pcListPic,std::vector
                     
                      & list,std::vector
                      
                       & flag ) #else Void TAppDecTop::xFlushOutput( TComList
                       
                        * pcListPic ) #endif #endif { if(!pcListPic) { return; } TComList
                        
                         ::iterator iterPic = pcListPic->begin(); iterPic = pcListPic->begin(); while (iterPic != pcListPic->end()) { TComPic* pcPic = *(iterPic); if ( pcPic->getOutputMark() ) { // write to file #if statistics_mode TComPicYuv *p_dstyuv=new TComPicYuv; TComPicYuv *p_orgyuv=pcPic->getPicYuvRec(); p_dstyuv->create(p_orgyuv->getWidth(),p_orgyuv->getHeight(),1,1,0); p_orgyuv->copyToPic(p_dstyuv); Pel *pY=p_dstyuv->getLumaAddr(); UInt stride = p_dstyuv->getStride(); for(UInt index = 0; index < flag[0]; index++) { for(UInt y = list[index]._pt1y; y <= list[index]._pt2y; y++) { for(UInt x = list[index]._pt1x; x <= list[index]._pt2x; x++) { switch(list[index].mode) { case SIZE_2Nx2N: if(y == list[index]._pt1y ) pY[y*stride + x] = 0; if(x == list[index]._pt1x ) pY[y*stride + x] = 0; break; case SIZE_2NxN: if(y == list[index]._pt1y ) pY[y*stride + x] = 0; if(y == list[index]._pt1y+(list[index]._pt2y-list[index]._pt1y+1)/2) pY[y*stride + x] = 0; if(x == list[index]._pt1x ) pY[y*stride + x] = 0; break; case SIZE_Nx2N: if(y == list[index]._pt1y) pY[y*stride + x] = 0; if(x == list[index]._pt1x+(list[index]._pt2x-list[index]._pt1x+1)/2) pY[y*stride + x] = 0; if(x == list[index]._pt1x) pY[y*stride + x] = 0; break; case SIZE_NxN: if(y == list[index]._pt1y) pY[y*stride + x] = 0; if(y == list[index]._pt1y+(list[index]._pt2y-list[index]._pt1y+1)/2) pY[y*stride + x] = 0; if(x == list[index]._pt1x+(list[index]._pt2x-list[index]._pt1x+1)/2) pY[y*stride + x] = 0; if(x == list[index]._pt1x ) pY[y*stride + x] = 0; break; case SIZE_2NxnU: if(y == list[index]._pt1y ) pY[y*stride + x] = 0; if(y == list[index]._pt1y+(list[index]._pt2y-list[index]._pt1y+1)/4) pY[y*stride + x] = 0; if(x == list[index]._pt1x ) pY[y*stride + x] = 0; break; case SIZE_2NxnD: if(y == list[index]._pt1y ) pY[y*stride + x] = 0; if(y == list[index]._pt1y+3*(list[index]._pt2y-list[index]._pt1y+1)/4) pY[y*stride + x] = 0; if(x == list[index]._pt1x) pY[y*stride + x] = 0; break; case SIZE_nLx2N: if(y == list[index]._pt1y) pY[y*stride + x] = 0; if(x == list[index]._pt1x+(list[index]._pt2x-list[index]._pt1x+1)/4) pY[y*stride + x] = 0; if(x == list[index]._pt1x) pY[y*stride + x] = 0; break; case SIZE_nRx2N: if(y == list[index]._pt1y ) pY[y*stride + x] = 0; if(x == list[index]._pt1x+3*(list[index]._pt2x-list[index]._pt1x+1)/4) pY[y*stride + x] = 0; if(x == list[index]._pt1x ) pY[y*stride + x] = 0; break; default: break; } } } } if(flag.size()>1) { list.erase(list.begin(),list.begin()+flag[0]); flag.erase(flag.begin()); } #endif #if H_MV if ( m_pchReconFiles[decIdx] ) #else if ( m_pchReconFile ) #endif { const Window &conf = pcPic->getConformanceWindow(); const Window &defDisp = m_respectDefDispWindow ? pcPic->getDefDisplayWindow() : Window(); #if H_MV #if H_MV5 assert( conf .getScaledFlag() ); assert( defDisp.getScaledFlag() ); #endif #if statistics_mode m_tVideoIOYuvReconFile[decIdx]->write( p_dstyuv, #else m_tVideoIOYuvReconFile[decIdx]->write( pcPic->getPicYuvRec(), #endif #else #if statistics_mode m_cTVideoIOYuvReconFile.write( p_dstyuv, #else m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), #endif #endif conf.getWindowLeftOffset() + defDisp.getWindowLeftOffset(), conf.getWindowRightOffset() + defDisp.getWindowRightOffset(), conf.getWindowTopOffset() + defDisp.getWindowTopOffset(), conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset() ); } // update POC of display order #if H_MV m_pocLastDisplay[decIdx] = pcPic->getPOC(); #else m_iPOCLastDisplay = pcPic->getPOC(); #endif // erase non-referenced picture in the reference picture list after display if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true ) { #if !DYN_REF_FREE pcPic->setReconMark(false); // mark it should be extended later pcPic->getPicYuvRec()->setBorderExtension( false ); #else pcPic->destroy(); pcListPic->erase( iterPic ); iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised! continue; #endif } pcPic->setOutputMark(false); } #if !H_MV #if !DYN_REF_FREE if(pcPic) { pcPic->destroy(); delete pcPic; pcPic = NULL; } #endif #endif iterPic++; } #if H_MV m_pocLastDisplay[decIdx] = -MAX_INT; #else pcListPic->clear(); m_iPOCLastDisplay = -MAX_INT; #endif } 
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           

2.6 解码看结果

将先编码过后的文件,用解码器解码,就会看到最终结果。有的可能不知道怎样使用解码器,贴出命令行供参考
TAppDecoder -b 2Dmodes.bin -o 2Dmodes.yuv (TAppDecoder解码器应用程序,2Dmodes.bin编码器输出的压缩文件,2Dmodes.yuv 为重建文件名,2Dmodes.yuv 总的2Dmodes可以任意取名)。

3. 

如果不想自己修改代码,我这有编译好的解码器,解码过后,就会看到像我们展示出的样例结果,是不是很直观吧!该解码器在以下QQ群:101118126







评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值