📄 encoder_toplevel.c
字号:
/* set up context of key frame sizes and distances for more local datarate control */ for( i = 0 ; i < KEY_FRAME_CONTEXT ; i ++ ) { cpi->PriorKeyFrameSize[i] = cpi->Configuration.KeyFrameDataTarget; cpi->PriorKeyFrameDistance[i] = cpi->pb.info.keyframe_frequency_force; } /* Keep track of the total number of Key Frames Coded. */ cpi->KeyFrameCount = 1; cpi->LastKeyFrame = 1; cpi->TotKeyFrameBytes = 0; /* A key frame is not a dropped frame there for reset the count of consequative dropped frames. */ cpi->DropCount = 0; SetupKeyFrame(cpi); /* Calculate a new target rate per frame allowing for average key frame frequency and size thus far. */ if ( cpi->Configuration.TargetBandwidth > ((cpi->Configuration.KeyFrameDataTarget * cpi->Configuration.OutputFrameRate)/ cpi->pb.info.keyframe_frequency) ) { cpi->frame_target_rate = (ogg_int32_t)((cpi->Configuration.TargetBandwidth - ((cpi->Configuration.KeyFrameDataTarget * cpi->Configuration.OutputFrameRate)/ cpi->pb.info.keyframe_frequency)) / cpi->Configuration.OutputFrameRate); }else cpi->frame_target_rate = 1; /* Set baseline frame target rate. */ cpi->BaseLineFrameTargetRate = cpi->frame_target_rate; /* A key frame is not a dropped frame there for reset the count of consequative dropped frames. */ cpi->DropCount = 0; /* Initialise drop frame trigger to 5 frames worth of data. */ cpi->DropFrameTriggerBytes = cpi->frame_target_rate * DF_CANDIDATE_WINDOW; /* Set a target size for this key frame based upon the baseline target and frequency */ cpi->ThisFrameTargetBytes = cpi->Configuration.KeyFrameDataTarget; /* Get a DCT quantizer level for the key frame. */ cpi->MotionScore = cpi->pb.UnitFragments; RegulateQ(cpi, cpi->pb.UnitFragments); cpi->pb.LastFrameQualityValue = cpi->pb.ThisFrameQualityValue; /* Initialise quantizer. */ UpdateQC(cpi, cpi->pb.ThisFrameQualityValue ); /* Initialise the cpi->pb.display_fragments and other fragment structures for the first frame. */ for ( i = 0; i < cpi->pb.UnitFragments; i ++ ) cpi->FragmentLastQ[i] = cpi->pb.ThisFrameQualityValue; /* Compress and output the frist frame. */ PickIntra( cpi, cpi->pb.YSBRows, cpi->pb.YSBCols); UpdateFrame(cpi); /* Initialise the carry over rate targeting variables. */ cpi->CarryOver = 0;}static void CompressKeyFrame(CP_INSTANCE *cpi){ ogg_uint32_t i; /* Before we compress reset the carry over to the actual frame carry over */ cpi->CarryOver = cpi->Configuration.TargetBandwidth * cpi->CurrentFrame / cpi->Configuration.OutputFrameRate - cpi->TotalByteCount; /* Keep track of the total number of Key Frames Coded */ cpi->KeyFrameCount += 1; /* A key frame is not a dropped frame there for reset the count of consequative dropped frames. */ cpi->DropCount = 0; SetupKeyFrame(cpi); /* set a target size for this frame */ cpi->ThisFrameTargetBytes = (ogg_int32_t) cpi->frame_target_rate + ( (cpi->Configuration.KeyFrameDataTarget - cpi->frame_target_rate) * cpi->LastKeyFrame / cpi->pb.info.keyframe_frequency_force ); if ( cpi->ThisFrameTargetBytes > cpi->Configuration.KeyFrameDataTarget ) cpi->ThisFrameTargetBytes = cpi->Configuration.KeyFrameDataTarget; /* Get a DCT quantizer level for the key frame. */ cpi->MotionScore = cpi->pb.UnitFragments; RegulateQ(cpi, cpi->pb.UnitFragments); cpi->pb.LastFrameQualityValue = cpi->pb.ThisFrameQualityValue; /* Initialise DCT tables. */ UpdateQC(cpi, cpi->pb.ThisFrameQualityValue ); /* Initialise the cpi->pb.display_fragments and other fragment structures for the first frame. */ for ( i = 0; i < cpi->pb.UnitFragments; i ++ ) cpi->FragmentLastQ[i] = cpi->pb.ThisFrameQualityValue; /* Compress and output the frist frame. */ PickIntra( cpi, cpi->pb.YSBRows, cpi->pb.YSBCols); UpdateFrame(cpi);}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); }}/********************** The toplevel: encode ***********************/static int _ilog(unsigned int v){ int ret=0; while(v){ ret++; v>>=1; } return(ret);}int theora_encode_init(theora_state *th, theora_info *c){ int i; CP_INSTANCE *cpi; memset(th, 0, sizeof(*th)); /*Currently only the 4:2:0 format is supported.*/ if(c->pixelformat!=OC_PF_420)return OC_IMPL; th->internal_encode=cpi=_ogg_calloc(1,sizeof(*cpi)); dsp_static_init (&cpi->dsp); memcpy (&cpi->pb.dsp, &cpi->dsp, sizeof(DspFunctions)); c->version_major=VERSION_MAJOR; c->version_minor=VERSION_MINOR; c->version_subminor=VERSION_SUB; InitTmpBuffers(&cpi->pb); InitPPInstance(&cpi->pp, &cpi->dsp); /* Initialise Configuration structure to legal values */ if(c->quality>63)c->quality=63; if(c->quality<0)c->quality=32; if(c->target_bitrate<0)c->target_bitrate=0; /* we clamp target_bitrate to 24 bits after setting up the encoder */ cpi->Configuration.BaseQ = c->quality; cpi->Configuration.FirstFrameQ = c->quality; cpi->Configuration.MaxQ = c->quality; cpi->Configuration.ActiveMaxQ = c->quality; cpi->MVChangeFactor = 14; cpi->FourMvChangeFactor = 8; cpi->MinImprovementForNewMV = 25; cpi->ExhaustiveSearchThresh = 2500; cpi->MinImprovementForFourMV = 100; cpi->FourMVThreshold = 10000; cpi->BitRateCapFactor = 1.50; cpi->InterTripOutThresh = 5000; cpi->MVEnabled = 1; cpi->InterCodeCount = 127; cpi->BpbCorrectionFactor = 1.0; cpi->GoldenFrameEnabled = 1; cpi->InterPrediction = 1; cpi->MotionCompensation = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -