/* ************************************************************************* ** INTEL Corporation Proprietary Information ** ** This listing is supplied under the terms of a license ** agreement with INTEL Corporation and may not be copied ** nor disclosed except in accordance with the terms of ** that agreement. ** ** Copyright (c) 1995-1996 Intel Corporation. ** All Rights Reserved. ** ** ************************************************************************* */ /***************************************************************************** * * d1dec.cpp * * DESCRIPTION: * H261 decoder top level functions * * Routines: Prototypes in: * H263InitDecoderGlobal d1dec.h * H263InitDecoderInstance d1dec.h * H263Decompress d1dec.h * H263TermDecoderInstance d1dec.h */ // $Header: S:\h26x\src\dec\d1dec.cpv 1.69 24 Mar 1997 11:34:36 mbodart $ // $Log: S:\h26x\src\dec\d1dec.cpv $ // // Rev 1.69 24 Mar 1997 11:34:36 mbodart // Added check for PREROLL, if so don't display. // // Rev 1.68 19 Mar 1997 16:24:36 mbodart // Fixed potential problem where aspect ratio adjustment to uNewOffsetToLine0 // should not occur for positive pitches. // // Rev 1.67 19 Mar 1997 15:01:46 mbodart // Changes to DibXY to support RGB output with a negative bitmap height. // // Rev 1.66 24 Jan 1997 17:05:16 RHAZRA // RTP change: we now look for an EBS for every frame. If there is one // then we copy the H.261 bits and the EBS separately into our local // bitstream buffer, inserting two zero bytes between the H261 bits and // the EBS. We need the two zero bytes to mark the end of the frame for // the pass 1 code. If there is no EBS, then we proceed as before by // copying the bitstream and then adding two zero bytes at the end. // // Rev 1.65 22 Jan 1997 13:33:40 RHAZRA // Since PPM now fills in the source format even for a PSC packet loss, // the check for format change has been moved back into d1pict.cpp. This // was how the check was initially designed in the pre-RTP era. // // Rev 1.64 23 Dec 1996 16:32:38 MBODART // Fixed a bug where we allowed more than 33 macro blocks to be present // in a GOB. Now we return an error in this case. // Also removed some dead code involving mb_start. // // Rev 1.63 16 Dec 1996 14:41:08 RHAZRA // Changed a bitstream error ASSERT to a bonafide error. // // Rev 1.62 16 Dec 1996 09:09:42 RHAZRA // Now LOSS_RECOVERY mode is turned on by default in Pass 1 // // Rev 1.61 12 Dec 1996 09:36:04 SCDAY // // Changed size of a couple of data structures in H263InitDecoderInstance // to improve memory footprint // // Rev 1.60 18 Nov 1996 17:12:38 MBODART // Replaced all debug message invocations with Active Movie's DbgLog. // // Rev 1.59 13 Nov 1996 11:35:56 RHAZRA // Added MMX_autosensing. // // Rev 1.58 11 Nov 1996 11:03:28 MBODART // Fixed bug where block action block type was not explicitly initialized for // skipped macro blocks. This led to the block edge filter being used more // often than needed. // // Rev 1.57 04 Nov 1996 08:43:18 RHAZRA // Fixed setting MMX on or off via the INI file when the MMX key // has an illegal value (<0 or > 1) assigned to it. // // Rev 1.56 31 Oct 1996 08:58:34 SCDAY // Raj added support for MMX decoder // // Rev 1.55 30 Oct 1996 09:59:46 MBODART // Fixed mirroring. Need to use absolute value of dst biWidth in most context // Also made cosmetic changes to DibXY. It's identical to H.263's DibXY, we // should probably put it into a common file. // // Rev 1.54 27 Sep 1996 14:59:32 MBODART // DECODE_STATS enabled build will now compile, but numbers aren't accurate. // // Rev 1.53 26 Sep 1996 12:30:00 RHAZRA // Added (i) MMX sensing in the decoder and ini file reading (requires a new // "MMX" section in h263test.ini to turn off MMX on a MMX CPU) and (ii) // MMX & PentiumPro CCs. // // Rev 1.52 25 Sep 1996 17:35:20 BECHOLS // // Added code just prior to color conversion that will perform the // Snapshot copy on request. // // Rev 1.51 24 Sep 1996 13:52:24 RHAZRA // Changed fpBlockAction synchronization to deal with MBAP being biased // by -1 in the RTP extension. // // Rev 1.50 17 Sep 1996 22:08:36 RHAZRA // Added code in RTP packet loss recovery to read GOB number from the // bitstream when the packet following the lost packet starts with a // GOB start code. // // Rev 1.49 16 Sep 1996 09:28:56 RHAZRA // Fixed a bug in MB-level fragmentation recovery. // // Rev 1.48 12 Sep 1996 14:23:12 MBODART // Replaced GlobalAlloc family with HeapAlloc in the H.261 decoder. // // Rev 1.47 10 Sep 1996 15:51:42 RHAZRA // Bug fixes in RTP packet loss recovery when bad GBSC or MBA is // detected in the PPM generated lost packet. // // Rev 1.45 04 Sep 1996 09:52:32 RHAZRA // Added a new pass 1 function to enable RTp decoder resiliency when // LOSS_RECOVERY is defined. // // Rev 1.44 14 Aug 1996 08:41:04 RHAZRA // // Added support for YUV12 and YUY2 color convertors // // Rev 1.43 09 Aug 1996 17:23:10 MBODART // Fixed uninitialized variable bugs: one in decoder rearchitecture, where // MB type needed to be defined for skipped blocks; and one previously // existing bug where the block action u8BlkType needed to be defined // for skip blocks, in order to suppress the BEF on those blocks. // These bugs render build 027 of H.261 broken. // // Rev 1.42 05 Aug 1996 11:00:30 MBODART // // H.261 decoder rearchitecture: // Files changed: d1gob.cpp, d1mblk.{cpp,h}, d1dec.{cpp,h}, // filelist.261, h261_32.mak // New files: d1bvriq.cpp, d1idct.cpp // Obsolete files: d1block.cpp // Work still to be done: // Update h261_mf.mak // Optimize uv pairing in d1bvriq.cpp and d1idct.cpp // Fix checksum code (it doesn't work now) // Put back in decoder stats // // Rev 1.41 10 Jul 1996 08:20:44 SCDAY // Increased memory allocation for I420 // // Rev 1.40 03 Jun 1996 12:21:52 AKASAI // Initialized DC = NULL and added tests so that don't try to free // and unlock if DC == NULL. This effected the "done" return area // of H263Decompress and one other place. // // Also added checking of return status from reading GOB start code. // // Rev 1.39 03 May 1996 15:54:26 AKASAI // Eliminate allocating space for B frame in decoder. This frame is // not used. // // Rev 1.38 17 Apr 1996 18:36:30 AKASAI // Updates to use non-distructive color convertors. // Color Convertor has modified parameter list. // FrameCopy is called only when BlockEdgeFilter is enabled or // AdjustPels is enabled or when mirroring is enabled. // For H.261 bitstreams. // A frame copy is used for YUV12 when mirroring is enabled or // AdjustPels is enabled. // // Basically normal processing without BEF you don't have to do // a frame copy which saves ~2msec per frame QCIF. // // Rev 1.37 05 Apr 1996 14:22:18 AKASAI // // Added support for BlockEdgeFilter. // Need to change where ReInitializeBlockActionStream was called. // // Rev 1.36 21 Mar 1996 16:59:54 AKASAI // Needed to move location of picture checksum calculation because // of the swap of Previous and Current Frames. // // Rev 1.35 18 Mar 1996 15:52:06 AKASAI // Many, many changes. // 1) To optimize for performance eliminated memcpy of current to // previous frame. Now switch the pointers and re-initialize // block Action stream. New routine H263ReInitializeBlockActionStream // written and called after each frame is compressed. This // change accounted to 3-4 of the 4-5 msec improvment. // 2) Needed to add call to BlockCopy (NOTE: maybe BlockCopySpecial would // be faster) to copy any skip blocks at the end of a GOB from // previous to current. Change was necessary after 1). // 3) Deleted some dead code // 4) Changed timing statistic code some. // // Rev 1.34 29 Feb 1996 09:20:30 SCDAY // Added support for mirroring // // Rev 1.33 14 Feb 1996 11:54:26 AKASAI // Update to use new color convertors that fix palette flash. // Also corrected data alignment problem which improves performance // of decoder. // // Rev 1.32 09 Feb 1996 13:33:36 AKASAI // // Updated interface to call new AdjustPels routine. CustomChange // Brightness, Saturation and Contrast seem to be working but very // little testing has been done. // // Rev 1.31 12 Jan 1996 15:12:34 AKASAI // Fixed pink blocks in RING0 QCIF TO FCIF by fixing static initialzation // of GOBUpdate arrays. Was based on input parameter but now on constant. // // Rev 1.30 11 Jan 1996 16:57:00 DBRUCKS // // added GetDecoderOptions // added use of bUseBlockEdgeFilter // added use of bForceOnAspectRatioCorrection // Changed to do aspect ratio correction for both I420 and H261 if either // forced or specified by result of the DecompressQuery // // Rev 1.29 26 Dec 1995 17:40:54 DBRUCKS // // changed bTimerIsOn to bTimingThisFrame because it is used after STOP_TIMER // fixed YUV12 decode when timer ifdefs are defined // // Rev 1.28 26 Dec 1995 12:48:18 DBRUCKS // remove TIMING code // add general purpose timing code using d1stat.* // // Rev 1.26 21 Dec 1995 17:49:06 AKASAI // Replaced an uninitialized variable to AdjustPels with the correct on. // Change of Contrast, Brightness and Saturation is not working correctly. // // Rev 1.25 13 Dec 1995 14:23:52 AKASAI // Deleted setting of Initialized to False; Added calling of H263TermDecoderIn // if Initialized == True. // // Rev 1.24 05 Dec 1995 10:20:12 SCDAY // Cleaned up warnings // // Rev 1.23 17 Nov 1995 15:21:48 BECHOLS // // Added ring 0 stuff. // // Rev 1.22 17 Nov 1995 15:13:18 SCDAY // // Added key field to picture checksum data // // Rev 1.21 16 Nov 1995 18:11:42 AGANTZX // Added p5 timing code (#define TIMING) // // Rev 1.20 15 Nov 1995 19:04:12 AKASAI // Should now be able to play raw YUV12 files. Note: funny white stop // when I play downriv4.avi. // // Rev 1.19 15 Nov 1995 14:27:22 AKASAI // Added support for YUV12 "if 0" old code with aspec correction and // 8 to 7 bit conversion. Added FrameCopy calls and DispFrame into structure. // (Integration point) // // Rev 1.18 08 Nov 1995 14:58:02 SCDAY // Added picture layer checksums // // Rev 1.17 03 Nov 1995 11:42:54 AKASAI // // Added and changed code to handle MB checksum hopefully better. // // Rev 1.16 01 Nov 1995 13:46:02 AKASAI // // Added allocation of temporary buffer for loop filter. uFilterBBuffer // right after uMBBuffer. // // Rev 1.15 30 Oct 1995 16:20:26 AKASAI // Fixed up extra bytes some more. Doug and Sylvia had already decided // on 2 extra bytes for the decoder instead of 4. We now copy 2 zeros // at the end of the biSizeImage. // // Rev 1.14 30 Oct 1995 15:38:22 AKASAI // Frame 94 of grouch read past the end of the bit stream finding junk. // Enabled code Sylvia had put in to copy 4 bytes of zero after biSizeImage. // This seems to fix the problem playing grouch.avi. // // Rev 1.13 27 Oct 1995 19:11:26 AKASAI // Added some special case code to handle when skip macroblock is last // in a gob. // // Rev 1.12 27 Oct 1995 18:17:22 AKASAI // // Put in fix "hack" to keep the block action stream pointers // in sync between d1dec and d1mblk. With skip macro blocks some // macroblocks were being processed multiple times. Still a problem // when gob ends with a skip macroblock. // // Rev 1.11 26 Oct 1995 15:33:10 SCDAY // // Delta frames partially working -- changed main loops to accommodate // skipped macroblocks by detecting next startcode // // Rev 1.10 16 Oct 1995 13:53:46 SCDAY // // Added macroblock level checksum // // Rev 1.9 10 Oct 1995 15:44:02 SCDAY // clean up // // Rev 1.8 10 Oct 1995 14:58:10 SCDAY // // added support for FCIF // // Rev 1.7 06 Oct 1995 15:32:28 SCDAY // // Integrated with latest AKK d1block // // Rev 1.6 04 Oct 1995 15:24:46 SCDAY // changed test pattern stuff // // Rev 1.5 22 Sep 1995 15:07:02 SCDAY // Doug fixed ASSERT bug, scd debug changes // // Rev 1.2 19 Sep 1995 15:25:32 SCDAY // // added H261 pict, GOB, MB/MBA parsing // // Rev 1.1 12 Sep 1995 15:52:24 DBRUCKS // add SKIP_DECODE option for encoder work // // Rev 1.0 11 Sep 1995 13:51:48 SCDAY // Initial revision. // // Rev 1.18 05 Sep 1995 17:22:12 DBRUCKS // u & v are offset by 8 from Y in YVU12ForEnc // // Rev 1.17 01 Sep 1995 17:13:52 DBRUCKS // add adjustpels // // Rev 1.16 01 Sep 1995 09:49:34 DBRUCKS // checkin partial ajdust pels changes // // Rev 1.15 29 Aug 1995 16:50:40 DBRUCKS // add support for YVU9 playback // // Rev 1.14 28 Aug 1995 17:45:58 DBRUCKS // add yvu12forenc // // Rev 1.13 28 Aug 1995 10:15:14 DBRUCKS // update to 5 July Spec and 8/25 Errata // // Rev 1.12 24 Aug 1995 08:51:30 CZHU // Turned off apsect ratio correction. // // Rev 1.11 23 Aug 1995 12:25:10 DBRUCKS // Turn on the color converters // // Rev 1.10 14 Aug 1995 16:40:34 DBRUCKS // initialize block action stream // // Rev 1.9 11 Aug 1995 17:47:58 DBRUCKS // cleanup // // Rev 1.8 11 Aug 1995 17:30:00 DBRUCKS // copy source to bitstream // // Rev 1.7 11 Aug 1995 16:12:14 DBRUCKS // add ptr check to MB data and add #ifndef early exit // // Rev 1.6 11 Aug 1995 15:10:18 DBRUCKS // get ready to integrate with block level code and hook up macro block level code // // Rev 1.5 03 Aug 1995 14:57:56 DBRUCKS // Add ASSERT macro // // Rev 1.4 02 Aug 1995 15:31:34 DBRUCKS // added GOB header parsing // // Rev 1.3 01 Aug 1995 12:27:38 DBRUCKS // add PSC parsing // // Rev 1.2 31 Jul 1995 16:28:00 DBRUCKS // move loacl BITS defs to D3DEC.CPP // // Rev 1.1 31 Jul 1995 15:32:22 CZHU // Moved global tables to d3tables.h // // Rev 1.0 31 Jul 1995 13:00:04 DBRUCKS // Initial revision. // // Rev 1.3 28 Jul 1995 13:57:36 CZHU // Started to add picture level decoding of fixed length codes. // // Rev 1.2 24 Jul 1995 14:57:52 CZHU // Added global tables for VLD decoding. Also added instance initialization // and termination. Several data structures are updated for H.263. // // Rev 1.1 17 Jul 1995 14:46:20 CZHU // // // Rev 1.0 17 Jul 1995 14:14:40 CZHU // Initial revision. ////////////////////////////////////////////////////////////////////////////// #include "precomp.h" static int iNumberOfGOBsBySourceFormat[2] = { 3, /* QCIF */ // 10, 12, /* CIF */ }; static int iNumberOfMBsInAGOBBySourceFormat[2] = { 33, /* QCIF */ 33, /* CIF */ }; // rearch //#ifndef LOSS_RECOVERY #if 0 static LRESULT IAPass1ProcessFrame( T_H263DecoderCatalog *DC, T_BlkAction *fpBlockAction, T_MBInfo *fpMBInfo, BITSTREAM_STATE *fpbsState, U8 *fpu8MaxPtr, U32 *pN, T_IQ_INDEX *pRUN_INVERSE_Q, const I32 iNumberOfGOBs, const I32 iNumberOfMBs, const I32 iGOB_start, const I32 iMB_start ); #else static LRESULT IAPass1ProcessFrameRTP( T_H263DecoderCatalog *DC, T_BlkAction *fpBlockAction, T_MBInfo *fpMBInfo, BITSTREAM_STATE *fpbsState, U8 *fpu8MaxPtr, U32 *pN, T_IQ_INDEX *pRUN_INVERSE_Q, const I32 iNumberOfGOBs, const I32 iNumberOfMBs, const I32 iGOB_start, const I32 iMB_start ); #endif static void IAPass2ProcessFrame( T_H263DecoderCatalog *DC, T_BlkAction *fpBlockAction, T_MBInfo *fpMBInfo, U32 *pN, T_IQ_INDEX *pRUN_INVERSE_Q, const I32 iNumberOfGOBs, const I32 iNumberOfMBs ); // rearch static long DibXY(ICDECOMPRESSEX FAR *lpicDecEx, LPINT lpiPitch, UINT yScale, BOOL bIsDCI); static void GetDecoderOptions(T_H263DecoderCatalog *); #define START_CODE 0xff18 static void ZeroFill(HPBYTE hpbY, HPBYTE hpbU, HPBYTE hpbV, int iPitch, U32 uWidth, U32 uHeight); extern T_H263ColorConvertorCatalog ColorConvertorCatalog[]; extern void BlockCopy( U32 uDstBlock, U32 uSrcBlock); extern void BlockEdgeFilter(U8 *YPlane, int Height, int Width, int Pitch, T_BlkAction *lpBlockAction); LRESULT H263InitDecoderGlobal(void) { //For 32-bit decoder, this is empty for now, 7/29/95 //need to add code for 16 bit version. return ICERR_OK; } ///////////////////////////////////////////////////////////////////////// // // H263InitializeBlockActionStream // // Initialize the block action stream // static void H263InitializeBlockActionStream( T_H263DecoderCatalog * DC) { U8 FAR * pu8; U32 uFrameHeight = DC->uFrameHeight; U32 uFrameWidth = DC->uFrameWidth; U32 uCurBlock; U32 uRefBlock; U32 uBBlock; U32 uYOffset; U32 uUOffset; U32 uVOffset; U32 x; U32 y; U32 g; U32 uPitch16; U32 uPitch8; U32 uYUpdate; U32 uUVUpdate; U32 uBlkNumber; T_BlkAction FAR * fpBlockAction; // Offsets for stepping thru GOBs for FCIF processing static U32 uYGOBFCIFUpdate[12] = { (PITCH*3*16)-(FCIF_WIDTH>>1), (FCIF_WIDTH>>1), (PITCH*3*16)-(FCIF_WIDTH>>1), (FCIF_WIDTH>>1), (PITCH*3*16)-(FCIF_WIDTH>>1), (FCIF_WIDTH>>1), (PITCH*3*16)-(FCIF_WIDTH>>1), (FCIF_WIDTH>>1), (PITCH*3*16)-(FCIF_WIDTH>>1), (FCIF_WIDTH>>1), (PITCH*3*16)-(FCIF_WIDTH>>1), (FCIF_WIDTH>>1), }; static U32 uUVGOBFCIFUpdate[12] = { (PITCH*3*8)-(FCIF_WIDTH>>2), (FCIF_WIDTH>>2), (PITCH*3*8)-(FCIF_WIDTH>>2), (FCIF_WIDTH>>2), (PITCH*3*8)-(FCIF_WIDTH>>2), (FCIF_WIDTH>>2), (PITCH*3*8)-(FCIF_WIDTH>>2), (FCIF_WIDTH>>2), (PITCH*3*8)-(FCIF_WIDTH>>2), (FCIF_WIDTH>>2), (PITCH*3*8)-(FCIF_WIDTH>>2), (FCIF_WIDTH>>2), }; // assume that the width and height are multiples of 16 ASSERT((uFrameHeight & 0xF) == 0); ASSERT((uFrameWidth & 0xF) == 0); // Init uPitch16 and uPitch8 uPitch16 = PITCH*16; uPitch8 = PITCH*8; // Point to the allocated space pu8 = (U8 FAR *) DC; uCurBlock = (U32) (pu8 + DC->CurrFrame.X32_YPlane); uRefBlock = (U32) (pu8 + DC->PrevFrame.X32_YPlane); uBBlock = (U32) (pu8 + DC->PBFrame.X32_YPlane); // skip the padding used for unconstrained motion vectors uYOffset = Y_START; uUOffset = DC->uSz_YPlane + UV_START; uVOffset = uUOffset + (PITCH >> 1); // start with block zero uBlkNumber = 0; if (uFrameWidth == QCIF_WIDTH) { /* if QCIF */ // calculate distance to the next row. uYUpdate = (16 * PITCH) - uFrameWidth; uUVUpdate = (8 * PITCH) - (uFrameWidth >> 1); // Initialize the array fpBlockAction = (T_BlkAction FAR *) (pu8 + DC->X16_BlkActionStream); for (y = 0 ; y < uFrameHeight ; y += 16) { for (x = 0 ; x < uFrameWidth ; x += 16) { // Four Y Blocks // Y0 Y1 // Y2 Y3 fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset += 8; fpBlockAction++; fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset = uYOffset - 8 + (8 * PITCH); fpBlockAction++; fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset += 8; fpBlockAction++; fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset = uYOffset + 8 - (8 * PITCH); fpBlockAction++; // One CR (V) Block fpBlockAction->pCurBlock = uCurBlock + uVOffset; fpBlockAction->pRefBlock = uRefBlock + uVOffset; fpBlockAction->pBBlock = uBBlock + uVOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uVOffset += 8; fpBlockAction++; // One CB (U) Block fpBlockAction->pCurBlock = uCurBlock + uUOffset; fpBlockAction->pRefBlock = uRefBlock + uUOffset; fpBlockAction->pBBlock = uBBlock + uUOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uUOffset += 8; fpBlockAction++; } uYOffset += uYUpdate; uUOffset += uUVUpdate; uVOffset += uUVUpdate; } } /* end if QCIF */ if (uFrameWidth == FCIF_WIDTH) { /* if FCIF */ // calculate distance to the next row. uYUpdate = (16 * PITCH) - (uFrameWidth >> 1); uUVUpdate = (8 * PITCH) - (uFrameWidth >> 2); // Initialize the array fpBlockAction = (T_BlkAction FAR *) (pu8 + DC->X16_BlkActionStream); for (g = 0; g < 12; g++) { /* for each GOB */ for (y = 0 ; y < 3 ; y++) { /* for each row in GOB */ for (x = 0 ; x < (uFrameWidth >> 1) ; x += 16) { // Four Y Blocks // Y0 Y1 // Y2 Y3 fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset += 8; fpBlockAction++; fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset = uYOffset - 8 + (8 * PITCH); fpBlockAction++; fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset += 8; fpBlockAction++; fpBlockAction->pCurBlock = uCurBlock + uYOffset; fpBlockAction->pRefBlock = uRefBlock + uYOffset; fpBlockAction->pBBlock = uBBlock + uYOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uYOffset = uYOffset + 8 - (8 * PITCH); fpBlockAction++; // One CR (V) Block fpBlockAction->pCurBlock = uCurBlock + uVOffset; fpBlockAction->pRefBlock = uRefBlock + uVOffset; fpBlockAction->pBBlock = uBBlock + uVOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uVOffset += 8; fpBlockAction++; // One CB (U) Block fpBlockAction->pCurBlock = uCurBlock + uUOffset; fpBlockAction->pRefBlock = uRefBlock + uUOffset; fpBlockAction->pBBlock = uBBlock + uUOffset; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction->uBlkNumber = uBlkNumber++; uUOffset += 8; fpBlockAction++; } uYOffset += uPitch16 - (uFrameWidth >> 1); uUOffset += uPitch8 - (uFrameWidth >> 2); uVOffset += uPitch8 - (uFrameWidth >> 2); } uYOffset -= uYGOBFCIFUpdate[g]; uUOffset -= uUVGOBFCIFUpdate[g]; uVOffset -= uUVGOBFCIFUpdate[g]; } } /* end if FCIF */ } // end H263InitializeBlockActionStream() ///////////////////////////////////////////////////////////////////////// // // H261ReInitializeBlockActionStream // // ReInitialize the block action stream // static void H261ReInitializeBlockActionStream( T_H263DecoderCatalog * DC) { U8 FAR * pu8; U32 uFrameHeight = DC->uFrameHeight; U32 uFrameWidth = DC->uFrameWidth; U32 utemp; U32 x; U32 y; U32 g; T_BlkAction FAR * fpBlockAction; pu8 = (U8 FAR *) DC; if (uFrameWidth == QCIF_WIDTH) { /* if QCIF */ // Initialize the array fpBlockAction = (T_BlkAction FAR *) (pu8 + DC->X16_BlkActionStream); for (y = 0 ; y < uFrameHeight ; y += 16) { for (x = 0 ; x < uFrameWidth ; x += 16) { // Four Y Blocks // Y0 Y1 // Y2 Y3 utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; // One CR (V) Block utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; // One CB (U) Block utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; } } } /* end if QCIF */ if (uFrameWidth == FCIF_WIDTH) { /* if FCIF */ // Initialize the array fpBlockAction = (T_BlkAction FAR *) (pu8 + DC->X16_BlkActionStream); for (g = 0; g < 12; g++) { /* for each GOB */ for (y = 0 ; y < 3 ; y++) { /* for each row in GOB */ for (x = 0 ; x < (uFrameWidth >> 1) ; x += 16) { // Four Y Blocks // Y0 Y1 // Y2 Y3 utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; // One CR (V) Block utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; // One CB (U) Block utemp = fpBlockAction->pCurBlock; fpBlockAction->pCurBlock = fpBlockAction->pRefBlock; fpBlockAction->pRefBlock = utemp; fpBlockAction->i8MVX=0; fpBlockAction->i8MVY=0; fpBlockAction->u8BlkType = BT_EMPTY; fpBlockAction++; } } } } /* end if FCIF */ } // end H261ReInitializeBlockActionStream() ////////////////////////////////////////////////////////////////////////////// // // H263InitDecoderInstance // // This function allocates and initializes the per-instance tables used by // the H263 decoder. Note that in 16-bit Windows, the non-instance-specific // global tables are copied to the per-instance data segment, so that they // can be used without segment override prefixes. // LRESULT H263InitDecoderInstance(LPDECINST lpInst, int CodecID) { U32 u32YActiveHeight, u32YActiveWidth; U32 u32UVActiveHeight, u32UVActiveWidth; U32 u32YPlane, u32VUPlanes ,u32YVUPlanes,u32SizeBlkActionStream; U32 uSizeBitStreamBuffer; U32 uSizeDecTimingInfo; U32 lOffset=0; U32 u32TotalSize; LRESULT iReturn= ICERR_OK; U32 * pInitLimit; U32 * pInitPtr; // rearch U32 u32SizeT_IQ_INDEXBuffer, u32SizepNBuffer, u32SizeMBInfoStream; // NEW // rearch T_H263DecoderCatalog * DC; U8 * P32Inst; SECURITY_ATTRIBUTES EventAttributes; // Used with Snapshot. if(IsBadWritePtr((LPVOID)lpInst, sizeof(DECINSTINFO))) { DBOUT("ERROR :: H263InitDecoderInstance :: ICERR_BADPARAM"); iReturn = ICERR_BADPARAM; goto done; } if ((CodecID == YUV12_CODEC && (lpInst->yres > 480 || lpInst->xres > 640)) || (CodecID == H263_CODEC && (lpInst->yres > 288 || lpInst->xres > 352))) { DBOUT("ERROR :: H263InitDecoderInstance :: ICERR_BADSIZE"); iReturn = ICERR_BADSIZE; goto done; } if (CodecID == YUV12_CODEC) { /* The active height and width must be padded to a multiple of 8 * since the adjustpels routine relies on it. */ u32YActiveHeight = ((lpInst->yres + 0x7) & (~ 0x7)); u32YActiveWidth = ((lpInst->xres + 0x7) & (~ 0x7)); u32UVActiveHeight = ((lpInst->yres + 0xF) & (~ 0xF)) >> 1; u32UVActiveWidth = ((lpInst->xres + 0xF) & (~ 0xF)) >> 1; u32YPlane = u32YActiveWidth * u32YActiveHeight; u32VUPlanes = u32UVActiveWidth * u32UVActiveHeight * 2; u32YVUPlanes = u32YPlane + u32VUPlanes; // added for I420 output support // wasn't allocating enough memory for YUV12 output, no color convert case // calculate the block action stream size. The Y portion has one block for // every 8x8 region. The U and V portion has one block for every 16x16 region. // We also want to make sure that the size is aligned to a cache line. u32SizeBlkActionStream = (lpInst->xres >> 3) * (lpInst->yres >> 3); u32SizeBlkActionStream += ((lpInst->xres >> 4) * (lpInst->yres >> 4)) * 2; u32SizeBlkActionStream *= sizeof (T_BlkAction); u32SizeBlkActionStream = (u32SizeBlkActionStream + 31) & ~0x1F; // calculate the bitstream buffer size. We copy the input data to a buffer // in our space because we read ahead up to 4 bytes beyond the end of the // input data. The input data size changes for each frame. So the following // is a very safe upper bound estimate. // Add + 2 for extra zeros for start code emulation. AKK uSizeBitStreamBuffer = lpInst->yres * lpInst->xres + 2; #ifdef DECODE_STATS uSizeDecTimingInfo = DEC_TIMING_INFO_FRAME_COUNT * sizeof (DEC_TIMING_INFO); #else uSizeDecTimingInfo = 0; #endif u32TotalSize = INSTANCE_DATA_FIXED_SIZE + u32SizeBlkActionStream + u32YVUPlanes + // current frame u32YVUPlanes + // prev frame BLOCK_BUFFER_SIZE + FILTER_BLOCK_BUFFER_SIZE + uSizeBitStreamBuffer + // input data uSizeDecTimingInfo + 0x1F; // u32TotalSize = 512L + 0x1FL; /* Just enough space for Decoder Catalog. */ } else { ASSERT(CodecID == H263_CODEC); u32YActiveHeight = lpInst->yres + UMV_EXPAND_Y + UMV_EXPAND_Y ; u32YActiveWidth = lpInst->xres + UMV_EXPAND_Y + UMV_EXPAND_Y ; u32UVActiveHeight = u32YActiveHeight/2; u32UVActiveWidth = u32YActiveWidth /2; u32YPlane = PITCH * u32YActiveHeight; u32VUPlanes = PITCH * u32UVActiveHeight; u32YVUPlanes = u32YPlane + u32VUPlanes; // calculate the block action stream size. The Y portion has one block for // every 8x8 region. The U and V portion has one block for every 16x16 region. // We also want to make sure that the size is aligned to a cache line. u32SizeBlkActionStream = (lpInst->xres >> 3) * (lpInst->yres >> 3); u32SizeBlkActionStream += ((lpInst->xres >> 4) * (lpInst->yres >> 4)) * 2; u32SizeBlkActionStream *= sizeof (T_BlkAction); u32SizeBlkActionStream = (u32SizeBlkActionStream + 31) & ~0x1F; // calculate the bitstream buffer size. We copy the input data to a buffer // in our space because we read ahead up to 4 bytes beyond the end of the // input data. The input data size changes for each frame. So the following // is a very safe upper bound estimate. // Add + 2 for extra zeros for start code emulation. AKK // Add some additional to make sure stay dword align (rearch) uSizeBitStreamBuffer = (lpInst->yres * lpInst->xres + 2 + 4) & ~0x3; // rearch // calculate sizes of NEW data structures u32SizeT_IQ_INDEXBuffer = (lpInst->xres)*(lpInst->yres*2)* sizeof(T_IQ_INDEX); u32SizepNBuffer = (lpInst->xres>>4)*(lpInst->yres>>4)*sizeof(U32)*6; u32SizeMBInfoStream = (lpInst->xres>>4)*(lpInst->yres>>4)* sizeof(T_MBInfo); // rearch #ifdef DECODE_STATS uSizeDecTimingInfo = DEC_TIMING_INFO_FRAME_COUNT * sizeof (DEC_TIMING_INFO); #else uSizeDecTimingInfo = 0; #endif u32TotalSize = INSTANCE_DATA_FIXED_SIZE + u32SizeBlkActionStream + u32YVUPlanes + // current frame u32YVUPlanes + // prev frame BLOCK_BUFFER_SIZE + FILTER_BLOCK_BUFFER_SIZE + uSizeBitStreamBuffer + // input data u32SizeT_IQ_INDEXBuffer + // NEW u32SizepNBuffer + // NEW u32SizeMBInfoStream + // PB-NEW uSizeDecTimingInfo + 0x1F; } /* If already initialized, terminate this instance before allocating * another. */ if(lpInst->Initialized == TRUE) { H263TermDecoderInstance(lpInst); } // allocate the memory for the instance lpInst->pDecoderInst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, u32TotalSize); if (lpInst->pDecoderInst == NULL) { DBOUT("ERROR :: H263InitDecoderInstance :: ICERR_MEMORY"); iReturn = ICERR_MEMORY; goto done; } //build the decoder catalog P32Inst = (U8 *) ((((U32) lpInst->pDecoderInst) + 31) & ~0x1F); //The catalog of per-instance data is at the start of the per-instance data. DC = (T_H263DecoderCatalog *) P32Inst; DC->DecoderType = CodecID; DC->uFrameHeight = lpInst->yres; DC->uFrameWidth = lpInst->xres; DC->uYActiveHeight = u32YActiveHeight; DC->uYActiveWidth = u32YActiveWidth; DC->uUVActiveHeight = u32UVActiveHeight; DC->uUVActiveWidth = u32UVActiveWidth; DC->uSz_YPlane = u32YPlane; DC->uSz_VUPlanes = u32VUPlanes; DC->uSz_YVUPlanes = u32YVUPlanes; DC->BrightnessSetting = H26X_DEFAULT_BRIGHTNESS; DC->ContrastSetting = H26X_DEFAULT_CONTRAST; DC->SaturationSetting = H26X_DEFAULT_SATURATION; DC->iAPColorConvPrev = 0; DC->pAPInstPrev = NULL; // assume no previous AP instance. DC->p16InstPostProcess = NULL; DC->a16InstPostProcess = NULL; DC->bReadSrcFormat = 0; EventAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); EventAttributes.lpSecurityDescriptor = NULL; EventAttributes.bInheritHandle = FALSE; DC->SnapshotEvent = CreateEvent(&EventAttributes, TRUE, FALSE, NULL); /* Get the Options */ GetDecoderOptions(DC); if (CodecID == H263_CODEC) { lOffset = INSTANCE_DATA_FIXED_SIZE; DC->Ticker = 127; //instance dependent table here DC->X16_BlkActionStream = lOffset; lOffset += u32SizeBlkActionStream; DC-> CurrFrame.X32_YPlane = lOffset; lOffset += DC->uSz_YPlane; DC->CurrFrame.X32_VPlane = lOffset; DC->CurrFrame.X32_UPlane = DC->CurrFrame.X32_VPlane + U_OFFSET; lOffset += DC->uSz_VUPlanes; //no padding is needed DC->PrevFrame.X32_YPlane = lOffset; lOffset += DC->uSz_YPlane; DC->PrevFrame.X32_VPlane = lOffset; DC->PrevFrame.X32_UPlane = DC->PrevFrame.X32_VPlane + U_OFFSET; lOffset += DC->uSz_VUPlanes; DC->uMBBuffer = lOffset; lOffset += BLOCK_BUFFER_SIZE; DC->uFilterBBuffer = lOffset; lOffset += FILTER_BLOCK_BUFFER_SIZE; // Bitstream ASSERT((lOffset & 0x3) == 0); // DWORD alignment DC->X32_BitStream = lOffset; lOffset += uSizeBitStreamBuffer; DC->uSizeBitStreamBuffer = uSizeBitStreamBuffer; // rearch ASSERT((lOffset & 0x3) == 0); // DWORD alignment DC->X32_InverseQuant = lOffset; lOffset += u32SizeT_IQ_INDEXBuffer; ASSERT((lOffset & 0x3) == 0); // DWORD alignment DC->X32_pN = lOffset; lOffset += u32SizepNBuffer; ASSERT((lOffset & 0x3) == 0); // DWORD alignment DC->X32_uMBInfoStream = lOffset; lOffset += u32SizeMBInfoStream; // rearch #ifdef DECODE_STATS // Decode Timing Info DC->X32_DecTimingInfo = lOffset; lOffset += uSizeDecTimingInfo; #endif // init the data ASSERT((U32)lOffset <= u32TotalSize); pInitLimit = (U32 *) (P32Inst + lOffset); pInitPtr = (U32 *) (P32Inst + DC->CurrFrame.X32_YPlane); for (;pInitPtr < pInitLimit;pInitPtr++) *pInitPtr =0; // Fill the Y,U,V Previous Frame space with black, this way // even if we lost an I frame, the background will remain black ZeroFill((HPBYTE)P32Inst + DC->PrevFrame.X32_YPlane + Y_START, (HPBYTE)P32Inst + DC->PrevFrame.X32_UPlane + UV_START, (HPBYTE)P32Inst + DC->PrevFrame.X32_VPlane + UV_START, PITCH, DC->uFrameWidth, DC->uFrameHeight); H263InitializeBlockActionStream(DC); } // not YVU9 lpInst->Initialized = TRUE; iReturn = ICERR_OK; done: return iReturn; } /*********************************************************************** * ZeroFill * Fill the YVU data area with black. ***********************************************************************/ static void ZeroFill(HPBYTE hpbY, HPBYTE hpbU, HPBYTE hpbV, int iPitch, U32 uWidth, U32 uHeight) { U32 w,h; int y,u,v; U32 uNext; HPBYTE pY, pU, pV; y = 32; uNext = iPitch - uWidth; for (h = 0 ; h < uHeight ; h++) { pY = hpbY; for (w = 0; w < uWidth ; w++) { *hpbY++ = (U8)16; } hpbY += uNext; } uWidth = uWidth / 2; uHeight = uHeight / 2; uNext = iPitch - uWidth; for (h = 0 ; h < uHeight ; h++) { pV = hpbV; pU = hpbU; for (w = 0; w < uWidth ; w++) { *hpbV++ = (U8)128; *hpbU++ = (U8)128; } hpbV += uNext; hpbU += uNext; } } //*********************************************************************** // // TestFill // // Fill the YVU data area with a test pattern. // #if 0 static void TestFill( HPBYTE hpbY, HPBYTE hpbU, HPBYTE hpbV, int iPitch, U32 uWidth, U32 uHeight) { U32 w,h; int y,u,v; U32 uNext; HPBYTE pY, pU, pV; y = 32; uNext = iPitch - uWidth; for (h = 0 ; h < uHeight ; h++) { pY = hpbY; for (w = 0; w < uWidth ; w++) { *hpbY++ = (U8) (y + (w & ~0xF)); } hpbY += uNext; } uWidth = uWidth / 2; uHeight = uHeight / 2; u = 0x4e * 2; v = 44; uNext = iPitch - uWidth; for (h = 0 ; h < uHeight ; h++) { pV = hpbV; pU = hpbU; for (w = 0; w < uWidth ; w++) { *hpbV++ = (U8) v; *hpbU++ = (U8) u; } hpbV += uNext; hpbU += uNext; } } /* end TestFill */ static void TestFillUV( HPBYTE hpbU, HPBYTE hpbV, int iPitch, U32 uWidth, U32 uHeight) { U32 w,h; int u,v; U32 uNext; HPBYTE pU, pV; uWidth = uWidth / 2; uHeight = uHeight / 2; u = 128; v = 128; uNext = iPitch - uWidth; for (h = 0 ; h < uHeight ; h++) { pV = hpbV; pU = hpbU; for (w = 0; w < uWidth ; w++) { *hpbV++ = (U8) v; *hpbU++ = (U8) u; } hpbV += uNext; hpbU += uNext; } } /* end TestFill */ #endif //********************************************************************* //H263Decompress -- This function drives the decompress // and display of one frame //********************************************************************* LRESULT H263Decompress( LPDECINST lpInst, ICDECOMPRESSEX FAR * lpicDecEx, BOOL bIsDCI) { LRESULT iReturn = ICERR_ERROR; U8 FAR * fpSrc; U8 FAR * P32Inst; U8 FAR * fpu8MaxPtr; T_H263DecoderCatalog * DC = NULL; int iNumberOfGOBs; int iNumberOfMBs; T_BlkAction FAR * fpBlockAction; LONG lOutput; int intPitch; U32 uNewOffsetToLine0; U16 u16NewFrameHeight; int bShapingFlag; int uYPitch; int uUVPitch; U8 bMirror; HPBYTE pSource, pDestination; U32 utemp; // rearch T_IQ_INDEX * pRUN_INVERSE_Q; U32 * pN; T_MBInfo FAR * fpMBInfo; I32 gob_start = 1, mb_start = 1; // rearch /* new variables added when change to color convertor/bef */ U32 uYPlane, uVPlane, uUPlane; U8 *pFrame, *lpAligned; T_H26X_RTP_BSINFO_TRAILER *pBsTrailer; /* the following is for MB Checksum */ U32 uReadChecksum = 0; #ifdef DECODE_STATS U32 uStartLow; U32 uStartHigh; U32 uElapsed; U32 uBefore; U32 uDecodeFrameSum = 0; U32 uHeadersSum = 0; U32 uMemcpySum = 0; U32 uFrameCopySum = 0; U32 uOutputCCSum = 0; U32 uInitBlkActStrSum = 0; U32 uBEFSum = 0; int bTimingThisFrame = 0; DEC_TIMING_INFO * pDecTimingInfo = NULL; #endif #ifdef CHECKSUM_PICTURE /* the following is for Picture Checksum */ YVUCheckSum pReadYVUCksum; YVUCheckSum YVUChkSum; U32 uCheckSumValid = 0; // flag to skip checksum check if // encoder calling decoder before // checksum valid #endif /* The following are used for reading bits */ U32 uWork; U32 uBitsReady; BITSTREAM_STATE bsState; BITSTREAM_STATE FAR * fpbsState = &bsState; #ifdef SKIP_DECODE TBD("Skipping Decode"); iReturn = ICERR_OK; goto done; #endif /* check the input pointers */ if (IsBadWritePtr((LPVOID)lpInst, sizeof(DECINSTINFO))|| IsBadReadPtr((LPVOID)lpicDecEx, sizeof(ICDECOMPRESSEX))) { DBOUT("ERROR :: H263Decompress :: ICERR_BADPARAM"); iReturn = ICERR_BADPARAM; goto done; } /* Check for a bad length */ if (lpicDecEx->lpbiSrc->biSizeImage == 0) { DBOUT("ERROR :: H263Decompress :: ICERR_BADIMAGESIZE"); iReturn = ICERR_BADIMAGESIZE; goto done; } /* Lock the memory */ if (lpInst->pDecoderInst == NULL) { DBOUT("ERROR :: H263Decompress :: ICERR_MEMORY"); iReturn = ICERR_MEMORY; goto done; } /* Set the frame mirroring flag */ bMirror = FALSE; if (lpicDecEx->lpbiDst != 0) { if(lpicDecEx->lpbiSrc->biWidth * lpicDecEx->lpbiDst->biWidth < 0) bMirror = TRUE; } /* for testing */ /* bMirror = TRUE; */ /* Build the decoder catalog pointer */ P32Inst = (U8 FAR *) ((((U32) lpInst->pDecoderInst) + 31) & ~0x1F); DC = (T_H263DecoderCatalog FAR *) P32Inst; if (DC->DecoderType == H263_CODEC) { #ifdef DECODE_STATS if ((DC->uStatFrameCount < DEC_TIMING_INFO_FRAME_COUNT) && (DC->ColorConvertor != YUV12ForEnc)) { ASSERT(DC->X32_DecTimingInfo > 0); DC->pDecTimingInfo = (DEC_TIMING_INFO FAR *)( ((U8 FAR *)P32Inst) + DC->X32_DecTimingInfo ); TIMER_START(bTimingThisFrame,uStartLow,uStartHigh); ASSERT(bTimingThisFrame); DC->uStartLow = uStartLow; DC->uStartHigh = uStartHigh; } else { DC->pDecTimingInfo = (DEC_TIMING_INFO FAR *) NULL; ASSERT(!bTimingThisFrame); } DC->bTimingThisFrame = bTimingThisFrame; #endif /* Is there room to copy the bitstream? We could at most add 2 (zeros) and 3 padding bytes for DWORD alignment to the original bitstream */\ ASSERT(lpicDecEx->lpbiSrc->biSizeImage + 5 <= DC->uSizeBitStreamBuffer); if ((lpicDecEx->lpbiSrc->biSizeImage + 5) > DC->uSizeBitStreamBuffer) { DBOUT("ERROR :: H263Decompress :: ICERR_ERROR: not enough room for bitstream"); iReturn = ICERR_ERROR; goto done; } /* Copy the source data to the bitstream region. * OPTIMIZE: Integrate MRV's BLKCOPY.ASM */ #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif fpSrc = (U8 FAR *)(P32Inst + DC->X32_BitStream); // New: we will first look for an EBS from the PPM. If there is one, then we will // insert two bytes of zero between the H.261 bistream and the EBS part with // DWORD alignment and update the total bitstream size. If no EBS is found, // then we proceed as before. DC->iVerifiedBsExt = FALSE; DC->Sz_BitStream = lpicDecEx->lpbiSrc->biSizeImage ; H26XRTP_VerifyBsInfoStream(DC,(U8 *) lpicDecEx->lpSrc,lpicDecEx->lpbiSrc->biSizeImage); if (!DC->iValidBsExt) { memcpy((char FAR *)fpSrc, (const char FAR *) lpicDecEx->lpSrc, lpicDecEx->lpbiSrc->biSizeImage); // also copy 16 bits of zero for end of frame detection fpSrc[lpicDecEx->lpbiSrc->biSizeImage] = 0; fpSrc[lpicDecEx->lpbiSrc->biSizeImage+1] = 0; DC->Sz_BitStream += 2; fpu8MaxPtr = fpSrc; fpu8MaxPtr += (lpicDecEx->lpbiSrc->biSizeImage + 2 - 1); } else { // First the H.261 stream data - relying on PPM to fill the compressed size correctly // in the trailer. pBsTrailer = ( (T_H26X_RTP_BSINFO_TRAILER *)(DC->pBsTrailer) ); memcpy((char FAR *)fpSrc, (const char FAR *) lpicDecEx->lpSrc, pBsTrailer->uCompressedSize); // Now write out two bytes of zeros at the end of the H.261 bitstream fpSrc[pBsTrailer->uCompressedSize] = 0; fpSrc[pBsTrailer->uCompressedSize + 1] = 0; // Now tack on the EBS after DWORD alignment. lpAligned = (U8 *) ( (U32) (fpSrc + (pBsTrailer->uCompressedSize + 2) + 3) & 0xfffffffc); memcpy(lpAligned, DC->pBsInfo, DC->uNumOfPackets*sizeof(T_RTP_H261_BSINFO)); memcpy(lpAligned + DC->uNumOfPackets*sizeof(T_RTP_H261_BSINFO), DC->pBsTrailer, sizeof(T_H26X_RTP_BSINFO_TRAILER)); // update lpicDecEx->lpbiSrc->biSizeImage DC->Sz_BitStream = lpAligned + DC->uNumOfPackets*sizeof(T_RTP_H261_BSINFO) + sizeof(T_H26X_RTP_BSINFO_TRAILER) - fpSrc; fpu8MaxPtr = fpSrc; fpu8MaxPtr += (pBsTrailer->uCompressedSize + 2 - 1); } #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uMemcpySum) #endif /* Initialize the bit stream reader */ GET_BITS_INIT(uWork, uBitsReady); // rearch // Initialize pointers to data structures which carry info // between passes pRUN_INVERSE_Q = (T_IQ_INDEX *)(P32Inst + DC->X32_InverseQuant); pN = (U32 *)(P32Inst + DC->X32_pN); fpMBInfo = (T_MBInfo FAR *) (P32Inst + DC->X32_uMBInfoStream); // rearch // #ifdef LOSS_RECOVERY #if 1 DC->iVerifiedBsExt = FALSE; #endif /* Decode the Picture Header */ #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif #ifdef CHECKSUM_PICTURE iReturn = H263DecodePictureHeader(DC, fpSrc, uBitsReady, uWork, fpbsState, &pReadYVUCksum, &uCheckSumValid); #else iReturn = H263DecodePictureHeader(DC, fpSrc, uBitsReady, uWork, fpbsState); #endif if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress :: Error reading the picture header"); goto done; } #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif /* Set a limit for testing for bitstream over-run */ /* For each GOB do... */ iNumberOfGOBs = iNumberOfGOBsBySourceFormat[DC->uSrcFormat]; iNumberOfMBs = iNumberOfMBsInAGOBBySourceFormat[DC->uSrcFormat]; /* In H263 a GOB is a single row of MB, and a MB is 16x16 */ /* In H261 a GOB is 33 MBs, and a MB is 16x16 */ /* Order of GOBs depends on source format */ if (DC->uSrcFormat == SRC_FORMAT_QCIF) { ASSERT(((U32)iNumberOfGOBs * 3 * 16) == DC->uFrameHeight); if (((U32)iNumberOfGOBs * 3 * 16) != DC->uFrameHeight) { DBOUT("ERROR :: H263Decompress :: Error matching picture header SRC field and actual frame height"); iReturn = ICERR_ERROR; goto done; } ASSERT(((U32)iNumberOfMBs / 3 * 16) == DC->uFrameWidth); if (((U32)iNumberOfMBs / 3 * 16) != DC->uFrameWidth) { DBOUT("ERROR :: H263Decompress :: Error matching picture header SRC field and actual frame width"); iReturn = ICERR_ERROR; goto done; } } if (DC->uSrcFormat == SRC_FORMAT_CIF) { ASSERT(((U32)iNumberOfGOBs / 2 * 3 * 16) == DC->uFrameHeight); if (((U32)iNumberOfGOBs / 2 * 3 * 16) != DC->uFrameHeight) { DBOUT("ERROR :: H263Decompress :: Error matching picture header SRC field and actual frame height"); iReturn = ICERR_ERROR; goto done; } ASSERT(((U32)iNumberOfMBs / 3 * 2 * 16) == DC->uFrameWidth); if (((U32)iNumberOfMBs / 3 * 2 * 16) != DC->uFrameWidth) { DBOUT("ERROR :: H263Decompress :: Error matching picture header SRC field and actual frame width"); iReturn = ICERR_ERROR; goto done; } } fpBlockAction = (T_BlkAction FAR *) (P32Inst + DC->X16_BlkActionStream); // rearch // H261, re initialize the block action stream for entire Frame // at end of H263Decompress. High bit is set in BlockType to // indicate if need to do BEF so can't re-init between GOBs. // H261ReInitializeBlockActionStream(DC); /***************************************************************** FIRST PASS - bitream parsing and IDCT prep work ***************************************************************/ // #ifndef LOSS_RECOVERY #if 0 iReturn = IAPass1ProcessFrame(DC, fpBlockAction, fpMBInfo, fpbsState, fpu8MaxPtr, pN, pRUN_INVERSE_Q, iNumberOfGOBs, iNumberOfMBs, gob_start, mb_start); #else iReturn = IAPass1ProcessFrameRTP(DC, fpBlockAction, fpMBInfo, fpbsState, fpu8MaxPtr, pN, pRUN_INVERSE_Q, iNumberOfGOBs, iNumberOfMBs, gob_start, mb_start); #endif if (iReturn != ICERR_OK) { DBOUT("H261Decompress : Pass 1 error"); goto done; } /***************************************************************** SECOND PASS - IDCT and motion compensation (MC) *****************************************************************/ fpBlockAction = (T_BlkAction FAR *)(P32Inst + DC->X16_BlkActionStream); pRUN_INVERSE_Q = (T_IQ_INDEX *)(P32Inst + DC->X32_InverseQuant); pN = (U32 *)(P32Inst + DC->X32_pN); fpMBInfo = (T_MBInfo FAR *)(P32Inst + DC->X32_uMBInfoStream); IAPass2ProcessFrame(DC, fpBlockAction, fpMBInfo, pN, pRUN_INVERSE_Q, iNumberOfGOBs, iNumberOfMBs); // rearch //Prepare which frame to display for inter frames DC->DispFrame.X32_YPlane = DC->CurrFrame.X32_YPlane; DC->DispFrame.X32_VPlane = DC->CurrFrame.X32_VPlane; DC->DispFrame.X32_UPlane = DC->CurrFrame.X32_UPlane; utemp = DC->CurrFrame.X32_YPlane; DC->CurrFrame.X32_YPlane = DC->PrevFrame.X32_YPlane; DC->PrevFrame.X32_YPlane = utemp; utemp = DC->CurrFrame.X32_VPlane ; DC->CurrFrame.X32_VPlane = DC->PrevFrame.X32_VPlane; DC->PrevFrame.X32_VPlane = utemp; utemp = DC->CurrFrame.X32_UPlane ; DC->CurrFrame.X32_UPlane = DC->PrevFrame.X32_UPlane; DC->PrevFrame.X32_UPlane = utemp; #ifdef CHECKSUM_PICTURE if (uCheckSumValid) { /* compute and compare picture checksum data */ iReturn = H261ComputePictureCheckSum(P32Inst, &YVUChkSum); iReturn = H261ComparePictureCheckSum(&YVUChkSum, &pReadYVUCksum); } #endif } /* end if (DC->DecoderType == H263_CODEC) */ else { ASSERT(DC->DecoderType == YUV12_CODEC); DC->DispFrame.X32_YPlane = DC->CurrFrame.X32_YPlane; DC->DispFrame.X32_VPlane = DC->CurrFrame.X32_VPlane; DC->DispFrame.X32_UPlane = DC->CurrFrame.X32_UPlane; } /* Return if there is no need to update screen yet. */ if ((lpicDecEx->dwFlags & ICDECOMPRESS_HURRYUP) || (lpicDecEx->dwFlags & ICDECOMPRESS_PREROLL)) { DBOUT("H261Decompress : Display suppressed, HURRYUP or PREROLL"); iReturn = ICERR_DONTDRAW; goto done; } #if 0 /* Fill the Y,U,V Current Frame space with a test pattern */ TestFill((HPBYTE)P32Inst + DC->CurrFrame.X32_YPlane + Y_START, (HPBYTE)P32Inst + DC->CurrFrame.X32_UPlane + UV_START, (HPBYTE)P32Inst + DC->CurrFrame.X32_VPlane + UV_START, PITCH, DC->uFrameWidth, DC->uFrameHeight); #endif #if MAKE_GRAY /* Fill the U,V Current Frame space with a test pattern */ TestFillUV((HPBYTE)P32Inst + DC->CurrFrame.X32_UPlane + UV_START, (HPBYTE)P32Inst + DC->CurrFrame.X32_VPlane + UV_START, PITCH, DC->uFrameWidth, DC->uFrameHeight); #endif /* Special case the YUV12 for the encoder because it should not include * BEF, Shaping or aspect ratio correction... */ if (DC->ColorConvertor == YUV12ForEnc) { H26x_YUV12ForEnc ((HPBYTE)P32Inst, DC->PrevFrame.X32_YPlane + Y_START, DC->PrevFrame.X32_VPlane + UV_START, DC->PrevFrame.X32_UPlane + UV_START, DC->uFrameWidth, DC->uFrameHeight, PITCH, (HPBYTE)lpicDecEx->lpDst, (DWORD)Y_START, (DWORD)(MAX_HEIGHT + 2L*UMV_EXPAND_Y) * PITCH + 8 + UV_START + PITCH / 2, (DWORD)(MAX_HEIGHT + 2L*UMV_EXPAND_Y) * PITCH + 8 + UV_START); iReturn = ICERR_OK; goto done; } /* Copy Planes to Post Processing area if mirror and/or block edge filter. */ if (DC->DecoderType == H263_CODEC) { #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif if(bMirror) { // copy with mirroring pFrame = (U8 *)DC->p16InstPostProcess; uYPlane = DC->PostFrame.X32_YPlane; uUPlane = DC->PostFrame.X32_UPlane; uVPlane = DC->PostFrame.X32_VPlane; FrameMirror(((HPBYTE) P32Inst) + DC->DispFrame.X32_YPlane + Y_START, ((HPBYTE) DC->p16InstPostProcess) + DC->PostFrame.X32_YPlane, DC->uFrameHeight, DC->uFrameWidth, PITCH); FrameMirror(((HPBYTE) P32Inst)+ DC->DispFrame.X32_UPlane + UV_START, ((HPBYTE) DC->p16InstPostProcess) + DC->PostFrame.X32_UPlane, DC->uFrameHeight/2, DC->uFrameWidth/2, PITCH); FrameMirror(((HPBYTE) P32Inst)+ DC->DispFrame.X32_VPlane + UV_START, ((HPBYTE) DC->p16InstPostProcess) + DC->PostFrame.X32_VPlane, DC->uFrameHeight/2, DC->uFrameWidth/2, PITCH); } else { /* no mirroring */ if ((DC->bUseBlockEdgeFilter) || (DC->bAdjustLuma) || (DC->bAdjustChroma)) { /* copy for BEF */ pFrame = (U8 *)DC->p16InstPostProcess; uYPlane = DC->PostFrame.X32_YPlane; uUPlane = DC->PostFrame.X32_UPlane; uVPlane = DC->PostFrame.X32_VPlane; FrameCopy (((HPBYTE) P32Inst) +DC->DispFrame.X32_YPlane+Y_START, ((HPBYTE) DC->p16InstPostProcess) +DC->PostFrame.X32_YPlane, DC->uFrameHeight, DC->uFrameWidth, PITCH); FrameCopy (((HPBYTE) P32Inst)+DC->DispFrame.X32_UPlane+UV_START, ((HPBYTE) DC->p16InstPostProcess) +DC->PostFrame.X32_UPlane, DC->uFrameHeight/2, DC->uFrameWidth/2, PITCH); FrameCopy (((HPBYTE) P32Inst)+DC->DispFrame.X32_VPlane+UV_START, ((HPBYTE) DC->p16InstPostProcess) +DC->PostFrame.X32_VPlane, DC->uFrameHeight/2, DC->uFrameWidth/2, PITCH); } /* end if BEF on */ else { /* no BEF or mirror so don't need copy */ pFrame = (U8 *) DC; uYPlane = DC->DispFrame.X32_YPlane + Y_START; uUPlane = DC->DispFrame.X32_UPlane + UV_START; uVPlane = DC->DispFrame.X32_VPlane + UV_START; } /* end of else no BEF */ } /* end else no mirroring */ #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uFrameCopySum) #endif uYPitch = PITCH; uUVPitch = PITCH; if (DC->bUseBlockEdgeFilter) { #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif fpBlockAction=(T_BlkAction FAR *) (P32Inst+DC->X16_BlkActionStream); BlockEdgeFilter(((HPBYTE) DC->p16InstPostProcess) + DC->PostFrame.X32_YPlane, DC->uFrameHeight, DC->uFrameWidth, PITCH, fpBlockAction); #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uBEFSum) #endif } } else { /* YUV12 */ const U32 uHeight = DC->uFrameHeight; const U32 uWidth = DC->uFrameWidth; const U32 uYPlaneSize = uHeight*uWidth; if(bMirror) // mirroring and YUV12 need to do copy { pFrame = (U8 *)DC->p16InstPostProcess; uYPlane = DC->PostFrame.X32_YPlane; uUPlane = uYPlane + uYPlaneSize; uVPlane = uUPlane + (uYPlaneSize>>2); pSource = (HPBYTE)lpicDecEx->lpSrc; pDestination = (HPBYTE)(DC->p16InstPostProcess + (DWORD)DC->PostFrame.X32_YPlane); FrameMirror (pSource, pDestination, uHeight, uWidth, uWidth); pSource += uYPlaneSize; pDestination += uYPlaneSize; FrameMirror (pSource, pDestination, (uHeight>>1), (uWidth>>1), (uWidth>>1)); pSource += (uYPlaneSize>>2); pDestination += (uYPlaneSize>>2); FrameMirror (pSource, pDestination, (uHeight>>1), (uWidth>>1), (uWidth>>1)); } else // no mirroring { if ((DC->bAdjustLuma)||(DC->bAdjustChroma)) // copy when adjust pels { pFrame = (U8 *)DC->p16InstPostProcess; //uYPlane = 0; uYPlane = DC->PostFrame.X32_YPlane; uUPlane = uYPlane + uYPlaneSize; uVPlane = uUPlane + (uYPlaneSize>>2); pSource = (HPBYTE)lpicDecEx->lpSrc; pDestination = (HPBYTE)(DC->p16InstPostProcess + (DWORD)DC->PostFrame.X32_YPlane); FrameCopy (pSource, pDestination, uHeight, uWidth, uWidth); pSource += uYPlaneSize; pDestination += uYPlaneSize; FrameCopy (pSource, pDestination, (uHeight>>1), (uWidth>>1), (uWidth>>1)); pSource += (uYPlaneSize>>2); pDestination += (uYPlaneSize>>2); FrameCopy (pSource, pDestination, (uHeight>>1), (uWidth>>1), (uWidth>>1)); } else { /* Do not have to do memcpy because color convertors don't * destroy input planes. */ pFrame = (HPBYTE)lpicDecEx->lpSrc; uYPlane = 0; uUPlane = uYPlane + uYPlaneSize; uVPlane = uUPlane + (uYPlaneSize>>2); //memcpy(((char FAR *)(DC->p16InstPostProcess + (DWORD)DC->PostFrame.X32_YPlane)), // (const char FAR *)lpicDecEx->lpSrc, // lpicDecEx->lpbiSrc->biSizeImage); } } /* end else if no mirroring */ uYPitch = DC->uFrameWidth; uUVPitch = DC->uFrameWidth >> 1; } /* end else YUV12 */ if (DC->bForceOnAspectRatioCorrection || lpInst->bCorrectAspectRatio) { bShapingFlag = 1; u16NewFrameHeight = (U16) (DC->uFrameHeight * 11 / 12); } else { bShapingFlag = 0; u16NewFrameHeight = (U16) DC->uFrameHeight; } /* Do the PEL color adjustments if necessary. */ if(DC->bAdjustLuma) { /* width is rounded up to a multiple of 8 */ AdjustPels(pFrame, uYPlane, DC->uFrameWidth, uYPitch, DC->uFrameHeight, (U32) DC->X16_LumaAdjustment); } if(DC->bAdjustChroma) { /* width = Y-Width / 4 and then rounded up to a multiple of 8 */ AdjustPels(pFrame, uUPlane, (DC->uFrameWidth >> 1), uUVPitch, (DC->uFrameHeight >> 1), (U32) DC->X16_ChromaAdjustment); AdjustPels(pFrame, uVPlane, (DC->uFrameWidth >> 1), uUVPitch, (DC->uFrameHeight >> 1), (U32) DC->X16_ChromaAdjustment); } /* Determine parameters (lOutput, intPitch, uNewOffsetToLine0) * needed for color conversion. */ if (lpicDecEx->lpbiDst->biCompression == FOURCC_YUY2) { // We are assuming here a positive pitch for YUY2. // This typically corresponds to a negative value for // the destination bit map height. // If we're ever asked to use YUY2 with a positive bit map // height, we'll have to revisit these calculations. intPitch = (lpicDecEx->lpbiDst->biBitCount >> 3) * abs ((int)(lpicDecEx->lpbiDst->biWidth)); lOutput = 0; uNewOffsetToLine0 = 0; #if 0 // Aspect ratio correction is now supported for YUY2. // This is necessary to enable direct draw under Active Movie 1.0. bShapingFlag=FALSE; #endif DBOUT("Using YUY2 ........"); } else if ((lpicDecEx->lpbiDst->biCompression == FOURCC_YUV12) || (lpicDecEx->lpbiDst->biCompression == FOURCC_IYUV)) { intPitch = 0xdeadbeef; // should not be used lOutput = 0; uNewOffsetToLine0 = DC->CCOffsetToLine0; bShapingFlag=FALSE; DBOUT("Using YUV ........"); } else if (lpicDecEx->lpbiDst->biCompression == FOURCC_IF09) { lOutput=0; intPitch = abs((int)(lpicDecEx->lpbiDst->biWidth)); uNewOffsetToLine0 = DC->CCOffsetToLine0; DBOUT("USing IF09........"); } else { lOutput = DibXY(lpicDecEx, &intPitch, lpInst->YScale, bIsDCI); uNewOffsetToLine0 = DC->CCOffsetToLine0; if (!bIsDCI) { // DC->CCOffsetToLine0 was initialized without taking into // account the sign of the destination bitmap height. Let's // compensate for that here. if (lpicDecEx->lpbiDst->biHeight < 0) uNewOffsetToLine0 = 0; // Adjust uNewOffsetToLine0 for aspect ratio correction. if (uNewOffsetToLine0 > 0) { ASSERT(intPitch < 0); if (lpInst->YScale == 2) { uNewOffsetToLine0 += 2 * (U32)intPitch * ((U32)DC->uFrameHeight - (U32)u16NewFrameHeight); } else { uNewOffsetToLine0 += (U32)intPitch * ((U32)DC->uFrameHeight - (U32)u16NewFrameHeight); } } } } /* Call the color convertors */ ///////////////////////////////////////////////////////////////////////////// // Check to see if we need to copy a Snapshot into the output buffer. // I added new fields to the Decoder Catalog to permit asynchronous // transfer of data. These fields are: // DC->SnapshotRequest // DC->SnapshotBuffer // DC->SnapshotEvent // Ben - 09/25/96 ///////////////////////////////////////////////////////////////////////////// if(DC->SnapshotRequest == SNAPSHOT_REQUESTED) { UINT uiSZ_Snapshot; DBOUT("D1DEC:DECOMPRESS::Snapshot requested"); uiSZ_Snapshot = (DC->uFrameWidth * DC->uFrameHeight * 12) >> 3; if(!(IsBadWritePtr(DC->SnapshotBuffer, uiSZ_Snapshot))) { DC->SnapshotRequest = SNAPSHOT_COPY_STARTED; DBOUT("D1DEC:DECOMPRESS::Snapshot copy started"); ColorConvertorCatalog[YUV12NOPITCH].ColorConvertor[0] ( (LPSTR) pFrame + uYPlane, (LPSTR) pFrame + uVPlane, (LPSTR) pFrame + uUPlane, (UN) DC->uFrameWidth, (UN) DC->uFrameHeight, (UN) uYPitch, (UN) uUVPitch, (UN) (bShapingFlag ? 12 : 9999), (LPSTR) DC->SnapshotBuffer, 0, 0, (int) DC->uFrameWidth, YUV12NOPITCH ); DC->SnapshotRequest = SNAPSHOT_COPY_FINISHED; DBOUT("D1DEC:DECOMPRESS::Snapshot copy finished"); } else { DC->SnapshotRequest = SNAPSHOT_COPY_REJECTED; DBOUT("D1DEC:DECOMPRESS::Snapshot copy rejected"); } SetEvent(DC->SnapshotEvent); } #ifndef RING0 #ifdef _DEBUG { char msg[180]; wsprintf(msg, "Decompress before CC: (%d,%d,%d,%d) (%d,%d,%d,%d) lOut %ld, NewOff %ld, DC->Off %ld, pitch %ld", lpicDecEx->xSrc, lpicDecEx->ySrc, lpicDecEx->dxSrc, lpicDecEx->dySrc, lpicDecEx->xDst, lpicDecEx->yDst, lpicDecEx->dxDst, lpicDecEx->dyDst, lOutput, uNewOffsetToLine0, DC->CCOffsetToLine0, intPitch); DBOUT(msg); } #endif #endif #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif ColorConvertorCatalog[DC->ColorConvertor].ColorConvertor[PENTIUM_CC]( (LPSTR) pFrame + uYPlane, (LPSTR) pFrame + uVPlane, (LPSTR) pFrame + uUPlane, (UN) DC->uFrameWidth, (UN) DC->uFrameHeight, (UN) uYPitch, (UN) uUVPitch, // ??? BSE ??? // (UN) (bShapingFlag ? 12 : 9999), // ??? BSE ??? // (LPSTR) lpicDecEx->lpDst, (U32) lOutput, (U32) uNewOffsetToLine0, (int) intPitch, // Color converter pitch DC->ColorConvertor); #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uOutputCCSum); #endif iReturn = ICERR_OK; done: if (DC != NULL) { if (DC->DecoderType == H263_CODEC) { #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif H261ReInitializeBlockActionStream(DC); #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uInitBlkActStrSum) #endif } /* end if (DC->DecoderType == H263_CODEC) */ #ifdef DECODE_STATS TIMER_STOP(bTimingThisFrame,uStartLow,uStartHigh,uDecodeFrameSum); if (bTimingThisFrame) { pDecTimingInfo = DC->pDecTimingInfo + DC->uStatFrameCount; pDecTimingInfo->uDecodeFrame = uDecodeFrameSum; pDecTimingInfo->uHeaders += uHeadersSum; pDecTimingInfo->uMemcpy = uMemcpySum; pDecTimingInfo->uFrameCopy = uFrameCopySum; pDecTimingInfo->uOutputCC = uOutputCCSum; pDecTimingInfo->uInitBlkActStr = uInitBlkActStrSum; pDecTimingInfo->uBEF = uBEFSum; DC->uStatFrameCount++; /* Verify that we have time for all the required steps */ ASSERT(pDecTimingInfo->uDecodeFrame); ASSERT(pDecTimingInfo->uHeaders); ASSERT(pDecTimingInfo->uMemcpy); ASSERT(pDecTimingInfo->uFrameCopy); ASSERT(pDecTimingInfo->uOutputCC); /* ASSERT(pDecTimingInfo->uDecodeBlock); 0 if all are empty */ ASSERT(pDecTimingInfo->uInitBlkActStr); ASSERT(pDecTimingInfo->uBEF); } #endif } return iReturn; } //************************************************************************ // //H263TermDecoderInstance -- This function frees the space allocated for an // instance of the H263 decoder. // //************************************************************************ LRESULT H263TermDecoderInstance(LPDECINST lpInst) { LRESULT iReturn = ICERR_OK; T_H263DecoderCatalog * DC; if(IsBadWritePtr((LPVOID)lpInst, sizeof(DECINSTINFO))) { DBOUT("ERROR :: H263TermDecoderInstance :: ICERR_BADPARAM"); iReturn = ICERR_BADPARAM; } if(lpInst->Initialized == FALSE) { DBOUT("Warning: H263TermDecoderInstance(): Uninitialized instance") return(ICERR_OK); } lpInst->Initialized = FALSE; DC = (T_H263DecoderCatalog *) ((((U32) lpInst->pDecoderInst) + 31) & ~0x1F); CloseHandle(DC->SnapshotEvent); if (DC->a16InstPostProcess != NULL) { HeapFree(GetProcessHeap(), 0, DC->a16InstPostProcess); // PhilF: Also freed in H263TerminateDecoderInstance! For now set to NULL to avoid second HeapFree. // Investigate reason for 2nd call later... DC->a16InstPostProcess = NULL; } HeapFree(GetProcessHeap(), 0, lpInst->pDecoderInst); return iReturn; } //**************************************************************************** //DibXY -- This function is used to map color converted output to the screen. //note: this function came from the H261 code base. //**************************************************************************** static long DibXY(ICDECOMPRESSEX FAR *lpicDecEx, LPINT lpiPitch, UINT yScale, BOOL bIsDCI) { int iPitch; /* width of DIB */ long lOffset = 0; LPBITMAPINFOHEADER lpbi = lpicDecEx->lpbiDst; iPitch = (((abs((int)lpbi->biWidth) * (int)lpbi->biBitCount) >> 3) + 3) & ~3; // The source and destination rectangles in lpicDecEx are only // meaningful if bIsDCI is true (because throughout our codec, if bIsDCI // is FALSE, we put zeroes in these rectangles). This may change, at // some later point, if we decide (or are required) to make use of the // rcSource and rcTarget rectangles that are associated with an Active // Movie media sample. if (!bIsDCI) { if (lpbi->biHeight >= 0) { // Typically for RGB, a positive bitmap height corresponds // to a negative pitch. iPitch = -iPitch; } } else { if(lpicDecEx->xDst > 0) /* go to proper X position */ lOffset += ((long)lpicDecEx->xDst * (long)lpbi->biBitCount) >> 3; if(lpbi->biHeight * lpicDecEx->dxSrc < 0) { /* DIB is bottom to top */ lOffset += (long) abs((int)lpbi->biWidth) * (long) abs((int)lpbi->biHeight) * ((long) lpbi->biBitCount >> 3) - (long) iPitch; /***************************************************************************/ /***** This next line is used to subtract the amount that Brian added *****/ /***** to CCOffsetToLine0 in COLOR.C during initialization. This is *****/ /***** needed because for DCI, the pitch he used is incorrect. *****/ /***************************************************************************/ lOffset -= ((long) yScale * (long)lpicDecEx->dySrc - 1) * (long) lpicDecEx->dxDst * ((long) lpbi->biBitCount >> 3); iPitch = -iPitch; } if(lpicDecEx->yDst > 0) /* go to proper Y position */ lOffset += ((long)lpicDecEx->yDst * (long)iPitch); if(lpicDecEx->dxSrc > 0) { lOffset += ((long)lpicDecEx->dyDst * (long)iPitch) - (long)iPitch; iPitch = -iPitch; } if((lpicDecEx->dxDst == 0) && (lpicDecEx->dyDst == 0)) iPitch = -iPitch; } *lpiPitch = iPitch; return(lOffset); } /************************************************************************ * * GetDecoderOptions * * Get the options, saving them in the catalog */ static void GetDecoderOptions( T_H263DecoderCatalog * DC) { int bSetOptions = 1; /* Default Options */ const int bDefaultForceOnAspectRatioCorrection = 0; const int bDefaultUseBlockEdgeFilter = 1; /* INI file variables */ #ifndef RING0 UN unResult; #define SECTION_NAME "Decode" #define INI_FILE_NAME "h261test.ini" #ifdef _DEBUG char buf132[132]; #endif #endif /* Read the options from the INI file */ #ifndef RING0 { DBOUT("Getting decode options from the ini file h261test.ini"); /* BlockEdgeFilter */ unResult = GetPrivateProfileInt(SECTION_NAME, "BlockEdgeFilter", bDefaultUseBlockEdgeFilter, INI_FILE_NAME); if (unResult != 0 && unResult != 1) { #ifdef _DEBUG wsprintf(buf132,"BlockEdgeFilter ini value error (should be 0 or 1) - using default=%d", (int) bDefaultUseBlockEdgeFilter); DBOUT(buf132); #endif unResult = bDefaultUseBlockEdgeFilter; } DC->bUseBlockEdgeFilter = unResult; /* Force on aspect ratio correction. */ unResult = GetPrivateProfileInt(SECTION_NAME, "ForceOnAspectRatioCorrection", bDefaultForceOnAspectRatioCorrection, INI_FILE_NAME); if (unResult != 0 && unResult != 1) { #ifdef _DEBUG wsprintf(buf132,"ForceOnAspectRatioCorrection ini value error (should be 0 or 1) - using default=%d", (int) bDefaultForceOnAspectRatioCorrection); DBOUT(buf132); #endif unResult = bDefaultForceOnAspectRatioCorrection; } DC->bForceOnAspectRatioCorrection = unResult; bSetOptions = 0; } #endif if (bSetOptions) { DC->bUseBlockEdgeFilter = bDefaultUseBlockEdgeFilter; DC->bForceOnAspectRatioCorrection = bDefaultForceOnAspectRatioCorrection; } /* Can only use force aspect ratio correction on if SQCIF, QCIF, or CIF */ if (DC->bForceOnAspectRatioCorrection) { if (! ( ((DC->uFrameWidth == 128) && (DC->uFrameHeight == 96)) || ((DC->uFrameWidth == 176) && (DC->uFrameHeight == 144)) || ((DC->uFrameWidth == 352) && (DC->uFrameHeight == 288)) ) ) { DBOUT("Aspect ratio correction can not be forced on unless the dimensions are SQCIF, QCIF, or CIF"); DC->bForceOnAspectRatioCorrection = 0; } } /* Display the options */ if (DC->bUseBlockEdgeFilter) { DBOUT("Decoder option (BlockEdgeFilter) is ON"); } else { DBOUT("Decoder option (BlockEdgeFilter) is OFF"); } if (DC->bForceOnAspectRatioCorrection) { DBOUT("Decoder option (ForceOnAspectRatioCorrection) is ON"); } else { DBOUT("Decoder option (ForceOnAspectRatioCorrection) is OFF"); } DBOUT("Decoder option (MMX) is OFF: get a life, get MMX"); } /* end GetDecoderOptions() */ /*********************************************************************** * Description: * This routine parses the bit-stream and initializes two major streams: * 1) pN: no of coefficients in each of the block (biased by 65 for INTRA) * 2) pRun_INVERSE_Q: de-quantized coefficient stream for the frame; * MMX stream is scaled because we use scaled IDCT. * Other information (e.g. MVs) is kept in decoder catalog, block action * stream, and MB infor stream. * Parameters: * DC: Decoder catalog ptr * fpBlockAction: block action stream ptr * fpMBInfo: Macroblock info ptr * fpbsState: bit-stream state pointer * fpu8MaxPtr: sentinel value to check for bit-stream overruns * pN: stream of no. of coeffs (biased by block type) for each block * pRun_INVERSE_Q:stream of de-quantized (and scaled if using MMX) coefficients * iNumberOfGOBs: no. of GOBs in the frame * iNumberOfMBs: no. of MBs in a GOB in the frame * iGOB_start: * iMB_start: * Note: ***********************************************************************/ #pragma code_seg("IACODE1") // #ifndef LOSS_RECOVERY #if 0 static LRESULT IAPass1ProcessFrame( T_H263DecoderCatalog *DC, T_BlkAction *fpBlockAction, T_MBInfo *fpMBInfo, BITSTREAM_STATE *fpbsState, U8 *fpu8MaxPtr, U32 *pN, T_IQ_INDEX *pRUN_INVERSE_Q, const I32 iNumberOfGOBs, const I32 iNumberOfMBs, const I32 iGOB_start, const I32 iMB_start ) { I32 g, iReturn, iBlockNumber = 0 ; I32 mb_start = iMB_start; U32 *pNnew; U32 uReadChecksum = 0; I8 i; I8 tmpcnt; #ifdef DECODE_STATS U32 uStartLow = DC->uStartLow; U32 uStartHigh = DC->uStartHigh; U32 uElapsed; U32 uBefore; U32 uHeadersSum = 0; int bTimingThisFrame = DC->bTimingThisFrame; DEC_TIMING_INFO *pDecTimingInfo = NULL; #endif #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif /* move decode of GOB start code outside of GOB header processing */ /* because if processing skipped macroblocks, looking for the last MBA */ /* will find the next start code */ iReturn = H263DecodeGOBStartCode(DC, fpbsState); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress :: Error reading the GOB StartCode"); goto done; } #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif for (g = 1 ; g <= iNumberOfGOBs; g++) { #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif iReturn = H263DecodeGOBHeader(DC, fpbsState, g); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress :: Error reading the GOB header"); goto done; } #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif DC->i16LastMBA = -1; DC->i8MVDH = DC->i8MVDV = 0; // re-sync iBlockNumber, fpBlockAction, fpMBInfo at this point iBlockNumber = (g - 1) * iNumberOfMBs*6; fpBlockAction = (T_BlkAction FAR *)((U8 *)DC + DC->X16_BlkActionStream); fpMBInfo = (T_MBInfo FAR *) ((U8 *)DC + DC->X32_uMBInfoStream); fpBlockAction += iBlockNumber; fpMBInfo += iBlockNumber/6; pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + iBlockNumber; while (pN < pNnew ) *pN++ = 0; /* For each MB until START_CODE detected do ... */ for (; ; iBlockNumber += 6, fpBlockAction += 6, fpMBInfo++) { #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif iReturn = H263DecodeMBHeader(DC, fpbsState, &uReadChecksum); #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif if (iReturn == START_CODE) break; /* If we didn't see a start code, then we either got an error, * or we have another MBA delta in DC->uMBA. */ if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress (First Pass) :: Error reading MB header"); goto error; } /* Update MBA */ DC->i16LastMBA += (I16)DC->uMBA; if (DC->i16LastMBA > 32) { DBOUT("ERROR :: H263Decompress :: Bad Macro Block Address"); goto done; } /* New for rearch */ /* adjust for empty macroblocks */ for ( tmpcnt = (I8)DC->uMBA; tmpcnt > 1; tmpcnt--) { for (i=0; i<6; i++) { *pN = 0; pN++; } iBlockNumber += 6; fpBlockAction += 6; /* Default fpBlockAction values were already initialized * in (Re)InitializeBlockActionStream. */ fpMBInfo->i8MBType = 2; fpMBInfo++; } fpMBInfo->i8MBType = (I8)DC->uMBType; // New rearch /* end of new rearch */ // decode and inverse quantize the transform coefficients iReturn = H263DecodeMBData(DC, fpBlockAction, iBlockNumber, fpbsState, fpu8MaxPtr, &uReadChecksum, &pN, &pRUN_INVERSE_Q); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress (First Pass) :: Error parsing MB data"); goto error; } } // end for each MB /* Fill in arrays and advance Block Action stream when there are skip MB at the end of each GOB */ while (iBlockNumber != (I32)g*198) { for (i=0; i<6; i++) { *pN = 0; pN++; } iBlockNumber += 6; fpBlockAction+= 6; /* Default fpBlockAction values were already initialized * in (Re)InitializeBlockActionStream. */ fpMBInfo->i8MBType = 2; fpMBInfo++; } /* allow the pointer to address up to four beyond the end - reading * by DWORD using postincrement. */ // ASSERT(fpbsState->fpu8 <= fpu8MaxPtr+4); if (fpbsState->fpu8 > fpu8MaxPtr+4) goto error; } // End for each GOB #ifdef DECODE_STATS if (bTimingThisFrame) { pDecTimingInfo = DC->pDecTimingInfo + DC->uStatFrameCount; pDecTimingInfo->uHeaders += uHeadersSum; } #endif done: return ICERR_OK; error: return ICERR_ERROR; } #else static LRESULT IAPass1ProcessFrameRTP( T_H263DecoderCatalog *DC, T_BlkAction *fpBlockAction, T_MBInfo *fpMBInfo, BITSTREAM_STATE *fpbsState, U8 *fpu8MaxPtr, U32 *pN, T_IQ_INDEX *pRUN_INVERSE_Q, const I32 iNumberOfGOBs, const I32 iNumberOfMBs, const I32 iGOB_start, const I32 iMB_start ) { BITSTREAM_STATE fpbsStateSave; I32 g, current_g, iReturn, iBlockNumber = 0 ; I32 mb_start = iMB_start; U32 *pNnew; U32 uReadChecksum = 0; I8 i; I8 tmpcnt; I32 g_skip, gtmp; I32 uMaxGOBNumber, uGOBStep, uMaxBlockNumber; #ifdef DECODE_STATS U32 uStartLow = DC->uStartLow; U32 uStartHigh = DC->uStartHigh; U32 uElapsed; U32 uBefore; U32 uHeadersSum = 0; int bTimingThisFrame = DC->bTimingThisFrame; DEC_TIMING_INFO *pDecTimingInfo = NULL; #endif #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif /* move decode of GOB start code outside of GOB header processing */ /* because if processing skipped macroblocks, looking for the last MBA */ /* will find the next start code */ iReturn = H263DecodeGOBStartCode(DC, fpbsState); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB StartCode"); goto done; } #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif if (iNumberOfGOBs == 3) { uMaxGOBNumber = 5; uGOBStep = 2; } else { uMaxGOBNumber = 12; uGOBStep = 1; } for (g = 1; g <= uMaxGOBNumber; g+=uGOBStep) { current_g = g; #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif iReturn = H263DecodeGOBHeader(DC, fpbsState, g); // #ifndef LOSS_RECOVERY #if 0 if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB header"); goto done; } #else if (iReturn == PACKET_FAULT_AT_MB_OR_GOB) { DBOUT("Packet fault at MBA or GBSC detected."); current_g -= uGOBStep; // back up to previous GOB iReturn = RtpH261FindNextPacket(DC, fpbsState, &pN, (U32 *)&(DC->uPQuant), (int *)&mb_start, (int *) &g ); switch (iReturn) { case NEXT_MODE_STARTS_GOB: // Next packet is the start of a GOB; mark missing // macroblocks as skipped, then read GOB start code, // and continue in the GOB loop. // Save bitstream state DBOUT("Next packet is NEXT_MODE_STARTS_GOB"); fpbsStateSave.fpu8 = fpbsState->fpu8; fpbsStateSave.uWork = fpbsState->uWork; fpbsStateSave.uBitsReady = fpbsState->uBitsReady; // Read GOB start code iReturn = H263DecodeGOBStartCode(DC, fpbsState); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB StartCode"); goto done; } // Read GOB Header iReturn = H263DecodeGOBHeader(DC, fpbsState, g); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB header"); goto done; } g = DC->uGroupNumber; // Restore bitstream state fpbsState->fpu8 = fpbsStateSave.fpu8; fpbsState->uWork = fpbsStateSave.uWork; fpbsState->uBitsReady = fpbsStateSave.uBitsReady; // re-sync iBlockNumber, fpBlockAction, fpMBInfo at this point if (DC->uSrcFormat == SRC_FORMAT_QCIF) g_skip = (g - 1) >> 1; else g_skip = g - 1 ; iBlockNumber = g_skip * iNumberOfMBs * 6; fpBlockAction = (T_BlkAction FAR *)((U8 *)DC + DC->X16_BlkActionStream); fpMBInfo = (T_MBInfo FAR *) ((U8 *)DC + DC->X32_uMBInfoStream); fpBlockAction += iBlockNumber; fpMBInfo += iBlockNumber/6; pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + iBlockNumber; while (pN < pNnew ) *pN++ = 0; // Now read the GOB start code and get ready to // process the new GOB. iReturn = H263DecodeGOBStartCode(DC, fpbsState); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB StartCode"); goto done; } g -= uGOBStep; continue; break; case NEXT_MODE_STARTS_MB : // Next packet starts with a macroblock; check the // GOB Number and mark all lost macroblocks as // skipped; initialize MBA and motion vector // predictors from the block action stream and // jump to the macroblock loop DBOUT("Next packet is NEXT_MODE_STARTS_MB"); if (DC->uSrcFormat == SRC_FORMAT_QCIF) g_skip = (g - 1) >> 1; else g_skip = g - 1; iBlockNumber = iNumberOfMBs * g_skip * 6 + (mb_start+1) * 6; fpBlockAction = (T_BlkAction FAR *)((U8 *)DC + DC->X16_BlkActionStream); fpMBInfo = (T_MBInfo FAR *) ((U8 *)DC + DC->X32_uMBInfoStream); fpBlockAction += iBlockNumber; fpMBInfo += iBlockNumber/6; DC->uMQuant = DC->uPQuant; //DC->i16LastMBA = (U16) (mb_start - 1); DC->i16LastMBA = (U16) (mb_start); pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + iBlockNumber; while (pN < pNnew ) *pN++ = 0; goto MB_LOOP; break; case NEXT_MODE_LAST: // all remaining packets in frame lost !! DBOUT("Next packet is NEXT_MODE_LAST"); uMaxBlockNumber = iNumberOfMBs * iNumberOfGOBs * 6; pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + uMaxBlockNumber; while (pN < pNnew ) *pN++ = 0; iReturn = ICERR_OK; goto done; break; default: // should never happen !! iReturn = ICERR_ERROR; goto done; } // end switch } else { if (iReturn == PACKET_FAULT_AT_PSC) // can only happen for the PSC packet { DBOUT("PSC packet fault detected"); iReturn = RtpGetPicHeaderFromBsExt(DC); if (iReturn != ICERR_OK) { DBOUT("ERROR:: cannot read Picture Header from RTP Trailer"); goto done; } iReturn = RtpH261FindNextPacket(DC, fpbsState, &pN, (U32 *)&(DC->uPQuant), (int *)&mb_start, (int *) &g); switch (iReturn) { case NEXT_MODE_STARTS_GOB: // Next packet is the start of a GOB; mark missing // macroblocks as skipped, then read GOB start code, // and continue in the GOB loop. // re-sync iBlockNumber, fpBlockAction, fpMBInfo at this point // Save bitstream state DBOUT("Next packet is NEXT_MODE_STARTS_GOB"); fpbsStateSave.fpu8 = fpbsState->fpu8; fpbsStateSave.uWork = fpbsState->uWork; fpbsStateSave.uBitsReady = fpbsState->uBitsReady; // Read GOB start code iReturn = H263DecodeGOBStartCode(DC, fpbsState); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB StartCode"); goto done; } // Read GOB Header iReturn = H263DecodeGOBHeader(DC, fpbsState, g); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB header"); goto done; } g = DC->uGroupNumber; // Restore bitstream state fpbsState->fpu8 = fpbsStateSave.fpu8; fpbsState->uWork = fpbsStateSave.uWork; fpbsState->uBitsReady = fpbsStateSave.uBitsReady; if (DC->uSrcFormat == SRC_FORMAT_QCIF) g_skip = (g - 1) >> 1; else g_skip = g - 1; iBlockNumber = g_skip * iNumberOfMBs * 6; fpBlockAction = (T_BlkAction FAR *)((U8 *)DC + DC->X16_BlkActionStream); fpMBInfo = (T_MBInfo FAR *) ((U8 *)DC + DC->X32_uMBInfoStream); fpBlockAction += iBlockNumber; fpMBInfo += iBlockNumber/6; pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + iBlockNumber; while (pN < pNnew ) *pN++ = 0; // Now read the GOB start code and get ready to // process the new GOB. iReturn = H263DecodeGOBStartCode(DC, fpbsState); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H261Decompress :: Error reading the GOB StartCode"); goto done; } g -= uGOBStep; continue; break; case NEXT_MODE_STARTS_MB : // Next packet starts with a macroblock; check the // GOB Number and mark all lost macroblocks as // skipped; initialize MBA and motion vector // predictors from the block action stream and // jump to the macroblock loop DBOUT("Next packet is NEXT_MODE_STARTS_MB"); if (DC->uSrcFormat == SRC_FORMAT_QCIF) g_skip = (g - 1) >> 1; else g_skip = g - 1; iBlockNumber = iNumberOfMBs * g_skip * 6 + (mb_start+1) * 6; fpBlockAction = (T_BlkAction FAR *)((U8 *)DC + DC->X16_BlkActionStream); fpMBInfo = (T_MBInfo FAR *) ((U8 *)DC + DC->X32_uMBInfoStream); fpBlockAction += iBlockNumber; fpMBInfo += iBlockNumber/6; DC->uMQuant = DC->uPQuant; //DC->i16LastMBA = (U16) (mb_start - 1); DC->i16LastMBA = (U16) (mb_start); pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + iBlockNumber; while (pN < pNnew ) *pN++ = 0; goto MB_LOOP; break; case NEXT_MODE_LAST: // all remaining packets in frame lost !! DBOUT("Next packet is NEXT_MODE_LAST"); uMaxBlockNumber = iNumberOfMBs * iNumberOfGOBs * 6; pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + uMaxBlockNumber; while (pN < pNnew ) *pN++ = 0; iReturn = ICERR_OK; goto done; break; default: // should never happen !! iReturn = ICERR_ERROR; goto done; } // end switch } // if .. PACKET_FAULT_AT_PSC else { if (iReturn == ICERR_ERROR) { DBOUT("ERROR :: H261Decompress :: Error reading GOB header"); DBOUT(" Packet fault not detected"); goto done; } // Outdated: Do the source format check here when it is known that // the PSC was not the canned one from the PPM. /* if (DC->bReadSrcFormat && DC->uPrevSrcFormat != DC->uSrcFormat) { DBOUT("ERROR::src format changed detected with no packet loss"); DBOUT(" not supported ... bailing out"); iReturn=ICERR_ERROR; goto done; } DC->uPrevSrcFormat = DC->uSrcFormat; DC->bReadSrcFormat = TRUE; */ } } #endif #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif DC->i16LastMBA = -1; DC->i8MVDH = DC->i8MVDV = 0; // re-sync iBlockNumber, fpBlockAction, fpMBInfo at this point if (DC->uSrcFormat == SRC_FORMAT_QCIF) iBlockNumber = ((g - 1)>>1) * iNumberOfMBs*6; else iBlockNumber = (g - 1)* iNumberOfMBs*6; fpBlockAction = (T_BlkAction FAR *)((U8 *)DC + DC->X16_BlkActionStream); fpMBInfo = (T_MBInfo FAR *) ((U8 *)DC + DC->X32_uMBInfoStream); fpBlockAction += iBlockNumber; fpMBInfo += iBlockNumber/6; pNnew = (U32 *)((U8 *)DC + DC->X32_pN) + iBlockNumber; while (pN < pNnew ) *pN++ = 0; /* For each MB until START_CODE detected do ... */ MB_LOOP: for (; ; iBlockNumber += 6, fpBlockAction += 6, fpMBInfo++) { #ifdef DECODE_STATS TIMER_BEFORE(bTimingThisFrame,uStartLow,uStartHigh,uBefore); #endif iReturn = H263DecodeMBHeader(DC, fpbsState, &uReadChecksum); #ifdef DECODE_STATS TIMER_AFTER_P5(bTimingThisFrame,uStartLow,uStartHigh,uBefore,uElapsed,uHeadersSum) #endif if (iReturn == START_CODE) break; /* If we didn't see a start code, then we either got an error, * or we have another MBA delta in DC->uMBA. */ if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress (First Pass) :: Error reading MB header"); goto error; } /* Update MBA */ DC->i16LastMBA += (I16)DC->uMBA; if (DC->i16LastMBA > 32) { DBOUT("ERROR :: H263Decompress :: Bad Macro Block Address"); goto done; } /* New for rearch */ /* adjust for empty macroblocks */ for ( tmpcnt = (I8)DC->uMBA; tmpcnt > 1; tmpcnt--) { for (i=0; i<6; i++) { *pN = 0; pN++; } iBlockNumber += 6; fpBlockAction += 6; /* Default fpBlockAction values were already initialized * in (Re)InitializeBlockActionStream. */ fpMBInfo->i8MBType = 2; fpMBInfo++; } fpMBInfo->i8MBType = (I8)DC->uMBType; // New rearch /* end of new rearch */ // decode and inverse quantize the transform coefficients iReturn = H263DecodeMBData(DC, fpBlockAction, iBlockNumber, fpbsState, fpu8MaxPtr, &uReadChecksum, &pN, &pRUN_INVERSE_Q); if (iReturn != ICERR_OK) { DBOUT("ERROR :: H263Decompress (First Pass) :: Error parsing MB data"); goto error; } } // end for each MB /* Fill in arrays and advance Block Action stream when there are skip MB at the end of each GOB */ if (DC->uSrcFormat == SRC_FORMAT_QCIF) { switch (g) { case 1: gtmp = 1; break; case 3: gtmp = 2; break; case 5: gtmp = 3; break; default: DBOUT("Bad GOB Number"); iReturn = ICERR_ERROR; goto error; break; } } else gtmp = g; while (iBlockNumber != (I32)gtmp*198) { for (i=0; i<6; i++) { *pN = 0; pN++; } iBlockNumber += 6; fpBlockAction+= 6; /* Default fpBlockAction values were already initialized * in (Re)InitializeBlockActionStream. */ fpMBInfo->i8MBType = 2; fpMBInfo++; } /* allow the pointer to address up to four beyond the end - reading * by DWORD using postincrement. */ ASSERT(fpbsState->fpu8 <= fpu8MaxPtr+4); } // End for each GOB #ifdef DECODE_STATS if (bTimingThisFrame) { pDecTimingInfo = DC->pDecTimingInfo + DC->uStatFrameCount; pDecTimingInfo->uHeaders += uHeadersSum; } #endif done: return ICERR_OK; error: return ICERR_ERROR; } #endif #pragma code_seg() /*********************************************************************** * Description: * This routines does IDCT and motion compensation. * Parameters: * DC: Decoder catalog ptr * fpBlockAction: block action stream ptr * fpMBInfo: Macroblock info ptr * pN: stream of no. of coeffs (biased by block type) for each block * pRun_INVERSE_Q:stream of de-quantized (and scaled if using MMX) coefficients * iNumberOfGOBs: no. of GOBs in the frame * iNumberOfMBs: no. of MBs in a GOB in the frame * Note: ***********************************************************************/ #pragma code_seg("IACODE2") static void IAPass2ProcessFrame( T_H263DecoderCatalog *DC, T_BlkAction *fpBlockAction, T_MBInfo *fpMBInfo, U32 *pN, T_IQ_INDEX *pRUN_INVERSE_Q, const I32 iNumberOfGOBs, const I32 iNumberOfMBs ) { I32 g, m, b, iEdgeFlag=0; // for each GOB do for (g = 1 ; g <= iNumberOfGOBs; g++) { // for each MB do for (m = 1; m <= iNumberOfMBs; m++, fpBlockAction+=6, fpMBInfo++) { // for each block do for (b = 0; b < 6; b++) { // AP-NEW // do inverse transform & motion compensation for the block H263IDCTandMC(DC, fpBlockAction, b, m, g, pN, pRUN_INVERSE_Q, fpMBInfo, iEdgeFlag); // AP-NEW // Adjust pointers for next block if ( *pN >= 65 ) pRUN_INVERSE_Q += *pN - 65; else pRUN_INVERSE_Q += *pN; pN++; } // end for each block } // end for each MB } // End for each GOB } #pragma code_seg() // rearch