www.pudn.com > avi 到 mpeg 的转换程序及源代码.zip > MULTPLEX.C


/************************************************************************* 
*  mplex - MPEG/SYSTEMS multiplexer					 * 
*  Copyright (C) 1994 1995 Christoph Moar				 * 
*  Siemens ZFE ST SN 11 / T SN 6					 * 
*									 * 
*  moar@informatik.tu-muenchen.de 					 * 
*       (Christoph Moar)			 			 * 
*  klee@heaven.zfe.siemens.de						 * 
*       (Christian Kleegrewe, Siemens only requests)			 * 
*									 * 
*  This program is free software; you can redistribute it and/or modify	 * 
*  it under the terms of the GNU General Public License as published by	 *	 
*  the Free Software Foundation; either version 2 of the License, or	 * 
*  (at your option) any later version.					 * 
*									 * 
*  This program is distributed in the hope that it will be useful,	 * 
*  but WITHOUT ANY WARRANTY; without even the implied warranty of	 * 
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	 * 
*  GNU General Public License for more details.				 * 
*									 * 
*  You should have received a copy of the GNU General Public License	 * 
*  along with this program; if not, write to the Free Software		 * 
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		 * 
*************************************************************************/ 
/* 
 * 4/4/97 - John Schlichther 
 * 
 * extensively altered to create avi2mpg1 - avi to mpeg-1 encoder 
 * 
 * Since avi file, and the avi subsystem are platform dependant, cross 
 * platform compatibility removed, many optional features disabled or 
 * removed, code generally trimmed to a minimum. 
 * 
 */ 
#include "mplex.h" 
#ifdef TIMER 
    extern long total_sec; 
    extern long total_usec; 
    extern long global_sec; 
    extern long global_usec; 
    extern struct timeval  tp_start; 
    extern struct timeval  tp_end; 
    extern struct timeval  tp_global_start; 
    extern struct timeval  tp_global_end; 
#endif 
extern unsigned int vcd_parm; 
/****************************************************************** 
	Hauptschleife Multiplexroutinenaufruf 
	Kuemmert sich um oeffnen und schliessen alles beteiligten 
	Dateien und um den korrekten Aufruf der jeweils 
	noetigen Video- und Audio-Packet Routinen. 
	Gewissermassen passiert hier das Wesentliche des  
	Multiplexens. Die Bufferkapazitaeten und die TimeStamps 
	werden ueberprueft und damit entschieden, ob ein Video- 
	Audio- oder Padding-Packet erstellt und geschrieben 
	werden soll. 
 
	Main multiplex iteration. 
	Opens and closes all needed files and manages the correct 
	call od the respective Video- and Audio- packet routines. 
	The basic multiplexing is done here. Buffer capacity and  
	Timestamp checking is also done here, decision is taken 
	wether we should genereate a Video-, Audio- or Padding- 
	packet. 
******************************************************************/ 
 
void outputstream (video_file, video_units, video_info, 
		   audio_file, audio_units, audio_info, 
		   multi_file, which_streams ) 
 
char 		*video_file; 
char 		*video_units; 
Video_struc 	*video_info; 
char 		*audio_file; 
char 		*audio_units; 
Audio_struc 	*audio_info; 
char 		*multi_file; 
unsigned int    which_streams; 
 
