📄 encoder_toplevel.c
字号:
ogg_uint32_t i;
/* 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;
cpi->wasKeyframe=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;
dsp_static_init ();
memset(th, 0, sizeof(*th));
th->internal_encode=cpi=_ogg_calloc(1,sizeof(*cpi));
c->version_major=VERSION_MAJOR;
c->version_minor=VERSION_MINOR;
c->version_subminor=VERSION_SUB;
InitTmpBuffers(&cpi->pb);
InitPPInstance(&cpi->pp);
/* Initialise Configuration structure to legal values */
if(c->quality>63)c->quality=63;
if(c->quality<0)c->quality=32;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -