Rev 2 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* readfile.c --
*
* Procedures concerned with reading data and parsing
* start codes from MPEG files.
*
*/
/*
* Copyright (c) 1995 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* Portions of this software Copyright (c) 1995 Brown University.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement
* is hereby granted, provided that the above copyright notice and the
* following two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
* UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include "video.h"
#include "proto.h"
#include <sys/types.h>
/*#include <signal.h> TO FIX!!! */
#ifndef MIPS
#include <netinet/in.h>
#else
#include <bsd/netinet/in.h>
#endif
#include "util.h"
#include "dither.h"
#ifdef __STDC__
#include <stdlib.h>
#include <string.h>
#endif
/*
*
*
*/
extern int x_fseek
(FILE
*file
, long where
, int from
);
extern size_t x_fread
(void *buffer
, size_t size
, size_t n
, FILE
*file
);
#define fread x_fread
#define fseek x_fseek
/*
Changes to make the code reentrant:
deglobalized: totNumFrames, realTimeStart, stream id vars, Prase_done,
swap, seekValue, input, EOF_flag, ReadPacket statics, sys_layer,
bitOffset, bitLength, bitBuffer, curVidStream
removed: [aud,sys,vid]Bytes
Additional changes:
get rid on ANSI C complaints about shifting
-lsh@cs.brown.edu (Loring Holden)
*/
/* Silly Constants.... */
#define PACK_START_CODE ((unsigned int)0x000001ba)
#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb)
#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00)
#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100)
#define ISO_11172_END_CODE ((unsigned int)0x000001b9)
#define PACK_HEADER_SIZE 8
#define STD_AUDIO_STREAM_ID ((unsigned char) 0xb8)
#define STD_VIDEO_STREAM_ID ((unsigned char) 0xb9)
#define MIN_STREAM_ID_ID ((unsigned char) 0xbc)
#define RESERVED_STREAM_ID ((unsigned char) 0xbc)
#define PRIVATE_STREAM_1_ID ((unsigned char) 0xbd)
#define PADDING_STREAM_ID ((unsigned char) 0xbe)
#define PRIVATE_STREAM_2_ID ((unsigned char) 0xbf)
#define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000
#define MUX_RATE_SCALE_FACTOR 50
#define MAX_STREAMS 8
#define NOT_PACKET_ID ((unsigned char) 0xff)
#define KILL_BUFFER ((unsigned char) 0xfe)
/*
*--------------------------------------------------------------
*
* get_more_data --
*
* Called by get_more_data to read in more data from
* video MPG files (non-system-layer)
*
* Results:
* Input buffer updated, buffer length updated.
* Returns 1 if data read, 0 if EOF, -1 if error.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int
get_more_data
(vid_stream
)
VidStream
*vid_stream
;
{
unsigned int **bs_ptr
=&vid_stream
->buf_start
;
int *max_length
=&vid_stream
->max_buf_length
;
int *length_ptr
=&vid_stream
->buf_length
;
unsigned int **buf_ptr
=&vid_stream
->buffer
;
int ioBytes
, data
, result
;
unsigned char byte
;
unsigned int *mark
;
int sys_layer
= vid_stream
->sys_layer
;
if (sys_layer
== 0) {
return pure_get_more_data
(*bs_ptr
,
*max_length
,
length_ptr
,
buf_ptr
,
vid_stream
);
}
if (sys_layer
== -1) {
/* Time to init ourselves */
vid_stream
->swap
= (htonl
(1) != 1);
mark
= *bs_ptr
;
ioBytes
= fread(&data
, 1, 4, vid_stream
->input
);
if (ioBytes
!= 4) {
return 0;
}
data
= ntohl
(data
);
if ( (data
== PACK_START_CODE
) || (data
== SYSTEM_HEADER_START_CODE
) ) {
got_sys
:
/* Yow, a System Layer Stream. Much harder to parse. Call in the
specialist.... */
fprintf(stderr
,"This is an MPEG System Layer Stream. ");
fprintf(stderr
,"Audio is not played.\n");
vid_stream
->sys_layer
= 1;
result
= read_sys
(vid_stream
,(unsigned int) data
);
return result
;
} else if (data
== SEQ_START_CODE
) {
got_seq
:
/* No system Layer junk, just pretent we didn't peek,
and hereafter just call pure_get_more_data */
vid_stream
->sys_layer
= 0;
**bs_ptr
= data
;
*length_ptr
= 1;
result
= pure_get_more_data
(*bs_ptr
, *max_length
,
length_ptr
, buf_ptr
, vid_stream
);
*buf_ptr
= *bs_ptr
;
return result
;
} else {
int state
;
fprintf(stderr
, "Junk at start of stream, searching for start code\n");
state
= 0;
while (TRUE
) {
if ((ioBytes
= fread(&byte
, 1, 1, vid_stream
->input
)) != 1) return 0;
if (byte
== 0) {
if (state
< 2) state
++;
} else if ((byte
== 1) && (state
== 2)) {
state
++;
} else {
state
= 0;
}
if (state
== 3) {
if ((ioBytes
= fread(&byte
, 1, 1, vid_stream
->input
)) != 1) return 0;
data
= ((unsigned int) byte
+ 0x100);
switch (data
) {
case SEQ_START_CODE
:
goto got_seq
;
case PACK_START_CODE
:
case SYSTEM_HEADER_START_CODE
:
goto got_sys
;
default:
/* keep looking */
state
=0;
}
}
}}
}
/* A system layer stream (called after the 1st time), call the specialist */
result
= read_sys
(vid_stream
,0);
return result
;
}
/*
*-------------------------------------------------------------
*
* clear_data_stream
*
* Empties out internal buffers
*
*-------------------------------------------------------------
*/
void
clear_data_stream
(vid_stream
)
VidStream
*vid_stream
;
{
/* Only internal buffer is in ReadPacket */
if (vid_stream
->sys_layer
) {
ReadPacket
(KILL_BUFFER
, vid_stream
);
}
}
/*
*-------------------------------------------------------------
*
* SeekStream
*
* Goto an offset in the steam
*
*-------------------------------------------------------------
*/
void
SeekStream
(vid_stream
)
VidStream
*vid_stream
;
{
int errno
;
int code
;
if (vid_stream
->seekValue
< 0) return; /* done seeking */
#ifdef SEEK_SET
errno
= fseek(vid_stream
->input
, vid_stream
->seekValue
, SEEK_SET
);
#else
errno
= fseek(vid_stream
->input
, vid_stream
->seekValue
, 0);
#endif
if (errno
!= 0) {
fprintf(stderr
,"Error in seek (%d)\n",errno
);
perror("mpeg_play");
}
vid_stream
->seekValue
= 0-vid_stream
->seekValue
;
vid_stream
->totNumFrames
= 0;
/* clear that buffer */
vid_stream
->buffer
= vid_stream
->buf_start
;
vid_stream
->buf_length
= 0;
vid_stream
->bit_offset
= 0;
/* Find a decent start code */
restart
:
NO_ZEROS
:
switch(fgetc(vid_stream
->input
)) {
case 0: goto ONE_ZERO
;
case EOF
: goto EOF_FOUND
;
default: goto NO_ZEROS
;
}
ONE_ZERO
:
switch(fgetc(vid_stream
->input
)) {
case 0: goto TWO_ZEROS
;
case EOF
: goto EOF_FOUND
;
default: goto NO_ZEROS
;
}
TWO_ZEROS
:
switch(fgetc(vid_stream
->input
)) {
case 0x01: goto CODE_FOUND
;
case 0x00: goto TWO_ZEROS
;
case EOF
: goto EOF_FOUND
;
default: goto NO_ZEROS
;
}
CODE_FOUND
:
code
= 0x00000100+fgetc(vid_stream
->input
);
if (vid_stream
->sys_layer
) {
clear_data_stream
(vid_stream
);
if (((code
& PACKET_START_CODE_MASK
) == PACKET_START_CODE_PREFIX
) &&
((code
& 0xff) >= 0xbc)) {
read_sys
(vid_stream
, code
);
while (TRUE
) {
next_start_code
(vid_stream
);
show_bits32
(code
);
if ((code
== SEQ_START_CODE
) ||
(code
== GOP_START_CODE
)) return;
flush_bits32
;
}
}
} else {
if ((code
== SEQ_START_CODE
) ||
(code
== GOP_START_CODE
)) {
*vid_stream
->buffer
= code
;
vid_stream
->buf_length
= 1;
return;
}
}
goto restart
;
EOF_FOUND
: /* received EOF */
fprintf(stderr
, "Hit EOF after seeking (offset %ld)\n",
ftell(vid_stream
->input
));
exit(1);
}
/*
*--------------------------------------------------------------
*
* pure_get_more_data --
* (get_more_data from ver 2.0 with swap added)
*
* Called by get_more_data to read in more data from
* video MPG files (non-system-layer)
*
* Results:
* Input buffer updated, buffer length updated.
* Returns 1 if data read, 0 if EOF, -1 if error.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int
pure_get_more_data
(buf_start
, max_length
, length_ptr
, buf_ptr
, vid_stream
)
unsigned int *buf_start
;
int max_length
;
int *length_ptr
;
unsigned int **buf_ptr
;
VidStream
*vid_stream
;
{
int length
, num_read
, i
;
unsigned int request
;
unsigned char *buffer
, *mark
;
unsigned int *lmark
;
BOOLEAN swap
=vid_stream
->swap
;
if (vid_stream
->EOF_flag
) return 0;
length
= *length_ptr
;
buffer
= (unsigned char *) *buf_ptr
;
if (length
> 0) {
memcpy((unsigned char *) buf_start
, buffer
, (unsigned int) (length
*4));
mark
= ((unsigned char *) (buf_start
+ length
));
}
else {
mark
= (unsigned char *) buf_start
;
length
= 0;
}
request
= (max_length
-length
)*4;
num_read
= fread(mark
, 1, request
, vid_stream
->input
);
/* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */
{
int num_read_rounded
;
unsigned char *index
;
num_read_rounded
= 4*(num_read
/4);
/* this can happen only if num_read<request; i.e. end of file reached */
if ( num_read_rounded
< num_read
) {
num_read_rounded
= 4*( num_read
/4+1 );
/* fill in with zeros */
for( index
=mark
+num_read
; index
<mark
+num_read_rounded
; *(index
++)=0 );
/* advance to the next 4-byte boundary */
num_read
= num_read_rounded
;
}
}
if (num_read
< 0) {
return -1;
} else if (num_read
== 0) {
*buf_ptr
= buf_start
;
/* Make 32 bits after end equal to 0 and 32
* bits after that equal to seq end code
* in order to prevent messy data from infinite
* recursion.
*/
*(buf_start
+ length
) = 0x0;
*(buf_start
+ length
+1) = SEQ_END_CODE
;
vid_stream
->EOF_flag
= 1;
return 0;
}
lmark
= (unsigned int *) mark
;
num_read
= num_read
/4;
if (swap
) {
for (i
= 0; i
< num_read
; i
++) {
*lmark
= htonl
(*lmark
);
lmark
++;
}
}
*buf_ptr
= buf_start
;
*length_ptr
= length
+ num_read
;
return 1;
}
/*
Here is the specialist....
Code is adapted from our program demux....
A bunch of this needs to be #ifdef ANALYSIS'ed
define __SYSREAD_LOGGING_ON__ to get an output file for debugging
*/
/* Brown - removed StreamID global variables */
#ifdef ANALYSIS
/* Statistics */
static int gNumAudioPackets
;
static int gNumVideoPackets
;
static int gNumPaddingPackets
;
static int gNumReservedPackets
;
static int gNumPrivate_1_Packets
;
static int gNumPrivate_2_Packets
;
#endif
/*
*----------------------------------------------------------
*
* read_sys
*
* Parse out a packet of the system layer MPEG file.
*
* Results: Returns 0 if error or EOF
* Returns 1 if more data read (could be just one int)
*
* Side Effects: ReadPacket can change *bs_ptr to be a new buffer
* buf_ptr will remain pointing at *length_ptr (at input)
* into the buffer
* *length_ptr will be changed to the new size
* *max_length can be changed if a new buffer is alloc'd
*
*----------------------------------------------------------
*/
int read_sys
(vid_stream
, start
)
VidStream
*vid_stream
;
unsigned int start
;
/* start is either a start code or 0 to indicate continued parsing */
{
unsigned int **bs_ptr
=&vid_stream
->buf_start
;
int *max_length
= &vid_stream
->max_buf_length
;
int *length_ptr
=&vid_stream
->buf_length
;
unsigned int **buf_ptr
=&vid_stream
->buffer
;
unsigned int startCode
;
int errorCode
, PacketReply
;
unsigned char packetID
;
double systemClockTime
;
unsigned long muxRate
;
/* Statistics */
#ifdef ANALYSIS
static int numPacks
= 0;
static int numPackets
= 0;
static int numSystemHeaders
= 0;
#endif
BOOLEAN match
;
if (!start
) {
errorCode
= ReadStartCode
(&startCode
,vid_stream
);
if (vid_stream
->EOF_flag
) return 0;
if (errorCode
!= 0) {
fprintf(stderr
, "Unable to read initial pack start code\n");
return 0;
}}
else {
errorCode
= 0;
startCode
= start
;
}
while (1) {
match
=FALSE
;
if (startCode
== PACK_START_CODE
) {
#ifdef ANALYSIS
++numPacks
;
#endif
match
= TRUE
;
errorCode
= ReadPackHeader
( &systemClockTime
, &muxRate
, vid_stream
);
if (errorCode
!= 0) {
fprintf(stderr
, "Error in reading pack header\n");
return 0;
}
errorCode
= ReadStartCode
( &startCode
, vid_stream
);
if (errorCode
!= 0) {
fprintf(stderr
, "Error in reading start code\n");
return 0;
}
}
if (startCode
== SYSTEM_HEADER_START_CODE
) {
#ifdef ANALYSIS
++numSystemHeaders
;
#endif
match
= TRUE
;
errorCode
= ReadSystemHeader
(vid_stream
);
if (errorCode
!= 0) {
fprintf(stderr
, "Error in reading system header\n");
return 0;
}
errorCode
= ReadStartCode
( &startCode
, vid_stream
);
if (errorCode
!= 0) {
fprintf(stderr
,"Error in reading start code after system header\n");
return 0;
}
}
packetID
= startCode
& 0xff;
while (((startCode
& PACKET_START_CODE_MASK
) == PACKET_START_CODE_PREFIX
) &&
(packetID
>= 0xbc)) {
#ifdef ANALYSIS
++numPackets
;
#endif
match
= TRUE
;
packetID
= startCode
& 0xff;
PacketReply
= ReadPacket
(packetID
, vid_stream
);
switch (PacketReply
) {
case 2:
return 1;
case 1:
return 0;
default: /* do nothing */
break;
}
errorCode
= ReadStartCode
( &startCode
, vid_stream
);
if (errorCode
!= 0) {
fprintf(stderr
,"Error in start code after packet\n");
return 0;
}
if (startCode
== PACK_START_CODE
|| startCode
== ISO_11172_END_CODE
) {
break;
}
}
if (startCode
== ISO_11172_END_CODE
) {
match
= TRUE
;
if (vid_stream
->Parse_done
) {
return 1;
}
#ifdef ANALYSIS
fprintf(stderr
, "Successful parse of MPEG system level\n");
fprintf(stderr
, "%d system headers, %d packs, %d packets\n",
numSystemHeaders
, numPacks
, numPackets
);
fprintf(stderr
, "%d audio packets, %d video packets, %d padding packets\n",
gNumAudioPackets
, gNumVideoPackets
, gNumPaddingPackets
);
fprintf(stderr
, "%d reserved packets, %d/%d private type 1/2 packets\n",
gNumReservedPackets
, gNumPrivate_1_Packets
, gNumPrivate_2_Packets
);
#endif
ReadPacket
(NOT_PACKET_ID
, vid_stream
);
vid_stream
->Parse_done
= TRUE
;
return 1;
}
if (errorCode
!= 0)
return 1;
if (! match
) {
fprintf(stderr
,"\nNo match found for start code %08x in system layer, skipping\n",startCode
);
startCode
= find_start_code
(vid_stream
->input
);
if (startCode
== EOF
) {
vid_stream
->EOF_flag
= 1;
return 0;
}
}
}
}
/*
*-----------------------------------------------------------
*
* ReadStartCode
*
* Parses a start code out of the stream
*
* Results/Side Effects: Sets *startCode to the code, returns
* 1 on error, 0 on success
*
*-----------------------------------------------------------
*/
int ReadStartCode
(startCode
, vid_stream
)
unsigned int *startCode
;
VidStream
*vid_stream
;
{
int numRead
;
numRead
= fread((unsigned char *)startCode
, 1, 4, vid_stream
->input
);
*startCode
= htonl
(*startCode
);
if (numRead
< 4) {
vid_stream
->EOF_flag
= 1;
return 1;
}
if ((*startCode
&0xfffffe00) != 0) {
fprintf(stderr
,"Problem with system layer parse, skipping to start code\n");
*startCode
= find_start_code
(vid_stream
->input
);
if (*startCode
== EOF
) {
vid_stream
->EOF_flag
= TRUE
;
return 0;
}
}
return 0;
}
/*
*-----------------------------------------------------------
*
* find_start_code
*
* Parses a start code out of the stream by tossing bytes until it gets one
*
* Results/Side Effects: Parses bytes of the stream, returns code
* Returns EOF in case of end of file
*
*-----------------------------------------------------------
*/
int find_start_code
(input
)
FILE
*input
;
{
NO_ZEROS
:
switch(fgetc(input
)) {
case 0: goto ONE_ZERO
;
case EOF
: goto EOF_FOUND
;
default: goto NO_ZEROS
;
}
ONE_ZERO
:
switch(fgetc(input
)) {
case 0: goto TWO_ZEROS
;
case EOF
: goto EOF_FOUND
;
default: goto NO_ZEROS
;
}
TWO_ZEROS
:
switch(fgetc(input
)) {
case 0x01: goto CODE_FOUND
;
case 0x00: goto TWO_ZEROS
;
case EOF
: goto EOF_FOUND
;
default: goto NO_ZEROS
;
}
CODE_FOUND
:
return 0x00000100+fgetc(input
);
EOF_FOUND
: /* received EOF */
return EOF
;
}
/*
*-----------------------------------------------------------------
*
* ReadPackHeader
*
* Parses out the PACK header
*
* Returns: 1 on error, 0 on success
*
*-------------------------------------------------------------------
*/
int ReadPackHeader
(systemClockTime
,muxRate
, vid_stream
)
double *systemClockTime
;
unsigned long *muxRate
;
VidStream
*vid_stream
;
{
int numRead
;
unsigned char inputBuffer
[PACK_HEADER_SIZE
];
unsigned long systemClockRef
;
unsigned char systemClockRefHiBit
;
int errorCode
;
numRead
= fread(inputBuffer
, 1, PACK_HEADER_SIZE
, vid_stream
->input
);
if (numRead
< PACK_HEADER_SIZE
) {
vid_stream
->EOF_flag
= 1;
return 1;
}
ReadTimeStamp
(inputBuffer
, &systemClockRefHiBit
, &systemClockRef
);
errorCode
= MakeFloatClockTime
(systemClockRefHiBit
, systemClockRef
,
systemClockTime
);
ReadRate
(&inputBuffer
[5], muxRate
);
*muxRate
*= MUX_RATE_SCALE_FACTOR
;
return 0;
}
/*
*------------------------------------------------------------------
*
* ReadSystemHeader
*
* Parse out the system header, setup out stream IDs for parsing packets
*
* Results: Returns 1 on error, 0 on success.
* Sets gAudioStreamID and gVideoStreamID
*
*------------------------------------------------------------------
*/
int ReadSystemHeader
(vid_stream
)
VidStream
*vid_stream
;
{
unsigned char *inputBuffer
= NULL
;
int numRead
;
int pos
;
unsigned short headerSize
;
unsigned char streamID
;
numRead
= fread((char *)&headerSize
, 1, 2, vid_stream
->input
);
headerSize
= ntohs
(headerSize
);
if (numRead
!= 2) {
vid_stream
->EOF_flag
= 1;
return 1;
}
inputBuffer
= (unsigned char *) malloc((unsigned int) headerSize
+1);
if (inputBuffer
== NULL
) {
return 1;
}
inputBuffer
[headerSize
]=0;
numRead
= fread(inputBuffer
, 1, headerSize
, vid_stream
->input
);
/* Brown - get rid of Ansi C complaints */
if (numRead
< (int) headerSize
) {
vid_stream
->EOF_flag
= 1;
return 1;
}
pos
= 6;
while ((inputBuffer
[pos
] & 0x80) == 0x80) {
streamID
= inputBuffer
[pos
];
switch (streamID
) {
case STD_VIDEO_STREAM_ID
:
break;
case STD_AUDIO_STREAM_ID
:
break;
case RESERVED_STREAM_ID
:
break;
case PADDING_STREAM_ID
:
break;
case PRIVATE_STREAM_1_ID
:
break;
case PRIVATE_STREAM_2_ID
:
break;
default:
if (streamID
< MIN_STREAM_ID_ID
) {
return 1;
}
switch (streamID
>> 4) {
case 0xc:
case 0xd:
vid_stream
->gAudioStreamID
= streamID
;
break;
case 0xe:
if ((vid_stream
->gVideoStreamID
!= 0) &&
(vid_stream
->gVideoStreamID
!=streamID
)) {
break;
}
vid_stream
->gVideoStreamID
= streamID
;
break;
case 0xf:
/*Brown - deglobalized gReservedStreamID */
vid_stream
->gReservedStreamID
= streamID
;
break;
}
break;
}
pos
+= 3;
}
if (inputBuffer
!= NULL
)
free(inputBuffer
);
return 0;
}
/*
*-----------------------------------------------------------------
*
* ReadPacket
*
* Reads a single packet out of the stream, and puts it in the
* buffer if it is video.
*
* Results:
* Changes the value of *length_ptr to be the new length (plus old)
* If the buffer is too small, can change *bs_ptr, *max_length, and
* buf_ptr to be correct for a newly allocated buffer.
*
* State:
* The buffer is in ints, but the packets can be an arbitrary number
* of bytes, so leftover bytes are kept in the VidStream variable and
* are added on the next call.
*
*-----------------------------------------------------------------
*/
#ifdef __STDC__
int ReadPacket
(unsigned char packetID
, VidStream
*vid_stream
)
#else
int ReadPacket
(packetID
, vid_stream
)
unsigned char packetID
;
VidStream
*vid_stream
;
#endif
/* Returns:
0 - no error, but not video packet we want
1 - error
2 - got video packet into buffer
*/
{
unsigned int **bs_ptr
=&vid_stream
->buf_start
;
int *max_length
= &vid_stream
->max_buf_length
;
int *length_ptr
=&vid_stream
->buf_length
;
unsigned int **buf_ptr
=&vid_stream
->buffer
;
int ioBytes
;
unsigned char nextByte
;
unsigned short packetLength
;
unsigned char *packetBuffer
= NULL
;
int pos
;
int numStuffBytes
= 0;
unsigned int packetDataLength
;
int byte_length
;
unsigned char scratch
[10];
/* Leftovers from previous video packets */
if (packetID
== NOT_PACKET_ID
) {
/* Gross hack to handle unread bytes before end of stream */
if (vid_stream
->num_left
!= 0) {
/* Sigh, deal with previous leftovers */
*(*buf_ptr
+*length_ptr
) = vid_stream
->leftover_bytes
;
*(*buf_ptr
+*length_ptr
+1) = ISO_11172_END_CODE
;
*length_ptr
+= 2;
} else {
*(*buf_ptr
+*length_ptr
) = ISO_11172_END_CODE
;
*length_ptr
+= 1;
}
return 1;
} else if (packetID
==KILL_BUFFER
) {
vid_stream
->num_left
=0;
vid_stream
->leftover_bytes
=0;
return 0;
}
ioBytes
= fread(&packetLength
, 1, 2, vid_stream
->input
);
packetLength
= htons
(packetLength
);
if (ioBytes
< 2) {
return 1;
}
if (packetID
== vid_stream
->gAudioStreamID
) {
#ifdef ANALYSIS
++gNumAudioPackets
;
#endif
}
else if (packetID
== vid_stream
->gVideoStreamID
) {
#ifdef ANALYSIS
++gNumVideoPackets
;
#endif
}
else {
switch (packetID
) {
case PADDING_STREAM_ID
:
#ifdef ANALYSIS
++gNumPaddingPackets
;
#endif
break;
case RESERVED_STREAM_ID
:
#ifdef ANALYSIS
++gNumReservedPackets
;
#endif
break;
case PRIVATE_STREAM_1_ID
:
#ifdef ANALYSIS
++gNumPrivate_1_Packets
;
#endif
break;
case PRIVATE_STREAM_2_ID
:
#ifdef ANALYSIS
++gNumPrivate_2_Packets
;
#endif
break;
default:
fprintf(stderr
, "\nUnknown packet type encountered. P'bly audio? (%x) at %d\n",
packetID
,(int) ftell(vid_stream
->input
));
}
if (packetID
!= vid_stream
->gVideoStreamID
) {/* changed by jim */
fseek(vid_stream
->input
, packetLength
, 1);
return 0;
}
}
fread(&nextByte
,1,1,vid_stream
->input
);
pos
= 0;
while (nextByte
& 0x80) {
++numStuffBytes
;
++pos
;
fread(&nextByte
,1,1,vid_stream
->input
);
}
if ((nextByte
>> 6) == 0x01) {
pos
+= 2;
fread(&nextByte
,1,1,vid_stream
->input
);
fread(&nextByte
,1,1,vid_stream
->input
);
}
if ((nextByte
>> 4) == 0x02) {
scratch
[0] = nextByte
; /* jim */
fread(&scratch
[1],1,4,vid_stream
->input
); /* jim */
fread(&nextByte
,1,1,vid_stream
->input
);
pos
+= 5;
}
else if ((nextByte
>> 4) == 0x03) {
scratch
[0] = nextByte
; /* jim */
fread(&scratch
[1],1,9,vid_stream
->input
); /* jim */
fread(&nextByte
,1,1,vid_stream
->input
);
pos
+= 10;
}
else {
fread(&nextByte
,1,1,vid_stream
->input
);
pos
+= 1;
}
/* Read all the headers, now make room for packet */
if (*bs_ptr
+ *max_length
< *buf_ptr
+ packetLength
/4 + *length_ptr
) {
/* Brown - get rid of Ansi C complaints */
if (*max_length
- *length_ptr
< (int) packetLength
/4) {
/* Buffer too small for a packet (plus whats there),
* time to enlarge it!
*/
unsigned int *old
= *bs_ptr
;
*max_length
= *length_ptr
+ packetLength
/2;
*bs_ptr
=(unsigned int *)malloc(*max_length
*4);
if (*bs_ptr
== NULL
) {
return 1;
}
memcpy((unsigned char *)*bs_ptr
, *buf_ptr
, (unsigned int) *length_ptr
*4);
free(old
);
*buf_ptr
= *bs_ptr
;
} else {
memcpy((unsigned char *)*bs_ptr
, *buf_ptr
, (unsigned int) *length_ptr
*4);
*buf_ptr
= *bs_ptr
;
}}
byte_length
= *length_ptr
*4;
if (vid_stream
->num_left
!= 0) {
/* Sigh, deal with previous leftovers */
byte_length
+= vid_stream
->num_left
;
*(*buf_ptr
+*length_ptr
) = vid_stream
->leftover_bytes
;
}
packetBuffer
=((unsigned char *)*buf_ptr
)+byte_length
;
packetDataLength
= packetLength
- pos
;
*packetBuffer
++ = nextByte
;
/* Brown - deglobalize gVideoStreamID */
if (packetID
== vid_stream
->gVideoStreamID
) {
ioBytes
= fread(packetBuffer
, 1, packetDataLength
-1, vid_stream
->input
);
if (ioBytes
!= packetDataLength
-1) {
vid_stream
->EOF_flag
= 1;
return 1;
}
if (1 != ntohl
(1)) {
unsigned int *mark
= *buf_ptr
+*length_ptr
;
int i
;
for (i
=0; i
< ((packetDataLength
+
vid_stream
->num_left
)&0xfffffffc); i
+=4) {
*mark
=ntohl
(*mark
);
mark
++;
}
}
byte_length
= byte_length
+ packetDataLength
;
vid_stream
->num_left
= byte_length
% 4;
*length_ptr
= byte_length
/ 4;
vid_stream
->leftover_bytes
= *(*buf_ptr
+ *length_ptr
);
return 2;
}
else if (packetID
== vid_stream
->gAudioStreamID
) {
packetBuffer
= (unsigned char *)(*buf_ptr
+ *length_ptr
+ 1);
fread(packetBuffer
, 1, packetDataLength
- 1, vid_stream
->input
);
}
else /* Donno what it is, just nuke it */ {
/* This code should be unreachable */
packetBuffer
= (unsigned char *)(*buf_ptr
+ *length_ptr
+ 1);
fread(packetBuffer
, 1, packetDataLength
- 1, vid_stream
->input
);
}
return 0;
}
/*
* The remaining procedures are formatting utility procedures.
*/
void ReadTimeStamp
(inputBuffer
,hiBit
,low4Bytes
)
unsigned char *inputBuffer
, *hiBit
;
unsigned long *low4Bytes
;
{
*hiBit
= ((unsigned long)inputBuffer
[0] >> 3) & 0x01;
*low4Bytes
= (((unsigned long)inputBuffer
[0] >> 1) & 0x03) << 30;
*low4Bytes
|= (unsigned long)inputBuffer
[1] << 22;
*low4Bytes
|= ((unsigned long)inputBuffer
[2] >> 1) << 15;
*low4Bytes
|= (unsigned long)inputBuffer
[3] << 7;
*low4Bytes
|= ((unsigned long)inputBuffer
[4]) >> 1;
}
void ReadSTD
(inputBuffer
,stdBufferScale
,stdBufferSize
)
unsigned char *inputBuffer
;
unsigned char *stdBufferScale
;
unsigned long *stdBufferSize
;
{
/* Brown - get rid of ANSI C complaints */
*stdBufferScale
= ((int)(inputBuffer
[0] & 0x20) >> 5);
*stdBufferSize
= ((unsigned long)inputBuffer
[0] & 0x1f) << 8;
*stdBufferSize
|= (unsigned long)inputBuffer
[1];
}
void ReadRate
(inputBuffer
,rate
)
unsigned char *inputBuffer
;
unsigned long *rate
;
{
*rate
= (inputBuffer
[0] & 0x7f) << 15;
*rate
|= inputBuffer
[1] << 7;
/* Brown - get rid of ANSI C complaints */
*rate
|= (int) (inputBuffer
[2] & 0xfe) >> 1;
}
#define FLOAT_0x10000 (double)((unsigned long)1 << 16)
#ifdef __STDC__
int MakeFloatClockTime
(unsigned char hiBit
, unsigned long low4Bytes
,
double * floatClockTime
)
#else
int MakeFloatClockTime
(hiBit
,low4Bytes
,floatClockTime
)
unsigned char hiBit
;
unsigned long low4Bytes
;
double *floatClockTime
;
#endif
{
if (hiBit
!= 0 && hiBit
!= 1) {
*floatClockTime
= 0.0;
return 1;
}
*floatClockTime
= (double)hiBit
*FLOAT_0x10000
*FLOAT_0x10000
+ (double)low4Bytes
;
*floatClockTime
/= (double)STD_SYSTEM_CLOCK_FREQ
;
return 0;
}