blob: f18f789b99750bf053bd22419c7434b53719f2f5 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "log/log.h"
#include "mp4dec_lib.h"
#include "bitstream.h"
#include "vlc_decode.h"
#include "zigzag.h"
#define OSCL_DISABLE_WARNING_CONV_POSSIBLE_LOSS_OF_DATA
#ifdef PV_SUPPORT_MAIN_PROFILE
/* INTRA */
const static int mpeg_iqmat_def[NCOEFF_BLOCK] =
{
8, 17, 18, 19, 21, 23, 25, 27,
17, 18, 19, 21, 23, 25, 27, 28,
20, 21, 22, 23, 24, 26, 28, 30,
21, 22, 23, 24, 26, 28, 30, 32,
22, 23, 24, 26, 28, 30, 32, 35,
23, 24, 26, 28, 30, 32, 35, 38,
25, 26, 28, 30, 32, 35, 38, 41,
27, 28, 30, 32, 35, 38, 41, 45
};
/* INTER */
const static int mpeg_nqmat_def[64] =
{
16, 17, 18, 19, 20, 21, 22, 23,
17, 18, 19, 20, 21, 22, 23, 24,
18, 19, 20, 21, 22, 23, 24, 25,
19, 20, 21, 22, 23, 24, 26, 27,
20, 21, 22, 23, 25, 26, 27, 28,
21, 22, 23, 24, 26, 27, 28, 30,
22, 23, 24, 26, 27, 28, 30, 31,
23, 24, 25, 27, 28, 30, 31, 33
};
#endif
/* ======================================================================== */
/* Function : CalcNumBits() */
/* Purpose : */
/* In/out : */
/* Return : Calculate the minimum number of bits required to */
/* represent x. */
/* Note : This is an equivalent implementation of */
/* (long)ceil(log((double)x)/log(2.0)) */
/* Modified : */
/* ======================================================================== */
int CalcNumBits(uint x)
{
int i = 1;
while (x >>= 1) i++;
return i;
}
/***********************************************************CommentBegin******
*
* -- DecodeVolHeader -- Decode the header of a VOL
*
* 04/10/2000 : initial modification to the new PV-Decoder Lib format.
* 10/12/2001 : reject non compliant bitstreams
*
***********************************************************CommentEnd********/
PV_STATUS DecodeVOLHeader(VideoDecData *video, int layer)
{
PV_STATUS status;
Vol *currVol;
BitstreamDecVideo *stream;
uint32 tmpvar, vol_shape;
uint32 startCode;
#ifdef PV_SUPPORT_MAIN_PROFILE
int *qmat, i, j;
#endif
int version_id = 1;
#ifdef PV_TOLERATE_VOL_ERRORS
uint32 profile = 0x01;
#endif
/* There's a "currLayer" variable inside videoDecData. */
/* However, we don't maintain it until we decode frame data. 04/05/2000 */
currVol = video->vol[layer];
stream = currVol->bitstream;
currVol->moduloTimeBase = 0;
/* Determine which start code for the decoder to begin with */
status = BitstreamShowBits32HC(stream, &startCode);
if (startCode == VISUAL_OBJECT_SEQUENCE_START_CODE)
{ /* Bitstream Exhchange Fix 9/99 */
/* Bitstream Exchange requires we allow start with Video Object Sequence */
/* visual_object_sequence_start_code */
(void) BitstreamReadBits32HC(stream);
tmpvar = (uint32) BitstreamReadBits16(stream, 8); /* profile */
#ifndef PV_TOLERATE_VOL_ERRORS
if (layer) /* */
{
/* support SSPL0-2 */
if (tmpvar != 0x10 && tmpvar != 0x11 && tmpvar != 0x12 &&
tmpvar != 0xA1 && tmpvar != 0xA2 && tmpvar != 0xA3/* Core SP@L1-L3 */)
return PV_FAIL;
}
else
{
/* support SPL0-3 & SSPL0-2 */
if (tmpvar != 0x01 && tmpvar != 0x02 && tmpvar != 0x03 && tmpvar != 0x08 &&
/* While not technically supported, try to decode SPL4&SPL5 files as well. */
/* We'll fail later if the size is too large. This is to allow playback of */
/* some <=CIF files generated by other encoders. */
tmpvar != 0x04 && tmpvar != 0x05 &&
tmpvar != 0x10 && tmpvar != 0x11 && tmpvar != 0x12 &&
tmpvar != 0x21 && tmpvar != 0x22 && /* Core Profile Levels */
tmpvar != 0xA1 && tmpvar != 0xA2 && tmpvar != 0xA3 &&
tmpvar != 0xF0 && tmpvar != 0xF1 && /* Advanced Simple Profile Levels*/
tmpvar != 0xF2 && tmpvar != 0xF3 &&
tmpvar != 0xF4 && tmpvar != 0xF5)
return PV_FAIL;
}
#else
profile = tmpvar;
#endif
// save the profile and level for the query
currVol->profile_level_id = (uint)tmpvar; // 6/10/04
status = BitstreamShowBits32HC(stream, &tmpvar);
if (tmpvar == USER_DATA_START_CODE)
{
/* Something has to be done with user data 11/11/99 */
status = DecodeUserData(stream);
if (status != PV_SUCCESS) return PV_FAIL;
}
/* visual_object_start_code */
BitstreamShowBits32HC(stream, &tmpvar);
if (tmpvar != VISUAL_OBJECT_START_CODE)
{
do
{
/* Search for VOL_HEADER */
status = PVSearchNextM4VFrame(stream); /* search 0x00 0x00 0x01 */
if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
PV_BitstreamFlushBits(stream, 8);
}
while (tmpvar != VOL_START_CODE);
goto decode_vol;
}
else
{
BitstreamReadBits32HC(stream);
}
/* is_visual_object_identifier */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar)
{
/* visual_object_verid */
tmpvar = (uint32) BitstreamReadBits16(stream, 4);
/* visual_object_priority */
tmpvar = (uint32) BitstreamReadBits16(stream, 3);
}
/* visual_object_type */
BitstreamShowBits32(stream, 4, &tmpvar);
if (tmpvar == 1)
{ /* video_signal_type */
PV_BitstreamFlushBits(stream, 4);
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar == 1)
{
/* video_format */
tmpvar = (uint32) BitstreamReadBits16(stream, 3);
/* video_range */
tmpvar = (uint32) BitstreamRead1Bits(stream);
/* color_description */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar == 1)
{
/* color_primaries */
tmpvar = (uint32) BitstreamReadBits16(stream, 8);
/* transfer_characteristics */
tmpvar = (uint32) BitstreamReadBits16(stream, 8);
/* matrix_coefficients */
tmpvar = (uint32) BitstreamReadBits16(stream, 8);
}
}
}
else
{
do
{
/* Search for VOL_HEADER */
status = PVSearchNextM4VFrame(stream); /* search 0x00 0x00 0x01 */
if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
PV_BitstreamFlushBits(stream, 8);
}
while (tmpvar != VOL_START_CODE);
goto decode_vol;
}
/* next_start_code() */
status = PV_BitstreamByteAlign(stream); /* 10/12/01 */
status = BitstreamShowBits32HC(stream, &tmpvar);
if (tmpvar == USER_DATA_START_CODE)
{
/* Something has to be done to deal with user data (parse it) 11/11/99 */
status = DecodeUserData(stream);
if (status != PV_SUCCESS) return PV_FAIL;
}
status = BitstreamShowBits32(stream, 27, &tmpvar); /* 10/12/01 */
}
else
{
/* tmpvar = 0; */ /* 10/12/01 */
status = BitstreamShowBits32(stream, 27, &tmpvar); /* uncomment this line if you want
to start decoding with a
video_object_start_code */
}
if (tmpvar == VO_START_CODE)
{
/*****
*
* Read the VOL header entries from the bitstream
*
*****/
/* video_object_start_code */
tmpvar = BitstreamReadBits32(stream, 27);
tmpvar = (uint32) BitstreamReadBits16(stream, 5);
/* video_object_layer_start_code */
BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
if (tmpvar != VOL_START_CODE)
{
status = BitstreamCheckEndBuffer(stream);
if (status == PV_END_OF_VOP)
{
video->shortVideoHeader = TRUE;
return PV_SUCCESS;
}
else
{
do
{
/* Search for VOL_HEADER */
status = PVSearchNextM4VFrame(stream);/* search 0x00 0x00 0x01 */
if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
PV_BitstreamFlushBits(stream, 8); /* advance the byte ptr */
}
while (tmpvar != VOL_START_CODE);
}
}
else
{
PV_BitstreamFlushBits(stream, 8);
}
decode_vol:
PV_BitstreamFlushBits(stream, VOL_START_CODE_LENGTH - 8);
video->shortVideoHeader = 0;
/* vol_id (4 bits) */
currVol->volID = (int) BitstreamReadBits16(stream, 4);
/* RandomAccessible flag */
tmpvar = (uint32) BitstreamRead1Bits(stream);
/* object type */
tmpvar = (uint32) BitstreamReadBits16(stream, 8); /* */
#ifdef PV_TOLERATE_VOL_ERRORS
if (tmpvar == 0)
{
if (layer) /* */
{
/* support SSPL0-2 */
if (profile != 0x10 && profile != 0x11 && profile != 0x12)
return PV_FAIL;
tmpvar = 0x02;
}
else
{
/* support SPL0-3 & SSPL0-2 */
if (profile != 0x01 && profile != 0x02 && profile != 0x03 && profile != 0x08 &&
profile != 0x10 && profile != 0x11 && profile != 0x12)
return PV_FAIL;
tmpvar = 0x01;
}
profile |= 0x0100;
}
#endif
if (layer)
{
if (tmpvar != 0x02) return PV_FAIL;
}
else
{
if (tmpvar != 0x01) return PV_FAIL;
}
/* version id specified? */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar == 1)
{
/* version ID */
version_id = (uint32) BitstreamReadBits16(stream, 4);
/* priority */
tmpvar = (uint32) BitstreamReadBits16(stream, 3);
}
/* aspect ratio info */
tmpvar = (uint32) BitstreamReadBits16(stream, 4);
if (tmpvar == 0) return PV_FAIL;
if (tmpvar == 0xf /* extended_par */)
{
/* width */
tmpvar = (uint32) BitstreamReadBits16(stream, 8);
/* height */
tmpvar = (uint32) BitstreamReadBits16(stream, 8);
}
/* control parameters present? */
tmpvar = (uint32) BitstreamRead1Bits(stream);
/* Get the parameters (skipped) */
/* 03/10/99 */
if (tmpvar)
{
/* chroma_format */
tmpvar = BitstreamReadBits16(stream, 2);
if (tmpvar != 1) return PV_FAIL;
/* low_delay */
tmpvar = BitstreamRead1Bits(stream);
/* vbv_parameters present? */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar)
{
/* first_half_bit_rate */
BitstreamReadBits16(stream, 15);
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* latter_half_bit_rate */
BitstreamReadBits16(stream, 15);
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* first_half_vbv_buffer_size */
BitstreamReadBits16(stream, 15);
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* latter_half_vbv_buffer_size */
BitstreamReadBits16(stream, 3);
/* first_half_vbv_occupancy */
BitstreamReadBits16(stream, 11);
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* latter_half_vbv_occupancy */
BitstreamReadBits16(stream, 15);
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
}
}
/* video_object_layer_shape (2 bits), only 00 (rect) is supported for now */
vol_shape = (uint32) BitstreamReadBits16(stream, 2);
if (vol_shape) return PV_FAIL;
/* marker bit, 03/10/99 */
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* vop_time_increment_resolution */
currVol->timeIncrementResolution = BitstreamReadBits16(stream, 16);
if (currVol->timeIncrementResolution == 0) return PV_FAIL;
/* . since nbitsTimeIncRes will be used over and over again, */
/* we should put it in Vol structure. 04/12/2000. */
currVol->nbitsTimeIncRes = CalcNumBits((uint)currVol->timeIncrementResolution - 1);
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* fixed_vop_rate */
currVol->fixedVopRate = (int) BitstreamRead1Bits(stream);
if (currVol->fixedVopRate)
{
/* fixed_vop_time_increment */
tmpvar = BitstreamReadBits16(stream, currVol->nbitsTimeIncRes);
}
/* marker bit */
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* video_object_layer_width (13 bits) */
video->displayWidth = video->width = (int) BitstreamReadBits16(stream, 13);
/* round up to a multiple of MB_SIZE. 08/09/2000 */
video->width = (video->width + 15) & -16;
// video->displayWidth += (video->displayWidth & 0x1); /* displayed image should be even size */
/* marker bit */
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* video_object_layer_height (13 bits) */
video->displayHeight = video->height = (int) BitstreamReadBits16(stream, 13);
/* round up to a multiple of MB_SIZE. 08/09/2000 */
video->height = (video->height + 15) & -16;
// video->displayHeight += (video->displayHeight & 0x1); /* displayed image should be even size */
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* 03/10/99 */
/* interlaced */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar != 0)
{
mp4dec_log("DecodeVOLHeader(): Interlaced video is not supported.\n");
return PV_FAIL;
}
/* obmc_disable */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar == 0) return PV_FAIL;
if (version_id == 1)
{
/* sprite_enable (1 bits) */
tmpvar = (uint32) BitstreamRead1Bits(stream);
if (tmpvar)
{
mp4dec_log("DecodeVOLHeader(): Sprite is not supported.\n");
return PV_FAIL;
}
}
else
{
/* For version 2, vol_sprite_usage has two bits. */
/* sprite_enable */
tmpvar = (uint32) BitstreamReadBits16(stream, 2);
if (tmpvar)
{
mp4dec_log("DecodeVOLHeader(): Sprite is not supported.\n");
return PV_FAIL;
}
}
/* not_8_bit */
if (BitstreamRead1Bits(stream))
{
/* quant_precision */
currVol->quantPrecision = BitstreamReadBits16(stream, 4);
/* bits_per_pixel */
currVol->bitsPerPixel = BitstreamReadBits16(stream, 4);
mp4dec_log("DecodeVOLHeader(): not an 8-bit stream.\n"); // For the time being we do not support != 8 bits
return PV_FAIL;
}
else
{
currVol->quantPrecision = 5;
currVol->bitsPerPixel = 8;
}
/* quant_type (1 bit) */
currVol->quantType = BitstreamRead1Bits(stream);
if (currVol->quantType)
{
#ifdef PV_SUPPORT_MAIN_PROFILE
/* load quantization matrices. 5/22/2000 */
/* load_intra_quant_mat (1 bit) */
qmat = currVol->iqmat;
currVol->loadIntraQuantMat = BitstreamRead1Bits(stream);
if (currVol->loadIntraQuantMat)
{
/* intra_quant_mat (8*64 bits) */
i = 0;
do
{
qmat[*(zigzag_inv+i)] = (int) BitstreamReadBits16(stream, 8);
}
while ((qmat[*(zigzag_inv+i)] != 0) && (++i < 64));
for (j = i; j < 64; j++)
qmat[*(zigzag_inv+j)] = qmat[*(zigzag_inv+i-1)];
}
else
{
oscl_memcpy(qmat, mpeg_iqmat_def, 64*sizeof(int));
}
qmat[0] = 0; /* necessary for switched && MPEG quant 07/09/01 */
/* load_nonintra_quant_mat (1 bit) */
qmat = currVol->niqmat;
currVol->loadNonIntraQuantMat = BitstreamRead1Bits(stream);
if (currVol->loadNonIntraQuantMat)
{
/* nonintra_quant_mat (8*64 bits) */
i = 0;
do
{
qmat[*(zigzag_inv+i)] = (int) BitstreamReadBits16(stream, 8);
}
while ((qmat[*(zigzag_inv+i)] != 0) && (++i < 64));
for (j = i; j < 64; j++)
qmat[*(zigzag_inv+j)] = qmat[*(zigzag_inv+i-1)];
}
else
{
oscl_memcpy(qmat, mpeg_nqmat_def, 64*sizeof(int));
}
#else
return PV_FAIL;
#endif
}
if (version_id != 1)
{
/* quarter_sample enabled */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar) return PV_FAIL;
}
/* complexity_estimation_disable */
currVol->complexity_estDisable = BitstreamRead1Bits(stream);
if (currVol->complexity_estDisable == 0)
{
currVol->complexity_estMethod = BitstreamReadBits16(stream, 2);
if (currVol->complexity_estMethod < 2)
{
/* shape_complexity_estimation_disable */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar == 0)
{
mp4dec_log("DecodeVOLHeader(): Shape Complexity estimation is not supported.\n");
return PV_FAIL;
}
/* texture_complexity_estimation_set_1_disable */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar == 0)
{
currVol->complexity.text_1 = BitstreamReadBits16(stream, 4);
}
/* marker bit */
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
/* texture_complexity_estimation_set_2_disable */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar == 0)
{
currVol->complexity.text_2 = BitstreamReadBits16(stream, 4);
}
/* motion_compensation_complexity_disable */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar == 0)
{
currVol->complexity.mc = BitstreamReadBits16(stream, 6);
}
/* marker bit */
if (!BitstreamRead1Bits(stream)) return PV_FAIL;
if (currVol->complexity_estMethod == 1)
{ /* version2_complexity_estimation_disable */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar == 0)
{
mp4dec_log("DecodeVOLHeader(): sadct, quarter pel not supported.\n");
return PV_FAIL;
}
}
}
}
/* 03/10/99 */
/* resync_marker_disable */
currVol->errorResDisable = (int) BitstreamRead1Bits(stream);
/* data_partititioned */
currVol->dataPartitioning = (int) BitstreamRead1Bits(stream);
video->vlcDecCoeffIntra = &VlcDecTCOEFIntra;
video->vlcDecCoeffInter = &VlcDecTCOEFInter;
if (currVol->dataPartitioning)
{
if (layer) return PV_FAIL; /* */
/* reversible_vlc */
currVol->useReverseVLC = (int)BitstreamRead1Bits(stream);
if (currVol->useReverseVLC)
{
video->vlcDecCoeffIntra = &RvlcDecTCOEFIntra;
video->vlcDecCoeffInter = &RvlcDecTCOEFInter;
}
currVol->errorResDisable = 0;
}
else
{
currVol->useReverseVLC = 0;
}
if (version_id != 1)
{
/* newpred_enable */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar) return PV_FAIL;
/* reduced_resolution_vop */
tmpvar = BitstreamRead1Bits(stream);
if (tmpvar) return PV_FAIL;
}
/* Intra AC/DC prediction is always true */
video->intra_acdcPredDisable = 0;
/* scalability */
currVol->scalability = (int) BitstreamRead1Bits(stream);
if (currVol->scalability)
{
if (layer == 0) return PV_FAIL; /* */
/* hierarchy_type: 1 : temporal, 0 : spatial */
/* 03/10/99 */
currVol->scalType = (int) BitstreamRead1Bits(stream); /* */
if (!currVol->scalType) return PV_FAIL;
/* ref_layer_id (4 bits) */
currVol->refVolID = (int) BitstreamReadBits16(stream, 4);
if (layer) /* */
{
if (currVol->refVolID != video->vol[0]->volID) return PV_FAIL;
}
/* ref_layer_sampling_direc (1 bits) */
/* 1 : ref. layer has higher resolution */
/* 0 : ref. layer has equal or lower resolution */
currVol->refSampDir = (int) BitstreamRead1Bits(stream);
if (currVol->refSampDir) return PV_FAIL;
/* hor_sampling_factor_n (5 bits) */
currVol->horSamp_n = (int) BitstreamReadBits16(stream, 5);
/* hor_sampling_factor_m (5 bits) */
currVol->horSamp_m = (int) BitstreamReadBits16(stream, 5);
if (currVol->horSamp_m == 0) return PV_FAIL;
if (currVol->horSamp_n != currVol->horSamp_m) return PV_FAIL;
/* ver_sampling_factor_n (5 bits) */
currVol->verSamp_n = (int) BitstreamReadBits16(stream, 5);
/* ver_sampling_factor_m (5 bits) */
currVol->verSamp_m = (int) BitstreamReadBits16(stream, 5);
if (currVol->verSamp_m == 0) return PV_FAIL;
if (currVol->verSamp_n != currVol->verSamp_m) return PV_FAIL;
/* enhancement_type: 1 : partial region, 0 : full region */
/* 04/10/2000: we only support full region enhancement layer. */
if (BitstreamRead1Bits(stream)) return PV_FAIL;
}
PV_BitstreamByteAlign(stream);
status = BitstreamShowBits32HC(stream, &tmpvar);
/* if we hit the end of buffer, tmpvar == 0. 08/30/2000 */
if (tmpvar == USER_DATA_START_CODE)
{
status = DecodeUserData(stream);
/* you should not check for status here 03/19/2002 */
status = PV_SUCCESS;
}
/* Compute some convenience variables: 04/13/2000 */
video->nMBPerRow = video->width / MB_SIZE;
video->nMBPerCol = video->height / MB_SIZE;
video->nTotalMB = video->nMBPerRow * video->nMBPerCol;
video->nBitsForMBID = CalcNumBits((uint)video->nTotalMB - 1);
#ifdef PV_ANNEX_IJKT_SUPPORT
video->modified_quant = 0;
video->advanced_INTRA = 0;
video->deblocking = 0;
video->slice_structure = 0;
#endif
}
else
{
/* SHORT_HEADER */
status = BitstreamShowBits32(stream, SHORT_VIDEO_START_MARKER_LENGTH, &tmpvar);
if (tmpvar == SHORT_VIDEO_START_MARKER)
{
video->shortVideoHeader = TRUE;
}
else
{
do
{
/* Search for VOL_HEADER */
status = PVSearchNextM4VFrame(stream); /* search 0x00 0x00 0x01 */
if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
PV_BitstreamFlushBits(stream, 8);
}
while (tmpvar != VOL_START_CODE);
goto decode_vol;
}
}
#ifdef PV_TOLERATE_VOL_ERRORS
if (profile > 0xFF || profile == 0)
{
return PV_BAD_VOLHEADER;
}
#endif
return status;
}
/***********************************************************CommentBegin******
*
* -- DecodeGOV -- Decodes the Group of VOPs from bitstream
*
* 04/20/2000 initial modification to the new PV-Decoder Lib format.
*
***********************************************************CommentEnd********/
PV_STATUS DecodeGOVHeader(BitstreamDecVideo *stream, uint32 *time_base)
{
uint32 tmpvar, time_s;
int closed_gov, broken_link;
/* group_start_code (32 bits) */
// tmpvar = BitstreamReadBits32(stream, 32);
/* hours */
tmpvar = (uint32) BitstreamReadBits16(stream, 5);
time_s = tmpvar * 3600;
/* minutes */
tmpvar = (uint32) BitstreamReadBits16(stream, 6);
time_s += tmpvar * 60;
/* marker bit */
tmpvar = (uint32) BitstreamRead1Bits(stream);
/* seconds */
tmpvar = (uint32) BitstreamReadBits16(stream, 6);
time_s += tmpvar;
/* We have to check the timestamp here. If the sync timestamp is */
/* earlier than the previous timestamp or longer than 60 sec. */
/* after the previous timestamp, assume the GOV header is */
/* corrupted. 05/12/2000 */
*time_base = time_s; /* 02/27/2002 */
// *time_base = *time_base/1000;
// tmpvar = time_s - *time_base;
// if (tmpvar <= 60) *time_base = time_s;
// else return PV_FAIL;
tmpvar = (uint32) BitstreamRead1Bits(stream);
closed_gov = tmpvar;
tmpvar = (uint32) BitstreamRead1Bits(stream);
broken_link = tmpvar;
if ((closed_gov == 0) && (broken_link == 1))
{
return PV_SUCCESS; /* 03/15/2002 you can also return PV_FAIL */
}
PV_BitstreamByteAlign(stream);
BitstreamShowBits32HC(stream, &tmpvar);
while (tmpvar == USER_DATA_START_CODE) /* 03/15/2002 */
{
DecodeUserData(stream);
BitstreamShowBits32HC(stream, &tmpvar);
}
return PV_SUCCESS;
}
/***********************************************************CommentBegin******
*
* -- DecodeVopHeader -- Decodes the VOPheader information from the bitstream
*
* 04/12/2000 Initial port to the new PV decoder library format.
* 05/10/2000 Error resilient decoding of vop header.
*
***********************************************************CommentEnd********/
PV_STATUS DecodeVOPHeader(VideoDecData *video, Vop *currVop, Bool use_ext_timestamp)
{
PV_STATUS status = PV_SUCCESS;
Vol *currVol = video->vol[video->currLayer];
BitstreamDecVideo *stream = currVol->bitstream;
uint32 tmpvar;
int time_base;
/*****
* Read the VOP header from the bitstream (No shortVideoHeader Mode here!)
*****/
BitstreamShowBits32HC(stream, &tmpvar);
/* check if we have a GOV header here. 08/30/2000 */
if (tmpvar == GROUP_START_CODE)
{
tmpvar = BitstreamReadBits32HC(stream);
// rewindBitstream(stream, START_CODE_LENGTH); /* for backward compatibility */
status = DecodeGOVHeader(stream, &tmpvar);
if (status != PV_SUCCESS)
{
return status;
}
// use_ext_timestamp = TRUE; /* 02/08/2002 */
/* We should have a VOP header following the GOV header. 03/15/2001 */
BitstreamShowBits32HC(stream, &tmpvar);
}
#ifdef PV_SUPPORT_TEMPORAL_SCALABILITY
currVop->timeStamp = -1;
#endif
if (tmpvar == VOP_START_CODE)
{
tmpvar = BitstreamReadBits32HC(stream);
}
else
{
PV_BitstreamFlushBits(stream, 8); // advance by a byte
status = PV_FAIL;
goto return_point;
}
/* vop_prediction_type (2 bits) */
currVop->predictionType = (int) BitstreamReadBits16(stream, 2);
/* modulo_time_base (? bits) */
time_base = -1;
do
{
time_base++;
tmpvar = (uint32) BitstreamRead1Bits(stream);
}
while (tmpvar == 1);
if (!use_ext_timestamp)
{
currVol->moduloTimeBase += 1000 * time_base; /* milliseconds based MTB 11/12/01 */
}
/* marker_bit (1 bit) */
if (!BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
/* vop_time_increment (1-15 bits) in Nov_Compliant (1-16 bits) */
/* we always assumes fixed vop rate here */
currVop->timeInc = BitstreamReadBits16(stream, currVol->nbitsTimeIncRes);
/* marker_bit (1 bit) */
if (!BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
/* vop_coded */
currVop->vopCoded = (int) BitstreamRead1Bits(stream);
if (currVop->vopCoded == 0)
{
status = PV_SUCCESS;
goto return_point;
}
/* read vop_rounding_type */
if (currVop->predictionType == P_VOP)
{
currVop->roundingType = (int) BitstreamRead1Bits(stream);
}
else
{
currVop->roundingType = 0;
}
if (currVol->complexity_estDisable == 0)
{
if (currVol->complexity_estMethod < 2) /* OCT 2002 */
{
if ((currVol->complexity.text_1 >> 3) & 0x1) /* intra */
BitstreamReadBits16(stream, 8);
if (currVol->complexity.text_1 & 0x1) /* not_coded */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.text_2 >> 3) & 0x1) /* dct_coefs */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.text_2 >> 2) & 0x1) /* dct_lines */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.text_2 >> 1) & 0x1) /* vlc_symbols */
BitstreamReadBits16(stream, 8);
if (currVol->complexity.text_2 & 0x1) /* vlc_bits */
BitstreamReadBits16(stream, 4);
if (currVop->predictionType != I_VOP)
{
if ((currVol->complexity.text_1 >> 2) & 0x1) /* inter */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.text_1 >> 1) & 0x1) /* inter_4v */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.mc >> 5) & 0x1) /* apm */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.mc >> 4) & 0x1) /* npm */
BitstreamReadBits16(stream, 8);
/* interpolate_mc_q */
if ((currVol->complexity.mc >> 2) & 0x1) /* forw_back_mc_q */
BitstreamReadBits16(stream, 8);
if ((currVol->complexity.mc >> 1) & 0x1) /* halfpel2 */
BitstreamReadBits16(stream, 8);
if (currVol->complexity.mc & 0x1) /* halfpel4 */
BitstreamReadBits16(stream, 8);
}
if (currVop->predictionType == B_VOP)
{
if ((currVol->complexity.mc >> 3) & 0x1) /* interpolate_mc_q */
BitstreamReadBits16(stream, 8);
}
}
}
/* read intra_dc_vlc_thr */
currVop->intraDCVlcThr = (int) BitstreamReadBits16(stream, 3);
/* read vop_quant (currVol->quantPrecision bits) */
currVop->quantizer = (int16) BitstreamReadBits16(stream, currVol->quantPrecision);
if (currVop->quantizer == 0)
{
currVop->quantizer = video->prevVop->quantizer;
status = PV_FAIL;
goto return_point;
}
/* read vop_fcode_forward */
if (currVop->predictionType != I_VOP)
{
tmpvar = (uint32) BitstreamReadBits16(stream, 3);
if (tmpvar < 1)
{
currVop->fcodeForward = 1;
status = PV_FAIL;
goto return_point;
}
currVop->fcodeForward = tmpvar;
}
else
{
currVop->fcodeForward = 0;
}
/* read vop_fcode_backward */
if (currVop->predictionType == B_VOP)
{
tmpvar = (uint32) BitstreamReadBits16(stream, 3);
if (tmpvar < 1)
{
currVop->fcodeBackward = 1;
status = PV_FAIL;
goto return_point;
}
currVop->fcodeBackward = tmpvar;
}
else
{
currVop->fcodeBackward = 0;
}
if (currVol->scalability)
{
currVop->refSelectCode = (int) BitstreamReadBits16(stream, 2);
}
return_point:
return status;
}
/***********************************************************CommentBegin******
*
* -- VideoPlaneWithShortHeader -- Decodes the short_video_header information from the bitstream
* Modified :
04/23/2001. Remove the codes related to the
"first pass" decoding. We use a different function
to set up the decoder now.
***********************************************************CommentEnd********/
PV_STATUS DecodeShortHeader(VideoDecData *video, Vop *currVop)
{
PV_STATUS status = PV_SUCCESS;
Vol *currVol = video->vol[0];
BitstreamDecVideo *stream = currVol->bitstream;
uint32 tmpvar;
int32 size;
int extended_PTYPE = FALSE;
int UFEP = 0, custom_PFMT = 0, custom_PCF = 0;
status = BitstreamShowBits32(stream, SHORT_VIDEO_START_MARKER_LENGTH, &tmpvar);
if (tmpvar != SHORT_VIDEO_START_MARKER)
{
status = PV_FAIL;
goto return_point;
}
PV_BitstreamFlushBits(stream, SHORT_VIDEO_START_MARKER_LENGTH);
/* Temporal reference. Using vop_time_increment_resolution = 30000 */
tmpvar = (uint32) BitstreamReadBits16(stream, 8);
currVop->temporalRef = (int) tmpvar;
currVop->timeInc = 0xff & (256 + currVop->temporalRef - video->prevVop->temporalRef);
currVol->moduloTimeBase += currVop->timeInc; /* mseconds 11/12/01 */
/* Marker Bit */
if (!BitstreamRead1Bits(stream))
{
mp4dec_log("DecodeShortHeader(): Marker bit wrong.\n");
status = PV_FAIL;
goto return_point;
}
/* Zero Bit */
if (BitstreamRead1Bits(stream))
{
mp4dec_log("DecodeShortHeader(): Zero bit wrong.\n");
status = PV_FAIL;
goto return_point;
}
/*split_screen_indicator*/
if (BitstreamRead1Bits(stream))
{
mp4dec_log("DecodeShortHeader(): Split Screen not supported.\n");
VideoDecoderErrorDetected(video);
}
/*document_freeze_camera*/
if (BitstreamRead1Bits(stream))
{
mp4dec_log("DecodeShortHeader(): Freeze Camera not supported.\n");
VideoDecoderErrorDetected(video);
}
/*freeze_picture_release*/
if (BitstreamRead1Bits(stream))
{
mp4dec_log("DecodeShortHeader(): Freeze Release not supported.\n");
VideoDecoderErrorDetected(video);
}
/* source format */
switch (BitstreamReadBits16(stream, 3))
{
case 1:
if (video->size < 128*96)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 128;
video->displayHeight = video->height = 96;
break;
case 2:
if (video->size < 176*144)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 176;
video->displayHeight = video->height = 144;
break;
case 3:
if (video->size < 352*288)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 352;
video->displayHeight = video->height = 288;
break;
case 4:
if (video->size < 704*576)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 704;
video->displayHeight = video->height = 576;
break;
case 5:
if (video->size < 1408*1152)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 1408;
video->displayHeight = video->height = 1152;
break;
case 7:
extended_PTYPE = TRUE;
break;
default:
/* Msg("H.263 source format not legal\n"); */
status = PV_FAIL;
goto return_point;
}
currVop->roundingType = 0;
if (extended_PTYPE == FALSE)
{
currVop->predictionType = (int) BitstreamRead1Bits(stream);
/* four_reserved_zero_bits */
if (BitstreamReadBits16(stream, 4))
{
mp4dec_log("DecodeShortHeader(): Reserved bits wrong.\n");
status = PV_FAIL;
goto return_point;
}
}
else
{
UFEP = BitstreamReadBits16(stream, 3);
if (UFEP == 1)
{
/* source format */
switch (BitstreamReadBits16(stream, 3))
{
case 1:
if (video->size < 128*96)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 128;
video->displayHeight = video->height = 96;
break;
case 2:
if (video->size < 176*144)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 176;
video->displayHeight = video->height = 144;
break;
case 3:
if (video->size < 352*288)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 352;
video->displayHeight = video->height = 288;
break;
case 4:
if (video->size < 704*576)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 704;
video->displayHeight = video->height = 576;
break;
case 5:
if (video->size < 1408*1152)
{
status = PV_FAIL;
goto return_point;
}
video->displayWidth = video->width = 1408;
video->displayHeight = video->height = 1152;
break;
case 6:
custom_PFMT = TRUE;
break;
default:
/* Msg("H.263 source format not legal\n"); */
status = PV_FAIL;
goto return_point;
}
custom_PCF = BitstreamRead1Bits(stream);
/* unrestricted MV */
if (BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
/* SAC */
if (BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
/* AP */
if (BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
video->advanced_INTRA = BitstreamRead1Bits(stream);
video->deblocking = BitstreamRead1Bits(stream);
video->slice_structure = BitstreamRead1Bits(stream);
/* RPS, ISD, AIV */
if (BitstreamReadBits16(stream, 3))
{
status = PV_FAIL;
goto return_point;
}
video->modified_quant = BitstreamRead1Bits(stream);
/* Marker Bit and reserved*/
if (BitstreamReadBits16(stream, 4) != 8)
{
status = PV_FAIL;
goto return_point;
}
}
#ifndef PV_ANNEX_IJKT_SUPPORT
if (video->advanced_INTRA | video->deblocking | video->modified_quant | video->modified_quant)
{
status = PV_FAIL;
goto return_point;
}
#endif
if (UFEP == 0 || UFEP == 1)
{
tmpvar = BitstreamReadBits16(stream, 3);
if (tmpvar > 1)
{
status = PV_FAIL;
goto return_point;
}
currVop->predictionType = tmpvar;
/* RPR */
if (BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
/* RRU */
if (BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
currVop->roundingType = (int) BitstreamRead1Bits(stream);
if (BitstreamReadBits16(stream, 3) != 1)
{
status = PV_FAIL;
goto return_point;
}
}
else
{
status = PV_FAIL;
goto return_point;
}
/* CPM */
if (BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
/* CPFMT */
if (custom_PFMT == 1 && UFEP == 1)
{
/* aspect ratio */
tmpvar = BitstreamReadBits16(stream, 4);
if (tmpvar == 0)
{
status = PV_FAIL;
goto return_point;
}
/* Extended PAR */
if (tmpvar == 0xF)
{
/* Read par_width and par_height but do nothing */
/* par_width */
tmpvar = BitstreamReadBits16(stream, 8);
/* par_height */
tmpvar = BitstreamReadBits16(stream, 8);
}
tmpvar = BitstreamReadBits16(stream, 9);
int tmpDisplayWidth = (tmpvar + 1) << 2;
/* marker bit */
if (!BitstreamRead1Bits(stream))
{
status = PV_FAIL;
goto return_point;
}
tmpvar = BitstreamReadBits16(stream, 9);
if (tmpvar == 0)
{
status = PV_FAIL;
goto return_point;
}
int tmpDisplayHeight = tmpvar << 2;
int tmpHeight = (tmpDisplayHeight + 15) & -16;
int tmpWidth = (tmpDisplayWidth + 15) & -16;
if (tmpHeight * tmpWidth > video->size)
{
// This is just possibly "b/37079296".
ALOGE("b/37079296");
status = PV_FAIL;
goto return_point;
}
video->displayWidth = tmpDisplayWidth;
video->width = tmpWidth;
video->displayHeight = tmpDisplayHeight;
video->height = tmpHeight;
video->nTotalMB = video->width / MB_SIZE * video->height / MB_SIZE;
if (video->nTotalMB <= 48)
{
video->nBitsForMBID = 6;
}
else if (video->nTotalMB <= 99)
{
video->nBitsForMBID = 7;
}
else if (video->nTotalMB <= 396)
{
video->nBitsForMBID = 9;
}
else if (video->nTotalMB <= 1584)
{
video->nBitsForMBID = 11;
}
else if (video->nTotalMB <= 6336)
{
video->nBitsForMBID = 13 ;
}
else if (video->nTotalMB <= 9216)
{
video->nBitsForMBID = 14 ;
}
else
{
status = PV_FAIL;
goto return_point;
}
}
if (UFEP == 1 && custom_PCF == 1)
{
BitstreamRead1Bits(stream);
tmpvar = BitstreamReadBits16(stream, 7);
if (tmpvar == 0)
{
status = PV_FAIL;
goto return_point;
}
}
if (custom_PCF == 1)
{
currVop->ETR = BitstreamReadBits16(stream, 2);
}
if (UFEP == 1 && video->slice_structure == 1)
{
/* SSS */
tmpvar = BitstreamReadBits16(stream, 2);
if (tmpvar != 0)
{
status = PV_FAIL;
goto return_point;
}
}
}
/* Recalculate number of macroblocks per row & col since */
/* the frame size can change. 04/23/2001. */
video->nMBinGOB = video->nMBPerRow = video->width / MB_SIZE;
video->nGOBinVop = video->nMBPerCol = video->height / MB_SIZE;
video->nTotalMB = video->nMBPerRow * video->nMBPerCol;
if (custom_PFMT == 0 || UFEP == 0)
{
video->nBitsForMBID = CalcNumBits((uint)video->nTotalMB - 1); /* otherwise calculate above */
}
size = (int32)video->width * video->height;
if (currVop->predictionType == P_VOP && size > video->videoDecControls->size)
{
status = PV_FAIL;
goto return_point;
}
video->videoDecControls->size = size;
video->currVop->uChan = video->currVop->yChan + size;
video->currVop->vChan = video->currVop->uChan + (size >> 2);
video->prevVop->uChan = video->prevVop->yChan + size;
video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
currVop->quantizer = (int16) BitstreamReadBits16(stream, 5);
if (currVop->quantizer == 0) /* 04/03/01 */
{
currVop->quantizer = video->prevVop->quantizer;
status = PV_FAIL;
goto return_point;
}
/* Zero bit */
if (extended_PTYPE == FALSE)
{
if (BitstreamRead1Bits(stream))
{
mp4dec_log("DecodeShortHeader(): Zero bit wrong.\n");
status = PV_FAIL;
goto return_point;
}
}
/* pei */
tmpvar = (uint32) BitstreamRead1Bits(stream);
while (tmpvar)
{
tmpvar = (uint32) BitstreamReadBits16(stream, 8); /* "PSPARE" */
tmpvar = (uint32) BitstreamRead1Bits(stream); /* "PEI" */
}
if (video->slice_structure) /* ANNEX_K */
{
if (!BitstreamRead1Bits(stream)) /* SEPB1 */
{
status = PV_FAIL;
goto return_point;
}
// if (currVol->nBitsForMBID //
if (BitstreamReadBits16(stream, video->nBitsForMBID))
{
status = PV_FAIL; /* no ASO, RS support for Annex K */
goto return_point;
}
if (!BitstreamRead1Bits(stream)) /*SEPB3 */
{
status = PV_FAIL;
goto return_point;
}
}
/* Setting of other VOP-header parameters */
currVop->gobNumber = 0;
currVop->vopCoded = 1;
currVop->intraDCVlcThr = 0;
currVop->gobFrameID = 0; /* initial value, 05/22/00 */
currVol->errorResDisable = 0;
/*PutVopInterlaced(0,curr_vop); no implemented yet */
if (currVop->predictionType != I_VOP)
currVop->fcodeForward = 1;
else
currVop->fcodeForward = 0;
return_point:
return status;
}
/***********************************************************CommentBegin******
*
* -- PV_DecodeVop -- Decodes the VOP information from the bitstream
*
* 04/12/2000
* Initial port to the new PV decoder library format.
* This function is different from the one in MoMuSys MPEG-4
* visual decoder. We handle combined mode with or withput
* error resilience and H.263 mode through the sam path now.
*
* 05/04/2000
* Added temporal scalability to the decoder.
*
***********************************************************CommentEnd********/
PV_STATUS PV_DecodeVop(VideoDecData *video)
{
Vol *currVol = video->vol[video->currLayer];
PV_STATUS status;
uint32 tmpvar;
/*****
* Do scalable or non-scalable decoding of the current VOP
*****/
if (!currVol->scalability)
{
if (currVol->dataPartitioning)
{
/* Data partitioning mode comes here */
status = DecodeFrameDataPartMode(video);
}
else
{
/* Combined mode with or without error resilience */
/* and short video header comes here. */
status = DecodeFrameCombinedMode(video);
}
}
else
{
#ifdef DO_NOT_FOLLOW_STANDARD
/* according to the standard, only combined mode is allowed */
/* in the enhancement layer. 06/01/2000. */
if (currVol->dataPartitioning)
{
/* Data partitioning mode comes here */
status = DecodeFrameDataPartMode(video);
}
else
{
/* Combined mode with or without error resilience */
/* and short video header comes here. */
status = DecodeFrameCombinedMode(video);
}
#else
status = DecodeFrameCombinedMode(video);
#endif
}
/* This part is for consuming Visual_object_sequence_end_code and EOS Code */ /* 10/15/01 */
if (!video->shortVideoHeader)
{
/* at this point bitstream is expected to be byte aligned */
BitstreamByteAlignNoForceStuffing(currVol->bitstream);
status = BitstreamShowBits32HC(currVol->bitstream, &tmpvar); /* 07/07/01 */
if (tmpvar == VISUAL_OBJECT_SEQUENCE_END_CODE)/* VOS_END_CODE */
{
PV_BitstreamFlushBits(currVol->bitstream, 16);
PV_BitstreamFlushBits(currVol->bitstream, 16);
}
}
else
{
#ifdef PV_ANNEX_IJKT_SUPPORT
if (video->deblocking)
{
H263_Deblock(video->currVop->yChan, video->width, video->height, video->QPMB, video->headerInfo.Mode, 0, 0);
H263_Deblock(video->currVop->uChan, video->width >> 1, video->height >> 1, video->QPMB, video->headerInfo.Mode, 1, video->modified_quant);
H263_Deblock(video->currVop->vChan, video->width >> 1, video->height >> 1, video->QPMB, video->headerInfo.Mode, 1, video->modified_quant);
}
#endif
/* Read EOS code for shortheader bitstreams */
status = BitstreamShowBits32(currVol->bitstream, 22, &tmpvar);
if (tmpvar == SHORT_VIDEO_END_MARKER)
{
PV_BitstreamFlushBits(currVol->bitstream, 22);
}
else
{
status = PV_BitstreamShowBitsByteAlign(currVol->bitstream, 22, &tmpvar);
if (tmpvar == SHORT_VIDEO_END_MARKER)
{
PV_BitstreamByteAlign(currVol->bitstream);
PV_BitstreamFlushBits(currVol->bitstream, 22);
}
}
}
return status;
}
/***********************************************************CommentBegin******
*
* -- CalcVopDisplayTime -- calculate absolute time when VOP is to be displayed
*
* 04/12/2000 Initial port to the new PV decoder library format.
*
***********************************************************CommentEnd********/
uint32 CalcVopDisplayTime(Vol *currVol, Vop *currVop, int shortVideoHeader)
{
uint32 display_time;
/*****
* Calculate the time when the VOP is to be displayed next
*****/
if (!shortVideoHeader)
{
display_time = (uint32)(currVol->moduloTimeBase + (((int32)currVop->timeInc - (int32)currVol->timeInc_offset) * 1000) / ((int32)currVol->timeIncrementResolution)); /* 11/12/2001 */
if (currVop->timeStamp >= display_time)
{
display_time += 1000; /* this case is valid if GOVHeader timestamp is ignored */
}
}
else
{
display_time = (uint32)(currVol->moduloTimeBase * 33 + (currVol->moduloTimeBase * 11) / 30); /* 11/12/2001 */
}
return(display_time);
}