www.pudn.com > coremp4-1.0.zip > mp4_decode.cpp
/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ***************************************************************************** * * Authors: * * Andrea Graziani (Ag): Original source code (Open Divx Decoder 0.4a). * Marc Dukette (Md) and * Pedro Mateu (Pm) and * Gabor Kovacs (Kg) Heavily modified and optimized code * Michal Bacik Porting into C++, optimizations * ****************************************************************************/ #include "Util.h" #include "SoftIdct.h" #include "profiling.h" #include "VideoCodec.h" #include "C_buffer.h" //---------------------------- #define MPEG4_ERROR_QPEL 0x200 #define MPEG4_ERROR_INTERLACE 0x201 #define MPEG4_ERROR_GMC 0x202 #define MPEG4_ERROR_PARTITIONING 0x205 #define POSX(pos) ((pos) & (MAX_MACROBLOCKS_X-1)) #define POSY(pos) ((pos) >> MB_X2) // maximun picture size in macroblocks (16x16) // example MB_X2=6 -> 2^6=64 macroblocks -> 1024 pixels #define MB_X2 6 #define MB_Y2 6 #define MAX_MACROBLOCKS_X (1<>16) //---------------------------- //macros for fast bit-access in frequently-used locations #define GetBits1() ((bits << bitpos++) < 0) #define LoadBits() \ if(bitpos >= 8){ \ do{ \ bits = (bits << 8) | *bit_ptr++; \ bitpos -= 8; \ }while(bitpos >= 8); \ } #define ShowBits(n) ((dword)(bits << bitpos) >> (32-(n))) #define FlushBits(n) bitpos += n //---------------------------- #if 0 static int Divide(int a, int b){ return ((a>0) ? (a+(b>>1))/b : (a-(b>>1))/b); } #else //optimized division for most common divisors // (using multiplication by reciprocal in 12.20 fixed-point format) #define RET_DIV(a, N) return (a*N+524288) >> 20; #define RET_SHR(a, N, S) return (a+N) >> S; static int Divide(int a, int b){ switch(b){ case 1: return a; case 2: RET_SHR(a, 1, 1); case 4: RET_SHR(a, 2, 2); case 8: RET_SHR(a, 4, 3); case 16: RET_SHR(a, 8, 4); case 32: RET_SHR(a, 16, 5); case 3: RET_DIV(a, 349525); case 5: RET_DIV(a, 209715); case 6: RET_DIV(a, 174763); case 7: RET_DIV(a, 149797); case 9: RET_DIV(a, 116509); case 10: RET_DIV(a, 104858); case 11: RET_DIV(a, 95325); case 12: RET_DIV(a, 87382); case 13: RET_DIV(a, 80660); case 14: RET_DIV(a, 74899); case 15: RET_DIV(a, 69905); case 17: RET_DIV(a, 61681); case 18: RET_DIV(a, 58255); case 19: RET_DIV(a, 55189); case 20: RET_DIV(a, 52429); case 21: RET_DIV(a, 49933); case 22: RET_DIV(a, 47663); case 23: RET_DIV(a, 45591); case 24: RET_DIV(a, 43691); case 25: RET_DIV(a, 41943); case 26: RET_DIV(a, 40330); case 27: RET_DIV(a, 38837); case 28: RET_DIV(a, 37450); case 29: RET_DIV(a, 36158); case 30: RET_DIV(a, 34953); case 31: RET_DIV(a, 33825); } if(a>0) a += b>>1; else a -= b>>1; return a/b; } #endif //---------------------------- static dword FindHighestBit(dword mask){ int base = 0; if(mask&0xffff0000){ base = 16; mask >>= 16; } if(mask&0x0000ff00){ base += 8; mask >>= 8; } if(mask&0x000000f0){ base += 4; mask >>= 4; } static const int lut[] = {-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3}; return base + lut[mask]; } //---------------------------- static void Clear32(void* p){ int *i = (int*)p; i[0] = 0; i[1] = 0; i[2] = 0; i[3] = 0; i[4] = 0; i[5] = 0; i[6] = 0; i[7] = 0; } //---------------------------- //---------------------------- struct S_bit_reader{ int bits, pos; const byte *ptr, *bitend; void Init(const byte *stream, int len){ bits = 0; pos = 32; ptr = stream; bitend = stream+len+6; //adding more just to be safe Flush(0); } inline void Flush(int n){ pos += n; } //---------------------------- // n=1..24 (or ..32 after bytealign) inline dword Show(int n) const{ return (dword)(bits << pos) >> (32-n); } //---------------------------- inline int Get(int n){ int i = Show(n); Flush(n); return i; } //---------------------------- inline bool Get1(){ return Get(1); } inline int BitsToNextByte() const{ return 8-(pos & 7); } inline bool Eof() const{ return (ptr >= bitend); } inline int ShowLarge(int n){ int i = Show(n); i |= *ptr >> (40-n-pos); return i; } inline void Rewind(const byte *p){ pos = 32; ptr = p; } inline void ByteAlign(){ pos = (pos + 7) & ~7; } void Load(); //---------------------------- int GetCodedBlockPatternLuminance(); int GetMCodedBlockPatternChrominance_i(); int GetMCodedBlockPatternChrominance_p(); void GetQuantMatrix(byte m[2*8*8]); //---------------------------- // Get single move value from bitstream. int GetMoveData(int fcode); //---------------------------- // Get movement vector from stream. The vector is stored in stream as delta, so pass in previous value, which is added to read values. int GetMovementVectorPair(int fcode, int prev_vector_pair); int GetDCsizeLum(); int GetDCsizeChr(); int GetDCdiff(int dct_dc_size); }; //---------------------------- void S_bit_reader::Load(){ if(pos >= 8){ do{ bits = (bits << 8) | *ptr++; pos -= 8; }while(pos >= 8); } } //---------------------------- // Meaning of CBPY (Coded Block Pattern-luminance), indicates which blocks within a macroblock contain coded coefficients. // First byte encodes bits 0-3 associated with 2x2 luminance (Y) blocks in one 16x16 maxroblock. // Second byte encodes number of bits representing this information in the bitstream. static const byte tab_coded_block_pattern_luminance[] = { 0, 0, 0, 0, 6, 6, 9,6, 8,5, 8,5, 4,5, 4,5, 2, 5, 2, 5, 1, 5, 1,5, 0,4, 0,4, 0,4, 0,4, 12,4, 12,4, 12,4, 12,4, 10,4, 10,4, 10,4, 10,4, 14,4, 14,4, 14,4, 14,4, 5,4, 5,4, 5,4, 5,4, 13,4, 13,4, 13,4, 13,4, 3,4, 3,4, 3,4, 3,4, 11,4, 11,4, 11,4, 11,4, 7,4, 7,4, 7,4, 7,4 }; //---------------------------- int S_bit_reader::GetCodedBlockPatternLuminance(){ //max 6 bits int code = Show(6); if(code < 2) return -1; if(code >= 0x30){ Flush(2); return 0xf; } code *= 2; Flush(tab_coded_block_pattern_luminance[code+1]); return tab_coded_block_pattern_luminance[code]; } //---------------------------- static const byte MCBPCtabIntra[] = { 0, 0, //-1,0 20,6, 36, 6, 52,6, 4,4, 4, 4, 4, 4, 4, 4, 19, 3, 19,3, 19,3, 19, 3, 19, 3, 19,3, 19, 3, 19,3, 35,3, 35, 3, 35, 3, 35,3, 35, 3, 35,3, 35,3, 35, 3, 51, 3, 51,3, 51, 3, 51,3, 51,3, 51, 3, 51, 3, 51,3 }; //---------------------------- int S_bit_reader::GetMCodedBlockPatternChrominance_i(){ //max 9bits int code = Show(9); if(code == 1){ Flush(9); // stuffing return 0; } if(code < 8) return -1; code >>= 3; if(code >= 32){ Flush(1); return 3; } code *= 2; Flush(MCBPCtabIntra[code+1]); return MCBPCtabIntra[code]; } //---------------------------- static const byte MCBPCtabInter[] = { 0,0, //-1,0 0,9, 52,9, 36,9, 20,9, 49,9, 35,8, 35,8, 19,8, 19,8, 50,8, 50,8, 51,7, 51,7, 51,7, 51,7, 34,7, 34,7, 34,7, 34,7, 18,7, 18,7, 18,7, 18,7, 33,7, 33,7, 33,7, 33,7, 17,7, 17,7, 17,7, 17,7, 4,6, 4,6, 4,6, 4,6, 4,6, 4,6, 4,6, 4,6, 48,6, 48,6, 48,6, 48,6, 48,6, 48,6, 48,6, 48,6, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 3,5, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 32,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 16,4, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 2,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3, 1,3 }; //---------------------------- int S_bit_reader::GetMCodedBlockPatternChrominance_p(){ //max 9bits int code = Show(9); if(code == 0) return -1; if(code >= 256){ Flush(1); return 0; } code *= 2; Flush(MCBPCtabInter[code+1]); return MCBPCtabInter[code]; } //---------------------------- static const byte scan_table[3][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 }, { 0, 1, 2, 3, 8, 9, 16, 17, 10, 11, 4, 5, 6, 7, 15, 14, 13, 12, 19, 18, 24, 25, 32, 33, 26, 27, 20, 21, 22, 23, 28, 29, 30, 31, 34, 35, 40, 41, 48, 49, 42, 43, 36, 37, 38, 39, 44, 45, 46, 47, 50, 51, 56, 57, 58, 59, 52, 53, 54, 55, 60, 61, 62, 63 }, { 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 } }; //---------------------------- void S_bit_reader::GetQuantMatrix(byte* m){ int i = 0; int last, value = 0; do{ last = value; Load(); value = Get(8); m[scan_table[0][i++]] = (byte)value; }while(value!=0 && i<64); i--; while(i < 64) m[scan_table[0][i++]] = (byte)last; } //---------------------------- #define _M(mv, bits) (mv<<8) | (bits) static const short move_vector_table_0[14] = { _M(3,4),_M(-3,4),_M(2,3),_M(2,3),_M(-2,3),_M(-2,3),_M(1,2),_M(1,2), _M(1,2),_M(1,2),_M(-1,2),_M(-1,2),_M(-1,2),_M(-1,2), }, move_vector_table_1[96] = { _M(12,10),_M(-12,10), _M(11,10),_M(-11,10),_M(10,9),_M(10,9),_M(-10,9),_M(-10,9),_M(9,9),_M(9,9), _M(-9,9),_M(-9,9),_M(8,9),_M(8,9),_M(-8,9),_M(-8,9),_M(7,7),_M(7,7), _M(7,7),_M(7,7),_M(7,7),_M(7,7),_M(7,7),_M(7,7),_M(-7,7),_M(-7,7), _M(-7,7),_M(-7,7),_M(-7,7),_M(-7,7),_M(-7,7),_M(-7,7),_M(6,7),_M(6,7), _M(6,7),_M(6,7),_M(6,7),_M(6,7),_M(6,7),_M(6,7),_M(-6,7),_M(-6,7), _M(-6,7),_M(-6,7),_M(-6,7),_M(-6,7),_M(-6,7),_M(-6,7),_M(5,7),_M(5,7), _M(5,7),_M(5,7),_M(5,7),_M(5,7),_M(5,7),_M(5,7),_M(-5,7),_M(-5,7), _M(-5,7),_M(-5,7),_M(-5,7),_M(-5,7),_M(-5,7),_M(-5,7),_M(4,6),_M(4,6), _M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(4,6), _M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(4,6),_M(-4,6),_M(-4,6), _M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6), _M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6),_M(-4,6) }, move_vector_table_2[124] = { _M(32,12),_M(-32,12), _M(31,12),_M(-31,12),_M(30,11),_M(30,11),_M(-30,11),_M(-30,11),_M(29,11),_M(29,11), _M(-29,11),_M(-29,11),_M(28,11),_M(28,11),_M(-28,11),_M(-28,11),_M(27,11),_M(27,11), _M(-27,11),_M(-27,11),_M(26,11),_M(26,11),_M(-26,11),_M(-26,11),_M(25,11),_M(25,11), _M(-25,11),_M(-25,11),_M(24,10),_M(24,10),_M(24,10),_M(24,10),_M(-24,10),_M(-24,10), _M(-24,10),_M(-24,10),_M(23,10),_M(23,10),_M(23,10),_M(23,10),_M(-23,10),_M(-23,10), _M(-23,10),_M(-23,10),_M(22,10),_M(22,10),_M(22,10),_M(22,10),_M(-22,10),_M(-22,10), _M(-22,10),_M(-22,10),_M(21,10),_M(21,10),_M(21,10),_M(21,10),_M(-21,10),_M(-21,10), _M(-21,10),_M(-21,10),_M(20,10),_M(20,10),_M(20,10),_M(20,10),_M(-20,10),_M(-20,10), _M(-20,10),_M(-20,10),_M(19,10),_M(19,10),_M(19,10),_M(19,10),_M(-19,10),_M(-19,10), _M(-19,10),_M(-19,10),_M(18,10),_M(18,10),_M(18,10),_M(18,10),_M(-18,10),_M(-18,10), _M(-18,10),_M(-18,10),_M(17,10),_M(17,10),_M(17,10),_M(17,10),_M(-17,10),_M(-17,10), _M(-17,10),_M(-17,10),_M(16,10),_M(16,10),_M(16,10),_M(16,10),_M(-16,10),_M(-16,10), _M(-16,10),_M(-16,10),_M(15,10),_M(15,10),_M(15,10),_M(15,10),_M(-15,10),_M(-15,10), _M(-15,10),_M(-15,10),_M(14,10),_M(14,10),_M(14,10),_M(14,10),_M(-14,10),_M(-14,10), _M(-14,10),_M(-14,10),_M(13,10),_M(13,10),_M(13,10),_M(13,10),_M(-13,10),_M(-13,10), _M(-13,10),_M(-13,10) }; //---------------------------- int S_bit_reader::GetMoveData(int fcode){ Load(); if(Get1()){ //no movement (coded in 1 bit) return 0; } int code = Show(12); if(code >= 512) code = move_vector_table_0[(code >> 8) - 2]; else if(code >= 128) code = move_vector_table_1[(code >> 2) - 32]; else code = move_vector_table_2[code-4]; Flush(code & 255); code >>= 8; if(fcode){ code <<= fcode; int res = Get(fcode); res -= (1 << fcode) - 1; if(code < 0) res = -res; code += res; } return code; } //---------------------------- int S_bit_reader::GetMovementVectorPair(int fcode, int prev_vector_pair){ --fcode; int mv_x = GetMoveData(fcode); int mv_y = GetMoveData(fcode); int range = 1 << (fcode+6); int high = (range/2) - 1; int low = -(range/2); mv_x += MOVE_VECTOR_X(prev_vector_pair); if(mv_x < low) mv_x += range; if(mv_x > high) mv_x -= range; mv_y += MOVE_VECTOR_Y(prev_vector_pair); if(mv_y < low) mv_y += range; if(mv_y > high) mv_y -= range; return MAKE_MOVEMENT_VECTOR_PAIR(mv_x, mv_y); } //---------------------------- int S_bit_reader::GetDCsizeLum(){ int code = Show(11); for(int i=0; i<8; i++){ if((code >> i)==1){ Flush(11-i); return 12-i; } } code >>= 8; if(code == 1){ Flush(3); return 4; } if(code == 2){ Flush(3); return 3; } if(code == 3){ Flush(3); return 0; } code >>=1; if(code == 2){ Flush(2); return 2; } if(code == 3){ Flush(2); return 1; } return 0; } //---------------------------- int S_bit_reader::GetDCsizeChr(){ int i,code = Show(12); for (i=0;i<10;i++){ if ((code >> i)==1) { Flush(12-i); return 12-i; } } return 3 - Get(2); } //---------------------------- int S_bit_reader::GetDCdiff(int dct_dc_size){ int code = Show(32); //we need only dct_dc_size bits (but in the higher bits) int adj = 0; Flush(dct_dc_size); if(code >= 0) adj = (-1 << dct_dc_size) + 1; return adj + ((dword)code >> (32-dct_dc_size)); } //---------------------------- //---------------------------- //---------------------------- class C_mp4_decode_imp: public C_mp4_decode{ enum{ RESCUE = 0x80 }; enum{ VOL_START_CODE_MASK = 0x0f }; enum{ VOL_START_CODE = 0x120, VOP_START_CODE = 0x1b6 }; enum{ ASPECT_SQUARE = 1, ASPECT_625TYPE_43 = 2, ASPECT_525TYPE_43 =3, ASPECT_625TYPE_169 = 8, ASPECT_525TYPE_169 = 9, ASPECT_CUSTOM = 15, }; //---------------------------- enum E_FRAME_TYPE{ I_VOP, P_VOP, B_VOP, S_VOP, N_VOP, }; //---------------------------- enum{ INTER = 0, //prediction INTER_Q = 1, INTER4V = 2, INTRA = 3, //no prediction INTRA_Q = 4, }; //---------------------------- enum E_SPRITE_TYPE{ SPRITE_NO, SPRITE_STATIC, SPRITE_GMC, }; //---------------------------- enum{ DIRECT = 0, INTERPOLATE = 1, BACKWARD = 2, FORWARD = 3, }; //---------------------------- #ifdef PROFILE C_profiler *prof; #endif C_softidct soft_idct; S_bit_reader bit_reader; bool has_b_frames; int quant_precision; //in how many bits is quantizier encoded dword video_sx, video_sy; bool valid_vol; //VOL information was successfully read bool interlaced; bool ac_pred_flag; int frame_index; int last_ref_frame_index; //index of last I or P frame //frame index, when the last time particular macro-block changed // (need to add 'block_update_base_indx' for getting actual index) // also contains RESCUE flag byte block_update_data[MAX_MACROBLOCKS_X*MAX_MACROBLOCKS_Y]; int mb_pos_end; //index of end of macro-block table 'block_update_data' int block_update_base_indx; //base frame index for above (typically set to last 'P' frame's index) int mb_xsize, mb_ysize; //number of macroblocks for width/height E_SPRITE_TYPE sprite_type; int quantizer; int intra_dc_threshold; int fcode_forward, fcode_backward; int resync_marker_bits; short _block[64+16/sizeof(short)]; short *block_8x8; //16-byte aligned, used for 8x8 block computations (intra, inter) int time_increment_resolution; //video framerate * 1000 int last_ref_time; //last time of reference frame (I or P, not B) // b-frame int time_pp, time_bp; int last_bframe; int trb, trb_trd; //8.8 fixed-point //---------------------------- int resyncpos; int time_increment_bits; bool quant_type; //type of quantizied - mpeg (true) or mpeg4 (false) // motion compensation buffer int *mv_buf; //32bytes aligned int* _mv_buf; int mv_bufmask; int move_buf_invalid; //packed B frame C_buffer packed_b_frame; dword packed_b_size; int refframe; byte quant_matrix[2][8*8]; // [intra / inter] short dc_lum[4*MAX_MACROBLOCKS_X*2]; //[4][double width row] short ac_left_lum[2][8]; //[lower/upper][8] short ac_top_lum[2*MAX_MACROBLOCKS_X][8]; //[double witdh row][8] short dc_chr[2][2*MAX_MACROBLOCKS_X]; //[U/V][2][normal width row] short ac_left_chr[2][8]; //[U/V][8] short ac_top_chr[MAX_MACROBLOCKS_X][2][8];//[normal width row][U/V][8] int _mv_bufrow[4*(MAX_MACROBLOCKS_X+1)+32/sizeof(int)]; // add one extra block for left border + 32align //---------------------------- void RescuePredict(int pos); //---------------------------- // Read all frame's headers (VOL, VOP). Return true if VOP was found and read. bool ReadFrameHeaders(E_FRAME_TYPE &frame_prediction_type); //---------------------------- // Read volume header. void ReadHeader_vol(); //---------------------------- // Read picture header. void ReadHeader_vop(E_FRAME_TYPE &frame_prediction_type); //---------------------------- int ReSync(); //---------------------------- bool ResyncMarker(); //---------------------------- int GetPreviousMoveVector(int block_num, int pos); //---------------------------- int Vld_block_mpeg(const word *table, const byte *scan, int len); int Vld_block_mpeg4(const word *table, const byte *scan, int len); //---------------------------- short *Dc_recon(int block_num, int pos, int dc_scaler, int &predict_dir); void Ac_recon(int block_num, int pos, int predict_dir); //---------------------------- // Decode block with no prediction. void BlockIntra(int pos, int coded_block_pattern); //---------------------------- // Decode block with prediction. void BlockInter(int coded_block_pattern); //---------------------------- void BlockDirect(int pos, int dmv, int coded_block_pattern); //---------------------------- void IVOP(); void PVOP(); void BVOP(); //---------------------------- bool Frame(const byte *strm, int len, bool drop_b_frames); public: //---------------------------- bool SetIDCTBufferCount(int count); bool UpdateCount(); bool Init(); bool Mp4_vop(const byte *strm, bool drop_b_frames, E_FRAME_TYPE frame_prediction_type); virtual bool Process(const byte *packet, dword len, bool drop_b_frames, S_yuv_image &out); //---------------------------- C_mp4_decode_imp(dword sx, dword sy, void *profiler); ~C_mp4_decode_imp(){ delete[] _mv_buf; } }; //---------------------------- bool C_mp4_decode_imp::Process(const byte *packet, dword len, bool drop_b_frames, S_yuv_image &out){ out.type = 0; #ifdef PROFILE if(frame_index==10) prof->ResetAverage(); #endif /* if(frame_to_show!=-1){ // pending frame? SendData(out); frame_to_show = -1; assert(out.type); return true; } */ // if(has_b_frames && FrameTime>0 && RefTime >= FrameTime) // RefTime -= FrameTime; if(!Frame(packet, len, drop_b_frames)) return false; //send to display if(!soft_idct.GetBuffer(out.y, out.u, out.v)){ assert(0); return false; } out.pitch = soft_idct.GetBufferPitch(); out.type = 1; return true; } //---------------------------- bool C_mp4_decode_imp::SetIDCTBufferCount(int c){ if(!soft_idct.SetBufferCount(c)) return false; return UpdateCount(); } //---------------------------- // msb..lsb // 4bit flushbits, 1bit last, 6bit run, 5bit level //no prediction static const word vld_intra[112+96+120+64+16] = { 0x7881,0x7861,0x70c1,0x78a1,0x70e1,0x7042,0x7023,0x7009, 0x6802,0x6802,0x60a1,0x60a1,0x6841,0x6841,0x6821,0x6821, 0x6081,0x6081,0x6061,0x6061,0x6008,0x6008,0x6007,0x6007, 0x6022,0x6022,0x6006,0x6006,0x5041,0x5041,0x5041,0x5041, 0x5005,0x5005,0x5005,0x5005,0x5004,0x5004,0x5004,0x5004, 0x4801,0x4801,0x4801,0x4801,0x4801,0x4801,0x4801,0x4801, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x3002,0x3002,0x3002,0x3002,0x3002,0x3002,0x3002,0x3002, 0x3002,0x3002,0x3002,0x3002,0x3002,0x3002,0x3002,0x3002, 0x4021,0x4021,0x4021,0x4021,0x4021,0x4021,0x4021,0x4021, 0x4003,0x4003,0x4003,0x4003,0x4003,0x4003,0x4003,0x4003, 0xa012,0xa011,0x99c1,0x99c1,0x99a1,0x99a1,0x9981,0x9981, 0x9961,0x9961,0x9941,0x9941,0x9822,0x9822,0x9804,0x9804, 0x9181,0x9181,0x9161,0x9161,0x90e2,0x90e2,0x90c2,0x90c2, 0x90a2,0x90a2,0x9063,0x9063,0x9043,0x9043,0x9026,0x9026, 0x9025,0x9025,0x9010,0x9010,0x9082,0x9082,0x900f,0x900f, 0x900e,0x900e,0x900d,0x900d,0x8901,0x8901,0x8901,0x8901, 0x88e1,0x88e1,0x88e1,0x88e1,0x88c1,0x88c1,0x88c1,0x88c1, 0x8803,0x8803,0x8803,0x8803,0x8141,0x8141,0x8141,0x8141, 0x8121,0x8121,0x8121,0x8121,0x8101,0x8101,0x8101,0x8101, 0x8921,0x8921,0x8921,0x8921,0x8062,0x8062,0x8062,0x8062, 0x8024,0x8024,0x8024,0x8024,0x800c,0x800c,0x800c,0x800c, 0x800b,0x800b,0x800b,0x800b,0x800a,0x800a,0x800a,0x800a, 0xb807,0xb807,0xb806,0xb806,0xb016,0xb016,0xb015,0xb015, 0xa842,0xa842,0xa842,0xa842,0xa823,0xa823,0xa823,0xa823, 0xa805,0xa805,0xa805,0xa805,0xa1a1,0xa1a1,0xa1a1,0xa1a1, 0xa0a3,0xa0a3,0xa0a3,0xa0a3,0xa102,0xa102,0xa102,0xa102, 0xa083,0xa083,0xa083,0xa083,0xa064,0xa064,0xa064,0xa064, 0xa044,0xa044,0xa044,0xa044,0xa027,0xa027,0xa027,0xa027, 0xa014,0xa014,0xa014,0xa014,0xa013,0xa013,0xa013,0xa013, 0xb017,0xb017,0xb018,0xb018,0xb028,0xb028,0xb122,0xb122, 0xb862,0xb862,0xb882,0xb882,0xb9e1,0xb9e1,0xba01,0xba01, 0xc019,0xc01a,0xc01b,0xc029,0xc0c3,0xc02a,0xc045,0xc0e3, 0xc1c1,0xc808,0xc8a2,0xc8c2,0xca21,0xca41,0xca61,0xca81, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x0a1b,0x0405,0x0303,0x0303,0x0202,0x0101,0x0101,0x0001, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0308,0x0202,0x0202,0x0102,0x0101,0x0101,0x0101,0x0101, 0x0101,0x0101,0x0001,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0f02,0x080a,0x0304,0x0202,0x0202,0x0102,0x0101,0x0101, 0x1501,0x0207,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101 }; //---------------------------- //prediction static const word vld_inter[112+96+120+64+16] = { 0x7901,0x78e1,0x78c1,0x78a1,0x7181,0x7161,0x7141,0x7004, 0x6881,0x6881,0x6861,0x6861,0x6841,0x6841,0x6821,0x6821, 0x6121,0x6121,0x6101,0x6101,0x60e1,0x60e1,0x60c1,0x60c1, 0x6022,0x6022,0x6003,0x6003,0x50a1,0x50a1,0x50a1,0x50a1, 0x5081,0x5081,0x5081,0x5081,0x5061,0x5061,0x5061,0x5061, 0x4801,0x4801,0x4801,0x4801,0x4801,0x4801,0x4801,0x4801, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001,0x2001, 0x3021,0x3021,0x3021,0x3021,0x3021,0x3021,0x3021,0x3021, 0x3021,0x3021,0x3021,0x3021,0x3021,0x3021,0x3021,0x3021, 0x4041,0x4041,0x4041,0x4041,0x4041,0x4041,0x4041,0x4041, 0x4002,0x4002,0x4002,0x4002,0x4002,0x4002,0x4002,0x4002, 0xa009,0xa008,0x9b01,0x9b01,0x9ae1,0x9ae1,0x9ac1,0x9ac1, 0x9aa1,0x9aa1,0x9a81,0x9a81,0x9a61,0x9a61,0x9a41,0x9a41, 0x9a21,0x9a21,0x9802,0x9802,0x92c1,0x92c1,0x92a1,0x92a1, 0x9281,0x9281,0x9261,0x9261,0x9241,0x9241,0x9221,0x9221, 0x9201,0x9201,0x91e1,0x91e1,0x9082,0x9082,0x9062,0x9062, 0x9007,0x9007,0x9006,0x9006,0x8a01,0x8a01,0x8a01,0x8a01, 0x89e1,0x89e1,0x89e1,0x89e1,0x89c1,0x89c1,0x89c1,0x89c1, 0x89a1,0x89a1,0x89a1,0x89a1,0x8981,0x8981,0x8981,0x8981, 0x8961,0x8961,0x8961,0x8961,0x8941,0x8941,0x8941,0x8941, 0x8921,0x8921,0x8921,0x8921,0x81c1,0x81c1,0x81c1,0x81c1, 0x81a1,0x81a1,0x81a1,0x81a1,0x8042,0x8042,0x8042,0x8042, 0x8023,0x8023,0x8023,0x8023,0x8005,0x8005,0x8005,0x8005, 0xb822,0xb822,0xb803,0xb803,0xb00b,0xb00b,0xb00a,0xb00a, 0xab81,0xab81,0xab81,0xab81,0xab61,0xab61,0xab61,0xab61, 0xab41,0xab41,0xab41,0xab41,0xab21,0xab21,0xab21,0xab21, 0xa122,0xa122,0xa122,0xa122,0xa102,0xa102,0xa102,0xa102, 0xa0e2,0xa0e2,0xa0e2,0xa0e2,0xa0c2,0xa0c2,0xa0c2,0xa0c2, 0xa0a2,0xa0a2,0xa0a2,0xa0a2,0xa063,0xa063,0xa063,0xa063, 0xa043,0xa043,0xa043,0xa043,0xa024,0xa024,0xa024,0xa024, 0xb00c,0xb00c,0xb025,0xb025,0xb2e1,0xb2e1,0xb301,0xb301, 0xbba1,0xbba1,0xbbc1,0xbbc1,0xbbe1,0xbbe1,0xbc01,0xbc01, 0xc026,0xc044,0xc083,0xc0a3,0xc0c3,0xc142,0xc321,0xc341, 0xcc21,0xcc41,0xcc61,0xcc81,0xcca1,0xccc1,0xcce1,0xcd01, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x060c,0x0304,0x0303,0x0203,0x0202,0x0102,0x0101,0x0101, 0x0101,0x0101,0x0101,0x0101,0x0101,0x0001,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0203,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101, 0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101, 0x0101,0x0101,0x0101,0x0101,0x0001,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x1b02,0x070b,0x0203,0x0102,0x0101,0x0101,0x0101,0x0101, 0x2901,0x0102,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101 }; //---------------------------- void C_mp4_decode_imp::RescuePredict(int pos){ int lumpos = 2*POSX(pos) + (POSY(pos) << (MB_X2+2)); if(pos>=MAX_MACROBLOCKS_X+1 && (block_update_data[pos-MAX_MACROBLOCKS_X-1]&RESCUE)){ //rescue -A- DC value dc_lum[(lumpos-MAX_MACROBLOCKS_X*2) & DC_LUM_MASK] = 1024; dc_chr[0][(pos-MAX_MACROBLOCKS_X) & DC_CHR_MASK] = 1024; dc_chr[1][(pos-MAX_MACROBLOCKS_X) & DC_CHR_MASK] = 1024; } //left if(pos>=1 && (block_update_data[pos-1]&RESCUE)){ // rescue -B- DC values dc_lum[(lumpos) & DC_LUM_MASK] = 1024; dc_lum[(lumpos+MAX_MACROBLOCKS_X*2) & DC_LUM_MASK] = 1024; dc_chr[0][pos & DC_CHR_MASK] = 1024; dc_chr[1][pos & DC_CHR_MASK] = 1024; if(ac_pred_flag){ //rescue -B- AC values Clear32(ac_left_lum); Clear32(ac_left_chr); } } //top if(pos>=MAX_MACROBLOCKS_X && (block_update_data[pos-MAX_MACROBLOCKS_X]&RESCUE)){ // rescue -C- DC values dc_lum[(lumpos+1-MAX_MACROBLOCKS_X*2) & DC_LUM_MASK] = 1024; dc_lum[(lumpos+2-MAX_MACROBLOCKS_X*2) & DC_LUM_MASK] = 1024; dc_chr[0][(pos+1-MAX_MACROBLOCKS_X) & DC_CHR_MASK] = 1024; dc_chr[1][(pos+1-MAX_MACROBLOCKS_X) & DC_CHR_MASK] = 1024; if(ac_pred_flag){ //rescue -C- AC values Clear32(ac_top_lum[lumpos & (MAX_MACROBLOCKS_X*2-1)]); Clear32(ac_top_chr[pos & (MAX_MACROBLOCKS_X-1)]); } } } //---------------------------- bool C_mp4_decode_imp::UpdateCount(){ int *mv; if(soft_idct.GetBufferCount() >= 3){ if(mv_bufmask != -1) move_buf_invalid = 1; mv_bufmask = -1; // full size mv buffer needed if(!_mv_buf){ int size = 32 + 4*sizeof(int) * (mb_pos_end+1); // add one extra block for left border _mv_buf = new int[size/4]; if(!_mv_buf) return false; MemSet(_mv_buf,0,size); } mv = _mv_buf; }else{ move_buf_invalid = 1; mv_bufmask = MAX_MACROBLOCKS_X-1; //only one row of mv buffer needed mv = _mv_bufrow; } mv_buf = (int*)(((int)mv + 31 + 4*sizeof(int)) & ~31); return true; } //---------------------------- bool C_mp4_decode_imp::Mp4_vop(const byte *strm, bool drop_b_frames, E_FRAME_TYPE frame_prediction_type){ resyncpos = 0; switch(frame_prediction_type){ case N_VOP: if(packed_b_size){ bit_reader.Init(packed_b_frame.Begin(), packed_b_size); packed_b_size = 0; if(ReadFrameHeaders(frame_prediction_type)){ bool ok = Mp4_vop(packed_b_frame.Begin(), drop_b_frames, frame_prediction_type); if(ok) return true; } } return (frame_index > 0); case P_VOP: //P (predicted) frames are predicted from the most recently reconstructed I or P frame //each macroblock in a P frame can either come with a vector and difference DCT coefficients for a close match in the last I or P, // or it can just be "intra" coded if there was no good match if(frame_index < 1) return false; //flow... case I_VOP: //I (intra) frames are coded as individual still images (JPG) //I/P-frames are the "reference" frames // they are decode into refframe // P-frames depend on last refenrence frame: refframe^1 refframe ^= 1; if(has_b_frames) ++last_bframe; int frame_to_show; if(!has_b_frames || frame_index==0) frame_to_show = refframe; // show this refframe else frame_to_show = refframe ^ 1; // show last refframe if(frame_prediction_type == I_VOP) { soft_idct.FrameStart(frame_index, refframe, -1, -1, frame_to_show); IVOP(); }else{ soft_idct.FrameStart(frame_index, refframe, refframe ^ 1, -1, frame_to_show); PVOP(); } break; case B_VOP: //B (bidirectional) frames are predicted from the closest two I or P frames, one in the past and one in the future if(frame_index < 2 || move_buf_invalid) return false; last_bframe = 0; if(drop_b_frames){ //ignore b-frames return false; } if(move_buf_invalid == 2){ move_buf_invalid = 0; MemSet(mv_buf, 0, 4*sizeof(int)*mb_pos_end); } assert(has_b_frames); /* if(soft_idct.GetBufferCount()<3){ SetIDCTBufferCount(3); if(move_buf_invalid) return false; } */ /* //save this b-frame if there was already a packed one if(frame_to_show >= 0){ //rewind bit_reader.Rewind(strm); return true; } */ soft_idct.FrameStart(-frame_index, 2, refframe,refframe ^ 1, 2); if(time_pp){ int TRB = time_pp - time_bp; trb = (TRB<<8) / time_pp; trb_trd = ((TRB - time_pp)<<8) / time_pp; }else{ trb = 0; trb_trd = 0; } BVOP(); break; default: return false; } frame_index++; //make sure that data in block_update_data don't overflow const int MAX_D = 128; if((frame_index - block_update_base_indx) >= MAX_D){ for(int pos=0; pos = (MAX_D-8)) i -= (MAX_D-8); else i = 0; block_update_data[pos] = i|r; } } block_update_base_indx += MAX_D-8; } return true; } //---------------------------- bool C_mp4_decode_imp::Frame(const byte* ptr, int len, bool drop_b_frames){ E_FRAME_TYPE frame_prediction_type; if(!len){ //null frame, return last rendered frame return true; } PROF_S(PROF_DECODE); bit_reader.Init(ptr, len); if(!ReadFrameHeaders(frame_prediction_type) || !valid_vol) return false; //invalid header or no vol information bool ok = Mp4_vop(ptr, drop_b_frames, frame_prediction_type); PROF_E(PROF_DECODE); #if defined _DEBUG && 0 //mark frame type if(ok){ byte *y, *u, *v; if(soft_idct.GetBuffer(y, u, v)){ dword pi = soft_idct.GetBufferPitch(); for(int i=0; i<3; i++){ byte *d = !i ? y : i==1 ? u : v; dword p = pi; dword s = 16; if(i){ p /= 2; s /= 2; d += p*4*4; }else d += p*8*4; byte val; switch(frame_prediction_type){ case I_VOP: val = !i ? 0x00 : i==1 ? 0x00 : 0xff; break; case P_VOP: val = !i ? 0x80 : i==1 ? 0x80 : 0x80; break; case B_VOP: val = !i ? 0x80 : i==1 ? 0xff : 0x00; break; default: val = !i ? 0x0 : i==1 ? 0x80 : 0x80; } for(int y=s; y--; ){ for(int x=s; x--; ){ d[x] = val; } d += p; } } } } #endif if(ok){ //check for packed b-frame const byte *pos = bit_reader.ptr - 4 + ((bit_reader.pos+7) >> 3); len -= (pos - ptr); if(len > 4){ if(!has_b_frames){ has_b_frames = true; SetIDCTBufferCount(3); } //save packed b-frame if(packed_b_frame.Size() < len) packed_b_frame.Resize((len+8+0x1fff) & ~0x1fff); packed_b_size = len; MemCpy(packed_b_frame.Begin(), pos, len); } } return ok; } //---------------------------- void C_mp4_decode_imp::Ac_recon(int block_num, int pos, int predict_dir){ int i; short *ac_top; short *ac_left; if(block_num < 4){ //Y ac_top = ac_top_lum[pos & (MAX_MACROBLOCKS_X*2-1)]; ac_left = ac_left_lum[(pos >> (MB_X2+1)) & 1]; i = MAX_MACROBLOCKS_X*2-1; //stride-1 }else{ //UV ac_top = ac_top_chr[pos & (MAX_MACROBLOCKS_X-1)][block_num & 1]; ac_left = ac_left_chr[block_num & 1]; i = MAX_MACROBLOCKS_X-1; //stride-1 } if(ac_pred_flag){ if(predict_dir == 1){ //TOP if(pos > i){ for(i = 1; i < 8; i++) block_8x8[i] = (short)(block_8x8[i] + ac_top[i]); } }else{ //LEFT if(pos & i){ for(i = 1; i < 8; i++) block_8x8[i<<3] = (short)(block_8x8[i<<3] + ac_left[i]); } } } for(i = 1; i < 8; i++){ ac_top[i] = block_8x8[i]; ac_left[i] = block_8x8[i<<3]; } } //---------------------------- short *C_mp4_decode_imp::Dc_recon(int block_num, int pos, int dc_scaler, int &predict_dir){ short *dc; int Fb = 1024; int Fc = 1024; if(block_num < 4){ //Y dc = dc_lum; if(pos >= MAX_MACROBLOCKS_X*2){ Fb = dc[(pos-MAX_MACROBLOCKS_X*2) & DC_LUM_MASK]; Fc = dc[(pos+1-MAX_MACROBLOCKS_X*2) & DC_LUM_MASK]; } dc += pos & DC_LUM_MASK; }else{ //UV dc = dc_chr[block_num & 1]; if(pos >= MAX_MACROBLOCKS_X){ Fb=dc[(pos-MAX_MACROBLOCKS_X) & DC_CHR_MASK]; Fc=dc[(pos+1-MAX_MACROBLOCKS_X) & DC_CHR_MASK]; } dc += pos & DC_CHR_MASK; } int Fa = dc[0]; if(Abs(Fb - Fa) < Abs(Fb - Fc)){ //TOP predict_dir = 1; Fa = Fc; }else{ //LEFT predict_dir = 0; } /* if(Fa>0) Fa += dc_scaler>>1; else Fa -= dc_scaler>>1; Fa /= dc_scaler; /**/ //assert(Divide(Fa, dc_scaler) == ( ((Fa>0)?(Fa+(dc_scaler>>1)):(Fa-(dc_scaler>>1)))/dc_scaler )); Fa = Divide(Fa, dc_scaler); ++dc; Fa *= dc_scaler; *dc = (short)Fa; return dc; } //---------------------------- static void ClearBlock(short *block){ int *i = (int*)block; const int *ie = i+32; do { i[3] = i[2] = i[1] = i[0] = 0; i[7] = i[6] = i[5] = i[4] = 0; i += 8; }while(i!=ie); } //---------------------------- void C_mp4_decode_imp::BlockIntra(int pos, int coded_block_pattern){ soft_idct.BeginBlock(POSX(pos), POSY(pos)); PROF_S(PROF_BLOCK_INTRA); short *block = block_8x8; //macroblock consists of four luminance blocks and the two spatially corresponding color difference blocks for(int i=0; i<6; ++i){ int subpos; int dc_scaler = quantizer; ClearBlock(block); bit_reader.Load(); //stream: 24bit available if(i < 4){ //Y if(dc_scaler >24) dc_scaler = dc_scaler*2 - 16; else if(dc_scaler>8) dc_scaler = (dc_scaler + 8); else if(dc_scaler>4) dc_scaler <<= 1; else dc_scaler = 8; //convert 1x1 -> 2x2 (accodring to block number) subpos = 2*POSX(pos) + (POSY(pos) << (MB_X2+2)); subpos += (i & 1) + ((i & 2) << MB_X2); }else{ //UV if(dc_scaler > 24) dc_scaler = (dc_scaler - 6); else if(dc_scaler > 4) dc_scaler = (dc_scaler + 13)>>1; else dc_scaler = 8; subpos = pos; } int len; if(quantizer < intra_dc_threshold){ int dct_dc_size, dct_dc_diff; dct_dc_diff = 0; dct_dc_size = i<4 ? bit_reader.GetDCsizeLum() : bit_reader.GetDCsizeChr(); //max11bit : max12bit if(dct_dc_size){ dct_dc_diff = bit_reader.GetDCdiff(dct_dc_size); if(dct_dc_size > 8) bit_reader.Flush(1); // marker bit } *block = (short)(dct_dc_diff * dc_scaler); len = 1; }else len = 0; //dc reconstruction, prediction direction int predict_dir; short *dc_addr = Dc_recon(i, subpos, dc_scaler, predict_dir); int scantype; if(ac_pred_flag){ if(predict_dir == 1) //TOP scantype = IDCTSCAN_ALT_HORI; else scantype = IDCTSCAN_ALT_VERT; }else scantype = IDCTSCAN_ZIGZAG; if((coded_block_pattern << (26+i)) < 0){ //coded block if(quant_type) len = Vld_block_mpeg(vld_intra, scan_table[scantype], len); else len = Vld_block_mpeg4(vld_intra, scan_table[scantype], len); } //dc add if(quantizer >= intra_dc_threshold){ if(quant_type) *block = (short)(Divide(*block*8, quant_matrix[0][0] * quantizer) * dc_scaler); else *block = (short)(Divide(*block, quantizer*2) * dc_scaler); } *block = *dc_addr = (short)(*block + *dc_addr); //ac reconstruction Ac_recon(i, subpos, predict_dir); soft_idct.Intra8x8(block, Max(len, 14), scantype); } PROF_E(PROF_BLOCK_INTRA); } //---------------------------- void C_mp4_decode_imp::BlockInter(int coded_block_pattern){ //texture decoding add //macroblock consists of four luminance blocks and the two spatially corresponding color difference blocks for(int i = 0; i < 6; i++){ int len = 0; if((coded_block_pattern << (26+i)) < 0){ //coded ClearBlock(block_8x8); if(quant_type) len = Vld_block_mpeg(vld_inter, scan_table[IDCTSCAN_ZIGZAG], len); else len = Vld_block_mpeg4(vld_inter, scan_table[IDCTSCAN_ZIGZAG], len); } soft_idct.Inter8x8(block_8x8, len); } } //---------------------------- static const signed char DQtab[4] = { -1, -2, 1, 2 }; //---------------------------- void C_mp4_decode_imp::IVOP(){ PROF_S(PROF_I_VOP); move_buf_invalid = 2; // invalid, but can be cleared to make it valid last_ref_frame_index = frame_index; block_update_base_indx = frame_index; MemSet(block_update_data, 0, mb_pos_end); // set all block to current frame (and clear rescue flag) resync_marker_bits = 17; for(int pos=0; pos =mb_pos_end) return; } //stream: 24bits available int mcbpc = bit_reader.GetMCodedBlockPatternChrominance_i(); //stream: 15bits available ac_pred_flag = bit_reader.Get1(); int coded_block_pattern = (bit_reader.GetCodedBlockPatternLuminance() << 2) | ((mcbpc >> 4) & 3); if((mcbpc & 7) == INTRA_Q){ //mb_type int q = quantizer + DQtab[bit_reader.Get(2)]; quantizer = q<1 ? 1: q>31 ? 31 : q; } BlockIntra(pos, coded_block_pattern); } } PROF_E(PROF_I_VOP); } //---------------------------- static int MvChroma(int v){ v |= ((v & 0x3)!=0) << 1; //adjust dx v |= ((v & 0x30000)!=0) << 17; //adjust dy v >>= 1; //shift //replace dx sign bit with old signed bit v &= ~0x8000; v |= (v & 0x4000) << 1; return v; } //---------------------------- static const byte roundtab[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 }; //---------------------------- #define sign(x) ((x)<0?-1:1) static int MvChroma4(const int* mv){ int dx = MOVE_VECTOR_X(mv[0]) + MOVE_VECTOR_X(mv[1]) + MOVE_VECTOR_X(mv[2]) + MOVE_VECTOR_X(mv[3]); int dy = MOVE_VECTOR_Y(mv[0]) + MOVE_VECTOR_Y(mv[1]) + MOVE_VECTOR_Y(mv[2]) + MOVE_VECTOR_Y(mv[3]); if (dx) dx = sign(dx) * (roundtab[Abs(dx) & 0xF] + ((Abs(dx) >> 4) <<1)); if (dy) dy = sign(dy) * (roundtab[Abs(dy) & 0xF] + ((Abs(dy) >> 4) <<1)); return MAKE_MOVEMENT_VECTOR_PAIR(dx, dy); } //---------------------------- void C_mp4_decode_imp::PVOP(){ PROF_S(PROF_P_VOP); //if no b-frames, we need only one row of mv vectors int j; move_buf_invalid = 0; byte currframemap = byte(frame_index - block_update_base_indx); last_ref_frame_index = frame_index; resync_marker_bits = 16 + fcode_forward; int last_frame_index = soft_idct.GetPreviousDstFrameIndex(); for(int pos=0; pos =mb_pos_end) return; } //stream: 24bits available if(!bit_reader.Get1()){ //coded int mcbpc = bit_reader.GetMCodedBlockPatternChrominance_p(); int mb_type = mcbpc & 7; mcbpc = (mcbpc >> 4) & 3; //stream: 14bits available block_update_data[pos] = (byte)currframemap; if(mb_type >= INTRA){ ac_pred_flag = bit_reader.Get1(); int coded_block_pattern = (bit_reader.GetCodedBlockPatternLuminance() << 2) | mcbpc; //stream: 7bits available if(mb_type == INTRA_Q){ int q = quantizer + DQtab[bit_reader.Get(2)]; //DQtab[dquant] quantizer = q<1 ? 1: (q>31 ? 31:q); } //stream: 5bits available mv[3] = mv[2] = mv[1] = mv[0] = 0; RescuePredict(pos); //Restore AC_DC values BlockIntra(pos, coded_block_pattern); }else{ //return; soft_idct.BeginBlock(POSX(pos), POSY(pos)); block_update_data[pos] |= RESCUE; // set rescue needed flag int coded_block_pattern = ((15-bit_reader.GetCodedBlockPatternLuminance()) << 2) | mcbpc; //stream: 8bits available // we will use mv[4],mv[5] for temporary purposes // in the next macroblock it will be overwrite (mv incremented by 4) switch(mb_type){ case INTER4V: for(j = 0; j<4; j++) mv[j] = bit_reader.GetMovementVectorPair(fcode_forward, GetPreviousMoveVector(j, pos)); mv[5] = mv[4] = MvChroma4(mv); soft_idct.SetMotionCompensationData(mv, NULL); break; case INTER_Q: { int q = quantizer + DQtab[bit_reader.Get(2)]; quantizer = q<1 ? 1: (q>31 ? 31:q); } default: //INTER mv[3] = mv[2] = mv[1] = mv[0] = bit_reader.GetMovementVectorPair(fcode_forward, GetPreviousMoveVector(0, pos)); mv[5] = mv[4] = MvChroma(mv[0]); soft_idct.SetMotionCompensationData(mv, NULL); break; } BlockInter(coded_block_pattern); } }else{ //not coded macroblock int n = block_update_base_indx + (block_update_data[pos]&0x7f); block_update_data[pos] |= RESCUE; //copy needed or the buffer already has this block? if(last_frame_index < n) soft_idct.Copy16x16(POSX(pos), POSY(pos), 0); mv[3] = mv[2] = mv[1] = mv[0] = 0; } } } PROF_E(PROF_P_VOP); } //---------------------------- #define vld_code \ code = ShowBits(12); \ if(code >> 9) \ code = (code >> 5) - 16 + TABLE_1; \ else if (code >> 7) \ code = (code >> 2) - 32 + TABLE_2; \ else /* if (code >= 8) but we don't care about invalid huffman codes */ \ code = code - 8 + TABLE_3; \ code = table[code]; \ FlushBits(code >> 12); #define TABLE_1 0 #define TABLE_2 112 #define TABLE_3 112+96 #define TABLE_LMAX 112+96+120 #define TABLE_RMAX 112+96+120+64 //---------------------------- int C_mp4_decode_imp::Vld_block_mpeg(const word *table, const byte *scan, int len){ int q_add = 0; int q_scale = quantizer << 1; byte *q_matrix = quant_matrix[0]; const byte *bit_ptr = bit_reader.ptr; int bitpos = bit_reader.pos, bits = bit_reader.bits; if(table == vld_inter){ q_add = quantizer; q_matrix += 8*8; } do {// event vld int code,level; LoadBits(); vld_code; level = code & 31; // 0x7FFF ESCAPE -> level = 31 if(level != 31){ code >>= 5; code &= 127; len += code; // last|run }else{ LoadBits(); //this value is escaped if(!GetBits1()){ //Type 1 vld_code; level = code & 31; code >>= 5; code &= 127; len += code; // last|run level += ((byte*)(table+TABLE_LMAX))[code]; // table_lmax[last][run] }else if(!GetBits1()){ //Type 2 vld_code; len += (code >> 5) & 127; code &= 31; level = code; if (code > 11) code = 11; if (len >= 64) code += 16; // add (last bit << 4) len += ((byte*)(table+TABLE_RMAX))[code]; // table_rmax[last][min(11,level)] }else{ //Type 3 - fixed length codes code = ShowBits(20); FlushBits(21); level = (code << 20) >> 20; //sign extend the lower 12 bits if (level < 0) level = -level; len += code >> 13; // last|run level *= q_scale; level += q_add; level *= q_matrix[scan[len & 63]]; level >>= 4; if ((code << 20) < 0) level = -level; block_8x8[scan[len & 63]] = (short)level; continue; } } code = scan[len & 63]; level *= q_scale; level += q_add; level *= q_matrix[code]; level >>= 4; if(GetBits1()) level = -level; block_8x8[code] = (short)level; }while(++len < 64); bit_reader.pos = bitpos; bit_reader.ptr = bit_ptr; bit_reader.bits = bits; return len - 64; } //---------------------------- #define vld_write \ block_8x8[scan[len & 63]] = (short)level; \ if(++len < 64) continue; \ bit_reader.pos = bitpos; \ bit_reader.ptr = bit_ptr; \ bit_reader.bits = bits; \ return len - 64; //---------------------------- #define vld_quant \ level *= q_scale; \ level += q_add; \ if(GetBits1()) \ level = -level; //---------------------------- int C_mp4_decode_imp::Vld_block_mpeg4(const word *table, const byte *scan, int len){ int q_scale = quantizer << 1; int q_add = (quantizer-1) | 1; const byte *bit_ptr = bit_reader.ptr; int bitpos = bit_reader.pos, bits = bit_reader.bits; while(true){ //event vld int code; LoadBits(); vld_code; int level = code&31; // 0x7FFF ESCAPE -> level = 31 if(level != 31){ code >>= 5; code &= 127; len += code; // last|run vld_quant vld_write }else{ //this value is escaped LoadBits(); if(!GetBits1()){ //Type 1 vld_code; level = code & 31; code >>= 5; code &= 127; len += code; // last|run level += ((byte*)(table+TABLE_LMAX))[code]; // table_lmax[last][run] vld_quant vld_write }else if(!GetBits1()){ //Type 2 vld_code; len += (code >> 5) & 127; code &= 31; level = code; if (code > 11) code = 11; if (len >= 64) code += 16; // add (last bit << 4) len += ((byte*)(table+TABLE_RMAX))[code]; // table_rmax[last][min(11,level)] vld_quant vld_write }else{ //Type 3 - fixed length codes code = ShowBits(21) >> 1; FlushBits(21); level = (code << 20) >> 20; //sign extend the lower 12 bits level *= q_scale; len += code >> 13; // last|run if(level > 0) level += q_add; else level -= q_add; vld_write; } } } } //---------------------------- static const byte def_quant_inter[64] = { 16, 17, 18, 19, 20, 21, 22, 23, 17, 18, 19, 20, 21, 22, 23, 24, 18, 19, 20, 21, 22, 23, 24, 25, 19, 20, 21, 22, 23, 24, 26, 27, 20, 21, 22, 23, 25, 26, 27, 28, 21, 22, 23, 24, 26, 27, 28, 30, 22, 23, 24, 26, 27, 28, 30, 31, 23, 24, 25, 27, 28, 30, 31, 33 }, def_quant_intra[64] = { 8, 17, 18, 19, 21, 23, 25, 27, 17, 18, 19, 21, 23, 25, 27, 28, 20, 21, 22, 23, 24, 26, 28, 30, 21, 22, 23, 24, 26, 28, 30, 32, 22, 23, 24, 26, 28, 30, 32, 35, 23, 24, 26, 28, 30, 32, 35, 38, 25, 26, 28, 30, 32, 35, 38, 41, 27, 28, 30, 32, 35, 38, 41, 45 }; //---------------------------- void C_mp4_decode_imp::ReadHeader_vol(){ bit_reader.Flush(32+1+8); // start_code + random_accessible_vol + video_object_type_indication bit_reader.Load(); int visual_object_layer_verid; if(bit_reader.Get1()){ //object layer identifier visual_object_layer_verid = bit_reader.Get(4); bit_reader.Flush(3); // video_object_layer_priority }else{ visual_object_layer_verid = 1; } int aspect = bit_reader.Get(4); // aspect ratio if(aspect == ASPECT_CUSTOM) { bit_reader.Load(); bit_reader.Get(8); //aspect_width bit_reader.Get(8); //aspect_height } if(bit_reader.Get1()){ // vol control parameters bit_reader.Flush(2); // chroma_format has_b_frames = !bit_reader.Get1(); if(has_b_frames) // b-frames SetIDCTBufferCount(3); if(bit_reader.Get1()) // vbv parameters bit_reader.Flush(15+1+15+1+15+1+3+11+1+15+1); } bit_reader.Flush(2+1); // shape + marker bit_reader.Load(); time_increment_resolution = bit_reader.Get(16); if(time_increment_resolution <= 0) time_increment_resolution = 1; time_increment_bits = FindHighestBit(time_increment_resolution-1)+1; bit_reader.Flush(1); // marker if(bit_reader.Get1()) //fixed_vop_rate bit_reader.Flush(time_increment_bits); bit_reader.Flush(1); // marker bit_reader.Load(); int width = bit_reader.Get(13); //width bit_reader.Flush(1); bit_reader.Load(); int height = bit_reader.Get(13); //height bit_reader.Flush(1); // marker interlaced = bit_reader.Get1(); /* if (interlaced && showerror && NotSupported(MPEG4_ERROR_INTERLACE)) // interlace return; */ bit_reader.Flush(1); // obmc_disable if(width!=video_sx || height!=video_sy){ valid_vol = false; return; } bit_reader.Load(); sprite_type = (E_SPRITE_TYPE)bit_reader.Get((visual_object_layer_verid==1) ? 1 : 2); if(sprite_type == SPRITE_STATIC || sprite_type == SPRITE_GMC){ //assert(0); //if(showerror && NotSupported(MPEG4_ERROR_GMC)) //return; if(sprite_type != SPRITE_GMC) { bit_reader.Flush(13+1+13+1+13+1+13+1); //width+marker+height+marker+left+marker+top+marker bit_reader.Load(); } //sprite warping points bit_reader.Get(6); //sprite warping accuracy bit_reader.Get(2); bit_reader.Get1(); // brightness change not supported if(sprite_type != SPRITE_GMC) bit_reader.Flush(1); // low_latency_sprite_enable } bit_reader.Load(); if(bit_reader.Get1()){ // not 8 bit quant_precision = bit_reader.Get(4); bit_reader.Flush(4); // bit per pixel }else quant_precision = 5; bool quant_type = bit_reader.Get1(); if(quant_type){ // quant type if(bit_reader.Get1()) // load intra bit_reader.GetQuantMatrix(quant_matrix[0]); else MemCpy(quant_matrix[0], def_quant_intra, sizeof(def_quant_intra)); if(bit_reader.Get1()) // load inter bit_reader.GetQuantMatrix(quant_matrix[1]); else MemCpy(quant_matrix[1], def_quant_inter, sizeof(def_quant_inter)); } bit_reader.Load(); if(visual_object_layer_verid != 1) { if(bit_reader.Get1()){// && showerror)// && NotSupported(MPEG4_ERROR_QPEL)) //quarter-pel assert(0); //return; } } bit_reader.Flush(1); // complexity estimation bit_reader.Flush(1); // resync marker disabled (?) if(bit_reader.Get1()){ //partitioning bit_reader.Flush(1); assert(0); //if(showerror)// && NotSupported(MPEG4_ERROR_PARTITIONING)) //return; //return; } if(visual_object_layer_verid != 1) { if(bit_reader.Get1()) //new pred not supported bit_reader.Flush(2+1); // req msg type, seg type bit_reader.Flush(1); //reduced res not supported } if(bit_reader.Get1()) // scalability bit_reader.Flush(1+4+1+5+5+5+5+1); // not supported valid_vol = true; //showerror = 0; } //---------------------------- static const byte tab_intra_dc_threshold[] = { 32, 13, 15, 17, 19, 21, 23, 1, }; //---------------------------- void C_mp4_decode_imp::ReadHeader_vop(E_FRAME_TYPE &frame_prediction_type){ bit_reader.Flush(32); bit_reader.Load(); frame_prediction_type = (E_FRAME_TYPE)bit_reader.Get(2); while(bit_reader.Get1()) bit_reader.Load(); bit_reader.Flush(1); //marker bit_reader.Load(); int time_increment = bit_reader.Get(time_increment_bits); if(time_increment_resolution){ if(frame_prediction_type != B_VOP){ time_pp = (time_increment_resolution + time_increment - last_ref_time) % time_increment_resolution; last_ref_time = time_increment; }else{ time_bp = (time_increment_resolution + last_ref_time - time_increment) % time_increment_resolution; } } bit_reader.Flush(1); //marker bit_reader.Load(); if(!bit_reader.Get1()){ frame_prediction_type = N_VOP; return; } bool rounding = false; if(frame_prediction_type == P_VOP || frame_prediction_type == S_VOP) rounding = bit_reader.Get1(); soft_idct.SetRounding(rounding); intra_dc_threshold = tab_intra_dc_threshold[bit_reader.Get(3)]; if(interlaced) bit_reader.Flush(2); //top_field_first, alternate_scan //if (frame_prediction_type == S_VOP && (sprite_type == SPRITE_STATIC || sprite_type == SPRITE_GMC)) //spritetrajectory(this); quantizer = bit_reader.Get(quant_precision); // vop quant bit_reader.Load(); if(frame_prediction_type != I_VOP) fcode_forward = bit_reader.Get(3); if(frame_prediction_type == B_VOP) fcode_backward = bit_reader.Get(3); } //---------------------------- bool C_mp4_decode_imp::ReadFrameHeaders(E_FRAME_TYPE &frame_prediction_type){ while(true){ bit_reader.ByteAlign(); bit_reader.Load(); if(bit_reader.Eof()) return false; int code = bit_reader.Show(32); if((code & ~VOL_START_CODE_MASK) == VOL_START_CODE){ ReadHeader_vol(); }else if(code == VOP_START_CODE){ ReadHeader_vop(frame_prediction_type); return true; }else bit_reader.Flush(8); } } //---------------------------- void C_mp4_decode_imp::BlockDirect(int pos, int dmv, int coded_block_pattern){ int fmv[6]; int bmv[6]; int *mv = &mv_buf[pos*4]; for(int j=0; j<4; ++j,++mv){ int dx, dy, v; v = trb * MOVE_VECTOR_X(*mv); if(v<0) //best code for (v<0) --v; dx = v >> 8; if(dx<0) ++dx; v = trb * MOVE_VECTOR_Y(*mv); if(v<0) //best code for (v<0) --v; dy = v >> 8; if(dy<0) ++dy; dx += MOVE_VECTOR_X(dmv); dy += MOVE_VECTOR_Y(dmv); fmv[j] = MAKE_MOVEMENT_VECTOR_PAIR(dx, dy); if(dmv & 0xffff) dx -= MOVE_VECTOR_X(*mv); else{ v = trb_trd * MOVE_VECTOR_X(*mv); if(v<0) //best code for (v<0) --v; dx = v >> 8; if(dx<0) ++dx; } if(dmv & 0xffff0000) dy -= MOVE_VECTOR_Y(*mv); else{ v = trb_trd * MOVE_VECTOR_Y(*mv); if(v<0) //best code for (v<0) --v; dy = v >> 8; if(dy<0) ++dy; } bmv[j] = MAKE_MOVEMENT_VECTOR_PAIR(dx, dy); } fmv[5]=fmv[4]=MvChroma4(fmv); bmv[5]=bmv[4]=MvChroma4(bmv); soft_idct.SetMotionCompensationData(bmv, fmv); BlockInter(coded_block_pattern); } //---------------------------- void C_mp4_decode_imp::BVOP(){ PROF_S(PROF_B_VOP); int fmv[6]; int bmv[6]; int pos; resync_marker_bits = 16 + Max(fcode_backward, fcode_forward); int last_frame_index = soft_idct.GetPreviousDstFrameIndex(); for(pos=0; pos =mb_pos_end) return; fprev = bprev = 0; } int n = block_update_base_indx + (block_update_data[pos]&0x7f); //did the last refframe touch this block? if(last_ref_frame_index > n){ //no change: this block is the same in both backward and forward buffer // copy needed? if(last_frame_index < n && last_frame_index >= -last_ref_frame_index) soft_idct.Copy16x16(POSX(pos),POSY(pos),1); }else{ //stream: 24bits available soft_idct.BeginBlock(POSX(pos), POSY(pos)); if(!bit_reader.Get1()){ int mb_type; n = bit_reader.Get(1); for(mb_type=0; mb_type<=3; ++mb_type){ if(bit_reader.Get1()) break; } int coded_block_pattern; //stream: 19bits available if(!n) coded_block_pattern = bit_reader.Get(6); else coded_block_pattern = 0; //stream: 13bits available if(mb_type != DIRECT){ if(coded_block_pattern && bit_reader.Get1()){ int q = quantizer + (bit_reader.Get1() ? 2:-2); quantizer = q<1 ? 1: (q>31 ? 31:q); } switch(mb_type){ case BACKWARD: bmv[3] = bmv[2] = bmv[1] = bmv[0] = bprev = bit_reader.GetMovementVectorPair(fcode_backward, bprev); bmv[5] = bmv[4] = MvChroma(bprev); soft_idct.SetMotionCompensationData(bmv, NULL); break; case FORWARD: fmv[3]=fmv[2]=fmv[1]=fmv[0]=fprev = bit_reader.GetMovementVectorPair(fcode_forward, fprev); fmv[5]=fmv[4]=MvChroma(fprev); soft_idct.SetMotionCompensationData(NULL, fmv); break; default: //case INTERPOLATE: fmv[3]=fmv[2]=fmv[1]=fmv[0]=fprev = bit_reader.GetMovementVectorPair(fcode_forward, fprev); fmv[5]=fmv[4]=MvChroma(fprev); bmv[3]=bmv[2]=bmv[1]=bmv[0]=bprev = bit_reader.GetMovementVectorPair(fcode_backward, bprev); bmv[5]=bmv[4]=MvChroma(bprev); soft_idct.SetMotionCompensationData(bmv, fmv); break; } BlockInter(coded_block_pattern); }else{ BlockDirect(pos, bit_reader.GetMovementVectorPair(1, 0), coded_block_pattern); } }else{ BlockDirect(pos, 0, 0); } } } } PROF_E(PROF_B_VOP); } //---------------------------- int C_mp4_decode_imp::GetPreviousMoveVector(int block_num, int pos){ int p1, p2, p3; int *mv = &mv_buf[(pos & mv_bufmask)*4]; int *mvlast = &mv_buf[((pos-MAX_MACROBLOCKS_X) & mv_bufmask)*4]; // we are allowed to access borders on left and right (always zero) switch(block_num){ case 0: if(pos == resyncpos) return 0; if(pos < resyncpos+MAX_MACROBLOCKS_X){ if(pos != resyncpos+MAX_MACROBLOCKS_X-1) return mv[-4+1]; if(POSX(pos)==0) return mvlast[4+2]; p1 = mv[-4+1]; p2 = 0; p3 = mvlast[4+2]; break; } p1 = mv[-4+1]; p2 = mvlast[2]; p3 = mvlast[4+2]; break; case 1: if(pos < resyncpos+MAX_MACROBLOCKS_X){ if(pos != resyncpos+MAX_MACROBLOCKS_X-1) return mv[0]; p1 = mv[0]; p2 = 0; p3 = mvlast[4+2]; break; } p1 = mv[0]; p2 = mvlast[3]; p3 = mvlast[4+2]; break; case 2: p1 = mv[-4+3]; p2 = mv[0]; p3 = mv[1]; if(pos == resyncpos) p1 = 0; break; default: //3 p1 = mv[2]; p2 = mv[0]; p3 = mv[1]; break; } int temp = Min(Max(p1, p2), Min(Max(p2, p3), Max(p1, p3))); p1 = (p1<<16)>>16; p2 = (p2<<16)>>16; p3 = (p3<<16)>>16; p1 = Min(Max(p1, p2), Min(Max(p2, p3), Max(p1, p3))); return ((temp&0xffff0000) | (p1&0xffff)); } //---------------------------- bool C_mp4_decode_imp::ResyncMarker(){ int bits = bit_reader.BitsToNextByte(); int code = bit_reader.Show(bits); return (code == (1 << (bits-1)) - 1) && (bit_reader.ShowLarge(bits + resync_marker_bits) & ((1 << resync_marker_bits)-1)) == 1; } //---------------------------- int C_mp4_decode_imp::ReSync(){ int i = bit_reader.BitsToNextByte(); bit_reader.Flush(i); bit_reader.Load(); for(i=0; i<32; ++i){ if(bit_reader.Get1()) break; if(i==16) bit_reader.Load(); } if(i+1 != resync_marker_bits) return mb_pos_end; bit_reader.Load(); int mb_bits = FindHighestBit(mb_xsize*mb_ysize)+1; int x = bit_reader.Get(mb_bits); int y = x/mb_xsize; x -= y*mb_xsize; bit_reader.Load(); i = bit_reader.Get(quant_precision); if(i) quantizer = i; if(bit_reader.Get1()){ //extension return mb_pos_end; //not supported yet } for (i = 0; i < 4*MAX_MACROBLOCKS_X*2; i++) dc_lum[i] = 1024; for (i = 0; i < 2*MAX_MACROBLOCKS_X; i++) { dc_chr[0][i] = 1024; dc_chr[1][i] = 1024; } MemSet(ac_left_lum,0,sizeof(ac_left_lum)); MemSet(ac_top_lum,0,sizeof(ac_top_lum)); MemSet(ac_left_chr,0,sizeof(ac_left_chr)); MemSet(ac_top_chr,0,sizeof(ac_top_chr)); resyncpos = x+y*MAX_MACROBLOCKS_X; return resyncpos; } //---------------------------- bool C_mp4_decode_imp::Init(){ if(video_sx > (MAX_MACROBLOCKS_X-1)*16 || video_sy > (MAX_MACROBLOCKS_Y-1)*16) return false; return SetIDCTBufferCount(2); } //---------------------------- C_mp4_decode_imp::C_mp4_decode_imp(dword sx, dword sy, void *_prof): has_b_frames(false), quant_precision(5), video_sx(sx), video_sy(sy), soft_idct(sx, sy), valid_vol(false), interlaced(false), ac_pred_flag(false), sprite_type(SPRITE_NO), frame_index(0), last_ref_frame_index(-1), mb_pos_end(0), block_update_base_indx(0), mb_xsize((sx + 15)>>4), mb_ysize((sy + 15)>>4), quantizer(0), intra_dc_threshold(0), fcode_forward(0), fcode_backward(0), resync_marker_bits(0), time_increment_resolution(30000), time_increment_bits(15), last_ref_time(0), time_pp(0), time_bp(0), last_bframe(0), refframe(0), resyncpos(0), quant_type(false), mv_bufmask(0), move_buf_invalid(0), #ifdef PROFILE prof((C_profiler*)_prof), #endif packed_b_size(0), mv_buf(NULL), _mv_buf(NULL) { MemSet(quant_matrix, 0, sizeof(quant_matrix)); MemSet(dc_lum, 0, sizeof(dc_lum)); MemSet(ac_left_lum, 0, sizeof(ac_left_lum)); MemSet(ac_top_lum, 0, sizeof(ac_top_lum)); MemSet(dc_chr, 0, sizeof(dc_chr)); MemSet(ac_left_chr, 0, sizeof(ac_left_chr)); MemSet(ac_top_chr, 0, sizeof(ac_top_chr)); MemSet(_mv_bufrow, 0, sizeof(_mv_bufrow)); block_8x8 = (short*)(((dword)(_block) + 15) & ~15); mb_pos_end = mb_ysize * MAX_MACROBLOCKS_X; int i; for(i = 0; i < 4*MAX_MACROBLOCKS_X*2; i++) dc_lum[i] = 1024; for(i = 0; i < 2*MAX_MACROBLOCKS_X; i++){ dc_chr[0][i] = 1024; dc_chr[1][i] = 1024; } } //---------------------------- C_mp4_decode *CreateMp4Decode(dword sx, dword sy, void *profiler){ C_mp4_decode_imp *dec = new C_mp4_decode_imp(sx, sy, profiler); if(dec){ if(!dec->Init()){ delete dec; dec = NULL; } } return dec; } //----------------------------