/*===========================================================================* * mheaders.c * * * * Procedures to generate MPEG headers * * * * EXPORTED PROCEDURES: * * Mhead_GenPictureHeader * * Mhead_GenSequenceHeader * * Mhead_GenSequenceEnder * * Mhead_GenGOPHeader * * Mhead_GenSliceHeader * * Mhead_GenSliceEnder * * Mhead_GenMBHeader * * * *===========================================================================*/ /* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* * $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/mheaders.c,v 1.15 1995/08/07 21:45:19 smoot Exp $ * $Log: mheaders.c,v $ * Revision 1.15 1995/08/07 21:45:19 smoot * check for illegal MVs (shouldnt ever be called, but....) * fix bug which made us not weite Iframe Qscale changes * warns if writing a size=0 mpeg * * Revision 1.14 1995/05/22 20:53:35 smoot * corrected bit_rate value in constrained params flag * * Revision 1.13 1995/05/02 01:50:38 eyhung * made VidRateNum un-static * * Revision 1.12 1995/03/27 19:28:23 smoot * auto-determines Qscale changes (was mb_quant) * * Revision 1.11 1995/02/16 09:12:39 eyhung * fixed compile bug with HP7xx * * Revision 1.10 1995/01/25 22:53:50 smoot * Better buf_size checking, and actually check constrained params * * Revision 1.9 1995/01/19 23:08:47 eyhung * Changed copyrights * * Revision 1.8 1995/01/16 08:45:10 eyhung * BLEAH'ed hsize and vsize * * Revision 1.7 1994/12/09 22:27:17 smoot * Fixed buffer size in stream * * Revision 1.6 1994/11/12 02:11:54 keving * nothing * * Revision 1.5 1994/03/15 00:27:11 keving * nothing * * Revision 1.4 1993/12/22 19:19:01 keving * nothing * * Revision 1.3 1993/07/22 22:23:43 keving * nothing * * Revision 1.2 1993/06/30 20:06:09 keving * nothing * * Revision 1.1 1993/06/03 21:08:08 keving * nothing * * Revision 1.6 1993/03/01 23:03:40 keving * nothing * * Revision 1.5 1993/02/17 23:18:20 dwallach * checkin prior to keving's joining the project * * Revision 1.4 1993/01/18 10:20:02 dwallach * *** empty log message *** * * Revision 1.3 1993/01/18 10:17:29 dwallach * RCS headers installed, code indented uniformly * * Revision 1.3 1993/01/18 10:17:29 dwallach * RCS headers installed, code indented uniformly * */ /*==============* * HEADER FILES * *==============*/ #include "all.h" #include "bitio.h" #include "frames.h" #include "mheaders.h" /*==================* * STATIC VARIABLES * *==================*/ static int gopStartFrame = 0; static int lastGOPStart = 0; static int lastQSSet; static uint32 mbAddrIncrTable[][2] = { {0x0, 0}, {0x1, 1}, {0x3, 3}, {0x2, 3}, {0x3, 4}, {0x2, 4}, {0x3, 5}, {0x2, 5}, {0x7, 7}, {0x6, 7}, {0xb, 8}, {0xa, 8}, {0x9, 8}, {0x8, 8}, {0x7, 8}, {0x6, 8}, {0x17, 10}, {0x16, 10}, {0x15, 10}, {0x14, 10}, {0x13, 10}, {0x12, 10}, {0x23, 11}, {0x22, 11}, {0x21, 11}, {0x20, 11}, {0x1f, 11}, {0x1e, 11}, {0x1d, 11}, {0x1c, 11}, {0x1b, 11}, {0x1a, 11}, {0x19, 11}, {0x18, 11}}; static uint32 mbMotionVectorTable[][2] = { {0x19, 11}, {0x1b, 11}, {0x1d, 11}, {0x1f, 11}, {0x21, 11}, {0x23, 11}, {0x13, 10}, {0x15, 10}, {0x17, 10}, {0x7, 8}, {0x9, 8}, {0xb, 8}, {0x7, 7}, {0x3, 5}, {0x3, 4}, {0x3, 3}, {0x1, 1}, {0x2, 3}, {0x2, 4}, {0x2, 5}, {0x6, 7}, {0xa, 8}, {0x8, 8}, {0x6, 8}, {0x16, 10}, {0x14, 10}, {0x12, 10}, {0x22, 11}, {0x20, 11}, {0x1e, 11}, {0x1c, 11}, {0x1a, 11}, {0x18, 11}}; static uint32 mbPatTable[][2] = { {0x0, 0}, {0xb, 5}, {0x9, 5}, {0xd, 6}, {0xd, 4}, {0x17, 7}, {0x13, 7}, {0x1f, 8}, {0xc, 4}, {0x16, 7}, {0x12, 7}, {0x1e, 8}, {0x13, 5}, {0x1b, 8}, {0x17, 8}, {0x13, 8}, {0xb, 4}, {0x15, 7}, {0x11, 7}, {0x1d, 8}, {0x11, 5}, {0x19, 8}, {0x15, 8}, {0x11, 8}, {0xf, 6}, {0xf, 8}, {0xd, 8}, {0x3, 9}, {0xf, 5}, {0xb, 8}, {0x7, 8}, {0x7, 9}, {0xa, 4}, {0x14, 7}, {0x10, 7}, {0x1c, 8}, {0xe, 6}, {0xe, 8}, {0xc, 8}, {0x2, 9}, {0x10, 5}, {0x18, 8}, {0x14, 8}, {0x10, 8}, {0xe, 5}, {0xa, 8}, {0x6, 8}, {0x6, 9}, {0x12, 5}, {0x1a, 8}, {0x16, 8}, {0x12, 8}, {0xd, 5}, {0x9, 8}, {0x5, 8}, {0x5, 9}, {0xc, 5}, {0x8, 8}, {0x4, 8}, {0x4, 9}, {0x7, 3}, {0xa, 5}, /* grrr... 61, 62, 63 added - Kevin */ {0x8, 5}, {0xc, 6} }; /*===========* * CONSTANTS * *===========*/ #define SEQ_HEAD_CODE 0x000001b3 #define EXT_START_CODE 0x000001b5 #define USER_START_CODE 0x000001b2 #define GOP_START_CODE 0x000001b8 #define PICT_START_CODE 0x00000100 #define SLICE_BASE_CODE 0x00000100 #define SEQ_END_CODE 0x000001b7 /* not static anymore because information is used for computing frame rate * and for statistics */ const double VidRateNum[9]={1.0, 23.976, 24.0, 25.0, 29.97, 30.0, 50.0 ,59.94, 60.0}; /*===============================* * INTERNAL PROCEDURE prototypes * *===============================*/ static void GenMBAddrIncr _ANSI_ARGS_((BitBucket *bb, uint32 addr_incr)); static void GenPictHead _ANSI_ARGS_((BitBucket *bb, uint32 temp_ref, uint32 code_type, uint32 vbv_delay, int32 full_pel_forw_flag, uint32 forw_f_code, int32 full_pel_back_flag, uint32 back_f_code, uint8 *extra_info, uint32 extra_info_size, uint8 *ext_data, uint32 ext_data_size, uint8 *user_data, uint32 user_data_size)); static void GenMBType _ANSI_ARGS_((BitBucket *bb, uint32 pict_code_type, uint32 mb_quant, uint32 motion_forw, uint32 motion_back, uint32 mb_pattern, uint32 mb_intra)); static void GenMotionCode _ANSI_ARGS_((BitBucket *bb, int32 vector)); static void GenBlockPattern _ANSI_ARGS_((BitBucket *bb, uint32 mb_pattern)); /*=====================* * EXPORTED PROCEDURES * *=====================*/ /*===========================================================================* * * SetGOPStartTime * * sets the start frame of the GOP; to be used with GenPictureHeader * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void SetGOPStartTime(index) int index; { lastGOPStart = gopStartFrame; gopStartFrame = index; } /*===========================================================================* * * Mhead_GenPictureHeader * * generate picture header with given frame type and picture count * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenPictureHeader(bbPtr, frameType, pictCount, f_code) BitBucket *bbPtr; int frameType; int pictCount; int f_code; { int temporalRef; if ( pictCount >= gopStartFrame ) { temporalRef = (pictCount-gopStartFrame); } else { temporalRef = (pictCount-lastGOPStart); } temporalRef = (temporalRef % 1024); DBG_PRINT(("Picture Header\n")); GenPictHead(bbPtr, temporalRef, frameType, 0 /* vbv_delay */, pixelFullSearch /* full_pel_forw_flag */, f_code /* forw_f_code */, pixelFullSearch /* full_pel_back_flag */, f_code /* back_f_code */, NULL, 0, NULL, 0, NULL, 0); } /*===========================================================================* * * Mhead_GenSequenceHeader * * generate sequence header with given attributes * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenSequenceHeader(bbPtr, hsize, vsize, pratio, pict_rate, bit_rate, buf_size, c_param_flag, iq_matrix, niq_matrix, ext_data, ext_data_size, user_data, user_data_size) BitBucket *bbPtr; uint32 hsize; uint32 vsize; int32 pratio; int32 pict_rate; int32 bit_rate; int32 buf_size; int32 c_param_flag; int32 *iq_matrix; int32 *niq_matrix; uint8 *ext_data; int32 ext_data_size; uint8 *user_data; int32 user_data_size; { extern int ZAG[]; int i; /* Write seq start code. */ Bitio_Write(bbPtr, SEQ_HEAD_CODE, 32); /* Write horiz. and vert. sizes. */ #ifdef BLEAH fprintf(stdout, "hsize, vsize = %d, %d\n", hsize, vsize); #endif if (hsize==0 || vsize==0) { fprintf(stderr, "Writing zero size to stream!\n"); } Bitio_Write(bbPtr, hsize, 12); Bitio_Write(bbPtr, vsize, 12); /* Write pixel aspect ratio, negative values default to 1. */ if (pratio < 0) { fprintf(stderr, "PROGRAMMER ERROR: pratio = %d\n", pratio); exit(1); } Bitio_Write(bbPtr, pratio, 4); /* Wrtie picture rate, negative values default to 30 fps. */ if (pict_rate < 0) { fprintf(stderr, "PROGRAMMER ERROR: pict_rate = %d\n", pict_rate); exit(1); } Bitio_Write(bbPtr, pict_rate, 4); /* Write bit rate, negative values default to variable. */ if (bit_rate < 0) { bit_rate = -1; } else { bit_rate = bit_rate / 400; } Bitio_Write(bbPtr, bit_rate, 18); /* Marker bit. */ Bitio_Write(bbPtr, 0x1, 1); /* Write VBV buffer size. Negative values default to zero. */ if (buf_size < 0) { buf_size = 0; } buf_size = (buf_size + (16*1024 - 1)) / (16*1024); if (buf_size>=0x400) buf_size=0x3ff; Bitio_Write(bbPtr, buf_size, 10); /* Write constrained parameter flag. */ { int num_mb = ((hsize+15)/16) * ((vsize+15)/16); /* At present we cheat on buffer size */ c_param_flag = ((bit_rate <= 4640) && (bit_rate >0) && (buf_size <= 20) && (pict_rate >= 1) && (pict_rate <= 5) && (hsize <= 768) && (vsize <= 576) && (num_mb <= 396) && (num_mb*VidRateNum[pict_rate] <= 9900) && (fCodeP<=4) && (fCodeB<=4)); } if (c_param_flag) { Bitio_Write(bbPtr, 0x01, 1); } else { Bitio_Write(bbPtr, 0x00, 1); } /* Write intra quant matrix if present. */ if (iq_matrix != NULL) { Bitio_Write(bbPtr, 0x01, 1); for (i = 0; i < 64; i++) { Bitio_Write(bbPtr, iq_matrix[ZAG[i]], 8); } } else { Bitio_Write(bbPtr, 0x00, 1); } /* Write non intra quant matrix if present. */ if (niq_matrix != NULL) { Bitio_Write(bbPtr, 0x01, 1); for (i = 0; i < 64; i++) { Bitio_Write(bbPtr, niq_matrix[ZAG[i]], 8); } } else { Bitio_Write(bbPtr, 0x00, 1); } /* next start code */ Bitio_BytePad(bbPtr); /* Write ext data if present. */ if (ext_data != NULL) { Bitio_Write(bbPtr, EXT_START_CODE, 32); for (i = 0; i < ext_data_size; i++) { Bitio_Write(bbPtr, ext_data[i], 8); } Bitio_BytePad(bbPtr); } /* Write user data if present. */ if ((user_data != NULL) && (user_data_size != 0)) { Bitio_Write(bbPtr, USER_START_CODE, 32); for (i = 0; i < user_data_size; i++) { Bitio_Write(bbPtr, user_data[i], 8); } Bitio_BytePad(bbPtr); } } /*===========================================================================* * * Mhead_GenSequenceEnder * * generate sequence ender * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenSequenceEnder(bbPtr) BitBucket *bbPtr; { Bitio_Write(bbPtr, SEQ_END_CODE, 32); } /*===========================================================================* * * Mhead_GenGOPHeader * * generate GOP header with specified attributes * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenGOPHeader(bbPtr, drop_frame_flag, tc_hrs, tc_min, tc_sec, tc_pict, closed_gop, broken_link, ext_data, ext_data_size, user_data, user_data_size) BitBucket *bbPtr; int32 drop_frame_flag; int32 tc_hrs; int32 tc_min; int32 tc_sec; int32 tc_pict; int32 closed_gop; int32 broken_link; uint8 *ext_data; int32 ext_data_size; uint8 *user_data; int32 user_data_size; { int i; /* Write gop start code. */ Bitio_Write(bbPtr, GOP_START_CODE, 32); /* Construct and write timecode. */ /* Drop frame flag. */ if (drop_frame_flag) { Bitio_Write(bbPtr, 0x01, 1); } else { Bitio_Write(bbPtr, 0x00, 1); } /* Time code hours. */ Bitio_Write(bbPtr, tc_hrs, 5); /* Time code minutes. */ Bitio_Write(bbPtr, tc_min, 6); /* Marker bit. */ Bitio_Write(bbPtr, 0x01, 1); /* Time code seconds. */ Bitio_Write(bbPtr, tc_sec, 6); /* Time code pictures. */ Bitio_Write(bbPtr, tc_pict, 6); /* Closed gop flag. */ if (closed_gop) { Bitio_Write(bbPtr, 0x01, 1); } else { Bitio_Write(bbPtr, 0x00, 1); } /* Broken link flag. */ if (broken_link) { Bitio_Write(bbPtr, 0x01, 1); } else { Bitio_Write(bbPtr, 0x00, 1); } /* next start code */ Bitio_BytePad(bbPtr); /* Write ext data if present. */ if (ext_data != NULL) { Bitio_Write(bbPtr, EXT_START_CODE, 32); for (i = 0; i < ext_data_size; i++) { Bitio_Write(bbPtr, ext_data[i], 8); } Bitio_BytePad(bbPtr); } /* Write user data if present. */ if (user_data != NULL) { Bitio_Write(bbPtr, USER_START_CODE, 32); for (i = 0; i < user_data_size; i++) { Bitio_Write(bbPtr, user_data[i], 8); } Bitio_BytePad(bbPtr); } } /*===========================================================================* * * Mhead_GenSliceHeader * * generate slice header with specified attributes * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenSliceHeader(bbPtr, verticalPos, qscale, extra_info, extra_info_size) BitBucket *bbPtr; uint32 verticalPos; uint32 qscale; uint8 *extra_info; uint32 extra_info_size; { int i; /* Write slice start code. */ Bitio_Write(bbPtr, (SLICE_BASE_CODE + verticalPos), 32); /* Quant. scale. */ Bitio_Write(bbPtr, qscale, 5); lastQSSet = qscale; /* Extra bit slice info. */ if (extra_info != NULL) { for (i = 0; i < extra_info_size; i++) { Bitio_Write(bbPtr, 0x01, 1); Bitio_Write(bbPtr, extra_info[i], 8); } } /* extra_bit_slice */ Bitio_Write(bbPtr, 0x00, 1); } /*===========================================================================* * * Mhead_GenSliceEnder * * generate slice ender * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenSliceEnder(bbPtr) BitBucket *bbPtr; { Bitio_BytePad(bbPtr); } /*===========================================================================* * * Mhead_GenMBHeader * * generate macroblock header with given attributes * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void Mhead_GenMBHeader(bbPtr, pict_code_type, addr_incr, q_scale, forw_f_code, back_f_code, horiz_forw_r, vert_forw_r, horiz_back_r, vert_back_r, motion_forw, m_horiz_forw, m_vert_forw, motion_back, m_horiz_back, m_vert_back, mb_pattern, mb_intra) BitBucket *bbPtr; uint32 pict_code_type; uint32 addr_incr; uint32 q_scale; uint32 forw_f_code; uint32 back_f_code; uint32 horiz_forw_r; uint32 vert_forw_r; uint32 horiz_back_r; uint32 vert_back_r; int32 motion_forw; int32 m_horiz_forw; int32 m_vert_forw; int32 motion_back; int32 m_horiz_back; int32 m_vert_back; uint32 mb_pattern; uint32 mb_intra; { uint32 mb_quant; /* MB escape sequences if necessary. */ #ifdef BLEAH if ( addr_incr != 1 ) fprintf(stdout, "Creating MB_INCR: %d\n", addr_incr); #endif while (addr_incr > 33) { Bitio_Write(bbPtr, 0x008, 11); addr_incr -= 33; } /* Generate addr incr code. */ GenMBAddrIncr(bbPtr, addr_incr); /* Determine mb_quant (true if change in q scale) */ if ((q_scale != lastQSSet) && ((mb_pattern != 0) || (mb_intra == TRUE))) { mb_quant = TRUE; lastQSSet = q_scale; } else { mb_quant = FALSE; } /* Generate mb type code. */ GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, mb_pattern, mb_intra); /* MB quant. */ if (mb_quant) { Bitio_Write(bbPtr, q_scale, 5); } /* Forward predictive vector stuff. */ if (motion_forw) { int forw_f, forw_r_size; forw_r_size = forw_f_code - 1; forw_f = 1 << forw_r_size; /* 1 > 0 */ if ((m_horiz_forw > 16*forw_f-1) || (m_horiz_forw < -16*forw_f)) { fprintf(stderr, "Illegal motion? %d %d\n", m_horiz_forw, 16*forw_f); } if ((m_vert_forw > 16*forw_f-1) || (m_vert_forw < -16*forw_f)) { fprintf(stderr, "Illegal motion? %d %d\n", m_vert_forw, 16*forw_f); } GenMotionCode(bbPtr, m_horiz_forw); if ((forw_f != 1) && (m_horiz_forw != 0)) { Bitio_Write(bbPtr, horiz_forw_r, forw_r_size); } GenMotionCode(bbPtr, m_vert_forw); if ((forw_f != 1) && (m_vert_forw != 0)) { Bitio_Write(bbPtr, vert_forw_r, forw_r_size); } } /* Back predicted vector stuff. */ if (motion_back) { int back_f, back_r_size; back_r_size = back_f_code - 1; back_f = 1 << back_r_size; /* 1 > 0 */ if ((m_horiz_back > 16*back_f-1) || (m_horiz_back < -16*back_f)) { fprintf(stderr, "Illegal motion? %d %d\n", m_horiz_back, 16*back_f); } if ((m_vert_back > 16*back_f-1) || (m_vert_back < -16*back_f)) { fprintf(stderr, "Illegal motion? %d %d\n", m_vert_back, 16*back_f); } GenMotionCode(bbPtr, m_horiz_back); if ((back_f != 1) && (m_horiz_back != 0)) { Bitio_Write(bbPtr, horiz_back_r, back_r_size); } GenMotionCode(bbPtr, m_vert_back); if ((back_f != 1) && (m_vert_back != 0)) { Bitio_Write(bbPtr, vert_back_r, back_r_size); } } /* MB pattern. */ if (mb_pattern) { GenBlockPattern(bbPtr, mb_pattern); } } /*=====================* * INTERNAL PROCEDURES * *=====================*/ /*===========================================================================* * * GenMBType * * generate macroblock type with given attributes * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ static void GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, mb_pattern, mb_intra) BitBucket *bbPtr; uint32 pict_code_type; uint32 mb_quant; uint32 motion_forw; uint32 motion_back; uint32 mb_pattern; uint32 mb_intra; { int code; switch (pict_code_type) { case 1: if ((motion_forw != 0) || (motion_back != 0) || (mb_pattern != 0) || (mb_intra != 1)) { perror("Illegal parameters for macroblock type."); exit(-1); } if (mb_quant) { Bitio_Write(bbPtr, 0x1, 2); } else { Bitio_Write(bbPtr, 0x1, 1); } break; case 2: code = 0; if (mb_quant) { code += 16; } if (motion_forw) { code += 8; } if (motion_back) { code += 4; } if (mb_pattern) { code += 2; } if (mb_intra) { code += 1; } switch (code) { case 1: Bitio_Write(bbPtr, 0x3, 5); break; case 2: Bitio_Write(bbPtr, 0x1, 2); break; case 8: Bitio_Write(bbPtr, 0x1, 3); break; case 10: Bitio_Write(bbPtr, 0x1, 1); break; case 17: Bitio_Write(bbPtr, 0x1, 6); break; case 18: Bitio_Write(bbPtr, 0x1, 5); break; case 26: Bitio_Write(bbPtr, 0x2, 5); break; default: perror("Illegal parameters for macroblock type."); exit(-1); break; } break; case 3: code = 0; if (mb_quant) { code += 16; } if (motion_forw) { code += 8; } if (motion_back) { code += 4; } if (mb_pattern) { code += 2; } if (mb_intra) { code += 1; } switch (code) { case 12: Bitio_Write(bbPtr, 0x2, 2); break; case 14: Bitio_Write(bbPtr, 0x3, 2); break; case 4: Bitio_Write(bbPtr, 0x2, 3); break; case 6: Bitio_Write(bbPtr, 0x3, 3); break; case 8: Bitio_Write(bbPtr, 0x2, 4); break; case 10: Bitio_Write(bbPtr, 0x3, 4); break; case 1: Bitio_Write(bbPtr, 0x3, 5); break; case 30: Bitio_Write(bbPtr, 0x2, 5); break; case 26: Bitio_Write(bbPtr, 0x3, 6); break; case 22: Bitio_Write(bbPtr, 0x2, 6); break; case 17: Bitio_Write(bbPtr, 0x1, 6); break; default: perror("Illegal parameters for macroblock type."); exit(-1); break; } break; } } /*===========================================================================* * * GenMotionCode * * generate motion vector output with given value * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ static void GenMotionCode(bbPtr, vector) BitBucket *bbPtr; int32 vector; { uint32 code, num; if ((vector < -16) || (vector > 16)) { perror("Motion vector out of range."); fprintf(stderr, "Motion vector out of range: vector = %d\n", vector); exit(-1); } code = mbMotionVectorTable[vector + 16][0]; num = mbMotionVectorTable[vector + 16][1]; Bitio_Write(bbPtr, code, num); } /*===========================================================================* * * GenBlockPattern * * generate macroblock pattern output * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ static void GenBlockPattern(bbPtr, mb_pattern) BitBucket *bbPtr; uint32 mb_pattern; { uint32 code, num; code = mbPatTable[mb_pattern][0]; num = mbPatTable[mb_pattern][1]; Bitio_Write(bbPtr, code, num); } /*===========================================================================* * * GenMBAddrIncr * * generate macroblock address increment output * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ static void GenMBAddrIncr(bbPtr, addr_incr) BitBucket *bbPtr; uint32 addr_incr; { uint32 code; uint32 num; code = mbAddrIncrTable[addr_incr][0]; num = mbAddrIncrTable[addr_incr][1]; Bitio_Write(bbPtr, code, num); } /*===========================================================================* * * GenPictHead * * generate picture header with given attributes * append result to the specified bitstream * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ static void GenPictHead(bbPtr, temp_ref, code_type, vbv_delay, full_pel_forw_flag, forw_f_code, full_pel_back_flag, back_f_code, extra_info, extra_info_size, ext_data, ext_data_size, user_data, user_data_size) BitBucket *bbPtr; uint32 temp_ref; uint32 code_type; uint32 vbv_delay; int32 full_pel_forw_flag; uint32 forw_f_code; int32 full_pel_back_flag; uint32 back_f_code; uint8 *extra_info; uint32 extra_info_size; uint8 *ext_data; uint32 ext_data_size; uint8 *user_data; uint32 user_data_size; { int i; /* Write picture start code. */ Bitio_Write(bbPtr, PICT_START_CODE, 32); /* Temp reference. */ Bitio_Write(bbPtr, temp_ref, 10); /* Code_type. */ if (code_type == 0) { code_type = 1; } Bitio_Write(bbPtr, code_type, 3); /* vbv_delay. */ vbv_delay = 0xffff; /* see page 36 (section 2.4.3.4) */ Bitio_Write(bbPtr, vbv_delay, 16); if ((code_type == 2) || (code_type == 3)) { /* Full pel forw flag. */ if (full_pel_forw_flag) { Bitio_Write(bbPtr, 0x01, 1); } else { Bitio_Write(bbPtr, 0x00, 1); } /* Forw f code. */ Bitio_Write(bbPtr, forw_f_code, 3); } if (code_type == 3) { /* Full pel back flag. */ if (full_pel_back_flag) { Bitio_Write(bbPtr, 0x01, 1); } else { Bitio_Write(bbPtr, 0x00, 1); } /* Back f code. */ Bitio_Write(bbPtr, back_f_code, 3); } /* Extra bit picture info. */ if (extra_info != NULL) { for (i = 0; i < extra_info_size; i++) { Bitio_Write(bbPtr, 0x01, 1); Bitio_Write(bbPtr, extra_info[i], 8); } } Bitio_Write(bbPtr, 0x00, 1); /* next start code */ Bitio_BytePad(bbPtr); /* Write ext data if present. */ if (ext_data != NULL) { Bitio_Write(bbPtr, EXT_START_CODE, 32); for (i = 0; i < ext_data_size; i++) { Bitio_Write(bbPtr, ext_data[i], 8); } Bitio_BytePad(bbPtr); } /* Write user data if present. */ if (user_data != NULL) { Bitio_Write(bbPtr, USER_START_CODE, 32); for (i = 0; i < user_data_size; i++) { Bitio_Write(bbPtr, user_data[i], 8); } Bitio_BytePad(bbPtr); } } #ifdef UNUSED_PROCEDURES /* GenMBEnd only used for `D` pictures. Shouldn't really ever be called. */ /* - dwallach */ void GenMBEnd(bbPtr) BitBucket *bbPtr; { Bitio_Write(bbPtr, 0x01, 1); } #endif /* UNUSED_PROCEDURES */