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 + -
显示快捷键?