--- bitstream.c 2002/12/14 09:39:42 1.28.2.11 +++ bitstream.c 2003/07/28 12:36:29 1.41 @@ -41,8 +41,8 @@ * * * Revision history: * * * - * 28.10.2002 GMC support - gruel * - * 04.10.2002 qpel support - Isibaar * + * 05.01.2003 GMC support - gruel * + * 04.10.2002 qpel support - Isibaar * * 11.07.2002 add VOP width & height return to dec when dec->width * * or dec->height is 0 (for use in examples/ex1.c) * * MinChen * @@ -173,7 +173,7 @@ if (dec->shape != VIDOBJLAY_SHAPE_BINARY_ONLY) { - *quant = BitstreamGetBits(bs, 5); /* quant_scale */ + *quant = BitstreamGetBits(bs, dec->quant_bits); /* quant_scale */ DPRINTF(DPRINTF_HEADER, "quant %i", *quant); } @@ -230,7 +230,7 @@ if (coding_type == B_VOP && fcode_backward) { *fcode_backward = BitstreamGetBits(bs, 3); - DPRINTF(DPRINTF_HEADER,"fcode_backward %i", fcode_backward); + DPRINTF(DPRINTF_HEADER,"fcode_backward %i", *fcode_backward); } } @@ -326,7 +326,7 @@ { ESTIMATION * e = &dec->estimation; - if (e->method == 0) + if (e->method == 0 || e->method == 1) { if (coding_type == I_VOP) { if (e->opaque) BitstreamSkip(bs, 8); /* dcecs_opaque */ @@ -432,13 +432,13 @@ uint32_t * fcode_forward, uint32_t * fcode_backward, uint32_t * intra_dc_threshold, - VECTOR * gmc_mv) + WARPPOINTS *gmc_warp) { uint32_t vol_ver_id; uint32_t coding_type; uint32_t start_code; uint32_t time_incr = 0; - int32_t time_increment; + int32_t time_increment = 0; int resize = 0; do { @@ -464,17 +464,18 @@ DPRINTF(DPRINTF_STARTCODE, ""); } else if (start_code == VISOBJ_START_CODE) { + int visobj_ver_id; DPRINTF(DPRINTF_STARTCODE, ""); BitstreamSkip(bs, 32); // visual_object_start_code if (BitstreamGetBit(bs)) // is_visual_object_identified { - vol_ver_id = BitstreamGetBits(bs, 4); // visual_object_ver_id - DPRINTF(DPRINTF_HEADER,"ver_id %i", vol_ver_id); + visobj_ver_id = BitstreamGetBits(bs, 4); // visual_object_ver_id + DPRINTF(DPRINTF_HEADER,"visobj_ver_id %i", visobj_ver_id); BitstreamSkip(bs, 3); // visual_object_priority } else { - vol_ver_id = 1; + visobj_ver_id = 1; } if (BitstreamShowBits(bs, 4) != VISOBJ_TYPE_VIDEO) // visual_object_type @@ -557,18 +558,29 @@ DPRINTF(DPRINTF_HEADER, "low_delay %i", dec->low_delay); if (BitstreamGetBit(bs)) // vbv_parameters { + unsigned int bitrate; + unsigned int buffer_size; + unsigned int occupancy; + DPRINTF(DPRINTF_HEADER,"+ vbv_parameters"); - BitstreamSkip(bs, 15); // first_half_bitrate + + bitrate = BitstreamGetBits(bs,15) << 15; // first_half_bit_rate READ_MARKER(); - BitstreamSkip(bs, 15); // latter_half_bitrate + bitrate |= BitstreamGetBits(bs,15); // latter_half_bit_rate READ_MARKER(); - BitstreamSkip(bs, 15); // first_half_vbv_buffer_size + + buffer_size = BitstreamGetBits(bs, 15) << 3; // first_half_vbv_buffer_size READ_MARKER(); - BitstreamSkip(bs, 3); // latter_half_vbv_buffer_size - BitstreamSkip(bs, 11); // first_half_vbv_occupancy + buffer_size |= BitstreamGetBits(bs, 3); // latter_half_vbv_buffer_size + + occupancy = BitstreamGetBits(bs, 11) << 15; // first_half_vbv_occupancy READ_MARKER(); - BitstreamSkip(bs, 15); // latter_half_vbv_occupancy + occupancy |= BitstreamGetBits(bs, 15); // latter_half_vbv_occupancy READ_MARKER(); + + DPRINTF(DPRINTF_HEADER,"bitrate %d (unit=400 bps)", bitrate); + DPRINTF(DPRINTF_HEADER,"buffer_size %d (unit=16384 bits)", buffer_size); + DPRINTF(DPRINTF_HEADER,"occupancy %d (unit=64 bits)", occupancy); } }else{ dec->low_delay = dec->low_delay_default; @@ -826,7 +838,7 @@ READ_MARKER(); seconds = BitstreamGetBits(bs, 6); - DPRINTF(DPRINTF_HEADER, "time %ih%im%is", hours); + DPRINTF(DPRINTF_HEADER, "time %ih%im%is", hours,minutes,seconds); } BitstreamSkip(bs, 1); // closed_gov BitstreamSkip(bs, 1); // broken_link @@ -1000,8 +1012,8 @@ } READ_MARKER(); - gmc_mv[i].x = x; - gmc_mv[i].y = y; + gmc_warp->duv[i].x = x; + gmc_warp->duv[i].y = y; DPRINTF(DPRINTF_HEADER,"sprite_warping_point[%i] xy=(%i,%i)", i, x, y); } @@ -1057,6 +1069,12 @@ } DPRINTF(DPRINTF_STARTCODE, ": %s\n", tmp); + + /* read xvid bitstream version */ + if(strncmp(tmp, "XviD", 4) == 0) { + sscanf(tmp, "XviD%d", &dec->bs_version); + DPRINTF(DPRINTF_HEADER, "xvid bitstream version=%i", dec->bs_version); + } /* divx detection */ i = sscanf(tmp, "DivX%dBuild%d%c", &version, &build, &packed); @@ -1114,20 +1132,45 @@ const MBParam * pParam, const FRAMEINFO * const frame) { + static const unsigned int vo_id = 0; + static const unsigned int vol_id = 0; int vol_ver_id=1; + int profile = 0x03; /* simple profile/level 3 */ if ( pParam->m_quarterpel || (frame->global_flags & XVID_GMC) || (pParam->global & XVID_GLOBAL_REDUCED)) vol_ver_id = 2; - - // video object_start_code & vo_id + + if ((pParam->global & XVID_GLOBAL_REDUCED)) + profile = 0x93; /* advanced realtime simple profile/level 3 */ + + if (pParam->m_quarterpel || (frame->global_flags & XVID_GMC)) + profile = 0xf3; /* advanced simple profile/level 2 */ + + // visual_object_sequence_start_code +// BitstreamPad(bs); +/* no padding here, anymore. You have to make sure that you are + byte aligned, and that always 1-8 padding bits have been written */ + + BitstreamPutBits(bs, VISOBJSEQ_START_CODE, 32); + BitstreamPutBits(bs, profile, 8); + + // visual_object_start_code BitstreamPad(bs); - BitstreamPutBits(bs, VO_START_CODE, 27); - BitstreamPutBits(bs, 0, 5); + BitstreamPutBits(bs, VISOBJ_START_CODE, 32); + BitstreamPutBits(bs, 0, 1); // is_visual_object_identifier + + /* Video type */ + BitstreamPutBits(bs, VISOBJ_TYPE_VIDEO, 4); // visual_object_type + BitstreamPutBit(bs, 0); /* video_signal_type */ + + // video object_start_code & vo_id + BitstreamPadAlways(bs); // next_start_code() + BitstreamPutBits(bs, VIDOBJ_START_CODE|(vo_id&0x5), 32); // video_object_layer_start_code & vol_id - BitstreamPutBits(bs, VOL_START_CODE, 28); - BitstreamPutBits(bs, 0, 4); + BitstreamPad(bs); + BitstreamPutBits(bs, VIDOBJLAY_START_CODE|(vol_id&0x4), 32); BitstreamPutBit(bs, 0); // random_accessible_vol BitstreamPutBits(bs, 0, 8); // video_object_type_indication @@ -1140,7 +1183,7 @@ { BitstreamPutBit(bs, 1); // is_object_layer_identified BitstreamPutBits(bs, vol_ver_id, 4); // vol_ver_id == 2 - BitstreamPutBits(bs, 4, 3); // vol_ver_priority (1==lowest, 7==highest) ?? + BitstreamPutBits(bs, 4, 3); // vol_ver_priority (1==highest, 7==lowest) } BitstreamPutBits(bs, 1, 4); // aspect_ratio_info (1=1:1) @@ -1236,6 +1279,17 @@ BitstreamPutBit(bs, 0); // scalability + BitstreamPadAlways(bs); // next_start_code() + + /* fake divx5 id, to ensure compatibility with divx5 decoder */ +#define DIVX5_ID "DivX501b481p" + if (pParam->max_bframes > 0 && (pParam->global & XVID_GLOBAL_PACKED)) { + BitstreamWriteUserData(bs, DIVX5_ID, strlen(DIVX5_ID)); + } + + /* xvid id */ +#define XVID_ID "XviD" XVID_BS_VERSION + BitstreamWriteUserData(bs, XVID_ID, strlen(XVID_ID)); } @@ -1251,7 +1305,10 @@ { uint32_t i; - BitstreamPad(bs); +// BitstreamPad(bs); +/* no padding here, anymore. You have to make sure that you are + byte aligned, and that always 1-8 padding bits have been written */ + BitstreamPutBits(bs, VOP_START_CODE, 32); BitstreamPutBits(bs, frame->coding_type, 2); @@ -1275,6 +1332,14 @@ if (!vop_coded) { BitstreamPutBits(bs, 0, 1); +#if 0 + BitstreamPadAlways(bs); /* next_start_code() */ +#endif + /* NB: It's up to the function caller to write the next_start_code(). + * At the moment encoder.c respects that requisite because a VOP + * always ends with a next_start_code either if it's coded or not + * and encoder.c terminates a frame with a next_start_code in whatever + * case */ return; } @@ -1294,39 +1359,26 @@ } if (frame->coding_type == S_VOP) { - if (1) { // no_of_sprite_warping_points>=1 - if (pParam->m_quarterpel) - bs_put_spritetrajectory(bs, frame->GMC_MV.x/2 ); // du[0] - else - bs_put_spritetrajectory(bs, frame->GMC_MV.x ); // du[0] - WRITE_MARKER(); + if (1) { // no_of_sprite_warping_points>=1 (we use 2!) + int k; + for (k=0;k<2;k++) + { + bs_put_spritetrajectory(bs, frame->warp.duv[k].x ); // du[k] + WRITE_MARKER(); - if (pParam->m_quarterpel) - bs_put_spritetrajectory(bs, frame->GMC_MV.y/2 ); // dv[0] - else - bs_put_spritetrajectory(bs, frame->GMC_MV.y ); // dv[0] - WRITE_MARKER(); - + bs_put_spritetrajectory(bs, frame->warp.duv[k].y ); // dv[k] + WRITE_MARKER(); if (pParam->m_quarterpel) { - DPRINTF(DPRINTF_HEADER,"sprite_warping_point[%i] xy=(%i,%i) *QPEL*", 0, frame->GMC_MV.x/2, frame->GMC_MV.y/2); + DPRINTF(DPRINTF_HEADER,"sprite_warping_point[%i] xy=(%i,%i) *QPEL*", k, frame->warp.duv[k].x/2, frame->warp.duv[k].y/2); } else { - DPRINTF(DPRINTF_HEADER,"sprite_warping_point[%i] xy=(%i,%i)", 0, frame->GMC_MV.x, frame->GMC_MV.y); + DPRINTF(DPRINTF_HEADER,"sprite_warping_point[%i] xy=(%i,%i)", k, frame->warp.duv[k].x, frame->warp.duv[k].y); + } } - - } -/* GMC is halfpel in bitstream, even though GMC_MV was pseudo-qpel (2*halfpel) */ - - if (2) { // no_of_sprite_warping_points>=2 (for DivX5 compat) - bs_put_spritetrajectory(bs, 0 ); - WRITE_MARKER(); - bs_put_spritetrajectory(bs, 0 ); - WRITE_MARKER(); } - // no support for brightness_change! }