1427 lines
52 KiB
C
1427 lines
52 KiB
C
//----------------------------------------------------------------------------
|
|
// STHEAD.C
|
|
//----------------------------------------------------------------------------
|
|
// Description : Header Interrupt Related routines
|
|
//----------------------------------------------------------------------------
|
|
// Copyright SGS Thomson Microelectronics ! Version alpha ! Jan 1st, 1995
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Include files
|
|
//----------------------------------------------------------------------------
|
|
#include "stdefs.h"
|
|
#include <stdlib.h> // labs
|
|
#include "common.h"
|
|
#include "STllapi.h"
|
|
#include "stfifo.h"
|
|
#include "debug.h"
|
|
#include "error.h"
|
|
#ifdef STi3520A
|
|
#include "STi3520A.h"
|
|
#else
|
|
#include "STi3520.h"
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// GLOBAL Variables (avoid as possible)
|
|
//----------------------------------------------------------------------------
|
|
char seq_occured;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Private Constants
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Private Types
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Private GLOBAL Variables (static)
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Functions (statics one are private)
|
|
//----------------------------------------------------------------------------
|
|
|
|
/****************************************************************************/
|
|
/* notations of the bits position in pVideo->hdrFirstWord registers are */
|
|
/* X for a nibble that must be read */
|
|
/* x for a bit that must be read */
|
|
/* 0 for a nibble not read */
|
|
/* o for a bit not read */
|
|
/* example : 0 X xxoo 0 means: bits 15 to 12 not read, */
|
|
/* bits 11 to 6 extracted, bits 5 to 0 not read */
|
|
/****************************************************************************/
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Read of the header data fifo
|
|
//----------------------------------------------------------------------------
|
|
/*
|
|
returns the next word(16 bits) of the
|
|
Header data Fifo into pVideo->hdrFirstWord variable
|
|
*/
|
|
void VideoReadHeaderDataFifo ( PVIDEO pVideo )
|
|
{
|
|
U16 i = 0;
|
|
while ( VideoHeaderFifoEmpty()) /* Header fifo not available */
|
|
{
|
|
i++;
|
|
if (i == 0xFFFF) {
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = BUF_EMPTY;
|
|
SetErrorCode(ERR_BIT_BUFFER_EMPTY);
|
|
break;
|
|
}
|
|
} /* Waiting... */
|
|
pVideo->hdrFirstWord = VideoRead(HDF);
|
|
if (pVideo->hdrPos == 8) {
|
|
pVideo->hdrFirstWord = pVideo->hdrNextWord | pVideo->hdrFirstWord;
|
|
#ifndef STi3520A
|
|
pVideo->hdrNextWord = VideoRead ( HDF + 1 ) << 8;
|
|
#else
|
|
pVideo->hdrNextWord = VideoRead(HDF) << 8;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
pVideo->hdrFirstWord = pVideo->hdrFirstWord << 8;
|
|
#ifndef STi3520A
|
|
pVideo->hdrFirstWord = VideoRead ( HDF + 1 ) | pVideo->hdrFirstWord;
|
|
#else
|
|
pVideo->hdrFirstWord = VideoRead(HDF) | pVideo->hdrFirstWord;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Routine associating the PTS values with each picture
|
|
//----------------------------------------------------------------------------
|
|
void VideoAssociatePTS ( PVIDEO pVideo )
|
|
{
|
|
U32 scd_cnt,
|
|
cd_cnt; // cd_count
|
|
FIFOELT elt;
|
|
U16 wErr;
|
|
S32 sign = 1;
|
|
|
|
scd_cnt = VideoReadSCDCount (pVideo);
|
|
pVideo->pDecodedPict->validPTS = FALSE;
|
|
|
|
wErr = FifoReadPts ( pVideo->pFifo, &elt);
|
|
|
|
if ( wErr == NO_ERROR ) // If at least one ptsin
|
|
// fifo
|
|
{
|
|
cd_cnt = elt.CdCount / 2 + 2;
|
|
/* CD_count / 2 ranges from 0 to 7fffff */
|
|
if ( scd_cnt >= 0x800000UL ) /* scd_cnt = SCD count */
|
|
scd_cnt = scd_cnt - 0x800000UL; /* bring scd_cnt in range 0
|
|
* to 7fffff */
|
|
if ( labs ( cd_cnt - scd_cnt ) >= 0x400000UL ) // Too big difference
|
|
// one of cd or scd has
|
|
// turned
|
|
sign = -1; // Comparison changes sign.
|
|
// If cdcount > Scdcount assossiate pts with picture
|
|
if ( ( sign * ( S32 ) ( scd_cnt - cd_cnt ) ) >= 0L )
|
|
{
|
|
// extract pts from fifo and associate with decoded picture
|
|
FifoGetPts (pVideo->pFifo, &elt);
|
|
pVideo->pDecodedPict->dwPTS = elt.PtsVal;
|
|
pVideo->pDecodedPict->validPTS = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Read of the next start code in the bit stream
|
|
//----------------------------------------------------------------------------
|
|
/*
|
|
This routine is used at the end of the picture header
|
|
when the Start Code Detection mechanism is not used
|
|
*/
|
|
void VideoNextStartCode ( PVIDEO pVideo, S16 i )
|
|
{
|
|
long temp = 0;
|
|
|
|
if ( i )
|
|
temp = pVideo->hdrFirstWord & 0xFF; // use LSB of pVideo->hdrFirstWord
|
|
while ( temp == 0 )
|
|
{
|
|
VideoReadHeaderDataFifo ( pVideo ); // read next 16 bits
|
|
if ( pVideo->errCode )
|
|
{
|
|
i = 3;
|
|
break;
|
|
}
|
|
temp = ( temp << 16 ) | pVideo->hdrFirstWord;
|
|
i = i + 2;
|
|
}
|
|
if ( i < 3 ) { // A start code is not found: bit stream error !!
|
|
pVideo->errCode = PICT_HEAD;
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
else
|
|
{
|
|
if ( ( temp & 0xFFFFFF00L ) == 0x00000100L ) // this is a start code
|
|
{
|
|
if ( !pVideo->hdrPos ) // there is nothing into
|
|
// pVideo->hdrNextWord
|
|
{
|
|
pVideo->hdrPos = 8;
|
|
pVideo->hdrNextWord = ( pVideo->hdrFirstWord & 0xFF ) << 8;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
}
|
|
else
|
|
{ // pVideo->hdrPos = 8: the next
|
|
// byte is into pVideo->hdrNextWord
|
|
pVideo->hdrFirstWord = ( pVideo->hdrFirstWord << 8 ) | ( pVideo->hdrNextWord >> 8 );
|
|
pVideo->hdrPos = 0;
|
|
}
|
|
}
|
|
else if ( ( temp & 0xFFFFFFFFL ) == 0x00000001L ) // this is a start code
|
|
{
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
}
|
|
else { // temp does not contain a start code : bit stream error !
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = PICT_HEAD;
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
}
|
|
i = VideoRead ( ITS ) << 8; // allows to clear the Header hit bit
|
|
i = ( i | VideoRead ( ITS + 1 ) ) & 0xFFFE; // allows to clear the
|
|
// Header hit bit
|
|
pVideo->intStatus = ( pVideo->intStatus | i ) & pVideo->intMask;
|
|
/* if no bit stream error, we leave the routine with the start code into pVideo->hdrFirstWord as XX00 */
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// SEQUENCE START CODE
|
|
//----------------------------------------------------------------------------
|
|
VOID VideoSequenceHeader(PVIDEO pVideo)
|
|
{
|
|
U16 compute, i;
|
|
/* default intra quantization matrix */
|
|
static U8 DefIntQuant[QUANT_TAB_SIZE] = {
|
|
0x08, 0x10, 0x10, 0x13, 0x10, 0x13, 0x16, 0x16,
|
|
0x16, 0x16, 0x16, 0x16, 0x1A, 0x18, 0x1A, 0x1B,
|
|
0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B,
|
|
0x1B, 0x1D, 0x1D, 0x1D, 0x22, 0x22, 0x22, 0x1D,
|
|
0x1D, 0x1D, 0x1B, 0x1B, 0x1D, 0x1D, 0x20, 0x20,
|
|
0x22, 0x22, 0x25, 0x26, 0x25, 0x23, 0x23, 0x22,
|
|
0x23, 0x26, 0x26, 0x28, 0x28, 0x28, 0x30, 0x30,
|
|
0x2E, 0x2E, 0x38, 0x38, 0x3A, 0x45, 0x45, 0x53
|
|
};
|
|
// Default Non Intra Table
|
|
static U8 DefNonIntQuant[QUANT_TAB_SIZE];
|
|
// Non Default Table
|
|
static U8 QuantTab[QUANT_TAB_SIZE];
|
|
|
|
// default Non intra quantization matrix, All coefs = 16
|
|
for (i = 0 ; i < QUANT_TAB_SIZE ; i++)
|
|
DefNonIntQuant[i] = 16;
|
|
|
|
seq_occured = 1; // mention to the picture header that a sequence has occured
|
|
// in order to reset the next pan offsets.
|
|
|
|
/* Horizontal picture size is 12 bits: 00XX + X000 */
|
|
pVideo->StreamInfo.horSize = ( pVideo->hdrFirstWord << 4 ) & 0xFFF; // extract 8 MSB
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.horSize = pVideo->StreamInfo.horSize | ( pVideo->hdrFirstWord >> 12 ); // 4 LSB of horizontal
|
|
// size
|
|
|
|
/* Vertical picture size is 12 bits: 0XXX */
|
|
pVideo->StreamInfo.verSize = pVideo->hdrFirstWord & 0xFFF; // 12 LSB of Vertical picture
|
|
// size
|
|
|
|
/* pixel aspect ratio is 4 bits: X000 */
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.pixelRatio = ( pVideo->hdrFirstWord >> 12 ) & 0xF;
|
|
|
|
/* frame rate is 4 bits: 0X00 */
|
|
pVideo->StreamInfo.frameRate = ( pVideo->hdrFirstWord >> 8 ) & 0xF;
|
|
pVideo->StreamInfo.displayMode = 1; // 60 Hz interlaced display
|
|
pVideo->BufferA = BUFF_A_NTSC;
|
|
pVideo->BufferB = BUFF_B_NTSC;
|
|
pVideo->BufferC = BUFF_C_NTSC;
|
|
switch ( pVideo->StreamInfo.frameRate )
|
|
{
|
|
case 1: // picture rate is 23.976 Hz:
|
|
break; // display in 3:2 pull-down at
|
|
// 59.94 Hz interlaced if MPEG1
|
|
case 2: // picture rate is 24 Hz:
|
|
break; // display in 3:2 pull-down at
|
|
// 60 Hz interlaced if MPEG1
|
|
case 3: // picture rate is 25 Hz:
|
|
// display 50 Hz interlaced
|
|
pVideo->StreamInfo.displayMode = 0;
|
|
pVideo->BufferA = BUFF_A_PAL;
|
|
pVideo->BufferB = BUFF_B_PAL;
|
|
pVideo->BufferC = BUFF_C_PAL;
|
|
#ifdef STi3520A
|
|
// Choose B Optimization for PAL for both Luma and Chroma
|
|
VideoWrite(CFG_BFS,NB_ROW_OF_MB);
|
|
// Select Full Res vertical filter without interpolation
|
|
// Interpollation NOT ALLOWED if Optimization
|
|
pVideo->fullVerFilter = 0x01;
|
|
#endif
|
|
break;
|
|
case 4: // picture rate is 29.97 Hz
|
|
break;
|
|
case 5: // picture rate is 30 Hz
|
|
break;
|
|
default:
|
|
SetErrorCode(ERR_FRAME_RATE_NOT_SUPPORTED);
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = FRAME_RATE; /* frame rate not supported by the board */
|
|
break;
|
|
}
|
|
|
|
/* bit rate is 18 bits: 00XX + XX xxoo 0 */
|
|
pVideo->StreamInfo.bitRate = ( long ) pVideo->hdrFirstWord;
|
|
pVideo->StreamInfo.bitRate = ( pVideo->StreamInfo.bitRate << 10 ) & 0x3FC00L;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.bitRate = pVideo->StreamInfo.bitRate | ( pVideo->hdrFirstWord >> 6 );
|
|
|
|
/* bit rate is 18 bits only for MPEG1 bit streams */
|
|
if ( !pVideo->StreamInfo.modeMPEG2 )
|
|
{
|
|
long tota = 400L;
|
|
pVideo->StreamInfo.bitRate = pVideo->StreamInfo.bitRate * tota; /* bit rate is a multiple of 400
|
|
* bits/s */
|
|
}
|
|
/*
|
|
* for MPEG2 bit streams bit rate is 30 bits: 12 more bits in
|
|
* sequence extension
|
|
*/
|
|
|
|
/* marker bit: 00 ooxo 0 : just skipped ... */
|
|
|
|
/* pVideo->vbvBufferSize is 10 bits : 00 ooox X + X xooo 00 */
|
|
pVideo->vbvBufferSize = ( pVideo->hdrFirstWord << 5 ) & 0x3E0;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->vbvBufferSize = pVideo->vbvBufferSize | ( pVideo->hdrFirstWord >> 11 );
|
|
// if( (!pVideo->StreamInfo.modeMPEG2) && ((pVideo->vbvBufferSize*8) > BUF_FULL) )
|
|
// if (!pVideo->errCode) pVideo->errCode = SMALL_BUF; /* Buffer size too small to decode the bit stream */
|
|
// for MPEG2 bit streams pVideo->vbvBufferSize is 15 bits: 5 more bits in
|
|
// sequence extension */
|
|
|
|
// constrained flag is 1 bit: 0 oxoo 00 : just skipped... */
|
|
|
|
// load intra quant table bit : 0 ooxo 00 */
|
|
if ( ( pVideo->hdrFirstWord & 0x200 ) != 0 ) // Test load intra quantizer
|
|
// matrix */
|
|
{
|
|
// Read Non Default Intra Quant Table
|
|
for ( i = 0; i < (QUANT_TAB_SIZE/2) ; i++)
|
|
{
|
|
compute = pVideo->hdrFirstWord << 7;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
compute = compute | ( pVideo->hdrFirstWord >> 9 );
|
|
QuantTab[2*i] = (U8)( compute >> 8 );
|
|
QuantTab[2*i+1] = (U8)( compute & 0xFF );
|
|
}
|
|
// Load Intra Quant Tables
|
|
VideoLoadQuantTables(pVideo , TRUE , QuantTab );
|
|
|
|
pVideo->defaultTbl = pVideo->defaultTbl & 0xE; // bit 0 = 0 : no default table
|
|
// in the chip */
|
|
}
|
|
else if ( !( pVideo->defaultTbl & 0x1 ) ) // Load default intra matrix */
|
|
{
|
|
VideoLoadQuantTables(pVideo , TRUE , DefIntQuant );
|
|
pVideo->defaultTbl++; // bit 0 = 1 default intra table
|
|
// is in the chip */
|
|
}
|
|
|
|
// load non intra quant table bit : 0 ooox 00 */
|
|
if ( ( pVideo->hdrFirstWord & 0x100 ) != 0 ) // Test load non intra quantizer
|
|
// matrix */
|
|
{ // Load non intra quantizer
|
|
// matrix */
|
|
for ( i = 0; i < (QUANT_TAB_SIZE/2) ; i++)
|
|
{
|
|
compute = pVideo->hdrFirstWord & 0xFF;
|
|
QuantTab[2*i] = (U8)( compute );
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
compute = ( pVideo->hdrFirstWord >> 8 ) & 0xFF;
|
|
QuantTab[2*i+1] = (U8)( compute );
|
|
}
|
|
VideoLoadQuantTables(pVideo , FALSE , QuantTab );
|
|
pVideo->defaultTbl = pVideo->defaultTbl & 0xD; // bit 1 = 0 : no default
|
|
// non-intra matrix */
|
|
}
|
|
else if ( !( pVideo->defaultTbl & 0x2 ) ) // default non intra table not
|
|
// in the chip */
|
|
{
|
|
VideoLoadQuantTables(pVideo , FALSE , DefNonIntQuant );
|
|
pVideo->defaultTbl = pVideo->defaultTbl | 0x2; // bit 1 = 1: default non intra
|
|
// table into the chip */
|
|
}
|
|
|
|
if ( ( !pVideo->StreamInfo.modeMPEG2 ) && ( pVideo->notInitDone ) ) // initialisation of the
|
|
// frame size is only done
|
|
// once
|
|
{
|
|
VideoSetPictureSize ( pVideo);
|
|
VideoSetDisplayMode ( pVideo->StreamInfo.displayMode );
|
|
VideoInitXY (pVideo);
|
|
pVideo->notInitDone = 0;
|
|
}
|
|
// in case of MPEG2 bit streams the initialisation can only be done
|
|
// after sequence extension */
|
|
|
|
// end of sequence header analysis */
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// EXTENSION START CODE
|
|
//----------------------------------------------------------------------------
|
|
// interrupt only enabled after sequence or GOP start code */
|
|
VOID VideoExtensionHeader(PVIDEO pVideo)
|
|
{
|
|
U16 comput1;
|
|
U32 temp;
|
|
|
|
// extension field is 4 bits: 00X0 */
|
|
switch ( pVideo->hdrFirstWord & 0xF0 )
|
|
{
|
|
//**********************************************************/
|
|
// SEQUENCE EXTENSION */
|
|
//**********************************************************/
|
|
case SEQ_EXT: // sequence extension field
|
|
// always present in MPEG2
|
|
if ( !pVideo->StreamInfo.modeMPEG2 ) // automatic detection of the
|
|
// standard
|
|
{
|
|
long tota = 400L;
|
|
// Select MPEG2 decoding
|
|
VideoSelectMpeg2( pVideo , TRUE);
|
|
pVideo->StreamInfo.bitRate = pVideo->StreamInfo.bitRate / tota; // bit rate was mult. by
|
|
// 400 in sequence header
|
|
// if pVideo->StreamInfo.modeMPEG2 = 0
|
|
pVideo->StreamInfo.modeMPEG2 = 1;
|
|
pVideo->NextInstr.Mp2 = 1;
|
|
pVideo->notInitDone = 1;
|
|
}
|
|
|
|
/* one bit reserved for future use : 000xooo */
|
|
|
|
/* Profile indication: 000oxxx */
|
|
comput1 = pVideo->hdrFirstWord & 0x7;
|
|
if ( ( comput1 != 4 ) && ( comput1 != 5 ) ) { // main profile Id =
|
|
// 100, simple profile =
|
|
// 101
|
|
SetErrorCode(ERR_PROFILE_NOT_SUPPORTED);
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = MAIN_PROF;// not simple or main profile bitstream
|
|
}
|
|
/* Level indication: X000 */
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
comput1 = pVideo->hdrFirstWord & 0xF000;
|
|
if ( ( comput1 != 0x8000 ) && ( comput1 != 0xA000 ) ) {// main level Id = 1000,
|
|
// low level = 1010
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = MAIN_PROF;// not low or main level bitstream
|
|
SetErrorCode(ERR_LEVEL_NOT_SUPPORTED);
|
|
}
|
|
/* non interlaced sequence bit : 0 xooo 00 */
|
|
pVideo->StreamInfo.progSeq = 0;
|
|
if ( ( pVideo->hdrFirstWord & 0x0800 ) ) // non-interlaced frames
|
|
pVideo->StreamInfo.progSeq = 1;
|
|
|
|
/* chroma format is 2 bits: 0 oxxo 00 */
|
|
// test if 4.1.1 chroma format
|
|
if ( ( pVideo->hdrFirstWord & 0x600 ) != 0x200 ) {
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = CHROMA; // chroma format not supported
|
|
SetErrorCode(ERR_CHROMA_FORMAT_NOT_SUPPORTED);
|
|
}
|
|
/* horizontal size extension is 2 bits : 0 ooox xooo 0 */
|
|
comput1 = ( pVideo->hdrFirstWord & 0x180 ); // extract 2 MSb of
|
|
// horizontal picture size
|
|
pVideo->StreamInfo.horSize = pVideo->StreamInfo.horSize | ( comput1 << 3 );
|
|
/* vertical size extension is 2 bits: 00 oxxo 0 */
|
|
comput1 = ( pVideo->hdrFirstWord & 0x60 ); // extract 2 MSb of
|
|
// vertical picture size
|
|
pVideo->StreamInfo.verSize = pVideo->StreamInfo.verSize | ( comput1 << 5 );
|
|
|
|
/* bit rate extension is 12 bits: 00 ooox X + X xxxo 00 */
|
|
temp = ( pVideo->hdrFirstWord & 0x1F ) << 25;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
temp = ( ( pVideo->hdrFirstWord & 0xFE00 ) << 9 ) | temp;
|
|
pVideo->StreamInfo.bitRate = temp | pVideo->StreamInfo.bitRate;
|
|
if ( pVideo->StreamInfo.bitRate > 37500L ) // more than 15 Mbits/s
|
|
{
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = HIGH_BIT_RATE; // put a warning only for the eval board
|
|
SetErrorCode(ERR_BITRATE_TO_HIGH);
|
|
}
|
|
else
|
|
{
|
|
long tota = 400L;
|
|
pVideo->StreamInfo.bitRate = pVideo->StreamInfo.bitRate * tota; /* bit rate is a multiple of 400 bits/s */
|
|
}
|
|
|
|
/* marker bit: 0 ooox 00 : just skipped */
|
|
|
|
/* pVideo->vbvBufferSize_extension is 8 bits : 00 XX */
|
|
pVideo->vbvBufferSize = pVideo->vbvBufferSize | ( ( pVideo->hdrFirstWord & 0xFF ) << 10 );
|
|
// if( pVideo->vbvBufferSize > (BUF_FULL/8) )
|
|
// if (!pVideo->errCode) pVideo->errCode = SMALL_BUF; /* Buffer size too small to decode the bit stream */
|
|
|
|
// frame rate extension not tested here */
|
|
if ( pVideo->notInitDone )
|
|
{
|
|
VideoSetPictureSize ( pVideo );
|
|
VideoSetDisplayMode ( pVideo->StreamInfo.displayMode );
|
|
VideoInitXY ( pVideo );
|
|
pVideo->notInitDone = 0;
|
|
}
|
|
break;
|
|
// end of sequence extension field */
|
|
|
|
|
|
//**********************************************************/
|
|
// SEQUENCE DISPLAY EXTENSION */
|
|
//**********************************************************/
|
|
case SEQ_DISP: // sequence display extension
|
|
// field
|
|
pVideo->seqDispExt = 1;
|
|
/* video format is 3 bits: 00 0 xxxo : not used... */
|
|
|
|
/* colour description is 1 bit : 00 0 ooox */
|
|
if ( pVideo->hdrFirstWord & 0x1 )
|
|
{
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
/* colour primaries is 8 bits: XX 00 : not used... */
|
|
/*
|
|
* transfer characteristics is 8 bits: 00 XX : not
|
|
* used...
|
|
*/
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
/* matrix coefficients is 8 bits: XX 00: not used... */
|
|
|
|
/*
|
|
* pan_horizontal_dimension is 14 bits: 00 XX + X xxoo
|
|
* 00
|
|
*/
|
|
pVideo->StreamInfo.horDimension = ( pVideo->hdrFirstWord & 0xFF ) << 6;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.horDimension = pVideo->StreamInfo.horDimension | ( ( pVideo->hdrFirstWord & 0xFC00 ) >> 10 );
|
|
|
|
/* skip marker bit : 0ooxo 00 */
|
|
|
|
/*
|
|
* pan_vertical_dimension is 14 bits: 0 ooox XX + X
|
|
* xooo 00
|
|
*/
|
|
pVideo->StreamInfo.verDimension = ( pVideo->hdrFirstWord & 0x1FF ) << 5;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.verDimension = pVideo->StreamInfo.verDimension | ( ( pVideo->hdrFirstWord & 0xF800 ) >> 11 );
|
|
}
|
|
else
|
|
{
|
|
/* pan_horizontal_dimension is 14 bits: XX X xxoo */
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.horDimension = ( pVideo->hdrFirstWord & 0xFFFC ) >> 2;
|
|
|
|
/* skip marker bit : 00 0 ooxo */
|
|
|
|
/*
|
|
* pan_vertical_dimension is 14 bits: 00 0 ooox + XX X
|
|
* xooo
|
|
*/
|
|
pVideo->StreamInfo.verDimension = ( pVideo->hdrFirstWord & 0x1 ) << 13;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->StreamInfo.verDimension = pVideo->StreamInfo.verDimension | ( ( pVideo->hdrFirstWord & 0xFFF8 ) >> 3 );
|
|
}
|
|
/* pVideo->StreamInfo.horDimension and pVideo->StreamInfo.verDimension represent the area of the decoded */
|
|
/* picture that will be displayed on the full screen */
|
|
/*
|
|
* this area should be interpolated to the size of the
|
|
* display
|
|
*/
|
|
/*
|
|
* this is not possible vertically. Horizontally the SRC is
|
|
* used
|
|
*/
|
|
/* to deliver 720 pixels */
|
|
if ( pVideo->StreamInfo.horDimension < pVideo->StreamInfo.horSize )
|
|
{
|
|
U32 lsr;
|
|
S16 i;
|
|
// lsr = 256 * (pVideo->StreamInfo.horSize-4) / (display size - 1)
|
|
lsr = ( 256 * ( long ) ( pVideo->StreamInfo.horDimension - 4 ) ) / 719;
|
|
if ( lsr < 32 )
|
|
lsr = 32;
|
|
i = VideoRead ( LSO );
|
|
VideoWrite ( LSO, i ); // programmation of the
|
|
// SRC
|
|
VideoWrite ( LSR, lsr );
|
|
i = VideoRead ( CSO );
|
|
VideoWrite ( CSO, i );
|
|
#ifndef STi3520A
|
|
VideoWrite ( CSR, lsr );
|
|
#endif
|
|
if ( !pVideo->useSRC ) // flag enabling or not the use
|
|
// of SRC
|
|
{
|
|
VideoSRCOn ( pVideo );
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
default: /* other extension fields are
|
|
* not tested here */
|
|
break; /* extensions related to the
|
|
* picture are tested at the end
|
|
* of the picture header */
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// G.O.P. START CODE
|
|
//----------------------------------------------------------------------------
|
|
/* GOP informations are extracted but not used ! */
|
|
VOID VideoGopHeader(PVIDEO pVideo)
|
|
{
|
|
U16 compute;
|
|
|
|
pVideo->hdrHours = ( pVideo->hdrFirstWord >> 2 ) & 0x1F; /* Skip drop frame flag */
|
|
compute = ( pVideo->hdrFirstWord << 4 ) & 0x3F;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->hdrMinutes = ( pVideo->hdrFirstWord >> 12 ) | compute;
|
|
pVideo->hdrSeconds = ( pVideo->hdrFirstWord >> 5 ) & 0x3F;
|
|
compute = ( pVideo->hdrFirstWord << 1 ) & 0x3F;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->pictTimeCode = ( pVideo->hdrFirstWord >> 15 ) | compute;
|
|
if ( pVideo->StreamInfo.countGOP != 0 )
|
|
pVideo->StreamInfo.countGOP = pVideo->StreamInfo.countGOP | 0x100; /* Second Gop */
|
|
// to avoid any confusion between gops when testing the pVideo->decSlowDownral
|
|
// ref. for display
|
|
pVideo->GOPindex = pVideo->GOPindex + 0x4000;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// PICTURE START CODE
|
|
//----------------------------------------------------------------------------
|
|
VOID VideoPictureHeader(PVIDEO pVideo)
|
|
{
|
|
U16 comput1;
|
|
U32 temp;
|
|
|
|
// Determine which picture variable can be used to store the next
|
|
// decoding parameters.
|
|
// We use the next variable in pVideo->pictArray table, because the
|
|
// corresponding frame
|
|
// has been already displayed.
|
|
// The decoded picture buffer is not incremented if we are on a
|
|
// second field picture
|
|
// or if we have decided to skip the previous picture.
|
|
// The first_field attribute is not changed on the second field of
|
|
// 2 field pictures.
|
|
if ( ( !pVideo->skipMode ) && ( pVideo->fieldMode < 2 ) )
|
|
{
|
|
S16 i; // increment picture buffer
|
|
for ( i = 0; i < 4; i++ )
|
|
if ( pVideo->pictArray[i].tempRef == 1025 )
|
|
{
|
|
pVideo->pDecodedPict = &pVideo->pictArray[i];
|
|
break;
|
|
}
|
|
// We always initialise first_field to TOP (default for MPEG1).
|
|
// It could be changed in case of 3:2 pull-down in MPEG1
|
|
// or into the picture coding extension for MPEG2 bit stream.
|
|
pVideo->pDecodedPict->first_field = TOP;
|
|
}
|
|
|
|
VideoAssociatePTS ( pVideo );
|
|
|
|
pVideo->currPictCount++;
|
|
if ( pVideo->currPictCount == 3 ) /* don't force black color after
|
|
* the third decoded picture */
|
|
{ // first picture is ready for
|
|
// display
|
|
pVideo->currDCF = pVideo->currDCF | 0x20;
|
|
VideoWrite ( DCF, 0 );
|
|
VideoWrite ( DCF + 1, pVideo->currDCF );
|
|
}
|
|
|
|
// write the latest transmitted pan offsets into the new pVideo->pictArray
|
|
// variable
|
|
// those offsets may be changed in the picture pan and scan
|
|
// extension...
|
|
// for MPEG1 bit stream they remain to zero.
|
|
// if a sequence had occured since the last decoded picture the pan
|
|
// offsets are all reset to 0
|
|
if ( seq_occured )
|
|
{
|
|
pVideo->latestPanHor = 0;
|
|
pVideo->latestPanVer = 0;
|
|
}
|
|
for ( comput1 = 0; comput1 < 3; comput1++ )
|
|
{
|
|
pVideo->pDecodedPict->pan_hor_offset[comput1] = pVideo->latestPanHor;
|
|
pVideo->pDecodedPict->pan_vert_offset[comput1] = pVideo->latestPanVer;
|
|
}
|
|
seq_occured = 0;
|
|
|
|
/* start analysis of the picture header */
|
|
comput1 = pVideo->hdrFirstWord << 2;
|
|
VideoReadHeaderDataFifo ( pVideo ); /* read next 16 bits */
|
|
|
|
/* picture pVideo->decSlowDownral reference is 10 bits: 00XX + xxoo 000 */
|
|
pVideo->pDecodedPict->tempRef = comput1 | ( pVideo->hdrFirstWord >> 14 ) | pVideo->GOPindex;
|
|
|
|
/* picture type is 3 bits : ooxx xooo 00 */
|
|
pVideo->pDecodedPict->pict_type = ( pVideo->hdrFirstWord >> 11 ) & 0x7; // set picture type of
|
|
// decoded picture
|
|
pVideo->NextInstr.Pct = (pVideo->pDecodedPict->pict_type)&0x3; /* Picture type in instruction register */
|
|
// Only 2 bits are stored
|
|
/*
|
|
if(pVideo->NextInstr.Pct == 1)
|
|
{
|
|
DBG1('I');
|
|
}
|
|
if(pVideo->NextInstr.Pct == 2)
|
|
{
|
|
DBG1('P');
|
|
}
|
|
if(pVideo->NextInstr.Pct == 3)
|
|
{
|
|
DBG1('B');
|
|
}
|
|
*/
|
|
if ( pVideo->skipMode ) // We are on the second picture:
|
|
// the previous one will be
|
|
// skipped
|
|
pVideo->skipMode++;
|
|
else // !pVideo->skipMode. We skip a picture if
|
|
// pVideo->fastForward = 1 and on B pictures
|
|
// only
|
|
if ( pVideo->fastForward && ( pVideo->fieldMode < 2 ) )
|
|
{
|
|
pVideo->NotSkipped++;
|
|
|
|
if ( ( pVideo->pDecodedPict->pict_type == 3 ) // we are on a B picture
|
|
|| ( ( pVideo->NotSkipped > 5 ) && ( pVideo->pDecodedPict->pict_type == 2 ) ) ) // we are on a P picture
|
|
// // we are on a B
|
|
// picture
|
|
{
|
|
pVideo->NotSkipped = 0;
|
|
pVideo->skipMode = 1; // this picture will be skipped
|
|
}
|
|
}
|
|
/* pVideo->vbvDelay is 16 bits: O oxxx XX + X xooo OO */
|
|
comput1 = pVideo->hdrFirstWord << 5; /* VBV delay is 16 bits */
|
|
VideoReadHeaderDataFifo ( pVideo ); /* read next 16 bits */
|
|
comput1 = comput1 | ( pVideo->hdrFirstWord >> 11 );
|
|
if (( comput1 == 0 )||( comput1 >= 0x3000 ))
|
|
// 0x0 means that the pVideo->vbvDelay is not compliant with MPEG !
|
|
// 0xFFFF variable bitrate
|
|
comput1 = 0x3000; // we force it to an average
|
|
// pVideo->vbvDelay ...
|
|
temp = ( ( long ) comput1 * ( pVideo->StreamInfo.bitRate / ( 2048 ) ) ) / 90000L; /* 2048 = 8*256 ! */
|
|
|
|
if ( temp < 0x20 )
|
|
temp = 0x20;
|
|
if ( temp > 0x330 )
|
|
temp = 0x330;
|
|
|
|
pVideo->vbvDelay = (S16) temp;
|
|
if ( !pVideo->vbvReached ) /* BBT set to vbv value for the
|
|
* first picture */
|
|
{
|
|
VideoSetBBThresh(temp);
|
|
pVideo->intMask = 0x8; /* Enable buffer full interrupts */
|
|
}
|
|
|
|
temp = 10; /* number of bits - 1 not
|
|
* analysed in pVideo->hdrFirstWord */
|
|
if ( pVideo->StreamInfo.countGOP < 0x100 ) /* To init the GOP structure */
|
|
{ /* this is only done for display
|
|
* of the GOP structure */
|
|
if ( pVideo->StreamInfo.countGOP < 28 )
|
|
{
|
|
if ( pVideo->pDecodedPict->pict_type == 1 ) /* I picture */
|
|
pVideo->StreamInfo.firstGOP[pVideo->StreamInfo.countGOP] = 'I';
|
|
else if ( pVideo->pDecodedPict->pict_type == 2 ) /* P picture */
|
|
pVideo->StreamInfo.firstGOP[pVideo->StreamInfo.countGOP] = 'P';
|
|
else if ( pVideo->pDecodedPict->pict_type == 3 ) /* B picture *//* B
|
|
* picture */
|
|
pVideo->StreamInfo.firstGOP[pVideo->StreamInfo.countGOP] = 'B';
|
|
else
|
|
pVideo->StreamInfo.firstGOP[pVideo->StreamInfo.countGOP] = 'D'; /* D picture */
|
|
pVideo->StreamInfo.firstGOP[pVideo->StreamInfo.countGOP + 1] = 0;
|
|
}
|
|
pVideo->StreamInfo.countGOP++;
|
|
}
|
|
|
|
/* P or B picture forward vectors extraction */
|
|
if ( ( pVideo->pDecodedPict->pict_type == 2 ) ||
|
|
( pVideo->pDecodedPict->pict_type == 3 ) ) /* P or B picture */
|
|
{
|
|
|
|
/* full_pixel_forward_vector is one bit: 0 oxoo 00 */
|
|
if ( ( pVideo->hdrFirstWord & 0x400 ) != 0 )
|
|
pVideo->NextInstr.Ffh = 0x8; //Msb of FFH is 1
|
|
else
|
|
pVideo->NextInstr.Ffh = 0;
|
|
/* forward_f_code is 3 bits: 0 ooxx xooo 0 */
|
|
comput1 = ( pVideo->hdrFirstWord >> 7 ) & 0x7;
|
|
pVideo->NextInstr.Ffh = pVideo->NextInstr.Ffh | comput1;
|
|
temp = 6; /* number of bits - 1 not
|
|
* analysed in pVideo->hdrFirstWord */
|
|
}
|
|
|
|
/* B picture backward vector extraction */
|
|
if ( pVideo->pDecodedPict->pict_type == 3 ) /* B picture */
|
|
{
|
|
|
|
/* full_pixel_backward_vector is one bit: 00 oxoo 0 */
|
|
if ( ( pVideo->hdrFirstWord & 0x40 ) != 0 )
|
|
pVideo->NextInstr.Bfh = 0x8;// Msb of Bfh is 1
|
|
else
|
|
pVideo->NextInstr.Bfh = 0x0;// Msb of Bfh is 0
|
|
/* backward_f_code is 3 bits: 00 ooxx xooo */
|
|
comput1 = ( pVideo->hdrFirstWord >> 3 ) & 0x0007;
|
|
pVideo->NextInstr.Bfh = pVideo->NextInstr.Bfh | comput1;
|
|
temp = 2; /* number of bits - 1 not analysed in pVideo->hdrFirstWord */
|
|
}
|
|
|
|
|
|
/*
|
|
* If extra informations picture follow they must be extracted from
|
|
* the header FIFO
|
|
*/
|
|
/*
|
|
* it is not possible to restart the header search as the next
|
|
* header may be a picture one
|
|
*/
|
|
/*
|
|
* the research of the first Slice is made by polling of the header
|
|
* fifo
|
|
*/
|
|
while ( !pVideo->errCode && ( ( pVideo->hdrFirstWord & ( 1 << temp ) ) != 0 ) ) /* extra bit picture = 1 */
|
|
{ /* if extra bit picture = 1 , 8 bits follow */
|
|
if ( temp <= 8 )
|
|
{
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
temp = temp + 16;
|
|
}
|
|
temp = temp - 9; /* skip 8 bit of extra
|
|
* information picture */
|
|
} /* and next extra bit picture
|
|
* bit */
|
|
|
|
/*
|
|
* if extension or user data follow they must be extracted from the
|
|
* header
|
|
*/
|
|
pVideo->hdrFirstWord = pVideo->hdrFirstWord & ( ( 1 << temp ) - 1 );
|
|
if ( pVideo->hdrFirstWord != 0 ) {/* all remaining bits should be zero */
|
|
if ( !pVideo->errCode ) {
|
|
pVideo->errCode = PICT_HEAD; /* picture header should be followed by a start code (at least slice) */
|
|
}
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
if ( temp > 7 ) /* LSbyte of pVideo->hdrFirstWord is part of the next start code */
|
|
VideoNextStartCode (pVideo, 1 ); // already one byte into
|
|
// pVideo->hdrFirstWord
|
|
else
|
|
VideoNextStartCode (pVideo, 0 );
|
|
|
|
/*
|
|
* at this point pVideo->hdrFirstWord contains the next start code value in the
|
|
* MSByte
|
|
*/
|
|
while (!pVideo->errCode) {
|
|
if ( ( pVideo->hdrFirstWord & 0xFF00 ) == 0x0100 )
|
|
break; // we have reached the slice start code
|
|
else if ( ( pVideo->hdrFirstWord & 0xFF00 ) == USER )
|
|
VideoUser ( pVideo );
|
|
else if ( ( pVideo->hdrFirstWord & 0xFF00 ) == EXT ) // there can be several
|
|
// extension fields
|
|
VideoPictExtensionHeader ( pVideo );
|
|
else
|
|
break;
|
|
}
|
|
/*
|
|
* We have reached the first Slice start code: all parameters are
|
|
* ready for next decoding
|
|
*/
|
|
|
|
/* end of picture header + picture extensions decoding */
|
|
if ( ( !pVideo->fieldMode && ( pVideo->skipMode != 1 ) ) || ( pVideo->fieldMode && ( !pVideo->skipMode || ( pVideo->skipMode == 3 ) ) ) )
|
|
{
|
|
VideoSetRecons ( pVideo ); // initialise RFP, FFP and BFP
|
|
if ( ( pVideo->fieldMode == 0 ) || ( pVideo->fieldMode == 2 ) ) // we are on a frame
|
|
// picture or the first
|
|
// field of a field
|
|
// picture
|
|
VideoDisplayCtrl (pVideo); // computes the next frame to
|
|
// display
|
|
}
|
|
|
|
// implementation of 3:2 pull-down functionality on MPEG1 bit
|
|
// streams
|
|
// encoded at 23.97Hz or 24 Hz and displayed at 60 Hz.
|
|
// 3:2 pull-down on MPEG2 bit streams must be controlled with
|
|
// "repeat_first_field" bit
|
|
if ( ( !pVideo->StreamInfo.modeMPEG2 ) && ( ( pVideo->StreamInfo.frameRate == 1 ) || ( pVideo->StreamInfo.frameRate == 2 ) ) )
|
|
{
|
|
if ( pVideo->pCurrDisplay->nb_display_field == 2 )
|
|
{ /* same field polarity for the
|
|
* next frame */
|
|
pVideo->pNextDisplay->nb_display_field = 3;
|
|
if ( pVideo->pCurrDisplay->first_field == TOP )
|
|
pVideo->pNextDisplay->first_field = TOP;
|
|
else
|
|
pVideo->pNextDisplay->first_field = BOT;
|
|
}
|
|
else
|
|
{ // previous picture was
|
|
// displayed 3 times //
|
|
// the first field polarity is
|
|
// changing
|
|
pVideo->pNextDisplay->nb_display_field = 2;
|
|
if ( pVideo->pCurrDisplay->first_field == TOP )
|
|
pVideo->pNextDisplay->first_field = BOT;
|
|
else
|
|
pVideo->pNextDisplay->first_field = TOP;
|
|
}
|
|
}
|
|
|
|
|
|
if ( pVideo->vbvReached ) // enable next instruction if
|
|
// not skipping a picture
|
|
{
|
|
if ( !pVideo->skipMode ) // no skipped picture
|
|
{
|
|
pVideo->NextInstr.Exe = 1; // enable EXE bit
|
|
pVideo->NextInstr.Skip = 0;
|
|
pVideo->currCommand = 0; // reset skip bits
|
|
}
|
|
else if ( ( pVideo->skipMode == 2 ) && !pVideo->fieldMode )
|
|
// skip == 2: We are on the picture following a skipped one
|
|
// the instruction can be stored with associated skip bits
|
|
// in CMD
|
|
{
|
|
pVideo->currCommand = 0x10; // pVideo->skipMode 1 picture
|
|
pVideo->NextInstr.Exe = 1; // enable EXE bit
|
|
pVideo->NextInstr.Skip = 1; // skip 1 picture
|
|
pVideo->skipMode = 0;
|
|
if ( pVideo->DecodeMode != FAST_MODE )
|
|
pVideo->fastForward = 0; /* allows to skip only one
|
|
* picture */
|
|
}
|
|
else if ( pVideo->skipMode == 3 )
|
|
{
|
|
// we are on the picture following two skipped fields
|
|
pVideo->currCommand = 0x20; // pVideo->skipMode 2 fields
|
|
pVideo->NextInstr.Exe = 1; // enable EXE bit
|
|
pVideo->NextInstr.Skip = 2; // Skip 2 fields
|
|
pVideo->skipMode = 0;
|
|
if ( pVideo->DecodeMode != FAST_MODE )
|
|
pVideo->fastForward = 0; /* allows to skip only one
|
|
* picture */
|
|
}
|
|
|
|
/*
|
|
* store the next instruction if we are on the good field to do
|
|
* it
|
|
*/
|
|
if ( ( ( pVideo->pictDispIndex >= pVideo->pCurrDisplay->nb_display_field - 1 ) && !pVideo->fieldMode )
|
|
|| ( ( pVideo->fieldMode == 2 ) && ( pVideo->pictDispIndex >= pVideo->pCurrDisplay->nb_display_field - 2 ) ) )
|
|
{
|
|
if ( pVideo->pNextDisplay->first_field != pVideo->currField )
|
|
VideoWaitDec (pVideo); // this is the opposite phase:
|
|
// put decoder in wait mode
|
|
else
|
|
// store the next instruction that will be taken into
|
|
// account on the next VSYNC
|
|
VideoStoreINS (pVideo); // store next INS in case where
|
|
// enough VSYNC already occured
|
|
}
|
|
else if ( pVideo->fieldMode == 1 )
|
|
VideoStoreINS ( pVideo );
|
|
}
|
|
|
|
// clear Header hit flag due to polling of extension or user bits
|
|
// after the picture start code
|
|
// but keep track of possible other interrupt
|
|
comput1 = VideoRead ( ITS ) << 8;
|
|
comput1 = ( comput1 | VideoRead ( ITS + 1 ) ) & 0xFFFE; // allows to clear the
|
|
// Header hit bit
|
|
pVideo->intStatus = ( pVideo->intStatus | comput1 ) & pVideo->intMask;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
/***************************************************************/
|
|
/* This is an extension start code following a picture */
|
|
/* In MPEG2 bit stream, this start code can be: */
|
|
/* Picture Coding (always) */
|
|
/* Quant matrix (optional) */
|
|
/* Picture Pan & Scan (optional) */
|
|
/* Picture Scalable (optional) : not tested yet */
|
|
/***************************************************************/
|
|
VOID VideoPictExtensionHeader(PVIDEO pVideo)
|
|
{
|
|
U16 comput1, i;
|
|
S16 compute; // need to be int!!
|
|
U8 QuantTab[QUANT_TAB_SIZE];
|
|
|
|
/* extension Id is 4 bits: 00 X0 */
|
|
comput1 = pVideo->hdrFirstWord & 0xF0;
|
|
switch ( comput1 )
|
|
{
|
|
/******* picture coding extension *******/
|
|
case PICT_COD:
|
|
if ( pVideo->StreamInfo.modeMPEG2 )
|
|
{
|
|
// clear top field first,forward and backward f_code,
|
|
// motion vectors flag
|
|
pVideo->NextInstr.Tff = 0; //pVideo->nextInstr1 & 0x403E;
|
|
pVideo->NextInstr.Bfh = 0;
|
|
pVideo->NextInstr.Ffh = 0;
|
|
pVideo->NextInstr.Cmv = 0;
|
|
|
|
pVideo->NextInstr.Pst = 0;
|
|
pVideo->NextInstr.Bfv = 0;
|
|
pVideo->NextInstr.Ffv = 0;
|
|
pVideo->NextInstr.Dcp = 0;
|
|
pVideo->NextInstr.Frm = 0;
|
|
pVideo->NextInstr.Qst = 0;
|
|
pVideo->NextInstr.Azz = 0;
|
|
pVideo->NextInstr.Ivf = 0;
|
|
|
|
// forward_horizontal_f_code is 4 bits: 00 0X
|
|
comput1 = pVideo->hdrFirstWord & 0xF;
|
|
pVideo->NextInstr.Ffh = comput1;
|
|
|
|
// forward_vertical_f_code is 4 bits: X0 00
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
comput1 = pVideo->hdrFirstWord & 0xF000;
|
|
comput1 = comput1 >> 12;
|
|
pVideo->NextInstr.Ffv = comput1;
|
|
|
|
// backward_horizontal_f_code is 4 bits: 0X 00
|
|
comput1 = pVideo->hdrFirstWord & 0xF00;
|
|
comput1 = comput1 >>8;
|
|
pVideo->NextInstr.Bfh = comput1;
|
|
|
|
// backward_vertical_f_code is 4bits: 00 X0
|
|
comput1 = pVideo->hdrFirstWord & 0xF0;
|
|
comput1 = comput1 >> 4;
|
|
pVideo->NextInstr.Bfv = comput1;
|
|
|
|
// intra DC precision is 2 bits: 00 0 xx00
|
|
comput1 = pVideo->hdrFirstWord & 0x0C;
|
|
if ( comput1 == 0xC ) {
|
|
if ( !pVideo->errCode ) {
|
|
pVideo->errCode = DC_PREC; // 11 bit DC precision
|
|
}
|
|
SetErrorCode(ERR_INTRA_DC_PRECISION);
|
|
}
|
|
pVideo->NextInstr.Dcp = ( comput1 >> 2 );
|
|
|
|
// picture structure is 2 bits: 00 0 ooxx
|
|
pVideo->pDecodedPict->pict_struc = pVideo->hdrFirstWord & 0x3;
|
|
pVideo->NextInstr.Pst = pVideo->pDecodedPict->pict_struc ;
|
|
if ( pVideo->pDecodedPict->pict_struc == 3 ) // frame picture
|
|
pVideo->fieldMode = 0;
|
|
else // field picture
|
|
if ( pVideo->fieldMode == 2 )
|
|
pVideo->fieldMode = 1; // second field
|
|
else
|
|
{
|
|
pVideo->fieldMode = 2; // first field
|
|
if ( pVideo->pDecodedPict->pict_struc == 2 ) // bottom field is the
|
|
// first field
|
|
pVideo->pDecodedPict->first_field = BOT;
|
|
}
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
|
|
// top_field_first bit is one bit: xooo 0 00
|
|
// first_field is already initialised to TOP (beginning
|
|
// of picture header)
|
|
if ( ( !pVideo->StreamInfo.progSeq ) && ( pVideo->pDecodedPict->pict_struc == 3 ) )
|
|
{ // this is an interlaced frame
|
|
// picture
|
|
if ( ( ( pVideo->hdrFirstWord & 0x8000 ) != 0 ) ) // top field first
|
|
pVideo->NextInstr.Tff = 1; // set top_field_first
|
|
else // top_field_first already reset
|
|
// into pVideo->NextInstr
|
|
pVideo->pDecodedPict->first_field = BOT; // bottom field is BOT
|
|
// field
|
|
}
|
|
if ( pVideo->vbvReached == 0 ) // pre-initialise for start of
|
|
// the first decoding task
|
|
{ // on the good field polarity
|
|
pVideo->pictArray[0].first_field = pVideo->pDecodedPict->first_field;
|
|
pVideo->pictArray[1].first_field = pVideo->pDecodedPict->first_field;
|
|
pVideo->pictArray[2].first_field = pVideo->pDecodedPict->first_field;
|
|
pVideo->pictArray[3].first_field = pVideo->pDecodedPict->first_field;
|
|
}
|
|
|
|
// frame_pred_frame_DCT is one bit: oxoo 0 00
|
|
if ( ( pVideo->hdrFirstWord & 0x4000 ) != 0 )
|
|
pVideo->NextInstr.Frm = 1 ; // frame DCT and 16x16
|
|
// prediction
|
|
|
|
// concealment_motion_vectors flag is one bit: ooxo 0
|
|
// 00
|
|
if ( pVideo->hdrFirstWord & 0x2000 )
|
|
pVideo->NextInstr.Cmv = 1;
|
|
|
|
// qscale_type is one bit: ooox 0 00
|
|
if ( ( pVideo->hdrFirstWord & 0x1000 ) != 0 )
|
|
pVideo->NextInstr.Qst = 1; // non linear quantizer
|
|
// scale
|
|
|
|
// intra_vlc_format is one bit: 0 xooo 00
|
|
if ( ( pVideo->hdrFirstWord & 0x800 ) != 0 )
|
|
pVideo->NextInstr.Ivf = 1; // alternative intra VLC
|
|
// table
|
|
|
|
// alternate scan bit: 0 oxoo 00
|
|
if ( ( pVideo->hdrFirstWord & 0x400 ) != 0 )
|
|
pVideo->NextInstr.Azz = 1; // alternative scan
|
|
|
|
// repeat_first_field is one bit: 0 ooxo 00
|
|
// A 2 field picture is considered as one picture
|
|
// displayed twice
|
|
pVideo->pDecodedPict->nb_display_field = 2; // display picture
|
|
// during 2 fields
|
|
// period
|
|
if ( pVideo->pDecodedPict->pict_struc == 3 ) // frame picture
|
|
{
|
|
if ( pVideo->hdrFirstWord & 0x200 ) // repeat first field
|
|
pVideo->pDecodedPict->nb_display_field = 3; // display picture
|
|
// during 3 fields
|
|
// period
|
|
}
|
|
|
|
// chroma_postprocessing_type is one bit: 0 ooox 00
|
|
if ( ( pVideo->hdrFirstWord & 0x100 ) )
|
|
{
|
|
// use the field repeat mode for chroma vertical
|
|
// filter (if enabled)
|
|
pVideo->fullVerFilter = pVideo->fullVerFilter | 0x2;
|
|
pVideo->currDCF = pVideo->currDCF | 0x2;
|
|
}
|
|
else
|
|
{
|
|
// use the line repeat mode for chroma vertical
|
|
// filter (if enabled)
|
|
pVideo->fullVerFilter = pVideo->fullVerFilter & 0xFFFD;
|
|
pVideo->currDCF = pVideo->currDCF & 0xFFFD;
|
|
}
|
|
VideoWrite ( DCF, 0 );
|
|
VideoWrite ( DCF + 1, pVideo->currDCF );
|
|
// progressive_frame is one bit: 00 xooo 0
|
|
|
|
// composite_display_flag is one bit: 00 oxoo 0
|
|
if ( pVideo->hdrFirstWord & 0x40 )
|
|
{
|
|
// v_axis is one bit: 00 ooxo 0
|
|
// field_sequence is 3 bits: 00 ooox xxoo
|
|
// sub_carrier is one bit: 00 0 ooxo
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
// burst_amplitude is 7 bit: 00 0 ooox + X xooo 00
|
|
// sub_carrier_phase is 8 bits: 0 oxxx X xooo
|
|
// check the 3 lsb of pVideo->hdrFirstWord: next info must be a
|
|
// start code
|
|
if ( pVideo->hdrFirstWord & 0x7 ) {
|
|
if ( !pVideo->errCode ) {
|
|
pVideo->errCode = PICT_HEAD;
|
|
}
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
VideoNextStartCode (pVideo, 0 );
|
|
}
|
|
else
|
|
{
|
|
if ( pVideo->hdrFirstWord & 0x3F ) {
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = PICT_HEAD;
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
VideoNextStartCode (pVideo, 0 );
|
|
}
|
|
} // end of if pVideo->StreamInfo.modeMPEG2
|
|
break;
|
|
|
|
|
|
/******* Quantization table extension *******/
|
|
case QUANT_EXT:
|
|
/* load_intra_quantizer_matrix is one bit: 00 0 xooo */
|
|
if ( ( pVideo->hdrFirstWord & 0x8 ) != 0 )
|
|
{ /* Load intra quantizer matrix */
|
|
/* two quant values are 16 bits: 00 0 oxxx + XX X xooo */
|
|
// Read Non Default Intra Quant Table
|
|
for ( i = 0; i < (QUANT_TAB_SIZE/2) ; i++)
|
|
{
|
|
compute = pVideo->hdrFirstWord << 13;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
compute = compute | ( pVideo->hdrFirstWord >> 3 );
|
|
QuantTab[2*i] = (U8)( compute >> 8 );
|
|
QuantTab[2*i+1] = (U8)( compute & 0xFF );
|
|
}
|
|
// Load Intra Quant Tables
|
|
VideoLoadQuantTables(pVideo , TRUE , QuantTab );
|
|
pVideo->defaultTbl = pVideo->defaultTbl & 0xE; // bit 0 = 0 : no default table
|
|
// in the chip */
|
|
}
|
|
/* load_non_intra_quantizer_matrix is one bit: 00 0 oxoo */
|
|
if ( ( pVideo->hdrFirstWord & 0x4 ) != 0 )
|
|
{ /* Load non intra quantizer matrix */
|
|
// Read Non Default Non Intra Quant Table
|
|
for ( i = 0; i < (QUANT_TAB_SIZE/2) ; i++)
|
|
{
|
|
compute = pVideo->hdrFirstWord << 14;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
compute = compute | ( pVideo->hdrFirstWord >> 2 );
|
|
QuantTab[2*i] = (U8)( compute >> 8 );
|
|
QuantTab[2*i+1] = (U8)( compute & 0xFF );
|
|
}
|
|
// Load Non Intra Quant Tables
|
|
VideoLoadQuantTables(pVideo , FALSE , QuantTab );
|
|
pVideo->defaultTbl = pVideo->defaultTbl & 0xD; /* bit 1 = 0 : no default
|
|
* non-intra matrix */
|
|
}
|
|
// check the 2 lsb of pVideo->hdrFirstWord: next info must be a start
|
|
// code
|
|
if ( pVideo->hdrFirstWord & 0x3 ) {
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = PICT_HEAD;
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
VideoNextStartCode (pVideo, 0 );
|
|
break;
|
|
|
|
|
|
/******* picture pan and scan extension *******/
|
|
case PICT_PSV:
|
|
/**************************************************************/
|
|
/* The programmation of the STi3500 offsets is given by: */
|
|
/* PSV = integer part of (pVideo->StreamInfo.horSize/2 - pVideo->StreamInfo.horDimension/2 + offset) */
|
|
/*
|
|
* LSO = fractional part of (pVideo->StreamInfo.horSize/2 - pVideo->StreamInfo.horDimension/2 +
|
|
* offset)
|
|
*/
|
|
/**************************************************************/
|
|
|
|
/* pan_horizontal_offset_integer is 12 bits: 00 0X + XX 00 */
|
|
pVideo->latestPanHor = ( pVideo->hdrFirstWord & 0xF ) << 12;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->latestPanHor = pVideo->latestPanHor | ( ( pVideo->hdrFirstWord & 0xFF00 ) >> 4 );
|
|
// pan_horizontal_offset has been multiplied by 16
|
|
/* pan_horizontal_offset_sub_pixel is 4 bits: 00 X0 */
|
|
/* that are concatenated with the integer part */
|
|
pVideo->latestPanHor = pVideo->latestPanHor | ( ( pVideo->hdrFirstWord & 0xF0 ) >> 4 );
|
|
// to simplify, the 2 last instructions can be concatenated
|
|
// in:
|
|
// pVideo->latestPanHor = pVideo->latestPanHor | ((pVideo->hdrFirstWord & 0xFFF0)
|
|
// >> 4);
|
|
// note that pVideo->latestPanHor is a signed int
|
|
|
|
// marker bit 00 0 xooo: just skipped
|
|
|
|
/*
|
|
* pan_vertical_offset_integer is 12 bits: 00 0oxxx + XX
|
|
* xooo0
|
|
*/
|
|
pVideo->latestPanVer = ( pVideo->hdrFirstWord & 0x7 ) << 13;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
|
|
/* pan_vertical_offset_sub_pixel is 4 bits: 00 oxxx xooo */
|
|
// they are linked with the integer part
|
|
pVideo->latestPanVer = pVideo->latestPanVer | ( ( pVideo->hdrFirstWord & 0xFFF8 ) >> 3 );
|
|
|
|
// write pan vectors into the decoded picture structure
|
|
if ( ( pVideo->fieldMode == 0 ) || ( pVideo->fieldMode == 2 ) ) // frame picture or
|
|
// first field
|
|
{
|
|
pVideo->pDecodedPict->pan_hor_offset[0] = pVideo->latestPanHor;
|
|
pVideo->pDecodedPict->pan_vert_offset[0] = pVideo->latestPanVer;
|
|
}
|
|
else
|
|
{ // the offset of second field of
|
|
// a field picture is stored
|
|
// // on the second offset
|
|
// position of the same variable
|
|
pVideo->pDecodedPict->pan_hor_offset[1] = pVideo->latestPanHor;
|
|
pVideo->pDecodedPict->pan_vert_offset[1] = pVideo->latestPanVer;
|
|
}
|
|
|
|
// marker bit 00 0 oxoo
|
|
|
|
if ( pVideo->StreamInfo.progSeq ) // a progressive sequence is
|
|
// always displayed with the
|
|
// same pan and scan offset
|
|
{
|
|
pVideo->pDecodedPict->pan_hor_offset[1] = pVideo->latestPanHor;
|
|
pVideo->pDecodedPict->pan_vert_offset[1] = pVideo->latestPanVer;
|
|
pVideo->pDecodedPict->pan_hor_offset[2] = pVideo->latestPanHor;
|
|
pVideo->pDecodedPict->pan_vert_offset[2] = pVideo->latestPanVer;
|
|
if ( pVideo->hdrFirstWord & 0x3 ) {
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = PICT_HEAD;
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
VideoNextStartCode (pVideo, 0 );
|
|
}
|
|
|
|
|
|
else if ( !pVideo->StreamInfo.progSeq && ( pVideo->pDecodedPict->pict_struc == 3 ) )
|
|
// Frame picture, not progressive sequence: 2 or 3 pan
|
|
// offsets
|
|
{
|
|
// extract second pan and scan offset
|
|
|
|
/*
|
|
* pan_horizontal_offset_integer is 12 bits: 00 0ooxx +
|
|
* XX xxoo0
|
|
*/
|
|
pVideo->latestPanHor = ( pVideo->hdrFirstWord & 0x3 ) << 14;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->latestPanHor = pVideo->latestPanHor | ( ( pVideo->hdrFirstWord & 0xFFC0 ) >> 2 );
|
|
// pan_horizontal_offset has been multiplied by 16
|
|
/*
|
|
* pan_horizontal_offset_sub_pixel is 4 bits: 00 ooxx
|
|
* xxoo
|
|
*/
|
|
/* that are concatenated with the integer part */
|
|
pVideo->latestPanHor = pVideo->latestPanHor | ( ( pVideo->hdrFirstWord & 0x3C ) >> 2 );
|
|
pVideo->pDecodedPict->pan_hor_offset[1] = pVideo->latestPanHor;
|
|
|
|
// marker bit 00 0 ooxo
|
|
|
|
/*
|
|
* pan_vertical_offset_integer is 12 bits: 00 0ooox +
|
|
* XX xxxo0
|
|
*/
|
|
pVideo->latestPanVer = ( pVideo->hdrFirstWord & 0x1 ) << 15;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
/*
|
|
* pan_vertical_offset_sub_pixel is 4 bits: 00 ooox
|
|
* xxxo
|
|
*/
|
|
// concatenated with the integer part
|
|
pVideo->latestPanVer = pVideo->latestPanVer | ( ( pVideo->hdrFirstWord & 0xFFFE ) >> 1 );
|
|
pVideo->pDecodedPict->pan_vert_offset[1] = pVideo->latestPanVer;
|
|
|
|
// marker bit 00 0 ooox
|
|
|
|
if ( pVideo->pDecodedPict->nb_display_field != 3 )
|
|
VideoNextStartCode (pVideo, 0 );
|
|
else
|
|
{ // 3 pan & scan offsets
|
|
/* pan_horizontal_offset_integer is 12 bits: XX X0 */
|
|
/* pan_horizontal_offset_sub_pixel is 4 bits: 00 0X */
|
|
/* they are concatenated in a single word */
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->latestPanHor = pVideo->hdrFirstWord;
|
|
pVideo->pDecodedPict->pan_hor_offset[2] = pVideo->latestPanHor;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
|
|
// marker bit xooo0 00
|
|
|
|
/*
|
|
* pan_vertical_offset_integer is 12 bits: oxxx X X
|
|
* xooo
|
|
*/
|
|
/*
|
|
* pan_vertical_offset_sub_pixel is 4 bits: 00 0
|
|
* oxxx + xooo 0 00
|
|
*/
|
|
pVideo->latestPanVer = ( pVideo->hdrFirstWord & 0x7FFF ) << 1;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
pVideo->latestPanVer = ( pVideo->hdrFirstWord & 0x8000 ) >> 15;
|
|
pVideo->pDecodedPict->pan_vert_offset[2] = pVideo->latestPanVer;
|
|
|
|
// marker bit oxoo 0 00
|
|
|
|
if ( pVideo->hdrFirstWord & 0x3FFF ) {
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = PICT_HEAD;
|
|
SetErrorCode(ERR_PICTURE_HEADER);
|
|
}
|
|
VideoNextStartCode (pVideo, 1 );
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
/******* picture scalable extension *******/
|
|
case PICT_SCAL:
|
|
pVideo->hdrFirstWord = 0x0100; // not supported: just leave the
|
|
// test
|
|
break;
|
|
|
|
|
|
/******* other extension start codes *******/
|
|
default:
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = BAD_EXT; // extension start code not at the good location !!
|
|
SetErrorCode(ERR_BAD_EXTENSION_SC);
|
|
break;
|
|
} // end of switch
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// USER HEADER routine
|
|
//----------------------------------------------------------------------------
|
|
/* this routine just bypasses all the bytes of the user header */
|
|
/* and is exit with the next start code value into pVideo->hdrFirstWord XX00 */
|
|
VOID VideoUser(PVIDEO pVideo)
|
|
{
|
|
long toto;
|
|
int i;
|
|
|
|
toto = pVideo->hdrFirstWord << 16;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
toto = toto | pVideo->hdrFirstWord;
|
|
while ( ( ( toto & 0x00FFFFFFL ) != 0x00000001L ) &&
|
|
( ( toto & 0xFFFFFF00L ) != 0x00000100L ) )
|
|
{
|
|
toto = toto << 16;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
toto = toto | pVideo->hdrFirstWord;
|
|
}
|
|
if ( ( toto & 0x00FFFFFFL ) == 0x00000001L )
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
else
|
|
{ // pVideo->hdrFirstWord == 01XX
|
|
if ( !pVideo->hdrPos ) // there is nothing into pVideo->hdrNextWord
|
|
{
|
|
pVideo->hdrPos = 8;
|
|
pVideo->hdrNextWord = ( pVideo->hdrFirstWord & 0xFF ) << 8;
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
}
|
|
else
|
|
{ // pVideo->hdrPos = 8: the next
|
|
// byte is into pVideo->hdrNextWord
|
|
pVideo->hdrFirstWord = ( pVideo->hdrFirstWord << 8 ) | ( pVideo->hdrNextWord >> 8 );
|
|
pVideo->hdrPos = 0;
|
|
}
|
|
}
|
|
i = VideoRead ( ITS ) << 8; // allows to clear the Header
|
|
// hit bit
|
|
i = ( i | VideoRead ( ITS + 1 ) ) & 0xFFFE; // allows to clear the
|
|
// Header hit bit
|
|
pVideo->intStatus = ( pVideo->intStatus | i ) & pVideo->intMask;
|
|
}
|
|
|
|
//------------------------------- End of File --------------------------------
|