Ejemplo n.º 1
0
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 ( cpi->pb.FrameType == 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 ( cpi->pb.FrameType == 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;
  }
}
Ejemplo n.º 2
0
static void CompressFrame( CP_INSTANCE *cpi) {
  ogg_int32_t min_blocks_per_frame;
  ogg_uint32_t  i;
  int DropFrame = 0;
  ogg_uint32_t  ResidueBlocksAdded=0;
  ogg_uint32_t  KFIndicator = 0;

  double QModStep;
  double QModifier = 1.0;

  /* Clear down the macro block level mode and MV arrays. */
  for ( i = 0; i < cpi->pb.UnitFragments; i++ ) {
    cpi->pb.FragCodingMethod[i] = CODE_INTER_NO_MV;  /* Default coding mode */
    cpi->pb.FragMVect[i].x = 0;
    cpi->pb.FragMVect[i].y = 0;
  }

  /* Default to delta frames. */
  SetFrameType( &cpi->pb, DELTA_FRAME );

  /* Clear down the difference arrays for the current frame. */
  memset( cpi->pb.display_fragments, 0, cpi->pb.UnitFragments );
  memset( cpi->extra_fragments, 0, cpi->pb.UnitFragments );

  /* Calculate the target bytes for this frame. */
  cpi->ThisFrameTargetBytes = cpi->frame_target_rate;

  /* Correct target to try and compensate for any overall rate error
     that is developing */

  /* Set the max allowed Q for this frame based upon carry over
     history.  First set baseline worst Q for this frame */
  cpi->Configuration.ActiveMaxQ = cpi->Configuration.MaxQ + 10;
  if ( cpi->Configuration.ActiveMaxQ >= Q_TABLE_SIZE )
    cpi->Configuration.ActiveMaxQ = Q_TABLE_SIZE - 1;

  /* Make a further adjustment based upon the carry over and recent
   history..  cpi->Configuration.ActiveMaxQ reduced by 1 for each 1/2
   seconds worth of -ve carry over up to a limit of 6.  Also
   cpi->Configuration.ActiveMaxQ reduced if frame is a
   "DropFrameCandidate".  Remember that if we are behind the bit
   target carry over is -ve. */
  if ( cpi->CarryOver < 0 ) {
    if ( cpi->DropFrameCandidate ) {
      cpi->Configuration.ActiveMaxQ -= 4;
    }

    if ( cpi->CarryOver <
         -((ogg_int32_t)cpi->Configuration.TargetBandwidth*3) )
      cpi->Configuration.ActiveMaxQ -= 6;
    else
      cpi->Configuration.ActiveMaxQ +=
        (ogg_int32_t) ((cpi->CarryOver*2) /
                       (ogg_int32_t)cpi->Configuration.TargetBandwidth);

    /* Check that we have not dropped quality too far */
    if ( cpi->Configuration.ActiveMaxQ < cpi->Configuration.MaxQ )
      cpi->Configuration.ActiveMaxQ = cpi->Configuration.MaxQ;
  }

  /* Calculate the Q Modifier step size required to cause a step down
     from full target bandwidth to 40% of target between max Q and
     best Q */
  QModStep = 0.5 / (double)((Q_TABLE_SIZE - 1) -
                            cpi->Configuration.ActiveMaxQ);

  /* Set up the cpi->QTargetModifier[] table. */
  for ( i = 0; i < cpi->Configuration.ActiveMaxQ; i++ ) {
    cpi->QTargetModifier[i] = QModifier;
  }
  for ( i = cpi->Configuration.ActiveMaxQ; i < Q_TABLE_SIZE; i++ ) {
    cpi->QTargetModifier[i] = QModifier;
    QModifier -= QModStep;
  }

  /* if we are allowed to drop frames and are falling behind (eg more
     than x frames worth of bandwidth) */
  if ( cpi->pb.info.dropframes_p &&
       ( cpi->DropCount < cpi->MaxConsDroppedFrames) &&
       ( cpi->CarryOver <
         -((ogg_int32_t)cpi->Configuration.TargetBandwidth)) &&
       ( cpi->DropFrameCandidate) ) {
    /* (we didn't do this frame so we should have some left over for
       the next frame) */
    cpi->CarryOver += cpi->frame_target_rate;
    DropFrame = 1;
    cpi->DropCount ++;

    /* Adjust DropFrameTriggerBytes to account for the saving achieved. */
    cpi->DropFrameTriggerBytes =
      (cpi->DropFrameTriggerBytes *
       (DF_CANDIDATE_WINDOW-1))/DF_CANDIDATE_WINDOW;

    /* Even if we drop a frame we should account for it when
        considering key frame seperation. */
    cpi->LastKeyFrame++;
  } else if ( cpi->CarryOver <
              -((ogg_int32_t)cpi->Configuration.TargetBandwidth * 2) ) {
    /* Reduce frame bit target by 1.75% for each 1/10th of a seconds
       worth of -ve carry over down to a minimum of 65% of its
       un-modified value. */

    cpi->ThisFrameTargetBytes =
      (ogg_uint32_t)(cpi->ThisFrameTargetBytes * 0.65);
  } else if ( cpi->CarryOver < 0 ) {
    /* Note that cpi->CarryOver is a -ve here hence 1.0 "+" ... */
    cpi->ThisFrameTargetBytes =
      (ogg_uint32_t)(cpi->ThisFrameTargetBytes *
                     (1.0 + ( ((cpi->CarryOver * 10)/
                               ((ogg_int32_t)cpi->
                                Configuration.TargetBandwidth)) * 0.0175) ));
  }

  if ( !DropFrame ) {
    /*  pick all the macroblock modes and motion vectors */
    ogg_uint32_t InterError;
    ogg_uint32_t IntraError;


    /* Set Baseline filter level. */
    ConfigurePP( &cpi->pp, cpi->pb.info.noise_sensitivity);

    /* Score / analyses the fragments. */
    cpi->MotionScore = YUVAnalyseFrame(&cpi->pp, &KFIndicator );

    /* Get the baseline Q value */
    RegulateQ( cpi, cpi->MotionScore );

    /* Recode blocks if the error score in last frame was high. */
    ResidueBlocksAdded  = 0;
    for ( i = 0; i < cpi->pb.UnitFragments; i++ ){
      if ( !cpi->pb.display_fragments[i] ){
        if ( cpi->LastCodedErrorScore[i] >=
             ResidueErrorThresh[cpi->pb.FrameQIndex] ) {
          cpi->pb.display_fragments[i] = 1; /* Force block update */
          cpi->extra_fragments[i] = 1;      /* Insures up to date
                                               pixel data is used. */
          ResidueBlocksAdded ++;
        }
      }
    }

    /* Adjust the motion score to allow for residue blocks
       added. These are assumed to have below average impact on
       bitrate (Hence ResidueBlockFactor). */
    cpi->MotionScore = cpi->MotionScore +
      (ResidueBlocksAdded / ResidueBlockFactor[cpi->pb.FrameQIndex]);

    /* Estimate the min number of blocks at best Q */
    min_blocks_per_frame =
      (ogg_int32_t)(cpi->ThisFrameTargetBytes /
                    GetEstimatedBpb( cpi, VERY_BEST_Q ));
    if ( min_blocks_per_frame == 0 )
      min_blocks_per_frame = 1;

    /* If we have less than this number then consider adding in some
       extra blocks */
    if ( cpi->MotionScore < min_blocks_per_frame ) {
      min_blocks_per_frame =
        cpi->MotionScore +
        (ogg_int32_t)(((min_blocks_per_frame - cpi->MotionScore) * 4) / 3 );
      UpRegulateDataStream( cpi, VERY_BEST_Q, min_blocks_per_frame );
    }else{
      /* Reset control variable for best quality final pass. */
      cpi->FinalPassLastPos = 0;
    }

    /* Get the modified Q prediction taking into account extra blocks added. */
    RegulateQ( cpi, cpi->MotionScore );

    /* Unless we are already well ahead (4 seconds of data) of the
       projected bitrate */
    if ( cpi->CarryOver <
         (ogg_int32_t)(cpi->Configuration.TargetBandwidth * 4) ){
      /* Look at the predicted Q (pbi->FrameQIndex).  Adjust the
         target bits for this frame based upon projected Q and
         re-calculate.  The idea is that if the Q is better than a
         given (good enough) level then we will try and save some bits
         for use in more difficult segments. */
      cpi->ThisFrameTargetBytes =
        (ogg_int32_t) (cpi->ThisFrameTargetBytes *
                       cpi->QTargetModifier[cpi->pb.FrameQIndex]);

      /* Recalculate Q again */
      RegulateQ( cpi, cpi->MotionScore );
    }


    /* Select modes and motion vectors for each of the blocks : return
       an error score for inter and intra */
    PickModes( cpi, cpi->pb.YSBRows, cpi->pb.YSBCols,
               cpi->pb.info.width,
               &InterError, &IntraError );

    /* decide whether we really should have made this frame a key frame */
    /* forcing out a keyframe if the max interval is up is done at a higher level */
    if( cpi->pb.info.keyframe_auto_p){
      if( ( 2* IntraError < 5 * InterError )
          && ( KFIndicator >= (ogg_uint32_t)
               cpi->pb.info.keyframe_auto_threshold)
          && ( cpi->LastKeyFrame > cpi->pb.info.keyframe_mindistance)
          ){
        CompressKeyFrame(cpi);  /* Code a key frame */
        return;
      }

    }

    /* Increment the frames since last key frame count */
    cpi->LastKeyFrame++;

    /* Proceed with the frame update. */
    UpdateFrame(cpi);
    cpi->DropCount = 0;

    if ( cpi->MotionScore > 0 ){
      /* Note the Quantizer used for each block coded. */
      for ( i = 0; i < cpi->pb.UnitFragments; i++ ){
        if ( cpi->pb.display_fragments[i] ){
          cpi->FragmentLastQ[i] = cpi->pb.ThisFrameQualityValue;
        }
      }

    }
  }else{
    /* even if we 'drop' a frame, a placeholder must be written as we
       currently assume fixed frame rate timebase as Ogg mapping
       invariant */
    UpdateFrame(cpi);
  }
}
Ejemplo n.º 3
0
/****************************************************************************
 * 
 *  ROUTINE       :     RegulateQ
 *
 *  INPUTS        :     INT32 BlocksToUpdate
 *
 *  OUTPUTS       :     None.
 *
 *  RETURNS       :     None.
 *
 *  FUNCTION      :     If appropriate this function regulates the DCT
 *                      coefficients to match the stream size to the    
 *                      available bandwidth (within defined limits). 
 *
 *  SPECIAL NOTES :     None. 
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void RegulateQ( CP_INSTANCE *cpi, INT32 UpdateScore ) 
{   
    double TargetUnitScoreBytes = (double)cpi->ThisFrameTargetBytes / (double)UpdateScore;
    double PredUnitScoreBytes;
    double LastBitError = 10000.0;       // Silly high number
    UINT32 QIndex = Q_TABLE_SIZE - 1;
    UINT32 i;

    // 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) == BASE_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])
        //if (cpi->pb.ThisFrameQualityValue > QThreshTable[cpi->Configuration.ActiveMaxQ])
    {
        cpi->pb.ThisFrameQualityValue = (UINT32)cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ];
    }  
    
    if(cpi->FixedQ)
    {
        if ( GetFrameType(&cpi->pb) == BASE_FRAME )
        {
            cpi->pb.ThisFrameQualityValue = cpi->pb.QThreshTable[43];
            cpi->pb.ThisFrameQualityValue = cpi->FixedQ;
        }
        else
        {
            cpi->pb.ThisFrameQualityValue = cpi->FixedQ;
        }
    }
    
    // If th quantiser 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;
    }

}