📄 encode.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:
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include "codec_internal.h"
#include "encoder_lookup.h"
#include "block_inline.h"
#define PUR 8
#define PU 4
#define PUL 2
#define PL 1
#define HIGHBITDUPPED(X) (((ogg_int16_t) X) >> 15)
static ogg_uint32_t QuadCodeComponent ( CP_INSTANCE *cpi,
ogg_uint32_t FirstSB,
ogg_uint32_t SBRows,
ogg_uint32_t SBCols,
ogg_uint32_t PixelsPerLine ){
ogg_int32_t FragIndex; /* Fragment number */
ogg_uint32_t MB, B; /* Macro-Block, Block indices */
ogg_uint32_t SBrow; /* Super-Block row number */
ogg_uint32_t SBcol; /* Super-Block row number */
ogg_uint32_t SB=FirstSB; /* Super-Block index, initialised to first
of this component */
ogg_uint32_t coded_pixels=0; /* Number of pixels coded */
int MBCodedFlag;
/* actually transform and quantize the image now that we've decided
on the modes Parse in quad-tree ordering */
SB=FirstSB;
for ( SBrow=0; SBrow<SBRows; SBrow++ ) {
for ( SBcol=0; SBcol<SBCols; SBcol++ ) {
/* Check its four Macro-Blocks */
for ( MB=0; MB<4; MB++ ) {
if ( QuadMapToMBTopLeft(cpi->pb.BlockMap,SB,MB) >= 0 ) {
MBCodedFlag = 0;
/* Now actually code the blocks */
for ( B=0; B<4; B++ ) {
FragIndex = QuadMapToIndex1( cpi->pb.BlockMap, SB, MB, B );
/* Does Block lie in frame: */
if ( FragIndex >= 0 ) {
/* In Frame: Is it coded: */
if ( cpi->pb.display_fragments[FragIndex] ) {
/* transform and quantize block */
TransformQuantizeBlock( cpi, FragIndex, PixelsPerLine );
/* Has the block got struck off (no MV and no data
generated after DCT) If not then mark it and the
assosciated MB as coded. */
if ( cpi->pb.display_fragments[FragIndex] ) {
/* Create linear list of coded block indices */
cpi->pb.CodedBlockList[cpi->pb.CodedBlockIndex] = FragIndex;
cpi->pb.CodedBlockIndex++;
/* MB is still coded */
MBCodedFlag = 1;
cpi->MBCodingMode = cpi->pb.FragCodingMethod[FragIndex];
}
}
}
}
/* If the MB is marked as coded and we are in the Y plane then */
/* the mode list needs to be updated. */
if ( MBCodedFlag && (FirstSB == 0) ){
/* Make a note of the selected mode in the mode list */
cpi->ModeList[cpi->ModeListCount] = cpi->MBCodingMode;
cpi->ModeListCount++;
}
}
}
SB++;
}
}
/* Return number of pixels coded */
return coded_pixels;
}
static void EncodeDcTokenList (CP_INSTANCE *cpi) {
ogg_int32_t i,j;
ogg_uint32_t Token;
ogg_uint32_t ExtraBitsToken;
ogg_uint32_t HuffIndex;
ogg_uint32_t BestDcBits;
ogg_uint32_t DcHuffChoice[2];
ogg_uint32_t EntropyTableBits[2][DC_HUFF_CHOICES];
oggpack_buffer *opb=cpi->oggbuffer;
/* Clear table data structure */
memset ( EntropyTableBits, 0, sizeof(ogg_uint32_t)*DC_HUFF_CHOICES*2 );
/* Analyse token list to see which is the best entropy table to use */
for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) {
/* Count number of bits for each table option */
Token = (ogg_uint32_t)cpi->OptimisedTokenList[i];
for ( j = 0; j < DC_HUFF_CHOICES; j++ ){
EntropyTableBits[cpi->OptimisedTokenListPl[i]][j] +=
cpi->pb.HuffCodeLengthArray_VP3x[DC_HUFF_OFFSET + j][Token];
}
}
/* Work out which table option is best for Y */
BestDcBits = EntropyTableBits[0][0];
DcHuffChoice[0] = 0;
for ( j = 1; j < DC_HUFF_CHOICES; j++ ) {
if ( EntropyTableBits[0][j] < BestDcBits ) {
BestDcBits = EntropyTableBits[0][j];
DcHuffChoice[0] = j;
}
}
/* Add the DC huffman table choice to the bitstream */
oggpackB_write( opb, DcHuffChoice[0], DC_HUFF_CHOICE_BITS );
/* Work out which table option is best for UV */
BestDcBits = EntropyTableBits[1][0];
DcHuffChoice[1] = 0;
for ( j = 1; j < DC_HUFF_CHOICES; j++ ) {
if ( EntropyTableBits[1][j] < BestDcBits ) {
BestDcBits = EntropyTableBits[1][j];
DcHuffChoice[1] = j;
}
}
/* Add the DC huffman table choice to the bitstream */
oggpackB_write( opb, DcHuffChoice[1], DC_HUFF_CHOICE_BITS );
/* Encode the token list */
for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) {
/* Get the token and extra bits */
Token = (ogg_uint32_t)cpi->OptimisedTokenList[i];
ExtraBitsToken = (ogg_uint32_t)cpi->OptimisedTokenListEb[i];
/* Select the huffman table */
if ( cpi->OptimisedTokenListPl[i] == 0)
HuffIndex = (ogg_uint32_t)DC_HUFF_OFFSET + (ogg_uint32_t)DcHuffChoice[0];
else
HuffIndex = (ogg_uint32_t)DC_HUFF_OFFSET + (ogg_uint32_t)DcHuffChoice[1];
/* Add the bits to the encode holding buffer. */
cpi->FrameBitCount += cpi->pb.HuffCodeLengthArray_VP3x[HuffIndex][Token];
oggpackB_write( opb, cpi->pb.HuffCodeArray_VP3x[HuffIndex][Token],
(ogg_uint32_t)cpi->
pb.HuffCodeLengthArray_VP3x[HuffIndex][Token] );
/* If the token is followed by an extra bits token then code it */
if ( cpi->pb.ExtraBitLengths_VP3x[Token] > 0 ) {
/* Add the bits to the encode holding buffer. */
cpi->FrameBitCount += cpi->pb.ExtraBitLengths_VP3x[Token];
oggpackB_write( opb, ExtraBitsToken,
(ogg_uint32_t)cpi->pb.ExtraBitLengths_VP3x[Token] );
}
}
/* Reset the count of second order optimised tokens */
cpi->OptimisedTokenCount = 0;
}
static void EncodeAcTokenList (CP_INSTANCE *cpi) {
ogg_int32_t i,j;
ogg_uint32_t Token;
ogg_uint32_t ExtraBitsToken;
ogg_uint32_t HuffIndex;
ogg_uint32_t BestAcBits;
ogg_uint32_t AcHuffChoice[2];
ogg_uint32_t EntropyTableBits[2][AC_HUFF_CHOICES];
oggpack_buffer *opb=cpi->oggbuffer;
memset ( EntropyTableBits, 0, sizeof(ogg_uint32_t)*AC_HUFF_CHOICES*2 );
/* Analyse token list to see which is the best entropy table to use */
for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) {
/* Count number of bits for each table option */
Token = (ogg_uint32_t)cpi->OptimisedTokenList[i];
HuffIndex = cpi->OptimisedTokenListHi[i];
for ( j = 0; j < AC_HUFF_CHOICES; j++ ) {
EntropyTableBits[cpi->OptimisedTokenListPl[i]][j] +=
cpi->pb.HuffCodeLengthArray_VP3x[HuffIndex + j][Token];
}
}
/* Select the best set of AC tables for Y */
BestAcBits = EntropyTableBits[0][0];
AcHuffChoice[0] = 0;
for ( j = 1; j < AC_HUFF_CHOICES; j++ ) {
if ( EntropyTableBits[0][j] < BestAcBits ) {
BestAcBits = EntropyTableBits[0][j];
AcHuffChoice[0] = j;
}
}
/* Add the AC-Y huffman table choice to the bitstream */
oggpackB_write( opb, AcHuffChoice[0], AC_HUFF_CHOICE_BITS );
/* Select the best set of AC tables for UV */
BestAcBits = EntropyTableBits[1][0];
AcHuffChoice[1] = 0;
for ( j = 1; j < AC_HUFF_CHOICES; j++ ) {
if ( EntropyTableBits[1][j] < BestAcBits ) {
BestAcBits = EntropyTableBits[1][j];
AcHuffChoice[1] = j;
}
}
/* Add the AC-UV huffman table choice to the bitstream */
oggpackB_write( opb, AcHuffChoice[1], AC_HUFF_CHOICE_BITS );
/* Encode the token list */
for ( i = 0; i < cpi->OptimisedTokenCount; i++ ) {
/* Get the token and extra bits */
Token = (ogg_uint32_t)cpi->OptimisedTokenList[i];
ExtraBitsToken = (ogg_uint32_t)cpi->OptimisedTokenListEb[i];
/* Select the huffman table */
HuffIndex = (ogg_uint32_t)cpi->OptimisedTokenListHi[i] +
AcHuffChoice[cpi->OptimisedTokenListPl[i]];
/* Add the bits to the encode holding buffer. */
cpi->FrameBitCount += cpi->pb.HuffCodeLengthArray_VP3x[HuffIndex][Token];
oggpackB_write( opb, cpi->pb.HuffCodeArray_VP3x[HuffIndex][Token],
(ogg_uint32_t)cpi->
pb.HuffCodeLengthArray_VP3x[HuffIndex][Token] );
/* If the token is followed by an extra bits token then code it */
if ( cpi->pb.ExtraBitLengths_VP3x[Token] > 0 ) {
/* Add the bits to the encode holding buffer. */
cpi->FrameBitCount += cpi->pb.ExtraBitLengths_VP3x[Token];
oggpackB_write( opb, ExtraBitsToken,
(ogg_uint32_t)cpi->pb.ExtraBitLengths_VP3x[Token] );
}
}
/* Reset the count of second order optimised tokens */
cpi->OptimisedTokenCount = 0;
}
static void PackModes (CP_INSTANCE *cpi) {
ogg_uint32_t i,j;
unsigned char ModeIndex;
unsigned char *SchemeList;
unsigned char BestModeSchemes[MAX_MODES];
ogg_int32_t ModeCount[MAX_MODES];
ogg_int32_t TmpFreq = -1;
ogg_int32_t TmpIndex = -1;
ogg_uint32_t BestScheme;
ogg_uint32_t BestSchemeScore;
ogg_uint32_t SchemeScore;
oggpack_buffer *opb=cpi->oggbuffer;
/* Build a frequency map for the modes in this frame */
memset( ModeCount, 0, MAX_MODES*sizeof(ogg_int32_t) );
for ( i = 0; i < cpi->ModeListCount; i++ )
ModeCount[cpi->ModeList[i]] ++;
/* Order the modes from most to least frequent. Store result as
scheme 0 */
for ( j = 0; j < MAX_MODES; j++ ) {
TmpFreq = -1; /* need to re-initialize for each loop */
/* Find the most frequent */
for ( i = 0; i < MAX_MODES; i++ ) {
/* Is this the best scheme so far ??? */
if ( ModeCount[i] > TmpFreq ) {
TmpFreq = ModeCount[i];
TmpIndex = i;
}
}
/* I don't know if the above loop ever fails to match, but it's
better safe than sorry. Plus this takes care of gcc warning */
if ( TmpIndex != -1 ) {
ModeCount[TmpIndex] = -1;
BestModeSchemes[TmpIndex] = (unsigned char)j;
}
}
/* Default/ fallback scheme uses MODE_BITS bits per mode entry */
BestScheme = (MODE_METHODS - 1);
BestSchemeScore = cpi->ModeListCount * 3;
/* Get a bit score for the available schemes. */
for ( j = 0; j < (MODE_METHODS - 1); j++ ) {
/* Reset the scheme score */
if ( j == 0 ){
/* Scheme 0 additional cost of sending frequency order */
SchemeScore = 24;
SchemeList = BestModeSchemes;
} else {
SchemeScore = 0;
SchemeList = ModeSchemes[j-1];
}
/* Find the total bits to code using each avaialable scheme */
for ( i = 0; i < cpi->ModeListCount; i++ )
SchemeScore += ModeBitLengths[SchemeList[cpi->ModeList[i]]];
/* Is this the best scheme so far ??? */
if ( SchemeScore < BestSchemeScore ) {
BestSchemeScore = SchemeScore;
BestScheme = j;
}
}
/* Encode the best scheme. */
oggpackB_write( opb, BestScheme, (ogg_uint32_t)MODE_METHOD_BITS );
/* If the chosen schems is scheme 0 send details of the mode
frequency order */
if ( BestScheme == 0 ) {
for ( j = 0; j < MAX_MODES; j++ )
/* Note that the last two entries are implicit */
oggpackB_write( opb, BestModeSchemes[j], (ogg_uint32_t)MODE_BITS );
SchemeList = BestModeSchemes;
}
else {
SchemeList = ModeSchemes[BestScheme-1];
}
/* Are we using one of the alphabet based schemes or the fallback scheme */
if ( BestScheme < (MODE_METHODS - 1)) {
/* Pack and encode the Mode list */
for ( i = 0; i < cpi->ModeListCount; i++ ) {
/* Add the appropriate mode entropy token. */
ModeIndex = SchemeList[cpi->ModeList[i]];
oggpackB_write( opb, ModeBitPatterns[ModeIndex],
(ogg_uint32_t)ModeBitLengths[ModeIndex] );
}
}else{
/* Fall back to MODE_BITS per entry */
for ( i = 0; i < cpi->ModeListCount; i++ ) {
/* Add the appropriate mode entropy token. */
oggpackB_write( opb, cpi->ModeList[i], MODE_BITS );
}
}
}
static void PackMotionVectors (CP_INSTANCE *cpi) {
ogg_int32_t i;
ogg_uint32_t MethodBits[2] = {0,0};
ogg_uint32_t * MvBitsPtr;
ogg_uint32_t * MvPatternPtr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -