misc_common.c

来自「mediastreamer2是开源的网络传输媒体流的库」· C语言 代码 · 共 340 行

C
340
字号
/******************************************************************** *                                                                  * * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       * *                                                                  * * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2003                * * by the Xiph.Org Foundation http://www.xiph.org/                  * *                                                                  * ********************************************************************  function:  last mod: $Id: misc_common.c 11442 2006-05-27 17:28:08Z giles $ ********************************************************************/#include <string.h>#include "codec_internal.h"#include "block_inline.h"#define FIXED_Q                 150#define MAX_UP_REG_LOOPS        2/* Gives the initial bytes per block estimate for each Q value */double BpbTable[Q_TABLE_SIZE] = {  0.42,  0.45,  0.46,  0.49,  0.51,  0.53,  0.56,  0.58,  0.61,  0.64,  0.68,  0.71,  0.74,  0.77,  0.80,  0.84,  0.89,  0.92,  0.98,  1.01,  1.04,  1.13,  1.17,  1.23,  1.28,  1.34,  1.41,  1.45,  1.51,  1.59,  1.69,  1.80,  1.84,  1.94,  2.02,  2.15,  2.23,  2.34,  2.44,  2.50,  2.69,  2.80,  2.87,  3.04,  3.16,  3.29,  3.59,  3.66,  3.86,  3.94,  4.22,  4.50,  4.64,  4.70,  5.24,  5.34,  5.61,  5.87,  6.11,  6.41,  6.71,  6.99,  7.36,  7.69};double KfBpbTable[Q_TABLE_SIZE] = {  0.74,  0.81,  0.88,  0.94,  1.00,  1.06,  1.14,  1.19,  1.27,  1.34,  1.42,  1.49,  1.54,  1.59,  1.66,  1.73,  1.80,  1.87,  1.97,  2.01,  2.08,  2.21,  2.25,  2.36,  2.39,  2.50,  2.55,  2.65,  2.71,  2.82,  2.95,  3.01,  3.11,  3.19,  3.31,  3.42,  3.58,  3.66,  3.78,  3.89,  4.11,  4.26,  4.36,  4.39,  4.63,  4.76,  4.85,  5.04,  5.26,  5.29,  5.47,  5.64,  5.76,  6.05,  6.35,  6.67,  6.91,  7.17,  7.40,  7.56,  8.02,  8.45,  8.86,  9.38};double GetEstimatedBpb( CP_INSTANCE *cpi, ogg_uint32_t TargetQ ){  ogg_uint32_t i;  ogg_int32_t ThreshTableIndex = Q_TABLE_SIZE - 1;  double BytesPerBlock;  /* Search for the Q table index that matches the given Q. */  for ( i = 0; i < Q_TABLE_SIZE; i++ ) {    if ( TargetQ >= cpi->pb.QThreshTable[i] ) {      ThreshTableIndex = i;      break;    }  }  /* Adjust according to Q shift and type of frame */  if ( GetFrameType(&cpi->pb) == KEY_FRAME ) {    /* Get primary prediction */    BytesPerBlock = KfBpbTable[ThreshTableIndex];  } else {    /* Get primary prediction */    BytesPerBlock = BpbTable[ThreshTableIndex];    BytesPerBlock = BytesPerBlock * cpi->BpbCorrectionFactor;  }  return BytesPerBlock;}static void UpRegulateMB( CP_INSTANCE *cpi, ogg_uint32_t RegulationQ,                   ogg_uint32_t SB, ogg_uint32_t MB, int NoCheck ) {  ogg_int32_t  FragIndex;  ogg_uint32_t B;  /* Variables used in calculating corresponding row,col and index in     UV planes */  ogg_uint32_t UVRow;  ogg_uint32_t UVColumn;  ogg_uint32_t UVFragOffset;  /* There may be MB's lying out of frame which must be ignored. For   these MB's Top left block will have a negative Fragment Index. */  if ( QuadMapToMBTopLeft(cpi->pb.BlockMap, SB, MB ) >= 0 ) {    /* Up regulate the component blocks Y then UV. */    for ( B=0; B<4; B++ ){      FragIndex = QuadMapToIndex1( cpi->pb.BlockMap, SB, MB, B );      if ( ( !cpi->pb.display_fragments[FragIndex] ) &&           ( (NoCheck) || (cpi->FragmentLastQ[FragIndex] > RegulationQ) ) ){        cpi->pb.display_fragments[FragIndex] = 1;        cpi->extra_fragments[FragIndex] = 1;        cpi->FragmentLastQ[FragIndex] = RegulationQ;        cpi->MotionScore++;      }    }    /* Check the two UV blocks */    FragIndex = QuadMapToMBTopLeft(cpi->pb.BlockMap, SB, MB );    UVRow = (FragIndex / (cpi->pb.HFragments * 2));    UVColumn = (FragIndex % cpi->pb.HFragments) / 2;    UVFragOffset = (UVRow * (cpi->pb.HFragments / 2)) + UVColumn;    FragIndex = cpi->pb.YPlaneFragments + UVFragOffset;    if ( ( !cpi->pb.display_fragments[FragIndex] ) &&         ( (NoCheck) || (cpi->FragmentLastQ[FragIndex] > RegulationQ) ) ) {      cpi->pb.display_fragments[FragIndex] = 1;      cpi->extra_fragments[FragIndex] = 1;      cpi->FragmentLastQ[FragIndex] = RegulationQ;      cpi->MotionScore++;    }    FragIndex += cpi->pb.UVPlaneFragments;    if ( ( !cpi->pb.display_fragments[FragIndex] ) &&         ( (NoCheck) || (cpi->FragmentLastQ[FragIndex] > RegulationQ) ) ) {      cpi->pb.display_fragments[FragIndex] = 1;      cpi->extra_fragments[FragIndex] = 1;      cpi->FragmentLastQ[FragIndex] = RegulationQ;      cpi->MotionScore++;    }  }}static void UpRegulateBlocks (CP_INSTANCE *cpi, ogg_uint32_t RegulationQ,                       ogg_int32_t RecoveryBlocks,                       ogg_uint32_t * LastSB, ogg_uint32_t * LastMB ) {  ogg_uint32_t LoopTimesRound = 0;  ogg_uint32_t MaxSB = cpi->pb.YSBRows *    cpi->pb.YSBCols;   /* Tot super blocks in image */  ogg_uint32_t SB, MB; /* Super-Block and macro block indices. */  /* First scan for blocks for which a residue update is outstanding. */  while ( (cpi->MotionScore < RecoveryBlocks) &&          (LoopTimesRound < MAX_UP_REG_LOOPS) ) {    LoopTimesRound++;    for ( SB = (*LastSB); SB < MaxSB; SB++ ) {      /* Check its four Macro-Blocks */      for ( MB=(*LastMB); MB<4; MB++ ) {        /* Mark relevant blocks for update */        UpRegulateMB( cpi, RegulationQ, SB, MB, 0 );        /* Keep track of the last refresh MB. */        (*LastMB) += 1;        if ( (*LastMB) == 4 )          (*LastMB) = 0;        /* Termination clause */        if (cpi->MotionScore >= RecoveryBlocks) {          /* Make sure we don't stall at SB level */          if ( *LastMB == 0 )            SB++;          break;        }      }      /* Termination clause */      if (cpi->MotionScore >= RecoveryBlocks)        break;    }    /* Update super block start index  */    if ( SB >= MaxSB){      (*LastSB) = 0;    }else{      (*LastSB) = SB;    }  }}void UpRegulateDataStream (CP_INSTANCE *cpi, ogg_uint32_t RegulationQ,                           ogg_int32_t RecoveryBlocks ) {  ogg_uint32_t LastPassMBPos = 0;  ogg_uint32_t StdLastMBPos = 0;  ogg_uint32_t MaxSB = cpi->pb.YSBRows *    cpi->pb.YSBCols;    /* Tot super blocks in image */  ogg_uint32_t SB=0;    /* Super-Block index */  ogg_uint32_t MB;      /* Macro-Block index */  /* Decduct the number of blocks in an MB / 2 from the recover block count.     This will compensate for the fact that once we start checking an MB     we test every block in that macro block */  if ( RecoveryBlocks > 3 )    RecoveryBlocks -= 3;  /* Up regulate blocks last coded at higher Q */  UpRegulateBlocks( cpi, RegulationQ, RecoveryBlocks,                    &cpi->LastEndSB, &StdLastMBPos );  /* If we have still not used up the minimum number of blocks and are     at the minimum Q then run through a final pass of the data to     insure that each block gets a final refresh. */  if ( (RegulationQ == VERY_BEST_Q) &&       (cpi->MotionScore < RecoveryBlocks) ) {    if ( cpi->FinalPassLastPos < MaxSB ) {      for ( SB = cpi->FinalPassLastPos; SB < MaxSB; SB++ ) {        /* Check its four Macro-Blocks */        for ( MB=LastPassMBPos; MB<4; MB++ ) {          /* Mark relevant blocks for update */          UpRegulateMB( cpi, RegulationQ, SB, MB, 1 );          /* Keep track of the last refresh MB. */          LastPassMBPos += 1;          if ( LastPassMBPos == 4 ) {            LastPassMBPos = 0;            /* Increment SB index */            cpi->FinalPassLastPos += 1;          }          /* Termination clause */          if (cpi->MotionScore >= RecoveryBlocks)            break;        }        /* Termination clause */        if (cpi->MotionScore >= RecoveryBlocks)          break;      }    }  }}void RegulateQ( CP_INSTANCE *cpi, ogg_int32_t UpdateScore ) {  double PredUnitScoreBytes;  ogg_uint32_t QIndex = Q_TABLE_SIZE - 1;  ogg_uint32_t i;  if ( UpdateScore > 0 ) {    double TargetUnitScoreBytes = (double)cpi->ThisFrameTargetBytes /      (double)UpdateScore;    double LastBitError = 10000.0;       /* Silly high number */    /* Search for the best Q for the target bitrate. */    for ( i = 0; i < Q_TABLE_SIZE; i++ ) {      PredUnitScoreBytes = GetEstimatedBpb( cpi, cpi->pb.QThreshTable[i] );      if ( PredUnitScoreBytes > TargetUnitScoreBytes ) {        if ( (PredUnitScoreBytes - TargetUnitScoreBytes) <= LastBitError ) {          QIndex = i;        } else {          QIndex = i - 1;        }        break;      } else {        LastBitError = TargetUnitScoreBytes - PredUnitScoreBytes;      }    }  }  /* QIndex should now indicate the optimal Q. */  cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[QIndex];  /* Apply range restrictions for key frames. */  if ( GetFrameType(&cpi->pb) == KEY_FRAME ) {    if ( cpi->pb.ThisFrameQualityValue > cpi->pb.QThreshTable[20] )      cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[20];    else if ( cpi->pb.ThisFrameQualityValue < cpi->pb.QThreshTable[50] )      cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[50];  }  /* Limit the Q value to the maximum available value */  if (cpi->pb.ThisFrameQualityValue >      cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ]) {    cpi->pb.ThisFrameQualityValue =      (ogg_uint32_t)cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ];  }  if(cpi->FixedQ) {    if ( GetFrameType(&cpi->pb) == KEY_FRAME ) {      cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[43];      cpi->pb.ThisFrameQualityValue = cpi->FixedQ;    } else {      cpi->pb.ThisFrameQualityValue = cpi->FixedQ;    }  }  /* If the quantizer value has changed then re-initialise it */  if ( cpi->pb.ThisFrameQualityValue != cpi->pb.LastFrameQualityValue ) {    /* Initialise quality tables. */    UpdateQC( cpi, cpi->pb.ThisFrameQualityValue );    cpi->pb.LastFrameQualityValue = cpi->pb.ThisFrameQualityValue;  }}void CopyBackExtraFrags(CP_INSTANCE *cpi){  ogg_uint32_t  i,j;  unsigned char * SrcPtr;  unsigned char * DestPtr;  ogg_uint32_t  PlaneLineStep;  ogg_uint32_t  PixelIndex;  /*  Copy back for Y plane. */  PlaneLineStep = cpi->pb.info.width;  for ( i = 0; i < cpi->pb.YPlaneFragments; i++ ) {    /* We are only interested in updated fragments. */    if ( cpi->extra_fragments[i] ) {      /* Get the start index for the fragment. */      PixelIndex = cpi->pb.pixel_index_table[i];      SrcPtr = &cpi->yuv1ptr[PixelIndex];      DestPtr = &cpi->ConvDestBuffer[PixelIndex];      for ( j = 0; j < VFRAGPIXELS; j++ ) {        memcpy( DestPtr, SrcPtr, HFRAGPIXELS);        SrcPtr += PlaneLineStep;        DestPtr += PlaneLineStep;      }    }  }  /* Now the U and V planes */  PlaneLineStep = cpi->pb.info.width / 2;  for ( i = cpi->pb.YPlaneFragments;        i < (cpi->pb.YPlaneFragments + (2 * cpi->pb.UVPlaneFragments)) ;        i++ ) {    /* We are only interested in updated fragments. */    if ( cpi->extra_fragments[i] ) {      /* Get the start index for the fragment. */      PixelIndex = cpi->pb.pixel_index_table[i];      SrcPtr = &cpi->yuv1ptr[PixelIndex];      DestPtr = &cpi->ConvDestBuffer[PixelIndex];      for ( j = 0; j < VFRAGPIXELS; j++ ) {        memcpy( DestPtr, SrcPtr, HFRAGPIXELS);        SrcPtr += PlaneLineStep;        DestPtr += PlaneLineStep;      }    }  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?