文件位置  
openh264/codec/processing/scenechangedetection/SceneChangeDetection.cppopenh264/codec/processing/scenechangedetection/SceneChangeDetection.h  
 代码流程  
 
说明 :  通过代码流程分析,当METHOD_SCENE_CHANGE_DETECTION_SCREEN场景类型为时候,创建CSceneChangeDetectorScreen子类进行场景变化检测;当METHOD_SCENE_CHANGE_DETECTION_VIDEO场景类型为时,创建CSceneChangeDetectorVideo子类进行场景变化检测。  
 原理  
开关控制参数 :(bool)bEnableSceneChangeDetect  
 CSceneChangeDetectorVideo 类  
功能 :通过CSceneChangeDetection类模板调用CSceneChangeDetectorVideo类中方法实现摄像视频场景变化检测功能类过程 :  
 
 第一步:CSceneChangeDetection类中process 函数; 
   初始化变量、参数设置; 场景变化阈值iSceneChangeThresholdLarge、iSceneChangeThresholdMedium计算; 设置eSceneChangeIdc类型为SIMILAR_SCENE; 调用一个名为m_cDetector的对象的重载运算符(),传入m_sLocalParam作为参数,调用指向CSceneChangeDetectorVideo类中场景变化检测算法; 场景变化判断; 
     如果,iMotionBlockNum 大于等于iSceneChangeThresholdLarge,则设置eSceneChangeIdc类型为LARGE_CHANGED_SCENE; 否则,iMotionBlockNum 大于等于iSceneChangeThresholdMedium,则设置eSceneChangeIdc类型为MEDIUM_CHANGED_SCENE;       第二步:CSceneChangeDetectorVideo类中operator重载; 
   双层嵌套 for 循环处理以 8x8 为单位的图像块,即处理每个 8x8 块; 
     调用m_pfSad函数(指向具体的WelsSampleSad8x8_c函数)计算 iSad 值; 比较 iSad 与HIGH_MOTION_BLOCK_THRESHOLD的大小,将结果累加到iMotionBlockNum中; 指针更新,下一个 8x8 块以及下一行图像;         
  
原理图 :  相关源码 :  
 
template < typename  T > 
class  CSceneChangeDetection  :  public  IStrategy   { 
 public : 
  CSceneChangeDetection  ( EMethods eMethod,  int32_t  iCpuFlag) :  m_cDetector  ( m_sSceneChangeParam,  iCpuFlag)  { 
    m_eMethod   =  eMethod; 
    WelsMemset  ( & m_sSceneChangeParam,  0 ,  sizeof  ( m_sSceneChangeParam) ) ; 
  } 
  ~ CSceneChangeDetection ( )  { 
  } 
  EResult Process  ( int32_t  iType,  SPixMap*  pSrcPixMap,  SPixMap*  pRefPixMap)  { 
    EResult eReturn =  RET_INVALIDPARAM; 
    m_sLocalParam. iWidth =  pSrcPixMap-> sRect. iRectWidth; 
    m_sLocalParam. iHeight =  pSrcPixMap-> sRect. iRectHeight; 
    m_sLocalParam. iBlock8x8Width =  m_sLocalParam. iWidth >>  3 ; 
    m_sLocalParam. iBlock8x8Height =  m_sLocalParam. iHeight >>  3 ; 
    m_sLocalParam. pRefY =  ( uint8_t * ) pRefPixMap-> pPixel[ 0 ] ; 
    m_sLocalParam. pCurY =  ( uint8_t * ) pSrcPixMap-> pPixel[ 0 ] ; 
    m_sLocalParam. iRefStride =  pRefPixMap-> iStride[ 0 ] ; 
    m_sLocalParam. iCurStride =  pSrcPixMap-> iStride[ 0 ] ; 
    m_sLocalParam. pStaticBlockIdc =  m_sSceneChangeParam. pStaticBlockIdc; 
    int32_t  iBlock8x8Num =  m_sLocalParam. iBlock8x8Width *  m_sLocalParam. iBlock8x8Height; 
    int32_t  iSceneChangeThresholdLarge =  WelsStaticCast  ( int32_t , 
                                         m_cDetector. GetSceneChangeMotionRatioLarge ( )  *  iBlock8x8Num +  0.5f  +  PESN) ; 
    int32_t  iSceneChangeThresholdMedium =  WelsStaticCast  ( int32_t , 
                                          m_cDetector. GetSceneChangeMotionRatioMedium ( )  *  iBlock8x8Num +  0.5f  +  PESN) ; 
    m_sSceneChangeParam. iMotionBlockNum =  0 ; 
    m_sSceneChangeParam. iFrameComplexity =  0 ; 
    m_sSceneChangeParam. eSceneChangeIdc =  SIMILAR_SCENE; 
    m_cDetector  ( m_sLocalParam) ; 
    if  ( m_sSceneChangeParam. iMotionBlockNum >=  iSceneChangeThresholdLarge)  { 
      m_sSceneChangeParam. eSceneChangeIdc =  LARGE_CHANGED_SCENE; 
    }  else  if  ( m_sSceneChangeParam. iMotionBlockNum >=  iSceneChangeThresholdMedium)  { 
      m_sSceneChangeParam. eSceneChangeIdc =  MEDIUM_CHANGED_SCENE; 
    } 
    eReturn =  RET_SUCCESS; 
    return  eReturn; 
  } 
  EResult Get  ( int32_t  iType,  void *  pParam)  { 
    if  ( pParam ==  NULL )  { 
      return  RET_INVALIDPARAM; 
    } 
    *  ( SSceneChangeResult* ) pParam =  m_sSceneChangeParam; 
    return  RET_SUCCESS; 
  } 
  EResult Set  ( int32_t  iType,  void *  pParam)  { 
    if  ( pParam ==  NULL )  { 
      return  RET_INVALIDPARAM; 
    } 
    m_sSceneChangeParam =  *  ( SSceneChangeResult* ) pParam; 
    return  RET_SUCCESS; 
  } 
 private : 
  SSceneChangeResult m_sSceneChangeParam; 
  SLocalParam m_sLocalParam; 
  T          m_cDetector; 
} ; 
  
CSceneChangeDetectorVideo类  
class  CSceneChangeDetectorVideo  { 
 public : 
  CSceneChangeDetectorVideo  ( SSceneChangeResult&  sParam,  int32_t  iCpuFlag)  :  m_sParam  ( sParam)  { 
    m_pfSad =  WelsSampleSad8x8_c; 
# ifdef  X86_ASM  
    if  ( iCpuFlag &  WELS_CPU_SSE2)  { 
      m_pfSad =  WelsSampleSad8x8_sse21; 
    } 
# endif  
# ifdef  HAVE_NEON  
    if  ( iCpuFlag &  WELS_CPU_NEON)  { 
      m_pfSad =  WelsProcessingSampleSad8x8_neon; 
    } 
# endif  
# ifdef  HAVE_NEON_AARCH64  
    if  ( iCpuFlag &  WELS_CPU_NEON)  { 
      m_pfSad =  WelsProcessingSampleSad8x8_AArch64_neon; 
    } 
# endif  
# ifdef  HAVE_MMI  
    if  ( iCpuFlag &  WELS_CPU_MMI)  { 
      m_pfSad =  WelsSampleSad8x8_mmi; 
    } 
# endif  
    m_fSceneChangeMotionRatioLarge =  SCENE_CHANGE_MOTION_RATIO_LARGE_VIDEO; 
    m_fSceneChangeMotionRatioMedium =  SCENE_CHANGE_MOTION_RATIO_MEDIUM; 
  } 
  virtual  ~ CSceneChangeDetectorVideo ( )  { 
  } 
  void  operator ( )  ( SLocalParam&  sLocalParam)  { 
    int32_t  iRefRowStride =  0 ,  iCurRowStride =  0 ; 
    uint8_t *  pRefY =  sLocalParam. pRefY; 
    uint8_t *  pCurY =  sLocalParam. pCurY; 
    uint8_t *  pRefTmp =  NULL ,  * pCurTmp =  NULL ; 
    iRefRowStride  =  sLocalParam. iRefStride <<  3 ; 
    iCurRowStride  =  sLocalParam. iCurStride <<  3 ; 
    for  ( int32_t  j =  0 ;  j <  sLocalParam. iBlock8x8Height;  j++ )  { 
      pRefTmp =  pRefY; 
      pCurTmp =  pCurY; 
      for  ( int32_t  i =  0 ;  i <  sLocalParam. iBlock8x8Width;  i++ )  { 
        int32_t  iSad =  m_pfSad  ( pCurTmp,  sLocalParam. iCurStride,  pRefTmp,  sLocalParam. iRefStride) ; 
        m_sParam. iMotionBlockNum +=  iSad >  HIGH_MOTION_BLOCK_THRESHOLD; 
        pRefTmp +=  8 ; 
        pCurTmp +=  8 ; 
      } 
      pRefY +=  iRefRowStride; 
      pCurY +=  iCurRowStride; 
    } 
  } 
  float   GetSceneChangeMotionRatioLarge ( )  const  { 
    return  m_fSceneChangeMotionRatioLarge; 
  } 
  float   GetSceneChangeMotionRatioMedium ( )  const  { 
    return  m_fSceneChangeMotionRatioMedium; 
  } 
 protected : 
  SadFuncPtr m_pfSad; 
  SSceneChangeResult&  m_sParam; 
  float     m_fSceneChangeMotionRatioLarge; 
  float     m_fSceneChangeMotionRatioMedium; 
} ; 
  
 
int32_t  WelsSampleSad8x8_c  ( uint8_t *  pSample1,  int32_t  iStride1,  uint8_t *  pSample2,  int32_t  iStride2)  { 
  int32_t  iSadSum =  0 ; 
  int32_t  i =  0 ; 
  uint8_t *  pSrc1 =  pSample1; 
  uint8_t *  pSrc2 =  pSample2; 
  for  ( i =  0 ;  i <  8 ;  i++ )  { 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 0 ]  -  pSrc2[ 0 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 1 ]  -  pSrc2[ 1 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 2 ]  -  pSrc2[ 2 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 3 ]  -  pSrc2[ 3 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 4 ]  -  pSrc2[ 4 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 5 ]  -  pSrc2[ 5 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 6 ]  -  pSrc2[ 6 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 7 ]  -  pSrc2[ 7 ] ) ) ; 
    pSrc1 +=  iStride1; 
    pSrc2 +=  iStride2; 
  } 
  return  iSadSum; 
} 
  
 CSceneChangeDetectorScreen类  