{ 
 
    FILE *istream_v;			/* Inputstream Video	*/ 
    FILE *istream_a;			/* Inputstream Audio	*/ 
    FILE *ostream;			/* Outputstream MPEG	*/ 
    FILE *vunits_info;			/* Input Video Units	*/ 
    FILE *aunits_info;			/* Input Audio Units	*/ 
 
    Vaunit_struc video_au;		/* Video Access Unit	*/ 
    Aaunit_struc audio_au;		/* Audio Access Unit	*/ 
 
    unsigned int data_rate=0;		/* AudioVideo Byterate	*/ 
    unsigned int video_rate=0; 
    unsigned int audio_rate=0; 
    double delay,audio_delay,video_delay; 
    double clock_cycles; 
    double audio_next_clock_cycles; 
    double video_next_clock_cycles; 
    unsigned int bytes_output; 
    double dmux_rate; 
    unsigned long sectors_delay,video_delay_ms,audio_delay_ms; 
    unsigned int mux_rate; 
    unsigned char picture_start; 
    unsigned char audio_frame_start; 
    //unsigned int bytes_left; 
    unsigned int audio_bytes; 
    unsigned int video_bytes; 
 
    unsigned int nsec_a=0; 
    unsigned int nsec_v=0; 
    unsigned int nsec_p=0; 
 
    unsigned char* index; 
	 
    Timecode_struc SCR_audio_delay; 
    Timecode_struc SCR_video_delay; 
    Timecode_struc current_SCR; 
    Timecode_struc audio_next_SCR; 
    Timecode_struc video_next_SCR; 
 
    Buffer_struc video_buffer; 
    Buffer_struc audio_buffer; 
 
    Pack_struc 		pack; 
    Sys_header_struc 	sys_header; 
    Sector_struc 	sector; 
    //Timecode_struc	timestamp; 
 
    unsigned long sector_size; 
    unsigned long min_packet_data; 
    unsigned long max_packet_data; 
    unsigned long packets_per_pack; 
    unsigned long audio_buffer_size; 
    unsigned long video_buffer_size; 
 
    unsigned long write_pack; 
    unsigned char marker_pack; 
    unsigned long packet_data_size; 
    unsigned char verbose; 
 
    /* Oeffne alle Ein- und Ausgabefiles			*/ 
    /* Open in- and outputstream				*/ 
 
    if (which_streams & STREAMS_VIDEO) istream_v = fopen (video_file, "rb"); 
    if (which_streams & STREAMS_AUDIO) istream_a = fopen (audio_file, "rb"); 
    if (which_streams & STREAMS_VIDEO) vunits_info = fopen (video_units, "rb"); 
    if (which_streams & STREAMS_AUDIO) aunits_info = fopen (audio_units, "rb"); 
    ostream	= fopen (multi_file, "wb"); 
 
    /* Einlesen erster Access Unit Informationen		*/ 
    /* read in first access unit information			*/ 
 
    picture_start     = FALSE; 
    audio_frame_start = FALSE; 
    empty_vaunit_struc (&video_au); 
    empty_aaunit_struc (&audio_au); 
 
    if (which_streams & STREAMS_AUDIO) { 
	fread (&audio_au, sizeof(Aaunit_struc), 1, aunits_info); 
	audio_frame_start = TRUE; 
    } 
    if (which_streams & STREAMS_VIDEO) { 
	fread (&video_au, sizeof(Vaunit_struc), 1, vunits_info); 
	picture_start = TRUE; 
    } 
 
//printf("\nMerging elementary streams to MPEG/SYSTEMS multiplexed stream.\n"); 
//printf("\n+------------------ MPEG/SYSTEMS INFORMATION -----------------+\n"); 
     
    //do  
    //{ 
    	//printf ("\nsector size (CD-ROM 2324 bytes)          : 4096"); 
    	//scanf ("%ld", §or_size); 
		if(vcd_parm) 
			sector_size = 2324; 
		else 
			sector_size = 2048; 
    //} while (sector_size>MAX_SECTOR_SIZE); 
 
    //printf   ("\npacks to packets ratio                 1 : 1"); 
    //scanf ("%ld", &packets_per_pack); 
	packets_per_pack = 1; 
    //printf ("\nSTD video buffer in kB (CSPS: max 46 kB) : "); 
    //scanf ("%ld", &video_buffer_size); 
	if(vcd_parm) 
		video_buffer_size = 40; 
	else 
		video_buffer_size = 46; 
    //printf   ("\nSTD audio buffer in kB (CSPS: max  4 kB) : "); 
    //scanf ("%ld", &audio_buffer_size); 
	audio_buffer_size = 4; 
 
    write_pack = packets_per_pack; 
    video_buffer_size *= 1024; 
    audio_buffer_size *= 1024; 
    min_packet_data = sector_size - PACK_HEADER_SIZE - SYS_HEADER_SIZE - 
	PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH; 
    max_packet_data = sector_size - PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH; 
 
    /* if we have only one stream, we have 3 more bytes in the sys header free */ 
 
     if (which_streams != STREAMS_BOTH) {  
 	min_packet_data += 3;  
     } 	 
 
    /* Bufferstrukturen Initialisieren				*/ 
    /* initialize buffer structure				*/ 
 
    init_buffer_struc (&video_buffer,video_buffer_size); 
    init_buffer_struc (&audio_buffer,audio_buffer_size); 
 
    /*	DTS ist in den ersten Units i.d.R. gleich null. Damit 
	kein Bufferunterlauf passiert, muss berechnet werden,  
	wie lange es dauert, bis alle Daten sowohl des ersten 
	Video- als auch des ersten Audio-Access units ankommen. 
	Diesen Wert dann als Art Startup-Delay zu den Time- 
	stamps dazurechnen. Um etwas Spielraum zu haben, wird 
	als Wert einfach die Anzahl der zu uebertragenden 
	Sektoren aufgerundet.					*/ 
    /*  DTS of the first units is supposed to be zero. To avoid 
	Buffer underflow, we have to compute how long it takes for 
	all first Video and Audio access units to arrive at the  
	system standard decoder buffer. This delay is added as a  
	kind of startup delay to all of the TimeStamps. We compute 
	a ceiling based on the number of sectors we will have 
	to transport for the first access units */ 
 
    if (which_streams & STREAMS_VIDEO) { 
	if (video_info->bit_rate > video_info->comp_bit_rate) 
	    video_rate = video_info->bit_rate * 50; 
	else 
	    video_rate = video_info->comp_bit_rate * 50; 
    } 
    if (which_streams & STREAMS_AUDIO) 
	audio_rate = bitrate_index[3-audio_info->layer][audio_info->bit_rate]*128; 
 
    data_rate = video_rate + audio_rate; 
 
    dmux_rate =  ceil((double)(data_rate) * 
		 ((double)(sector_size)/(double)(min_packet_data) + 
		 ((double)(sector_size)/(double)(max_packet_data) * 
		 (double)(packets_per_pack-1.))) / (double)(packets_per_pack) ); 
    data_rate = (unsigned int)ceil(dmux_rate/50.)*50; 
 
    //printf ("\ncomputed multiplexed stream data rate    : %7.3f\n",dmux_rate); 
    //printf ("target data rate (e.g. %6u)           : ",data_rate); 
    //scanf  ("%lf", &dmux_rate); 
 
	if(vcd_parm) 
		dmux_rate = 176400; 
 
    //printf ("\nstartup sectors_delay                    : 8"); 
    //scanf  ("%u", §ors_delay); 
	sectors_delay = 8; 
    //printf ("\nvideo stream startup offset (ms)         : 0"); 
    //scanf  ("%u", &video_delay_ms); 
	video_delay_ms = 0; 
    //printf ("\naudio stream startup offset (ms)         : 0"); 
    //scanf  ("%u", &audio_delay_ms); 
	audio_delay_ms = 0; 
 
    video_delay = (double)video_delay_ms*(double)(CLOCKS/1000); 
    audio_delay = (double)audio_delay_ms*(double)(CLOCKS/1000); 
 
    //verbose=ask_verbose(); 
	verbose=FALSE; 
    //printf ("\n"); 
 
#ifdef TIMER 
    gettimeofday (&tp_global_start,NULL); 
#endif 
 
    mux_rate = (unsigned int)ceil(dmux_rate/50.); 
    dmux_rate= mux_rate * 50.; 
 
    delay = ((double)sectors_delay + 
	    ceil((double)video_au.length/(double)min_packet_data)  + 
	    ceil((double)audio_au.length/(double)min_packet_data )) * 
	    (double)sector_size/dmux_rate*(double)CLOCKS; 
 
    audio_delay += delay; 
    video_delay += delay; 
 
    make_timecode (audio_delay, &SCR_audio_delay); 
    make_timecode (video_delay, &SCR_video_delay); 
 
    add_to_timecode	(&SCR_video_delay, &video_au.DTS); 
    add_to_timecode	(&SCR_video_delay, &video_au.PTS); 
    add_to_timecode	(&SCR_audio_delay, &audio_au.PTS); 
 
    bytes_output = 0; 
 
    /* 	Jetzt probieren wir mal, Unit fuer Unit auszulesen und  
	ins Outputstream auszuschreiben. Die Schwierigkeit liegt 
	darin, dass die Buffer konstant ueberprueft werden muessen 
	und dass die jeweilige Access Unit auch innerhalb des DTS 
	eintreten muss. Es kann passieren, dass z.B. im Video- 
	Buffer noch ein altes Picture liegt, das noch dekodiert 
	werden muss, wir jetzt schon das naechste schicken, aber 
	nach einigen Packets der Buffer voll ist. Da darf nichts 
	mehr geschickt werden, bis die DTS des alten Bildes 
	eingetreten ist und damit der Buffer kleiner geworden ist. 
	In der Zwischenzeit kann ein Audio-Packet geschickt werden 
	und/oder ein Padding-Packet generiert werden.		*/ 
    /*  Let's try to read in unit after unit and to write it out into 
	the outputstream. The only difficulty herein lies into the  
	buffer management, and into the fact the the actual access 
	unit *has* to arrive in time, that means the whole unit 
	(better yet, packet data), has to arrive before arrival of 
	DTS. If both buffers are full we'll generate a padding packet */ 
 
 
    //status_header (); 
 
 
    while ((video_au.length + audio_au.length) > 0) 
    { 
 
	if (write_pack-- == packets_per_pack)  
	{ 
	    marker_pack = TRUE; 
	    packet_data_size = min_packet_data; 
	} else  
	{ 
	    marker_pack = FALSE; 
	    packet_data_size = max_packet_data; 
	} 
 
	if (write_pack == 0) write_pack = packets_per_pack; 
 
	audio_bytes = (audio_au.length/min_packet_data)*sector_size + 
		(audio_au.length%min_packet_data)+(sector_size-min_packet_data); 
	video_bytes = (video_au.length/min_packet_data)*sector_size + 
		(video_au.length%min_packet_data)+(sector_size-min_packet_data); 
 
 
	clock_cycles = (double)(bytes_output+LAST_SCR_BYTE_IN_PACK)* 
		CLOCKS/dmux_rate; 
	audio_next_clock_cycles = (double)(bytes_output+sector_size+ 
		audio_bytes)/dmux_rate*CLOCKS; 
	video_next_clock_cycles = (double)(bytes_output+sector_size+ 
		video_bytes)/dmux_rate*CLOCKS; 
 
	make_timecode (clock_cycles, ¤t_SCR); 
	make_timecode (audio_next_clock_cycles, &audio_next_SCR); 
	make_timecode (video_next_clock_cycles, &video_next_SCR); 
 
	if (which_streams & STREAMS_AUDIO) buffer_clean (&audio_buffer, ¤t_SCR); 
	if (which_streams & STREAMS_VIDEO) buffer_clean (&video_buffer, ¤t_SCR); 
 
	/* FALL: Video Buffer OK, Video Daten vorhanden		*/ 
	/*       Audio Daten werden on time ankommen		*/ 
	/* CASE: Video Buffer OK, Video Data ready		*/ 
	/*	 Audio Data will arrive on time			*/ 
 
	if ( (buffer_space (&video_buffer) >= packet_data_size) 
	     && (video_au.length>0) 
	     && ((comp_timecode (&audio_next_SCR, &audio_au.PTS)) || 
		 (audio_au.length==0) )) 
	{ 
	    /* video packet schicken */ 
	    /* write out video packet */ 
	    output_video (¤t_SCR, &SCR_video_delay, vunits_info, 
		istream_v, ostream, &pack, &sys_header, §or, 
		&video_buffer, &video_au, &picture_start, 
		&bytes_output, mux_rate, audio_buffer_size, video_buffer_size, 
		packet_data_size, marker_pack, which_streams); 
 
	    /* status info */ 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    //status_info (nsec_a, ++nsec_v, nsec_p, bytes_output, 
		//	 buffer_space(&video_buffer), 
		//	 buffer_space(&audio_buffer),verbose); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	} 
 
	/* FALL: Audio Buffer OK, Audio Daten vorhanden		*/ 
	/*       Video Daten werden on time ankommen		*/ 
	/* CASE: Audio Buffer OK, Audio Data ready		*/ 
	/*	 Video Data will arrive on time			*/ 
 
	else if ( (buffer_space (&audio_buffer) >= packet_data_size) 
		  && (audio_au.length>0) 
		  && ((comp_timecode (&video_next_SCR, &video_au.DTS)) || 
		      (video_au.length==0) )) 
	{ 
	    /* audio packet schicken */ 
	    /* write out audio packet */ 
 
	    output_audio (¤t_SCR, &SCR_audio_delay, aunits_info, 
		istream_a, ostream, &pack, &sys_header, §or, 
		&audio_buffer, &audio_au, &audio_frame_start, 
		&bytes_output, mux_rate, audio_buffer_size, video_buffer_size, 
		packet_data_size, marker_pack, which_streams); 
 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    /* status info */ 
	    //status_info (++nsec_a, nsec_v, nsec_p, bytes_output,  
		//	 buffer_space(&video_buffer), 
		//	 buffer_space(&audio_buffer),verbose); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	} 
 
 
	/* FALL: Audio Buffer OK, Audio Daten vorhanden		*/ 
	/*       Audio Daten werden nicht on time ankommen	*/ 
	/* CASE: Audio Buffer OK, Audio data ready		*/ 
	/*	 Audio data will be time out			*/ 
 
	else if ( (buffer_space (&audio_buffer) >= packet_data_size) 
		  && (audio_au.length>0) 
		  &! comp_timecode (&audio_next_SCR, &audio_au.PTS)) 
	{ 
	    /* audio packet schicken */ 
	    /* write out audio packet */ 
	    output_audio (¤t_SCR, &SCR_audio_delay, aunits_info, 
		istream_a, ostream, &pack, &sys_header, §or, 
		&audio_buffer, &audio_au, &audio_frame_start, 
		&bytes_output, mux_rate, audio_buffer_size, video_buffer_size, 
		packet_data_size, marker_pack, which_streams); 
 
	    /* audio fehlermeldung */ 
	    /* audio error message */ 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    status_message (STATUS_AUDIO_TIME_OUT); 
	    /* status info */ 
	    //status_info (++nsec_a, nsec_v, nsec_p, bytes_output,  
		//	 buffer_space(&video_buffer), 
		//	 buffer_space(&audio_buffer),verbose); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	} 
 
	/* FALL: Video Buffer OK, Video Daten vorhanden		*/ 
	/*       Video Daten werden nicht on time ankommen	*/ 
	/* CASE: Video Buffer OK, Video data ready		*/ 
	/*	 Video data will be time out			*/ 
 
	else if ( (buffer_space (&video_buffer) >= packet_data_size) 
		   && (video_au.length>0) 
		   &! comp_timecode (&video_next_SCR, &video_au.DTS)) 
	{ 
	    /* video packet schicken */ 
	    /* write out video packet */ 
	    output_video (¤t_SCR, &SCR_video_delay, vunits_info, 
		istream_v, ostream, &pack, &sys_header, §or, 
		&video_buffer, &video_au, &picture_start, 
		&bytes_output, mux_rate, audio_buffer_size, video_buffer_size, 
		packet_data_size, marker_pack, which_streams); 
 
	    /* video fehlermeldung */ 
	    /* video error message */ 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    status_message (STATUS_VIDEO_TIME_OUT); 
 
	    /* status info */ 
	    //status_info (nsec_a, ++nsec_v, nsec_p, bytes_output,  
		//	 buffer_space(&video_buffer), 
		//	 buffer_space(&audio_buffer),verbose); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	} 
 
	/* FALL: Audio Buffer nicht OK				*/ 
	/*       Video Buffer nicht OK				*/ 
	/* CASE: Audio Buffer NOT OK				*/ 
	/*	 Video Buffer NOT OK				*/ 
 
	else 
	{ 
	    /* padding packet schicken */ 
	    /* write out padding packet */ 
	    output_padding (¤t_SCR, ostream, &pack, &sys_header, 
		§or, &bytes_output, mux_rate, audio_buffer_size,  
		video_buffer_size,packet_data_size, marker_pack, which_streams); 
 
	    /* status info */ 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    //status_info (nsec_a, nsec_v, ++nsec_p, bytes_output,  
		//	 buffer_space(&video_buffer), 
		//	 buffer_space(&audio_buffer),verbose); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	} 
    } 
 
 
    /* ISO 11172 END CODE schreiben				*/ 
    /* write out ISO 11172 END CODE				*/ 
    index = sector.buf; 
 
    *(index++) = (unsigned char)((ISO11172_END)>>24); 
    *(index++) = (unsigned char)((ISO11172_END & 0x00ff0000)>>16); 
    *(index++) = (unsigned char)((ISO11172_END & 0x0000ff00)>>8); 
    *(index++) = (unsigned char)(ISO11172_END & 0x000000ff); 
 
    fwrite (sector.buf, sizeof (unsigned char), 4, ostream); 
    bytes_output += 4; 
 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
    /* status info*/ 
    //status_info (nsec_a, nsec_v, nsec_p, bytes_output,  
	//	 buffer_space(&video_buffer), 
	//	 buffer_space(&audio_buffer),verbose); 
    if (!verbose) printf ("\n"); 
    //status_footer (); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
    /* Schliesse alle Ein- und Ausgabefiles			*/ 
    /* close all In- and Outputfiles				*/ 
 
    fclose (ostream); 
 
    if (which_streams & STREAMS_AUDIO) fclose (aunits_info); 
    if (which_streams & STREAMS_VIDEO) fclose (vunits_info); 
    if (which_streams & STREAMS_AUDIO) fclose (istream_a); 
    if (which_streams & STREAMS_VIDEO) fclose (istream_v); 
 
    /* loeschen der temporaeren Files */ 
    /* delete tmp files	*/ 
 
    if (which_streams & STREAMS_VIDEO) unlink (video_units); 
    if (which_streams & STREAMS_AUDIO) unlink (audio_units);  
 
    //printf ("\nDone, tmp files removed.\n\n"); 
 
#ifdef TIMER 
    gettimeofday (&tp_global_end, NULL); 
    global_sec = 10*(tp_global_end.tv_sec - tp_global_start.tv_sec); 
    global_usec= 10*(tp_global_end.tv_usec - tp_global_start.tv_usec); 
    global_sec += (global_usec / 100000); 
    total_sec *= 10; 
    total_sec  += (total_usec  / 100000); 
 
    printf ("Timing global: %10.1f secs\n",(float)global_sec/10.); 
    printf ("Timing IO    : %10.1f secs\n",(float)total_sec/10.); 
#endif 
     
} 
 
 
/****************************************************************** 
	Next_Video_Access_Unit 
	holt aus dem TMP File, der die Info's ueber die Access 
	Units enthaelt, die jetzt gueltige Info her. Nach 
	dem Erstellen des letzten Packs sind naemlich eine 
	bestimmte Anzahl Bytes und damit AU's eingelesen worden. 
 
	gets information for the next access unit from the tmp 
	file 
******************************************************************/ 
 
void next_video_access_unit (buffer, video_au, bytes_left, vunits_info, 
			picture_start, SCR_delay) 
Buffer_struc *buffer; 
Vaunit_struc *video_au; 
unsigned int *bytes_left; 
FILE *vunits_info; 
unsigned char *picture_start; 
Timecode_struc *SCR_delay; 
 
{ 
 
	int i; 
 
	if (*bytes_left == 0) 
	    return; 
 
	while (video_au->length < *bytes_left) 
	{ 
	    queue_buffer (buffer, video_au->length, &video_au->DTS); 
	    *bytes_left -= video_au->length; 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    i=fread (video_au, sizeof(Vaunit_struc), 1, vunits_info); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	    if (i != 1) 
	    { 
		empty_vaunit_struc (video_au); 
		//status_message(STATUS_VIDEO_END); 
		return; 
	    } 
	    *picture_start = TRUE; 
	    add_to_timecode (SCR_delay, &video_au->DTS); 
	    add_to_timecode (SCR_delay, &video_au->PTS); 
	}; 
 
	if (video_au->length > *bytes_left) 
	{ 
	    queue_buffer (buffer, *bytes_left, &video_au->DTS); 
	    video_au->length -= *bytes_left; 
	    *picture_start = FALSE; 
	} else 
	if (video_au->length == *bytes_left) 
	{ 
	    queue_buffer (buffer, *bytes_left, &video_au->DTS); 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    i=fread (video_au, sizeof(Vaunit_struc), 1, vunits_info); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	    if (i != 1) 
	    { 
		empty_vaunit_struc (video_au); 
		//status_message(STATUS_VIDEO_END); 
		return; 
	    } 
	    *picture_start = TRUE; 
	    add_to_timecode (SCR_delay, &video_au->DTS); 
	    add_to_timecode (SCR_delay, &video_au->PTS); 
	}; 
 
} 
 
 
/****************************************************************** 
	Output_Video 
	generiert Pack/Sys_Header/Packet Informationen aus dem 
	Video Stream und speichert den so erhaltenen Sektor ab. 
 
	generates Pack/Sys_Header/Packet information from the 
	video stream and writes out the new sector 
******************************************************************/ 
 
void output_video (SCR, SCR_delay, vunits_info, istream_v, ostream, 
		   pack, sys_header, sector, buffer, video_au, 
		   picture_start, bytes_output, mux_rate, 
		   audio_buffer_size, video_buffer_size, 
		   packet_data_size, marker_pack, which_streams) 
 
Timecode_struc *SCR; 
Timecode_struc *SCR_delay; 
FILE *vunits_info; 
FILE *istream_v; 
FILE *ostream; 
Pack_struc *pack; 
Sys_header_struc *sys_header; 
Sector_struc *sector; 
Buffer_struc *buffer; 
Vaunit_struc *video_au; 
unsigned char *picture_start; 
unsigned int  *bytes_output; 
unsigned int mux_rate; 
unsigned long audio_buffer_size; 
unsigned long video_buffer_size; 
unsigned long packet_data_size; 
unsigned char marker_pack; 
unsigned int which_streams; 
 
{ 
 
    unsigned int bytes_left; 
    unsigned int temp; 
    Pack_struc *pack_ptr; 
    Sys_header_struc *sys_header_ptr; 
    unsigned char timestamps; 
 
 
    if (marker_pack) 
    { 
    	/* Wir generieren den Pack Header				*/ 
	/* let's generate pack header					*/ 
    	create_pack (pack, SCR, mux_rate); 
 
    	/* Wir generieren den System Header				*/ 
	/* let's generate system header					*/ 
    	create_sys_header (sys_header, mux_rate, 1, 1, 1, 1, 1, 1, 
			AUDIO_STR_0, 0, audio_buffer_size/128, 
			VIDEO_STR_0, 1, video_buffer_size/1024, which_streams ); 
	pack_ptr = pack; 
	sys_header_ptr = sys_header; 
    } else 
    { 
	pack_ptr = NULL; 
	sys_header_ptr = NULL; 
    } 
 
    /* Wir generieren das Packet				*/ 
    /* let's generate packet					*/ 
 
    /* faengt im Packet ein Bild an?				*/ 
    /* does a frame start in this packet?			*/ 
     
    /* FALL: Packet beginnt mit neuer Access Unit		*/ 
    /* CASE: Packet starts with new access unit			*/ 
    if (*picture_start) 
    { 
	if (video_au->type == BFRAME) 
	    timestamps=TIMESTAMPS_PTS; 
	else 
	    timestamps=TIMESTAMPS_PTS_DTS; 
 
	create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_v, VIDEO_STR_0, 1, video_buffer_size/1024, 
			TRUE, &video_au->PTS, &video_au->DTS, 
		        timestamps, which_streams ); 
 
	bytes_left = sector->length_of_packet_data; 
 
	next_video_access_unit (buffer, video_au, &bytes_left, vunits_info, 
				picture_start, SCR_delay); 
 
    } 
 
    /* FALL: Packet beginnt mit alter Access Unit, es kommt	*/ 
    /*       keine neue im selben Packet vor			*/ 
    /* CASE: Packet begins with old access unit, no new one	*/ 
    /*	     begins in the very same packet			*/ 
    else if (!(*picture_start) && (video_au->length >= packet_data_size)) 
    { 
	create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_v, VIDEO_STR_0, 1, video_buffer_size/1024, 
			TRUE, NULL, NULL, 
			TIMESTAMPS_NO, which_streams ); 
 
	bytes_left = sector->length_of_packet_data; 
 
	next_video_access_unit (buffer, video_au, &bytes_left, vunits_info, 
				picture_start, SCR_delay); 
 
    } 
 
    /* FALL: Packet beginnt mit alter Access Unit, es kommt	*/ 
    /*       eine neue im selben Packet vor			*/ 
    /* CASE: Packet begins with old access unit, a new one	*/ 
    /*	     begins in the very same packet			*/ 
    else if (!(*picture_start) && (video_au->length < packet_data_size)) 
    { 
	temp = video_au->length; 
	queue_buffer (buffer, video_au->length, &video_au->DTS); 
 
	/* gibt es ueberhaupt noch eine Access Unit ? */ 
	/* is there a new access unit anyway? */ 
 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	if (fread (video_au, sizeof(Vaunit_struc), 1, vunits_info)==1) 
	{ 
	    if (video_au->type == BFRAME) 
		timestamps=TIMESTAMPS_PTS; 
	    else 
		timestamps=TIMESTAMPS_PTS_DTS; 
 
	    *picture_start = TRUE; 
	    add_to_timecode (SCR_delay, &video_au->DTS); 
	    add_to_timecode (SCR_delay, &video_au->PTS); 
	    create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_v, VIDEO_STR_0, 1, video_buffer_size/1024, 
			TRUE, &video_au->PTS, &video_au->DTS, 
			timestamps, which_streams ); 
	bytes_left = sector->length_of_packet_data - temp; 
 
	next_video_access_unit (buffer, video_au, &bytes_left, vunits_info, 
				picture_start, SCR_delay); 
	} else 
	{ 
	    //status_message(STATUS_VIDEO_END); 
	    empty_vaunit_struc (video_au); 
	    create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_v, VIDEO_STR_0, 1, video_buffer_size/1024, 
			TRUE, NULL, NULL, 
			TIMESTAMPS_NO, which_streams ); 
	}; 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
 
    } 
 
 
    /* Sector auf Platte schreiben				*/ 
    /* write out sector						*/ 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
    fwrite (sector->buf, sector->length_of_sector, 1, ostream); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
             total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
    *bytes_output += sector->length_of_sector; 
	 
} 
 
 
/****************************************************************** 
	Next_Audio_Access_Unit 
	holt aus dem TMP File, der die Info's ueber die Access 
	Units enthaelt, die jetzt gueltige Info her. Nach 
	dem Erstellen des letzten Packs sind naemlich eine 
	bestimmte Anzahl Bytes und damit AU's eingelesen worden. 
 
	gets information on access unit from the tmp file 
******************************************************************/ 
 
void next_audio_access_unit (buffer, audio_au, bytes_left, aunits_info, 
			audio_frame_start, SCR_delay) 
Buffer_struc *buffer; 
Aaunit_struc *audio_au; 
unsigned int *bytes_left; 
FILE *aunits_info; 
unsigned char *audio_frame_start; 
Timecode_struc *SCR_delay; 
 
{ 
 
	int i; 
 
	if (*bytes_left == 0) 
	    return; 
 
	while (audio_au->length < *bytes_left) 
	{ 
	    queue_buffer (buffer, audio_au->length, &audio_au->PTS); 
	    *bytes_left -= audio_au->length; 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    i=fread (audio_au, sizeof(Aaunit_struc), 1, aunits_info); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	    if (i != 1) 
	    { 
		empty_aaunit_struc (audio_au); 
		//status_message(STATUS_AUDIO_END); 
		return; 
	    } 
	    *audio_frame_start = TRUE; 
	    add_to_timecode (SCR_delay, &audio_au->PTS); 
	}; 
 
	if (audio_au->length > *bytes_left) 
	{ 
	    queue_buffer (buffer, *bytes_left, &audio_au->PTS); 
	    audio_au->length -= *bytes_left; 
	    *audio_frame_start = FALSE; 
	} else 
	if (audio_au->length == *bytes_left) 
	{ 
	    queue_buffer (buffer, *bytes_left, &audio_au->PTS); 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	    i=fread (audio_au, sizeof(Aaunit_struc), 1, aunits_info); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
	    if (i != 1) 
	    { 
		empty_aaunit_struc (audio_au); 
		//status_message(STATUS_AUDIO_END); 
		return; 
	    } 
	    *audio_frame_start = TRUE; 
	    add_to_timecode (SCR_delay, &audio_au->PTS); 
	}; 
 
} 
 
/****************************************************************** 
	Output_Audio 
	erstellt Pack/Sys_Header/Packet Informationen aus dem 
	Audio Stream und speichert den so erhaltenen Sector ab. 
 
	generates Pack/Sys Header/Packet information from the 
	audio stream and saves them into the sector 
******************************************************************/ 
 
void output_audio (SCR, SCR_delay, aunits_info, istream_a, ostream, 
		   pack, sys_header, sector, buffer, audio_au, 
		   audio_frame_start, bytes_output, mux_rate, 
		   audio_buffer_size, video_buffer_size, 
		   packet_data_size, marker_pack, which_streams) 
 
Timecode_struc *SCR; 
Timecode_struc *SCR_delay; 
FILE *aunits_info; 
FILE *istream_a; 
FILE *ostream; 
Pack_struc *pack; 
Sys_header_struc *sys_header; 
Sector_struc *sector; 
Buffer_struc *buffer; 
Aaunit_struc *audio_au; 
unsigned char *audio_frame_start; 
unsigned int  *bytes_output; 
unsigned int mux_rate; 
unsigned long audio_buffer_size; 
unsigned long video_buffer_size; 
unsigned long packet_data_size; 
unsigned char marker_pack; 
unsigned int which_streams; 
 
{ 
 
    unsigned int bytes_left; 
    unsigned int temp; 
    Pack_struc *pack_ptr; 
    Sys_header_struc *sys_header_ptr; 
 
    if (marker_pack) 
    { 
    	/* Wir generieren den Pack Header				*/ 
	/* let's generate pack header					*/ 
    	create_pack (pack, SCR, mux_rate); 
 
    	/* Wir generieren den System Header				*/ 
	/* let's generate system header					*/ 
    	create_sys_header (sys_header, mux_rate, 1, 1, 1, 1, 1, 1, 
			AUDIO_STR_0, 0, audio_buffer_size/128, 
			VIDEO_STR_0, 1, video_buffer_size/1024, which_streams ); 
	pack_ptr = pack; 
	sys_header_ptr = sys_header; 
    } 
    else 
    { 
	pack_ptr = NULL; 
	sys_header_ptr = NULL; 
    } 
 
    /* Wir generieren das Packet				*/ 
    /* Let's generate packet					*/ 
 
    /* faengt im Packet ein Audio Frame an?			*/ 
    /* does a audio frame start in this packet?			*/ 
 
    /* FALL: Packet beginnt mit neuer Access Unit			*/ 
    /* CASE: packet starts with new access unit			*/ 
    if (*audio_frame_start) 
    { 
	create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_a, AUDIO_STR_0, 0, audio_buffer_size/128, 
			TRUE, &audio_au->PTS, NULL, 
			TIMESTAMPS_PTS, which_streams); 
 
	bytes_left = sector->length_of_packet_data; 
 
	next_audio_access_unit (buffer, audio_au, &bytes_left, aunits_info, 
				audio_frame_start, SCR_delay); 
    } 
 
    /* FALL: Packet beginnt mit alter Access Unit, es kommt	*/ 
    /*       keine neue im selben Packet vor			*/ 
    /* CASE: packet starts with old access unit, no new one	*/ 
    /*       starts in this very same packet			*/ 
    else if (!(*audio_frame_start) && (audio_au->length >= packet_data_size)) 
    { 
	create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_a, AUDIO_STR_0, 0, audio_buffer_size/128, 
			TRUE, NULL, NULL, 
			TIMESTAMPS_NO, which_streams ); 
 
	bytes_left = sector->length_of_packet_data; 
 
	next_audio_access_unit (buffer, audio_au, &bytes_left, aunits_info, 
				audio_frame_start, SCR_delay); 
    } 
 
    /* FALL: Packet beginnt mit alter Access Unit, es kommt	*/ 
    /*       eine neue im selben Packet vor			*/ 
    /* CASE: packet starts with old access unit, a new one	*/ 
    /*       starts in this very same packet			*/ 
    else if (!(*audio_frame_start) && (audio_au->length < packet_data_size)) 
    { 
	temp = audio_au->length; 
	queue_buffer (buffer, audio_au->length, &audio_au->PTS); 
 
	/* gibt es ueberhaupt noch eine Access Unit ? */ 
	/* is there another access unit anyway ? */ 
 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
	if (fread (audio_au, sizeof(Aaunit_struc), 1, aunits_info)==1) 
	{ 
	    *audio_frame_start = TRUE; 
	    add_to_timecode (SCR_delay, &audio_au->PTS); 
	    create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_a, AUDIO_STR_0, 0, audio_buffer_size/128, 
			TRUE, &audio_au->PTS, NULL, 
			TIMESTAMPS_PTS, which_streams ); 
 
	bytes_left = sector->length_of_packet_data - temp; 
 
	next_audio_access_unit (buffer, audio_au, &bytes_left, aunits_info, 
				audio_frame_start, SCR_delay); 
	} else 
	{ 
	    //status_message(STATUS_AUDIO_END); 
	    empty_aaunit_struc (audio_au); 
	    create_sector (sector, pack_ptr, sys_header_ptr, 
			packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
			istream_a, AUDIO_STR_0, 0, audio_buffer_size/128, 
			TRUE, NULL, NULL, 
			TIMESTAMPS_NO, which_streams ); 
	}; 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
 
 
    } 
 
    /* Sector auf Platte schreiben				*/ 
    /* write out sector onto disk				*/ 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
    fwrite (sector->buf, sector->length_of_sector, 1, ostream); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
    *bytes_output += sector->length_of_sector; 
 
	 
} 
 
