multiplexor.cpp

来自「Motion JPEG编解码器源代码」· C++ 代码 · 共 1,502 行 · 第 1/4 页

CPP
1,502
字号
			break;		case ElementaryStream::audio :			mjpeg_log( level,					   "Audio %02x: buf=%7d frame=%06d sector=%08d",					   (*str)->stream_id,					   (*str)->BufferSize()-(*str)->bufmodel.Space(),					   (*str)->DecodeOrder(),					   (*str)->nsec				);			break;		default :			mjpeg_log( level,					   "Other %02x: buf=%7d sector=%08d",					   (*str)->stream_id,					   (*str)->bufmodel.Space(),					   (*str)->nsec				);			break;		}	}	if( !vbr )		mjpeg_log( level,				   "Padding : sector=%08d",				   pstrm.nsec			);		}/**   Append input substreams to the output multiplex stream. */void Multiplexor::AppendMuxStreamsOf( vector<ElementaryStream *> &elem,                                        vector<MuxStream *> &mux ){	std::vector<ElementaryStream *>::iterator str;    for( str = elem.begin(); str < elem.end(); ++str )    {        mux.push_back( static_cast<MuxStream *>( *str ) );    }}/******************************************************************    Program start-up packets.  Generate any irregular packets						needed at the start of the stream...	Note: *must* leave a sensible in-stream system header in	sys_header.	TODO: get rid of this grotty sys_header global.******************************************************************/void Multiplexor::OutputPrefix( ){    vector<MuxStream *> vmux,amux,emux;    AppendMuxStreamsOf( vstreams, vmux );    AppendMuxStreamsOf( astreams, amux );    AppendMuxStreamsOf( estreams, emux );	/* Deal with transport padding */	SetPosAndSCR( bytes_output + 				  transport_prefix_sectors*sector_transport_size );		/* VCD: Two padding packets with video and audio system headers */	switch (mux_format)	{	case MPEG_FORMAT_VCD :	case MPEG_FORMAT_VCD_NSR :		/* Annoyingly VCD generates seperate system headers for		   audio and video ... DOH... */		if( astreams.size() > 1 || vstreams.size() > 1 ||			astreams.size() + vstreams.size() != estreams.size() )		{				mjpeg_error_exit1("VCD man only have max. 1 audio and 1 video stream");		}        if( vstreams.size() > 0 )        {		/* First packet carries video-info-only sys_header */		psstrm->CreateSysHeader (&sys_header, mux_rate, 								 false, true, 								 true, true, vmux  );		sys_header_ptr = &sys_header;		pack_header_ptr = &pack_header;	  	OutputPadding( false);		        }        if( astreams.size() > 0 )        {            /* Second packet carries audio-info-only sys_header */            psstrm->CreateSysHeader (&sys_header, mux_rate,                                       false, true,                                      true, true, amux );            sys_header_ptr = &sys_header;            pack_header_ptr = &pack_header;            OutputPadding( true );        }        break;			case MPEG_FORMAT_SVCD :	case MPEG_FORMAT_SVCD_NSR :		/* First packet carries sys_header */		psstrm->CreateSysHeader (&sys_header, mux_rate,  !vbr, true,                                  true, true, emux );		sys_header_ptr = &sys_header;		pack_header_ptr = &pack_header;	  	OutputPadding(false);        break;	case MPEG_FORMAT_VCD_STILL :		/* First packet carries small-still sys_header */		/* TODO No support mixed-mode stills sequences... */		psstrm->CreateSysHeader (&sys_header, mux_rate, false, false,								 true, true, emux );		sys_header_ptr = &sys_header;		pack_header_ptr = &pack_header;		OutputPadding(  false);	        break;				case MPEG_FORMAT_SVCD_STILL :		/* TODO: Video only at present */		/* First packet carries video-info-only sys_header */		psstrm->CreateSysHeader (&sys_header, mux_rate, 								 false, true, 								 true, true, vmux );		sys_header_ptr = &sys_header;		pack_header_ptr = &pack_header;	  	OutputPadding( false);				break;    case MPEG_FORMAT_DVD_NAV :        /* A DVD System header is a weird thing.  We seem to need to           include buffer info about streams 0xb8, 0xb9, 0xbd, 0xbf even if           they're not physically present but the buffers for the actual           video streams aren't included.          */    {        // MANY DVD streams appear not to include system headers        // and some tools have weak parsers that can't handle all        // the possible variations. Soooo probably best not to generate        // them        DummyMuxStream dvd_0xb9_strm_dummy( 0xb9, 1, 232*1024 );        DummyMuxStream dvd_0xb8_strm_dummy( 0xb8, 0, 4096 );        DummyMuxStream dvd_0xbf_strm_dummy( 0xbf, 1, 2048 );        vector<MuxStream *> dvdmux;		std::vector<MuxStream *>::iterator muxstr;        dvdmux.push_back( &dvd_0xb9_strm_dummy );        dvdmux.push_back( &dvd_0xb8_strm_dummy );        unsigned int max_priv1_buffer = 58*1024;        for( muxstr = amux.begin(); muxstr < amux.end(); ++muxstr )        {            // We mux *many* substreams on PRIVATE_STR_1            // we set the system header buffer size to the maximum            // of all those we find            if( (*muxstr)->stream_id == PRIVATE_STR_1 )             {                if( (*muxstr)->BufferSize() > max_priv1_buffer )                    max_priv1_buffer = (*muxstr)->BufferSize();            }            // Now the *sane* thing to do if MPEG audio is present would be            // record this in the system header.  However, dvdauthor lacks            // a header parser and barfs if the system headers aren't exactly            // 18 bytes.  Soooo we simply skip them for now...            // TOOD: Add back in when dvdauthor can parse system headers            //else            //    dvdmux.push_back( *muxstr );        }                DummyMuxStream dvd_priv1_strm_dummy( PRIVATE_STR_1, 1,                                              max_priv1_buffer );        dvdmux.push_back( &dvd_priv1_strm_dummy );                    dvdmux.push_back( &dvd_0xbf_strm_dummy );        psstrm->CreateSysHeader (&sys_header, mux_rate, !vbr, false,                                  true, true, dvdmux );        sys_header_ptr = &sys_header;        pack_header_ptr = &pack_header;        /* It is then followed up by a pair of PRIVATE_STR_2 packets which            we keep empty 'cos we don't know what goes there...        */    }    break;    default :        /* Create the in-stream header in case it is needed */        psstrm->CreateSysHeader (&sys_header, mux_rate, !vbr, false,                                  true, true, emux );	}}/******************************************************************    Program shutdown packets.  Generate any irregular packets    needed at the end of the stream...   ******************************************************************/void Multiplexor::OutputSuffix(){	psstrm->CreatePack (&pack_header, current_SCR, mux_rate);	psstrm->CreateSector (&pack_header, NULL,						  0,						  pstrm, 						  false,						  true,						  0, 0,						  TIMESTAMPBITS_NO );}/******************************************************************	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 Multiplexor::Multiplex(){	segment_state seg_state;	std::vector<bool> completed;	std::vector<bool>::iterator pcomp;	std::vector<ElementaryStream *>::iterator str;	unsigned int packets_left_in_pack = 0; /* Suppress warning */	bool padding_packet;	bool video_first = true;	Init( );	unsigned int i;    for(i = 0; i < estreams.size() ; ++i )		completed.push_back(false);    	/*  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	  		Of course, when we start we're starting a new segment with no		bytes output...	*/	ByteposTimecode( sector_transport_size, ticks_per_sector );	seg_state = start_segment;	running_out = false;	for(;;)	{		bool completion = true;		for( str = estreams.begin(); str < estreams.end() ; ++str )			completion &= (*str)->MuxCompleted();		if( completion )			break;		/* A little state-machine for handling the transition from one		   segment to the next 		*/		bool runout_incomplete;		VideoStream *master;		switch( seg_state )		{			/* Audio and slave video access units at end of segment.			   If there are any audio AU's whose PTS implies they			   should be played *before* the video AU starting the			   next segement is presented we mux them out.  Once			   they're gone we've finished this segment so we write			   the suffix switch file, and start muxing a new segment.			*/		case runout_segment :			runout_incomplete = false;			for( str = estreams.begin(); str < estreams.end(); ++str )			{				runout_incomplete |= !(*str)->RunOutComplete();			}			if( runout_incomplete )				break;			/* Otherwise we write the stream suffix and start a new			   stream file */			OutputSuffix();			psstrm->NextSegment();			running_out = false;			seg_state = start_segment;			/* Starting a new segment.			   We send the segment prefix, video and audio reciever			   buffers are assumed to start empty.  We reset the segment			   length count and hence the SCR.			   			*/		case start_segment :			mjpeg_info( "New sequence commences..." );			SetPosAndSCR(0);			MuxStatus( LOG_INFO );			for( str = estreams.begin(); str < estreams.end(); ++str )			{				(*str)->AllDemuxed();			}			packets_left_in_pack = packets_per_pack;            start_of_new_pack = true;			include_sys_header = sys_header_in_pack1;			buffers_in_video = always_buffers_in_video;			video_first = seg_starts_with_video & (vstreams.size() > 0);			OutputPrefix();			/* Set the offset applied to the raw PTS/DTS of AU's to               make the DTS of the first AU in the master (video) stream               precisely the video delay plus whatever time we wasted in               the sequence pre-amble.               The DTS of the remaining streams are set so that               (modulo the relevant delay offset) they maintain the               same relative timing to the master stream.               			*/            clockticks ZeroSCR;            if( vstreams.size() != 0 )                ZeroSCR = vstreams[0]->BaseDTS();            else                ZeroSCR = estreams[0]->BaseDTS();			for( str = vstreams.begin(); str < vstreams.end(); ++str )				(*str)->SetSyncOffset(video_delay + current_SCR - ZeroSCR );			for( str = astreams.begin(); str < astreams.end(); ++str )				(*str)->SetSyncOffset(audio_delay + current_SCR - ZeroSCR );			pstrm.nsec = 0;			for( str = estreams.begin(); str < estreams.end(); ++str )				(*str)->nsec = 0;			seg_state = mid_segment;			break;		case mid_segment :			/* Once we exceed our file size limit, we need to			   start a new file soon.  If we want a single stream we			   simply switch.							   Otherwise we're in the last gop of the current segment			   (and need to start running streams out ready for a			   clean continuation in the next segment).			   TODO: runout_PTS really needs to be expressed in			   sync delay adjusted units...			*/						master = 				vstreams.size() > 0 ? 				static_cast<VideoStream*>(vstreams[0]) : 0 ;			if( psstrm->SegmentLimReached() )			{				if( split_at_seq_end )                    mjpeg_warn( "File size exceeded before split-point in video stream" );                mjpeg_info( "Starting new output file...");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?