功能 :通过CSceneChangeDetection类模板调用CSceneChangeDetectorScreen类中方法实现桌面视频场景变化检测功能类过程 :  
 
 第一步:同CSceneChangeDetectorVideo类中检测过程; 第二步:CSceneChangeDetectorScreen类中operator重载; 
   获取滚动检测标志bScrollDetectFlag和 mv 坐标iScrollMvX、iScrollMvY; 初始化工作; 双层 for 嵌套循环处理每个 8x8 图像块; 
     调用m_pfSad函数计算 iSad; 如果 iSad 为 0,则标记当前块为COLLOCATED_STATIC,表明是静止的; 如果滚动检测标志为真,并且滚动向量不为空,当前块的坐标加上滚动向量后仍在图像范围内; 
       使用滚动向量调整参考块的位置pRefTmpScroll; 再次调用m_pfSad函数,得到iSadScroll值; 如果 iSadScroll 为 0,则标记当前块为COLLOCATED_STATIC,表明是静止的; 否则, 
         将 iSad 累加到iFrameComplexity; 判断 iSad 与HIGH_MOTION_BLOCK_THRESHOLD的大小关系,将结果累加到iMotionBlockNum;       否则, 
       将 iSad 累加到iFrameComplexity; 判断 iSad 与HIGH_MOTION_BLOCK_THRESHOLD的大小关系,将结果累加到iMotionBlockNum;    更新图像块位置。         
  
相关源码 :  
 