/****************************************************************** 
	Output_Padding 
	erstellt Pack/Sys_Header/Packet Informationen zu einem 
	Padding-Stream und speichert den so erhaltenen Sector ab. 
 
	generates Pack/Sys Header/Packet information for a  
	padding stream and saves the sector 
******************************************************************/ 
 
void output_padding (SCR,  ostream, 
		   pack, sys_header, sector, bytes_output, mux_rate, 
		   audio_buffer_size, video_buffer_size, 
		   packet_data_size, marker_pack, which_streams) 
 
Timecode_struc *SCR; 
FILE *ostream; 
Pack_struc *pack; 
Sys_header_struc *sys_header; 
Sector_struc *sector; 
unsigned int  *bytes_output; 
unsigned int mux_rate; 
unsigned long audio_buffer_size; 
unsigned long video_buffer_size; 
unsigned long packet_data_size; 
unsigned char marker_pack; 
unsigned int which_streams; 
 
{ 
    //unsigned int bytes_left; 
    //unsigned int temp; 
    Pack_struc *pack_ptr; 
    Sys_header_struc *sys_header_ptr; 
 
    if (marker_pack) 
    { 
    	/* Wir generieren den Pack Header				*/ 
	/* let's generate the pack header				*/ 
    	create_pack (pack, SCR, mux_rate); 
 
    	/* Wir generieren den System Header				*/ 
	/* let's generate the system header				*/ 
    	create_sys_header (sys_header, mux_rate, 1, 1, 1, 1, 1, 1, 
			AUDIO_STR_0, 0, audio_buffer_size/128, 
			VIDEO_STR_0, 1, video_buffer_size/1024, which_streams ); 
	pack_ptr = pack; 
	sys_header_ptr = sys_header; 
    } 
    else 
    { 
	pack_ptr = NULL; 
	sys_header_ptr = NULL; 
    } 
 
    /* Wir generieren das Packet				*/ 
    /* let's generate the packet				*/ 
    create_sector (sector, pack_ptr, sys_header_ptr, 
		packet_data_size+PACKET_HEADER_SIZE+AFTER_PACKET_LENGTH, 
		NULL, PADDING_STR, 0, 0, 
		FALSE, NULL, NULL, 
		TIMESTAMPS_NO, which_streams ); 
 
#ifdef TIMER 
            gettimeofday (&tp_start,NULL); 
#endif  
    fwrite (sector->buf, sector->length_of_sector*sizeof (unsigned char), 1, 
	    ostream); 
#ifdef TIMER 
            gettimeofday (&tp_end,NULL); 
            total_sec  += (tp_end.tv_sec - tp_start.tv_sec); 
            total_usec += (tp_end.tv_usec - tp_start.tv_usec); 
#endif 
    *bytes_output += sector->length_of_sector; 
	 
}