/*******************************************************
* System stream decoder ...
* grabs an audio stream inside a video/audio system stream
* This Program outputs only the first audio stream to STDOUT
*
* copyright (c) 1997/1998 by Michael Hipp
*
* currently this is an external program. You must pipe
* your streams file to this program and the output to
* the mpg123 player. e.g:
* ./system < my_system_stream.mpg | mpg123 -
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "mpg123.h"
static int filept;
static int verbose = 1;
#define PACKET_START 0x000001ba
#define STREAM_END 0x000001b9
#define SYSTEM_STREAM 0x000001bb
/* the following two types are not supported */
#define AUDIO_STREAM 0x000001b8
#define VIDEO_STREAM 0x000001b9
#define PADDING_STREAM 0x000001be
#define RESERVED_STREAM 0x000001bc
#define PRIVATE_STREAM_1 0x000001bd
#define PRIVATE_STREAM_2 0x000001bf
static int system_back_frame(struct frame *fr,int num);
static int system_head_read(unsigned char *hbuf,unsigned long *newhead);
static int system_head_shift(unsigned char *hbuf,unsigned long *head);
static int system_skip_bytes(int len);
static int system_read_frame_body(int size);
static long system_tell(void);
struct system_info {
unsigned long rate;
int num_audio;
int num_video;
int fixed;
int csps;
int audio_lock;
int video_lock;
};
struct stream_info {
int id;
int id1;
int type;
int size;
int scale;
};
struct packet_info {
int scale;
int size;
unsigned long dts;
unsigned long pts;
};
struct system_info sys_info;
struct stream_info str_info[64];
static int my_read(int f,char *buf,int len)
{
int len1 = 0;
int ret;
while(len1 < len) {
ret = read(f,buf+len1,len-len1);
if(ret < 0)
return -1;
len1 += ret;
}
return len;
}
static int system_raw_read_head(int f,unsigned long *head)
{
unsigned char buf[4];
if(my_read(f,buf,4) != 4) {
perror("read_head");
return -1;
}
*head = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3];
if(verbose > 1)
fprintf(stderr,"head: %08lx\n",*head);
return 0;
}
static int system_raw_read_word(int f,int *word)
{
unsigned char buf[2];
int ret;
if(my_read(f,buf,2) != 2) {
perror("read_word");
return -1;
}
*word = (buf[0]<<8) + buf[1];
return 0;
}
static int system_raw_read(int f,int len,unsigned char *buf)
{
if(my_read(f,buf,len) != len)
return -1;
return 0;
}
static int system_raw_skip(int f,int len)
{
int ret;
int cnt = 0;
ret = lseek(f,len,SEEK_CUR);
if(ret < 0 && errno == ESPIPE) {
cnt = len;
while(cnt) {
char buf[1024];
if(cnt > 1024)
ret = read(f,buf,1024);
else
ret = read(f,buf,cnt);
if(ret < 0)
return -1;
cnt -= ret;
}
ret = len;
}
return ret;
}
static unsigned long system_raw_timer_value(unsigned char *buf)
{
unsigned long val;
if(!(buf[0] & 0x1) || !(buf[2] & 0x1) || !(buf[4] & 0x1)) {
if(verbose)
fprintf(stderr,"Warning: missing marker in time stamp!\n");
}
val = (buf[0] & 0xe) << (29-1);
val |= buf[1] << 21;
val |= (buf[2] & 0xfe) << (14-1);
val |= buf[3] << 7;
val |= buf[4] >> 1;
return val;
}
static int system_raw_read_packet_data(int fd,struct packet_info *pi)
{
static unsigned char buf[16384];
int len;
int pos = 0;
int i;
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(verbose > 1)
fprintf(stderr,"Stream video/audio len: %d\n",len);
if(system_raw_read(fd,len,buf) < 0)
return -1;
for(i=0;i<16;i++,pos++) {
if(buf[pos] != 0xff)
break;
}
if(i == 16) {
fprintf(stderr,"Ouch ... too much stuffing bytes!\n");
return -1;
}
if( (buf[pos] & 0xc0) == 0x40 ) {
pi->scale = (buf[pos] >> 5) & 0x1;
pi->size = (buf[pos] & 0x1f) << 8;
pi->size |= buf[pos+1];
pos += 2;
}
switch( buf[pos] & 0xf0) {
case 0x00:
if(buf[pos] != 0x0f) {
fprintf(stderr,"Ouch ... illegal timer code!\n");
return -1;
}
pos++;
break;
case 0x20:
pi->pts = system_raw_timer_value(buf+pos);
pos += 5;
break;
case 0x30:
pi->pts = system_raw_timer_value(buf+pos);
pos += 5;
if( (buf[pos] & 0xf) != 0x10) {
if(verbose)
fprintf(stderr,"DTS should start with 0x1x!\n");
}
pi->dts = system_raw_timer_value(buf+pos);
pos += 5;
break;
default:
if(verbose)
fprintf(stderr,"Ouch ... illegal timer code!\n");
return -1;
}
#if 1
write(1,buf+pos,len-pos);
#endif
return 0;
}
static int system_raw_read_packet_info(int f,double *clock,unsigned long *rate)
{
unsigned char buf[8];
int i;
if(my_read(f,buf,8) != 8) {
perror("read_packet_info");
return -1;
}
*clock = 0.0;
for(i=0;i<5;i++) {
*clock *= 256.0;
*clock += (double) buf[4-i];
}
*rate = (buf[5]<<16) + (buf[6]<<8) + buf[7];
return 0;
}
static int system_raw_read_system_header(int f,struct system_info *ssi)
{
int rlen,len;
unsigned char buf[6+48*3];
int i,cnt;
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(verbose > 1)
fprintf(stderr,"system len: %d\n",len);
rlen = len;
if(len > 6 + 48 * 3) {
if(verbose)
fprintf(stderr,"Oops .. large System header!\n");
rlen = 6+48*3;
}
if(my_read(f,buf,rlen) != rlen) {
perror("raw_read_system_header");
return -1;
}
if(len - rlen) {
if(system_raw_skip(filept,len-rlen) < 0)
return -1;
}
if(buf[5] != 0xff) {
if(verbose)
fprintf(stderr,"Warning: buf[5] !=0xff \n");
}
ssi->rate = (buf[0]<<16)+(buf[1]<<8)+buf[2];
if( (ssi->rate & 0x800001) != 0x800001) {
if(verbose)
fprintf(stderr,"System Header Byte 0: Missing bits\n");
return -1;
}
ssi->rate >>= 1;
ssi->rate &= 0x7fffff;
ssi->num_audio = buf[3] >> 2;
ssi->num_video = buf[4] & 0x1f;
ssi->fixed = buf[3] & 0x2;
ssi->csps = buf[3] & 0x1;
ssi->audio_lock = buf[4] & 0x80;
ssi->video_lock = buf[4] & 0x40;
if(verbose)
fprintf(stderr,"Audio: %d Video: %d, Lock: %d/%d, fixed: %d, csps: %d\n",
ssi->num_audio,ssi->num_video,ssi->audio_lock?1:0,ssi->video_lock?1:0,
ssi->fixed?1:0,ssi->csps?1:0);
i = 6;
cnt = 0;
while( i < rlen ) {
if( !(buf[i] & 0x80) || ((buf[i+1] & 0xc0) != 0xc0) ) {
fprintf(stderr,"system_raw_read_system_header byte %d,%d: bits not set!\n",i,i+1);
return -1;
}
str_info[cnt].id = buf[i];
if( (str_info[cnt].id & 0xe0) == 0xc0 ) {
str_info[cnt].type = 'A';
str_info[cnt].id1 = str_info[cnt].id & 0x1f;
}
else if((str_info[cnt].id & 0xf0) == 0xe0 ) {
str_info[cnt].type = 'V';
str_info[cnt].id1 = str_info[cnt].id & 0x0f;
}
else {
str_info[cnt].type = 'R';
str_info[cnt].id1 = str_info[cnt].id & 0x3f;
}
str_info[cnt].scale = buf[i+1] & 0x20;
str_info[cnt].size = ((buf[i+1] & 0x1f)<<8)+buf[i+2];
i += 3;
if(verbose)
fprintf(stderr,"ID: %#02x=%c%d, scale: %d, size %d\n",
str_info[cnt].id,str_info[cnt].type,str_info[cnt].id1,str_info[cnt].scale?1:0,str_info[cnt].size);
}
return 0;
}
/***************************************************
* init system layer read functions
*/
int system_init(struct reader *r)
{
unsigned long head;
double clk;
unsigned long rate;
int len;
int err;
r->back_frame = NULL;
r->head_read = system_head_read;
r->head_shift = system_head_shift;
r->skip_bytes = system_skip_bytes;
r->read_frame_body = system_read_frame_body;
r->tell = system_tell;
if(system_raw_read_head(filept,&head) < 0)
return -1;
if(head != PACKET_START) {
fprintf(stderr,"No PACKET_START found!\n");
return -1;
}
if(system_raw_read_packet_info(filept,&clk,&rate) < 0)
return -1;
err = 0;
while(err == 0) {
if(system_raw_read_head(filept,&head) < 0)
return -1;
if((head & 0xffffff00) != 0x00000100)
return -1;
switch(head) {
case PACKET_START:
if(system_raw_read_packet_info(filept,&clk,&rate))
return -1;
if(verbose > 1)
fprintf(stderr,"Packet Start\n");
break;
case STREAM_END:
if(verbose)
fprintf(stderr,"Stream End\n");
break;
case SYSTEM_STREAM:
if(system_raw_read_system_header(filept,&sys_info) < 0)
return -1;
break;
#if 0
case AUDIO_STREAM:
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(verbose > 1)
fprintf(stderr,"STD audio len: %d\n",len);
if(system_raw_skip(filept,len) < 0)
return -1;
break;
case VIDEO_STREAM:
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(verbose > 1)
fprintf(stderr,"STD video len: %d\n",len);
if(system_raw_skip(filept,len) < 0)
return -1;
break;
#endif
default:
if(head >= 0x000001c0 && head < 0x000001f0) {
if(verbose > 1)
fprintf(stderr,"Stream ID %ld\n",head - 0x000001c0);
if( (head - 0x000001c0) == 0x0) {
struct packet_info pi;
if(system_raw_read_packet_data(filept,&pi) < 0 )
return -1;
}
else {
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(system_raw_skip(filept,len) < 0)
return -1;
}
break;
}
else if(head >= 0x000001bd && head < 0x000001c0) {
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(system_raw_skip(filept,len) < 0)
return -1;
break;
}
else {
if(verbose)
fprintf(stderr,"unsupported head %8lx\n",head);
if(system_raw_read_word(filept,&len) < 0)
return -1;
if(verbose)
fprintf(stderr,"Skipping: %d bytes\n",len);
if(system_raw_skip(filept,len) < 0)
return -1;
break;
}
err = 1;
break;
}
}
return 0;
}
static int system_back_frame(struct frame *fr,int num)
{
return 0;
}
static int system_head_read(unsigned char *hbuf,unsigned long *newhead)
{
return 0;
}
static int system_head_shift(unsigned char *hbuf,unsigned long *head)
{
return 0;
}
static int system_skip_bytes(int len)
{
return 0;
}
static int system_read_frame_body(int size)
{
return 0;
}
static long system_tell(void)
{
return 0;
}
struct reader rd1;
void main(void)
{
int ret;
filept = 0;
ret = system_init(&rd1);
fprintf(stderr,"ret: %d\n",ret);
}