template < typename  T > 
class  CSceneChangeDetection  :  public  IStrategy   { 
 public : 
  CSceneChangeDetection  ( EMethods eMethod,  int32_t  iCpuFlag) :  m_cDetector  ( m_sSceneChangeParam,  iCpuFlag)  { 
    m_eMethod   =  eMethod; 
    WelsMemset  ( & m_sSceneChangeParam,  0 ,  sizeof  ( m_sSceneChangeParam) ) ; 
  } 
  ~ CSceneChangeDetection ( )  { 
  } 
  EResult Process  ( int32_t  iType,  SPixMap*  pSrcPixMap,  SPixMap*  pRefPixMap)  { 
    EResult eReturn =  RET_INVALIDPARAM; 
    m_sLocalParam. iWidth =  pSrcPixMap-> sRect. iRectWidth; 
    m_sLocalParam. iHeight =  pSrcPixMap-> sRect. iRectHeight; 
    m_sLocalParam. iBlock8x8Width =  m_sLocalParam. iWidth >>  3 ; 
    m_sLocalParam. iBlock8x8Height =  m_sLocalParam. iHeight >>  3 ; 
    m_sLocalParam. pRefY =  ( uint8_t * ) pRefPixMap-> pPixel[ 0 ] ; 
    m_sLocalParam. pCurY =  ( uint8_t * ) pSrcPixMap-> pPixel[ 0 ] ; 
    m_sLocalParam. iRefStride =  pRefPixMap-> iStride[ 0 ] ; 
    m_sLocalParam. iCurStride =  pSrcPixMap-> iStride[ 0 ] ; 
    m_sLocalParam. pStaticBlockIdc =  m_sSceneChangeParam. pStaticBlockIdc; 
    int32_t  iBlock8x8Num =  m_sLocalParam. iBlock8x8Width *  m_sLocalParam. iBlock8x8Height; 
    int32_t  iSceneChangeThresholdLarge =  WelsStaticCast  ( int32_t , 
                                         m_cDetector. GetSceneChangeMotionRatioLarge ( )  *  iBlock8x8Num +  0.5f  +  PESN) ; 
    int32_t  iSceneChangeThresholdMedium =  WelsStaticCast  ( int32_t , 
                                          m_cDetector. GetSceneChangeMotionRatioMedium ( )  *  iBlock8x8Num +  0.5f  +  PESN) ; 
    m_sSceneChangeParam. iMotionBlockNum =  0 ; 
    m_sSceneChangeParam. iFrameComplexity =  0 ; 
    m_sSceneChangeParam. eSceneChangeIdc =  SIMILAR_SCENE; 
    m_cDetector  ( m_sLocalParam) ; 
    if  ( m_sSceneChangeParam. iMotionBlockNum >=  iSceneChangeThresholdLarge)  { 
      m_sSceneChangeParam. eSceneChangeIdc =  LARGE_CHANGED_SCENE; 
    }  else  if  ( m_sSceneChangeParam. iMotionBlockNum >=  iSceneChangeThresholdMedium)  { 
      m_sSceneChangeParam. eSceneChangeIdc =  MEDIUM_CHANGED_SCENE; 
    } 
    eReturn =  RET_SUCCESS; 
    return  eReturn; 
  } 
  EResult Get  ( int32_t  iType,  void *  pParam)  { 
    if  ( pParam ==  NULL )  { 
      return  RET_INVALIDPARAM; 
    } 
    *  ( SSceneChangeResult* ) pParam =  m_sSceneChangeParam; 
    return  RET_SUCCESS; 
  } 
  EResult Set  ( int32_t  iType,  void *  pParam)  { 
    if  ( pParam ==  NULL )  { 
      return  RET_INVALIDPARAM; 
    } 
    m_sSceneChangeParam =  *  ( SSceneChangeResult* ) pParam; 
    return  RET_SUCCESS; 
  } 
 private : 
  SSceneChangeResult m_sSceneChangeParam; 
  SLocalParam m_sLocalParam; 
  T          m_cDetector; 
} ; 
  
