home *** CD-ROM | disk | FTP | other *** search
Wrap
/************************************************************************* tompeg.cpp 03/02/08 Xiaohong *************************************************************************/ /********************************************************** âwâbâ_âtâ@âCâïé╠âCâôâNâïü[âh **********************************************************/ #pragma comment(lib,"vfw32.lib") #include "tompeg.h" #include "systemdata.h" #include "picturestruct.h" #include "uvtempbuffers.h" #include "sequencedata.h" #include "cDCT.h" #include "macros.h" #include <vfw.h> #include <math.h> /********************************************************** ì\æóæ╠é╠ÉΘî╛ **********************************************************/ typedef struct { unsigned char code; /* right justified */ char len; }VLCtable; /* for codes longer than 8 bits (excluding leading zeroes) */ typedef struct { unsigned short code; /* right justified */ char len; }sVLCtable; /*--------------------------------------------------------- Äσé╔ Rcü` è╓Éöôαé┼Ägùpé╖éΘò╧Éöé╠ì\æóæ╠ ---------------------------------------------------------*/ typedef struct { int r,Xi,Xb,Xp,d0i,d0p,d0b; double avg_act; int R, T, d; double actsum; int Np, Nb, S, Q; int prev_mquant; }TOMPEG_RATECONTROL; /*--------------------------------------------------------- AddFrame é╞ NextFrame é╠ù╝ò√é┼ïñÆ╩é╡é─Ägùpé╖éΘò╧Éöé╠ì\æóæ╠ ---------------------------------------------------------*/ typedef struct { int sxf, syf, sxb, syb; unsigned char *neworg[3], *newref[3]; }ADDFRAME_STRUCT; /*--------------------------------------------------------- PICTUREDATA é╠ÉΘî╛ ---------------------------------------------------------*/ typedef struct { int nTempRef; int nPictType; }PICTUREHEADER; typedef struct { int nForwHorFCode,nForwVertFCode; int nBackHorFCode,nBackVertFCode; int nDCPrecision; int nPictStruct; bool bFramePredDCTTab[3],bFramePredDCT; bool bConcealTab[3]; bool bQScaleTab[3],bQScaleType; bool bTopFirst; bool bIntravlcTab[3],bIntravlc; bool bAltScanTab[3],bAltScan; bool bRepeatFirst; bool bProgFrame; }PICTURECODINGEXTENSION; typedef struct { PICTUREHEADER stHeader; PICTURECODINGEXTENSION stCodingExtension; }PICTUREDATA; /*--------------------------------------------------------- CODINGMODELPARAMS ---------------------------------------------------------*/ typedef struct { int nFramesNumberInGroupOfPicture; // N int nDistanceBetweenIPFrames; // M int nIntraSliceRefreshIntaeval; // P int nTotalNumberOfFramesToEncode; // nframes int nTimeCodeOfFirstFrame; // tc0 bool bFieldPicture; // fieldpic }CODINGMODELPARAMS; /********************************************************** âOâìü[âoâïÆΦÉöé╠ÉΘî╛ **********************************************************/ /* zig-zag scan */ static const unsigned char g_ZigZagScanArray[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5, 12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28, 35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51, 58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; /* alternate scan */ static const unsigned char g_AlternateScanArray[64] = { 0,8,16,24,1,9,2,10,17,25,32,40,48,56,57,49, 41,33,26,18,3,11,4,12,19,27,34,42,50,58,35,43, 51,59,20,28,5,13,6,14,21,29,36,44,52,60,37,45, 53,61,22,30,7,15,23,31,38,46,54,62,39,47,55,63 }; /* non-linear quantization coefficient table */ static const unsigned char g_NonLinerQuantizationArray[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,10,12,14,16,18,20,22, 24,28,32,36,40,44,48,52, 56,64,72,80,88,96,104,112 }; static const unsigned char g_MapNonLinearQuantizationArray[113] = { 0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16, 16,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,22,22, 22,22,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26, 26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,29, 29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31 }; static const VLCtable g_AddRincArray[33]= { {0x01,1}, {0x03,3}, {0x02,3}, {0x03,4}, {0x02,4}, {0x03,5}, {0x02,5}, {0x07,7}, {0x06,7}, {0x0b,8}, {0x0a,8}, {0x09,8}, {0x08,8}, {0x07,8}, {0x06,8}, {0x17,10}, {0x16,10}, {0x15,10}, {0x14,10}, {0x13,10}, {0x12,10}, {0x23,11}, {0x22,11}, {0x21,11}, {0x20,11}, {0x1f,11}, {0x1e,11}, {0x1d,11}, {0x1c,11}, {0x1b,11}, {0x1a,11}, {0x19,11}, {0x18,11} }; /* Table B-2, B-3, B-4 variable length codes for macroblock_type * * indexed by [macroblock_type] */ static const VLCtable g_MacroblockTypeTable[3][32]= { /* I */ { {0,0}, {1,1}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {1,2}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} }, /* P */ { {0,0}, {3,5}, {1,2}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {1,3}, {0,0}, {1,1}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {1,6}, {1,5}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {2,5}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} }, /* B */ { {0,0}, {3,5}, {0,0}, {0,0}, {2,3}, {0,0}, {3,3}, {0,0}, {2,4}, {0,0}, {3,4}, {0,0}, {2,2}, {0,0}, {3,2}, {0,0}, {0,0}, {1,6}, {0,0}, {0,0}, {0,0}, {0,0}, {2,6}, {0,0}, {0,0}, {0,0}, {3,6}, {0,0}, {0,0}, {0,0}, {2,5}, {0,0} } }; /* Table B-5 ... B-8 variable length codes for macroblock_type in * scalable sequences * * not implemented */ /* Table B-9, variable length codes for coded_block_pattern * * indexed by [coded_block_pattern] */ static const VLCtable g_CodedBlockPatternArray[64]= { {0x01,9}, {0x0b,5}, {0x09,5}, {0x0d,6}, {0x0d,4}, {0x17,7}, {0x13,7}, {0x1f,8}, {0x0c,4}, {0x16,7}, {0x12,7}, {0x1e,8}, {0x13,5}, {0x1b,8}, {0x17,8}, {0x13,8}, {0x0b,4}, {0x15,7}, {0x11,7}, {0x1d,8}, {0x11,5}, {0x19,8}, {0x15,8}, {0x11,8}, {0x0f,6}, {0x0f,8}, {0x0d,8}, {0x03,9}, {0x0f,5}, {0x0b,8}, {0x07,8}, {0x07,9}, {0x0a,4}, {0x14,7}, {0x10,7}, {0x1c,8}, {0x0e,6}, {0x0e,8}, {0x0c,8}, {0x02,9}, {0x10,5}, {0x18,8}, {0x14,8}, {0x10,8}, {0x0e,5}, {0x0a,8}, {0x06,8}, {0x06,9}, {0x12,5}, {0x1a,8}, {0x16,8}, {0x12,8}, {0x0d,5}, {0x09,8}, {0x05,8}, {0x05,9}, {0x0c,5}, {0x08,8}, {0x04,8}, {0x04,9}, {0x07,3}, {0x0a,5}, {0x08,5}, {0x0c,6} }; /* Table B-10, variable length codes for motion_code * * indexed by [abs(motion_code)] * sign of motion_code is treated elsewhere */ static const VLCtable g_MotionCodeArray[17]= { {0x01,1}, {0x01,2}, {0x01,3}, {0x01,4}, {0x03,6}, {0x05,7}, {0x04,7}, {0x03,7}, {0x0b,9}, {0x0a,9}, {0x09,9}, {0x11,10}, {0x10,10}, {0x0f,10}, {0x0e,10}, {0x0d,10}, {0x0c,10} }; /* Table B-11, variable length codes for dmvector * * treated elsewhere */ /* Table B-12, variable length codes for dct_dc_size_luminance * * indexed by [dct_dc_size_luminance] */ static const sVLCtable g_DCTDcSizeLuminanceArray[12]= { {0x0004,3}, {0x0000,2}, {0x0001,2}, {0x0005,3}, {0x0006,3}, {0x000e,4}, {0x001e,5}, {0x003e,6}, {0x007e,7}, {0x00fe,8}, {0x01fe,9}, {0x01ff,9} }; /* Table B-13, variable length codes for dct_dc_size_chrominance * * indexed by [dct_dc_size_chrominance] */ static const sVLCtable g_DCTDcSizeChrominanceArray[12]= { {0x0000,2}, {0x0001,2}, {0x0002,2}, {0x0006,3}, {0x000e,4}, {0x001e,5}, {0x003e,6}, {0x007e,7}, {0x00fe,8}, {0x01fe,9}, {0x03fe,10},{0x03ff,10} }; /* Table B-14, DCT coefficients table zero * * indexed by [run][level-1] * split into two tables (g_DCTCodeTable1, g_DCTCodeTable2) to reduce size * 'first DCT coefficient' condition and 'End of Block' are treated elsewhere * codes do not include s (sign bit) */ static VLCtable g_DCTCodeTable1[2][40]= { /* run = 0, level = 1...40 */ { {0x03, 2}, {0x04, 4}, {0x05, 5}, {0x06, 7}, {0x26, 8}, {0x21, 8}, {0x0a,10}, {0x1d,12}, {0x18,12}, {0x13,12}, {0x10,12}, {0x1a,13}, {0x19,13}, {0x18,13}, {0x17,13}, {0x1f,14}, {0x1e,14}, {0x1d,14}, {0x1c,14}, {0x1b,14}, {0x1a,14}, {0x19,14}, {0x18,14}, {0x17,14}, {0x16,14}, {0x15,14}, {0x14,14}, {0x13,14}, {0x12,14}, {0x11,14}, {0x10,14}, {0x18,15}, {0x17,15}, {0x16,15}, {0x15,15}, {0x14,15}, {0x13,15}, {0x12,15}, {0x11,15}, {0x10,15} }, /* run = 1, level = 1...18 */ { {0x03, 3}, {0x06, 6}, {0x25, 8}, {0x0c,10}, {0x1b,12}, {0x16,13}, {0x15,13}, {0x1f,15}, {0x1e,15}, {0x1d,15}, {0x1c,15}, {0x1b,15}, {0x1a,15}, {0x19,15}, {0x13,16}, {0x12,16}, {0x11,16}, {0x10,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0} } }; static VLCtable g_DCTCodeTable2[30][5]= { /* run = 2...31, level = 1...5 */ {{0x05, 4}, {0x04, 7}, {0x0b,10}, {0x14,12}, {0x14,13}}, {{0x07, 5}, {0x24, 8}, {0x1c,12}, {0x13,13}, {0x00, 0}}, {{0x06, 5}, {0x0f,10}, {0x12,12}, {0x00, 0}, {0x00, 0}}, {{0x07, 6}, {0x09,10}, {0x12,13}, {0x00, 0}, {0x00, 0}}, {{0x05, 6}, {0x1e,12}, {0x14,16}, {0x00, 0}, {0x00, 0}}, {{0x04, 6}, {0x15,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x07, 7}, {0x11,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x05, 7}, {0x11,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x27, 8}, {0x10,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x23, 8}, {0x1a,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x22, 8}, {0x19,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x20, 8}, {0x18,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x0e,10}, {0x17,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x0d,10}, {0x16,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x08,10}, {0x15,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1f,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1a,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x19,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x17,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x16,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1f,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1e,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1d,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1c,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1b,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1f,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1e,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1d,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1c,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1b,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}} }; /* Table B-15, DCT coefficients table one * * indexed by [run][level-1] * split into two tables (g_DCTCodeTable1a, g_DCTCodeTable2a) to reduce size * 'End of Block' is treated elsewhere * codes do not include s (sign bit) */ static VLCtable g_DCTCodeTable1a[2][40]= { /* run = 0, level = 1...40 */ { {0x02, 2}, {0x06, 3}, {0x07, 4}, {0x1c, 5}, {0x1d, 5}, {0x05, 6}, {0x04, 6}, {0x7b, 7}, {0x7c, 7}, {0x23, 8}, {0x22, 8}, {0xfa, 8}, {0xfb, 8}, {0xfe, 8}, {0xff, 8}, {0x1f,14}, {0x1e,14}, {0x1d,14}, {0x1c,14}, {0x1b,14}, {0x1a,14}, {0x19,14}, {0x18,14}, {0x17,14}, {0x16,14}, {0x15,14}, {0x14,14}, {0x13,14}, {0x12,14}, {0x11,14}, {0x10,14}, {0x18,15}, {0x17,15}, {0x16,15}, {0x15,15}, {0x14,15}, {0x13,15}, {0x12,15}, {0x11,15}, {0x10,15} }, /* run = 1, level = 1...18 */ { {0x02, 3}, {0x06, 5}, {0x79, 7}, {0x27, 8}, {0x20, 8}, {0x16,13}, {0x15,13}, {0x1f,15}, {0x1e,15}, {0x1d,15}, {0x1c,15}, {0x1b,15}, {0x1a,15}, {0x19,15}, {0x13,16}, {0x12,16}, {0x11,16}, {0x10,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0} } }; static VLCtable g_DCTCodeTable2a[30][5]= { /* run = 2...31, level = 1...5 */ {{0x05, 5}, {0x07, 7}, {0xfc, 8}, {0x0c,10}, {0x14,13}}, {{0x07, 5}, {0x26, 8}, {0x1c,12}, {0x13,13}, {0x00, 0}}, {{0x06, 6}, {0xfd, 8}, {0x12,12}, {0x00, 0}, {0x00, 0}}, {{0x07, 6}, {0x04, 9}, {0x12,13}, {0x00, 0}, {0x00, 0}}, {{0x06, 7}, {0x1e,12}, {0x14,16}, {0x00, 0}, {0x00, 0}}, {{0x04, 7}, {0x15,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x05, 7}, {0x11,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x78, 7}, {0x11,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x7a, 7}, {0x10,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x21, 8}, {0x1a,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x25, 8}, {0x19,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x24, 8}, {0x18,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x05, 9}, {0x17,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x07, 9}, {0x16,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x0d,10}, {0x15,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1f,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1a,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x19,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x17,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x16,12}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1f,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1e,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1d,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1c,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1b,13}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1f,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1e,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1d,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1c,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}}, {{0x1b,16}, {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}} }; /********************************************************** âìü[âJâïè╓Éö é╠ÉΘî╛ **********************************************************/ /*--------------------------------------------------------- êΩÄ₧âtâ@âCâïé╠âpâXé╠ì∞ɼ ---------------------------------------------------------*/ static void MakeTmpFilePath(char* szPath,unsigned long uLength,char *szFname); /*--------------------------------------------------------- ò╧Éöé╠É▌ÆΦ ---------------------------------------------------------*/ static inline TOMPGRET SetParam(void); /*--------------------------------------------------------- ò╧Éöé╠ö═ê═é╠â`âFâbâN ---------------------------------------------------------*/ static inline TOMPGRET RangeCheck(void); /*--------------------------------------------------------- ârâbâgâîü[âgé╠â`âFâbâN ---------------------------------------------------------*/ static inline bool ValidBitrate(const unsigned char,const unsigned int); /*========================================================= Rate Control =========================================================*/ /*--------------------------------------------------------- âVü[âPâôâXé╠Åëè·ë╗ ---------------------------------------------------------*/ static inline void RcInitSeq(void); static inline void RcInitGOP(const int,const int); static inline void RcInitPic(unsigned char* frame); static inline void RcUpdatePict(void); /*--------------------------------------------------------- compute initial quantization stepsize (at the beginning of picture) ---------------------------------------------------------*/ static inline int RcStartMb(void); /*--------------------------------------------------------- Step 2: measure virtual buffer - estimated buffer discrepancy ---------------------------------------------------------*/ static inline int RcCalcMQuant(const int); /*--------------------------------------------------------- compute variance of 8x8 block ---------------------------------------------------------*/ static double VarSBlock(unsigned char*,const int); /*========================================================= VBV é╠îvÄZ generates warnings if underflow or overflow occurs =========================================================*/ /*--------------------------------------------------------- vbv_end_of_picture has to be called directly after writing picture_data() needed for accurate VBV buffer overflow calculation assumes there is no byte stuffing prior to the next start code ---------------------------------------------------------*/ static void VBVEndOfPicture(void); /*--------------------------------------------------------- has to be called directly after writing the picture start code, the reference point for vbv_delay ---------------------------------------------------------*/ static inline int CalcVBVDelay(void); /*========================================================= âwâbâ_é╠Åæé½ì₧é▌ =========================================================*/ /*--------------------------------------------------------- âwâbâ_é╠Åæé½ì₧é▌ ---------------------------------------------------------*/ static inline void PutGroupHeader(const int,const unsigned char); /*--------------------------------------------------------- âtâîü[âÇö╘ìåé⌐éτâ^âCâÇâRü[âhé╓ò╧è╖ ---------------------------------------------------------*/ static inline int FrameToTimeCode(int); /*--------------------------------------------------------- output a zero terminated string as user data string must not emulate start codes ---------------------------------------------------------*/ static inline void PutUserData(char* userdata); /*--------------------------------------------------------- generate picture header ---------------------------------------------------------*/ static inline void PutPictureHeader(void); /*--------------------------------------------------------- generate picture coding extension (6.2.3.1, 6.3.11) composite display information (v_axis etc.) not implemented ---------------------------------------------------------*/ static inline void PutPictureCodingExtension(void); /*--------------------------------------------------------- BITMAPINFOHEADER é╞ ârâbâgâfü[â^é≡Ä≤é»Äµé┴é─üCÄgùpë┬ö\é╚î`é╔ò╧ìXé╖éΘ ---------------------------------------------------------*/ static inline TOMPGRET ConvRGBtoYUV(const LPBITMAPINFO,const unsigned char*,unsigned char* []); /*========================================================= ô«é½é╠ÉäÆΦ =========================================================*/ /*--------------------------------------------------------- ô«é½é╠ÉäÆΦ ---------------------------------------------------------*/ static void MotionEstimation(unsigned char* oldorg, unsigned char* neworg, unsigned char* oldref, unsigned char* newref, unsigned char* cur, unsigned char* curref, int sxf,int syf,int sxb,int syb, MACROBLOCKINFO* mbi, int secondfield,bool ipflag); /*--------------------------------------------------------- âtâîü[âÇÅπé┼é╠ô«é½ÉäÆΦ ---------------------------------------------------------*/ static inline void FrameME(unsigned char* oldorg, unsigned char* neworg, unsigned char* oldref, unsigned char* newref, unsigned char* cur, int i,int j,int sxf,int syf,int sxb,int syb, MACROBLOCKINFO* mbi); /*--------------------------------------------------------- âtâBü[âïâhÅπé┼é╠ô«é½ÉäÆΦ oldorg: original frame for forward prediction (P and B frames) neworg: original frame for backward prediction (B frames only) oldref: reconstructed frame for forward prediction (P and B frames) newref: reconstructed frame for backward prediction (B frames only) cur: current original frame (the one for which the prediction is formed) curref: current reconstructed frame (to predict second field from first) sxf,syf: forward search window (frame coordinates) sxb,syb: backward search window (frame coordinates) mbi: pointer to macroblock info structure secondfield: indicates second field of a frame (in P fields this means that reference field of opposite parity is in curref instead of oldref) ipflag: indicates a P type field which is the second field of a frame in which the first field is I type (this restricts predictions to be based only on the opposite parity (=I) field) results: mbi-> mb_type: 0, MB_INTRA, MB_FORWARD, MB_BACKWARD, MB_FORWARD|MB_BACKWARD MV[][][]: motion vectors (field format) mv_field_sel: top/bottom field motion_type: MC_FIELD, MC_16X8 uses global vars: pict_type, pict_struct ---------------------------------------------------------*/ static inline void FieldME(unsigned char *oldorg, unsigned char *neworg, unsigned char *oldref, unsigned char *newref, unsigned char *cur, unsigned char *curref, int i, int j, int sxf, int syf, int sxb, int syb, MACROBLOCKINFO *mbi, int secondfield, bool ipflag); /*--------------------------------------------------------- frame picture motion estimation org: top left pel of source reference frame ref: top left pel of reconstructed reference frame mb: macroblock to be matched i,j: location of mb relative to ref (=center of search window) sx,sy: half widths of search window iminp,jminp,dframep: location and value of best frame prediction imintp,jmintp,tselp: location of best field pred. for top field of mb iminbp,jminbp,bselp: location of best field pred. for bottom field of mb dfieldp: value of field prediction ---------------------------------------------------------*/ static void FrameEstimate(unsigned char *org, unsigned char *ref, unsigned char *mb, int i, int j, int sx, int sy, int *iminp, int *jminp, int *imintp, int *jmintp, int *iminbp, int *jminbp, int *dframep, int *dfieldp, int *tselp, int *bselp, int imins[2][2], int jmins[2][2]); static inline void DPFrameEstimate(unsigned char *ref, unsigned char *mb, int i, int j, int iminf[2][2], int jminf[2][2], int *iminp, int *jminp, int *imindmvp, int *jmindmvp, int *dmcp, int *vmcp); /*--------------------------------------------------------- field picture motion estimation subroutine toporg: address of original top reference field topref: address of reconstructed top reference field botorg: address of original bottom reference field botref: address of reconstructed bottom reference field mb: macroblock to be matched i,j: location of mb (=center of search window) sx,sy: half width/height of search window iminp,jminp,selp,dfieldp: location and distance of best field prediction imin8up,jmin8up,sel8up: location of best 16x8 pred. for upper half of mb imin8lp,jmin8lp,sel8lp: location of best 16x8 pred. for lower half of mb d8p: distance of best 16x8 prediction iminsp,jminsp,dsp: location and distance of best same parity field prediction (needed for dual prime, only valid if ipflag==0) ---------------------------------------------------------*/ static void FieldEstimate(unsigned char *toporg, unsigned char *topref, unsigned char *botorg, unsigned char *botref, unsigned char *mb, int i, int j, int sx, int sy, bool ipflag, int *iminp, int *jminp, int *imin8up, int *jmin8up, int *imin8lp, int *jmin8lp, int *dfieldp, int *d8p, int *selp, int *sel8up, int *sel8lp, int *iminsp, int *jminsp, int *dsp); static inline void DPFieldEstimate(unsigned char *topref, unsigned char *botref, unsigned char *mb, int i, int j, int imins, int jmins, int *imindmvp, int *jmindmvp, int *dmcp, int *vmcp); /*--------------------------------------------------------- full search block matching blk: top left pel of (16*h) block h: height of block lx: distance (in bytes) of vertically adjacent pels in ref,blk org: top left pel of source reference picture ref: top left pel of reconstructed reference picture i0,j0: center of search window sx,sy: half widths of search window xmax,ymax: right/bottom limits of search area iminp,jminp: pointers to where the result is stored result is given as half pel offset from ref(0,0) i.e. NOT relative to (i0,j0) ---------------------------------------------------------*/ static int FullSearch(unsigned char *org, unsigned char *ref, unsigned char *blk, int lx, int i0, int j0, int sx, int sy, int h, int xmax, int ymax, int *iminp, int *jminp); /*--------------------------------------------------------- total absolute difference between two (16*h) blocks including optional half pel interpolation of blk1 (hx,hy) blk1,blk2: addresses of top left pels of both blocks lx: distance (in bytes) of vertically adjacent pels hx,hy: flags for horizontal and/or vertical interpolation h: height of block (usually 8 or 16) distlim: bail out if sum exceeds this value ---------------------------------------------------------*/ static int Dist1(unsigned char *blk1, unsigned char *blk2, int lx, int hx, int hy, int h, int distlim); /*--------------------------------------------------------- total squared difference between two (16*h) blocks including optional half pel interpolation of blk1 (hx,hy) blk1,blk2: addresses of top left pels of both blocks lx: distance (in bytes) of vertically adjacent pels hx,hy: flags for horizontal and/or vertical interpolation h: height of block (usually 8 or 16) ---------------------------------------------------------*/ static int Dist2(unsigned char *blk1, unsigned char *blk2, int lx, int hx, int hy, int h); /*--------------------------------------------------------- absolute difference error between a (16*h) block and a bidirectional prediction p2: address of top left pel of block pf,hxf,hyf: address and half pel flags of forward ref. block pb,hxb,hyb: address and half pel flags of backward ref. block h: height of block lx: distance (in bytes) of vertically adjacent pels in p2,pf,pb ---------------------------------------------------------*/ static int BDist1(unsigned char *pf, unsigned char *pb, unsigned char *p2, int lx, int hxf, int hyf, int hxb, int hyb, int h); /*--------------------------------------------------------- squared error between a (16*h) block and a bidirectional prediction p2: address of top left pel of block pf,hxf,hyf: address and half pel flags of forward ref. block pb,hxb,hyb: address and half pel flags of backward ref. block h: height of block lx: distance (in bytes) of vertically adjacent pels in p2,pf,pb ---------------------------------------------------------*/ static int BDist2(unsigned char *pf, unsigned char *pb, unsigned char *p2, int lx, int hxf, int hyf, int hxb, int hyb, int h); /*--------------------------------------------------------- variance of a (16*16) block, multiplied by 256 p: address of top left pel of block lx: distance (in bytes) of vertically adjacent pels ---------------------------------------------------------*/ static int Variance(unsigned char *p,int lx); /*========================================================= predict =========================================================*/ /*--------------------------------------------------------- form prediction for a complete picture (frontend for predict_mb) reff: reference frame for forward prediction refb: reference frame for backward prediction cur: destination (current) frame secondfield: predict second field of a frame mbi: macroblock info ---------------------------------------------------------*/ static void Predict(unsigned char* reff[],unsigned char* refb[],unsigned char* cur[], int secondfield,MACROBLOCKINFO* mbi); /*--------------------------------------------------------- form prediction for one macroblock oldref: reference frame for forward prediction newref: reference frame for backward prediction cur: destination (current) frame lx: frame width (identical to global var `width') bx,by: picture (field or frame) coordinates of macroblock to be predicted pict_type: I, P or B pict_struct: FRAME_PICTURE, TOP_FIELD, BOTTOM_FIELD mb_type: MB_FORWARD, MB_BACKWARD, MB_INTRA motion_type: MC_FRAME, MC_FIELD, MC_16X8, MC_DMV secondfield: predict second field of a frame PMV[2][2][2]: motion vectors (in half pel picture coordinates) mv_field_sel[2][2]: motion vertical field selects (for field predictions) dmvector: differential motion vectors (for dual prime) Notes: - when predicting a P type picture which is the second field of a frame, the same parity reference field is in oldref, while the opposite parity reference field is assumed to be in newref! - intra macroblocks are modelled to have a constant prediction of 128 for all pels; this results in a DC DCT coefficient symmetric to 0 - vectors for field prediction in frame pictures are in half pel frame coordinates (vertical component is twice the field value and always even) already covers dual prime (not yet used) ---------------------------------------------------------*/ static inline void PredictMB( unsigned char *oldref[], unsigned char *newref[], unsigned char *cur[], int lx, int bx, int by, int pict_type, int pict_struct, int mb_type, int motion_type, int secondfield, int PMV[][2][2], int mv_field_sel[][2], int dmvector[]); /*--------------------------------------------------------- predict a rectangular block (all three components) src: source frame (Y,U,V) sfield: source field select (0: frame or top field, 1: bottom field) dst: destination frame (Y,U,V) dfield: destination field select (0: frame or top field, 1: bottom field) the following values are in luminance picture (frame or field) dimensions lx: distance of vertically adjacent pels (selects frame or field pred.) w,h: width and height of block (only 16x16 or 16x8 are used) x,y: coordinates of destination block dx,dy: half pel motion vector addflag: store or add (= average) prediction ---------------------------------------------------------*/ static void Pred(unsigned char *src[], int sfield, unsigned char *dst[], int dfield, int lx, int w, int h, int x, int y, int dx, int dy, int addflag); /*--------------------------------------------------------- low level prediction routine src: prediction source dst: prediction destination lx: line width (for both src and dst) x,y: destination coordinates dx,dy: half pel motion vector w,h: size of prediction block addflag: store or add prediction ---------------------------------------------------------*/ static inline void PredComp(unsigned char *src, unsigned char *dst, int lx, int w, int h, int x, int y, int dx, int dy, int addflag); /*--------------------------------------------------------- calculate derived motion vectors (DMV) for dual prime prediction dmvector[2]: differential motion vectors (-1,0,+1) mvx,mvy: motion vector (for same parity) DMV[2][2]: derived motion vectors (for opposite parity) uses global variables pict_struct and topfirst Notes: - all vectors are in field coordinates (even for frame pictures) ---------------------------------------------------------*/ static void CalDMV(int DMV[][2], int *dmvector, int mvx,int mvy); static inline void ClearBlock(unsigned char *cur[], int i0, int j0); /*========================================================= ò╧î` =========================================================*/ /*--------------------------------------------------------- subtract prediction and transform prediction error ---------------------------------------------------------*/ static void Transform(unsigned char* pred[], unsigned char* cur[], MACROBLOCKINFO* mbi, short blocks[][64]); /*--------------------------------------------------------- inverse transform prediction error and add prediction ---------------------------------------------------------*/ static void ITransform(unsigned char* pred[], unsigned char* cur[], MACROBLOCKINFO* mbi, short blocks[][64]); /*--------------------------------------------------------- add prediction and prediction error, saturate to 0...255 ---------------------------------------------------------*/ static inline void AddPred(unsigned char* pred,unsigned char* cur,int lx,short* blk); /*--------------------------------------------------------- subtract prediction from block data ---------------------------------------------------------*/ static inline void SubPred(unsigned char* pred,unsigned char* cur,int lx,short* blk); /*--------------------------------------------------------- select between frame and field DCT preliminary version: based on inter-field correlation ---------------------------------------------------------*/ static void DCTTypeEstimation(unsigned char* pred, unsigned char* cur, MACROBLOCKINFO* mbi); /*========================================================= PutPic =========================================================*/ /*--------------------------------------------------------- quantization / variable length encoding of a complete picture ---------------------------------------------------------*/ static TOMPGRET PutPicture(unsigned char* frame); /*--------------------------------------------------------- output motion vectors (6.2.5.2, 6.3.16.2) this routine also updates the predictions for motion vectors (PMV) ---------------------------------------------------------*/ static void PutMotionVectors(int MV[2][2][2], int PMV[2][2][2], int mv_field_sel[2][2], int dmvector[2], int s, int motion_type, int hor_f_code, int vert_f_code); /*========================================================= Put Mpeg =========================================================*/ /*--------------------------------------------------------- generate variable length codes for an intra-coded block (6.2.6, 6.3.17) ---------------------------------------------------------*/ static inline TOMPGRET PutIntraCodedBlock(short* blk,int cc); /*--------------------------------------------------------- generate variable length codes for a non-intra-coded block (6.2.6, 6.3.17) ---------------------------------------------------------*/ static inline TOMPGRET PutNonIntraCodedBlock(short* blk); /*--------------------------------------------------------- generate variable length code for a motion vector component (7.6.3.1) ---------------------------------------------------------*/ static void PutMotionVector(int dmv,int f_code); /*========================================================= Put Variable Length Codes =========================================================*/ /*--------------------------------------------------------- generate variable length code for luminance DC coefficient ---------------------------------------------------------*/ static inline TOMPGRET PutLuminanceDCCoefficient(const int); /*--------------------------------------------------------- generate variable length code for chrominance DC coefficient ---------------------------------------------------------*/ static inline TOMPGRET PutChrominanceDCCoefficient(const int); /*--------------------------------------------------------- generate variable length code for DC coefficient (7.2.1) ---------------------------------------------------------*/ static TOMPGRET PutDC(const void*,const int); /*--------------------------------------------------------- generate variable length code for first coefficient of a non-intra block (7.2.2.2) ---------------------------------------------------------*/ static inline TOMPGRET PutACFirst(const int,const int); /*--------------------------------------------------------- generate variable length code for other DCT coefficients (7.2.2) ---------------------------------------------------------*/ static TOMPGRET PutAC(const int,const int,const int); /*--------------------------------------------------------- generate variable length code for macroblock_address_increment ---------------------------------------------------------*/ static inline void PutMacroblockAddressIncement(int); /*--------------------------------------------------------- generate variable length code for macroblock_type ---------------------------------------------------------*/ static inline void PutMacroblockType(const int,const int); /*--------------------------------------------------------- generate variable length code for motion_code ---------------------------------------------------------*/ static inline void PutMotionCode(const int); /*--------------------------------------------------------- generate variable length code for dmvector[t] ---------------------------------------------------------*/ static void PutDMVector(const int); /*--------------------------------------------------------- generate variable length code for coded_block_pattern 4:2:2, 4:4:4 not implemented ---------------------------------------------------------*/ static inline void PutCodedBlockPattern(const int); /*========================================================= ù╩Äqë╗âeü[âuâïè╓îW =========================================================*/ static inline int QuantIntra(short* src,short* dst,int dc_prec, unsigned char* quant_mat,unsigned short* recip_quant_mat, int mquant); static inline int QuantNonIntra(short* src,short* dst, unsigned char* quant_mat, unsigned short* recip_quant_mat, int mquant); /*--------------------------------------------------------- MPEG-1 inverse quantization ---------------------------------------------------------*/ static void IQuantIntra(short* src,short* dst,int dc_prec,unsigned char* quant_mat,int mquant); static void IQuantNonIntra(short* src,short* dst, unsigned char* quant_mat, int mquant); /********************************************************** âìü[âJâïò╧Éö é╠ÉΘî╛ **********************************************************/ static PICTURESTRUCT g_stPictureStruct; static PICTUREDATA g_stPictureData; static UVTEMPBUFFERS g_stUVTempBuffers; static CODINGMODELPARAMS g_stCodingModelParams; static SYSTEMDATA g_stSystemData; static SEQUENCEDATA g_stSequenceData; static cDCT g_cDCT; static TOMPEG_RATECONTROL g_stRateControl; static ADDFRAME_STRUCT g_stAddFrameStruct; static bool (*g_pProcFunction)(TOMPEG_PROCESS_PARAM,int); static char g_szTmpVideoPath[260]; static char g_szTmpAudioPath[260]; static int g_nWriteSequenceGrounp = 0; static int g_nSearchSize; static int g_nFastMotionCompensationLevel; static int g_nCurrentFrame; /********************************************************** SEQUENCEDATA é╠âüâôâoè╓Éöé╠ÉΘî╛ ôαòöé┼ g_ZigZagScanArray é≡Ägùpé╡é─éóéΘòöò¬é¬éáéΘé╠é┼ ò╩é╠Ä└ìsâtâ@âCâïé╔é╖éΘé▒é╞é¬Åoùêé▄é╣é±é┼é╡é╜üièOòöÄQÅ╞îÖüIüj **********************************************************/ void SEQUENCEDATA::PutSequenceHeader(SYSTEMDATA* pSystemData,const PICTURESTRUCT* pPictureStruct) { int i; pSystemData->alignbits(); pSystemData->putbits(SEQ_START_CODE,32); /* sequence_header_code */ pSystemData->putbits(stHeader.nHFrameSize,12); /* horizontal_size_value */ pSystemData->putbits(stHeader.nVFrameSize,12); /* vertical_size_value */ pSystemData->putbits(stHeader.nAspectRatio,4); /* aspect_ratio_information */ pSystemData->putbits(stHeader.nFrameRateCode+1,4); /* frame_rate_code */ pSystemData->putbits((int)ceil(stHeader.fBitRate/400.0),18); /* bit_rate_value */ pSystemData->putbits(1,1); /* marker_bit */ pSystemData->putbits(stHeader.nVBVBufferSize,10); /* vbv_buffer_size_value */ pSystemData->putbits(stHeader.uConstrainedParams,1); /* constrained_parameters_flag */ if (stHeader.bLoadIQuant) { pSystemData->putbits(1,1); /* load_intra_quantizer_matrix */ for (i=0; i<64; i++) /* matrices are always downloaded in zig-zag order */ pSystemData->putbits(pPictureStruct->uIntraQArray[g_ZigZagScanArray[i]],8); /* intra_quantizer_matrix */ } else pSystemData->putbits(0,1); if (stHeader.bLoadNIQuant) { pSystemData->putbits(1,1); /* load_non_intra_quantizer_matrix */ for (i=0; i<64; i++) pSystemData->putbits(pPictureStruct->uInterQArray[g_ZigZagScanArray[i]],8); /* non_intra_quantizer_matrix */ } else pSystemData->putbits(0,1); /* load_non_intra_quantizer_matrix */ } void SEQUENCEDATA::PutSequenceDisplayExtension(SYSTEMDATA* pSystemData) { pSystemData->alignbits(); pSystemData->putbits(EXT_START_CODE,32); /* extension_start_code */ pSystemData->putbits(DISP_ID,4); /* extension_start_code_identifier */ pSystemData->putbits(stDisplayExtension.nVideoFormat,3); /* video_format */ pSystemData->putbits(1,1); /* colour_description */ pSystemData->putbits(stDisplayExtension.nColorPrimaries,8); /* colour_primaries */ pSystemData->putbits(stDisplayExtension.nTransferCharacteristics,8); /* transfer_characteristics */ pSystemData->putbits(stDisplayExtension.nMatrixCoefficients,8); /* matrix_coefficients */ pSystemData->putbits(stDisplayExtension.nDisplayHSize,14); /* display_horizontal_size */ pSystemData->putbits(1,1); /* marker_bit */ pSystemData->putbits(stDisplayExtension.nDisplayVSize,14); /* display_vertical_size */ } void SEQUENCEDATA::PutSequenceEndCode(SYSTEMDATA* pSystemData) { pSystemData->alignbits(); pSystemData->putbits(SEQ_END_CODE,32); } /********************************************************** cTompeg é╠âüâôâoè╓Éöé╠ÉΘî╛ **********************************************************/ int WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, PVOID pvReserved) { TOMPEG_Init(); return TRUE; } /*--------------------------------------------------------- âëâCâuâëâèé╠Åëè·ë╗ ---------------------------------------------------------*/ EXPORT void CALLBACK TOMPEG_Init(void) { g_szTmpAudioPath[0] = '\0'; g_szTmpVideoPath[0] = '\0'; TOMPEG_Clear(); } /*--------------------------------------------------------- âüâéâèé╠ë≡ò· ---------------------------------------------------------*/ EXPORT void CALLBACK TOMPEG_Clear(void) { g_pProcFunction = NULL; g_nFastMotionCompensationLevel = 0; g_nCurrentFrame = 0; g_stUVTempBuffers.Clear(); g_stPictureStruct.Clear(); g_stSystemData.CloseOutFile(); if(g_szTmpVideoPath[0]!='\0') DeleteFile(g_szTmpVideoPath); g_szTmpVideoPath[0] = '\0'; if(g_szTmpAudioPath[0]!='\0') DeleteFile(g_szTmpAudioPath); g_szTmpAudioPath[0] = '\0'; } /*--------------------------------------------------------- âtâ@âCâïé≡ò█æ╢é╖éΘ ---------------------------------------------------------*/ EXPORT TOMPGRET CALLBACK TOMPEG_SaveAs(const char* szFile) { g_stSequenceData.PutSequenceEndCode(&g_stSystemData); g_stSystemData.flushbits(); g_stSystemData.CloseOutFile(); TOMPGRET ret; if(g_szTmpAudioPath[0] == '\0') { // âIü[âfâBâIâfü[â^é╚é╡ if(!MoveFile(g_szTmpVideoPath,szFile)) { return TR_ERR_RENAME_TMP_FILE; } g_szTmpVideoPath[0] = '\0'; } else { // mplex if((ret = TOMPEG_ConvAudioAndVideo(g_szTmpVideoPath,g_szTmpAudioPath,szFile,g_pProcFunction))!=TR_OK) { return ret; } } TOMPEG_Clear(); return TR_OK; } /*--------------------------------------------------------- ăé╠âtâîü[âÇö╘ìåé≡ò╘é╖ ---------------------------------------------------------*/ EXPORT int CALLBACK TOMPEG_NextFrame(void) { int f,j; int f0, n, np, nb; if(g_nCurrentFrame == 0) { RcInitSeq(); /* initialize rate control */ /* sequence header, sequence extension and sequence display extension */ g_stSequenceData.PutSequenceHeader(&g_stSystemData,&g_stPictureStruct); /* optionally output some text data (description, copyright or whatever) */ PutUserData(VERSION_INFO); } /* f0: lowest frame number in current GOP * * first GOP contains N-(M-1) frames, * all other GOPs contain N frames */ if(g_stCodingModelParams.nFramesNumberInGroupOfPicture == 0) { return TR_FRAME_NUMBER_IN_GROOUP_ERR; } f0 = g_stCodingModelParams.nFramesNumberInGroupOfPicture*((g_nCurrentFrame+(g_stCodingModelParams.nDistanceBetweenIPFrames-1))/g_stCodingModelParams.nFramesNumberInGroupOfPicture) - (g_stCodingModelParams.nDistanceBetweenIPFrames-1); if (f0<0) f0 = 0; if (g_nCurrentFrame==0 || (g_nCurrentFrame-1)%g_stCodingModelParams.nDistanceBetweenIPFrames==0) { /* I or P frame */ for (j=0; j<3; j++) { /* shuffle reference frames */ g_stAddFrameStruct.neworg[j] = g_stPictureStruct.stOriginalFrames.pOldFrame[j]; g_stAddFrameStruct.newref[j] = g_stPictureStruct.stReconstructedFrames.pOldFrame[j]; g_stPictureStruct.stOriginalFrames.pOldFrame[j] = g_stPictureStruct.stOriginalFrames.pNewFrame[j]; g_stPictureStruct.stReconstructedFrames.pOldFrame[j] = g_stPictureStruct.stReconstructedFrames.pNewFrame[j]; g_stPictureStruct.stOriginalFrames.pNewFrame[j] = g_stAddFrameStruct.neworg[j]; g_stPictureStruct.stReconstructedFrames.pNewFrame[j] = g_stAddFrameStruct.newref[j]; } /* f: frame number in display order */ if(g_nCurrentFrame==0) { f = 0; } else { f = g_nCurrentFrame + g_stCodingModelParams.nDistanceBetweenIPFrames-1; } if (f >= g_stCodingModelParams.nTotalNumberOfFramesToEncode) f = g_stCodingModelParams.nTotalNumberOfFramesToEncode - 1; if (g_nCurrentFrame==f0) /* first displayed frame in GOP is I */ { /* I frame */ g_stPictureData.stHeader.nPictType = I_TYPE; g_stPictureData.stCodingExtension.nForwHorFCode = g_stPictureData.stCodingExtension.nForwVertFCode = 15; g_stPictureData.stCodingExtension.nBackHorFCode = g_stPictureData.stCodingExtension.nBackVertFCode = 15; /* n: number of frames in current GOP * * first GOP contains (M-1) less (B) frames */ if(g_nCurrentFrame == 0) { n = g_stCodingModelParams.nFramesNumberInGroupOfPicture-(g_stCodingModelParams.nDistanceBetweenIPFrames-1); } else { n = g_stCodingModelParams.nFramesNumberInGroupOfPicture; } /* last GOP may contain less frames */ if (n > g_stCodingModelParams.nTotalNumberOfFramesToEncode-f0) n = g_stCodingModelParams.nTotalNumberOfFramesToEncode-f0; /* number of P frames */ if (g_nCurrentFrame==0) np = (n + 2*(g_stCodingModelParams.nDistanceBetweenIPFrames-1))/g_stCodingModelParams.nDistanceBetweenIPFrames - 1; /* first GOP */ else np = (n + (g_stCodingModelParams.nDistanceBetweenIPFrames-1))/g_stCodingModelParams.nDistanceBetweenIPFrames - 1; /* number of B frames */ nb = n - np - 1; RcInitGOP(np,nb); /* Write sequence header to every g_nWriteSequenceGrounp-th GOP if required but skip 1st GOP */ if(g_nWriteSequenceGrounp) { if(!((g_nCurrentFrame/g_stCodingModelParams.nFramesNumberInGroupOfPicture)%g_nWriteSequenceGrounp)&&(g_nCurrentFrame)) g_stSequenceData.PutSequenceHeader(&g_stSystemData,&g_stPictureStruct); } /* set closed_GOP in first GOP only */ PutGroupHeader(f0,g_nCurrentFrame==0); } else { /* P frame */ g_stPictureData.stHeader.nPictType = P_TYPE; g_stPictureData.stCodingExtension.nForwHorFCode = g_stPictureStruct.pstMotionData[0].forw_hor_f_code; g_stPictureData.stCodingExtension.nForwVertFCode = g_stPictureStruct.pstMotionData[0].forw_vert_f_code; g_stPictureData.stCodingExtension.nBackHorFCode = g_stPictureData.stCodingExtension.nBackVertFCode = 15; g_stAddFrameStruct.sxf = g_stPictureStruct.pstMotionData[0].sxf; g_stAddFrameStruct.syf = g_stPictureStruct.pstMotionData[0].syf; } } else { /* B frame */ for (j=0; j<3; j++) { g_stAddFrameStruct.neworg[j] = g_stPictureStruct.stOriginalFrames.pAuxFrame[j]; g_stAddFrameStruct.newref[j] = g_stPictureStruct.stReconstructedFrames.pAuxFrame[j]; } /* f: frame number in display order */ f = g_nCurrentFrame - 1; g_stPictureData.stHeader.nPictType = B_TYPE; n = (g_nCurrentFrame-2)%g_stCodingModelParams.nDistanceBetweenIPFrames + 1; /* first B: n=1, second B: n=2, ... */ g_stPictureData.stCodingExtension.nForwHorFCode = g_stPictureStruct.pstMotionData[n].forw_hor_f_code; g_stPictureData.stCodingExtension.nForwVertFCode = g_stPictureStruct.pstMotionData[n].forw_vert_f_code; g_stPictureData.stCodingExtension.nBackHorFCode = g_stPictureStruct.pstMotionData[n].back_hor_f_code; g_stPictureData.stCodingExtension.nBackVertFCode = g_stPictureStruct.pstMotionData[n].back_vert_f_code; g_stAddFrameStruct.sxf = g_stPictureStruct.pstMotionData[n].sxf; g_stAddFrameStruct.syf = g_stPictureStruct.pstMotionData[n].syf; g_stAddFrameStruct.sxb = g_stPictureStruct.pstMotionData[n].sxb; g_stAddFrameStruct.syb = g_stPictureStruct.pstMotionData[n].syb; } g_stPictureData.stHeader.nTempRef = f - f0; g_stPictureData.stCodingExtension.bFramePredDCT = g_stPictureData.stCodingExtension.bFramePredDCTTab[g_stPictureData.stHeader.nPictType-1]; g_stPictureData.stCodingExtension.bQScaleType = g_stPictureData.stCodingExtension.bQScaleTab[g_stPictureData.stHeader.nPictType-1]; g_stPictureData.stCodingExtension.bIntravlc = g_stPictureData.stCodingExtension.bIntravlcTab[g_stPictureData.stHeader.nPictType-1]; g_stPictureData.stCodingExtension.bAltScan = g_stPictureData.stCodingExtension.bAltScanTab[g_stPictureData.stHeader.nPictType-1]; g_nCurrentFrame++; if(g_pProcFunction!=NULL) { if(!g_pProcFunction(TOMPEG_PROCESS_ENCODE_M1V,g_nCurrentFrame*100/g_stCodingModelParams.nTotalNumberOfFramesToEncode)) { return -1; } } return f; } /*--------------------------------------------------------- ëµæ£é≡Æ╟ë┴é╖éΘ ---------------------------------------------------------*/ EXPORT TOMPGRET CALLBACK TOMPEG_AddFrame(const LPBITMAPINFO lpInfo,const unsigned char* pBytes) { static const char ipb[5] = {' ','I','P','B','D'}; TOMPGRET ret; bool ipflag; int j,k; if((ret = ConvRGBtoYUV(lpInfo,pBytes,g_stAddFrameStruct.neworg))!=TR_OK) { return ret; } if (g_stCodingModelParams.bFieldPicture) { if(g_stPictureData.stCodingExtension.bTopFirst) { g_stPictureData.stCodingExtension.nPictStruct = TOP_FIELD; } else { g_stPictureData.stCodingExtension.nPictStruct = BOTTOM_FIELD; } MotionEstimation(g_stPictureStruct.stOriginalFrames.pOldFrame[0], g_stPictureStruct.stOriginalFrames.pNewFrame[0], g_stPictureStruct.stReconstructedFrames.pOldFrame[0], g_stPictureStruct.stReconstructedFrames.pNewFrame[0], g_stAddFrameStruct.neworg[0],g_stAddFrameStruct.newref[0], g_stAddFrameStruct.sxf,g_stAddFrameStruct.syf,g_stAddFrameStruct.sxb,g_stAddFrameStruct.syb, g_stPictureStruct.pstMacroBlockInfo, 0,0); Predict(g_stPictureStruct.stReconstructedFrames.pOldFrame, g_stPictureStruct.stReconstructedFrames.pNewFrame, g_stPictureStruct.pPredictionFrameArray, 0, g_stPictureStruct.pstMacroBlockInfo); DCTTypeEstimation(g_stPictureStruct.pPredictionFrameArray[0], g_stAddFrameStruct.neworg[0], g_stPictureStruct.pstMacroBlockInfo); Transform(g_stPictureStruct.pPredictionFrameArray, g_stAddFrameStruct.neworg, g_stPictureStruct.pstMacroBlockInfo, g_stPictureStruct.pBlocksArray); if((ret = PutPicture(g_stAddFrameStruct.neworg[0]))!=TR_OK) { return ret; } for (k=0; k<g_stSequenceData.stHeader.nMacroBlocksHeight2*g_stSequenceData.stHeader.nMacroBlocksWidth; k++) { if (g_stPictureStruct.pstMacroBlockInfo[k].mb_type & MB_INTRA) for (j=0; j<g_stSequenceData.stHeader.nBlockCount; j++) IQuantIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureData.stCodingExtension.nDCPrecision, g_stPictureStruct.uIntraQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); else for (j=0;j<g_stSequenceData.stHeader.nBlockCount;j++) IQuantNonIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.uInterQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); } ITransform(g_stPictureStruct.pPredictionFrameArray, g_stAddFrameStruct.newref, g_stPictureStruct.pstMacroBlockInfo, g_stPictureStruct.pBlocksArray); if(g_stPictureData.stCodingExtension.bTopFirst) { g_stPictureData.stCodingExtension.nPictStruct = BOTTOM_FIELD; } else { g_stPictureData.stCodingExtension.nPictStruct = TOP_FIELD; } if(g_stPictureData.stHeader.nPictType==I_TYPE) { ipflag = true; } else { ipflag = false; } if (ipflag) { /* first field = I, second field = P */ g_stPictureData.stHeader.nPictType = P_TYPE; g_stPictureData.stCodingExtension.nForwHorFCode = g_stPictureStruct.pstMotionData[0].forw_hor_f_code; g_stPictureData.stCodingExtension.nForwVertFCode = g_stPictureStruct.pstMotionData[0].forw_vert_f_code; g_stPictureData.stCodingExtension.nBackHorFCode = g_stPictureData.stCodingExtension.nBackVertFCode = 15; g_stAddFrameStruct.sxf = g_stPictureStruct.pstMotionData[0].sxf; g_stAddFrameStruct.syf = g_stPictureStruct.pstMotionData[0].syf; } MotionEstimation(g_stPictureStruct.stOriginalFrames.pOldFrame[0], g_stPictureStruct.stOriginalFrames.pNewFrame[0], g_stPictureStruct.stReconstructedFrames.pOldFrame[0], g_stPictureStruct.stReconstructedFrames.pNewFrame[0], g_stAddFrameStruct.neworg[0],g_stAddFrameStruct.newref[0], g_stAddFrameStruct.sxf,g_stAddFrameStruct.syf,g_stAddFrameStruct.sxb,g_stAddFrameStruct.syb, g_stPictureStruct.pstMacroBlockInfo, 1,ipflag); Predict(g_stPictureStruct.stReconstructedFrames.pOldFrame, g_stPictureStruct.stReconstructedFrames.pNewFrame, g_stPictureStruct.pPredictionFrameArray, 1, g_stPictureStruct.pstMacroBlockInfo); DCTTypeEstimation(g_stPictureStruct.pPredictionFrameArray[0], g_stAddFrameStruct.neworg[0], g_stPictureStruct.pstMacroBlockInfo); Transform(g_stPictureStruct.pPredictionFrameArray, g_stAddFrameStruct.neworg, g_stPictureStruct.pstMacroBlockInfo, g_stPictureStruct.pBlocksArray); PutPicture(g_stAddFrameStruct.neworg[0]); for (k=0; k<g_stSequenceData.stHeader.nMacroBlocksHeight2*g_stSequenceData.stHeader.nMacroBlocksWidth; k++) { if (g_stPictureStruct.pstMacroBlockInfo[k].mb_type & MB_INTRA) for (j=0; j<g_stSequenceData.stHeader.nBlockCount; j++) IQuantIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureData.stCodingExtension.nDCPrecision, g_stPictureStruct.uIntraQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); else for (j=0;j<g_stSequenceData.stHeader.nBlockCount;j++) IQuantNonIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.uInterQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); } ITransform(g_stPictureStruct.pPredictionFrameArray, g_stAddFrameStruct.newref, g_stPictureStruct.pstMacroBlockInfo, g_stPictureStruct.pBlocksArray); } else { g_stPictureData.stCodingExtension.nPictStruct = FRAME_PICTURE; /* do motion_estimation * * uses source frames (...orgframe) for full pel search * and reconstructed frames (...refframe) for half pel search */ MotionEstimation(g_stPictureStruct.stOriginalFrames.pOldFrame[0], g_stPictureStruct.stOriginalFrames.pNewFrame[0], g_stPictureStruct.stReconstructedFrames.pOldFrame[0], g_stPictureStruct.stReconstructedFrames.pNewFrame[0], g_stAddFrameStruct.neworg[0],g_stAddFrameStruct.newref[0], g_stAddFrameStruct.sxf,g_stAddFrameStruct.syf,g_stAddFrameStruct.sxb,g_stAddFrameStruct.syb, g_stPictureStruct.pstMacroBlockInfo, 0,0); Predict(g_stPictureStruct.stReconstructedFrames.pOldFrame, g_stPictureStruct.stReconstructedFrames.pNewFrame, g_stPictureStruct.pPredictionFrameArray, 0, g_stPictureStruct.pstMacroBlockInfo); DCTTypeEstimation(g_stPictureStruct.pPredictionFrameArray[0], g_stAddFrameStruct.neworg[0], g_stPictureStruct.pstMacroBlockInfo); Transform(g_stPictureStruct.pPredictionFrameArray, g_stAddFrameStruct.neworg, g_stPictureStruct.pstMacroBlockInfo, g_stPictureStruct.pBlocksArray); PutPicture(g_stAddFrameStruct.neworg[0]); for (k=0; k<g_stSequenceData.stHeader.nMacroBlocksHeight*g_stSequenceData.stHeader.nMacroBlocksWidth; k++) { if (g_stPictureStruct.pstMacroBlockInfo[k].mb_type & MB_INTRA) for (j=0; j<g_stSequenceData.stHeader.nBlockCount; j++) IQuantIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureData.stCodingExtension.nDCPrecision, g_stPictureStruct.uIntraQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); else for (j=0;j<g_stSequenceData.stHeader.nBlockCount;j++) IQuantNonIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+j], g_stPictureStruct.uInterQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); } ITransform(g_stPictureStruct.pPredictionFrameArray, g_stAddFrameStruct.newref, g_stPictureStruct.pstMacroBlockInfo, g_stPictureStruct.pBlocksArray); } // sprintf(name,g_stSystemData.szTPlref,f+g_stCodingModelParams.nNumberOfFirstFrame); // g_stSequenceData.WriteFrame(name,newref); return TR_OK; } /*--------------------------------------------------------- ì∞ɼèJÄn ---------------------------------------------------------*/ EXPORT TOMPGRET CALLBACK TOMPEG_Start(const TOMPEG_VIDEO_FORMAT* pTompegFormat, const char* szTmpVideoPath, const char* szTmpAudioPath, bool(* CallBack)(TOMPEG_PROCESS_PARAM,int)) { const double fRateArray[8]= {24000.0/1001.0,24.0,25.0,30000.0/1001.0,30.0,50.0,60000.0/1001.0,60.0}; TOMPGRET ret; int i, size; int block_count_tab[3] = {6,8,12}; double tmp_rate = ((double)pTompegFormat->nRate)/((double)pTompegFormat->nScale); double min_err,err; //---------------- êΩÄ₧âtâ@âCâïé╠âpâXé≡ì∞ɼé╖éΘ ----------------// if(szTmpVideoPath != NULL) { strncpy(g_szTmpVideoPath,szTmpVideoPath,sizeof(g_szTmpVideoPath)); } else { MakeTmpFilePath(g_szTmpVideoPath,sizeof(g_szTmpVideoPath),"tmp.m1v"); } g_szTmpAudioPath[0] = '\0'; if(pTompegFormat->stAudioFormat.pAudioStream!=NULL) { if(szTmpAudioPath != NULL) { strncpy(g_szTmpAudioPath,szTmpAudioPath,sizeof(g_szTmpAudioPath)); } else { MakeTmpFilePath(g_szTmpAudioPath,sizeof(g_szTmpAudioPath),"tmp.mp2"); } } //---------------- ò╧Éöé╠É▌ÆΦ ----------------------------------// g_pProcFunction = CallBack; g_nWriteSequenceGrounp = pTompegFormat->nWriteSequenceGrounp; g_stSequenceData.stHeader.nVBVBufferSize = pTompegFormat->nVBVBufferSize; g_stSequenceData.stDisplayExtension.nDisplayHSize = pTompegFormat->nWidth; g_stSequenceData.stDisplayExtension.nDisplayVSize = pTompegFormat->nHeight; g_stCodingModelParams.nTotalNumberOfFramesToEncode = pTompegFormat->uLength; // âtâîü[âÇâîü[âgé≡îvÄZ min_err = fabs(fRateArray[0] - tmp_rate); g_stSequenceData.stHeader.nFrameRateCode = 0; for(i=1;i<sizeof(fRateArray)/sizeof(fRateArray[0]);i++) { err = fabs(fRateArray[i] - tmp_rate); if(err<min_err) { g_stSequenceData.stHeader.nFrameRateCode = i; } } g_stSequenceData.stHeader.fFrameRate = fRateArray[g_stSequenceData.stHeader.nFrameRateCode]; if(pTompegFormat->stAudioFormat.pAudioStream==NULL) { g_stSequenceData.stHeader.fBitRate = (double)(pTompegFormat->uSystemByteRateParam*8*1024); } else { g_stSequenceData.stHeader.fBitRate = (double)(pTompegFormat->uSystemByteRateParam*8*1024) - (double)(pTompegFormat->stAudioFormat.uAudioBitrateParam*1024) - (float)(4*8*1024); g_stSequenceData.stHeader.fBitRate = g_stSequenceData.stHeader.fBitRate * 0.9; // allow some room for the bitrate to overun... if(g_stSequenceData.stHeader.fBitRate <= 81920.0) { return TR_BITRATE_ERR; } } g_nSearchSize = pTompegFormat->nSearchSize; if(g_nSearchSize<0||g_nSearchSize>4) { return TR_SEARCH_SIZE_ERR; } if((pTompegFormat->uSystemByteRateParam < 10) ||(pTompegFormat->uSystemByteRateParam > 5000)) { return TR_ERR_SYSTEM_BYTE_RATE_PARAM; } g_stSequenceData.stHeader.nHFrameSize = ((g_stSequenceData.stDisplayExtension.nDisplayHSize + 15)>>4)<<4; // make it multiple of 16 g_stSequenceData.stHeader.nVFrameSize = ((g_stSequenceData.stDisplayExtension.nDisplayVSize + 3)>>2)<<2; g_nFastMotionCompensationLevel = pTompegFormat->nFastMotionCompensationLevel; if(g_nFastMotionCompensationLevel < 0 || g_nFastMotionCompensationLevel > 3) { return TR_FAST_MOTION_COMP_LEVEL_ERR; } if((ret=SetParam())!=TR_OK) { return ret; } //---------------- ù╩Äqë╗âeü[âuâïé╠Åëè·ë╗ ----------------------------// if (pTompegFormat->pQuantizerMatrix == NULL) { /* use default intra matrix */ const unsigned char default_intra_quantizer_matrix[64] = { 8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37, 19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40, 22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58, 26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83 }; g_stSequenceData.stHeader.bLoadIQuant = false; memcpy(g_stPictureStruct.uIntraQArray,default_intra_quantizer_matrix,sizeof(g_stPictureStruct.uIntraQArray)); } else { g_stSequenceData.stHeader.bLoadIQuant = true; memcpy(g_stPictureStruct.uIntraQArray,pTompegFormat->pQuantizerMatrix,sizeof(g_stPictureStruct.uIntraQArray)); } for (i=0; i<64; i++) { if(g_stPictureStruct.uIntraQArray[i]==0) { g_stPictureStruct.uIntraQArray[i] = 1; } g_stPictureStruct.uRecipIntraQArray[i] = (unsigned short)((16384.0 + (double) g_stPictureStruct.uIntraQArray[i]/2.0)/g_stPictureStruct.uIntraQArray[i]); } if (pTompegFormat->pNonIntraMatrix == NULL) { /* use default non-intra matrix */ g_stSequenceData.stHeader.bLoadNIQuant = false; for (i=0; i<64; i++) { g_stPictureStruct.uInterQArray[i] = 16; } } else { /* read customized non-intra matrix */ g_stSequenceData.stHeader.bLoadNIQuant = true; memcpy(g_stPictureStruct.uInterQArray,pTompegFormat->pNonIntraMatrix,sizeof(g_stPictureStruct.uInterQArray)); } for (i=0; i<64; i++) { if(g_stPictureStruct.uInterQArray[i]==0) { g_stPictureStruct.uInterQArray[i] = 1; } g_stPictureStruct.uRecipInterQArray[i] = (unsigned short)((16384.0 + (double) g_stPictureStruct.uInterQArray[i]/2.0)/g_stPictureStruct.uInterQArray[i]); } g_stSystemData.initbits(); /* round picture dimensions to nearest multiple of 16 or 32 */ g_stSequenceData.stHeader.nMacroBlocksWidth = (g_stSequenceData.stHeader.nHFrameSize+15)/16; if(g_stSequenceData.stExtension.bProgressSequence) { g_stSequenceData.stHeader.nMacroBlocksHeight = (g_stSequenceData.stHeader.nVFrameSize+15)/16; } else { g_stSequenceData.stHeader.nMacroBlocksHeight = 2*((g_stSequenceData.stHeader.nVFrameSize+31)/32); } if(g_stCodingModelParams.bFieldPicture) { g_stSequenceData.stHeader.nMacroBlocksHeight2 = g_stSequenceData.stHeader.nMacroBlocksHeight>>1; } else { g_stSequenceData.stHeader.nMacroBlocksHeight2 = g_stSequenceData.stHeader.nMacroBlocksHeight; } g_stSequenceData.stHeader.nWidth = 16*g_stSequenceData.stHeader.nMacroBlocksWidth; g_stSequenceData.stHeader.nHeight = 16*g_stSequenceData.stHeader.nMacroBlocksHeight; if(g_stSequenceData.stExtension.nChromaFormat==CHROMA444) { g_stSequenceData.stHeader.nChromWidth = g_stSequenceData.stHeader.nWidth; } else { g_stSequenceData.stHeader.nChromWidth = g_stSequenceData.stHeader.nWidth>>1; } if(g_stSequenceData.stExtension.nChromaFormat!=CHROMA420) { g_stSequenceData.stHeader.nChromHeight = g_stSequenceData.stHeader.nHeight; } else { g_stSequenceData.stHeader.nChromHeight = g_stSequenceData.stHeader.nHeight>>1; } if(g_stCodingModelParams.bFieldPicture) { g_stSequenceData.stHeader.nHeight2 = g_stSequenceData.stHeader.nHeight>>1; } else { g_stSequenceData.stHeader.nHeight2 = g_stSequenceData.stHeader.nHeight; } if(g_stCodingModelParams.bFieldPicture) { g_stSequenceData.stHeader.nWidth2 = g_stSequenceData.stHeader.nWidth<<1; } else { g_stSequenceData.stHeader.nWidth2 = g_stSequenceData.stHeader.nWidth; } if(g_stCodingModelParams.bFieldPicture) { g_stSequenceData.stHeader.nChromWidth2 = g_stSequenceData.stHeader.nChromWidth<<1; } else { g_stSequenceData.stHeader.nChromWidth2 = g_stSequenceData.stHeader.nChromWidth; } g_stSequenceData.stHeader.nBlockCount = block_count_tab[g_stSequenceData.stExtension.nChromaFormat-1]; /* clip table */ if(!g_stPictureStruct.MakeClippingTable()) { return TR_ERR_MAKE_CLIPPING_TABLE; } for (i=0; i<3; i++) { if(i == 0) { size = g_stSequenceData.stHeader.nWidth*g_stSequenceData.stHeader.nHeight; } else { size = g_stSequenceData.stHeader.nChromWidth*g_stSequenceData.stHeader.nChromHeight; } if(!g_stPictureStruct.AllocFrames(i,size)) { return TR_ERR_ALLOC_FRAMES; } } // now allocate space U and V buffers for readpic routine if (!g_stPictureStruct.AllocMacloBlockInfo(g_stSequenceData.stHeader.nMacroBlocksWidth*g_stSequenceData.stHeader.nMacroBlocksHeight2)) { return TR_ERR_ALLOC_BLOCK_INFO; } if(!g_stUVTempBuffers.Alloc(g_stSequenceData.stHeader.nWidth*g_stSequenceData.stHeader.nHeight, pTompegFormat->bUseImageNoiseReduction)) { return TR_ERR_ALLOC_TEMP_UV_BUFFER; } if (!g_stPictureStruct.AllocBlockArray(g_stSequenceData.stHeader.nMacroBlocksWidth*g_stSequenceData.stHeader.nMacroBlocksHeight2*g_stSequenceData.stHeader.nBlockCount)) { return TR_ERR_ALLOC_BLOCK_ARRAY; } if(pTompegFormat->stAudioFormat.pAudioStream!=NULL) { if((ret = TOMPEG_PCM2MP(g_szTmpAudioPath, &(pTompegFormat->stAudioFormat), g_pProcFunction))!=TR_OK) { return ret; } } /* open output file */ if (!g_stSystemData.OpenOutFile(g_szTmpVideoPath)) return TR_ERR_OPEN_FILE; return TR_OK; } /*--------------------------------------------------------- êΩÄ₧âtâ@âCâïé╠âpâXé╠ì∞ɼ ---------------------------------------------------------*/ static void MakeTmpFilePath(char* szPath,unsigned long uLength,char *szFname) { unsigned int i; GetCurrentDirectory(uLength,szPath); for(i=1;i<uLength;i++) { if(szPath[i] == '\0') { if(szPath[i-1] != '\\') { lstrcat(szPath,"\\"); } lstrcat(szPath,szFname); break; } } } /*--------------------------------------------------------- ò╧Éöé╠É▌ÆΦ ---------------------------------------------------------*/ inline TOMPGRET SetParam(void) { TOMPGRET ret; int i; int h,m,s,f; //char temp[256]="Encoded by AVI2MPG1 Version "; // several of the encoding parameters are implied by the source file // format, lets get these parameters from the .avi file. //strcpy(g_stSystemData.szTPlref, "-"); //strcpy(g_stSystemData.szStatName, "nul:"); // lets assume starts at frame 0 //g_stCodingModelParams.nNumberOfFirstFrame = 0; g_stCodingModelParams.bFieldPicture = false; // frame pictures only for mpeg1 // g_stSequenceData.stHeader.fBitRate = 1856000; // max SIF g_stSequenceData.stExtension.bLowDelay = false; g_stSequenceData.stExtension.bProgressSequence = true; g_stSequenceData.stExtension.nChromaFormat = 1; // 4:2:0 g_stPictureData.stCodingExtension.bConcealTab[0] = false; g_stPictureData.stCodingExtension.bConcealTab[1] = false; g_stPictureData.stCodingExtension.bConcealTab[2] = false; g_stPictureData.stCodingExtension.bTopFirst = false; g_stPictureData.stCodingExtension.bProgFrame = true; h = 0; m = 0; s = 0; f = 0; g_stCodingModelParams.nFramesNumberInGroupOfPicture = 15; g_stCodingModelParams.nDistanceBetweenIPFrames = 3; g_stSequenceData.stHeader.nAspectRatio = 8; g_stSequenceData.stExtension.nProfile = 4; g_stSequenceData.stDisplayExtension.nVideoFormat = 1; g_stSequenceData.stExtension.nLevel = 10; g_stSequenceData.stHeader.uConstrainedParams = 1; g_stSequenceData.stDisplayExtension.nColorPrimaries = 5; g_stSequenceData.stDisplayExtension.nTransferCharacteristics = 5; g_stSequenceData.stDisplayExtension.nMatrixCoefficients = 5; g_stPictureData.stCodingExtension.nDCPrecision = 0; g_stPictureData.stCodingExtension.bFramePredDCTTab[0] = true; g_stPictureData.stCodingExtension.bFramePredDCTTab[1] = true; g_stPictureData.stCodingExtension.bFramePredDCTTab[2] = true; g_stPictureData.stCodingExtension.bQScaleTab[0] = false; g_stPictureData.stCodingExtension.bQScaleTab[1] = false; g_stPictureData.stCodingExtension.bQScaleTab[2] = false; g_stPictureData.stCodingExtension.bIntravlcTab[0] = false; g_stPictureData.stCodingExtension.bIntravlcTab[1] = false; g_stPictureData.stCodingExtension.bIntravlcTab[2] = false; g_stPictureData.stCodingExtension.bAltScanTab[0] = false; g_stPictureData.stCodingExtension.bAltScanTab[1] = false; g_stPictureData.stCodingExtension.bAltScanTab[2] = false; g_stPictureData.stCodingExtension.bRepeatFirst = false; g_stCodingModelParams.nIntraSliceRefreshIntaeval = 0; g_stRateControl.r = 0; g_stRateControl.avg_act = 0; g_stRateControl.Xi = 0; g_stRateControl.Xp = 0; g_stRateControl.Xb = 0; g_stRateControl.d0i = 0; g_stRateControl.d0p = 0; g_stRateControl.d0b = 0; // Check for consistency here if (g_nWriteSequenceGrounp<0) { return TR_WRSEQH2GOP_ERR; } if (g_stCodingModelParams.nFramesNumberInGroupOfPicture<1) { return TR_FRAME_NUMBER_IN_GROOUP_ERR; } if (g_stCodingModelParams.nDistanceBetweenIPFrames<1) { return TR_DISTANCE_BETWEEN_IP_FRAMES_ERR; } if (g_stCodingModelParams.nFramesNumberInGroupOfPicture%g_stCodingModelParams.nDistanceBetweenIPFrames != 0) { return TR_FNIG_MULTIPLE_DBIPF_ERR; } if (!g_stPictureStruct.AllocMotionStruct(g_stCodingModelParams.nDistanceBetweenIPFrames)) { return TR_ERR_ALLOC_MOTION_STRUCT; } /* intra slice interval refresh period */ g_stCodingModelParams.nIntraSliceRefreshIntaeval = 0; g_stRateControl.r = 0; g_stRateControl.avg_act = 0; g_stRateControl.Xi = 0; g_stRateControl.Xp = 0; g_stRateControl.Xb = 0; g_stRateControl.d0i = 0; g_stRateControl.d0p = 0; g_stRateControl.d0b = 0; /* if (!g_stPictureStruct.AllocMotionStruct(g_stCodingModelParams.nDistanceBetweenIPFrames)) _error("malloc failed\n"); */ // It's not so easy to introduce default values, so switch for the search size here switch (g_nSearchSize) { case 0: g_stPictureStruct.pstMotionData[0].forw_hor_f_code = g_stPictureStruct.pstMotionData[0].forw_vert_f_code = 2; g_stPictureStruct.pstMotionData[0].sxf = g_stPictureStruct.pstMotionData[0].syf = 11; g_stPictureStruct.pstMotionData[1].forw_hor_f_code = g_stPictureStruct.pstMotionData[1].forw_vert_f_code = 1; g_stPictureStruct.pstMotionData[1].sxf = g_stPictureStruct.pstMotionData[1].syf = 3; g_stPictureStruct.pstMotionData[1].back_hor_f_code = g_stPictureStruct.pstMotionData[1].back_vert_f_code = 1; g_stPictureStruct.pstMotionData[1].sxb = g_stPictureStruct.pstMotionData[1].syb = 7; g_stPictureStruct.pstMotionData[2].forw_hor_f_code = g_stPictureStruct.pstMotionData[2].forw_vert_f_code = 1; g_stPictureStruct.pstMotionData[2].sxf = g_stPictureStruct.pstMotionData[2].syf = 7; g_stPictureStruct.pstMotionData[2].back_hor_f_code = g_stPictureStruct.pstMotionData[2].back_vert_f_code = 1; g_stPictureStruct.pstMotionData[2].sxb = g_stPictureStruct.pstMotionData[2].syb = 3; break; case 1: g_stPictureStruct.pstMotionData[0].forw_hor_f_code = g_stPictureStruct.pstMotionData[0].forw_vert_f_code = 2; g_stPictureStruct.pstMotionData[0].sxf = g_stPictureStruct.pstMotionData[0].syf = 15; g_stPictureStruct.pstMotionData[1].forw_hor_f_code = g_stPictureStruct.pstMotionData[1].forw_vert_f_code = 1; g_stPictureStruct.pstMotionData[1].sxf = g_stPictureStruct.pstMotionData[1].syf = 7; g_stPictureStruct.pstMotionData[1].back_hor_f_code = g_stPictureStruct.pstMotionData[1].back_vert_f_code = 2; g_stPictureStruct.pstMotionData[1].sxb = g_stPictureStruct.pstMotionData[1].syb = 15; g_stPictureStruct.pstMotionData[2].forw_hor_f_code = g_stPictureStruct.pstMotionData[2].forw_vert_f_code = 2; g_stPictureStruct.pstMotionData[2].sxf = g_stPictureStruct.pstMotionData[2].syf = 15; g_stPictureStruct.pstMotionData[2].back_hor_f_code = g_stPictureStruct.pstMotionData[2].back_vert_f_code = 1; g_stPictureStruct.pstMotionData[2].sxb = g_stPictureStruct.pstMotionData[2].syb = 7; break; case 2: g_stPictureStruct.pstMotionData[0].forw_hor_f_code = g_stPictureStruct.pstMotionData[0].forw_vert_f_code = 3; g_stPictureStruct.pstMotionData[0].sxf = g_stPictureStruct.pstMotionData[0].syf = 31; g_stPictureStruct.pstMotionData[1].forw_hor_f_code = g_stPictureStruct.pstMotionData[1].forw_vert_f_code = 2; g_stPictureStruct.pstMotionData[1].sxf = g_stPictureStruct.pstMotionData[1].syf = 15; g_stPictureStruct.pstMotionData[1].back_hor_f_code = g_stPictureStruct.pstMotionData[1].back_vert_f_code = 3; g_stPictureStruct.pstMotionData[1].sxb = g_stPictureStruct.pstMotionData[1].syb = 31; g_stPictureStruct.pstMotionData[2].forw_hor_f_code = g_stPictureStruct.pstMotionData[2].forw_vert_f_code = 3; g_stPictureStruct.pstMotionData[2].sxf = g_stPictureStruct.pstMotionData[2].syf = 31; g_stPictureStruct.pstMotionData[2].back_hor_f_code = g_stPictureStruct.pstMotionData[2].back_vert_f_code = 2; g_stPictureStruct.pstMotionData[2].sxb = g_stPictureStruct.pstMotionData[2].syb = 15; break; case 3: g_stPictureStruct.pstMotionData[0].forw_hor_f_code = g_stPictureStruct.pstMotionData[0].forw_vert_f_code = 4; g_stPictureStruct.pstMotionData[0].sxf = g_stPictureStruct.pstMotionData[0].syf = 63; g_stPictureStruct.pstMotionData[1].forw_hor_f_code = g_stPictureStruct.pstMotionData[1].forw_vert_f_code = 3; g_stPictureStruct.pstMotionData[1].sxf = g_stPictureStruct.pstMotionData[1].syf = 31; g_stPictureStruct.pstMotionData[1].back_hor_f_code = g_stPictureStruct.pstMotionData[1].back_vert_f_code = 4; g_stPictureStruct.pstMotionData[1].sxb = g_stPictureStruct.pstMotionData[1].syb = 63; g_stPictureStruct.pstMotionData[2].forw_hor_f_code = g_stPictureStruct.pstMotionData[2].forw_vert_f_code = 4; g_stPictureStruct.pstMotionData[2].sxf = g_stPictureStruct.pstMotionData[2].syf = 63; g_stPictureStruct.pstMotionData[2].back_hor_f_code = g_stPictureStruct.pstMotionData[2].back_vert_f_code = 3; g_stPictureStruct.pstMotionData[2].sxb = g_stPictureStruct.pstMotionData[2].syb = 31; break; case 4: g_stPictureStruct.pstMotionData[0].forw_hor_f_code = g_stPictureStruct.pstMotionData[0].forw_vert_f_code = 4; g_stPictureStruct.pstMotionData[0].sxf = g_stPictureStruct.pstMotionData[0].syf = 63; g_stPictureStruct.pstMotionData[1].forw_hor_f_code = g_stPictureStruct.pstMotionData[1].forw_vert_f_code = 4; g_stPictureStruct.pstMotionData[1].sxf = g_stPictureStruct.pstMotionData[1].syf = 63; g_stPictureStruct.pstMotionData[1].back_hor_f_code = g_stPictureStruct.pstMotionData[1].back_vert_f_code = 4; g_stPictureStruct.pstMotionData[1].sxb = g_stPictureStruct.pstMotionData[1].syb = 63; g_stPictureStruct.pstMotionData[2].forw_hor_f_code = g_stPictureStruct.pstMotionData[2].forw_vert_f_code = 4; g_stPictureStruct.pstMotionData[2].sxf = g_stPictureStruct.pstMotionData[2].syf = 63; g_stPictureStruct.pstMotionData[2].back_hor_f_code = g_stPictureStruct.pstMotionData[2].back_vert_f_code = 4; g_stPictureStruct.pstMotionData[2].sxb = g_stPictureStruct.pstMotionData[2].syb = 63; break; } /* make sure MPEG specific parameters are valid */ if((ret = RangeCheck())!=TR_OK) { return ret; } /* timecode -> frame number */ g_stCodingModelParams.nTimeCodeOfFirstFrame = h; g_stCodingModelParams.nTimeCodeOfFirstFrame = 60*g_stCodingModelParams.nTimeCodeOfFirstFrame + m; g_stCodingModelParams.nTimeCodeOfFirstFrame = 60*g_stCodingModelParams.nTimeCodeOfFirstFrame + s; g_stCodingModelParams.nTimeCodeOfFirstFrame = (int)(g_stSequenceData.stHeader.fFrameRate+0.5)*g_stCodingModelParams.nTimeCodeOfFirstFrame + f; /* MPEG-1 */ if (g_stSequenceData.stHeader.uConstrainedParams) { if (g_stSequenceData.stHeader.nHFrameSize>768 || g_stSequenceData.stHeader.nVFrameSize>576 || ((g_stSequenceData.stHeader.nHFrameSize+15)/16)*((g_stSequenceData.stHeader.nVFrameSize+15)/16)>396 || ((g_stSequenceData.stHeader.nHFrameSize+15)/16)*((g_stSequenceData.stHeader.nVFrameSize+15)/16)*g_stSequenceData.stHeader.fFrameRate>396*25.0 || g_stSequenceData.stHeader.fFrameRate>30.0) { g_stSequenceData.stHeader.uConstrainedParams = 0; } } if (g_stSequenceData.stHeader.uConstrainedParams) { for (i=0; i<g_stCodingModelParams.nDistanceBetweenIPFrames; i++) { if (g_stPictureStruct.pstMotionData[i].forw_hor_f_code>4) { g_stSequenceData.stHeader.uConstrainedParams = 0; break; } if (g_stPictureStruct.pstMotionData[i].forw_vert_f_code>4) { g_stSequenceData.stHeader.uConstrainedParams = 0; break; } if (i!=0) { if (g_stPictureStruct.pstMotionData[i].back_hor_f_code>4) { g_stSequenceData.stHeader.uConstrainedParams = 0; break; } if (g_stPictureStruct.pstMotionData[i].back_vert_f_code>4) { g_stSequenceData.stHeader.uConstrainedParams = 0; break; } } } } /* relational checks */ if (!g_stSequenceData.stExtension.bProgressSequence) { g_stSequenceData.stExtension.bProgressSequence = true; } if (g_stSequenceData.stExtension.nChromaFormat!=CHROMA420) { g_stSequenceData.stExtension.nChromaFormat = CHROMA420; } if (g_stPictureData.stCodingExtension.nDCPrecision!=0) { g_stPictureData.stCodingExtension.nDCPrecision = 0; } for (i=0; i<3; i++) if(g_stPictureData.stCodingExtension.bQScaleTab[i]) { g_stPictureData.stCodingExtension.bQScaleTab[i] = 0; } for (i=0; i<3; i++) if (g_stPictureData.stCodingExtension.bIntravlcTab[i]) { g_stPictureData.stCodingExtension.bIntravlcTab[i] = 0; } for (i=0; i<3; i++) if (g_stPictureData.stCodingExtension.bAltScanTab[i]) { g_stPictureData.stCodingExtension.bAltScanTab[i] = 0; } if (g_stSequenceData.stExtension.bProgressSequence && !g_stPictureData.stCodingExtension.bProgFrame) { g_stPictureData.stCodingExtension.bProgFrame = true; } if (g_stPictureData.stCodingExtension.bProgFrame && g_stCodingModelParams.bFieldPicture) { g_stCodingModelParams.bFieldPicture = false; } if (!g_stPictureData.stCodingExtension.bProgFrame && g_stPictureData.stCodingExtension.bRepeatFirst) { g_stPictureData.stCodingExtension.bRepeatFirst = 0; } if (g_stPictureData.stCodingExtension.bProgFrame) { for (i=0; i<3; i++) if (!g_stPictureData.stCodingExtension.bFramePredDCTTab[i]) { g_stPictureData.stCodingExtension.bFramePredDCTTab[i] = 1; } } if (g_stSequenceData.stExtension.bProgressSequence && !g_stPictureData.stCodingExtension.bRepeatFirst && g_stPictureData.stCodingExtension.bTopFirst) { g_stPictureData.stCodingExtension.bTopFirst = false; } /* search windows */ for (i=0; i<g_stCodingModelParams.nDistanceBetweenIPFrames; i++) { if (g_stPictureStruct.pstMotionData[i].sxf > (4<<g_stPictureStruct.pstMotionData[i].forw_hor_f_code)-1) { g_stPictureStruct.pstMotionData[i].sxf = (4<<g_stPictureStruct.pstMotionData[i].forw_hor_f_code)-1; } if (g_stPictureStruct.pstMotionData[i].syf > (4<<g_stPictureStruct.pstMotionData[i].forw_vert_f_code)-1) { g_stPictureStruct.pstMotionData[i].syf = (4<<g_stPictureStruct.pstMotionData[i].forw_vert_f_code)-1; } if (i!=0) { if (g_stPictureStruct.pstMotionData[i].sxb > (4<<g_stPictureStruct.pstMotionData[i].back_hor_f_code)-1) { g_stPictureStruct.pstMotionData[i].sxb = (4<<g_stPictureStruct.pstMotionData[i].back_hor_f_code)-1; } if (g_stPictureStruct.pstMotionData[i].syb > (4<<g_stPictureStruct.pstMotionData[i].back_vert_f_code)-1) { g_stPictureStruct.pstMotionData[i].syb = (4<<g_stPictureStruct.pstMotionData[i].back_vert_f_code)-1; } } } return TR_OK; } /*--------------------------------------------------------- ò╧Éöé╠ö═ê═é╠â`âFâbâN ---------------------------------------------------------*/ inline TOMPGRET RangeCheck(void) { int i; /* range and value checks */ if (g_stSequenceData.stHeader.nHFrameSize<1 || g_stSequenceData.stHeader.nHFrameSize>16383) { return TR_HFRAME_SIZE_ERR; } if (g_stSequenceData.stHeader.nHFrameSize>4095) { return TR_HFRAME_SIZE_ERR; } if ((g_stSequenceData.stHeader.nHFrameSize&4095)==0) { return TR_HFRAME_SIZE_ERR; } if (g_stSequenceData.stExtension.nChromaFormat!=CHROMA444 && g_stSequenceData.stHeader.nHFrameSize%2 != 0) { return TR_CHROMA_FORMAT_ERR; } if (g_stSequenceData.stHeader.nVFrameSize<1 || g_stSequenceData.stHeader.nVFrameSize>16383) { return TR_VFRAME_SIZE_ERR; } if (g_stSequenceData.stHeader.nVFrameSize>4095) { return TR_VFRAME_SIZE_ERR; } if ((g_stSequenceData.stHeader.nVFrameSize&4095)==0) { return TR_VFRAME_SIZE_ERR; } if (g_stSequenceData.stExtension.nChromaFormat==CHROMA420 && g_stSequenceData.stHeader.nVFrameSize%2 != 0) { return TR_CHROMA_FORMAT_ERR; } if(g_stCodingModelParams.bFieldPicture) { if (g_stSequenceData.stHeader.nVFrameSize%2 != 0) { return TR_VFRAME_SIZE_ERR; } if (g_stSequenceData.stExtension.nChromaFormat==CHROMA420 && g_stSequenceData.stHeader.nVFrameSize%4 != 0) { return TR_CHROMA_FORMAT_ERR; } } if (g_stSequenceData.stHeader.nAspectRatio<1 || g_stSequenceData.stHeader.nAspectRatio>14) { return TR_ASPECT_RATIO_ERR; } if (g_stSequenceData.stHeader.nFrameRateCode<0 || g_stSequenceData.stHeader.nFrameRateCode>7) { return TR_FRAME_RATE_CODE_ERR; } if (g_stSequenceData.stHeader.fBitRate<=0.0) { return TR_BITRATE_ERR; } if (g_stSequenceData.stHeader.fBitRate > ((double)((1<<30)-1))*400.0) { return TR_BITRATE_ERR; } if (g_stSequenceData.stHeader.fBitRate > ((double)((1<<18)-1))*400.0) { return TR_BITRATE_ERR; } if (g_stSequenceData.stHeader.nVBVBufferSize<1 || g_stSequenceData.stHeader.nVBVBufferSize>0x3ffff) { return TR_VBV_BUFFER_SIZE_ERR; } if (g_stSequenceData.stHeader.nVBVBufferSize>=1024) { return TR_VBV_BUFFER_SIZE_ERR; } if (g_stSequenceData.stExtension.nChromaFormat<CHROMA420 || g_stSequenceData.stExtension.nChromaFormat>CHROMA444) { return TR_CHROMA_FORMAT_ERR; } if (g_stSequenceData.stDisplayExtension.nVideoFormat<0 || g_stSequenceData.stDisplayExtension.nVideoFormat>4) { return TR_VIDEO_FORMAT_ERR; } if (g_stSequenceData.stDisplayExtension.nColorPrimaries<1 || g_stSequenceData.stDisplayExtension.nColorPrimaries>7 || g_stSequenceData.stDisplayExtension.nColorPrimaries==3) { return TR_COLOR_PRIMARIES_ERR; } if (g_stSequenceData.stDisplayExtension.nTransferCharacteristics<1 || g_stSequenceData.stDisplayExtension.nTransferCharacteristics>7 || g_stSequenceData.stDisplayExtension.nTransferCharacteristics==3) { return TR_TRANSFER_CHARACTERISTICS_ERR; } if (g_stSequenceData.stDisplayExtension.nMatrixCoefficients<1 || g_stSequenceData.stDisplayExtension.nMatrixCoefficients>7 || g_stSequenceData.stDisplayExtension.nMatrixCoefficients==3) { return TR_MATRIX_COEFFICIENTS_ERR; } if (g_stSequenceData.stDisplayExtension.nDisplayHSize<0 || g_stSequenceData.stDisplayExtension.nDisplayHSize>16383) { return TR_DISPLAY_HSIZE_ERR; } if (g_stSequenceData.stDisplayExtension.nDisplayVSize<0 || g_stSequenceData.stDisplayExtension.nDisplayVSize>16383) { return TR_DISPLAY_VSIZE_ERR; } if (g_stPictureData.stCodingExtension.nDCPrecision<0 || g_stPictureData.stCodingExtension.nDCPrecision>3) { return TR_INTRA_DC_PRECISION_ERR; } for (i=0; i<g_stCodingModelParams.nDistanceBetweenIPFrames; i++) { if (g_stPictureStruct.pstMotionData[i].forw_hor_f_code<1 || g_stPictureStruct.pstMotionData[i].forw_hor_f_code>9) { return TR_FHCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].forw_vert_f_code<1 || g_stPictureStruct.pstMotionData[i].forw_vert_f_code>9) { return TR_FVCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].forw_hor_f_code>7) { return TR_FHCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].forw_vert_f_code>7) { return TR_FVCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].sxf<=0) { return TR_SXF_ERR; } if (g_stPictureStruct.pstMotionData[i].syf<=0) { return TR_SYF_ERR; } if (i!=0) { if (g_stPictureStruct.pstMotionData[i].back_hor_f_code<1 || g_stPictureStruct.pstMotionData[i].back_hor_f_code>9) { return TR_BHCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].back_vert_f_code<1 || g_stPictureStruct.pstMotionData[i].back_vert_f_code>9) { return TR_BVCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].back_hor_f_code>7) { return TR_BHCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].back_vert_f_code>7) { return TR_BVCODE_ERR; } if (g_stPictureStruct.pstMotionData[i].sxb<=0) { return TR_SXB_ERR; } if (g_stPictureStruct.pstMotionData[i].syb<=0) { return TR_SYB_ERR; } } } return TR_OK; } /*========================================================= Rate Control =========================================================*/ /*--------------------------------------------------------- âVü[âPâôâXé╠Åëè·ë╗ ---------------------------------------------------------*/ inline void RcInitSeq(void) { /* reaction parameter (constant) */ if (g_stRateControl.r == 0) { g_stRateControl.r = (int)(2.0*g_stSequenceData.stHeader.fBitRate/g_stSequenceData.stHeader.fFrameRate + 0.5); } /* average activity */ if (g_stRateControl.avg_act == 0.0) { g_stRateControl.avg_act = 400.0; } /* remaining # of bits in GOP */ g_stRateControl.R = 0; /* global complexity measure */ if (g_stRateControl.Xi==0) { g_stRateControl.Xi = (int)(160.0*g_stSequenceData.stHeader.fBitRate/115.0 + 0.5); } if (g_stRateControl.Xp==0) { g_stRateControl.Xp = (int)( 60.0*g_stSequenceData.stHeader.fBitRate/115.0 + 0.5); } if (g_stRateControl.Xb==0) { g_stRateControl.Xb = (int)( 42.0*g_stSequenceData.stHeader.fBitRate/115.0 + 0.5); } /* virtual buffer fullness */ if (g_stRateControl.d0i==0) { g_stRateControl.d0i = (int)(10.0*g_stRateControl.r/31.0 + 0.5); } if (g_stRateControl.d0p==0) { g_stRateControl.d0p = (int)(10.0*g_stRateControl.r/31.0 + 0.5); } if (g_stRateControl.d0b==0) { g_stRateControl.d0b = (int)(1.4*10.0*g_stRateControl.r/31.0 + 0.5); } } inline void RcInitGOP(const int np,const int nb) { g_stRateControl.R += (int) (((double)(1 + np + nb)) * g_stSequenceData.stHeader.fBitRate / g_stSequenceData.stHeader.fFrameRate + 0.5); if(g_stCodingModelParams.bFieldPicture) { g_stRateControl.Np = 2*np+1; } else { g_stRateControl.Np = np; } if(g_stCodingModelParams.bFieldPicture) { g_stRateControl.Nb = 2*nb; } else { g_stRateControl.Nb = nb; } } inline void RcInitPic(unsigned char* frame) { const int width = g_stSequenceData.stHeader.nWidth; const int width2 = g_stSequenceData.stHeader.nWidth2; double Tmin; int i,j,k; unsigned char *p; double actj,var; switch (g_stPictureData.stHeader.nPictType) { case I_TYPE: g_stRateControl.T = (int)(g_stRateControl.R/(1.0+g_stRateControl.Np*g_stRateControl.Xp/(g_stRateControl.Xi*1.0)+g_stRateControl.Nb*g_stRateControl.Xb/(g_stRateControl.Xi*1.4)) + 0.5); g_stRateControl.d = g_stRateControl.d0i; break; case P_TYPE: g_stRateControl.T = (int)(g_stRateControl.R/(g_stRateControl.Np+g_stRateControl.Nb*1.0*g_stRateControl.Xb/(1.4*g_stRateControl.Xp)) + 0.5); g_stRateControl.d = g_stRateControl.d0p; break; case B_TYPE: g_stRateControl.T = (int)(g_stRateControl.R/(g_stRateControl.Nb+g_stRateControl.Np*1.4*g_stRateControl.Xp/(1.0*g_stRateControl.Xb)) + 0.5); g_stRateControl.d = g_stRateControl.d0b; break; } Tmin = (int)(g_stSequenceData.stHeader.fBitRate/(8.0*g_stSequenceData.stHeader.fFrameRate) + 0.5); if (g_stRateControl.T<Tmin) g_stRateControl.T = (int)Tmin; g_stRateControl.S = g_stSystemData.bitcount(); g_stRateControl.Q = 0; k = 0; for (j=0; j<g_stSequenceData.stHeader.nHeight2; j+=16) { for (i=0; i<width; i+=16) { if(g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) { p = frame + width + i + width2*j; } else { p = frame + i + width2*j; } /* take minimum spatial activity measure of luminance blocks */ actj = VarSBlock(p,width2); var = VarSBlock(p+8,width2); if (var<actj) { actj = var; } var = VarSBlock(p+8*width2,width2); if (var<actj) { actj = var; } var = VarSBlock(p+8*width2+8,width2); if (var<actj) { actj = var; } if (!g_stCodingModelParams.bFieldPicture && !g_stSequenceData.stExtension.bProgressSequence) { /* field */ var = VarSBlock(p,width<<1); if (var<actj) actj = var; var = VarSBlock(p+8,width<<1); if (var<actj) actj = var; var = VarSBlock(p+width,width<<1); if (var<actj) actj = var; var = VarSBlock(p+width+8,width<<1); if (var<actj) actj = var; } actj+= 1.0; g_stPictureStruct.pstMacroBlockInfo[k++].act = actj; } } g_stRateControl.actsum = 0.0; } inline void RcUpdatePict(void) { const int mb_wh2 = g_stSequenceData.stHeader.nMacroBlocksWidth*g_stSequenceData.stHeader.nMacroBlocksHeight2; double X; g_stRateControl.S = g_stSystemData.bitcount() - g_stRateControl.S; /* total # of bits in picture */ g_stRateControl.R-= g_stRateControl.S; /* remaining # of bits in GOP */ X = (int)(g_stRateControl.S*((0.5*(double)g_stRateControl.Q)/(mb_wh2)) + 0.5); g_stRateControl.d+= g_stRateControl.S - g_stRateControl.T; g_stRateControl.avg_act = g_stRateControl.actsum/(mb_wh2); switch (g_stPictureData.stHeader.nPictType) { case I_TYPE: g_stRateControl.Xi = (int)X; g_stRateControl.d0i = g_stRateControl.d; break; case P_TYPE: g_stRateControl.Xp = (int)X; g_stRateControl.d0p = g_stRateControl.d; g_stRateControl.Np--; break; case B_TYPE: g_stRateControl.Xb = (int)X; g_stRateControl.d0b = g_stRateControl.d; g_stRateControl.Nb--; break; } } /*--------------------------------------------------------- compute initial quantization stepsize (at the beginning of picture) ---------------------------------------------------------*/ inline int RcStartMb(void) { int mquant; if (g_stPictureData.stCodingExtension.bQScaleType) { mquant = (int)(2.0*g_stRateControl.d*31.0/g_stRateControl.r + 0.5); /* clip mquant to legal (linear) range */ if (mquant<1) mquant = 1; if (mquant>112) mquant = 112; /* map to legal quantization level */ mquant = g_NonLinerQuantizationArray[g_MapNonLinearQuantizationArray[mquant]]; } else { mquant = (int)(g_stRateControl.d*31.0/g_stRateControl.r + 0.5); mquant <<= 1; /* clip mquant to legal (linear) range */ if (mquant<2) mquant = 2; if (mquant>62) mquant = 62; g_stRateControl.prev_mquant = mquant; } return mquant; } /*--------------------------------------------------------- Step 2: measure virtual buffer - estimated buffer discrepancy ---------------------------------------------------------*/ inline int RcCalcMQuant(const int j) { int mquant; double dj, Qj, actj, N_actj; /* measure virtual buffer discrepancy from uniform distribution model */ dj = g_stRateControl.d + (g_stSystemData.bitcount()-g_stRateControl.S) - j*(g_stRateControl.T/(g_stSequenceData.stHeader.nMacroBlocksWidth*g_stSequenceData.stHeader.nMacroBlocksHeight2)); /* scale against dynamic range of mquant and the bits/picture count */ Qj = dj*31.0/g_stRateControl.r; /*Qj = dj*(q_scale_type ? 56.0 : 31.0)/r; */ actj = g_stPictureStruct.pstMacroBlockInfo[j].act; g_stRateControl.actsum+= actj; /* compute normalized activity */ N_actj = (2.0*actj+g_stRateControl.avg_act)/(actj+2.0*g_stRateControl.avg_act); if (g_stPictureData.stCodingExtension.bQScaleType) { /* modulate mquant with combined buffer and local activity measures */ mquant = (int)(2.0*Qj*N_actj + 0.5); /* clip mquant to legal (linear) range */ if (mquant<1) mquant = 1; if (mquant>112) mquant = 112; /* map to legal quantization level */ mquant = g_NonLinerQuantizationArray[g_MapNonLinearQuantizationArray[mquant]]; } else { /* modulate mquant with combined buffer and local activity measures */ mquant = (int)(Qj*N_actj + 0.5); mquant <<= 1; /* clip mquant to legal (linear) range */ if (mquant<2) mquant = 2; if (mquant>62) mquant = 62; /* ignore small changes in mquant */ if (mquant>=8 && (mquant-g_stRateControl.prev_mquant)>=-4 && (mquant-g_stRateControl.prev_mquant)<=4) mquant = g_stRateControl.prev_mquant; g_stRateControl.prev_mquant = mquant; } g_stRateControl.Q+= mquant; /* for calculation of average mquant */ return mquant; } /*--------------------------------------------------------- compute variance of 8x8 block ---------------------------------------------------------*/ double VarSBlock(unsigned char* p,const int lx) { int i, j; unsigned int v, s, s2; s = s2 = 0; for (j=0; j<8; j++) { for (i=0; i<8; i++) { v = *p++; s+= v; s2+= v*v; } p+= lx - 8; } return s2/64.0 - (s/64.0)*(s/64.0); } /*========================================================= VBV é╠îvÄZ generates warnings if underflow or overflow occurs =========================================================*/ /*--------------------------------------------------------- has to be called directly after writing picture_data() needed for accurate VBV buffer overflow calculation assumes there is no byte stuffing prior to the next start code ---------------------------------------------------------*/ void VBVEndOfPicture(void) { static int bitcnt_EOP; bitcnt_EOP = g_stSystemData.bitcount(); bitcnt_EOP = (bitcnt_EOP + 7) & ~7; /* account for bit stuffing */ } /*--------------------------------------------------------- has to be called directly after writing the picture start code, the reference point for vbv_delay ---------------------------------------------------------*/ inline int CalcVBVDelay(void) { const double frame_rate = g_stSequenceData.stHeader.fFrameRate; const bool prog_seq = g_stSequenceData.stExtension.bProgressSequence; double picture_delay; int nVBVDelay; static double next_ip_delay; /* due to frame reordering delay */ static double decoding_time = 0.0; /* number of 1/90000 s ticks until next picture is to be decoded */ if (g_stPictureData.stHeader.nPictType == B_TYPE) { if (prog_seq) { if (!g_stPictureData.stCodingExtension.bRepeatFirst) picture_delay = 90000.0/frame_rate; /* 1 frame */ else { if (!g_stPictureData.stCodingExtension.bTopFirst) picture_delay = 90000.0*2.0/frame_rate; /* 2 frames */ else picture_delay = 90000.0*3.0/frame_rate; /* 3 frames */ } } else { /* interlaced */ if (g_stCodingModelParams.bFieldPicture) picture_delay = 90000.0/(2.0*frame_rate); /* 1 field */ else { if (!g_stPictureData.stCodingExtension.bRepeatFirst) picture_delay = 90000.0*2.0/(2.0*frame_rate); /* 2 flds */ else picture_delay = 90000.0*3.0/(2.0*frame_rate); /* 3 flds */ } } } else { /* I or P picture */ if (g_stCodingModelParams.bFieldPicture) { if(g_stPictureData.stCodingExtension.bTopFirst==(g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD)) { /* first field */ picture_delay = 90000.0/(2.0*frame_rate); } else { /* second field */ /* take frame reordering delay into account */ picture_delay = next_ip_delay - 90000.0/(2.0*frame_rate); } } else { /* frame picture */ /* take frame reordering delay into account*/ picture_delay = next_ip_delay; } if (!g_stCodingModelParams.bFieldPicture || g_stPictureData.stCodingExtension.bTopFirst!=(g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD)) { /* frame picture or second field */ if (prog_seq) { if (!g_stPictureData.stCodingExtension.bRepeatFirst) next_ip_delay = 90000.0/frame_rate; else { if (!g_stPictureData.stCodingExtension.bTopFirst) next_ip_delay = 90000.0*2.0/frame_rate; else next_ip_delay = 90000.0*3.0/frame_rate; } } else { if (g_stCodingModelParams.bFieldPicture) next_ip_delay = 90000.0/(2.0*frame_rate); else { if (!g_stPictureData.stCodingExtension.bRepeatFirst) next_ip_delay = 90000.0*2.0/(2.0*frame_rate); else next_ip_delay = 90000.0*3.0/(2.0*frame_rate); } } } } if (decoding_time==0.0) { /* first call of calc_vbv_delay */ /* we start with a 7/8 filled VBV buffer (12.5% back-off) */ picture_delay = ((g_stSequenceData.stHeader.nVBVBufferSize*16384*7)/8)*90000.0/g_stSequenceData.stHeader.fBitRate; if (g_stCodingModelParams.bFieldPicture) next_ip_delay = (int)(90000.0/frame_rate+0.5); } /* VBV checks */ /* when to decode current frame */ decoding_time += picture_delay; /* warning: bitcount() may overflow (e.g. after 9 min. at 8 Mbit/s */ nVBVDelay = (int)(decoding_time - g_stSystemData.bitcount()*90000.0/g_stSequenceData.stHeader.fBitRate); if (nVBVDelay<0) { nVBVDelay = 0; } if (nVBVDelay>65535) { nVBVDelay = 65535; } return nVBVDelay; } /*========================================================= âwâbâ_é╠Åæé½ì₧é▌ =========================================================*/ /*--------------------------------------------------------- âwâbâ_é╠Åæé½ì₧é▌ ---------------------------------------------------------*/ inline void PutGroupHeader(const int frame,const unsigned char closed_gop) { g_stSystemData.alignbits(); g_stSystemData.putbits(GOP_START_CODE,32); /* group_start_code */ g_stSystemData.putbits(FrameToTimeCode(g_stCodingModelParams.nTimeCodeOfFirstFrame+frame),25); /* time_code */ g_stSystemData.putbits(closed_gop,1); /* closed_gop */ g_stSystemData.putbits(0,1); /* broken_link */ } /*--------------------------------------------------------- âtâîü[âÇö╘ìåé⌐éτâ^âCâÇâRü[âhé╓ò╧è╖ ---------------------------------------------------------*/ inline int FrameToTimeCode(int frame) { int fps, pict, sec, minute, hour, tc; fps = (int)(g_stSequenceData.stHeader.fFrameRate+0.5); pict = frame%fps; frame = (frame-pict)/fps; sec = frame%60; frame = (frame-sec)/60; minute = frame%60; frame = (frame-minute)/60; hour = frame%24; tc = (hour<<19) | (minute<<13) | (1<<12) | (sec<<6) | pict; return tc; } /*--------------------------------------------------------- output a zero terminated string as user data string must not emulate start codes ---------------------------------------------------------*/ inline void PutUserData(char* userdata) { g_stSystemData.alignbits(); g_stSystemData.putbits(USER_START_CODE,32); /* user_data_start_code */ while (*userdata) g_stSystemData.putbits(*userdata++,8); } /*--------------------------------------------------------- generate picture header ---------------------------------------------------------*/ inline void PutPictureHeader(void) { g_stSystemData.alignbits(); g_stSystemData.putbits(PICTURE_START_CODE,32); /* picture_start_code */ g_stSystemData.putbits(g_stPictureData.stHeader.nTempRef,10); /* temporal_reference */ g_stSystemData.putbits(g_stPictureData.stHeader.nPictType,3); /* picture_coding_type */ g_stSystemData.putbits(CalcVBVDelay(),16); /* vbv_delay */ if (g_stPictureData.stHeader.nPictType==P_TYPE || g_stPictureData.stHeader.nPictType==B_TYPE) { g_stSystemData.putbits(0,1); /* full_pel_forward_vector */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nForwHorFCode,3); } if (g_stPictureData.stHeader.nPictType==B_TYPE) { g_stSystemData.putbits(0,1); /* full_pel_backward_vector */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nBackHorFCode,3); } g_stSystemData.putbits(0,1); /* extra_bit_picture */ } /*--------------------------------------------------------- generate picture coding extension (6.2.3.1, 6.3.11) composite display information (v_axis etc.) not implemented ---------------------------------------------------------*/ inline void PutPictureCodingExtension(void) { g_stSystemData.alignbits(); g_stSystemData.putbits(EXT_START_CODE,32); /* extension_start_code */ g_stSystemData.putbits(CODING_ID,4); /* extension_start_code_identifier */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nForwHorFCode,4); /* forward_horizontal_f_code */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nForwVertFCode,4); /* forward_vertical_f_code */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nBackHorFCode,4); /* backward_horizontal_f_code */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nBackVertFCode,4); /* backward_vertical_f_code */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nDCPrecision,2); /* intra_dc_precision */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.nPictStruct,2); /* picture_structure */ if(g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) g_stSystemData.putbits(g_stPictureData.stCodingExtension.bTopFirst?1:0,1); /* top_field_first */ else g_stSystemData.putbits(0,1); /* top_field_first */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bFramePredDCT?1:0,1); /* frame_pred_frame_dct */ g_stSystemData.putbits(0,1); /* concealment_motion_vectors -- currently not implemented */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bQScaleType?1:0,1); /* q_scale_type */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bIntravlc?1:0,1); /* intra_vlc_format */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bAltScan?1:0,1); /* g_AlternateScanArray */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bRepeatFirst?1:0,1); /* repeat_first_field */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bProgFrame?1:0,1); /* chroma_420_type */ g_stSystemData.putbits(g_stPictureData.stCodingExtension.bProgFrame?1:0,1); /* progressive_frame */ g_stSystemData.putbits(0,1); /* composite_display_flag */ } /*--------------------------------------------------------- BITMAPINFOHEADER é╞ ârâbâgâfü[â^é≡Ä≤é»Äµé┴é─üCÄgùpë┬ö\é╚î`é╔ò╧ìXé╖éΘ ---------------------------------------------------------*/ inline TOMPGRET ConvRGBtoYUV(const LPBITMAPINFO lpInfo,const unsigned char* pBytes,unsigned char* frame[]) { const int width = g_stSequenceData.stHeader.nWidth; const int height = g_stSequenceData.stHeader.nHeight; const int vertical_size = g_stSequenceData.stHeader.nVFrameSize; const double RY = (77.0/256.0), GY = (150.0/256.0), BY = (29.0/256.0); const double RU = (-44.0/256.0), GU = (-87.0/256.0), BU = (131.0/256.0); const double RV = (131.0/256.0), GV = (-110.0/256.0), BV = (-21.0/256.0); const unsigned short pixsz = lpInfo->bmiHeader.biBitCount; const int bytewidth = (((lpInfo->bmiHeader.biWidth*lpInfo->bmiHeader.biBitCount+31)&~31)/8); static unsigned int u, dib_offset, j, hblank, vblank, hcrop, vcrop, topblank; static int x, y; static double R, G, B; unsigned char *lpcurpix,*lpcurscanl; unsigned short *lpcurpixw; int h, w, p; int lblank, rblank; unsigned char *lpframeY; const RGBQUAD *lpPal = (RGBQUAD*)(((unsigned char*)lpInfo) + lpInfo->bmiHeader.biSize); if((pixsz!=8)&&(pixsz!=16)&&(pixsz!=24)&&(pixsz!=32)) { return TR_BITCOUNT_ERR; } // check for compression type of retrieved DIB if (lpInfo->bmiHeader.biCompression != BI_RGB) // does not support BI_BITFIELDS { return TR_BICOMPRESSION_ERR; } // if frame width is less than output width, then there are blank pixels in output frame on left and right if(width>lpInfo->bmiHeader.biWidth) hblank = width - lpInfo->bmiHeader.biWidth; else hblank=0; // similarily, if height is less than output, then there are blank lines at the top and bottom if(height>lpInfo->bmiHeader.biHeight) vblank = height - lpInfo->bmiHeader.biHeight; else vblank=0; // if frame width is greater than output width, we have to trim pixels if(width<lpInfo->bmiHeader.biWidth) hcrop = lpInfo->bmiHeader.biWidth - width; else hcrop=0; // if frame height is greater than output height, we have to trim pixels if(height<lpInfo->bmiHeader.biHeight) vcrop = lpInfo->bmiHeader.biHeight - height; else vcrop=0; if(vertical_size>lpInfo->bmiHeader.biHeight) topblank = (vertical_size - lpInfo->bmiHeader.biHeight)/2; else topblank = 0; // convert RGB DIB to YUV (4:2:0) lpframeY = (unsigned char *)frame[0]; // take care of any blank lines on the top j = topblank; while(j > 0) { for(x = 0; x < width; x++) { *lpframeY++ = 0; p = x + (j - 1)*width; g_stUVTempBuffers.SetUVBuffer(p,128,128); } j--; } switch(pixsz) { case 8: lpcurscanl = (unsigned char *)(pBytes + ((lpInfo->bmiHeader.biHeight - 1 - (vcrop/2)) * bytewidth) + ((hcrop/2))); p = (hblank/2)+topblank*width; h = lpInfo->bmiHeader.biHeight - (int) vcrop; lblank = hblank/2; rblank = hblank - lblank; do { // take care of any blank pixels on the left if(lblank > 0) { memset(lpframeY, 0, lblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,lblank); lpframeY += lblank; p += lblank; } w = lpInfo->bmiHeader.biWidth - (int) hcrop; lpcurpix = lpcurscanl; do { R = (float) lpPal[*lpcurpix * 4].rgbRed; G = (float) lpPal[*lpcurpix * 4].rgbGreen; B = (float) lpPal[*lpcurpix * 4].rgbBlue; lpcurpix++; *lpframeY++ = (int)(RY*R + GY*G + BY*B); g_stUVTempBuffers.SetUVBuffer(p, (int)(RU*R + GU*G + BU*B + 128.5), (int)(RV*R + GV*G + BV*B + 128.5)); p++; } while(--w); // take care of any blank pixels on the right if(rblank > 0) { memset(lpframeY, 0, rblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,rblank); lpframeY += rblank; p += rblank; } lpcurscanl -= bytewidth; } while(--h); break; case 16: lpcurscanl = (unsigned char *)(pBytes + ((lpInfo->bmiHeader.biHeight - 1 - (vcrop/2)) * bytewidth) + ((hcrop/2) * 2)); p = (hblank/2)+topblank*width; h = lpInfo->bmiHeader.biHeight - (int) vcrop; lblank = hblank/2; rblank = hblank - lblank; do { // take care of any blank pixels on the left if(lblank > 0) { memset(lpframeY, 0, lblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,lblank); lpframeY += lblank; p += lblank; } w = lpInfo->bmiHeader.biWidth - (int) hcrop; lpcurpixw = (unsigned short *) lpcurscanl; do { R = (float)(((*lpcurpixw >> 7) & 0xf8)|0x07); G = (float)(((*lpcurpixw >> 2) & 0xf8)|0x07); B = (float)(((*lpcurpixw << 3) & 0xf8)|0x07); lpcurpixw++; *lpframeY++ = (int)(RY*R + GY*G + BY*B); g_stUVTempBuffers.SetUVBuffer(p, (int)(RU*R + GU*G + BU*B + 128.5), (int)(RV*R + GV*G + BV*B + 128.5)); p++; } while(--w); // take care of any blank pixels on the right if(rblank > 0) { memset(lpframeY, 0, rblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,rblank); lpframeY += rblank; p += rblank; } lpcurscanl -= bytewidth; } while(--h); break; case 24: lpcurscanl = (unsigned char *)(pBytes + ((lpInfo->bmiHeader.biHeight - 1 - (vcrop/2)) * bytewidth) + ((hcrop/2) * 3)); p = (hblank/2)+topblank*width; h = lpInfo->bmiHeader.biHeight - (int) vcrop; lblank = hblank/2; rblank = hblank - lblank; do { // take care of any blank pixels on the left if(lblank > 0) { memset(lpframeY, 0, lblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,lblank); lpframeY += lblank; p += lblank; } w = lpInfo->bmiHeader.biWidth - (int) hcrop; lpcurpix = lpcurscanl; do { B = *lpcurpix++; G = *lpcurpix++; R = *lpcurpix++; *lpframeY++ = (int)(RY*R + GY*G + BY*B); g_stUVTempBuffers.SetUVBuffer(p, (int)(RU*R + GU*G + BU*B + 128.5), (int)(RV*R + GV*G + BV*B + 128.5)); p++; } while(--w); // take care of any blank pixels on the right if(rblank > 0) { memset(lpframeY, 0, rblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,rblank); lpframeY += rblank; p += rblank; } lpcurscanl -= bytewidth; } while(--h); break; case 32: lpcurscanl = (unsigned char *)(pBytes + ((lpInfo->bmiHeader.biHeight - 1 - (vcrop/2)) * bytewidth) + ((hcrop/2) * 4)); p = (hblank/2)+topblank*width; h = lpInfo->bmiHeader.biHeight - (int) vcrop; lblank = hblank/2; rblank = hblank - lblank; do { // take care of any blank pixels on the left if(lblank > 0) { memset(lpframeY, 0, lblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,lblank); lpframeY += lblank; p += lblank; } w = lpInfo->bmiHeader.biWidth - (int) hcrop; lpcurpix = lpcurscanl; do { B = *lpcurpix++; G = *lpcurpix++; R = *lpcurpix++; lpcurpix++; *lpframeY++ = (int)(RY*R + GY*G + BY*B); g_stUVTempBuffers.SetUVBuffer(p, (int)(RU*R + GU*G + BU*B + 128.5), (int)(RV*R + GV*G + BV*B + 128.5)); p++; } while(--w); // take care of any blank pixels on the right if(rblank > 0) { memset(lpframeY, 0, rblank); g_stUVTempBuffers.SetUVBuffer(p,128,128,rblank); lpframeY += rblank; p += rblank; } lpcurscanl -= bytewidth; } while(--h); break; default: return TR_BITCOUNT_ERR; } // and any blank lines on the bottom j = vblank - topblank; //printf("j=%u, vblank=%u, vertical_size=%u, biHeight=%u\n",j,vblank,vertical_size,lpbi->biHeight); while(j > 0) { for(x = 0; x < width; x++) { *lpframeY++ = 0; p = x + (topblank+lpInfo->bmiHeader.biHeight + j - 1)*width; g_stUVTempBuffers.SetUVBuffer(p,128,128); } j--; } // now do FIR chroma subsampling g_stUVTempBuffers.conv444to422U(&g_stPictureStruct,&g_stSequenceData); g_stUVTempBuffers.conv444to422V(&g_stPictureStruct,&g_stSequenceData); g_stUVTempBuffers.conv422to420U(frame[1],&g_stPictureStruct,&g_stSequenceData); g_stUVTempBuffers.conv422to420V(frame[2],&g_stPictureStruct,&g_stSequenceData); g_stUVTempBuffers.SoftFilter(frame,width,height); return TR_OK; } /*========================================================= ô«é½é╠ÉäÆΦ =========================================================*/ /*--------------------------------------------------------- ô«é½é╠ÉäÆΦ ---------------------------------------------------------*/ void MotionEstimation(unsigned char* oldorg, unsigned char* neworg, unsigned char* oldref, unsigned char* newref, unsigned char* cur, unsigned char* curref, int sxf,int syf,int sxb,int syb, MACROBLOCKINFO* mbi, int secondfield,bool ipflag) { int i, j; const int width = g_stSequenceData.stHeader.nWidth; const int height2 = g_stSequenceData.stHeader.nHeight2; /* loop through all macroblocks of the picture */ for (j=0; j<height2; j+=16) { for (i=0; i<width; i+=16) { if (g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) FrameME(oldorg,neworg,oldref,newref,cur,i,j,sxf,syf,sxb,syb,mbi); else FieldME(oldorg,neworg,oldref,newref,cur,curref,i,j,sxf,syf,sxb,syb, mbi,secondfield,ipflag); mbi++; } } } /*--------------------------------------------------------- âtâîü[âÇÅπé┼é╠ô«é½ÉäÆΦ ---------------------------------------------------------*/ inline void FrameME(unsigned char* oldorg, unsigned char* neworg, unsigned char* oldref, unsigned char* newref, unsigned char* cur, int i,int j,int sxf,int syf,int sxb,int syb, MACROBLOCKINFO* mbi) { const int width = g_stSequenceData.stHeader.nWidth; const int height = g_stSequenceData.stHeader.nHeight; int imin,jmin,iminf,jminf,iminr,jminr; int imint,jmint,iminb,jminb; int imintf,jmintf,iminbf,jminbf; int imintr,jmintr,iminbr,jminbr; int var,v0; int dmc,dmcf,dmcr,dmci,vmc,vmcf,vmcr,vmci; int dmcfield,dmcfieldf,dmcfieldr,dmcfieldi; int tsel,bsel,tself,bself,tselr,bselr; unsigned char *mb; int imins[2][2],jmins[2][2]; int imindp,jmindp,imindmv,jmindmv,dmc_dp,vmc_dp; mb = cur + i + width*j; var = Variance(mb,width); if (g_stPictureData.stHeader.nPictType==I_TYPE) mbi->mb_type = MB_INTRA; else if (g_stPictureData.stHeader.nPictType==P_TYPE) { if (g_stPictureData.stCodingExtension.bFramePredDCT) { dmc = FullSearch(oldorg,oldref,mb, width,i,j,sxf,syf,16,width,height,&imin,&jmin); vmc = Dist2(oldref+(imin>>1)+width*(jmin>>1),mb, width,imin&1,jmin&1,16); mbi->motion_type = MC_FRAME; } else { FrameEstimate(oldorg,oldref,mb,i,j,sxf,syf, &imin,&jmin,&imint,&jmint,&iminb,&jminb, &dmc,&dmcfield,&tsel,&bsel,imins,jmins); if (g_stCodingModelParams.nDistanceBetweenIPFrames==1) DPFrameEstimate(oldref,mb,i,j>>1,imins,jmins, &imindp,&jmindp,&imindmv,&jmindmv,&dmc_dp,&vmc_dp); /* select between dual prime, frame and field prediction */ if (g_stCodingModelParams.nDistanceBetweenIPFrames==1 && dmc_dp<dmc && dmc_dp<dmcfield) { mbi->motion_type = MC_DMV; dmc = dmc_dp; vmc = vmc_dp; } else if (dmc<=dmcfield) { mbi->motion_type = MC_FRAME; vmc = Dist2(oldref+(imin>>1)+width*(jmin>>1),mb, width,imin&1,jmin&1,16); } else { mbi->motion_type = MC_FIELD; dmc = dmcfield; vmc = Dist2(oldref+(tsel?width:0)+(imint>>1)+(width<<1)*(jmint>>1), mb,width<<1,imint&1,jmint&1,8); vmc+= Dist2(oldref+(bsel?width:0)+(iminb>>1)+(width<<1)*(jminb>>1), mb+width,width<<1,iminb&1,jminb&1,8); } } /* select between intra or non-intra coding: * * selection is based on intra block variance (var) vs. * prediction error variance (vmc) * * blocks with small prediction error are always coded non-intra * even if variance is smaller (is this reasonable?) */ if (vmc>var && vmc>=9*256) mbi->mb_type = MB_INTRA; else { /* select between MC / No-MC * * use No-MC if var(No-MC) <= 1.25*var(MC) * (i.e slightly biased towards No-MC) * * blocks with small prediction error are always coded as No-MC * (requires no motion vectors, allows skipping) */ v0 = Dist2(oldref+i+width*j,mb,width,0,0,16); if (4*v0>5*vmc && v0>=9*256) { /* use MC */ var = vmc; mbi->mb_type = MB_FORWARD; if (mbi->motion_type==MC_FRAME) { mbi->MV[0][0][0] = imin - (i<<1); mbi->MV[0][0][1] = jmin - (j<<1); } else if (mbi->motion_type==MC_DMV) { /* these are FRAME vectors */ /* same parity vector */ mbi->MV[0][0][0] = imindp - (i<<1); mbi->MV[0][0][1] = (jmindp<<1) - (j<<1); /* opposite parity vector */ mbi->dmvector[0] = imindmv; mbi->dmvector[1] = jmindmv; } else { /* these are FRAME vectors */ mbi->MV[0][0][0] = imint - (i<<1); mbi->MV[0][0][1] = (jmint<<1) - (j<<1); mbi->MV[1][0][0] = iminb - (i<<1); mbi->MV[1][0][1] = (jminb<<1) - (j<<1); mbi->mv_field_sel[0][0] = tsel; mbi->mv_field_sel[1][0] = bsel; } } else { /* No-MC */ var = v0; mbi->mb_type = 0; mbi->motion_type = MC_FRAME; mbi->MV[0][0][0] = 0; mbi->MV[0][0][1] = 0; } } } else /* if (pict_type==B_TYPE) */ { if (g_stPictureData.stCodingExtension.bFramePredDCT) { /* forward */ dmcf = FullSearch(oldorg,oldref,mb, width,i,j,sxf,syf,16,width,height,&iminf,&jminf); vmcf = Dist2(oldref+(iminf>>1)+width*(jminf>>1),mb, width,iminf&1,jminf&1,16); /* backward */ dmcr = FullSearch(neworg,newref,mb, width,i,j,sxb,syb,16,width,height,&iminr,&jminr); vmcr = Dist2(newref+(iminr>>1)+width*(jminr>>1),mb, width,iminr&1,jminr&1,16); /* interpolated (bidirectional) */ vmci = BDist2(oldref+(iminf>>1)+width*(jminf>>1), newref+(iminr>>1)+width*(jminr>>1), mb,width,iminf&1,jminf&1,iminr&1,jminr&1,16); /* decisions */ /* select between forward/backward/interpolated prediction: * use the one with smallest mean sqaured prediction error */ if (vmcf<=vmcr && vmcf<=vmci) { vmc = vmcf; mbi->mb_type = MB_FORWARD; } else if (vmcr<=vmci) { vmc = vmcr; mbi->mb_type = MB_BACKWARD; } else { vmc = vmci; mbi->mb_type = MB_FORWARD|MB_BACKWARD; } mbi->motion_type = MC_FRAME; } else { /* forward prediction */ FrameEstimate(oldorg,oldref,mb,i,j,sxf,syf, &iminf,&jminf,&imintf,&jmintf,&iminbf,&jminbf, &dmcf,&dmcfieldf,&tself,&bself,imins,jmins); /* backward prediction */ FrameEstimate(neworg,newref,mb,i,j,sxb,syb, &iminr,&jminr,&imintr,&jmintr,&iminbr,&jminbr, &dmcr,&dmcfieldr,&tselr,&bselr,imins,jmins); /* calculate interpolated distance */ /* frame */ dmci = BDist1(oldref+(iminf>>1)+width*(jminf>>1), newref+(iminr>>1)+width*(jminr>>1), mb,width,iminf&1,jminf&1,iminr&1,jminr&1,16); /* top field */ dmcfieldi = BDist1(oldref+(imintf>>1)+(tself?width:0)+(width<<1)*(jmintf>>1), newref+(imintr>>1)+(tselr?width:0)+(width<<1)*(jmintr>>1), mb,width<<1,imintf&1,jmintf&1,imintr&1,jmintr&1,8); /* bottom field */ dmcfieldi+= BDist1(oldref+(iminbf>>1)+(bself?width:0)+(width<<1)*(jminbf>>1), newref+(iminbr>>1)+(bselr?width:0)+(width<<1)*(jminbr>>1), mb+width,width<<1,iminbf&1,jminbf&1,iminbr&1,jminbr&1,8); /* select prediction type of minimum distance from the * six candidates (field/frame * forward/backward/interpolated) */ if (dmci<dmcfieldi && dmci<dmcf && dmci<dmcfieldf && dmci<dmcr && dmci<dmcfieldr) { /* frame, interpolated */ mbi->mb_type = MB_FORWARD|MB_BACKWARD; mbi->motion_type = MC_FRAME; vmc = BDist2(oldref+(iminf>>1)+width*(jminf>>1), newref+(iminr>>1)+width*(jminr>>1), mb,width,iminf&1,jminf&1,iminr&1,jminr&1,16); } else if (dmcfieldi<dmcf && dmcfieldi<dmcfieldf && dmcfieldi<dmcr && dmcfieldi<dmcfieldr) { /* field, interpolated */ mbi->mb_type = MB_FORWARD|MB_BACKWARD; mbi->motion_type = MC_FIELD; vmc = BDist2(oldref+(imintf>>1)+(tself?width:0)+(width<<1)*(jmintf>>1), newref+(imintr>>1)+(tselr?width:0)+(width<<1)*(jmintr>>1), mb,width<<1,imintf&1,jmintf&1,imintr&1,jmintr&1,8); vmc+= BDist2(oldref+(iminbf>>1)+(bself?width:0)+(width<<1)*(jminbf>>1), newref+(iminbr>>1)+(bselr?width:0)+(width<<1)*(jminbr>>1), mb+width,width<<1,iminbf&1,jminbf&1,iminbr&1,jminbr&1,8); } else if (dmcf<dmcfieldf && dmcf<dmcr && dmcf<dmcfieldr) { /* frame, forward */ mbi->mb_type = MB_FORWARD; mbi->motion_type = MC_FRAME; vmc = Dist2(oldref+(iminf>>1)+width*(jminf>>1),mb, width,iminf&1,jminf&1,16); } else if (dmcfieldf<dmcr && dmcfieldf<dmcfieldr) { /* field, forward */ mbi->mb_type = MB_FORWARD; mbi->motion_type = MC_FIELD; vmc = Dist2(oldref+(tself?width:0)+(imintf>>1)+(width<<1)*(jmintf>>1), mb,width<<1,imintf&1,jmintf&1,8); vmc+= Dist2(oldref+(bself?width:0)+(iminbf>>1)+(width<<1)*(jminbf>>1), mb+width,width<<1,iminbf&1,jminbf&1,8); } else if (dmcr<dmcfieldr) { /* frame, backward */ mbi->mb_type = MB_BACKWARD; mbi->motion_type = MC_FRAME; vmc = Dist2(newref+(iminr>>1)+width*(jminr>>1),mb, width,iminr&1,jminr&1,16); } else { /* field, backward */ mbi->mb_type = MB_BACKWARD; mbi->motion_type = MC_FIELD; vmc = Dist2(newref+(tselr?width:0)+(imintr>>1)+(width<<1)*(jmintr>>1), mb,width<<1,imintr&1,jmintr&1,8); vmc+= Dist2(newref+(bselr?width:0)+(iminbr>>1)+(width<<1)*(jminbr>>1), mb+width,width<<1,iminbr&1,jminbr&1,8); } } /* select between intra or non-intra coding: * * selection is based on intra block variance (var) vs. * prediction error variance (vmc) * * blocks with small prediction error are always coded non-intra * even if variance is smaller (is this reasonable?) */ if (vmc>var && vmc>=9*256) mbi->mb_type = MB_INTRA; else { var = vmc; if (mbi->motion_type==MC_FRAME) { /* forward */ mbi->MV[0][0][0] = iminf - (i<<1); mbi->MV[0][0][1] = jminf - (j<<1); /* backward */ mbi->MV[0][1][0] = iminr - (i<<1); mbi->MV[0][1][1] = jminr - (j<<1); } else { /* these are FRAME vectors */ /* forward */ mbi->MV[0][0][0] = imintf - (i<<1); mbi->MV[0][0][1] = (jmintf<<1) - (j<<1); mbi->MV[1][0][0] = iminbf - (i<<1); mbi->MV[1][0][1] = (jminbf<<1) - (j<<1); mbi->mv_field_sel[0][0] = tself; mbi->mv_field_sel[1][0] = bself; /* backward */ mbi->MV[0][1][0] = imintr - (i<<1); mbi->MV[0][1][1] = (jmintr<<1) - (j<<1); mbi->MV[1][1][0] = iminbr - (i<<1); mbi->MV[1][1][1] = (jminbr<<1) - (j<<1); mbi->mv_field_sel[0][1] = tselr; mbi->mv_field_sel[1][1] = bselr; } } } mbi->var = var; } /*--------------------------------------------------------- âtâBü[âïâhÅπé┼é╠ô«é½ÉäÆΦ ---------------------------------------------------------*/ inline void FieldME(unsigned char *oldorg, unsigned char *neworg, unsigned char *oldref, unsigned char *newref, unsigned char *cur, unsigned char *curref, int i, int j, int sxf, int syf, int sxb, int syb, MACROBLOCKINFO *mbi, int secondfield, bool ipflag) { const int width = g_stSequenceData.stHeader.nWidth; int w2; unsigned char *mb, *toporg, *topref, *botorg, *botref; int var,vmc,v0,dmc,dmcfieldi,dmc8i; int imin,jmin,imin8u,jmin8u,imin8l,jmin8l,dmcfield,dmc8,sel,sel8u,sel8l; int iminf,jminf,imin8uf,jmin8uf,imin8lf,jmin8lf,dmcfieldf,dmc8f,self,sel8uf,sel8lf; int iminr,jminr,imin8ur,jmin8ur,imin8lr,jmin8lr,dmcfieldr,dmc8r,selr,sel8ur,sel8lr; int imins,jmins,ds,imindmv,jmindmv,vmc_dp,dmc_dp; w2 = width<<1; mb = cur + i + w2*j; if (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) mb += width; var = Variance(mb,w2); if (g_stPictureData.stHeader.nPictType==I_TYPE) mbi->mb_type = MB_INTRA; else if (g_stPictureData.stHeader.nPictType==P_TYPE) { toporg = oldorg; topref = oldref; botorg = oldorg + width; botref = oldref + width; if (secondfield) { /* opposite parity field is in same frame */ if (g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD) { /* current is top field */ botorg = cur + width; botref = curref + width; } else { /* current is bottom field */ toporg = cur; topref = curref; } } FieldEstimate(toporg,topref,botorg,botref,mb,i,j,sxf,syf,ipflag, &imin,&jmin,&imin8u,&jmin8u,&imin8l,&jmin8l, &dmcfield,&dmc8,&sel,&sel8u,&sel8l,&imins,&jmins,&ds); if (g_stCodingModelParams.nDistanceBetweenIPFrames==1 && !ipflag) /* generic condition which permits Dual Prime */ DPFieldEstimate(topref,botref,mb,i,j,imins,jmins,&imindmv,&jmindmv, &dmc_dp,&vmc_dp); /* select between dual prime, field and 16x8 prediction */ if (g_stCodingModelParams.nDistanceBetweenIPFrames==1 && !ipflag && dmc_dp<dmc8 && dmc_dp<dmcfield) { /* Dual Prime prediction */ mbi->motion_type = MC_DMV; dmc = dmc_dp; /* L1 metric */ vmc = vmc_dp; /* we already calculated L2 error for Dual */ } else if (dmc8<dmcfield) { /* 16x8 prediction */ mbi->motion_type = MC_16X8; /* upper half block */ vmc = Dist2((sel8u?botref:topref) + (imin8u>>1) + w2*(jmin8u>>1), mb,w2,imin8u&1,jmin8u&1,8); /* lower half block */ vmc+= Dist2((sel8l?botref:topref) + (imin8l>>1) + w2*(jmin8l>>1), mb+8*w2,w2,imin8l&1,jmin8l&1,8); } else { /* field prediction */ mbi->motion_type = MC_FIELD; vmc = Dist2((sel?botref:topref) + (imin>>1) + w2*(jmin>>1), mb,w2,imin&1,jmin&1,16); } /* select between intra and non-intra coding */ if (vmc>var && vmc>=9*256) mbi->mb_type = MB_INTRA; else { /* zero MV field prediction from same parity ref. field * (not allowed if ipflag is set) */ if (!ipflag) v0 = Dist2(((g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD)?botref:topref) + i + w2*j, mb,w2,0,0,16); if (ipflag || (4*v0>5*vmc && v0>=9*256)) { var = vmc; mbi->mb_type = MB_FORWARD; if (mbi->motion_type==MC_FIELD) { mbi->MV[0][0][0] = imin - (i<<1); mbi->MV[0][0][1] = jmin - (j<<1); mbi->mv_field_sel[0][0] = sel; } else if (mbi->motion_type==MC_DMV) { /* same parity vector */ mbi->MV[0][0][0] = imins - (i<<1); mbi->MV[0][0][1] = jmins - (j<<1); /* opposite parity vector */ mbi->dmvector[0] = imindmv; mbi->dmvector[1] = jmindmv; } else { mbi->MV[0][0][0] = imin8u - (i<<1); mbi->MV[0][0][1] = jmin8u - (j<<1); mbi->MV[1][0][0] = imin8l - (i<<1); mbi->MV[1][0][1] = jmin8l - ((j+8)<<1); mbi->mv_field_sel[0][0] = sel8u; mbi->mv_field_sel[1][0] = sel8l; } } else { /* No MC */ var = v0; mbi->mb_type = 0; mbi->motion_type = MC_FIELD; mbi->MV[0][0][0] = 0; mbi->MV[0][0][1] = 0; mbi->mv_field_sel[0][0] = (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD); } } } else /* if (pict_type==B_TYPE) */ { /* forward prediction */ FieldEstimate(oldorg,oldref,oldorg+width,oldref+width,mb, i,j,sxf,syf,0, &iminf,&jminf,&imin8uf,&jmin8uf,&imin8lf,&jmin8lf, &dmcfieldf,&dmc8f,&self,&sel8uf,&sel8lf,&imins,&jmins,&ds); /* backward prediction */ FieldEstimate(neworg,newref,neworg+width,newref+width,mb, i,j,sxb,syb,0, &iminr,&jminr,&imin8ur,&jmin8ur,&imin8lr,&jmin8lr, &dmcfieldr,&dmc8r,&selr,&sel8ur,&sel8lr,&imins,&jmins,&ds); /* calculate distances for bidirectional prediction */ /* field */ dmcfieldi = BDist1(oldref + (self?width:0) + (iminf>>1) + w2*(jminf>>1), newref + (selr?width:0) + (iminr>>1) + w2*(jminr>>1), mb,w2,iminf&1,jminf&1,iminr&1,jminr&1,16); /* 16x8 upper half block */ dmc8i = BDist1(oldref + (sel8uf?width:0) + (imin8uf>>1) + w2*(jmin8uf>>1), newref + (sel8ur?width:0) + (imin8ur>>1) + w2*(jmin8ur>>1), mb,w2,imin8uf&1,jmin8uf&1,imin8ur&1,jmin8ur&1,8); /* 16x8 lower half block */ dmc8i+= BDist1(oldref + (sel8lf?width:0) + (imin8lf>>1) + w2*(jmin8lf>>1), newref + (sel8lr?width:0) + (imin8lr>>1) + w2*(jmin8lr>>1), mb+8*w2,w2,imin8lf&1,jmin8lf&1,imin8lr&1,jmin8lr&1,8); /* select prediction type of minimum distance */ if (dmcfieldi<dmc8i && dmcfieldi<dmcfieldf && dmcfieldi<dmc8f && dmcfieldi<dmcfieldr && dmcfieldi<dmc8r) { /* field, interpolated */ mbi->mb_type = MB_FORWARD|MB_BACKWARD; mbi->motion_type = MC_FIELD; vmc = BDist2(oldref + (self?width:0) + (iminf>>1) + w2*(jminf>>1), newref + (selr?width:0) + (iminr>>1) + w2*(jminr>>1), mb,w2,iminf&1,jminf&1,iminr&1,jminr&1,16); } else if (dmc8i<dmcfieldf && dmc8i<dmc8f && dmc8i<dmcfieldr && dmc8i<dmc8r) { /* 16x8, interpolated */ mbi->mb_type = MB_FORWARD|MB_BACKWARD; mbi->motion_type = MC_16X8; /* upper half block */ vmc = BDist2(oldref + (sel8uf?width:0) + (imin8uf>>1) + w2*(jmin8uf>>1), newref + (sel8ur?width:0) + (imin8ur>>1) + w2*(jmin8ur>>1), mb,w2,imin8uf&1,jmin8uf&1,imin8ur&1,jmin8ur&1,8); /* lower half block */ vmc+= BDist2(oldref + (sel8lf?width:0) + (imin8lf>>1) + w2*(jmin8lf>>1), newref + (sel8lr?width:0) + (imin8lr>>1) + w2*(jmin8lr>>1), mb+8*w2,w2,imin8lf&1,jmin8lf&1,imin8lr&1,jmin8lr&1,8); } else if (dmcfieldf<dmc8f && dmcfieldf<dmcfieldr && dmcfieldf<dmc8r) { /* field, forward */ mbi->mb_type = MB_FORWARD; mbi->motion_type = MC_FIELD; vmc = Dist2(oldref + (self?width:0) + (iminf>>1) + w2*(jminf>>1), mb,w2,iminf&1,jminf&1,16); } else if (dmc8f<dmcfieldr && dmc8f<dmc8r) { /* 16x8, forward */ mbi->mb_type = MB_FORWARD; mbi->motion_type = MC_16X8; /* upper half block */ vmc = Dist2(oldref + (sel8uf?width:0) + (imin8uf>>1) + w2*(jmin8uf>>1), mb,w2,imin8uf&1,jmin8uf&1,8); /* lower half block */ vmc+= Dist2(oldref + (sel8lf?width:0) + (imin8lf>>1) + w2*(jmin8lf>>1), mb+8*w2,w2,imin8lf&1,jmin8lf&1,8); } else if (dmcfieldr<dmc8r) { /* field, backward */ mbi->mb_type = MB_BACKWARD; mbi->motion_type = MC_FIELD; vmc = Dist2(newref + (selr?width:0) + (iminr>>1) + w2*(jminr>>1), mb,w2,iminr&1,jminr&1,16); } else { /* 16x8, backward */ mbi->mb_type = MB_BACKWARD; mbi->motion_type = MC_16X8; /* upper half block */ vmc = Dist2(newref + (sel8ur?width:0) + (imin8ur>>1) + w2*(jmin8ur>>1), mb,w2,imin8ur&1,jmin8ur&1,8); /* lower half block */ vmc+= Dist2(newref + (sel8lr?width:0) + (imin8lr>>1) + w2*(jmin8lr>>1), mb+8*w2,w2,imin8lr&1,jmin8lr&1,8); } /* select between intra and non-intra coding */ if (vmc>var && vmc>=9*256) mbi->mb_type = MB_INTRA; else { var = vmc; if (mbi->motion_type==MC_FIELD) { /* forward */ mbi->MV[0][0][0] = iminf - (i<<1); mbi->MV[0][0][1] = jminf - (j<<1); mbi->mv_field_sel[0][0] = self; /* backward */ mbi->MV[0][1][0] = iminr - (i<<1); mbi->MV[0][1][1] = jminr - (j<<1); mbi->mv_field_sel[0][1] = selr; } else /* MC_16X8 */ { /* forward */ mbi->MV[0][0][0] = imin8uf - (i<<1); mbi->MV[0][0][1] = jmin8uf - (j<<1); mbi->mv_field_sel[0][0] = sel8uf; mbi->MV[1][0][0] = imin8lf - (i<<1); mbi->MV[1][0][1] = jmin8lf - ((j+8)<<1); mbi->mv_field_sel[1][0] = sel8lf; /* backward */ mbi->MV[0][1][0] = imin8ur - (i<<1); mbi->MV[0][1][1] = jmin8ur - (j<<1); mbi->mv_field_sel[0][1] = sel8ur; mbi->MV[1][1][0] = imin8lr - (i<<1); mbi->MV[1][1][1] = jmin8lr - ((j+8)<<1); mbi->mv_field_sel[1][1] = sel8lr; } } } mbi->var = var; } /* * frame picture motion estimation * * org: top left pel of source reference frame * ref: top left pel of reconstructed reference frame * mb: macroblock to be matched * i,j: location of mb relative to ref (=center of search window) * sx,sy: half widths of search window * iminp,jminp,dframep: location and value of best frame prediction * imintp,jmintp,tselp: location of best field pred. for top field of mb * iminbp,jminbp,bselp: location of best field pred. for bottom field of mb * dfieldp: value of field prediction */ void FrameEstimate(unsigned char *org, unsigned char *ref, unsigned char *mb, int i, int j, int sx, int sy, int *iminp, int *jminp, int *imintp, int *jmintp, int *iminbp, int *jminbp, int *dframep, int *dfieldp, int *tselp, int *bselp, int imins[2][2], int jmins[2][2]) { const int width = g_stSequenceData.stHeader.nWidth; const int height = g_stSequenceData.stHeader.nHeight; int dt,db,dmint,dminb; int imint,iminb,jmint,jminb; /* frame prediction */ *dframep = FullSearch(org,ref,mb,width,i,j,sx,sy,16,width,height, iminp,jminp); /* predict top field from top field */ dt = FullSearch(org,ref,mb,width<<1,i,j>>1,sx,sy>>1,8,width,height>>1, &imint,&jmint); /* predict top field from bottom field */ db = FullSearch(org+width,ref+width,mb,width<<1,i,j>>1,sx,sy>>1,8,width,height>>1, &iminb,&jminb); imins[0][0] = imint; jmins[0][0] = jmint; imins[1][0] = iminb; jmins[1][0] = jminb; /* select prediction for top field */ if (dt<=db) { dmint=dt; *imintp=imint; *jmintp=jmint; *tselp=0; } else { dmint=db; *imintp=iminb; *jmintp=jminb; *tselp=1; } /* predict bottom field from top field */ dt = FullSearch(org,ref,mb+width,width<<1,i,j>>1,sx,sy>>1,8,width,height>>1, &imint,&jmint); /* predict bottom field from bottom field */ db = FullSearch(org+width,ref+width,mb+width,width<<1,i,j>>1,sx,sy>>1,8,width,height>>1, &iminb,&jminb); imins[0][1] = imint; jmins[0][1] = jmint; imins[1][1] = iminb; jmins[1][1] = jminb; /* select prediction for bottom field */ if (db<=dt) { dminb=db; *iminbp=iminb; *jminbp=jminb; *bselp=1; } else { dminb=dt; *iminbp=imint; *jminbp=jmint; *bselp=0; } *dfieldp=dmint+dminb; } /*--------------------------------------------------------- field picture motion estimation subroutine toporg: address of original top reference field topref: address of reconstructed top reference field botorg: address of original bottom reference field botref: address of reconstructed bottom reference field mb: macroblock to be matched i,j: location of mb (=center of search window) sx,sy: half width/height of search window iminp,jminp,selp,dfieldp: location and distance of best field prediction imin8up,jmin8up,sel8up: location of best 16x8 pred. for upper half of mb imin8lp,jmin8lp,sel8lp: location of best 16x8 pred. for lower half of mb d8p: distance of best 16x8 prediction iminsp,jminsp,dsp: location and distance of best same parity field prediction (needed for dual prime, only valid if ipflag==0) ---------------------------------------------------------*/ void FieldEstimate(unsigned char *toporg, unsigned char *topref, unsigned char *botorg, unsigned char *botref, unsigned char *mb, int i, int j, int sx, int sy, bool ipflag, int *iminp, int *jminp, int *imin8up, int *jmin8up, int *imin8lp, int *jmin8lp, int *dfieldp, int *d8p, int *selp, int *sel8up, int *sel8lp, int *iminsp, int *jminsp, int *dsp) { const int width = g_stSequenceData.stHeader.nWidth; const int height = g_stSequenceData.stHeader.nHeight; int dt, db, imint, jmint, iminb, jminb; bool notop = false, nobot = false; /* if ipflag is set, predict from field of opposite parity only */ if(ipflag && (g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD)) { notop = true; } if(ipflag && (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD)) { nobot = true; } /* field prediction */ /* predict current field from top field */ if (notop) dt = 65536; /* infinity */ else dt = FullSearch(toporg,topref,mb,width<<1, i,j,sx,sy>>1,16,width,height>>1, &imint,&jmint); /* predict current field from bottom field */ if (nobot) db = 65536; /* infinity */ else db = FullSearch(botorg,botref,mb,width<<1, i,j,sx,sy>>1,16,width,height>>1, &iminb,&jminb); /* same parity prediction (only valid if ipflag==0) */ if (g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD) { *iminsp = imint; *jminsp = jmint; *dsp = dt; } else { *iminsp = iminb; *jminsp = jminb; *dsp = db; } /* select field prediction */ if (dt<=db) { *dfieldp = dt; *iminp = imint; *jminp = jmint; *selp = 0; } else { *dfieldp = db; *iminp = iminb; *jminp = jminb; *selp = 1; } /* 16x8 motion compensation */ /* predict upper half field from top field */ if (notop) dt = 65536; else dt = FullSearch(toporg,topref,mb,width<<1, i,j,sx,sy>>1,8,width,height>>1, &imint,&jmint); /* predict upper half field from bottom field */ if (nobot) db = 65536; else db = FullSearch(botorg,botref,mb,width<<1, i,j,sx,sy>>1,8,width,height>>1, &iminb,&jminb); /* select prediction for upper half field */ if (dt<=db) { *d8p = dt; *imin8up = imint; *jmin8up = jmint; *sel8up = 0; } else { *d8p = db; *imin8up = iminb; *jmin8up = jminb; *sel8up = 1; } /* predict lower half field from top field */ if (notop) dt = 65536; else dt = FullSearch(toporg,topref,mb+(width<<4),width<<1, i,j+8,sx,sy>>1,8,width,height>>1, &imint,&jmint); /* predict lower half field from bottom field */ if (nobot) db = 65536; else db = FullSearch(botorg,botref,mb+(width<<4),width<<1, i,j+8,sx,sy>>1,8,width,height>>1, &iminb,&jminb); /* select prediction for lower half field */ if (dt<=db) { *d8p += dt; *imin8lp = imint; *jmin8lp = jmint; *sel8lp = 0; } else { *d8p += db; *imin8lp = iminb; *jmin8lp = jminb; *sel8lp = 1; } } inline void DPFrameEstimate(unsigned char *ref, unsigned char *mb, int i, int j, int iminf[2][2], int jminf[2][2], int *iminp, int *jminp, int *imindmvp, int *jmindmvp, int *dmcp, int *vmcp) { const int width = g_stSequenceData.stHeader.nWidth; const int height = g_stSequenceData.stHeader.nHeight; int pref,ppred,delta_x,delta_y; int is,js,it,jt,ib,jb,it0,jt0,ib0,jb0; int imins,jmins,imint,jmint,iminb,jminb,imindmv,jmindmv; int vmc,local_dist; /* Calculate Dual Prime distortions for 9 delta candidates * for each of the four minimum field vectors * Note: only for P pictures! */ /* initialize minimum dual prime distortion to large value */ vmc = 1 << 30; for (pref=0; pref<2; pref++) { for (ppred=0; ppred<2; ppred++) { /* convert Cartesian absolute to relative motion vector * values (wrt current macroblock address (i,j) */ is = iminf[pref][ppred] - (i<<1); js = jminf[pref][ppred] - (j<<1); if (pref!=ppred) { /* vertical field shift adjustment */ if (ppred==0) js++; else js--; /* mvxs and mvys scaling*/ is<<=1; js<<=1; if ((g_stPictureData.stCodingExtension.bTopFirst&&ppred==1) || (!g_stPictureData.stCodingExtension.bTopFirst&&ppred==0)) { /* second field: scale by 1/3 */ is = (is>=0) ? (is+1)/3 : -((-is+1)/3); js = (js>=0) ? (js+1)/3 : -((-js+1)/3); } else continue; } /* vector for prediction from field of opposite 'parity' */ if (g_stPictureData.stCodingExtension.bTopFirst) { /* vector for prediction of top field from bottom field */ it0 = ((is+(is>0))>>1); jt0 = ((js+(js>0))>>1) - 1; /* vector for prediction of bottom field from top field */ ib0 = ((3*is+(is>0))>>1); jb0 = ((3*js+(js>0))>>1) + 1; } else { /* vector for prediction of top field from bottom field */ it0 = ((3*is+(is>0))>>1); jt0 = ((3*js+(js>0))>>1) - 1; /* vector for prediction of bottom field from top field */ ib0 = ((is+(is>0))>>1); jb0 = ((js+(js>0))>>1) + 1; } /* convert back to absolute half-pel field picture coordinates */ is += i<<1; js += j<<1; it0 += i<<1; jt0 += j<<1; ib0 += i<<1; jb0 += j<<1; if (is >= 0 && is <= (width-16)<<1 && js >= 0 && js <= (height-16)) { for (delta_y=-1; delta_y<=1; delta_y++) { for (delta_x=-1; delta_x<=1; delta_x++) { /* opposite field coordinates */ it = it0 + delta_x; jt = jt0 + delta_y; ib = ib0 + delta_x; jb = jb0 + delta_y; if (it >= 0 && it <= (width-16)<<1 && jt >= 0 && jt <= (height-16) && ib >= 0 && ib <= (width-16)<<1 && jb >= 0 && jb <= (height-16)) { /* compute prediction error */ local_dist = BDist2( ref + (is>>1) + (width<<1)*(js>>1), ref + width + (it>>1) + (width<<1)*(jt>>1), mb, /* current mb location */ width<<1, /* adjacent line distance */ is&1, js&1, it&1, jt&1, /* half-pel flags */ 8); /* block height */ local_dist += BDist2( ref + width + (is>>1) + (width<<1)*(js>>1), ref + (ib>>1) + (width<<1)*(jb>>1), mb + width, /* current mb location */ width<<1, /* adjacent line distance */ is&1, js&1, ib&1, jb&1, /* half-pel flags */ 8); /* block height */ /* update delta with least distortion vector */ if (local_dist < vmc) { imins = is; jmins = js; imint = it; jmint = jt; iminb = ib; jminb = jb; imindmv = delta_x; jmindmv = delta_y; vmc = local_dist; } } } /* end delta x loop */ } /* end delta y loop */ } } } /* Compute L1 error for decision purposes */ local_dist = BDist1( ref + (imins>>1) + (width<<1)*(jmins>>1), ref + width + (imint>>1) + (width<<1)*(jmint>>1), mb, width<<1, imins&1, jmins&1, imint&1, jmint&1, 8); local_dist += BDist1( ref + width + (imins>>1) + (width<<1)*(jmins>>1), ref + (iminb>>1) + (width<<1)*(jminb>>1), mb + width, width<<1, imins&1, jmins&1, iminb&1, jminb&1, 8); *dmcp = local_dist; *iminp = imins; *jminp = jmins; *imindmvp = imindmv; *jmindmvp = jmindmv; *vmcp = vmc; } inline void DPFieldEstimate(unsigned char *topref, unsigned char *botref, unsigned char *mb, int i, int j, int imins, int jmins, int *imindmvp, int *jmindmvp, int *dmcp, int *vmcp) { const int width = g_stSequenceData.stHeader.nWidth; const int width2 = g_stSequenceData.stHeader.nWidth2; const int height2 = g_stSequenceData.stHeader.nHeight2; unsigned char *sameref, *oppref; int io0,jo0,io,jo,delta_x,delta_y,mvxs,mvys,mvxo0,mvyo0; int imino,jmino,imindmv,jmindmv,vmc_dp,local_dist; /* Calculate Dual Prime distortions for 9 delta candidates */ /* Note: only for P pictures! */ /* Assign opposite and same reference pointer */ if (g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD) { sameref = topref; oppref = botref; } else { sameref = botref; oppref = topref; } /* convert Cartesian absolute to relative motion vector * values (wrt current macroblock address (i,j) */ mvxs = imins - (i<<1); mvys = jmins - (j<<1); /* vector for prediction from field of opposite 'parity' */ mvxo0 = (mvxs+(mvxs>0)) >> 1; /* mvxs // 2 */ mvyo0 = (mvys+(mvys>0)) >> 1; /* mvys // 2 */ /* vertical field shift correction */ if (g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD) mvyo0--; else mvyo0++; /* convert back to absolute coordinates */ io0 = mvxo0 + (i<<1); jo0 = mvyo0 + (j<<1); /* initialize minimum dual prime distortion to large value */ vmc_dp = 1 << 30; for (delta_y = -1; delta_y <= 1; delta_y++) { for (delta_x = -1; delta_x <=1; delta_x++) { /* opposite field coordinates */ io = io0 + delta_x; jo = jo0 + delta_y; if (io >= 0 && io <= (width-16)<<1 && jo >= 0 && jo <= (height2-16)<<1) { /* compute prediction error */ local_dist = BDist2( sameref + (imins>>1) + width2*(jmins>>1), oppref + (io>>1) + width2*(jo>>1), mb, /* current mb location */ width2, /* adjacent line distance */ imins&1, jmins&1, io&1, jo&1, /* half-pel flags */ 16); /* block height */ /* update delta with least distortion vector */ if (local_dist < vmc_dp) { imino = io; jmino = jo; imindmv = delta_x; jmindmv = delta_y; vmc_dp = local_dist; } } } /* end delta x loop */ } /* end delta y loop */ /* Compute L1 error for decision purposes */ *dmcp = BDist1( sameref + (imins>>1) + width2*(jmins>>1), oppref + (imino>>1) + width2*(jmino>>1), mb, /* current mb location */ width2, /* adjacent line distance */ imins&1, jmins&1, imino&1, jmino&1, /* half-pel flags */ 16); /* block height */ *imindmvp = imindmv; *jmindmvp = jmindmv; *vmcp = vmc_dp; } /*--------------------------------------------------------- full search block matching blk: top left pel of (16*h) block h: height of block lx: distance (in bytes) of vertically adjacent pels in ref,blk org: top left pel of source reference picture ref: top left pel of reconstructed reference picture i0,j0: center of search window sx,sy: half widths of search window xmax,ymax: right/bottom limits of search area iminp,jminp: pointers to where the result is stored result is given as half pel offset from ref(0,0) i.e. NOT relative to (i0,j0) ---------------------------------------------------------*/ int FullSearch(unsigned char *org, unsigned char *ref, unsigned char *blk, int lx, int i0, int j0, int sx, int sy, int h, int xmax, int ymax, int *iminp, int *jminp) { int i,j,imin,jmin,ilow,ihigh,jlow,jhigh; int d,dmin; int k,l,sxy; ilow = i0 - sx; ihigh = i0 + sx; if (ilow<0) ilow = 0; if (ihigh>xmax-16) ihigh = xmax-16; jlow = j0 - sy; jhigh = j0 + sy; if (jlow<0) jlow = 0; if (jhigh>ymax-h) jhigh = ymax-h; /* full pel search, spiraling outwards */ imin = i0; jmin = j0; dmin = Dist1(org+imin+lx*jmin,blk,lx,0,0,h,65536); sxy = (sx>sy) ? sx : sy; for (l=1; l<=sxy; l++) { i = i0 - l; j = j0 - l; for (k=0; k<8*l; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { d = Dist1(org+i+lx*j,blk,lx,0,0,h,dmin); if (d<dmin) { dmin = d; imin = i; jmin = j; } } if (k<2*l) i++; else if (k<4*l) j++; else if (k<6*l) i--; else j--; } } /* half pel */ dmin = 65536; imin <<= 1; jmin <<= 1; ilow = imin - (imin>0); ihigh = imin + (imin<((xmax-16)<<1)); jlow = jmin - (jmin>0); jhigh = jmin + (jmin<((ymax-h)<<1)); for (j=jlow; j<=jhigh; j++) for (i=ilow; i<=ihigh; i++) { d = Dist1(ref+(i>>1)+lx*(j>>1),blk,lx,i&1,j&1,h,dmin); if (d<dmin) { dmin = d; imin = i; jmin = j; } } *iminp = imin; *jminp = jmin; return dmin; } /*--------------------------------------------------------- total absolute difference between two (16*h) blocks including optional half pel interpolation of blk1 (hx,hy) blk1,blk2: addresses of top left pels of both blocks lx: distance (in bytes) of vertically adjacent pels hx,hy: flags for horizontal and/or vertical interpolation h: height of block (usually 8 or 16) distlim: bail out if sum exceeds this value ---------------------------------------------------------*/ int Dist1(unsigned char *blk1, unsigned char *blk2, int lx, int hx, int hy, int h, int distlim) { unsigned char *p1,*p1a,*p2; int i,j; int s,v; if(g_nFastMotionCompensationLevel) { lx <<= g_nFastMotionCompensationLevel; h >>= g_nFastMotionCompensationLevel; } if (!hx && !hy) { s = 0; p1 = blk1; p2 = blk2; for (j=0; j<h; j++) { if ((v = p1[0] - p2[0])<0) v = -v; s+= v; if ((v = p1[1] - p2[1])<0) v = -v; s+= v; if ((v = p1[2] - p2[2])<0) v = -v; s+= v; if ((v = p1[3] - p2[3])<0) v = -v; s+= v; if ((v = p1[4] - p2[4])<0) v = -v; s+= v; if ((v = p1[5] - p2[5])<0) v = -v; s+= v; if ((v = p1[6] - p2[6])<0) v = -v; s+= v; if ((v = p1[7] - p2[7])<0) v = -v; s+= v; if ((v = p1[8] - p2[8])<0) v = -v; s+= v; if ((v = p1[9] - p2[9])<0) v = -v; s+= v; if ((v = p1[10] - p2[10])<0) v = -v; s+= v; if ((v = p1[11] - p2[11])<0) v = -v; s+= v; if ((v = p1[12] - p2[12])<0) v = -v; s+= v; if ((v = p1[13] - p2[13])<0) v = -v; s+= v; if ((v = p1[14] - p2[14])<0) v = -v; s+= v; if ((v = p1[15] - p2[15])<0) v = -v; s+= v; if (s >= distlim) break; p1+= lx; p2+= lx; } } else if (hx && !hy) { s = 0; p1 = blk1; p2 = blk2; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((unsigned int)(p1[i]+p1[i+1]+1)>>1) - p2[i]; if (v>=0) s+= v; else s-= v; } p1+= lx; p2+= lx; } } else if (!hx && hy) { s = 0; p1 = blk1; p2 = blk2; p1a = p1 + lx; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((unsigned int)(p1[i]+p1a[i]+1)>>1) - p2[i]; if (v>=0) s+= v; else s-= v; } p1 = p1a; p1a+= lx; p2+= lx; } } else // if (hx && hy) { s = 0; p1 = blk1; p2 = blk2; p1a = p1 + lx; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((unsigned int)(p1[i]+p1[i+1]+p1a[i]+p1a[i+1]+2)>>2) - p2[i]; if (v>=0) s+= v; else s-= v; } p1 = p1a; p1a+= lx; p2+= lx; } } return s; } /*--------------------------------------------------------- total squared difference between two (16*h) blocks including optional half pel interpolation of blk1 (hx,hy) blk1,blk2: addresses of top left pels of both blocks lx: distance (in bytes) of vertically adjacent pels hx,hy: flags for horizontal and/or vertical interpolation h: height of block (usually 8 or 16) ---------------------------------------------------------*/ int Dist2(unsigned char *blk1, unsigned char *blk2, int lx, int hx, int hy, int h) { unsigned char *p1,*p1a,*p2; int i,j; int s,v; if(g_nFastMotionCompensationLevel) { lx <<= g_nFastMotionCompensationLevel; h >>= g_nFastMotionCompensationLevel; } if (!hx && !hy) { s = 0; p1 = blk1; p2 = blk2; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = p1[i] - p2[i]; s+= v*v; } p1+= lx; p2+= lx; } } else if (hx && !hy) { s = 0; p1 = blk1; p2 = blk2; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((unsigned int)(p1[i]+p1[i+1]+1)>>1) - p2[i]; s+= v*v; } p1+= lx; p2+= lx; } } else if (!hx && hy) { s = 0; p1 = blk1; p2 = blk2; p1a = p1 + lx; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((unsigned int)(p1[i]+p1a[i]+1)>>1) - p2[i]; s+= v*v; } p1 = p1a; p1a+= lx; p2+= lx; } } else // if (hx && hy) { s = 0; p1 = blk1; p2 = blk2; p1a = p1 + lx; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((unsigned int)(p1[i]+p1[i+1]+p1a[i]+p1a[i+1]+2)>>2) - p2[i]; s+= v*v; } p1 = p1a; p1a+= lx; p2+= lx; } } return s; } /*--------------------------------------------------------- absolute difference error between a (16*h) block and a bidirectional prediction p2: address of top left pel of block pf,hxf,hyf: address and half pel flags of forward ref. block pb,hxb,hyb: address and half pel flags of backward ref. block h: height of block lx: distance (in bytes) of vertically adjacent pels in p2,pf,pb ---------------------------------------------------------*/ int BDist1(unsigned char *pf, unsigned char *pb, unsigned char *p2, int lx, int hxf, int hyf, int hxb, int hyb, int h) { unsigned char *pfa,*pfb,*pfc,*pba,*pbb,*pbc; int i,j; int s,v; if(g_nFastMotionCompensationLevel) { lx <<= g_nFastMotionCompensationLevel; h >>= g_nFastMotionCompensationLevel; } pfa = pf + hxf; pfb = pf + lx*hyf; pfc = pfb + hxf; pba = pb + hxb; pbb = pb + lx*hyb; pbc = pbb + hxb; s = 0; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((((unsigned int)(*pf++ + *pfa++ + *pfb++ + *pfc++ + 2)>>2) + ((unsigned int)(*pb++ + *pba++ + *pbb++ + *pbc++ + 2)>>2) + 1)>>1) - *p2++; if (v>=0) s+= v; else s-= v; } p2+= lx-16; pf+= lx-16; pfa+= lx-16; pfb+= lx-16; pfc+= lx-16; pb+= lx-16; pba+= lx-16; pbb+= lx-16; pbc+= lx-16; } return s; } /*--------------------------------------------------------- squared error between a (16*h) block and a bidirectional prediction p2: address of top left pel of block pf,hxf,hyf: address and half pel flags of forward ref. block pb,hxb,hyb: address and half pel flags of backward ref. block h: height of block lx: distance (in bytes) of vertically adjacent pels in p2,pf,pb ---------------------------------------------------------*/ int BDist2(unsigned char *pf, unsigned char *pb, unsigned char *p2, int lx, int hxf, int hyf, int hxb, int hyb, int h) { unsigned char *pfa,*pfb,*pfc,*pba,*pbb,*pbc; int i,j; int s,v; if(g_nFastMotionCompensationLevel) { lx <<= g_nFastMotionCompensationLevel; h >>= g_nFastMotionCompensationLevel; } pfa = pf + hxf; pfb = pf + lx*hyf; pfc = pfb + hxf; pba = pb + hxb; pbb = pb + lx*hyb; pbc = pbb + hxb; s = 0; for (j=0; j<h; j++) { for (i=0; i<16; i++) { v = ((((unsigned int)(*pf++ + *pfa++ + *pfb++ + *pfc++ + 2)>>2) + ((unsigned int)(*pb++ + *pba++ + *pbb++ + *pbc++ + 2)>>2) + 1)>>1) - *p2++; s+=v*v; } p2+= lx-16; pf+= lx-16; pfa+= lx-16; pfb+= lx-16; pfc+= lx-16; pb+= lx-16; pba+= lx-16; pbb+= lx-16; pbc+= lx-16; } return s; } /*--------------------------------------------------------- variance of a (16*16) block, multiplied by 256 p: address of top left pel of block lx: distance (in bytes) of vertically adjacent pels ---------------------------------------------------------*/ int Variance(unsigned char *p,int lx) { unsigned int i,j; unsigned int v,s,s2; s = s2 = 0; for (j=0; j<16; j++) { for (i=0; i<16; i++) { v = *p++; s+= v; s2+= v*v; } p+= lx-16; } return s2 - (s*s)/256; } static int calcDist16(unsigned char *p1In, unsigned char *p2In) { /* * Returns the sum of the absolute differences between bytes * in two 16 bytes arrays. * */ unsigned char *p1,*p2; int v; int s = 0; /* * Need local variables p1, p2 because function may be called with * variables in registers * */ p1 = p1In; p2 = p2In; if ((v = p1[0] - p2[0])<0) v = -v; s+= v; if ((v = p1[1] - p2[1])<0) v = -v; s+= v; if ((v = p1[2] - p2[2])<0) v = -v; s+= v; if ((v = p1[3] - p2[3])<0) v = -v; s+= v; if ((v = p1[4] - p2[4])<0) v = -v; s+= v; if ((v = p1[5] - p2[5])<0) v = -v; s+= v; if ((v = p1[6] - p2[6])<0) v = -v; s+= v; if ((v = p1[7] - p2[7])<0) v = -v; s+= v; if ((v = p1[8] - p2[8])<0) v = -v; s+= v; if ((v = p1[9] - p2[9])<0) v = -v; s+= v; if ((v = p1[10] - p2[10])<0) v = -v; s+= v; if ((v = p1[11] - p2[11])<0) v = -v; s+= v; if ((v = p1[12] - p2[12])<0) v = -v; s+= v; if ((v = p1[13] - p2[13])<0) v = -v; s+= v; if ((v = p1[14] - p2[14])<0) v = -v; s+= v; if ((v = p1[15] - p2[15])<0) v = -v; s+= v; return s; } /*========================================================= predict =========================================================*/ /*--------------------------------------------------------- form prediction for a complete picture (frontend for predict_mb) reff: reference frame for forward prediction refb: reference frame for backward prediction cur: destination (current) frame secondfield: predict second field of a frame mbi: macroblock info ---------------------------------------------------------*/ void Predict(unsigned char* reff[],unsigned char* refb[],unsigned char* cur[], int secondfield,MACROBLOCKINFO* mbi) { int i, j, k; k = 0; /* loop through all macroblocks of the picture */ for (j=0; j<g_stSequenceData.stHeader.nHeight2; j+=16) { for (i=0; i<g_stSequenceData.stHeader.nWidth; i+=16) { PredictMB(reff,refb,cur,g_stSequenceData.stHeader.nWidth,i,j, g_stPictureData.stHeader.nPictType, g_stPictureData.stCodingExtension.nPictStruct, mbi[k].mb_type,mbi[k].motion_type,secondfield, mbi[k].MV,mbi[k].mv_field_sel,mbi[k].dmvector); k++; } } } /*--------------------------------------------------------- form prediction for one macroblock oldref: reference frame for forward prediction newref: reference frame for backward prediction cur: destination (current) frame lx: frame width (identical to global var `width') bx,by: picture (field or frame) coordinates of macroblock to be predicted pict_type: I, P or B pict_struct: FRAME_PICTURE, TOP_FIELD, BOTTOM_FIELD mb_type: MB_FORWARD, MB_BACKWARD, MB_INTRA motion_type: MC_FRAME, MC_FIELD, MC_16X8, MC_DMV secondfield: predict second field of a frame PMV[2][2][2]: motion vectors (in half pel picture coordinates) mv_field_sel[2][2]: motion vertical field selects (for field predictions) dmvector: differential motion vectors (for dual prime) Notes: - when predicting a P type picture which is the second field of a frame, the same parity reference field is in oldref, while the opposite parity reference field is assumed to be in newref! - intra macroblocks are modelled to have a constant prediction of 128 for all pels; this results in a DC DCT coefficient symmetric to 0 - vectors for field prediction in frame pictures are in half pel frame coordinates (vertical component is twice the field value and always even) already covers dual prime (not yet used) ---------------------------------------------------------*/ inline void PredictMB(unsigned char *oldref[], unsigned char *newref[], unsigned char *cur[], int lx, int bx, int by, int pict_type, int pict_struct, int mb_type, int motion_type, int secondfield, int PMV[][2][2], int mv_field_sel[][2], int dmvector[]) { int addflag, currentfield; unsigned char **predframe; int DMV[2][2]; if (mb_type&MB_INTRA) { ClearBlock(cur,bx,by); return; } addflag = 0; /* first prediction is stored, second is added and averaged */ if ((mb_type & MB_FORWARD) || (pict_type==P_TYPE)) { /* forward prediction, including zero MV in P pictures */ if (pict_struct==FRAME_PICTURE) { /* frame picture */ if ((motion_type==MC_FRAME) || !(mb_type & MB_FORWARD)) { /* frame-based prediction in frame picture */ Pred(oldref,0,cur,0, lx,16,16,bx,by,PMV[0][0][0],PMV[0][0][1],0); } else if (motion_type==MC_FIELD) { /* field-based prediction in frame picture * * note scaling of the vertical coordinates (by, PMV[][0][1]) * from frame to field! */ /* top field prediction */ Pred(oldref,mv_field_sel[0][0],cur,0, lx<<1,16,8,bx,by>>1,PMV[0][0][0],PMV[0][0][1]>>1,0); /* bottom field prediction */ Pred(oldref,mv_field_sel[1][0],cur,1, lx<<1,16,8,bx,by>>1,PMV[1][0][0],PMV[1][0][1]>>1,0); } else if (motion_type==MC_DMV) { /* dual prime prediction */ /* calculate derived motion vectors */ CalDMV(DMV,dmvector,PMV[0][0][0],PMV[0][0][1]>>1); /* predict top field from top field */ Pred(oldref,0,cur,0, lx<<1,16,8,bx,by>>1,PMV[0][0][0],PMV[0][0][1]>>1,0); /* predict bottom field from bottom field */ Pred(oldref,1,cur,1, lx<<1,16,8,bx,by>>1,PMV[0][0][0],PMV[0][0][1]>>1,0); /* predict and add to top field from bottom field */ Pred(oldref,1,cur,0, lx<<1,16,8,bx,by>>1,DMV[0][0],DMV[0][1],1); /* predict and add to bottom field from top field */ Pred(oldref,0,cur,1, lx<<1,16,8,bx,by>>1,DMV[1][0],DMV[1][1],1); } else { /* invalid motion_type in frame picture */ } } else /* TOP_FIELD or BOTTOM_FIELD */ { /* field picture */ currentfield = (pict_struct==BOTTOM_FIELD); /* determine which frame to use for prediction */ if ((pict_type==P_TYPE) && secondfield && (currentfield!=mv_field_sel[0][0])) predframe = newref; /* same frame */ else predframe = oldref; /* previous frame */ if ((motion_type==MC_FIELD) || !(mb_type & MB_FORWARD)) { /* field-based prediction in field picture */ Pred(predframe,mv_field_sel[0][0],cur,currentfield, lx<<1,16,16,bx,by,PMV[0][0][0],PMV[0][0][1],0); } else if (motion_type==MC_16X8) { /* 16 x 8 motion compensation in field picture */ /* upper half */ Pred(predframe,mv_field_sel[0][0],cur,currentfield, lx<<1,16,8,bx,by,PMV[0][0][0],PMV[0][0][1],0); /* determine which frame to use for lower half prediction */ if ((pict_type==P_TYPE) && secondfield && (currentfield!=mv_field_sel[1][0])) predframe = newref; /* same frame */ else predframe = oldref; /* previous frame */ /* lower half */ Pred(predframe,mv_field_sel[1][0],cur,currentfield, lx<<1,16,8,bx,by+8,PMV[1][0][0],PMV[1][0][1],0); } else if (motion_type==MC_DMV) { /* dual prime prediction */ /* determine which frame to use for prediction */ if (secondfield) predframe = newref; /* same frame */ else predframe = oldref; /* previous frame */ /* calculate derived motion vectors */ CalDMV(DMV,dmvector,PMV[0][0][0],PMV[0][0][1]); /* predict from field of same parity */ Pred(oldref,currentfield,cur,currentfield, lx<<1,16,16,bx,by,PMV[0][0][0],PMV[0][0][1],0); /* predict from field of opposite parity */ Pred(predframe,!currentfield,cur,currentfield, lx<<1,16,16,bx,by,DMV[0][0],DMV[0][1],1); } else { /* invalid motion_type in field picture */ } } addflag = 1; /* next prediction (if any) will be averaged with this one */ } if (mb_type & MB_BACKWARD) { /* backward prediction */ if (pict_struct==FRAME_PICTURE) { /* frame picture */ if (motion_type==MC_FRAME) { /* frame-based prediction in frame picture */ Pred(newref,0,cur,0, lx,16,16,bx,by,PMV[0][1][0],PMV[0][1][1],addflag); } else { /* field-based prediction in frame picture * * note scaling of the vertical coordinates (by, PMV[][1][1]) * from frame to field! */ /* top field prediction */ Pred(newref,mv_field_sel[0][1],cur,0, lx<<1,16,8,bx,by>>1,PMV[0][1][0],PMV[0][1][1]>>1,addflag); /* bottom field prediction */ Pred(newref,mv_field_sel[1][1],cur,1, lx<<1,16,8,bx,by>>1,PMV[1][1][0],PMV[1][1][1]>>1,addflag); } } else /* TOP_FIELD or BOTTOM_FIELD */ { /* field picture */ currentfield = (pict_struct==BOTTOM_FIELD); if (motion_type==MC_FIELD) { /* field-based prediction in field picture */ Pred(newref,mv_field_sel[0][1],cur,currentfield, lx<<1,16,16,bx,by,PMV[0][1][0],PMV[0][1][1],addflag); } else if (motion_type==MC_16X8) { /* 16 x 8 motion compensation in field picture */ /* upper half */ Pred(newref,mv_field_sel[0][1],cur,currentfield, lx<<1,16,8,bx,by,PMV[0][1][0],PMV[0][1][1],addflag); /* lower half */ Pred(newref,mv_field_sel[1][1],cur,currentfield, lx<<1,16,8,bx,by+8,PMV[1][1][0],PMV[1][1][1],addflag); } else { /* invalid motion_type in field picture */ } } } } /*--------------------------------------------------------- predict a rectangular block (all three components) src: source frame (Y,U,V) sfield: source field select (0: frame or top field, 1: bottom field) dst: destination frame (Y,U,V) dfield: destination field select (0: frame or top field, 1: bottom field) the following values are in luminance picture (frame or field) dimensions lx: distance of vertically adjacent pels (selects frame or field pred.) w,h: width and height of block (only 16x16 or 16x8 are used) x,y: coordinates of destination block dx,dy: half pel motion vector addflag: store or add (= average) prediction ---------------------------------------------------------*/ void Pred(unsigned char *src[], int sfield, unsigned char *dst[], int dfield, int lx, int w, int h, int x, int y, int dx, int dy, int addflag) { int cc; for (cc=0; cc<3; cc++) { if (cc==1) { /* scale for color components */ if (g_stSequenceData.stExtension.nChromaFormat==CHROMA420) { /* vertical */ h >>= 1; y >>= 1; dy /= 2; } if (g_stSequenceData.stExtension.nChromaFormat!=CHROMA444) { /* horizontal */ w >>= 1; x >>= 1; dx /= 2; lx >>= 1; } } PredComp(src[cc]+(sfield?lx>>1:0),dst[cc]+(dfield?lx>>1:0), lx,w,h,x,y,dx,dy,addflag); } } /*--------------------------------------------------------- low level prediction routine src: prediction source dst: prediction destination lx: line width (for both src and dst) x,y: destination coordinates dx,dy: half pel motion vector w,h: size of prediction block addflag: store or add prediction ---------------------------------------------------------*/ inline void PredComp(unsigned char *src, unsigned char *dst, int lx, int w, int h, int x, int y, int dx, int dy, int addflag) { int xint, xh, yint, yh; int i, j; unsigned char *s, *d; /* half pel scaling */ xint = dx>>1; /* integer part */ xh = dx & 1; /* half pel flag */ yint = dy>>1; yh = dy & 1; /* origins */ s = src + lx*(y+yint) + (x+xint); /* motion vector */ d = dst + lx*y + x; if (!xh && !yh) { if (addflag) { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (unsigned int)(d[i]+s[i]+1)>>1; s+= lx; d+= lx; } } else { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = s[i]; s+= lx; d+= lx; } } } else if (!xh && yh) if (addflag) { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (d[i] + ((unsigned int)(s[i]+s[i+lx]+1)>>1)+1)>>1; s+= lx; d+= lx; } } else { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (unsigned int)(s[i]+s[i+lx]+1)>>1; s+= lx; d+= lx; } } else if (xh && !yh) if (addflag) { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (d[i] + ((unsigned int)(s[i]+s[i+1]+1)>>1)+1)>>1; s+= lx; d+= lx; } } else { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (unsigned int)(s[i]+s[i+1]+1)>>1; s+= lx; d+= lx; } } else /* if (xh && yh) */ if (addflag) { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (d[i] + ((unsigned int)(s[i]+s[i+1]+s[i+lx]+s[i+lx+1]+2)>>2)+1)>>1; s+= lx; d+= lx; } } else { for (j=0; j<h; j++) { for (i=0; i<w; i++) d[i] = (unsigned int)(s[i]+s[i+1]+s[i+lx]+s[i+lx+1]+2)>>2; s+= lx; d+= lx; } } } /*--------------------------------------------------------- calculate derived motion vectors (DMV) for dual prime prediction dmvector[2]: differential motion vectors (-1,0,+1) mvx,mvy: motion vector (for same parity) DMV[2][2]: derived motion vectors (for opposite parity) uses global variables pict_struct and topfirst Notes: - all vectors are in field coordinates (even for frame pictures) ---------------------------------------------------------*/ void CalDMV(int DMV[][2], int *dmvector, int mvx,int mvy) { if (g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) { if (g_stPictureData.stCodingExtension.bTopFirst) { /* vector for prediction of top field from bottom field */ DMV[0][0] = ((mvx +(mvx>0))>>1) + dmvector[0]; DMV[0][1] = ((mvy +(mvy>0))>>1) + dmvector[1] - 1; /* vector for prediction of bottom field from top field */ DMV[1][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0]; DMV[1][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] + 1; } else { /* vector for prediction of top field from bottom field */ DMV[0][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0]; DMV[0][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] - 1; /* vector for prediction of bottom field from top field */ DMV[1][0] = ((mvx +(mvx>0))>>1) + dmvector[0]; DMV[1][1] = ((mvy +(mvy>0))>>1) + dmvector[1] + 1; } } else { /* vector for prediction from field of opposite 'parity' */ DMV[0][0] = ((mvx+(mvx>0))>>1) + dmvector[0]; DMV[0][1] = ((mvy+(mvy>0))>>1) + dmvector[1]; /* correct for vertical field shift */ if (g_stPictureData.stCodingExtension.nPictStruct==TOP_FIELD) DMV[0][1]--; else DMV[0][1]++; } } inline void ClearBlock(unsigned char *cur[], int i0, int j0) { const int width = g_stSequenceData.stHeader.nWidth; const int width2 = g_stSequenceData.stHeader.nWidth2; const int chroma_format = g_stSequenceData.stExtension.nChromaFormat; const int chrog_width = g_stSequenceData.stHeader.nChromWidth; const int chrog_width2 = g_stSequenceData.stHeader.nChromWidth2; int i, j, w, h; unsigned char *p; if(g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) { p = cur[0] + width + i0 + width2*j0; } else { p = cur[0] + i0 + width2*j0; } for (j=0; j<16; j++) { for (i=0; i<16; i++) p[i] = 128; p+= width2; } w = h = 16; if (chroma_format!=CHROMA444) { i0>>=1; w>>=1; } if (chroma_format==CHROMA420) { j0>>=1; h>>=1; } if(g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) { p = cur[1] + chrog_width + i0 + chrog_width2*j0; } else { p = cur[1] + i0 + chrog_width2*j0; } for (j=0; j<h; j++) { for (i=0; i<w; i++) p[i] = 128; p+= chrog_width2; } if(g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) { p = cur[2] + chrog_width + i0 + chrog_width2*j0; } else { p = cur[2] + i0 + chrog_width2*j0; } for (j=0; j<h; j++) { for (i=0; i<w; i++) p[i] = 128; p+= chrog_width2; } } /*========================================================= ò╧î` =========================================================*/ /*--------------------------------------------------------- subtract prediction and transform prediction error ---------------------------------------------------------*/ void Transform(unsigned char* pred[], unsigned char* cur[], MACROBLOCKINFO* mbi, short blocks[][64]) { const int width = g_stSequenceData.stHeader.nWidth; const int width2 = g_stSequenceData.stHeader.nWidth2; const int chroma_format = g_stSequenceData.stExtension.nChromaFormat; const int chrog_width = g_stSequenceData.stHeader.nChromWidth; const int chrog_width2 = g_stSequenceData.stHeader.nChromWidth2; const int block_count = g_stSequenceData.stHeader.nBlockCount; int i, j, i1, j1, k, n, cc, offs, lx; k = 0; for (j=0; j<g_stSequenceData.stHeader.nHeight2; j+=16) for (i=0; i<width; i+=16) { for (n=0; n<block_count; n++) { cc = (n<4) ? 0 : (n&1)+1; /* color component index */ if (cc==0) { /* luminance */ if ((g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) && mbi[k].dct_type) { /* field DCT */ offs = i + ((n&1)<<3) + width*(j+((n&2)>>1)); lx = width<<1; } else { /* frame DCT */ offs = i + ((n&1)<<3) + width2*(j+((n&2)<<2)); lx = width2; } if (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) offs += width; } else { /* chrominance */ /* scale coordinates */ i1 = (chroma_format==CHROMA444) ? i : i>>1; j1 = (chroma_format!=CHROMA420) ? j : j>>1; if ((g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) && mbi[k].dct_type && (chroma_format!=CHROMA420)) { /* field DCT */ offs = i1 + (n&8) + chrog_width*(j1+((n&2)>>1)); lx = chrog_width<<1; } else { /* frame DCT */ offs = i1 + (n&8) + chrog_width2*(j1+((n&2)<<2)); lx = chrog_width2; } if (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) offs += chrog_width; } SubPred(pred[cc]+offs,cur[cc]+offs,lx,blocks[k*block_count+n]); g_cDCT.fDCT(blocks[k*block_count+n]); } k++; } } /*--------------------------------------------------------- inverse transform prediction error and add prediction ---------------------------------------------------------*/ void ITransform(unsigned char* pred[], unsigned char* cur[], MACROBLOCKINFO* mbi, short blocks[][64]) { const int width = g_stSequenceData.stHeader.nWidth; const int width2 = g_stSequenceData.stHeader.nWidth2; const int chroma_format = g_stSequenceData.stExtension.nChromaFormat; const int chrog_width = g_stSequenceData.stHeader.nChromWidth; const int chrog_width2 = g_stSequenceData.stHeader.nChromWidth2; const int block_count = g_stSequenceData.stHeader.nBlockCount; int i, j, i1, j1, k, n, cc, offs, lx; k = 0; for (j=0; j<g_stSequenceData.stHeader.nHeight2; j+=16) for (i=0; i<width; i+=16) { for (n=0; n<block_count; n++) { cc = (n<4) ? 0 : (n&1)+1; /* color component index */ if (cc==0) { /* luminance */ if ((g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) && mbi[k].dct_type) { /* field DCT */ offs = i + ((n&1)<<3) + width*(j+((n&2)>>1)); lx = width<<1; } else { /* frame DCT */ offs = i + ((n&1)<<3) + width2*(j+((n&2)<<2)); lx = width2; } if (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) offs += width; } else { /* chrominance */ /* scale coordinates */ i1 = (chroma_format==CHROMA444) ? i : i>>1; j1 = (chroma_format!=CHROMA420) ? j : j>>1; if ((g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) && mbi[k].dct_type && (chroma_format!=CHROMA420)) { /* field DCT */ offs = i1 + (n&8) + chrog_width*(j1+((n&2)>>1)); lx = chrog_width<<1; } else { /* frame DCT */ offs = i1 + (n&8) + chrog_width2*(j1+((n&2)<<2)); lx = chrog_width2; } if (g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD) offs += chrog_width; } g_cDCT.iDCT(blocks[k*block_count+n]); AddPred(pred[cc]+offs,cur[cc]+offs,lx,blocks[k*block_count+n]); } k++; } } /*--------------------------------------------------------- add prediction and prediction error, saturate to 0...255 ---------------------------------------------------------*/ inline void AddPred(unsigned char* pred, unsigned char* cur, int lx,short* blk) { int i, j; for (j=0; j<8; j++) { for (i=0; i<8; i++) cur[i] = g_stPictureStruct.pClippingTable[blk[i] + pred[i]]; blk+= 8; cur+= lx; pred+= lx; } } /*--------------------------------------------------------- subtract prediction from block data ---------------------------------------------------------*/ inline void SubPred(unsigned char* pred,unsigned char* cur,int lx,short* blk) { int i, j; for (j=0; j<8; j++) { for (i=0; i<8; i++) blk[i] = cur[i] - pred[i]; blk+= 8; cur+= lx; pred+= lx; } } /*--------------------------------------------------------- select between frame and field DCT preliminary version: based on inter-field correlation ---------------------------------------------------------*/ void DCTTypeEstimation(unsigned char* pred, unsigned char* cur, MACROBLOCKINFO* mbi) { const int width = g_stSequenceData.stHeader.nWidth; short blk0[128], blk1[128]; int i, j, i0, j0, k, offs, s0, s1, sq0, sq1, s01; double d, r; k = 0; for (j0=0; j0<g_stSequenceData.stHeader.nHeight2; j0+=16) for (i0=0; i0<width; i0+=16) { if (g_stPictureData.stCodingExtension.bFramePredDCT || g_stPictureData.stCodingExtension.nPictStruct!=FRAME_PICTURE) mbi[k].dct_type = 0; else { /* interlaced frame picture */ /* * calculate prediction error (cur-pred) for top (blk0) * and bottom field (blk1) */ for (j=0; j<8; j++) { offs = width*((j<<1)+j0) + i0; for (i=0; i<16; i++) { blk0[16*j+i] = cur[offs] - pred[offs]; blk1[16*j+i] = cur[offs+width] - pred[offs+width]; offs++; } } /* correlate fields */ s0=s1=sq0=sq1=s01=0; for (i=0; i<128; i++) { s0+= blk0[i]; sq0+= blk0[i]*blk0[i]; s1+= blk1[i]; sq1+= blk1[i]*blk1[i]; s01+= blk0[i]*blk1[i]; } d = (sq0-(s0*s0)/128.0)*(sq1-(s1*s1)/128.0); if (d>0.0) { r = (s01-(s0*s1)/128.0)/sqrt(d); if (r>0.5) mbi[k].dct_type = 0; /* frame DCT */ else mbi[k].dct_type = 1; /* field DCT */ } else mbi[k].dct_type = 1; /* field DCT */ } k++; } } /*========================================================= PutPicture =========================================================*/ /*--------------------------------------------------------- quantization / variable length encoding of a complete picture ---------------------------------------------------------*/ TOMPGRET PutPicture(unsigned char* frame) { TOMPGRET ret; int i, j, k, comp, cc; int mb_type; int PMV[2][2][2]; int prev_mquant; int cbp, MBAinc; RcInitPic(frame); /* set up rate control */ /* picture header and picture coding extension */ PutPictureHeader(); prev_mquant = RcStartMb(); /* initialize quantization parameter */ k = 0; for (j=0; j<g_stSequenceData.stHeader.nMacroBlocksHeight2; j++) { /* macroblock row loop */ for (i=0; i<g_stSequenceData.stHeader.nMacroBlocksWidth; i++) { /* macroblock loop */ if (i==0) { /* slice header (6.2.4) */ g_stSystemData.alignbits(); g_stSystemData.putbits(SLICE_MIN_START+j,32); /* slice_start_code */ /* quantiser_scale_code */ if(g_stPictureData.stCodingExtension.bQScaleType) { g_stSystemData.putbits(g_MapNonLinearQuantizationArray[prev_mquant],5); } else { g_stSystemData.putbits(prev_mquant >> 1,5); } g_stSystemData.putbits(0,1); /* extra_bit_slice */ /* reset predictors */ for(cc=0; cc<3; cc++) g_stPictureStruct.nDcDctPredictionArray[cc] = 0; PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; PMV[0][1][0]=PMV[0][1][1]=PMV[1][1][0]=PMV[1][1][1]=0; MBAinc = i + 1; /* first MBAinc denotes absolute position */ } mb_type = g_stPictureStruct.pstMacroBlockInfo[k].mb_type; /* determine mquant (rate control) */ g_stPictureStruct.pstMacroBlockInfo[k].mquant = RcCalcMQuant(k); /* quantize macroblock */ if (mb_type & MB_INTRA) { for (comp=0; comp<g_stSequenceData.stHeader.nBlockCount; comp++) QuantIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+comp], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+comp], g_stPictureData.stCodingExtension.nDCPrecision, g_stPictureStruct.uIntraQArray, g_stPictureStruct.uRecipIntraQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); g_stPictureStruct.pstMacroBlockInfo[k].cbp = cbp = (1<<g_stSequenceData.stHeader.nBlockCount) - 1; } else { cbp = 0; for (comp=0;comp<g_stSequenceData.stHeader.nBlockCount;comp++) cbp = (cbp<<1) | QuantNonIntra(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+comp], g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+comp], g_stPictureStruct.uInterQArray, g_stPictureStruct.uRecipInterQArray, g_stPictureStruct.pstMacroBlockInfo[k].mquant); g_stPictureStruct.pstMacroBlockInfo[k].cbp = cbp; if (cbp) mb_type|= MB_PATTERN; } /* output mquant if it has changed */ if (cbp && prev_mquant!=g_stPictureStruct.pstMacroBlockInfo[k].mquant) mb_type|= MB_QUANT; /* check if macroblock can be skipped */ if (i!=0 && i!=g_stSequenceData.stHeader.nMacroBlocksWidth-1 && !cbp) { /* no DCT coefficients and neither first nor last macroblock of slice */ if (g_stPictureData.stHeader.nPictType==P_TYPE && !(mb_type&MB_FORWARD)) { /* P picture, no motion vectors -> skip */ /* reset predictors */ for(cc=0; cc<3; cc++) g_stPictureStruct.nDcDctPredictionArray[cc] = 0; PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; PMV[0][1][0]=PMV[0][1][1]=PMV[1][1][0]=PMV[1][1][1]=0; g_stPictureStruct.pstMacroBlockInfo[k].mb_type = mb_type; g_stPictureStruct.pstMacroBlockInfo[k].skipped = 1; MBAinc++; k++; continue; } if (g_stPictureData.stHeader.nPictType==B_TYPE && g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE && g_stPictureStruct.pstMacroBlockInfo[k].motion_type==MC_FRAME && ((g_stPictureStruct.pstMacroBlockInfo[k-1].mb_type^mb_type)&(MB_FORWARD|MB_BACKWARD))==0 && (!(mb_type&MB_FORWARD) || (PMV[0][0][0]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][0][0] && PMV[0][0][1]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][0][1])) && (!(mb_type&MB_BACKWARD) || (PMV[0][1][0]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][1][0] && PMV[0][1][1]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][1][1]))) { /* conditions for skipping in B frame pictures: * - must be frame predicted * - must be the same prediction type (forward/backward/interp.) * as previous macroblock * - relevant vectors (forward/backward/both) have to be the same * as in previous macroblock */ g_stPictureStruct.pstMacroBlockInfo[k].mb_type = mb_type; g_stPictureStruct.pstMacroBlockInfo[k].skipped = 1; MBAinc++; k++; continue; } if (g_stPictureData.stHeader.nPictType==B_TYPE && g_stPictureData.stCodingExtension.nPictStruct!=FRAME_PICTURE && g_stPictureStruct.pstMacroBlockInfo[k].motion_type==MC_FIELD && ((g_stPictureStruct.pstMacroBlockInfo[k-1].mb_type^mb_type)&(MB_FORWARD|MB_BACKWARD))==0 && (!(mb_type&MB_FORWARD) || (PMV[0][0][0]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][0][0] && PMV[0][0][1]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][0][1] && g_stPictureStruct.pstMacroBlockInfo[k].mv_field_sel[0][0]==(g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD))) && (!(mb_type&MB_BACKWARD) || (PMV[0][1][0]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][1][0] && PMV[0][1][1]==g_stPictureStruct.pstMacroBlockInfo[k].MV[0][1][1] && g_stPictureStruct.pstMacroBlockInfo[k].mv_field_sel[0][1]==(g_stPictureData.stCodingExtension.nPictStruct==BOTTOM_FIELD)))) { /* conditions for skipping in B field pictures: * - must be field predicted * - must be the same prediction type (forward/backward/interp.) * as previous macroblock * - relevant vectors (forward/backward/both) have to be the same * as in previous macroblock * - relevant motion_vertical_field_selects have to be of same * parity as current field */ g_stPictureStruct.pstMacroBlockInfo[k].mb_type = mb_type; g_stPictureStruct.pstMacroBlockInfo[k].skipped = 1; MBAinc++; k++; continue; } } /* macroblock cannot be skipped */ g_stPictureStruct.pstMacroBlockInfo[k].skipped = 0; /* there's no VLC for 'No MC, Not Coded': * we have to transmit (0,0) motion vectors */ if (g_stPictureData.stHeader.nPictType==P_TYPE && !cbp && !(mb_type&MB_FORWARD)) mb_type|= MB_FORWARD; PutMacroblockAddressIncement(MBAinc); /* macroblock_address_increment */ MBAinc = 1; PutMacroblockType(g_stPictureData.stHeader.nPictType,mb_type); /* macroblock type */ if (mb_type & (MB_FORWARD|MB_BACKWARD) && !g_stPictureData.stCodingExtension.bFramePredDCT) g_stSystemData.putbits(g_stPictureStruct.pstMacroBlockInfo[k].motion_type,2); if (g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE && cbp && !g_stPictureData.stCodingExtension.bFramePredDCT) g_stSystemData.putbits(g_stPictureStruct.pstMacroBlockInfo[k].dct_type,1); if (mb_type & MB_QUANT) { if(g_stPictureData.stCodingExtension.bQScaleType) { g_stSystemData.putbits(g_MapNonLinearQuantizationArray[g_stPictureStruct.pstMacroBlockInfo[k].mquant],5); } else { g_stSystemData.putbits(g_stPictureStruct.pstMacroBlockInfo[k].mquant>>1,5); } prev_mquant = g_stPictureStruct.pstMacroBlockInfo[k].mquant; } if (mb_type & MB_FORWARD) { /* forward motion vectors, update predictors */ PutMotionVectors(g_stPictureStruct.pstMacroBlockInfo[k].MV, PMV, g_stPictureStruct.pstMacroBlockInfo[k].mv_field_sel, g_stPictureStruct.pstMacroBlockInfo[k].dmvector, 0, g_stPictureStruct.pstMacroBlockInfo[k].motion_type, g_stPictureData.stCodingExtension.nForwHorFCode, g_stPictureData.stCodingExtension.nForwVertFCode); } if (mb_type & MB_BACKWARD) { /* backward motion vectors, update predictors */ PutMotionVectors(g_stPictureStruct.pstMacroBlockInfo[k].MV, PMV, g_stPictureStruct.pstMacroBlockInfo[k].mv_field_sel, g_stPictureStruct.pstMacroBlockInfo[k].dmvector, 1, g_stPictureStruct.pstMacroBlockInfo[k].motion_type, g_stPictureData.stCodingExtension.nBackHorFCode, g_stPictureData.stCodingExtension.nBackVertFCode); } if (mb_type & MB_PATTERN) { PutCodedBlockPattern((cbp >> (g_stSequenceData.stHeader.nBlockCount-6)) & 63); if (g_stSequenceData.stExtension.nChromaFormat!=CHROMA420) g_stSystemData.putbits(cbp,g_stSequenceData.stHeader.nBlockCount-6); } for (comp=0; comp<g_stSequenceData.stHeader.nBlockCount; comp++) { /* block loop */ if (cbp & (1<<(g_stSequenceData.stHeader.nBlockCount-1-comp))) { if (mb_type & MB_INTRA) { cc = (comp<4) ? 0 : (comp&1)+1; if((ret = PutIntraCodedBlock(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+comp],cc))!=TR_OK) { return ret; } } else { if((ret = PutNonIntraCodedBlock(g_stPictureStruct.pBlocksArray[k*g_stSequenceData.stHeader.nBlockCount+comp]))!=TR_OK) { return ret; } } } } /* reset predictors */ if (!(mb_type & MB_INTRA)) for (cc=0; cc<3; cc++) g_stPictureStruct.nDcDctPredictionArray[cc] = 0; if (mb_type & MB_INTRA || (g_stPictureData.stHeader.nPictType==P_TYPE && !(mb_type & MB_FORWARD))) { PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; PMV[0][1][0]=PMV[0][1][1]=PMV[1][1][0]=PMV[1][1][1]=0; } g_stPictureStruct.pstMacroBlockInfo[k].mb_type = mb_type; k++; } } RcUpdatePict(); VBVEndOfPicture(); return TR_OK; } /*--------------------------------------------------------- output motion vectors (6.2.5.2, 6.3.16.2) this routine also updates the predictions for motion vectors (PMV) ---------------------------------------------------------*/ void PutMotionVectors(int MV[2][2][2], int PMV[2][2][2], int mv_field_sel[2][2], int dmvector[2], int s, int motion_type, int hor_f_code, int vert_f_code) { if(g_stPictureData.stCodingExtension.nPictStruct==FRAME_PICTURE) { if(motion_type==MC_FRAME) { /* frame prediction */ PutMotionVector(MV[0][s][0]-PMV[0][s][0],hor_f_code); PutMotionVector(MV[0][s][1]-PMV[0][s][1],vert_f_code); PMV[0][s][0]=PMV[1][s][0]=MV[0][s][0]; PMV[0][s][1]=PMV[1][s][1]=MV[0][s][1]; } else if (motion_type==MC_FIELD) { /* field prediction */ g_stSystemData.putbits(mv_field_sel[0][s],1); PutMotionVector(MV[0][s][0]-PMV[0][s][0],hor_f_code); PutMotionVector((MV[0][s][1]>>1)-(PMV[0][s][1]>>1),vert_f_code); g_stSystemData.putbits(mv_field_sel[1][s],1); PutMotionVector(MV[1][s][0]-PMV[1][s][0],hor_f_code); PutMotionVector((MV[1][s][1]>>1)-(PMV[1][s][1]>>1),vert_f_code); PMV[0][s][0]=MV[0][s][0]; PMV[0][s][1]=MV[0][s][1]; PMV[1][s][0]=MV[1][s][0]; PMV[1][s][1]=MV[1][s][1]; } else { /* dual prime prediction */ PutMotionVector(MV[0][s][0]-PMV[0][s][0],hor_f_code); PutDMVector(dmvector[0]); PutMotionVector((MV[0][s][1]>>1)-(PMV[0][s][1]>>1),vert_f_code); PutDMVector(dmvector[1]); PMV[0][s][0]=PMV[1][s][0]=MV[0][s][0]; PMV[0][s][1]=PMV[1][s][1]=MV[0][s][1]; } } else { /* field picture */ if (motion_type==MC_FIELD) { /* field prediction */ g_stSystemData.putbits(mv_field_sel[0][s],1); PutMotionVector(MV[0][s][0]-PMV[0][s][0],hor_f_code); PutMotionVector(MV[0][s][1]-PMV[0][s][1],vert_f_code); PMV[0][s][0]=PMV[1][s][0]=MV[0][s][0]; PMV[0][s][1]=PMV[1][s][1]=MV[0][s][1]; } else if (motion_type==MC_16X8) { /* 16x8 prediction */ g_stSystemData.putbits(mv_field_sel[0][s],1); PutMotionVector(MV[0][s][0]-PMV[0][s][0],hor_f_code); PutMotionVector(MV[0][s][1]-PMV[0][s][1],vert_f_code); g_stSystemData.putbits(mv_field_sel[1][s],1); PutMotionVector(MV[1][s][0]-PMV[1][s][0],hor_f_code); PutMotionVector(MV[1][s][1]-PMV[1][s][1],vert_f_code); PMV[0][s][0]=MV[0][s][0]; PMV[0][s][1]=MV[0][s][1]; PMV[1][s][0]=MV[1][s][0]; PMV[1][s][1]=MV[1][s][1]; } else { /* dual prime prediction */ PutMotionVector(MV[0][s][0]-PMV[0][s][0],hor_f_code); PutDMVector(dmvector[0]); PutMotionVector(MV[0][s][1]-PMV[0][s][1],vert_f_code); PutDMVector(dmvector[1]); PMV[0][s][0]=PMV[1][s][0]=MV[0][s][0]; PMV[0][s][1]=PMV[1][s][1]=MV[0][s][1]; } } } /*========================================================= Put Mpeg =========================================================*/ /*--------------------------------------------------------- generate variable length codes for an intra-coded block (6.2.6, 6.3.17) ---------------------------------------------------------*/ inline TOMPGRET PutIntraCodedBlock(short* blk,int cc) { TOMPGRET ret; int n, dct_diff, run, signed_level; const unsigned char* scan_array = (g_stPictureData.stCodingExtension.bAltScan?g_AlternateScanArray:g_ZigZagScanArray); /* DC coefficient (7.2.1) */ dct_diff = blk[0] - g_stPictureStruct.nDcDctPredictionArray[cc]; /* difference to previous block */ g_stPictureStruct.nDcDctPredictionArray[cc] = blk[0]; if (cc==0) { if((ret = PutLuminanceDCCoefficient(dct_diff))!=TR_OK) { return ret; } } else { if((ret = PutChrominanceDCCoefficient(dct_diff))!=TR_OK) { return ret; } } /* AC coefficients (7.2.2) */ run = 0; for (n=1; n<64; n++) { /* use appropriate entropy scanning pattern */ signed_level = blk[scan_array[n]]; if (signed_level!=0) { if((ret = PutAC(run,signed_level,g_stPictureData.stCodingExtension.bIntravlc))!=TR_OK) { return ret; } run = 0; } else run++; /* count zero coefficients */ } /* End of Block -- normative block punctuation */ if (g_stPictureData.stCodingExtension.bIntravlc) g_stSystemData.putbits(6,4); /* 0110 (Table B-15) */ else g_stSystemData.putbits(2,2); /* 10 (Table B-14) */ return TR_OK; } /*--------------------------------------------------------- generate variable length codes for a non-intra-coded block (6.2.6, 6.3.17) ---------------------------------------------------------*/ inline TOMPGRET PutNonIntraCodedBlock(short* blk) { TOMPGRET ret; int n, run, signed_level, first; const unsigned char* scan_array = (g_stPictureData.stCodingExtension.bAltScan? g_AlternateScanArray:g_ZigZagScanArray); run = 0; first = 1; for (n=0; n<64; n++) { /* use appropriate entropy scanning pattern */ signed_level = blk[scan_array[n]]; if (signed_level!=0) { if (first) { /* first coefficient in non-intra block */ if((ret = PutACFirst(run,signed_level))!=TR_OK) { return ret; } first = 0; } else { if((ret = PutAC(run,signed_level,0))!=TR_OK) { return ret; } } run = 0; } else run++; /* count zero coefficients */ } /* End of Block -- normative block punctuation */ g_stSystemData.putbits(2,2); return TR_OK; } /*--------------------------------------------------------- generate variable length code for a motion vector component (7.6.3.1) ---------------------------------------------------------*/ void PutMotionVector(int dmv,int f_code) { int r_size, f, vmin, vmax, dv, temp, motion_code, motion_residual; r_size = f_code - 1; /* number of fixed length code ('residual') bits */ f = 1<<r_size; vmin = -16*f; /* lower range limit */ vmax = 16*f - 1; /* upper range limit */ dv = 32*f; /* fold vector difference into [vmin...vmax] */ if (dmv>vmax) dmv-= dv; else if (dmv<vmin) dmv+= dv; /* check value */ if (dmv<vmin || dmv>vmax) { } /* split dmv into motion_code and motion_residual */ temp = ((dmv<0) ? -dmv : dmv) + f - 1; motion_code = temp>>r_size; if (dmv<0) motion_code = -motion_code; motion_residual = temp & (f-1); PutMotionCode(motion_code); /* variable length code */ if (r_size!=0 && motion_code!=0) g_stSystemData.putbits(motion_residual,r_size); /* fixed length code */ } /*========================================================= Put Variable Length Codes =========================================================*/ /*--------------------------------------------------------- generate variable length code for luminance DC coefficient ---------------------------------------------------------*/ inline TOMPGRET PutLuminanceDCCoefficient(const int val) { return PutDC(g_DCTDcSizeLuminanceArray,val); } /*--------------------------------------------------------- generate variable length code for chrominance DC coefficient ---------------------------------------------------------*/ inline TOMPGRET PutChrominanceDCCoefficient(const int val) { return PutDC(g_DCTDcSizeChrominanceArray,val); } /*--------------------------------------------------------- generate variable length code for DC coefficient (7.2.1) ---------------------------------------------------------*/ TOMPGRET PutDC(const void* pvtab,const int val) { const sVLCtable *tab = (sVLCtable*)pvtab; int absval, size; absval = (val<0) ? -val : val; /* abs(val) */ if (absval>255) { /* should never happen */ return TR_DC_VALUE_OUT_OF_RANGE; } /* compute dct_dc_size */ size = 0; while (absval) { absval >>= 1; size++; } /* generate VLC for dct_dc_size (Table B-12 or B-13) */ g_stSystemData.putbits(tab[size].code,tab[size].len); /* append fixed length code (dc_dct_differential) */ if (size!=0) { if (val>=0) absval = val; else absval = val + (1<<size) - 1; /* val + (2 ^ size) - 1 */ g_stSystemData.putbits(absval,size); } return TR_OK; } /*--------------------------------------------------------- generate variable length code for first coefficient of a non-intra block (7.2.2.2) ---------------------------------------------------------*/ inline TOMPGRET PutACFirst(const int run,const int val) { if (run==0 && (val==1 || val==-1)) { /* these are treated differently */ g_stSystemData.putbits(2|(val<0?1:0),2); /* generate '1s' (s=sign), (Table B-14, line 2) */ return TR_OK; } else { return PutAC(run,val,0); /* no difference for all others */ } return TR_OK; } /*--------------------------------------------------------- generate variable length code for other DCT coefficients (7.2.2) ---------------------------------------------------------*/ TOMPGRET PutAC(const int run,const int signed_level,const int vlcformat) { int level, len; VLCtable *ptab; level = (signed_level<0) ? -signed_level : signed_level; /* abs(signed_level) */ /* make sure run and level are valid */ if (run<0 || run>63 || level==0 || level>255) { return TR_AC_VALUE_OUT_OF_RANGE; } len = 0; if (run<2 && level<41) { /* vlcformat selects either of Table B-14 / B-15 */ if (vlcformat) ptab = &g_DCTCodeTable1a[run][level-1]; else ptab = &g_DCTCodeTable1[run][level-1]; len = ptab->len; } else if (run<32 && level<6) { /* vlcformat selects either of Table B-14 / B-15 */ if (vlcformat) ptab = &g_DCTCodeTable2a[run-2][level-1]; else ptab = &g_DCTCodeTable2[run-2][level-1]; len = ptab->len; } if (len!=0) /* a VLC code exists */ { g_stSystemData.putbits(ptab->code,len); g_stSystemData.putbits(signed_level<0,1); /* sign */ } else { /* no VLC for this (run, level) combination: use escape coding (7.2.2.3) */ g_stSystemData.putbits(1l,6); /* Escape */ g_stSystemData.putbits(run,6); /* 6 bit code for run */ /* ISO/IEC 11172-2 uses a 8 or 16 bit code */ if (signed_level>127) g_stSystemData.putbits(0,8); if (signed_level<-127) g_stSystemData.putbits(128,8); g_stSystemData.putbits(signed_level,8); } return TR_OK; } /*--------------------------------------------------------- generate variable length code for macroblock_address_increment ---------------------------------------------------------*/ inline void PutMacroblockAddressIncement(int addrinc) { while (addrinc>33) { g_stSystemData.putbits(0x08,11); /* macroblock_escape */ addrinc-= 33; } g_stSystemData.putbits(g_AddRincArray[addrinc-1].code,g_AddRincArray[addrinc-1].len); } /*--------------------------------------------------------- generate variable length code for macroblock_type ---------------------------------------------------------*/ inline void PutMacroblockType(const int pict_type,const int mb_type) { g_stSystemData.putbits(g_MacroblockTypeTable[pict_type-1][mb_type].code, g_MacroblockTypeTable[pict_type-1][mb_type].len); } /*--------------------------------------------------------- generate variable length code for motion_code ---------------------------------------------------------*/ inline void PutMotionCode(const int motion_code) { int abscode = abs(motion_code); /* abs(motion_code) */ g_stSystemData.putbits(g_MotionCodeArray[abscode].code,g_MotionCodeArray[abscode].len); if (motion_code!=0) g_stSystemData.putbits(motion_code<0,1); /* sign, 0=positive, 1=negative */ } /*--------------------------------------------------------- generate variable length code for dmvector[t] ---------------------------------------------------------*/ void PutDMVector(const int dmv) { if (dmv==0) g_stSystemData.putbits(0,1); else if (dmv>0) g_stSystemData.putbits(2,2); else g_stSystemData.putbits(3,2); } /*--------------------------------------------------------- generate variable length code for coded_block_pattern 4:2:2, 4:4:4 not implemented ---------------------------------------------------------*/ inline void PutCodedBlockPattern(const int cbp) { g_stSystemData.putbits(g_CodedBlockPatternArray[cbp].code,g_CodedBlockPatternArray[cbp].len); } /*========================================================= ù╩Äqë╗âeü[âuâïè╓îW =========================================================*/ inline int QuantIntra(short* src,short* dst,int dc_prec, unsigned char* quant_mat,unsigned short* recip_quant_mat, int mquant) { int i; int x, y, d; static short mquantm3p2div4[4]; static unsigned short recip_mquant[4]; x = src[0]; d = 8>>dc_prec; /* intra_dc_mult */ dst[0] = (x>=0) ? (x+(d>>1))/d : -((-x+(d>>1))/d); /* round(x/d) */ for (i=1; i<64; i++) { x = src[i]; d = quant_mat[i]; y = (32*(x>=0 ? x : -x) + (d>>1))/d; /* round(32*x/quant_mat) */ //y = (32*(x>=0 ? x : -x))/d; d = (3*mquant+2)>>2; y = (y+d)/(2*mquant); /* (y+0.75*mquant) / (2*mquant) */ /* clip to syntax limits */ if (y > 255) { y = 255; } dst[i] = (x>=0) ? y : -y; } return 1; } inline int QuantNonIntra(short* src,short* dst, unsigned char* quant_mat, unsigned short* recip_quant_mat, int mquant) { int i; int x, y, d; int nzflag; nzflag = 0; for (i=0; i<64; i++) { x = src[i]; d = quant_mat[i]; y = (32*(x>=0 ? x : -x) + (d>>1))/d; // round(32*x/quant_mat) y /= (2*mquant); // clip to syntax limits if (y > 255) { y = 255; } if ((dst[i] = (x>=0 ? y : -y)) != 0) nzflag=1; } return nzflag; } /*--------------------------------------------------------- MPEG-1 inverse quantization ---------------------------------------------------------*/ void IQuantIntra(short* src,short* dst,int dc_prec,unsigned char* quant_mat,int mquant) { int i, val; dst[0] = src[0] << (3-dc_prec); for (i=1; i<64; i++) { val = (int)(src[i]*quant_mat[i]*mquant)/16; /* mismatch control */ if ((val&1)==0 && val!=0) val+= (val>0) ? -1 : 1; /* saturation */ dst[i] = (val>2047) ? 2047 : ((val<-2048) ? -2048 : val); } } void IQuantNonIntra(short* src,short* dst, unsigned char* quant_mat, int mquant) { int i, val; for (i=0; i<64; i++) { val = src[i]; if (val!=0) { val = (int)((2*val+(val>0 ? 1 : -1))*quant_mat[i]*mquant)/32; /* mismatch control */ if ((val&1)==0 && val!=0) val+= (val>0) ? -1 : 1; } /* saturation */ dst[i] = (val>2047) ? 2047 : ((val<-2048) ? -2048 : val); } }