Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3625 lines
110 KiB

/* *************************************************************************
** 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 Intel Corporation.
** All Rights Reserved.
**
** *************************************************************************
*/
/*****************************************************************************
* e3enc.cpp
*
* DESCRIPTION:
* Specific encoder compression functions.
*
* Routines: Prototypes in:
* H263InitEncoderInstance
* H263Compress
* H263TermEncoderInstance
*
*
*
* $Author: JMCVEIGH $
* $Date: 05 Feb 1997 12:19:24 $
* $Archive: S:\h26x\src\enc\e3mbenc.cpv $
* $Header: S:\h26x\src\enc\e3mbenc.cpv 1.54 05 Feb 1997 12:19:24 JMCVEIGH $
* $Log: S:\h26x\src\enc\e3mbenc.cpv $
//
// Rev 1.54 05 Feb 1997 12:19:24 JMCVEIGH
// Support for separate improved PB-frame flag.
//
// Rev 1.53 19 Dec 1996 16:02:04 JMCVEIGH
//
// And'ed CodedBlocksB with 0x3f to surpress high bit that indicates
// if only forward prediction is to be used in improved PB-frame mode.
// This is done in the VLC generation of CBPB and the block coeffs.
//
// Rev 1.52 16 Dec 1996 17:50:38 JMCVEIGH
// Encoding of MODB for improved PB-frame mode.
//
// Rev 1.51 05 Dec 1996 17:02:32 GMLIM
//
// Changed the way RTP packetization was done to guarantee proper packet
// size. Calls to update bitstream info buffer were modified.
//
// Rev 1.50 06 Nov 1996 16:30:32 gmlim
// Removed H263ModeC.
//
// Rev 1.49 05 Nov 1996 13:33:48 GMLIM
// Added mode c support for mmx case.
//
// Rev 1.48 03 Nov 1996 18:47:02 gmlim
// Modified to generate
// rtp bs ext. for mode c.
//
// Rev 1.47 28 Oct 1996 12:03:16 KLILLEVO
// fixed an EMV bug in the writing of motion vectors for the PB-frame
//
// Rev 1.46 24 Oct 1996 16:27:40 KLILLEVO
//
// changed from DBOUT to DbgLog
//
// Rev 1.45 22 Oct 1996 17:09:04 KLILLEVO
// reversed the condition on whether or not to skip a macroblock.
// Fall-through is now coded.
// Set the pCurMB->COD member properly and use that in the coded/
// not-coded test in the PB-frame encoding instead of repeating
// the same test as in the P-frame case.
//
// Rev 1.44 14 Oct 1996 11:58:42 KLILLEVO
// EMV bug fixed
//
// Rev 1.43 04 Oct 1996 08:43:16 KLILLEVO
// initial support for extended motion vectors
//
// Rev 1.42 13 Sep 1996 12:48:04 KLILLEVO
// cleaned up intra update code to make it more understandable
//
// Rev 1.41 10 Sep 1996 17:51:42 KLILLEVO
// moved reset of InterCodeCnt to e3enc.cpp CalcGobChroma..._InterCodeCnt
//
// Rev 1.40 09 Sep 1996 17:05:50 KLILLEVO
// changed small type in intercodecnt increment
//
// Rev 1.39 06 Sep 1996 16:12:24 KLILLEVO
// fixed the logical problem that the inter code count was always
// incremented no matter whether coefficients were transmitted or not
//
// Rev 1.38 03 May 1996 10:53:56 KLILLEVO
//
// cleaned up and fixed indentation in two routines which might
// need to be rewritten for MMX PB-frames
//
// Rev 1.37 28 Apr 1996 20:19:30 BECHOLS
//
// Merged RTP code into Main Base.
//
// Rev 1.36 15 Mar 1996 15:58:56 BECHOLS
//
// added support for monolithic MMx code with separate passes over
// luma and chroma.
//
// Rev 1.35 22 Feb 1996 18:52:44 BECHOLS
//
// Added boolean to switch between MMX and P5 quantization function.
//
// Rev 1.34 26 Jan 1996 16:25:42 TRGARDOS
// Added conditional compilation code to count bits.
//
// Rev 1.33 12 Jan 1996 16:34:30 BNICKERS
//
// Fix numerous macroblock layer bugs w.r.t. PB encoding.
//
// Rev 1.32 22 Dec 1995 11:12:46 TRGARDOS
// Fixed bug in MV prediction calculation for blocks 2-4 of
// AP. Was not zeroing outside motion vectors when their
// block was INTRA coded.
//
// Rev 1.31 18 Dec 1995 12:40:18 RMCKENZX
// added copyright notice
//
// Rev 1.30 13 Dec 1995 22:00:58 TRGARDOS
// Changed MV predictor to not use ME state variable.
//
// Rev 1.29 13 Dec 1995 12:18:38 RMCKENZX
// Restored version 1.27
//
// Rev 1.27 11 Dec 1995 10:00:30 TRGARDOS
// Fixed debug messages for motion vectors.
//
// Rev 1.26 06 Dec 1995 12:06:26 TRGARDOS
// Finished 4MV support in MV delta and VLC/bit stream writing.
//
// Rev 1.25 05 Dec 1995 10:20:30 TRGARDOS
// Fixed MV predictors in GOBs with headers.
//
// Rev 1.24 09 Nov 1995 14:11:24 AGUPTA2
// PB-frame+performance+structure enhancements.
//
// Rev 1.23 19 Oct 1995 11:35:14 BNICKERS
// Made some changes to MacroBlockActionDescriptor structure to support B-Fram
// Motion Estimation and Frame Differencing. Added some arguments to ME and F
//
// Rev 1.22 12 Oct 1995 17:39:34 TRGARDOS
// Fixed bug in MV prediction.
//
// Rev 1.21 03 Oct 1995 18:34:26 BECHOLS
// Changed the table sizes to reduce the memory requirements for the
// data to about half. This also required a change to the initialization
// routine that sets up TCOEF_ and TCOEF_LAST_ tables.
//
// Rev 1.20 03 Oct 1995 09:21:34 TRGARDOS
// Fixed bug VLC encoding regarding MV prediction.
//
// Rev 1.19 29 Sep 1995 17:14:06 TRGARDOS
// Fixed offset value for cur to prev frame
//
// Rev 1.18 27 Sep 1995 19:10:02 TRGARDOS
//
// Fixed bug in writing MB headers.
//
// Rev 1.17 27 Sep 1995 11:26:30 TRGARDOS
// Integrated motion estimation.
//
// Rev 1.16 18 Sep 1995 17:08:54 TRGARDOS
// Debugged delta frames.
//
// Rev 1.15 15 Sep 1995 16:37:32 TRGARDOS
//
//
// Rev 1.14 13 Sep 1995 10:26:44 AGUPTA2
// Added blockType flag to QUANTRLE and changed the name to all upper-case.
//
// Rev 1.13 11 Sep 1995 14:10:42 BECHOLS
//
// Changed this module to call the VLC routine in E35VLC.ASM. I also
// renamed a couple of tables for clarity, and moved tables that I needed
// to the ASM module.
//
// Rev 1.12 08 Sep 1995 17:39:30 TRGARDOS
// Added more decoder code to encoder.
//
// Rev 1.11 07 Sep 1995 17:46:30 TRGARDOS
// Started adding delta frame support.
//
// Rev 1.10 05 Sep 1995 15:50:20 TRGARDOS
//
// Rev 1.9 05 Sep 1995 11:36:26 TRGARDOS
//
// Rev 1.8 01 Sep 1995 17:51:10 TRGARDOS
// Added DCT print routine.
//
// Rev 1.7 01 Sep 1995 10:13:32 TRGARDOS
// Debugging bit stream errors.
//
// Rev 1.6 31 Aug 1995 11:00:44 TRGARDOS
// Cut out MB VLC code.
//
// Rev 1.5 30 Aug 1995 12:42:22 TRGARDOS
// Fixed bugs in intra AC coef VLC coding.
//
// Rev 1.4 29 Aug 1995 17:19:16 TRGARDOS
//
//
// Rev 1.3 25 Aug 1995 10:36:20 TRGARDOS
//
// Fixed bugs in integration.
//
// Rev 1.2 22 Aug 1995 17:20:14 TRGARDOS
// Finished integrating asm quant & rle.
//
// Rev 1.1 22 Aug 1995 10:26:32 TRGARDOS
// Removed compile errors for adding quantization asm code.
//
// Rev 1.0 21 Aug 1995 16:30:04 TRGARDOS
// Initial revision.
//
// Add quantization hooks and call RTP MB packetization only if
// the bRTPHeader boolean is true
//
*/
#include "precomp.h"
/*
* VLC table for MCBPC for INTRA pictures.
* Table is stored as {number of bits, code}.
* The index to the table is built as:
* bit 2 = 1 if DQUANT is present, 0 else.
* bit 1 = 1 if V block is coded, 0 if not coded
* bit 0 = 1 if U block is coded, 0 if not coded.
*/
// TODO : why int, why not const
int VLC_MCBPC_INTRA[9][2] =
{ { 1, 1}, // 0
{ 3, 2}, // 1
{ 3, 1}, // 2
{ 3, 3}, // 3
{ 4, 1}, // 4
{ 6, 2}, // 5
{ 6, 1}, // 6
{ 6, 3}, // 7
{ 9, 1} };// 8 stuffing
/*
* VLC table for MCBPC for INTER pictures.
* Table is stored as {number of bits, code}.
* The index to the table is built as:
* bits 3,2 = MB type <0,1,2,3>
* bit 1 = 1 if V block is coded, 0 if not coded.
* bit 0 = 1 if U block is coded, 0 if not coded.
*
* For INTER pictures, MB types are defined as:
* 0: INTER
* 1: INTER+Q
* 2: INTER4V
* 3: INTRA
* 4: INTRA+Q
*/
// TODO : why int, why not const
const int VLC_MCBPC_INTER[20][2] =
{ { 1, 1}, // 0
{ 4, 2}, // 1
{ 4, 3}, // 2
{ 6, 5}, // 3
{ 3, 3}, // 4
{ 7, 6}, // 5
{ 7, 7}, // 6
{ 9, 5}, // 7
{ 3, 2}, // 8
{ 7, 4}, // 9
{ 7, 5}, // 10
{ 8, 5}, // 11
{ 5, 3}, // 12
{ 8, 3}, // 13
{ 8, 4}, // 14
{ 7, 3}, // 15
{ 6, 4}, // 16
{ 9, 3}, // 17
{ 9, 4}, // 18
{ 9, 2} };// 19
/*
* VLC's for motion vector delta's
*/
// TODO : why int, why not const
int vlc_mvd[] = {
// Index: Vector Differences
13,5, // 0: -16 16
13,7,
12,5,
12,7,
12,9,
12,11,
12,13,
12,15,
11,9,
11,11,
11,13,
11,15,
11,17,
11,19,
11,21,
11,23,
11,25,
11,27,
11,29,
11,31,
11,33,
11,35,
10,19,
10,21,
10,23,
8,7,
8,9,
8,11,
7,7,
5,3,
4,3,
3,3,
1,1, // 32: 0
3,2,
4,2,
5,2,
7,6,
8,10,
8,8,
8,6,
10,22,
10,20,
10,18,
11,34,
11,32,
11,30,
11,28,
11,26,
11,24,
11,22,
11,20,
11,18,
11,16,
11,14,
11,12,
11,10,
11,8,
12,14,
12,12,
12,10,
12,8,
12,6,
12,4,
13,6,
};
/*
* VLC table for CBPY
* Table is stores as {number of bits, code}
* Index into the table for INTRA macroblocks is the
* coded block pattern for the blocks in the order
* bit 3 = block 4
* bit 2 = block 3
* bit 1 = block 2
* bit 0 = block 1
*
* For INTER macroblocks, a CBP is built as above and
* then is subtracted from 15 to get the index into the
* array: index = 15 - interCBP.
*/
// TODO : why int, why not const
int VLC_CBPY[16][2] =
{ { 4, 3}, // 0
{ 5, 2}, // 1
{ 5, 3}, // 2
{ 4, 4}, // 3
{ 5, 4}, // 4
{ 4, 5}, // 5
{ 6, 2}, // 6
{ 4, 6}, // 7
{ 5, 5}, // 8
{ 6, 3}, // 9
{ 4, 7}, // 10
{ 4, 8}, // 11
{ 4, 9}, // 12
{ 4, 10}, // 13
{ 4, 11}, // 14
{ 2, 3} // 15
};
/*
* TODO : VLC tables for MODB and CBPB
*/
const U8 VLC_MODB[4][2] =
{
{1, 0}, // 0
{1, 0}, // should not happen
{2, 2}, // 2
{2, 3} // 3
};
#ifdef H263P
/*
* VLC table for MODB when improved PB-frame mode selected
*/
const U8 VLC_IMPROVED_PB_MODB[4][2] =
{
{1, 0}, // Bidirectional prediction with all empty blocks (CBPB=0, MVDB=0)
{2, 2}, // Forward prediction with all empty blocks (CBPB=0, MVDB=1)
{3, 6}, // Forward prediction with some non-empty blocks (CBPB=1, MVDB=1)
{3, 7} // Bidirectional prediction with some non-empty blocks (CBPB=1, MVDB=0)
};
#endif
/*
* TODO : VLC tables for CBPB; indexed using CodedBlocksB
*
*/
const U8 VLC_CBPB[64] =
{
0, // 000000
32, // 000001
16, // 000010
48, // 000011
8, // 000100
40, // 000101
24, // 000110
56, // 000111
4, // 001000
36, // 001001
20, // 001010
52, // 001011
12, // 001100
44, // 001101
28, // 001110
60, // 001111
2, // 010000
34, // 010001
18, // 010010
50, // 010011
10, // 010100
42, // 010101
26, // 010110
58, // 010111
6, // 011000
38, // 011001
22, // 011010
54, // 011011
14, // 011100
46, // 011101
30, // 011110
62, // 011111
1, // 100000
33, // 100001
17, // 100010
49, // 100011
9, // 100100
41, // 100101
25, // 100110
57, // 100111
5, // 101000
37, // 101001
21, // 101010
53, // 101011
13, // 101100
45, // 101101
29, // 101110
61, // 101111
3, // 110000
35, // 110001
19, // 110010
51, // 110011
11, // 110100
43, // 110101
27, // 110110
59, // 110111
7, // 111000
39, // 111001
23, // 111010
55, // 111011
15, // 111100
47, // 111101
31, // 111110
63 // 111111
};
/*
* VLC table for TCOEFs
* Table entries are size, code.
* Stored as (size, value)
* BSE -- The "+ 1" and "<< 1" makes room for the sign bit. This permits
* us to do a single write to the stream, versus two writes.
*/
// TODO : why int, why not const
int VLC_TCOEF[102*2] = {
2 + 1, 2 << 1, /* 0, runs of 0 *** table for nonlast coefficient */
4 + 1, 15 << 1,
6 + 1, 21 << 1,
7 + 1, 23 << 1,
8 + 1, 31 << 1,
9 + 1, 37 << 1,
9 + 1, 36 << 1,
10 + 1, 33 << 1,
10 + 1, 32 << 1,
11 + 1, 7 << 1,
11 + 1, 6 << 1,
11 + 1, 32 << 1,
3 + 1, 6 << 1, /* 24, runs of 1 */
6 + 1, 20 << 1,
8 + 1, 30 << 1,
10 + 1, 15 << 1,
11 + 1, 33 << 1,
12 + 1, 80 << 1,
4 + 1, 14 << 1, /* 36, runs of 2 */
8 + 1, 29 << 1,
10 + 1, 14 << 1,
12 + 1, 81 << 1,
5 + 1, 13 << 1, /* 44, runs of 3 */
9 + 1, 35 << 1,
10 + 1, 13 << 1,
5 + 1, 12 << 1, /* 50, runs of 4 */
9 + 1, 34 << 1,
12 + 1, 82 << 1,
5 + 1, 11 << 1, /* 56, runs of 5 */
10 + 1, 12 << 1,
12 + 1, 83 << 1,
6 + 1, 19 << 1, /* 62, runs of 6 */
10 + 1, 11 << 1,
12 + 1, 84 << 1,
6 + 1, 18 << 1, /* 68, runs of 7 */
10 + 1, 10 << 1,
6 + 1, 17 << 1, /* 72, runs of 8 */
10 + 1, 9 << 1,
6 + 1, 16 << 1, /* 76, runs of 9 */
10 + 1, 8 << 1,
7 + 1, 22 << 1, /* 80, runs of 10 */
12 + 1, 85 << 1,
7 + 1, 21 << 1, /* 84, runs of 11 */
7 + 1, 20 << 1, /* 86, runs of 12 */
8 + 1, 28 << 1, /* 88, runs of 13 */
8 + 1, 27 << 1, /* 90, runs of 14 */
9 + 1, 33 << 1,
9 + 1, 32 << 1,
9 + 1, 31 << 1,
9 + 1, 30 << 1,
9 + 1, 29 << 1,
9 + 1, 28 << 1,
9 + 1, 27 << 1,
9 + 1, 26 << 1,
11 + 1, 34 << 1,
11 + 1, 35 << 1,
12 + 1, 86 << 1,
12 + 1, 87 << 1,
4 + 1, 7 << 1, /* Table for last coeff */
9 + 1, 25 << 1,
11 + 1, 5 << 1,
6 + 1, 15 << 1,
11 + 1, 4 << 1,
6 + 1, 14 << 1,
6 + 1, 13 << 1,
6 + 1, 12 << 1,
7 + 1, 19 << 1,
7 + 1, 18 << 1,
7 + 1, 17 << 1,
7 + 1, 16 << 1,
8 + 1, 26 << 1,
8 + 1, 25 << 1,
8 + 1, 24 << 1,
8 + 1, 23 << 1,
8 + 1, 22 << 1,
8 + 1, 21 << 1,
8 + 1, 20 << 1,
8 + 1, 19 << 1,
9 + 1, 24 << 1,
9 + 1, 23 << 1,
9 + 1, 22 << 1,
9 + 1, 21 << 1,
9 + 1, 20 << 1,
9 + 1, 19 << 1,
9 + 1, 18 << 1,
9 + 1, 17 << 1,
10 + 1, 7 << 1,
10 + 1, 6 << 1,
10 + 1, 5 << 1,
10 + 1, 4 << 1,
11 + 1, 36 << 1,
11 + 1, 37 << 1,
11 + 1, 38 << 1,
11 + 1, 39 << 1,
12 + 1, 88 << 1,
12 + 1, 89 << 1,
12 + 1, 90 << 1,
12 + 1, 91 << 1,
12 + 1, 92 << 1,
12 + 1, 93 << 1,
12 + 1, 94 << 1,
12 + 1, 95 << 1
};
/*
* This table lists the maximum level represented in the
* VLC table for a given run. If the level exceeds the
* max, then escape codes must be used to encode the
* run & level.
* The table entries are of the form {maxlevel, ptr to table for this run}.
*/
T_MAXLEVEL_PTABLE TCOEF_RUN_MAXLEVEL[65] = {
{12, &VLC_TCOEF[0]}, // run of 0
{ 6, &VLC_TCOEF[24]}, // run of 1
{ 4, &VLC_TCOEF[36]}, // run of 2
{ 3, &VLC_TCOEF[44]}, // run of 3
{ 3, &VLC_TCOEF[50]}, // run of 4
{ 3, &VLC_TCOEF[56]}, // run of 5
{ 3, &VLC_TCOEF[62]}, // run of 6
{ 2, &VLC_TCOEF[68]}, // run of 7
{ 2, &VLC_TCOEF[72]}, // run of 8
{ 2, &VLC_TCOEF[76]}, // run of 9
{ 2, &VLC_TCOEF[80]}, // run of 10
{ 1, &VLC_TCOEF[84]}, // run of 11
{ 1, &VLC_TCOEF[86]}, // run of 12
{ 1, &VLC_TCOEF[88]}, // run of 13
{ 1, &VLC_TCOEF[90]}, // run of 14
{ 1, &VLC_TCOEF[92]}, // run of 15
{ 1, &VLC_TCOEF[94]}, // run of 16
{ 1, &VLC_TCOEF[96]}, // run of 17
{ 1, &VLC_TCOEF[98]}, // run of 18
{ 1, &VLC_TCOEF[100]}, // run of 19
{ 1, &VLC_TCOEF[102]}, // run of 20
{ 1, &VLC_TCOEF[104]}, // run of 21
{ 1, &VLC_TCOEF[106]}, // run of 22
{ 1, &VLC_TCOEF[108]}, // run of 23
{ 1, &VLC_TCOEF[110]}, // run of 24
{ 1, &VLC_TCOEF[112]}, // run of 25
{ 1, &VLC_TCOEF[114]}, // run of 26
{ 0, 0}, // run of 27 not in VLC table
{ 0, 0}, // run of 28 not in VLC table
{ 0, 0}, // run of 29 not in VLC table
{ 0, 0}, // run of 30 not in VLC table
{ 0, 0}, // run of 31 not in VLC table
{ 0, 0}, // run of 32 not in VLC table
{ 0, 0}, // run of 33 not in VLC table
{ 0, 0}, // run of 34 not in VLC table
{ 0, 0}, // run of 35 not in VLC table
{ 0, 0}, // run of 36 not in VLC table
{ 0, 0}, // run of 37 not in VLC table
{ 0, 0}, // run of 38 not in VLC table
{ 0, 0}, // run of 39 not in VLC table
{ 0, 0}, // run of 40 not in VLC table
{ 0, 0}, // run of 41 not in VLC table
{ 0, 0}, // run of 42 not in VLC table
{ 0, 0}, // run of 43 not in VLC table
{ 0, 0}, // run of 44 not in VLC table
{ 0, 0}, // run of 45 not in VLC table
{ 0, 0}, // run of 46 not in VLC table
{ 0, 0}, // run of 47 not in VLC table
{ 0, 0}, // run of 48 not in VLC table
{ 0, 0}, // run of 49 not in VLC table
{ 0, 0}, // run of 50 not in VLC table
{ 0, 0}, // run of 51 not in VLC table
{ 0, 0}, // run of 52 not in VLC table
{ 0, 0}, // run of 53 not in VLC table
{ 0, 0}, // run of 54 not in VLC table
{ 0, 0}, // run of 55 not in VLC table
{ 0, 0}, // run of 56 not in VLC table
{ 0, 0}, // run of 57 not in VLC table
{ 0, 0}, // run of 58 not in VLC table
{ 0, 0}, // run of 59 not in VLC table
{ 0, 0}, // run of 60 not in VLC table
{ 0, 0}, // run of 61 not in VLC table
{ 0, 0}, // run of 62 not in VLC table
{ 0, 0}, // run of 63 not in VLC table
{ 0, 0} // run of 64 not in VLC table
};
static char __fastcall median(char v1, char v2, char v3);
static I8 * MB_Quantize_RLE(
I32 **DCTCoefs,
I8 *MBRunValPairs,
U8 *CodedBlocks,
U8 BlockType,
I32 QP
);
/*************************************************************
* Name: writePB_MVD
* Description: Writes out the VLC for horizontal and vertical motion vector
* to the bit-stream addressed by (pPB_BitStream, pPB_BitOffset) in a
* PB-frame (in a PB-frame, a predictor is NOT set to 0 for INTRABLOCKS).
* In its current incarnation, it cannot be used to write MV for non-PB
* frames.
* Parameters:
* curMB Write MV for the MB no. "curMB" in the frame. MBs are
* numbererd from 0 in a frame.
* pCurMB Pointer to the current MB action descriptor
* NumMBPerRow No. of MBs in a row; e.g. 11 in QCIF.
* pPB_BitStream Current byte being written
* pPB_BitOffset Offset at which VLC code is written
* Side-effects:
* Modifies pPB_BitStream and pPB_BitOffset.
*************************************************************/
static void writePB_MVD(
const U32 curMB,
T_MBlockActionStream * const pCurMB,
const U32 NumMBPerRow,
const U32 NumMBs,
U8 ** pPB_BitStream,
U8 * pPB_BitOffset,
U32 GOBHeaderFlag,
const T_H263EncoderCatalog *EC
);
/*************************************************************
* Name: writeP_MVD
* Description: Writes out the VLC for horizontal and vertical motion vector
* to the bit-stream addressed by (pP_BitStream, pP_BitOffset) in a
* P-frame.
* Parameters:
* curMB Write MV for the MB no. "curMB" in the frame. MBs are
* numbererd from 0 in a frame.
* pCurMB Pointer to current MB action descriptor
* NumMBPerRow No. of MBs in a row; e.g. 11 in QCIF.
* pP_BitStream Current byte being written
* pP_BitOffset Offset at which VLC code is written
* GOBHeaderPresent IF true, then GOB header is present for this GOB.
* Side-effects:
* Modifies pP_BitStream and pP_BitOffset.
*************************************************************/
static void writeP_MVD(
const U32 curMB,
T_MBlockActionStream * const pCurMB,
const U32 NumMBPerRow,
const U32 NumMBs,
U8 ** pP_BitStream,
U8 * pP_BitOffset,
U32 GOBHeaderPresent,
T_H263EncoderCatalog *EC
);
/**********************************************************************
* Quantize and RLE each macroblock, then VLC and write to stream.
* This function is only used for P or I frames, not B.
*
* Parameters:
* FutrPMBData
**********************************************************************/
void GOB_Q_RLE_VLC_WriteBS(
T_H263EncoderCatalog *EC,
I32 *DCTCoefs,
U8 **pBitStream,
U8 *pBitOffset,
T_FutrPMBData *FutrPMBData, // Start of GOB
U32 GOB,
U32 QP,
BOOL bRTPHeader,
U32 StartingMB
)
{
U32 MB, curMB, index;
I8 MBRunValSign[65*3*6], * EndAddress, *rvs;
U8 bUseDQUANT = 0; // Indicates if DQUANT is present.
U8 MBType;
U8 *pFrmStart = EC->pU8_BitStream; // TODO : should be a param.
U32 GOBHeaderMask, GOBHeaderFlag;
#ifdef COUNT_BITS
U32 savebyteptr, savebitptr;
#endif
register T_MBlockActionStream *pCurMB;
FX_ENTRY("GOB_Q_RLE_VLC_WriteBS")
// Create GOB header mask to be used further down.
GOBHeaderMask = 1 << GOB;
// Loop through each macroblock of the GOB.
for(MB = 0, curMB = GOB*EC->NumMBPerRow,
pCurMB = EC->pU8_MBlockActionStream + curMB;
MB < EC->NumMBPerRow;
MB++, curMB++, pCurMB++)
{
DEBUGMSG(ZONE_ENCODE_MB, ("%s: MB #%d: QP=%d\r\n", _fx_, MB, QP));
/*
* Quantize and RLE each block in the macroblock,
* skipping empty blocks as denoted by CodedBlocks.
* If any more blocks are empty after quantization
* then the appropriate CodedBlocks bit is cleared.
*/
EndAddress = MB_Quantize_RLE(
&DCTCoefs,
(I8 *)MBRunValSign,
&(pCurMB->CodedBlocks),
pCurMB->BlockType,
QP
);
// default COD is coded (= 0). Will be set to 1 only if skipped
pCurMB->COD = 0;
#ifdef ENCODE_STATS
StatsUsedQuant(QP);
#endif /* ENCODE_STATS */
if(EC->PictureHeader.PicCodType == INTRAPIC)
{
pCurMB->MBType = INTRA;
MBType = INTRA;
}
else // inter picture code type
{
if(pCurMB->BlockType == INTERBLOCK)
{
pCurMB->MBType = INTER;
MBType = INTER;
}
else if(pCurMB->BlockType == INTER4MV)
{
pCurMB->MBType = INTER4V;
MBType = INTER4V;
}
else if(pCurMB->BlockType == INTRABLOCK)
{
pCurMB->MBType = INTRA;
MBType = INTRA;
}
else
{
ERRORMESSAGE(("%s: Unexpected MacroBlock Type found\r\n", _fx_));
}
}
// Save starting bit offset of the macroblock data from start of
// of the frame data. The offset for the first macroblock is saved
// in e3enc.cpp before this routine is called.
if (EC->u8EncodePBFrame == TRUE
&& MB != 0)
{
FutrPMBData[curMB].MBStartBitOff
= (U32) (((*pBitStream - pFrmStart)<<3) + *pBitOffset);
}
/*
* Write macroblock header to bit stream.
*/
if( (MBType == INTER) || (MBType == INTER4V) )
{
// Check if entire macroblock is empty, including zero MV's.
// If there is only one MV for the block, all block MVs in the
// structure are still set but are equal.
if( ((pCurMB->CodedBlocks & 0x3f) != 0)
|| (pCurMB->BlkY1.PHMV != 0)
|| (pCurMB->BlkY1.PVMV != 0)
|| (pCurMB->BlkY2.PHMV != 0)
|| (pCurMB->BlkY2.PVMV != 0)
|| (pCurMB->BlkY3.PHMV != 0)
|| (pCurMB->BlkY3.PVMV != 0)
|| (pCurMB->BlkY4.PHMV != 0)
|| (pCurMB->BlkY4.PVMV != 0)
)
{
PutBits(0, 1, pBitStream, pBitOffset); // COD = 0, nonempty MB
#ifdef COUNT_BITS
if(MBType == INTER)
EC->Bits.num_inter++;
else if (MBType == INTER4V)
EC->Bits.num_inter4v++;
EC->Bits.MBHeader += 1;
EC->Bits.Coded++;
#endif
// Increment the InterCoded block count if the block
// is intercoded (not B frame) and is not empty.
if (((pCurMB->CodedBlocks & 0x3f) != 0) &&
((pCurMB->BlockType == INTERBLOCK) || (pCurMB->BlockType == INTER4MV)))
{
// Macroblock is coded. Need to increment inter code count if
// there are no coefficients: see section 4.4 of the H.263
// recommendation
pCurMB->InterCodeCnt++;
}
// pCurMB->InterCodeCnt is reset in calcGOBChromaVecs_InterCodeCnt
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
// Write MCBPC to bitstream.
// The rightmost two bits are the CBPC (65).
// Note that this is the reverse of the order in the
// VLC table in the H.263 spec.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
// Add the MB type to next two bits to the left.
index |= (MBType << 2);
// Write code to bitstream.
PutBits(VLC_MCBPC_INTER[index][1], VLC_MCBPC_INTER[index][0],
pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_MCBPC_INTER[index][0];
EC->Bits.MCBPC += VLC_MCBPC_INTER[index][0];
#endif
// Save bit offset of CBPY data from start of macroblock data
// if PB frame is on since we will reuse this later.
if (EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].CBPYBitOff
= (U8)( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
// Write CBPY to bitstream.
index = pCurMB->CodedBlocks & 0xf;
index = (~index) & 0xf;
PutBits(VLC_CBPY[index][1], VLC_CBPY[index][0],
pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_CBPY[index][0];
EC->Bits.CBPY += VLC_CBPY[index][0];
#endif
//if( bUseDQUANT )
//{
// TODO: write DQUANT to bit stream here. We can only do
// this if MBtype is not INTER4V since that type doesn't
// allow quantizer as well.
//}
// Save bit offset of CBPY data from start of macroblock data
if (EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].MVDBitOff
= (U8)( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
// Write motion vectors to bit stream.
if( (EC->GOBHeaderPresent & GOBHeaderMask) != 0 )
{
GOBHeaderFlag = TRUE;
}
else
{
GOBHeaderFlag = FALSE;
}
writeP_MVD(
curMB, // Current MB number.
pCurMB, // pointer to current MB action desc. struct.
EC->NumMBPerRow,
EC->NumMBs,
pBitStream,
pBitOffset,
GOBHeaderFlag,
EC
);
// Save bit offset of block data from start of MB data
if (EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].BlkDataBitOff
= (U8) ( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
/*
* Encode intra DC and all run/val pairs.
*/
#ifdef COUNT_BITS
savebyteptr = (U32) *pBitStream;
savebitptr = (U32) *pBitOffset;
#endif
rvs = MBRunValSign;
MBEncodeVLC(&rvs,NULL, pCurMB->CodedBlocks,
pBitStream, pBitOffset, 0, 0);
#ifdef COUNT_BITS
EC->Bits.Coefs += ((U32) *pBitStream - savebyteptr)*8 - savebitptr + *pBitOffset;
#endif
}
else // Macroblock is empty.
{
PutBits(1, 1, pBitStream, pBitOffset); // COD = 1, empty MB
// Instead of repeating the above test in the PB-frame encoding
// pCurMB->COD can now be tested instead.
pCurMB->COD = 1;
if (EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].CBPYBitOff = 1;
FutrPMBData[curMB].MVDBitOff = 1;
FutrPMBData[curMB].BlkDataBitOff = 1;
}
#ifdef COUNT_BITS
EC->Bits.MBHeader += 1;
#endif
} // end of else
} // end of if macroblock
else if( (MBType == INTRA) && (EC->PictureHeader.PicCodType == INTERPIC))
{
// Stagger inter code count.
pCurMB->InterCodeCnt = (unsigned char) (StartingMB & 0xf);
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
PutBits(0, 1, pBitStream, pBitOffset); // COD = 0, nonempty MB
#ifdef COUNT_BITS
EC->Bits.num_intra++;
EC->Bits.MBHeader += 1;
EC->Bits.Coded++;
#endif
// Write MCBPC to bitstream.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
index |= (MBType << 2);
PutBits(VLC_MCBPC_INTER[index][1], VLC_MCBPC_INTER[index][0],
pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_MCBPC_INTER[index][0];
EC->Bits.MCBPC += VLC_MCBPC_INTER[index][0];
#endif
// Save bit offset of CBPY data from start of macroblock data
if (EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].CBPYBitOff
= (U8) ( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
// Write CBPY to bitstream.
index = pCurMB->CodedBlocks & 0xf;
//index = pMBActionStream[curMB].CBPY;
PutBits(VLC_CBPY[index][1], VLC_CBPY[index][0], pBitStream,
pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_CBPY[index][0];
EC->Bits.CBPY += VLC_CBPY[index][0];
#endif
//if( bUseDQUANT )
//{
// write DQUANT to bit stream here.
//}
// Save bit offset of block data from start of macroblock data
if (EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].BlkDataBitOff = FutrPMBData[curMB].MVDBitOff
= (U8) ( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
#ifdef COUNT_BITS
savebyteptr = (U32) *pBitStream;
savebitptr = (U32) *pBitOffset;
#endif
// Encode run/val pairs
rvs = MBRunValSign;
MBEncodeVLC(&rvs, NULL, pCurMB->CodedBlocks, pBitStream,
pBitOffset, 1, 0);
#ifdef COUNT_BITS
EC->Bits.Coefs += ((U32) *pBitStream - savebyteptr)*8 - savebitptr + *pBitOffset;
#endif
} // end of else
else if ( (MBType == INTRA) && (EC->PictureHeader.PicCodType == INTRAPIC))
{
// Stagger inter code count.
pCurMB->InterCodeCnt = (unsigned char) (StartingMB & 0xf);
// An INTRA frame should not be the P-frame in a PB-frame
ASSERT(EC->u8SavedBFrame == FALSE)
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
// Write MCBPC to bitstream.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
//index = pMBActionStream[curMB].CBPC;
//index |= bUseDQUANT << 2;
PutBits(VLC_MCBPC_INTRA[index][1], VLC_MCBPC_INTRA[index][0],
pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.num_intra++;
EC->Bits.MBHeader += VLC_MCBPC_INTRA[index][0];
EC->Bits.MCBPC += VLC_MCBPC_INTRA[index][0];
#endif
// Write CBPY to bitstream.
index = pCurMB->CodedBlocks & 0xf;
//index = pMBActionStream[curMB].CBPY;
PutBits(VLC_CBPY[index][1], VLC_CBPY[index][0],
pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_CBPY[index][0];
EC->Bits.CBPY += VLC_CBPY[index][0];
#endif
//if( bUseDQUANT )
//{
// write DQUANT to bit stream here.
//}
#ifdef COUNT_BITS
savebyteptr = (U32) *pBitStream;
savebitptr = (U32) *pBitOffset;
#endif
rvs = MBRunValSign;
MBEncodeVLC(&rvs, NULL, pCurMB->CodedBlocks,
pBitStream, pBitOffset, 1, 0);
#ifdef COUNT_BITS
EC->Bits.Coefs += ((U32) *pBitStream - savebyteptr)*8 - savebitptr + *pBitOffset;
#endif
} // end of else
else
ERRORMESSAGE(("%s: Unexpected case in writing MB header VLC\r\n", _fx_));
// Calculate DQUANT based on bits used in previous MBs.
// CalcDQUANT();
if (bRTPHeader)
H263RTP_UpdateBsInfo(EC, pCurMB, QP, MB, GOB, *pBitStream,
(U32) *pBitOffset);
} // for MB
} // end of GOB_Q_RLE_VLC_WriteBS()
void GOB_VLC_WriteBS(
T_H263EncoderCatalog *EC,
I8 *pMBRVS_Luma,
I8 *pMBRVS_Chroma,
U8 **pBitStream,
U8 *pBitOffset,
T_FutrPMBData *FutrPMBData, // Start of GOB
U32 GOB,
U32 QP,
BOOL bRTPHeader,
U32 StartingMB)
{
U32 MB, curMB, index;
U8 bUseDQUANT = 0; // Indicates if DQUANT is present.
U8 MBType;
U8 *pFrmStart = EC->pU8_BitStream; // TODO : should be a param.
U32 GOBHeaderMask, GOBHeaderFlag;
#ifdef COUNT_BITS
U32 savebyteptr, savebitptr;
#endif
register T_MBlockActionStream *pCurMB;
FX_ENTRY("GOB_VLC_WriteBS")
// Create GOB header mask to be used further down.
GOBHeaderMask = 1 << GOB;
// Loop through each macroblock of the GOB.
for(MB = 0, curMB = GOB*EC->NumMBPerRow, pCurMB = EC->pU8_MBlockActionStream + curMB;
MB < EC->NumMBPerRow; MB++, curMB++, pCurMB++)
{
DEBUGMSG(ZONE_ENCODE_MB, ("%s: MB #%d\r\n", _fx_, MB));
// default COD is coded (= 0). Will be set to 1 only if skipped
pCurMB->COD = 0;
if(EC->PictureHeader.PicCodType == INTRAPIC)
{
pCurMB->MBType = INTRA;
MBType = INTRA;
}
else
{ // inter picture code type
if(pCurMB->BlockType == INTERBLOCK)
{
pCurMB->MBType = INTER;
MBType = INTER;
}
else if(pCurMB->BlockType == INTER4MV)
{
pCurMB->MBType = INTER4V;
MBType = INTER4V;
}
else if(pCurMB->BlockType == INTRABLOCK)
{
pCurMB->MBType = INTRA;
MBType = INTRA;
}
else
{
ERRORMESSAGE(("%s: Unexpected MacroBlock Type found\r\n", _fx_));
}
}
// Save starting bit offset of the macroblock data from start of
// of the frame data. The offset for the first macroblock is saved
// in e3enc.cpp before this routine is called.
if(EC->u8EncodePBFrame == TRUE && MB != 0)
{
FutrPMBData[curMB].MBStartBitOff
= (U32) (((*pBitStream - pFrmStart)<<3) + *pBitOffset);
}
/*
* Write macroblock header to bit stream.
*/
if((MBType == INTER) || (MBType == INTER4V))
{
// Check if entire macroblock is empty, including zero MV's.
// If there is only one MV for the block, all block MVs in the
// structure are still set but are equal.
if(((pCurMB->CodedBlocks & 0x3f) != 0)
|| (pCurMB->BlkY1.PHMV != 0)
|| (pCurMB->BlkY1.PVMV != 0)
|| (pCurMB->BlkY2.PHMV != 0)
|| (pCurMB->BlkY2.PVMV != 0)
|| (pCurMB->BlkY3.PHMV != 0)
|| (pCurMB->BlkY3.PVMV != 0)
|| (pCurMB->BlkY4.PHMV != 0)
|| (pCurMB->BlkY4.PVMV != 0))
{
PutBits(0, 1, pBitStream, pBitOffset); // COD = 0, nonempty MB
#ifdef COUNT_BITS
if(MBType == INTER)
EC->Bits.num_inter++;
else if (MBType == INTER4V)
EC->Bits.num_inter4v++;
EC->Bits.MBHeader += 1;
EC->Bits.Coded++;
#endif
// Increment the InterCoded block count if the block
// is intercoded (not B frame) and is not empty.
if (((pCurMB->CodedBlocks & 0x3f) != 0) &&
((pCurMB->BlockType == INTERBLOCK) || (pCurMB->BlockType == INTER4MV)))
{
// Macroblock is coded. Need to increment inter code count if
// there are no coefficients: see section 4.4 of the H.263
// recommendation
pCurMB->InterCodeCnt++;
}
// pCurMB->InterCodeCnt is reset in calcGOBChromaVecs_InterCodeCnt
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
// Write MCBPC to bitstream.
// The rightmost two bits are the CBPC (65).
// Note that this is the reverse of the order in the
// VLC table in the H.263 spec.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
// Add the MB type to next two bits to the left.
index |= (MBType << 2);
// Write code to bitstream.
PutBits(VLC_MCBPC_INTER[index][1], VLC_MCBPC_INTER[index][0],
pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_MCBPC_INTER[index][0];
EC->Bits.MCBPC += VLC_MCBPC_INTER[index][0];
#endif
// Save bit offset of CBPY data from start of macroblock data
// if PB frame is on since we will reuse this later.
if(EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].CBPYBitOff
= (U8)( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
// Write CBPY to bitstream.
index = pCurMB->CodedBlocks & 0xf;
index = (~index) & 0xf;
PutBits(VLC_CBPY[index][1], VLC_CBPY[index][0], pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_CBPY[index][0];
EC->Bits.CBPY += VLC_CBPY[index][0];
#endif
//if(bUseDQUANT)
//{
// TODO: write DQUANT to bit stream here. We can only do
// this if MBtype is not INTER4V since that type doesn't
// allow quantizer as well.
//}
// Save bit offset of CBPY data from start of macroblock data
if(EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].MVDBitOff
= (U8)( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
// Write motion vectors to bit stream.
if((EC->GOBHeaderPresent & GOBHeaderMask) != 0)
{
GOBHeaderFlag = TRUE;
}
else
{
GOBHeaderFlag = FALSE;
}
writeP_MVD(
curMB, // Current MB number.
pCurMB, // pointer to current MB action desc. struct.
EC->NumMBPerRow,
EC->NumMBs,
pBitStream,
pBitOffset,
GOBHeaderFlag,
EC);
// Save bit offset of block data from start of MB data
if(EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].BlkDataBitOff
= (U8) ( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
/*
* Encode intra DC and all run/val pairs.
*/
#ifdef COUNT_BITS
savebyteptr = (U32) *pBitStream;
savebitptr = (U32) *pBitOffset;
#endif
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma, pCurMB->CodedBlocks,
pBitStream, pBitOffset, 0, 1);
#ifdef COUNT_BITS
EC->Bits.Coefs += ((U32) *pBitStream - savebyteptr)*8 - savebitptr + *pBitOffset;
#endif
}
else
{ // Macroblock is empty.
PutBits(1, 1, pBitStream, pBitOffset); // COD = 1, empty MB
// Instead of repeating the above test in the PB-frame encoding
// pCurMB->COD can now be tested instead.
pCurMB->COD = 1;
if(EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].CBPYBitOff = 1;
FutrPMBData[curMB].MVDBitOff = 1;
FutrPMBData[curMB].BlkDataBitOff = 1;
}
#ifdef COUNT_BITS
EC->Bits.MBHeader += 1;
#endif
} // end of else
}
else if( (MBType == INTRA) && (EC->PictureHeader.PicCodType == INTERPIC))
{
// Stagger inter code count.
pCurMB->InterCodeCnt = (unsigned char) (StartingMB & 0xf);
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
PutBits(0, 1, pBitStream, pBitOffset); // COD = 0, nonempty MB
#ifdef COUNT_BITS
EC->Bits.num_intra++;
EC->Bits.MBHeader += 1;
EC->Bits.Coded++;
#endif
// Write MCBPC to bitstream.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
index |= (MBType << 2);
PutBits(VLC_MCBPC_INTER[index][1], VLC_MCBPC_INTER[index][0], pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_MCBPC_INTER[index][0];
EC->Bits.MCBPC += VLC_MCBPC_INTER[index][0];
#endif
// Save bit offset of CBPY data from start of macroblock data
if(EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].CBPYBitOff
= (U8) ( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
// Write CBPY to bitstream.
index = pCurMB->CodedBlocks & 0xf;
//index = pMBActionStream[curMB].CBPY;
PutBits(VLC_CBPY[index][1], VLC_CBPY[index][0], pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_CBPY[index][0];
EC->Bits.CBPY += VLC_CBPY[index][0];
#endif
//if( bUseDQUANT )
//{
// write DQUANT to bit stream here.
//}
// Save bit offset of block data from start of macroblock data
if(EC->u8EncodePBFrame == TRUE)
{
FutrPMBData[curMB].BlkDataBitOff = FutrPMBData[curMB].MVDBitOff
= (U8) ( ((*pBitStream - pFrmStart)<<3) + *pBitOffset
- FutrPMBData[curMB].MBStartBitOff);
}
#ifdef COUNT_BITS
savebyteptr = (U32) *pBitStream;
savebitptr = (U32) *pBitOffset;
#endif
// Encode run/val pairs
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma, pCurMB->CodedBlocks,
pBitStream, pBitOffset, 1, 1);
#ifdef COUNT_BITS
EC->Bits.Coefs += ((U32) *pBitStream - savebyteptr)*8 - savebitptr + *pBitOffset;
#endif
}
else if ( (MBType == INTRA) && (EC->PictureHeader.PicCodType == INTRAPIC))
{
// Stagger inter code count.
pCurMB->InterCodeCnt = (unsigned char) (StartingMB & 0xf);
// An INTRA frame should not be the P-frame in a PB-frame
ASSERT(EC->u8SavedBFrame == FALSE)
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
// Write MCBPC to bitstream.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
//index = pMBActionStream[curMB].CBPC;
//index |= bUseDQUANT << 2;
PutBits(VLC_MCBPC_INTRA[index][1], VLC_MCBPC_INTRA[index][0], pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.num_intra++;
EC->Bits.MBHeader += VLC_MCBPC_INTRA[index][0];
EC->Bits.MCBPC += VLC_MCBPC_INTRA[index][0];
#endif
// Write CBPY to bitstream.
index = pCurMB->CodedBlocks & 0xf;
//index = pMBActionStream[curMB].CBPY;
PutBits(VLC_CBPY[index][1], VLC_CBPY[index][0], pBitStream, pBitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += VLC_CBPY[index][0];
EC->Bits.CBPY += VLC_CBPY[index][0];
#endif
//if( bUseDQUANT )
//{
// write DQUANT to bit stream here.
//}
#ifdef COUNT_BITS
savebyteptr = (U32) *pBitStream;
savebitptr = (U32) *pBitOffset;
#endif
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma, pCurMB->CodedBlocks,
pBitStream, pBitOffset, 1, 1);
#ifdef COUNT_BITS
EC->Bits.Coefs += ((U32) *pBitStream - savebyteptr)*8 - savebitptr + *pBitOffset;
#endif
}
else
ERRORMESSAGE(("%s: Unexpected case in writing MB header VLC\r\n", _fx_));
// Calculate DQUANT based on bits used in previous MBs.
// CalcDQUANT();
if (bRTPHeader)
H263RTP_UpdateBsInfo(EC, pCurMB, QP, MB, GOB, *pBitStream,
(U32) *pBitOffset);
} // for MB
} // end of GOB_VLC_WriteBS()
/*************************************************************
* Name: PB_GOB_Q_RLE_VLC_WriteBS
* Description: Write out GOB layer bits for GOB number "GOB".
* Parameters:
* EC Encoder catalog
* DCTCoefs Pointer to DCT coefficients for the GOB
* pP_BitStreamStart Pointer to start of bit stream for the future
* P-frame. Some data from future P frame is copied over
* to PB-frame.
* pPB_BitStream Current PB-frame byte pointer
* pPB_BitOffset Bit offset in the current byte pointed by pPB_BitStream
* FutrPMBData Bit stream info on future P-frame. This info. is
* initialized in GOB_Q_RLE_VLC_WriteBS()
* GOB GOBs are numbered from 0 in a frame.
* QP Quantization value for B-block coefficients.
* Side-effects:
* pPB_BitStream and pPB_BitOffset are modified as a result of writing bits
* to the stream.
*************************************************************/
void PB_GOB_Q_RLE_VLC_WriteBS(
T_H263EncoderCatalog * EC,
I32 * DCTCoefs,
U8 * pP_BitStreamStart,
U8 ** pPB_BitStream,
U8 * pPB_BitOffset,
const T_FutrPMBData * const FutrPMBData,
const U32 GOB,
const U32 QP,
BOOL bRTPHeader
)
{
UN MB;
U32 curMB, index;
U32 GOBHeaderMask, GOBHeaderFlag;
I8 MBRunValSign[65*3*6], *EndAddress, *rvs;
U8 bUseDQUANT = 0; // Indicates if DQUANT is present.
U8 emitCBPB, emitMVDB;
register T_MBlockActionStream *pCurMB;
FX_ENTRY("PB_GOB_Q_RLE_VLC_WriteBS")
#ifdef H263P
// The H.263+ options are currently only available in MMX enabled
// encoders. If the improved PB-frame mode is desired in non-MMX
// implementations, the H263P-defined code in PB_GOB_VLC_WriteBS
// should be mimiced here.
#endif
// Create GOB header mask to be used further down.
GOBHeaderMask = 1 << GOB;
for (MB = 0, curMB = GOB*EC->NumMBPerRow,
pCurMB = EC->pU8_MBlockActionStream + curMB;
MB < EC->NumMBPerRow;
MB++, curMB++, pCurMB++)
{
/*
* Quantize and RLE each block in the macroblock,
* skipping empty blocks as denoted by CodedBlocks.
* If any more blocks are empty after quantization
* then the appropriate CodedBlocks bit is cleared.
*/
EndAddress = (I8 *)MB_Quantize_RLE(
&DCTCoefs,
(I8 *)MBRunValSign,
&(pCurMB->CodedBlocksB),
INTERBLOCK, // B coeffs are INTER-coded
QP
);
#ifdef ENCODE_STATS
StatsUsedQuant(QP);
#endif /* ENCODE_STATS */
// Write MBlock data
// Check if entire macroblock is empty, including zero MV's.
if( ((pCurMB->MBType == INTER)
|| (pCurMB->MBType == INTER4V))
&& (pCurMB->COD == 1) )
{
if( ((pCurMB->CodedBlocksB & 0x3f) == 0)
&& (pCurMB->BlkY1.BHMV == 0)
&& (pCurMB->BlkY1.BVMV == 0))
{
// P-mblock not coded, and neither is PB-mblock.
// COD = 1, empty MB.
// If it is the first MB in the GOb, then GOB header
// is also copied
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff,// src
FutrPMBData[curMB+1].MBStartBitOff // len
- FutrPMBData[curMB].MBStartBitOff);
}
else // Macro block is not empty.
{
// Copy COD and MCBPC
// If it is the first MB in the GOB, then GOB header
// is also copied.
if (FutrPMBData[curMB+1].MBStartBitOff - FutrPMBData[curMB].MBStartBitOff != 1)
{
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff,// src
FutrPMBData[curMB+1].MBStartBitOff // len
- FutrPMBData[curMB].MBStartBitOff - 1);
}
PutBits(0, 1, pPB_BitStream, pPB_BitOffset); // COD = 0, nonempty MB
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
// Write MCBPC to bitstream.
// The rightmost two bits are the CBPC (65).
// Note that this is the reverse of the order in the
// VLC table in the H.263 spec.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
// Add the MB type to next two bits to the left.
index |= (pCurMB->MBType << 2);
// Write code to bitstream.
PutBits(VLC_MCBPC_INTER[index][1], VLC_MCBPC_INTER[index][0],
pPB_BitStream, pPB_BitOffset);
// Write MODB
if ((pCurMB->CodedBlocksB & 0x3f) == 0)
{
emitCBPB = 0;
}
else
{
emitCBPB = 1;
}
if (((pCurMB->BlkY1.BHMV != 0)
|| (pCurMB->BlkY1.BVMV != 0))
|| emitCBPB == 1)
{
emitMVDB = 1;
}
else
{
emitMVDB = 0;
}
index = (emitMVDB<<1) | emitCBPB;
PutBits(VLC_MODB[index][1], VLC_MODB[index][0],
pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: MB=%d emitCBPB=%d emitMVDB=%d MODB=%d\r\n", _fx_, curMB, (int)emitCBPB, (int)emitMVDB, (int)VLC_MODB[index][1]));
// Write CBPB
if (emitCBPB)
{
PutBits(VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)],
6, pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: CBPB=0x%x\r\n", _fx_, VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)]));
}
// The P blocks are all empty
PutBits(3, 2, pPB_BitStream, pPB_BitOffset); // CBPY = 11, no coded P blocks
//if( bUseDQUANT )
//{
// write DQUANT to bit stream here.
//}
// Write MVD{2-4}
// Note: MVD cannot be copied from future frame because
// predictors are different for PB-frame (G.2)
if( (EC->GOBHeaderPresent & GOBHeaderMask) != 0 )
{
GOBHeaderFlag = TRUE;
}
else
{
GOBHeaderFlag = FALSE;
}
writePB_MVD(curMB, pCurMB, EC->NumMBPerRow, EC->NumMBs,
pPB_BitStream, pPB_BitOffset, GOBHeaderFlag, EC);
// Write MVDB
if (emitMVDB)
{
ASSERT(pCurMB->BlkY1.BHMV >= -32 && pCurMB->BlkY1.BHMV <= 31)
ASSERT(pCurMB->BlkY1.BVMV >= -32 && pCurMB->BlkY1.BVMV <= 31)
// Write horizontal motion vector
index = (pCurMB->BlkY1.BHMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index),
pPB_BitStream, pPB_BitOffset);
// Write vertical motion vector
index = (pCurMB->BlkY1.BVMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index),
pPB_BitStream, pPB_BitOffset);
}
// There is no P-mblock blk data
// B-frame block data is always INTER-coded (last param is 0)
if (emitCBPB)
{
rvs = MBRunValSign;
#ifdef H263P
MBEncodeVLC(&rvs, NULL, (pCurMB->CodedBlocksB & 0x3f),
pPB_BitStream, pPB_BitOffset, 0, 0);
#else
MBEncodeVLC(&rvs, NULL, pCurMB->CodedBlocksB,
pPB_BitStream, pPB_BitOffset, 0, 0);
#endif
}
} // end of else
}
else
{
// Copy COD and MCBPC
// If it is the first MB in the GOB, then GOB header
// is also copied.
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff,// src
FutrPMBData[curMB].CBPYBitOff); // len
// Write MODB
if ((pCurMB->CodedBlocksB & 0x3f) == 0)
{
emitCBPB = 0;
}
else
{
emitCBPB = 1;
}
if (((pCurMB->BlkY1.BHMV != 0)
|| (pCurMB->BlkY1.BVMV != 0))
|| emitCBPB == 1)
{
emitMVDB = 1;
}
else
{
emitMVDB = 0;
}
index = (emitMVDB<<1) | emitCBPB;
PutBits(VLC_MODB[index][1], VLC_MODB[index][0],
pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: MB=%d emitCBPB=%d emitMVDB=%d MODB=%d\r\n", _fx_, curMB, (int)emitCBPB, (int)emitMVDB, (int)VLC_MODB[index][1]));
// Write CBPB
if (emitCBPB)
{
PutBits(VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)],
6, pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: CBPB=0x%x\r\n", _fx_, VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)]));
}
// Copy CBPY, {DQUANT}
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff // src
+ FutrPMBData[curMB].CBPYBitOff,
FutrPMBData[curMB].MVDBitOff // len
- FutrPMBData[curMB].CBPYBitOff);
// Write MVD{2-4}
// Note: MVD cannot be copied from future frame because
// predictors are different for PB-frame (G.2)
if( (EC->GOBHeaderPresent & GOBHeaderMask) != 0 )
{
GOBHeaderFlag = TRUE;
}
else
{
GOBHeaderFlag = FALSE;
}
writePB_MVD(curMB, pCurMB, EC->NumMBPerRow, EC->NumMBs,
pPB_BitStream, pPB_BitOffset, GOBHeaderFlag, EC);
// Write MVDB
if (emitMVDB)
{
ASSERT(pCurMB->BlkY1.BHMV >= -32 && pCurMB->BlkY1.BHMV <= 31)
ASSERT(pCurMB->BlkY1.BVMV >= -32 && pCurMB->BlkY1.BVMV <= 31)
// Write horizontal motion vector
index = (pCurMB->BlkY1.BHMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index),
pPB_BitStream, pPB_BitOffset);
// Write vertical motion vector
index = (pCurMB->BlkY1.BVMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index),
pPB_BitStream, pPB_BitOffset);
}
// Copy P-mblock blk data
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff // src
+ FutrPMBData[curMB].BlkDataBitOff,
FutrPMBData[curMB+1].MBStartBitOff // len
- FutrPMBData[curMB].MBStartBitOff
- FutrPMBData[curMB].BlkDataBitOff);
// B-frame block data is always INTER-coded (last param is 0)
if (emitCBPB)
{
rvs = MBRunValSign;
#ifdef H263P
MBEncodeVLC(&rvs, NULL, (pCurMB->CodedBlocksB & 0x3f),
pPB_BitStream, pPB_BitOffset, 0, 0);
#else
MBEncodeVLC(&rvs, NULL, pCurMB->CodedBlocksB,
pPB_BitStream, pPB_BitOffset, 0, 0);
#endif
}
} // end of else
if (bRTPHeader)
H263RTP_UpdateBsInfo(EC, pCurMB, QP, MB, GOB, *pPB_BitStream,
(U32) *pPB_BitOffset);
} // for MB
} // end of PB_GOB_Q_RLE_VLC_WriteBS()
/*************************************************************
* Name: PB_GOB_VLC_WriteBS
* Description: Write out GOB layer bits for GOB number "GOB".
* Parameters:
* EC Encoder catalog
* pMBRVS_Luma Quantized DCT coeffs. of B-block luma
* pMBRVS_Chroma Quantized DCT coeffs. of B-block chroma
* pP_BitStreamStart Pointer to start of bit stream for the future
* P-frame. Some data from future P frame is copied over
* to PB-frame.
* pPB_BitStream Current PB-frame byte pointer
* pPB_BitOffset Bit offset in the current byte pointed by pPB_BitStream
* FutrPMBData Bit stream info on future P-frame. This info. is
* initialized in GOB_Q_RLE_VLC_WriteBS()
* GOB GOBs are numbered from 0 in a frame.
* QP Quantization value for B-block coefficients.
* Side-effects:
* pPB_BitStream and pPB_BitOffset are modified as a result of writing bits
* to the stream.
* Notes:
* The improved PB-frame mode of H.263+ is currently only available in
* MMX enabled versions of the encoder. This routine is the MMX equivalent
* of PB_GOB_Q_RLE_VLC_WriteBS(), which does not contain the H.263+
* modifications.
*************************************************************/
void PB_GOB_VLC_WriteBS(
T_H263EncoderCatalog * EC,
I8 * pMBRVS_Luma,
I8 * pMBRVS_Chroma,
U8 * pP_BitStreamStart,
U8 ** pPB_BitStream,
U8 * pPB_BitOffset,
const T_FutrPMBData * const FutrPMBData,
const U32 GOB,
const U32 QP,
BOOL bRTPHeader
)
{
UN MB;
U32 curMB, index;
U32 GOBHeaderMask, GOBHeaderFlag;
U8 bUseDQUANT = 0; // Indicates if DQUANT is present.
U8 emitCBPB, emitMVDB;
register T_MBlockActionStream *pCurMB;
FX_ENTRY("PB_GOB_VLC_WriteBS")
// Create GOB header mask to be used further down.
GOBHeaderMask = 1 << GOB;
for (MB = 0, curMB = GOB*EC->NumMBPerRow,
pCurMB = EC->pU8_MBlockActionStream + curMB;
MB < EC->NumMBPerRow;
MB++, curMB++, pCurMB++)
{
/*
* Quantize and RLE each block in the macroblock,
* skipping empty blocks as denoted by CodedBlocks.
* If any more blocks are empty after quantization
* then the appropriate CodedBlocks bit is cleared.
*/
// Write MBlock data
// Check if entire macroblock is empty, including zero MV's.
if(((pCurMB->MBType == INTER)
|| (pCurMB->MBType == INTER4V))
&& (pCurMB->COD == 1) )
{
#ifdef H263P
// If forward prediction selected for B block, macroblock is not empty
if( ((pCurMB->CodedBlocksB & 0x3f) == 0)
&& (pCurMB->BlkY1.BHMV == 0)
&& (pCurMB->BlkY1.BVMV == 0)
&& ((pCurMB->CodedBlocksB & 0x80) == 0)) // forward pred. not selected
#else
if( ((pCurMB->CodedBlocksB & 0x3f) == 0)
&& (pCurMB->BlkY1.BHMV == 0)
&& (pCurMB->BlkY1.BVMV == 0))
#endif
{
// P-mblock not coded, and neither is PB-mblock.
// COD = 1, empty MB.
// If it is the first MB in the GOb, then GOB header
// is also copied
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff, // src
FutrPMBData[curMB+1].MBStartBitOff // len
- FutrPMBData[curMB].MBStartBitOff);
}
else
{ // Macro block is not empty.
// Copy COD and MCBPC
// If it is the first MB in the GOB, then GOB header
// is also copied.
if(FutrPMBData[curMB+1].MBStartBitOff - FutrPMBData[curMB].MBStartBitOff != 1)
{
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff, // src
FutrPMBData[curMB+1].MBStartBitOff // len
- FutrPMBData[curMB].MBStartBitOff - 1);
}
PutBits(0, 1, pPB_BitStream, pPB_BitOffset); // COD = 0, nonempty MB
/*******************************************
* Write macroblock header to bit stream.
*******************************************/
// Write MCBPC to bitstream.
// The rightmost two bits are the CBPC (65).
// Note that this is the reverse of the order in the
// VLC table in the H.263 spec.
index = (pCurMB->CodedBlocks >> 4) & 0x3;
// Add the MB type to next two bits to the left.
index |= (pCurMB->MBType << 2);
// Write code to bitstream.
PutBits(VLC_MCBPC_INTER[index][1], VLC_MCBPC_INTER[index][0], pPB_BitStream, pPB_BitOffset);
// Write MODB
if((pCurMB->CodedBlocksB & 0x3f) == 0)
{
emitCBPB = 0;
}
else
{
emitCBPB = 1;
}
#ifdef H263P
if (EC->PictureHeader.PB == ON && EC->PictureHeader.ImprovedPB == ON)
{
// include MVDB only if forward prediction selected
// for bidirectional prediction, MVd = [0, 0]
if (pCurMB->CodedBlocksB & 0x80)
{
emitMVDB = 1;
}
else
{
emitMVDB = 0;
}
}
else
#endif // H263P
{
if(((pCurMB->BlkY1.BHMV != 0) || (pCurMB->BlkY1.BVMV != 0)) || emitCBPB == 1)
{
emitMVDB = 1;
}
else {
emitMVDB = 0;
}
}
#ifdef H263P
if (EC->PictureHeader.PB == ON && EC->PictureHeader.ImprovedPB == ON)
{
if (!emitCBPB) {
if (!emitMVDB)
// Bidirectional prediction with all empty blocks
index = 0;
else
// Forward prediction with all empty blocks
index = 1;
} else {
if (emitMVDB)
// Forward prediction with non-empty blocks
index = 2;
else
// Bidirectional prediction with non-empty blocks
index = 3;
}
PutBits(VLC_IMPROVED_PB_MODB[index][1], VLC_IMPROVED_PB_MODB[index][0],
pPB_BitStream, pPB_BitOffset);
DbgLog((LOG_TRACE,6,TEXT("MB=%d emitCBPB=%d emitMVDB=%d MODB=%d"),
curMB, (int)emitCBPB, (int)emitMVDB,
(int)VLC_IMPROVED_PB_MODB[index][1]));
}
else // not using improved PB-frame mode
#endif // H263P
{
index = (emitMVDB<<1) | emitCBPB;
PutBits(VLC_MODB[index][1], VLC_MODB[index][0], pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: MB=%d emitCBPB=%d emitMVDB=%d MODB=%d\r\n", _fx_, curMB, (int)emitCBPB, (int)emitMVDB, (int)VLC_MODB[index][1]));
}
// Write CBPB
if(emitCBPB) {
PutBits(VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)], 6, pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: CBPB=0x%x\r\n", _fx_, VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)]));
}
PutBits(3, 2, pPB_BitStream, pPB_BitOffset); // CBPY = 11, no coded P blocks
//if( bUseDQUANT )
//{
// write DQUANT to bit stream here.
//}
// Write MVD{2-4}
// Note: MVD cannot be copied from future frame because
// predictors are different for PB-frame (G.2)
if((EC->GOBHeaderPresent & GOBHeaderMask) != 0)
{
GOBHeaderFlag = TRUE;
}
else
{
GOBHeaderFlag = FALSE;
}
writePB_MVD(curMB, pCurMB, EC->NumMBPerRow, EC->NumMBs,
pPB_BitStream, pPB_BitOffset, GOBHeaderFlag, EC);
// Write MVDB
if (emitMVDB)
{
ASSERT(pCurMB->BlkY1.BHMV >= -32 && pCurMB->BlkY1.BHMV <= 31)
ASSERT(pCurMB->BlkY1.BVMV >= -32 && pCurMB->BlkY1.BVMV <= 31)
// Write horizontal motion vector
index = (pCurMB->BlkY1.BHMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
// Write vertical motion vector
index = (pCurMB->BlkY1.BVMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
}
// There is no P-mblock blk data
// B-frame block data is always INTER-coded (last param is 0)
if (emitCBPB)
{
#ifdef H263P
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma, (pCurMB->CodedBlocksB & 0x3f),
pPB_BitStream, pPB_BitOffset, 0, 1);
#else
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma, pCurMB->CodedBlocksB,
pPB_BitStream, pPB_BitOffset, 0, 1);
#endif
}
} // end of else
}
else
{
// Copy COD and MCBPC
// If it is the first MB in the GOB, then GOB header
// is also copied.
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff, // src
FutrPMBData[curMB].CBPYBitOff); // len
// Write MODB
if((pCurMB->CodedBlocksB & 0x3f) == 0)
{
emitCBPB = 0;
}
else
{
emitCBPB = 1;
}
#ifdef H263P
if (EC->PictureHeader.PB == ON && EC->PictureHeader.ImprovedPB == ON)
{
// include MVDB only if forward prediction selected
// for bidirectional prediction, MVd = [0, 0]
if (pCurMB->CodedBlocksB & 0x80)
{
emitMVDB = 1;
}
else
{
emitMVDB = 0;
}
}
else
#endif // H263P
{
if(((pCurMB->BlkY1.BHMV != 0) || (pCurMB->BlkY1.BVMV != 0)) || emitCBPB == 1)
{
emitMVDB = 1;
}
else {
emitMVDB = 0;
}
}
#ifdef H263P
if (EC->PictureHeader.PB == ON && EC->PictureHeader.ImprovedPB == ON)
{
if (!emitCBPB) {
if (!emitMVDB)
// Bidirectional prediction with all empty blocks
index = 0;
else
// Forward prediction with all empty blocks
index = 1;
} else {
if (emitMVDB)
// Forward prediction with non-empty blocks
index = 2;
else
// Bidirectional prediction with non-empty blocks
index = 3;
}
PutBits(VLC_IMPROVED_PB_MODB[index][1], VLC_IMPROVED_PB_MODB[index][0],
pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: MB=%d emitCBPB=%d emitMVDB=%d MODB=%d\r\n", _fx_, curMB, (int)emitCBPB, (int)emitMVDB, (int)VLC_IMPROVED_PB_MODB[index][1]));
}
else // not using improved PB-frame mode
#endif // H263P
{
index = (emitMVDB<<1) | emitCBPB;
PutBits(VLC_MODB[index][1], VLC_MODB[index][0], pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: MB=%d emitCBPB=%d emitMVDB=%d MODB=%d\r\n", _fx_, curMB, (int)emitCBPB, (int)emitMVDB, (int)VLC_MODB[index][1]));
}
// Write CBPB
if (emitCBPB) {
PutBits(VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)], 6, pPB_BitStream, pPB_BitOffset);
DEBUGMSG(ZONE_ENCODE_DETAILS, ("%s: CBPB=0x%x\r\n", _fx_, VLC_CBPB[(pCurMB->CodedBlocksB & 0x3f)]));
}
// Copy CBPY, {DQUANT}
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff // src
+ FutrPMBData[curMB].CBPYBitOff, FutrPMBData[curMB].MVDBitOff // len
- FutrPMBData[curMB].CBPYBitOff);
// Write MVD{2-4}
// Note: MVD cannot be copied from future frame because
// predictors are different for PB-frame (G.2)
if((EC->GOBHeaderPresent & GOBHeaderMask) != 0)
{
GOBHeaderFlag = TRUE;
}
else
{
GOBHeaderFlag = FALSE;
}
writePB_MVD(curMB, pCurMB, EC->NumMBPerRow, EC->NumMBs,
pPB_BitStream, pPB_BitOffset, GOBHeaderFlag, EC);
// Write MVDB
if (emitMVDB)
{
ASSERT(pCurMB->BlkY1.BHMV >= -32 && pCurMB->BlkY1.BHMV <= 31)
ASSERT(pCurMB->BlkY1.BVMV >= -32 && pCurMB->BlkY1.BVMV <= 31)
// Write horizontal motion vector
index = (pCurMB->BlkY1.BHMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
// Write vertical motion vector
index = (pCurMB->BlkY1.BVMV + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
}
// Copy P-mblock blk data
CopyBits(pPB_BitStream, pPB_BitOffset, // dest
pP_BitStreamStart, FutrPMBData[curMB].MBStartBitOff // src
+ FutrPMBData[curMB].BlkDataBitOff,
FutrPMBData[curMB+1].MBStartBitOff // len
- FutrPMBData[curMB].MBStartBitOff
- FutrPMBData[curMB].BlkDataBitOff);
// B-frame block data is always INTER-coded (last param is 0)
if(emitCBPB)
{
#ifdef H263P
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma,
(pCurMB->CodedBlocksB & 0x3f),
pPB_BitStream, pPB_BitOffset, 0, 1);
#else
MBEncodeVLC(&pMBRVS_Luma, &pMBRVS_Chroma,
pCurMB->CodedBlocksB,
pPB_BitStream, pPB_BitOffset, 0, 1);
#endif
}
} // end of else
if (bRTPHeader)
H263RTP_UpdateBsInfo(EC, pCurMB, QP, MB, GOB, *pPB_BitStream,
(U32) *pPB_BitOffset);
} // for MB
} // end of PB_GOB_VLC_WriteBS()
/***************************************************************
* MB_Quantize_RLE
* Takes the list of coefficient pairs from the DCT routine
* and returns a list of Run/Level/Sign triples (each 1 byte)
* The end of the run/level/sign triples for a block
* is signalled by an illegal combination (TBD).
****************************************************************/
static I8 * MB_Quantize_RLE(
I32 **DCTCoefs,
I8 *MBRunValPairs,
U8 *CodedBlocks,
U8 BlockType,
I32 QP
)
{
int b;
U8 bitmask = 1;
I8 * EndAddress;
#ifdef DEBUG_DCT
int DCTarray[64];
#endif
FX_ENTRY("MB_Quantize_RLE")
/*
* Loop through all 6 blocks of macroblock.
*/
for(b = 0; b < 6; b++, bitmask <<= 1)
{
DEBUGMSG(ZONE_ENCODE_MB, ("%s: Block #%d\r\n", _fx_, b));
// Skip this block if not coded.
if( (*CodedBlocks & bitmask) == 0)
continue;
#ifdef DEBUG_DCT
cnvt_fdct_output((unsigned short *) *DCTCoefs, DCTarray, (int) BlockType);
#endif
/*
* Quantize and run-length encode a block.
*/
EndAddress = QUANTRLE(*DCTCoefs, MBRunValPairs, QP, (int)BlockType);
#ifdef DEBUG
char *p;
for(p = (char *)MBRunValPairs; p < (char *)EndAddress; p+=3)
{
DEBUGMSG(ZONE_ENCODE_MB, ("%s: (%u, %u, %d)\r\n", _fx_, (unsigned char)*p, (unsigned char)*(p+1), (int)*(p+2)));
}
#endif
// Clear coded block bit for this block.
if ( EndAddress == MBRunValPairs)
{
ASSERT(BlockType != INTRABLOCK) // should have at least INTRADC in an INTRA blck
*CodedBlocks &= ~bitmask;
}
else if ( (EndAddress == (MBRunValPairs+3)) && (BlockType == INTRABLOCK) )
{
*CodedBlocks &= ~bitmask;
MBRunValPairs = EndAddress;
}
else
{
MBRunValPairs = EndAddress;
*MBRunValPairs = -1; // Assign an illegal run to signal end of block.
MBRunValPairs += 3; // Increment to the next triple.
}
*DCTCoefs += 32; // Increment DCT Coefficient pointer to next block.
}
return MBRunValPairs;
}
/*******************************************************************
* Variable length code teh run/level/sign triples and write the
* codes to the bitstream.
*******************************************************************/
/*
U8 * MB_VLC_WriteBS()
{
for(b = 0; b < 6; b++)
{
Block_VLC_WriteBS()
}
}
*/
void InitVLC(void)
{
int i, size, code;
int run, level;
/*
* initialize INTRADC fixed length code table.
*/
for(i = 1; i < 254; i++)
{
FLC_INTRADC[i] = i;
}
FLC_INTRADC[0] = 1;
FLC_INTRADC[128] = 255;
FLC_INTRADC[254] = 254;
FLC_INTRADC[255] = 254;
/*
* Initialize tcoef tables.
*/
for(i=0; i < 64*12; i++)
{
VLC_TCOEF_TBL[i] = 0x0000FFFF;
}
for(run=0; run < 64; run++)
{
for(level=1; level <= TCOEF_RUN_MAXLEVEL[run].maxlevel; level++)
{
size = *(TCOEF_RUN_MAXLEVEL[run].ptable + (level - 1)*2);
size <<= 16;
code = *(TCOEF_RUN_MAXLEVEL[run].ptable + (level - 1)*2 +1);
VLC_TCOEF_TBL[ (run) + (level-1)*64 ] = code;
VLC_TCOEF_TBL[ (run) + (level-1)*64 ] |= size;
} // end of for level
} // end of for run
/*
* Initialize last tcoef tables.
*/
for(i=0; i < 64*3; i++)
{
VLC_TCOEF_LAST_TBL[i] = 0x0000FFFF;
}
run = 0;
for(level=1; level <= 3; level++)
{
size = *(VLC_TCOEF + 58*2 + (level - 1)*2);
size <<= 16;
code = *(VLC_TCOEF + 58*2 + (level - 1)*2 +1);
VLC_TCOEF_LAST_TBL[ run + (level-1)*64 ] = code;
VLC_TCOEF_LAST_TBL[ run + (level-1)*64 ] |= size;
} // end of for level
run = 1;
for(level=1; level <= 2; level++)
{
size = *(VLC_TCOEF + 61*2 + (level - 1)*2);
size <<= 16;
code = *(VLC_TCOEF + 61*2 + (level - 1)*2 +1);
VLC_TCOEF_LAST_TBL[ run + (level-1)*64 ] = code;
VLC_TCOEF_LAST_TBL[ run + (level-1)*64 ] |= size;
} // end of for level
level=1;
for(run=2; run <= 40; run++)
{
size = *(VLC_TCOEF + 63*2+ (run - 2)*2);
size <<= 16;
code = *(VLC_TCOEF + 63*2 + (run - 2)*2 +1);
VLC_TCOEF_LAST_TBL[ run + (level-1)*64 ] = code;
VLC_TCOEF_LAST_TBL[ run + (level-1)*64 ] |= size;
} // end of for run
} // InitVLC.
/******************************************************************
* Name: median
*
* Description: Take the median of three signed chars. Implementation taken
* from the decoder.
*******************************************************************/
static char __fastcall median(char v1, char v2, char v3)
{
char temp;
if (v2 < v1)
{
temp = v2; v2 = v1; v1 = temp;
}
// Invariant : v1 < v2
if (v2 > v3)
{
v2 = (v1 < v3) ? v3 : v1;
}
return v2;
}
/*************************************************************
* Name: writeP_MVD
* Algorithm: See section 6.1.1
* This routine assumes that there are always four motion
* vectors per macroblock defined. If there is actually one
* motion vector in the macroblock, then the four MV fields
* should be equivalent. In this way the MV predictor for
* block 1 of the 4 MV case is calculated the same way as the
* MV predictor for the macroblock in the 1 MV case.
************************************************************/
static void writeP_MVD(
const U32 curMB,
T_MBlockActionStream * const pCurMB,
const U32 NumMBPerRow,
const U32 NumMBs,
U8 ** pP_BitStream,
U8 * pP_BitOffset,
U32 GOBHeaderPresent,
T_H263EncoderCatalog *EC
)
{
I8 HMV, VMV, BHMV, BVMV, CHMV, CVMV, DHMV, DVMV;
I8 HMV1, HMV2, HMV3, VMV1, VMV2, VMV3;
FX_ENTRY("writeP_MVD")
//FirstMEState = pCurMB->FirstMEState;
/*
* Top left corner of picture of GOB.
*/
if( (curMB == 0) ||
( (GOBHeaderPresent == TRUE) && ((curMB % NumMBPerRow) == 0) ) )
{
HMV = 0;
VMV = 0;
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
BHMV = pCurMB->BlkY1.PHMV;
BVMV = pCurMB->BlkY1.PVMV;
// Predictor for Block 3.
HMV1 = VMV1 = 0;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Upper edge (not corner) or upper right corner of picture
* or GOB.
*/
else if( (curMB < NumMBPerRow) ||
( (GOBHeaderPresent == TRUE) && ((curMB % NumMBPerRow) > 0) ) )
{
register T_MBlockActionStream *pMB1;
pMB1 = pCurMB - 1;
HMV = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PHMV : 0);
VMV = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PVMV : 0);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
BHMV = pCurMB->BlkY1.PHMV;
BVMV = pCurMB->BlkY1.PVMV;
// Predictor for Block 3.
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PHMV : 0);
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PVMV : 0);
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Central portion of the picture, not next to any edge.
*/
else if ( ((curMB % NumMBPerRow) != 0) && // not left edge
(curMB >= NumMBPerRow) && // not top row
((curMB % NumMBPerRow) != (NumMBPerRow-1)) && // not right edge
(curMB < (NumMBs - NumMBPerRow)) ) // not bottom row
{
register T_MBlockActionStream *pMB1, *pMB2, *pMB3;
pMB1 = pCurMB - 1;
pMB2 = pCurMB - NumMBPerRow;
pMB3 = pMB2 + 1;
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PHMV : 0);
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PHMV : 0);
HMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PHMV : 0);
HMV = median(HMV1, HMV2, HMV3);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PVMV : 0);
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PVMV : 0);
VMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PVMV : 0);
VMV = median(VMV1, VMV2, VMV3);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PHMV : 0);
HMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PHMV : 0);
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PVMV : 0);
VMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PVMV : 0);
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PHMV : 0);
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PVMV : 0);
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Left edge or lower left corner.
*/
else if( (curMB % NumMBPerRow) == 0 )
{
register T_MBlockActionStream *pMB2, *pMB3;
pMB2 = pCurMB - NumMBPerRow;
pMB3 = pMB2 + 1;
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PHMV : 0);
HMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PHMV : 0);
HMV = median(0, HMV2, HMV3);
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PVMV : 0);
VMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PVMV : 0);
VMV = median(0, VMV2, VMV3);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PHMV : 0);
HMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PHMV : 0);
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PVMV : 0);
VMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PVMV : 0);
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = 0;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = 0;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Right edge or lower right corner.
*/
else if( (curMB % NumMBPerRow) == (NumMBPerRow-1) )
{
register T_MBlockActionStream *pMB1, *pMB2;
pMB1 = pCurMB - 1;
pMB2 = pCurMB - NumMBPerRow;
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PHMV : 0);
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PHMV : 0);
HMV = median(HMV1, HMV2, 0);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PVMV : 0);
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PVMV : 0);
VMV = median(VMV1, VMV2, 0);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PHMV : 0);
HMV3 = 0;
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PVMV : 0);
VMV3 = 0;
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PHMV : 0);
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PVMV : 0);
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
else
{
register T_MBlockActionStream *pMB1, *pMB2, *pMB3;
pMB1 = pCurMB - 1;
pMB2 = pCurMB - NumMBPerRow;
pMB3 = pMB2 + 1;
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PHMV : 0);
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PHMV : 0);
HMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PHMV : 0);
HMV = median(HMV1, HMV2, HMV3);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY2.PVMV : 0);
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY3.PVMV : 0);
VMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PVMV : 0);
VMV = median(VMV1, VMV2, VMV3);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PHMV : 0);
HMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PHMV : 0);
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = (pMB2->BlockType != INTRABLOCK ? pMB2->BlkY4.PVMV : 0);
VMV3 = (pMB3->BlockType != INTRABLOCK ? pMB3->BlkY3.PVMV : 0);
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PHMV : 0);
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = (pMB1->BlockType != INTRABLOCK ? pMB1->BlkY4.PVMV : 0);
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/******************************************************************
* Compute motion vector delta and write VLC out to the bitstream
******************************************************************/
register I32 hdelta, vdelta;
register U32 index;
hdelta = pCurMB->BlkY1.PHMV - HMV;
vdelta = pCurMB->BlkY1.PVMV - VMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY2.PHMV >= -32 && pCurMB->BlkY2.PHMV <= 31));
ASSERT((pCurMB->BlkY2.PVMV >= -32 && pCurMB->BlkY2.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY2.PHMV >= -63 && pCurMB->BlkY2.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY2.PHMV >= 0 && pCurMB->BlkY2.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY2.PVMV >= -63 && pCurMB->BlkY2.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY2.PVMV >= 0 && pCurMB->BlkY2.PVMV <= 63));
}
}
#endif
if (EC->PictureHeader.UMV == ON)
{
if (HMV < -31 && hdelta < -63)
hdelta += 64;
else if (HMV > 32 && hdelta > 63)
hdelta -= 64;
if (VMV < -31 && vdelta < -63)
vdelta += 64;
else if (VMV > 32 && vdelta > 63)
vdelta -= 64;
}
// Adjust the deltas to be in the range of -32...+31
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (P Block 1) MB#=%d - MV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY1.PHMV, pCurMB->BlkY1.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
/*
* Deal with 4 MV case.
*/
if(pCurMB->MBType == INTER4V)
{
/*--------------
* Block 2.
*--------------*/
hdelta = pCurMB->BlkY2.PHMV - BHMV;
vdelta = pCurMB->BlkY2.PVMV - BVMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY2.PHMV >= -32 && pCurMB->BlkY2.PHMV <= 31));
ASSERT((pCurMB->BlkY2.PVMV >= -32 && pCurMB->BlkY2.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY2.PHMV >= -63 && pCurMB->BlkY2.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY2.PHMV >= 0 && pCurMB->BlkY2.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY2.PVMV >= -63 && pCurMB->BlkY2.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY2.PVMV >= 0 && pCurMB->BlkY2.PVMV <= 63));
}
}
#endif
if (EC->PictureHeader.UMV == ON)
{
if (BHMV < -31 && hdelta < -63)
hdelta += 64;
else if (BHMV > 32 && hdelta > 63)
hdelta -= 64;
if (BVMV < -31 && vdelta < -63)
vdelta += 64;
else if (BVMV > 32 && vdelta > 63)
vdelta -= 64;
}
// Adjust the deltas to be in the range of -32...+31
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (P Block 2)MB#=%d - MV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY2.PHMV, pCurMB->BlkY2.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
/*----------------
* Block 3
*---------------*/
hdelta = pCurMB->BlkY3.PHMV - CHMV;
vdelta = pCurMB->BlkY3.PVMV - CVMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY3.PHMV >= -32 && pCurMB->BlkY3.PHMV <= 31));
ASSERT((pCurMB->BlkY3.PVMV >= -32 && pCurMB->BlkY3.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY3.PHMV >= -63 && pCurMB->BlkY3.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY3.PHMV >= 0 && pCurMB->BlkY3.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY3.PVMV >= -63 && pCurMB->BlkY3.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY3.PVMV >= 0 && pCurMB->BlkY3.PVMV <= 63));
}
}
#endif
if (EC->PictureHeader.UMV == ON)
{
if (CHMV < -31 && hdelta < -63)
hdelta += 64;
else if (CHMV > 32 && hdelta > 63)
hdelta -= 64;
if (CVMV < -31 && vdelta < -63)
vdelta += 64;
else if (CVMV > 32 && vdelta > 63)
vdelta -= 64;
}
// Adjust the deltas to be in the range of -32...+31
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (P Block 3)MB#=%d - MV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY3.PHMV, pCurMB->BlkY3.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
/*-----------------
* Block 4
*-------------------*/
hdelta = pCurMB->BlkY4.PHMV - DHMV;
vdelta = pCurMB->BlkY4.PVMV - DVMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY4.PHMV >= -32 && pCurMB->BlkY4.PHMV <= 31));
ASSERT((pCurMB->BlkY4.PVMV >= -32 && pCurMB->BlkY4.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY4.PHMV >= -63 && pCurMB->BlkY4.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY4.PHMV >= 0 && pCurMB->BlkY4.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY4.PVMV >= -63 && pCurMB->BlkY4.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY4.PVMV >= 0 && pCurMB->BlkY4.PVMV <= 63));
}
}
#endif
if (EC->PictureHeader.UMV == ON)
{
if (DHMV < -31 && hdelta < -63)
hdelta += 64;
else if (DHMV > 32 && hdelta > 63)
hdelta -= 64;
if (DVMV < -31 && vdelta < -63)
vdelta += 64;
else if (DVMV > 32 && vdelta > 63)
vdelta -= 64;
}
// Adjust the deltas to be in the range of -32...+31
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (P Block 4)MB#=%d - MV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY4.PHMV, pCurMB->BlkY4.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pP_BitStream, pP_BitOffset);
#ifdef COUNT_BITS
EC->Bits.MBHeader += *(vlc_mvd+index);
EC->Bits.MV += *(vlc_mvd+index);
#endif
} // end of if INTER4V
}
/*************************************************************
* Name: writePB_MVD
* Algorithm: See section 6.1.1 and annex G
* This routine assumes that there are always four motion
* vectors per macroblock defined. If there is actually one
* motion vector in the macroblock, then the four MV fields
* should be equivalent. In this way the MV predictor for
* block 1 of the 4 MV case is calculated the same way as the
* MV predictor for the macroblock in the 1 MV case.
************************************************************/
static void writePB_MVD(
const U32 curMB,
T_MBlockActionStream * const pCurMB,
const U32 NumMBPerRow,
const U32 NumMBs,
U8 ** pPB_BitStream,
U8 * pPB_BitOffset,
U32 GOBHeaderPresent,
const T_H263EncoderCatalog *EC
)
{
U8 FirstMEState;
I8 HMV, VMV, BHMV, BVMV, CHMV, CVMV, DHMV, DVMV;
I8 HMV1, HMV2, HMV3, VMV1, VMV2, VMV3;
FX_ENTRY("writePB_MVD")
FirstMEState = pCurMB->FirstMEState;
/*
* Top left corner of picture of GOB.
*/
if( (curMB == 0) ||
( (GOBHeaderPresent == TRUE) && ((curMB % NumMBPerRow) == 0) ) )
{
HMV = 0;
VMV = 0;
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
BHMV = pCurMB->BlkY1.PHMV;
BVMV = pCurMB->BlkY1.PVMV;
// Predictor for Block 3.
HMV1 = VMV1 = 0;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Upper edge (not corner) or upper right corner of picture
* or GOB.
*/
else if( (curMB < NumMBPerRow) ||
( (GOBHeaderPresent == TRUE) && ((curMB % NumMBPerRow) > 0) ) )
{
register T_MBlockActionStream *pMB1;
pMB1 = pCurMB - 1;
HMV = pMB1->BlkY2.PHMV;
VMV = pMB1->BlkY2.PVMV;
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
BHMV = pCurMB->BlkY1.PHMV;
BVMV = pCurMB->BlkY1.PVMV;
// Predictor for Block 3.
HMV1 = pMB1->BlkY4.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = pMB1->BlkY4.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Central portion of the picture, not next to any edge.
*/
else if ( ((curMB % NumMBPerRow) != 0) && // not left edge
(curMB >= NumMBPerRow) && // not top row
((curMB % NumMBPerRow) != (NumMBPerRow-1)) && // not right edge
(curMB < (NumMBs - NumMBPerRow)) ) // not bottom row
{
register T_MBlockActionStream *pMB1, *pMB2, *pMB3;
pMB1 = pCurMB - 1;
pMB2 = pCurMB - NumMBPerRow;
pMB3 = pMB2 + 1;
HMV = median(pMB1->BlkY2.PHMV, pMB2->BlkY3.PHMV, pMB3->BlkY3.PHMV);
VMV = median(pMB1->BlkY2.PVMV, pMB2->BlkY3.PVMV, pMB3->BlkY3.PVMV);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = pMB2->BlkY4.PHMV;
HMV3 = pMB3->BlkY3.PHMV;
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = pMB2->BlkY4.PVMV;
VMV3 = pMB3->BlkY3.PVMV;
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = pMB1->BlkY4.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = pMB1->BlkY4.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Left edge or lower left corner.
*/
else if( (curMB % NumMBPerRow) == 0 )
{
register T_MBlockActionStream *pMB2, *pMB3;
pMB2 = pCurMB - NumMBPerRow;
pMB3 = pMB2 + 1;
HMV = median(0, pMB2->BlkY3.PHMV, pMB3->BlkY3.PHMV);
VMV = median(0, pMB2->BlkY3.PVMV, pMB3->BlkY3.PVMV);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = pMB2->BlkY4.PHMV;
HMV3 = pMB3->BlkY3.PHMV;
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = pMB2->BlkY4.PVMV;
VMV3 = pMB3->BlkY3.PVMV;
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = 0;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = 0;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/*
* Right edge or lower right corner.
*/
else if( (curMB % NumMBPerRow) == (NumMBPerRow-1) )
{
register T_MBlockActionStream *pMB1, *pMB2;
pMB1 = pCurMB - 1;
pMB2 = pCurMB - NumMBPerRow;
HMV = median(pMB1->BlkY2.PHMV, pMB2->BlkY3.PHMV, 0);
VMV = median(pMB1->BlkY2.PVMV, pMB2->BlkY3.PVMV, 0);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = pMB2->BlkY4.PHMV;
HMV3 = 0;
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = pMB2->BlkY4.PVMV;
VMV3 = 0;
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = pMB1->BlkY4.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = pMB1->BlkY4.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
else
{
register T_MBlockActionStream *pMB1, *pMB2, *pMB3;
pMB1 = pCurMB - 1;
pMB2 = pCurMB - NumMBPerRow;
pMB3 = pMB2 + 1;
HMV = median(pMB1->BlkY2.PHMV, pMB2->BlkY3.PHMV, pMB3->BlkY3.PHMV);
VMV = median(pMB1->BlkY2.PVMV, pMB2->BlkY3.PVMV, pMB3->BlkY3.PVMV);
if(pCurMB->MBType == INTER4V)
{
// Predictor for Block 2.
HMV1 = pCurMB->BlkY1.PHMV;
HMV2 = pMB2->BlkY4.PHMV;
HMV3 = pMB3->BlkY3.PHMV;
BHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY1.PVMV;
VMV2 = pMB2->BlkY4.PVMV;
VMV3 = pMB3->BlkY3.PVMV;
BVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 3.
HMV1 = pMB1->BlkY4.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
CHMV = median(HMV1, HMV2, HMV3);
VMV1 = pMB1->BlkY4.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
CVMV = median(VMV1, VMV2, VMV3);
// Predictor for Block 4
HMV1 = pCurMB->BlkY3.PHMV;
HMV2 = pCurMB->BlkY1.PHMV;
HMV3 = pCurMB->BlkY2.PHMV;
DHMV = median(HMV1, HMV2, HMV3);
VMV1 = pCurMB->BlkY3.PVMV;
VMV2 = pCurMB->BlkY1.PVMV;
VMV3 = pCurMB->BlkY2.PVMV;
DVMV = median(VMV1, VMV2, VMV3);
} // end of if INTER4V
}
/******************************************************************
* Compute motion vector delta and write VLC out to the bitstream
******************************************************************/
register I32 hdelta, vdelta;
register U32 index;
hdelta = pCurMB->BlkY1.PHMV - HMV;
vdelta = pCurMB->BlkY1.PVMV - VMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY1.PHMV >= -32 && pCurMB->BlkY1.PHMV <= 31));
ASSERT((pCurMB->BlkY1.PVMV >= -32 && pCurMB->BlkY1.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY1.PHMV >= -63 && pCurMB->BlkY1.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY1.PHMV >= 0 && pCurMB->BlkY1.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY1.PVMV >= -63 && pCurMB->BlkY1.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY1.PVMV >= 0 && pCurMB->BlkY1.PVMV <= 63));
}
}
#endif
// Adjust the deltas to be in the range of -32...+31
if (EC->PictureHeader.UMV == ON)
{
if (HMV < -31 && hdelta < -63)
hdelta += 64;
else if (HMV > 32 && hdelta > 63)
hdelta -= 64;
if (VMV < -31 && vdelta < -63)
vdelta += 64;
else if (VMV > 32 && vdelta > 63)
vdelta -= 64;
}
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (PB Block 1)MB#=%d - MV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY1.PHMV, pCurMB->BlkY1.PVMV));
// Write horizontal motion vector delta
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
// Write vertical motion vector delta
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
/*
* Deal with 4 MV case.
*/
if(pCurMB->MBType == INTER4V)
{
/*--------------
* Block 2.
*--------------*/
hdelta = pCurMB->BlkY2.PHMV - BHMV;
vdelta = pCurMB->BlkY2.PVMV - BVMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY2.PHMV >= -32 && pCurMB->BlkY2.PHMV <= 31));
ASSERT((pCurMB->BlkY2.PVMV >= -32 && pCurMB->BlkY2.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY2.PHMV >= -63 && pCurMB->BlkY2.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY2.PHMV >= 0 && pCurMB->BlkY2.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY2.PVMV >= -63 && pCurMB->BlkY2.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY2.PVMV >= 0 && pCurMB->BlkY2.PVMV <= 63));
}
}
#endif
// Adjust the deltas to be in the range of -32...+31
if (EC->PictureHeader.UMV == ON)
{
if (BHMV < -31 && hdelta < -63)
hdelta += 64;
else if (BHMV > 32 && hdelta > 63)
hdelta -= 64;
if (BVMV < -31 && vdelta < -63)
vdelta += 64;
else if (BVMV > 32 && vdelta > 63)
vdelta -= 64;
}
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (PB Block 2)MB#=%d - MV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY2.PHMV, pCurMB->BlkY2.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
/*----------------
* Block 3
*---------------*/
hdelta = pCurMB->BlkY3.PHMV - CHMV;
vdelta = pCurMB->BlkY3.PVMV - CVMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY3.PHMV >= -32 && pCurMB->BlkY3.PHMV <= 31));
ASSERT((pCurMB->BlkY3.PVMV >= -32 && pCurMB->BlkY3.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY3.PHMV >= -63 && pCurMB->BlkY3.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY3.PHMV >= 0 && pCurMB->BlkY3.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY3.PVMV >= -63 && pCurMB->BlkY3.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY3.PVMV >= 0 && pCurMB->BlkY3.PVMV <= 63));
}
}
#endif
// Adjust the deltas to be in the range of -32...+31
if (EC->PictureHeader.UMV == ON)
{
if (CHMV < -31 && hdelta < -63)
hdelta += 64;
else if (CHMV > 32 && hdelta > 63)
hdelta -= 64;
if (CVMV < -31 && vdelta < -63)
vdelta += 64;
else if (CVMV > 32 && vdelta > 63)
vdelta -= 64;
}
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (PB Block 3)MB#=%d\nMV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY3.PHMV, pCurMB->BlkY3.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
/*-----------------
* Block 4
*-------------------*/
hdelta = pCurMB->BlkY4.PHMV - DHMV;
vdelta = pCurMB->BlkY4.PVMV - DVMV;
#ifdef DEBUG
if (EC->PictureHeader.UMV == OFF) {
ASSERT((pCurMB->BlkY4.PHMV >= -32 && pCurMB->BlkY4.PHMV <= 31));
ASSERT((pCurMB->BlkY4.PVMV >= -32 && pCurMB->BlkY4.PVMV <= 31));
} else {
if (HMV <= -32) {
ASSERT((pCurMB->BlkY4.PHMV >= -63 && pCurMB->BlkY4.PHMV <= 0));
} else if (HMV <= 32) {
ASSERT((hdelta >= -32 && hdelta <= 31));
} else {
ASSERT((pCurMB->BlkY4.PHMV >= 0 && pCurMB->BlkY4.PHMV <= 63));
}
if (VMV <= -32) {
ASSERT((pCurMB->BlkY4.PVMV >= -63 && pCurMB->BlkY4.PVMV <= 0));
} else if (VMV <= 32) {
ASSERT((vdelta >= -32 && vdelta <= 31));
} else {
ASSERT((pCurMB->BlkY4.PVMV >= 0 && pCurMB->BlkY4.PVMV <= 63));
}
}
#endif
// Adjust the deltas to be in the range of -32...+31
if (EC->PictureHeader.UMV == ON)
{
if (DHMV < -31 && hdelta < -63)
hdelta += 64;
else if (DHMV > 32 && hdelta > 63)
hdelta -= 64;
if (DVMV < -31 && vdelta < -63)
vdelta += 64;
else if (DVMV > 32 && vdelta > 63)
vdelta -= 64;
}
if(hdelta > 31)
hdelta -= 64;
if(hdelta < -32)
hdelta += 64;
if(vdelta > 31)
vdelta -= 64;
if(vdelta < -32)
vdelta += 64;
DEBUGMSG(ZONE_ENCODE_MV, ("%s: (PB Block 4)MB#=%d\nMV Delta: (%d, %d) Motion Vectors: (%d, %d)\r\n", _fx_, curMB, hdelta, vdelta, pCurMB->BlkY4.PHMV, pCurMB->BlkY4.PVMV));
// Write horizontal motion vector delta here.
index = (hdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
// Write horizontal motion vector delta here.
index = (vdelta + 32)*2;
PutBits( *(vlc_mvd+index+1), *(vlc_mvd+index), pPB_BitStream, pPB_BitOffset);
} // end of if INTER4V
}