multiplexor.cpp
来自「Motion JPEG编解码器源代码」· C++ 代码 · 共 1,502 行 · 第 1/4 页
CPP
1,502 行
std::vector<VideoParams *>::iterator vidparm = job.video_param.begin(); std::vector<LpcmParams *>::iterator lpcmparm = job.lpcm_param.begin(); std::vector<JobStream *>::iterator i; for( i = job.streams.begin() ; i < job.streams.end() ; ++i ) { switch( (*i)->kind ) { case MPEG_VIDEO : { VideoStream *videoStrm; // // The first video stream is made the master stream... // if( video_track == 0 && job.mux_format == MPEG_FORMAT_DVD_NAV ) videoStrm = new DVDVideoStream( *(*i)->bs, *vidparm, *this); else videoStrm = new VideoStream( *(*i)->bs, *vidparm, *this); videoStrm->Init( video_track ); ++video_track; ++vidparm; estreams.push_back( videoStrm ); vstreams.push_back( videoStrm ); } break; case MPEG_AUDIO : { AudioStream *audioStrm = new MPAStream( *(*i)->bs, *this); audioStrm->Init ( audio_track ); estreams.push_back(audioStrm); astreams.push_back(audioStrm); ++audio_track; } break; case AC3_AUDIO : { AudioStream *audioStrm = new AC3Stream( *(*i)->bs, *this); audioStrm->Init ( audio_track ); estreams.push_back(audioStrm); astreams.push_back(audioStrm); ++audio_track; } break; case DTS_AUDIO : { AudioStream *audioStrm = new DTSStream( *(*i)->bs, *this); audioStrm->Init ( audio_track ); estreams.push_back(audioStrm); astreams.push_back(audioStrm); ++audio_track; } break; case LPCM_AUDIO : { AudioStream *audioStrm = new LPCMStream( *(*i)->bs, *lpcmparm, *this); audioStrm->Init ( audio_track ); estreams.push_back(audioStrm); astreams.push_back(audioStrm); ++lpcmparm; ++audio_track; } break;#ifdef ZALPHA // just copies the video parameters from the first video stream case Z_ALPHA : { ZAlphaStream *zalphaStrm = new ZAlphaStream( *(*i)->bs, *(job.video_param.begin()), *this); zalphaStrm->Init (0); estreams.push_back(zalphaStrm); vstreams.push_back(zalphaStrm); //++vidparm; }#endif } }}/******************************************************************* Find the timecode corresponding to given position in the system stream (assuming the SCR starts at 0 at the beginning of the stream @param bytepos byte position in the stream@param ts returns the number of clockticks the bytepos is from the file start ****************************************************************** */void Multiplexor::ByteposTimecode(bitcount_t bytepos, clockticks &ts){ ts = (bytepos*CLOCKS)/static_cast<bitcount_t>(dmux_rate);}/********** * * NextPosAndSCR - Update nominal (may be >= actual) byte count * and SCR to next output sector. * ********/void Multiplexor::NextPosAndSCR(){ bytes_output += sector_transport_size; ByteposTimecode( bytes_output, current_SCR ); if (start_of_new_pack) { psstrm->CreatePack (&pack_header, current_SCR, mux_rate); pack_header_ptr = &pack_header; if( include_sys_header ) sys_header_ptr = &sys_header; else sys_header_ptr = NULL; } else pack_header_ptr = NULL;}/********** * * SetPosAndSCR - Update nominal (may be >= actual) byte count * and SCR to next output sector. * @param bytepos byte position in the stream ********/void Multiplexor::SetPosAndSCR( bitcount_t bytepos ){ bytes_output = bytepos; ByteposTimecode( bytes_output, current_SCR ); if (start_of_new_pack) { psstrm->CreatePack (&pack_header, current_SCR, mux_rate); pack_header_ptr = &pack_header; if( include_sys_header ) sys_header_ptr = &sys_header; else sys_header_ptr = NULL; } else pack_header_ptr = NULL;}/* Stream syntax parameters.*/ typedef enum { start_segment, mid_segment, runout_segment }segment_state;/** * Compute the number of run-in sectors needed to fill up the buffers to * suit the type of stream being muxed. * * For stills we have to ensure an entire buffer is loaded as we only * ever process one frame at a time. * @returns the number of run-in sectors needed to fill up the buffers to suit the type of stream being muxed. */unsigned int Multiplexor::RunInSectors(){ std::vector<ElementaryStream *>::iterator str; unsigned int sectors_delay = 1; for( str = vstreams.begin(); str < vstreams.end(); ++str ) { if( MPEG_STILLS_FORMAT( mux_format ) ) { sectors_delay += static_cast<unsigned int>(1.02*(*str)->BufferSize()) / sector_size+2; } else if( vbr ) sectors_delay += 3*(*str)->BufferSize() / ( 4 * sector_size ); else sectors_delay += 5 *(*str)->BufferSize() / ( 6 * sector_size ); } sectors_delay += astreams.size(); return sectors_delay;}/********************************************************************** * * Initializes the output stream proper. Traverses the input files * and calculates their payloads. Estimates the multiplex * rate. Estimates the necessary stream delay for the different * substreams. * *********************************************************************/void Multiplexor::Init(){ std::vector<ElementaryStream *>::iterator str; clockticks delay; unsigned int sectors_delay; Pack_struc dummy_pack; Sys_header_struc dummy_sys_header; Sys_header_struc *sys_hdr; unsigned int nominal_rate_sum; mjpeg_info("SYSTEMS/PROGRAM stream:"); psstrm->Open(); /* These are used to make (conservative) decisions about whether a packet should fit into the recieve buffers... Audio packets always have PTS fields, video packets needn'. TODO: Really this should be encapsulated in Elementary stream...? */ psstrm->CreatePack (&dummy_pack, 0, mux_rate); if( always_sys_header_in_pack ) { vector<MuxStream *> muxstreams; AppendMuxStreamsOf( estreams, muxstreams ); psstrm->CreateSysHeader (&dummy_sys_header, mux_rate, !vbr, 1, true, true, muxstreams); sys_hdr = &dummy_sys_header; } else sys_hdr = NULL; nominal_rate_sum = 0; for( str = estreams.begin(); str < estreams.end(); ++str ) { switch( (*str)->Kind() ) { case ElementaryStream::audio : (*str)->SetMaxPacketData( psstrm->PacketPayload( **str, NULL, NULL, false, true, false ) ); (*str)->SetMinPacketData( psstrm->PacketPayload( **str, sys_hdr, &dummy_pack, always_buffers_in_audio, true, false ) ); break; case ElementaryStream::video : (*str)->SetMaxPacketData( psstrm->PacketPayload( **str, NULL, NULL, false, false, false ) ); (*str)->SetMinPacketData( psstrm->PacketPayload( **str, sys_hdr, &dummy_pack, always_buffers_in_video, true, true ) ); break; default : mjpeg_error_exit1("INTERNAL: Only audio and video payload calculations implemented!"); } if( (*str)->NominalBitRate() == 0 && data_rate == 0) mjpeg_error_exit1( "Variable bit-rate stream present: output stream (max) data-rate *must* be specified!"); nominal_rate_sum += (*str)->NominalBitRate(); } /* Attempt to guess a sensible mux rate for the given video and * audio estreams. This is a rough and ready guess for MPEG-1 like formats. */ dmux_rate = static_cast<int>(1.0205 * nominal_rate_sum); dmux_rate = (dmux_rate/50 + 25)*50/8; mjpeg_info ("rough-guess multiplexed stream data rate : %07d", dmux_rate*8 ); if( data_rate != 0 ) mjpeg_info ("target data-rate specified : %7d", data_rate*8 ); if( data_rate == 0 ) { mjpeg_info( "Setting best-guess data rate."); } else if ( data_rate >= dmux_rate) { mjpeg_info( "Setting specified specified data rate: %7d", data_rate*8 ); dmux_rate = data_rate; } else if ( data_rate < dmux_rate ) { mjpeg_warn( "Target data rate lower than computed requirement!"); mjpeg_warn( "N.b. a 20%% or so discrepancy in variable bit-rate"); mjpeg_warn( "streams is common and harmless provided no time-outs will occur"); dmux_rate = data_rate; } mux_rate = dmux_rate/50; // // Now that all mux parameters are set we can trigger parsing // of actual input stream data and calculation of associated // PTS/DTS by causing the read of the first AU's... // for( str = estreams.begin(); str < estreams.end(); ++str ) { (*str)->NextAU(); } // // Now that we have both output and input streams initialised and // data-rates set we can make a decent job of setting the maximum // STD buffer delay in video streams. // for( str = vstreams.begin(); str < vstreams.end(); ++str ) { static_cast<VideoStream*>(*str)->SetMaxStdBufferDelay( dmux_rate ); } /* To avoid Buffer underflow, the DTS of the first video and audio AU's must be offset sufficiently forward of the SCR to allow the buffer time to fill before decoding starts. Calculate the necessary delays... */ sectors_delay = RunInSectors(); ByteposTimecode( static_cast<bitcount_t>(sectors_delay*sector_transport_size), delay ); video_delay += delay; audio_delay += delay; /* * The PTS of the first frame may be different from its DTS. * Thus to hit perfect A/V sync we need to delay audio by the difference * PTS-DTS. * */ if( vstreams.size() != 0 ) { audio_delay += vstreams[0]->BasePTS()-vstreams[0]->BaseDTS(); } mjpeg_info( "Run-in Sectors = %d Video delay = %lld Audio delay = %lld", sectors_delay, video_delay / 300, audio_delay / 300 ); if( max_PTS != 0 ) mjpeg_info( "Multiplexed stream will be ended at %lld seconds playback time\n", max_PTS/CLOCKS );}/** Prints the current status of the substreams. @param level the desired log level */void Multiplexor::MuxStatus(log_level_t level){ std::vector<ElementaryStream *>::iterator str; for( str = estreams.begin(); str < estreams.end(); ++str ) { switch( (*str)->Kind() ) { case ElementaryStream::video : mjpeg_log( level, "Video %02x: buf=%7d frame=%06d sector=%08d", (*str)->stream_id, (*str)->BufferSize()-(*str)->bufmodel.Space(), (*str)->DecodeOrder(), (*str)->nsec );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?