CSceneChangeDetectorScreen类  
class  CSceneChangeDetectorScreen  :  public  CSceneChangeDetectorVideo   { 
 public : 
  CSceneChangeDetectorScreen  ( SSceneChangeResult&  sParam,  int32_t  iCpuFlag)  :  CSceneChangeDetectorVideo  ( sParam, 
        iCpuFlag)  { 
    m_fSceneChangeMotionRatioLarge =  SCENE_CHANGE_MOTION_RATIO_LARGE_SCREEN; 
    m_fSceneChangeMotionRatioMedium =  SCENE_CHANGE_MOTION_RATIO_MEDIUM; 
  } 
  virtual  ~ CSceneChangeDetectorScreen ( )  { 
  } 
  void  operator ( )  ( SLocalParam&  sLocalParam)  { 
    bool  bScrollDetectFlag =  m_sParam. sScrollResult. bScrollDetectFlag; 
    int32_t  iScrollMvX =  m_sParam. sScrollResult. iScrollMvX; 
    int32_t  iScrollMvY =  m_sParam. sScrollResult. iScrollMvY; 
    int32_t  iRefRowStride =  0 ,  iCurRowStride =  0 ; 
    uint8_t *  pRefY =  sLocalParam. pRefY; 
    uint8_t *  pCurY =  sLocalParam. pCurY; 
    uint8_t *  pRefTmp =  NULL ,  * pCurTmp =  NULL ; 
    int32_t  iWidth =  sLocalParam. iWidth; 
    int32_t  iHeight =  sLocalParam. iHeight; 
    iRefRowStride  =  sLocalParam. iRefStride <<  3 ; 
    iCurRowStride  =  sLocalParam. iCurStride <<  3 ; 
    for  ( int32_t  j =  0 ;  j <  sLocalParam. iBlock8x8Height;  j++ )  { 
      pRefTmp =  pRefY; 
      pCurTmp =  pCurY; 
      for  ( int32_t  i =  0 ;  i <  sLocalParam. iBlock8x8Width;  i++ )  { 
        int32_t  iBlockPointX =  i <<  3 ; 
        int32_t  iBlockPointY =  j <<  3 ; 
        uint8_t  uiBlockIdcTmp =  NO_STATIC; 
        int32_t  iSad =  m_pfSad  ( pCurTmp,  sLocalParam. iCurStride,  pRefTmp,  sLocalParam. iRefStride) ; 
        if  ( iSad ==  0 )  { 
          uiBlockIdcTmp =  COLLOCATED_STATIC; 
        }  else  if  ( bScrollDetectFlag &&  ( ! iScrollMvX ||  ! iScrollMvY)  &&  ( iBlockPointX +  iScrollMvX >=  0 ) 
                   &&  ( iBlockPointX +  iScrollMvX <=  iWidth -  8 )  && 
                   ( iBlockPointY +  iScrollMvY >=  0 )  &&  ( iBlockPointY +  iScrollMvY <=  iHeight -  8 ) )  { 
          uint8_t *  pRefTmpScroll =  pRefTmp +  iScrollMvY *  sLocalParam. iRefStride +  iScrollMvX; 
          int32_t  iSadScroll =  m_pfSad  ( pCurTmp,  sLocalParam. iCurStride,  pRefTmpScroll,  sLocalParam. iRefStride) ; 
          if  ( iSadScroll ==  0 )  { 
            uiBlockIdcTmp =  SCROLLED_STATIC; 
          }  else  { 
            m_sParam. iFrameComplexity +=  iSad; 
            m_sParam. iMotionBlockNum +=  iSad >  HIGH_MOTION_BLOCK_THRESHOLD; 
          } 
        }  else  { 
          m_sParam. iFrameComplexity +=  iSad; 
          m_sParam. iMotionBlockNum +=  iSad >  HIGH_MOTION_BLOCK_THRESHOLD; 
        } 
        *  ( sLocalParam. pStaticBlockIdc)  ++  =  uiBlockIdcTmp; 
        pRefTmp +=  8 ; 
        pCurTmp +=  8 ; 
      } 
      pRefY +=  iRefRowStride; 
      pCurY +=  iCurRowStride; 
    } 
  } 
} ; 
  
 
int32_t  WelsSampleSad8x8_c  ( uint8_t *  pSample1,  int32_t  iStride1,  uint8_t *  pSample2,  int32_t  iStride2)  { 
  int32_t  iSadSum =  0 ; 
  int32_t  i =  0 ; 
  uint8_t *  pSrc1 =  pSample1; 
  uint8_t *  pSrc2 =  pSample2; 
  for  ( i =  0 ;  i <  8 ;  i++ )  { 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 0 ]  -  pSrc2[ 0 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 1 ]  -  pSrc2[ 1 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 2 ]  -  pSrc2[ 2 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 3 ]  -  pSrc2[ 3 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 4 ]  -  pSrc2[ 4 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 5 ]  -  pSrc2[ 5 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 6 ]  -  pSrc2[ 6 ] ) ) ; 
    iSadSum +=  WELS_ABS  ( ( pSrc1[ 7 ]  -  pSrc2[ 7 ] ) ) ; 
    pSrc1 +=  iStride1; 
    pSrc2 +=  iStride2; 
  } 
  return  iSadSum; 
}