📄 encoder_toplevel.c
字号:
/******************************************************************** * * * 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: encoder_toplevel.c 11442 2006-05-27 17:28:08Z giles $ ********************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <stdlib.h>#include <string.h>#include "toplevel_lookup.h"#include "toplevel.h"#include "dsp.h"#define A_TABLE_SIZE 29#define DF_CANDIDATE_WINDOW 5static void EClearFragmentInfo(CP_INSTANCE * cpi){ if(cpi->extra_fragments) _ogg_free(cpi->extra_fragments); if(cpi->FragmentLastQ) _ogg_free(cpi->FragmentLastQ); if(cpi->FragTokens) _ogg_free(cpi->FragTokens); if(cpi->FragTokenCounts) _ogg_free(cpi->FragTokenCounts); if(cpi->RunHuffIndices) _ogg_free(cpi->RunHuffIndices); if(cpi->LastCodedErrorScore) _ogg_free(cpi->LastCodedErrorScore); if(cpi->ModeList) _ogg_free(cpi->ModeList); if(cpi->MVList) _ogg_free(cpi->MVList); if(cpi->DCT_codes ) _ogg_free( cpi->DCT_codes ); if(cpi->DCTDataBuffer ) _ogg_free( cpi->DCTDataBuffer); if(cpi->quantized_list) _ogg_free( cpi->quantized_list); if(cpi->OriginalDC) _ogg_free( cpi->OriginalDC); if(cpi->PartiallyCodedFlags) _ogg_free(cpi->PartiallyCodedFlags); if(cpi->PartiallyCodedMbPatterns) _ogg_free(cpi->PartiallyCodedMbPatterns); if(cpi->UncodedMbFlags) _ogg_free(cpi->UncodedMbFlags); if(cpi->BlockCodedFlags) _ogg_free(cpi->BlockCodedFlags); cpi->extra_fragments = 0; cpi->FragmentLastQ = 0; cpi->FragTokens = 0; cpi->FragTokenCounts = 0; cpi->RunHuffIndices = 0; cpi->LastCodedErrorScore = 0; cpi->ModeList = 0; cpi->MVList = 0; cpi->DCT_codes = 0; cpi->DCTDataBuffer = 0; cpi->quantized_list = 0; cpi->OriginalDC = 0; cpi->BlockCodedFlags = 0;}static void EInitFragmentInfo(CP_INSTANCE * cpi){ /* clear any existing info */ EClearFragmentInfo(cpi); /* Perform Fragment Allocations */ cpi->extra_fragments = _ogg_malloc(cpi->pb.UnitFragments*sizeof(unsigned char)); /* A note to people reading and wondering why malloc returns aren't checked: lines like the following that implement a general strategy of 'check the return of malloc; a zero pointer means we're out of memory!'...: if(!cpi->extra_fragments) { EDeleteFragmentInfo(cpi); return FALSE; } ...are not useful. It's true that many platforms follow this malloc behavior, but many do not. The more modern malloc strategy is only to allocate virtual pages, which are not mapped until the memory on that page is touched. At *that* point, if the machine is out of heap, the page fails to be mapped and a SEGV is generated. That means that if we want to deal with out of memory conditions, we *must* be prepared to process a SEGV. If we implement the SEGV handler, there's no reason to to check malloc return; it is a waste of code. */ cpi->FragmentLastQ = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->FragmentLastQ)); cpi->FragTokens = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->FragTokens)); cpi->OriginalDC = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->OriginalDC)); cpi->FragTokenCounts = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->FragTokenCounts)); cpi->RunHuffIndices = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->RunHuffIndices)); cpi->LastCodedErrorScore = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->LastCodedErrorScore)); cpi->BlockCodedFlags = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->BlockCodedFlags)); cpi->ModeList = _ogg_malloc(cpi->pb.UnitFragments* sizeof(*cpi->ModeList)); cpi->MVList = _ogg_malloc(cpi->pb.UnitFragments* sizeof(cpi->MVList)); cpi->DCT_codes = _ogg_malloc(64* sizeof(*cpi->DCT_codes)); cpi->DCTDataBuffer = _ogg_malloc(64* sizeof(*cpi->DCTDataBuffer)); cpi->quantized_list = _ogg_malloc(64* sizeof(*cpi->quantized_list)); cpi->PartiallyCodedFlags = _ogg_malloc(cpi->pb.MacroBlocks* sizeof(*cpi->PartiallyCodedFlags)); cpi->PartiallyCodedMbPatterns = _ogg_malloc(cpi->pb.MacroBlocks* sizeof(*cpi->PartiallyCodedMbPatterns)); cpi->UncodedMbFlags = _ogg_malloc(cpi->pb.MacroBlocks* sizeof(*cpi->UncodedMbFlags));}static void EClearFrameInfo(CP_INSTANCE * cpi) { if(cpi->ConvDestBuffer ) _ogg_free(cpi->ConvDestBuffer ); cpi->ConvDestBuffer = 0; if(cpi->yuv0ptr) _ogg_free(cpi->yuv0ptr); cpi->yuv0ptr = 0; if(cpi->yuv1ptr) _ogg_free(cpi->yuv1ptr); cpi->yuv1ptr = 0; if(cpi->OptimisedTokenListEb ) _ogg_free(cpi->OptimisedTokenListEb); cpi->OptimisedTokenListEb = 0; if(cpi->OptimisedTokenList ) _ogg_free(cpi->OptimisedTokenList); cpi->OptimisedTokenList = 0; if(cpi->OptimisedTokenListHi ) _ogg_free(cpi->OptimisedTokenListHi); cpi->OptimisedTokenListHi = 0; if(cpi->OptimisedTokenListPl ) _ogg_free(cpi->OptimisedTokenListPl); cpi->OptimisedTokenListPl = 0;}static void EInitFrameInfo(CP_INSTANCE * cpi){ int FrameSize = cpi->pb.ReconYPlaneSize + 2 * cpi->pb.ReconUVPlaneSize; /* clear any existing info */ EClearFrameInfo(cpi); /* allocate frames */ cpi->ConvDestBuffer = _ogg_malloc(FrameSize* sizeof(*cpi->ConvDestBuffer)); cpi->yuv0ptr = _ogg_malloc(FrameSize* sizeof(*cpi->yuv0ptr)); cpi->yuv1ptr = _ogg_malloc(FrameSize* sizeof(*cpi->yuv1ptr)); cpi->OptimisedTokenListEb = _ogg_malloc(FrameSize* sizeof(*cpi->OptimisedTokenListEb)); cpi->OptimisedTokenList = _ogg_malloc(FrameSize* sizeof(*cpi->OptimisedTokenList)); cpi->OptimisedTokenListHi = _ogg_malloc(FrameSize* sizeof(*cpi->OptimisedTokenListHi)); cpi->OptimisedTokenListPl = _ogg_malloc(FrameSize* sizeof(*cpi->OptimisedTokenListPl));}static void SetupKeyFrame(CP_INSTANCE *cpi) { /* Make sure the "last frame" buffer contains the first frame data as well. */ memcpy ( cpi->yuv0ptr, cpi->yuv1ptr, cpi->pb.ReconYPlaneSize + 2 * cpi->pb.ReconUVPlaneSize ); /* Initialise the cpi->pb.display_fragments and other fragment structures for the first frame. */ memset( cpi->pb.display_fragments, 1, cpi->pb.UnitFragments ); memset( cpi->extra_fragments, 1, cpi->pb.UnitFragments ); /* Set up for a KEY FRAME */ SetFrameType( &cpi->pb,KEY_FRAME );}static void AdjustKeyFrameContext(CP_INSTANCE *cpi) { ogg_uint32_t i; ogg_uint32_t AvKeyFrameFrequency = (ogg_uint32_t) (cpi->CurrentFrame / cpi->KeyFrameCount); ogg_uint32_t AvKeyFrameBytes = (ogg_uint32_t) (cpi->TotKeyFrameBytes / cpi->KeyFrameCount); ogg_uint32_t TotalWeight=0; ogg_int32_t AvKeyFramesPerSecond; ogg_int32_t MinFrameTargetRate; /* Update the frame carry over. */ cpi->TotKeyFrameBytes += oggpackB_bytes(cpi->oggbuffer); /* reset keyframe context and calculate weighted average of last KEY_FRAME_CONTEXT keyframes */ for( i = 0 ; i < KEY_FRAME_CONTEXT ; i ++ ) { if ( i < KEY_FRAME_CONTEXT -1) { cpi->PriorKeyFrameSize[i] = cpi->PriorKeyFrameSize[i+1]; cpi->PriorKeyFrameDistance[i] = cpi->PriorKeyFrameDistance[i+1]; } else { cpi->PriorKeyFrameSize[KEY_FRAME_CONTEXT - 1] = oggpackB_bytes(cpi->oggbuffer); cpi->PriorKeyFrameDistance[KEY_FRAME_CONTEXT - 1] = cpi->LastKeyFrame; } AvKeyFrameBytes += PriorKeyFrameWeight[i] * cpi->PriorKeyFrameSize[i]; AvKeyFrameFrequency += PriorKeyFrameWeight[i] * cpi->PriorKeyFrameDistance[i]; TotalWeight += PriorKeyFrameWeight[i]; } AvKeyFrameBytes /= TotalWeight; AvKeyFrameFrequency /= TotalWeight; AvKeyFramesPerSecond = 100 * cpi->Configuration.OutputFrameRate / AvKeyFrameFrequency ; /* Calculate a new target rate per frame allowing for average key frame frequency over newest frames . */ if ( 100 * cpi->Configuration.TargetBandwidth > AvKeyFrameBytes * AvKeyFramesPerSecond && (100 * cpi->Configuration.OutputFrameRate - AvKeyFramesPerSecond )){ cpi->frame_target_rate = (ogg_int32_t)(100* cpi->Configuration.TargetBandwidth - AvKeyFrameBytes * AvKeyFramesPerSecond ) / ( (100 * cpi->Configuration.OutputFrameRate - AvKeyFramesPerSecond ) ); } else { /* don't let this number get too small!!! */ cpi->frame_target_rate = 1; } /* minimum allowable frame_target_rate */ MinFrameTargetRate = (cpi->Configuration.TargetBandwidth / cpi->Configuration.OutputFrameRate) / 3; if(cpi->frame_target_rate < MinFrameTargetRate ) { cpi->frame_target_rate = MinFrameTargetRate; } cpi->LastKeyFrame = 1; cpi->LastKeyFrameSize=oggpackB_bytes(cpi->oggbuffer);}static void UpdateFrame(CP_INSTANCE *cpi){ double CorrectionFactor; /* Reset the DC predictors. */ cpi->pb.LastIntraDC = 0; cpi->pb.InvLastIntraDC = 0; cpi->pb.LastInterDC = 0; cpi->pb.InvLastInterDC = 0; /* Initialise bit packing mechanism. */#ifndef LIBOGG2 oggpackB_reset(cpi->oggbuffer);#else oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate);#endif /* mark as video frame */ oggpackB_write(cpi->oggbuffer,0,1); /* Write out the frame header information including size. */ WriteFrameHeader(cpi); /* Copy back any extra frags that are to be updated by the codec as part of the background cleanup task */ CopyBackExtraFrags(cpi); /* Encode the data. */ EncodeData(cpi); /* Adjust drop frame trigger. */ if ( GetFrameType(&cpi->pb) != KEY_FRAME ) { /* Apply decay factor then add in the last frame size. */ cpi->DropFrameTriggerBytes = ((cpi->DropFrameTriggerBytes * (DF_CANDIDATE_WINDOW-1)) / DF_CANDIDATE_WINDOW) + oggpackB_bytes(cpi->oggbuffer); }else{ /* Increase cpi->DropFrameTriggerBytes a little. Just after a key frame may actually be a good time to drop a frame. */ cpi->DropFrameTriggerBytes = (cpi->DropFrameTriggerBytes * DF_CANDIDATE_WINDOW) / (DF_CANDIDATE_WINDOW-1); } /* Test for overshoot which may require a dropped frame next time around. If we are already in a drop frame condition but the previous frame was not dropped then the threshold for continuing to allow dropped frames is reduced. */ if ( cpi->DropFrameCandidate ) { if ( cpi->DropFrameTriggerBytes > (cpi->frame_target_rate * (DF_CANDIDATE_WINDOW+1)) ) cpi->DropFrameCandidate = 1; else cpi->DropFrameCandidate = 0; } else { if ( cpi->DropFrameTriggerBytes > (cpi->frame_target_rate * ((DF_CANDIDATE_WINDOW*2)-2)) ) cpi->DropFrameCandidate = 1; else cpi->DropFrameCandidate = 0; } /* Update the BpbCorrectionFactor variable according to whether or not we were close enough with our selection of DCT quantiser. */ if ( GetFrameType(&cpi->pb) != KEY_FRAME ) { /* Work out a size correction factor. */ CorrectionFactor = (double)oggpackB_bytes(cpi->oggbuffer) / (double)cpi->ThisFrameTargetBytes; if ( (CorrectionFactor > 1.05) && (cpi->pb.ThisFrameQualityValue < cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ]) ) { CorrectionFactor = 1.0 + ((CorrectionFactor - 1.0)/2); if ( CorrectionFactor > 1.5 ) cpi->BpbCorrectionFactor *= 1.5; else cpi->BpbCorrectionFactor *= CorrectionFactor; /* Keep BpbCorrectionFactor within limits */ if ( cpi->BpbCorrectionFactor > MAX_BPB_FACTOR ) cpi->BpbCorrectionFactor = MAX_BPB_FACTOR; } else if ( (CorrectionFactor < 0.95) && (cpi->pb.ThisFrameQualityValue > VERY_BEST_Q) ){ CorrectionFactor = 1.0 - ((1.0 - CorrectionFactor)/2); if ( CorrectionFactor < 0.75 ) cpi->BpbCorrectionFactor *= 0.75; else cpi->BpbCorrectionFactor *= CorrectionFactor; /* Keep BpbCorrectionFactor within limits */ if ( cpi->BpbCorrectionFactor < MIN_BPB_FACTOR ) cpi->BpbCorrectionFactor = MIN_BPB_FACTOR; } } /* Adjust carry over and or key frame context. */ if ( GetFrameType(&cpi->pb) == KEY_FRAME ) { /* Adjust the key frame context unless the key frame was very small */ AdjustKeyFrameContext(cpi); } else { /* Update the frame carry over */ cpi->CarryOver += ((ogg_int32_t)cpi->frame_target_rate - (ogg_int32_t)oggpackB_bytes(cpi->oggbuffer)); } cpi->TotalByteCount += oggpackB_bytes(cpi->oggbuffer);}static void CompressFirstFrame(CP_INSTANCE *cpi) { ogg_uint32_t i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -