diff options
author | Ronald S. Bultje <rbultje@ronald.bitfreak.net> | 2004-01-01 22:45:57 +0000 |
---|---|---|
committer | Ronald S. Bultje <rbultje@ronald.bitfreak.net> | 2004-01-01 22:45:57 +0000 |
commit | 9003ed34ba8e694b44433597c890affac369c368 (patch) | |
tree | dca1fa1b1decb37f42397813935add00b4f13182 /gst-libs/ext/mplex/multplex.cc | |
parent | 0e3024712e2a935d1f5b216cd4d7794a0132c522 (diff) | |
download | gst-plugins-bad-9003ed34ba8e694b44433597c890affac369c368.tar.gz gst-plugins-bad-9003ed34ba8e694b44433597c890affac369c368.tar.bz2 gst-plugins-bad-9003ed34ba8e694b44433597c890affac369c368.zip |
configure.ac: Fix configure check for mpeg2enc. We need 1.6.1.93 instead of 1.6.1.92, since the pkg-config file of 1....
Original commit message from CVS:
2004-01-01 Ronald Bultje <rbultje@ronald.bitfreak.net>
* configure.ac:
Fix configure check for mpeg2enc. We need 1.6.1.93 instead of
1.6.1.92, since the pkg-config file of 1.6.1.92 is borked and
it therefore uses the wrong include paths. Too bad... Note
that 1.6.1.93 is not release yet. ;).
Also add a check for mplex, which is now using the lib'ified
mplex from mjpegtools, too.
* ext/ffmpeg/gstffmpegcodecmap.c:
Add codec_tag for 3ivx/xvid. For xvid, this should fix playback
issues. I don't think ffmpeg handles 3ivx correctly, so this
probably won't work. But it won't hurt either.
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_connect),
(gst_ffmpegdec_chain):
* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_connect),
(gst_ffmpegenc_chain_audio):
Fix memleak in audio encoding. Close codec if open fails, this
calls the cleanup routines so we can re-use the context.
* ext/mpeg2enc/gstmpeg2enc.cc:
Fix pad template names/types, fix memory issue with getcaps().
* ext/mpeg2enc/gstmpeg2encoder.cc:
* ext/mpeg2enc/gstmpeg2encoder.hh:
Fix compile issue with new caps system (const thingy).
* ext/mpeg2enc/gstmpeg2encpicturereader.cc:
* ext/mpeg2enc/gstmpeg2encpicturereader.hh:
We read a first frame right on initing, so that we have a caps
when we init the output. This caps is cached in padprivate and
read as first frame.
* ext/mplex/Makefile.am:
* ext/mplex/gstmplex.cc:
* ext/mplex/gstmplex.h:
* ext/mplex/gstmplex.hh:
* ext/mplex/gstmplexibitstream.cc:
* ext/mplex/gstmplexibitstream.hh:
* ext/mplex/gstmplexjob.cc:
* ext/mplex/gstmplexjob.hh:
* ext/mplex/gstmplexoutputstream.cc:
* ext/mplex/gstmplexoutputstream.hh:
We wrap mjpegtools mplex. So I rewrote the plugin. The old plugin
had issues, didn't do capsnego, supported only a subset of the
mplex features and required a mplex fork in our local CVS. Plus
that it worked agaist a very old mplex version. Rewriting was
faster than updating it.
* gst-libs/ext/Makefile.am:
* gst-libs/ext/mplex/INSTRUCT:
* gst-libs/ext/mplex/Makefile.am:
* gst-libs/ext/mplex/README:
* gst-libs/ext/mplex/TODO:
* gst-libs/ext/mplex/ac3strm_in.cc:
* gst-libs/ext/mplex/audiostrm.hh:
* gst-libs/ext/mplex/audiostrm_out.cc:
* gst-libs/ext/mplex/aunit.hh:
* gst-libs/ext/mplex/bits.cc:
* gst-libs/ext/mplex/bits.hh:
* gst-libs/ext/mplex/buffer.cc:
* gst-libs/ext/mplex/buffer.hh:
* gst-libs/ext/mplex/fastintfns.h:
* gst-libs/ext/mplex/format_codes.h:
* gst-libs/ext/mplex/inputstrm.cc:
* gst-libs/ext/mplex/inputstrm.hh:
* gst-libs/ext/mplex/lpcmstrm_in.cc:
* gst-libs/ext/mplex/mjpeg_logging.cc:
* gst-libs/ext/mplex/mjpeg_logging.h:
* gst-libs/ext/mplex/mjpeg_types.h:
* gst-libs/ext/mplex/mpastrm_in.cc:
* gst-libs/ext/mplex/mpegconsts.cc:
* gst-libs/ext/mplex/mpegconsts.h:
* gst-libs/ext/mplex/mplexconsts.hh:
* gst-libs/ext/mplex/multplex.cc:
* gst-libs/ext/mplex/outputstream.hh:
* gst-libs/ext/mplex/padstrm.cc:
* gst-libs/ext/mplex/padstrm.hh:
* gst-libs/ext/mplex/stillsstream.cc:
* gst-libs/ext/mplex/stillsstream.hh:
* gst-libs/ext/mplex/systems.cc:
* gst-libs/ext/mplex/systems.hh:
* gst-libs/ext/mplex/vector.cc:
* gst-libs/ext/mplex/vector.hh:
* gst-libs/ext/mplex/videostrm.hh:
* gst-libs/ext/mplex/videostrm_in.cc:
* gst-libs/ext/mplex/videostrm_out.cc:
* gst-libs/ext/mplex/yuv4mpeg.cc:
* gst-libs/ext/mplex/yuv4mpeg.h:
* gst-libs/ext/mplex/yuv4mpeg_intern.h:
* gst-libs/ext/mplex/yuv4mpeg_ratio.cc:
We don't fork mjpegtools' mplex in our CVS anymore.
* gst/avi/gstavidemux.c: (gst_avi_demux_src_getcaps),
(gst_avi_demux_add_stream):
* gst/avi/gstavidemux.h:
Add getcaps() function for proper caps nego. This makes some
parts of AVI playback/reading work.
* sys/ximage/ximagesink.c: (gst_ximagesink_sinkconnect):
Resize window on new capsnego. This is probably wrong, but
I'm still committing it because with current capsnego, the
first successfull capsnego is auto-fixated, therefore rounded
down to the lowest values in the caps. this results in a 16x16
XWindow that is not reized when real capsnego finishes.
Dave, I see more cases of this, do you know a proper solution?
* tools/gst-launch-ext.in:
Fix MPEG-4 AAC (Apple iPod/iTunes) file commandline.
Diffstat (limited to 'gst-libs/ext/mplex/multplex.cc')
-rw-r--r-- | gst-libs/ext/mplex/multplex.cc | 1125 |
1 files changed, 0 insertions, 1125 deletions
diff --git a/gst-libs/ext/mplex/multplex.cc b/gst-libs/ext/mplex/multplex.cc deleted file mode 100644 index b7cd02ce..00000000 --- a/gst-libs/ext/mplex/multplex.cc +++ /dev/null @@ -1,1125 +0,0 @@ - -#include <config.h> -#include <math.h> -#include <stdlib.h> -#include <unistd.h> - -#include <mjpeg_types.h> -#include <mjpeg_logging.h> -#include <format_codes.h> - -#include "videostrm.hh" -#include "outputstream.hh" -#include <cassert> - - -/******************************************************************* - 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 -OutputStream::ByteposTimecode (bitcount_t bytepos, clockticks & ts) -{ - ts = (bytepos * CLOCKS) / static_cast < bitcount_t > (dmux_rate); -} - - -/********** - * - * UpdateSectorHeaders - Update the sector headers after a change in stream - * position / SCR - ********** - - ********** - * - * NextPosAndSCR - Update nominal (may be >= actual) byte count - * and SCR to next output sector. - * - ********/ - -void -OutputStream::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; -} - - -/********** - * - * NextPosAndSCR - Update nominal (may be >= actual) byte count - * and SCR to next output sector. - * @param bytepos byte position in the stream - ********/ - -void -OutputStream::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. -*/ - - -/****************************************************************** - - Initialisation of stream syntax paramters based on selected - user options. -******************************************************************/ - - -// TODO: this mixes class member parameters with opt_ globals... - -void -OutputStream::InitSyntaxParameters () -{ - video_buffer_size = 0; - seg_starts_with_video = false; - audio_buffer_size = 4 * 1024; - - switch (opt_mux_format) { - case MPEG_FORMAT_VCD: - opt_data_rate = 75 * 2352; /* 75 raw CD sectors/sec */ - video_buffer_size = 46 * 1024; - opt_VBR = 0; - - case MPEG_FORMAT_VCD_NSR: /* VCD format, non-standard rate */ - mjpeg_info ("Selecting VCD output profile"); - if (video_buffer_size == 0) - video_buffer_size = opt_buffer_size * 1024; - vbr = opt_VBR; - opt_mpeg = 1; - packets_per_pack = 1; - sys_header_in_pack1 = 0; - always_sys_header_in_pack = 0; - sector_transport_size = 2352; /* Each 2352 bytes with 2324 bytes payload */ - transport_prefix_sectors = 30; - sector_size = 2324; - buffers_in_video = 1; - always_buffers_in_video = 0; - buffers_in_audio = 1; // This is needed as otherwise we have - always_buffers_in_audio = 1; // to stuff the packer header which - // must be 13 bytes for VCD audio - vcd_zero_stuffing = 20; // The famous 20 zero bytes for VCD - // audio sectors. - dtspts_for_all_vau = false; - sector_align_iframeAUs = false; - timestamp_iframe_only = false; - seg_starts_with_video = true; - break; - - case MPEG_FORMAT_MPEG2: - mjpeg_info ("Selecting generic MPEG2 output profile"); - opt_mpeg = 2; - packets_per_pack = 1; - sys_header_in_pack1 = 1; - always_sys_header_in_pack = 0; - sector_transport_size = 2048; /* Each 2352 bytes with 2324 bytes payload */ - transport_prefix_sectors = 0; - sector_size = 2048; - video_buffer_size = 234 * 1024; - buffers_in_video = 1; - always_buffers_in_video = 0; - buffers_in_audio = 1; - always_buffers_in_audio = 1; - vcd_zero_stuffing = 0; - dtspts_for_all_vau = 0; - sector_align_iframeAUs = false; - timestamp_iframe_only = false; - video_buffers_iframe_only = false; - vbr = opt_VBR; - break; - - case MPEG_FORMAT_SVCD: - opt_data_rate = 150 * 2324; - video_buffer_size = 230 * 1024; - - case MPEG_FORMAT_SVCD_NSR: /* Non-standard data-rate */ - mjpeg_info ("Selecting SVCD output profile"); - if (video_buffer_size == 0) - video_buffer_size = opt_buffer_size * 1024; - opt_mpeg = 2; - packets_per_pack = 1; - sys_header_in_pack1 = 0; - always_sys_header_in_pack = 0; - sector_transport_size = 2324; - transport_prefix_sectors = 0; - sector_size = 2324; - vbr = true; - buffers_in_video = 1; - always_buffers_in_video = 0; - buffers_in_audio = 1; - always_buffers_in_audio = 0; - vcd_zero_stuffing = 0; - dtspts_for_all_vau = 0; - sector_align_iframeAUs = true; - seg_starts_with_video = true; - timestamp_iframe_only = false; - video_buffers_iframe_only = false; - break; - - case MPEG_FORMAT_VCD_STILL: - opt_data_rate = 75 * 2352; /* 75 raw CD sectors/sec */ - vbr = false; - opt_mpeg = 1; - packets_per_pack = 1; - sys_header_in_pack1 = 0; - always_sys_header_in_pack = 0; - sector_transport_size = 2352; /* Each 2352 bytes with 2324 bytes payload */ - transport_prefix_sectors = 0; - sector_size = 2324; - buffers_in_video = 1; - always_buffers_in_video = 0; - buffers_in_audio = 1; - always_buffers_in_audio = 0; - vcd_zero_stuffing = 20; - dtspts_for_all_vau = 1; - sector_align_iframeAUs = true; - timestamp_iframe_only = false; - video_buffers_iframe_only = false; - if (opt_buffer_size == 0) - opt_buffer_size = 46; - else if (opt_buffer_size > 220) { - mjpeg_error_exit1 ("VCD stills has max. permissible video buffer size of 220KB"); - } else { - /* Add a margin for sequence header overheads for HR stills */ - /* So the user simply specifies the nominal size... */ - opt_buffer_size += 4; - } - video_buffer_size = opt_buffer_size * 1024; - break; - - case MPEG_FORMAT_SVCD_STILL: - mjpeg_info ("Selecting SVCD output profile"); - if (opt_data_rate == 0) - opt_data_rate = 150 * 2324; - video_buffer_size = 230 * 1024; - opt_mpeg = 2; - packets_per_pack = 1; - sys_header_in_pack1 = 0; - always_sys_header_in_pack = 0; - sector_transport_size = 2324; - transport_prefix_sectors = 0; - sector_size = 2324; - vbr = true; - buffers_in_video = 1; - always_buffers_in_video = 0; - buffers_in_audio = 1; - always_buffers_in_audio = 0; - vcd_zero_stuffing = 0; - dtspts_for_all_vau = 0; - sector_align_iframeAUs = true; - timestamp_iframe_only = false; - video_buffers_iframe_only = false; - break; - - case MPEG_FORMAT_DVD: - mjpeg_info ("Selecting DVD output profile (INCOMPLETE!!!!)"); - opt_data_rate = 1260000; - opt_mpeg = 2; - packets_per_pack = 1; - sys_header_in_pack1 = false; // Handle by control packets - always_sys_header_in_pack = false; - sector_transport_size = 2048; - transport_prefix_sectors = 0; - sector_size = 2048; - video_buffer_size = 232 * 1024; - buffers_in_video = true; - always_buffers_in_video = false; - buffers_in_audio = true; - always_buffers_in_audio = false; - vcd_zero_stuffing = 0; - dtspts_for_all_vau = 0; - sector_align_iframeAUs = true; - timestamp_iframe_only = true; - video_buffers_iframe_only = true; - vbr = true; - if (opt_max_segment_size == 0) - opt_max_segment_size = 2000 * 1024 * 1024; - break; - - default: /* MPEG_FORMAT_MPEG1 - auto format MPEG1 */ - mjpeg_info ("Selecting generic MPEG1 output profile"); - opt_mpeg = 1; - vbr = opt_VBR; - packets_per_pack = opt_packets_per_pack; - always_sys_header_in_pack = opt_always_system_headers; - sys_header_in_pack1 = 1; - sector_transport_size = opt_sector_size; - transport_prefix_sectors = 0; - sector_size = opt_sector_size; - if (opt_buffer_size == 0) { - opt_buffer_size = 46; - } - video_buffer_size = opt_buffer_size * 1024; - buffers_in_video = 1; - always_buffers_in_video = 1; - buffers_in_audio = 0; - always_buffers_in_audio = 1; - vcd_zero_stuffing = 0; - dtspts_for_all_vau = 0; - sector_align_iframeAUs = false; - timestamp_iframe_only = false; - video_buffers_iframe_only = false; - break; - } - -} - -/** - * 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 -OutputStream::RunInSectors () -{ - vector < ElementaryStream * >::iterator str; - unsigned int sectors_delay = 1; - - for (str = vstreams.begin (); str < vstreams.end (); ++str) { - - if (MPEG_STILLS_FORMAT (opt_mux_format)) { - sectors_delay += (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. Traverses the input files and calculates their payloads. - Estimates the multiplex rate. Estimates the neccessary stream delay for the different substreams. - */ - - -void -OutputStream::Init (vector < ElementaryStream * >*strms, PS_Stream *strm) -{ - 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; - - packets_left_in_pack = 0; /* Suppress warning */ - video_first = false; - - estreams = strms; - - for (str = estreams->begin (); str < estreams->end (); ++str) { - switch ((*str)->Kind ()) { - case ElementaryStream::audio: - astreams.push_back (*str); - break; - case ElementaryStream::video: - vstreams.push_back (*str); - break; - default: - break; - } - - completed.push_back (false); - } - - mjpeg_info ("SYSTEMS/PROGRAM stream:"); - this->psstrm = strm; - - psstrm->Init (opt_mpeg, sector_size, opt_max_segment_size); - - /* 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 && opt_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.015 * nominal_rate_sum); - - dmux_rate = (dmux_rate / 50 + 25) * 50; - - mjpeg_info ("rough-guess multiplexed stream data rate : %07d", dmux_rate * 8); - if (opt_data_rate != 0) - mjpeg_info ("target data-rate specified : %7d", opt_data_rate * 8); - - if (opt_data_rate == 0) { - mjpeg_info ("Setting best-guess data rate."); - } else if (opt_data_rate >= dmux_rate) { - mjpeg_info ("Setting specified specified data rate: %7d", opt_data_rate * 8); - dmux_rate = opt_data_rate; - } else if (opt_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 = opt_data_rate; - } - - mux_rate = dmux_rate / 50; - - /* 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 + static_cast < clockticks > (opt_video_offset * CLOCKS / 1000); - audio_delay = delay + static_cast < clockticks > (opt_audio_offset * CLOCKS / 1000); - mjpeg_info ("Sectors = %d Video delay = %lld Audio delay = %lld", - sectors_delay, video_delay / 300, audio_delay / 300); - - - // - // 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); - } - - - - /* 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; -} - -/** - Prints the current status of the substreams. - @param level the desired log level - */ -void -OutputStream::MuxStatus (log_level_t level) -{ - 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)->bufmodel.Space (), (*str)->au->dorder, (*str)->nsec); - break; - case ElementaryStream::audio: - mjpeg_log (level, - "Audio %02x: buf=%7d frame=%06d sector=%08d", - (*str)->stream_id, (*str)->bufmodel.Space (), (*str)->au->dorder, (*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 -OutputStream::AppendMuxStreamsOf (vector < ElementaryStream * >&elem, vector < MuxStream * >&mux) -{ - 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 -OutputStream::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 */ - split_at_seq_end = !opt_multifile_segment; - - switch (opt_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"); - } - /* 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); - - /* 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: - split_at_seq_end = false; - /* 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: - /* A DVD System header is a weird thing. We seem to need to - include buffer info about streams 0xb8, 0xb9, 0xbf even if - they're not physically present but the buffers for the actual - video streams aren't included. - - TODO: I have no idead about MPEG audio streams if present... - */ - { - DummyMuxStream dvd_0xb9_strm_dummy (0xb9, 1, video_buffer_size); - DummyMuxStream dvd_0xb8_strm_dummy (0xb8, 0, 4096); - DummyMuxStream dvd_0xbf_strm_dummy (0xbf, 1, 2048); - - vector < MuxStream * >dvdmux; - vector < MuxStream * >::iterator muxstr; - dvdmux.push_back (&dvd_0xb9_strm_dummy); - dvdmux.push_back (&dvd_0xb8_strm_dummy); - unsigned int max_priv1_buffer = 0; - - 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 && (*muxstr)->BufferSize () > max_priv1_buffer) { - max_priv1_buffer = (*muxstr)->BufferSize (); - } else - dvdmux.push_back (*muxstr); - } - - DummyMuxStream dvd_priv1_strm_dummy (PRIVATE_STR_1, 1, max_priv1_buffer); - - if (max_priv1_buffer > 0) - 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 -OutputStream::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. -******************************************************************/ - - - -bool -OutputStream::OutputMultiplex () -{ - 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->NextFile (); - - 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]->au->DTS; - else - ZeroSCR = (*estreams)[0]->au->DTS; - - 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; - //for( str = estreams->begin(); str < estreams->end(); ++str ) - //{ - //mjpeg_info("STREAM %02x: SCR=%lld mux=%d reqDTS=%lld", - //(*str)->stream_id, - //current_SCR /300, - //(*str)->MuxPossible(current_SCR), - //(*str)->RequiredDTS()/300 - //); - //} - 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->FileLimReached ()) { - if (opt_multifile_segment || master == 0) - psstrm->NextFile (); - else { - if (master->NextAUType () == IFRAME) { - seg_state = runout_segment; - runout_PTS = master->NextRequiredPTS (); - mjpeg_debug ("Running out to (raw) PTS %lld SCR=%lld", - runout_PTS / 300, current_SCR / 300); - running_out = true; - seg_state = runout_segment; - } - } - } else if (master != 0 && master->EndSeq ()) { - if (split_at_seq_end && master->Lookahead () != 0) { - if (!master->SeqHdrNext () || master->NextAUType () != IFRAME) { - mjpeg_error_exit1 ("Sequence split detected %d but no following sequence found...", - master->NextAUType ()); - } - - runout_PTS = master->NextRequiredPTS (); - mjpeg_debug ("Running out to %lld SCR=%lld", runout_PTS / 300, current_SCR / 300); - MuxStatus (LOG_INFO); - running_out = true; - seg_state = runout_segment; - } - } - break; - - } - - padding_packet = false; - start_of_new_pack = (packets_left_in_pack == packets_per_pack); - - for (str = estreams->begin (); str < estreams->end (); ++str) { - (*str)->DemuxedTo (current_SCR); - } - - - - // - // Find the ready-to-mux stream with the most urgent DTS - // - ElementaryStream *despatch = 0; - clockticks earliest = 0; - - for (str = estreams->begin (); str < estreams->end (); ++str) { - /* DEBUG - mjpeg_info("STREAM %02x: SCR=%lld mux=%d reqDTS=%lld", - (*str)->stream_id, - current_SCR /300, - (*str)->MuxPossible(current_SCR), - (*str)->RequiredDTS()/300 - ); - */ - if ((*str)->MuxPossible (current_SCR) && - (!video_first || (*str)->Kind () == ElementaryStream::video) - ) { - if (despatch == 0 || earliest > (*str)->RequiredDTS ()) { - despatch = *str; - earliest = (*str)->RequiredDTS (); - } - } - } - - if (underrun_ignore > 0) - --underrun_ignore; - - if (despatch) { - despatch->OutputSector (); - video_first = false; - if (current_SCR >= earliest && underrun_ignore == 0) { - mjpeg_warn ("Stream %02x: data will arrive too late sent(SCR)=%lld required(DTS)=%d", - despatch->stream_id, current_SCR / 300, (int) earliest / 300); - MuxStatus (LOG_WARN); - // Give the stream a chance to recover - underrun_ignore = 300; - ++underruns; - if (underruns > 10 && !opt_ignore_underrun) { - mjpeg_error_exit1 ("Too many frame drops -exiting"); - } - } - if (despatch->nsec > 50 && despatch->Lookahead () != 0 && !running_out) - despatch->UpdateBufferMinMax (); - padding_packet = false; - - } else { - // - // If we got here no stream could be muxed out. - // We therefore generate padding packets if necessary - // usually this is because reciever buffers are likely to be - // full. - // - if (vbr) { - // - // VBR: For efficiency we bump SCR up to five times or - // until it looks like buffer status will change - NextPosAndSCR (); - clockticks next_change = static_cast < clockticks > (0); - - for (str = estreams->begin (); str < estreams->end (); ++str) { - clockticks change_time = (*str)->bufmodel.NextChange (); - - if (next_change == 0 || change_time < next_change) - next_change = change_time; - } - unsigned int bumps = 5; - - while (bumps > 0 && next_change > current_SCR + ticks_per_sector) { - NextPosAndSCR (); - --bumps; - } - } else { - // Just output a padding packet - OutputPadding (false); - } - padding_packet = true; - } - - /* Update the counter for pack packets. VBR is a tricky - case as here padding packets are "virtual" */ - - if (!(vbr && padding_packet)) { - --packets_left_in_pack; - if (packets_left_in_pack == 0) - packets_left_in_pack = packets_per_pack; - } - - MuxStatus (LOG_DEBUG); - /* Unless sys headers are always required we turn them off after the first - packet has been generated */ - include_sys_header = always_sys_header_in_pack; - - pcomp = completed.begin (); - str = estreams->begin (); - while (str < estreams->end ()) { - if (!(*pcomp) && (*str)->MuxCompleted ()) { - mjpeg_info ("STREAM %02x completed @ %d.", (*str)->stream_id, (*str)->au->dorder); - MuxStatus (LOG_DEBUG); - (*pcomp) = true; - } - ++str; - ++pcomp; - } - - return true; - } - - return false; -} - - -void -OutputStream::Close () -{ - // Tidy up - OutputSuffix (); - psstrm->Close (); - mjpeg_info ("Multiplex completion at SCR=%lld.", current_SCR / 300); - MuxStatus (LOG_INFO); - for (str = estreams->begin (); str < estreams->end (); ++str) { - (*str)->Close (); - if ((*str)->nsec <= 50) - mjpeg_info ("BUFFERING stream too short for useful statistics"); - else - mjpeg_info ("BUFFERING min %d Buf max %d", (*str)->BufferMin (), (*str)->BufferMax ()); - } - - if (underruns > 0) { - mjpeg_error ("foo"); - mjpeg_error_exit1 ("MUX STATUS: Frame data under-runs detected!"); - } else { - mjpeg_info ("foo"); - mjpeg_info ("MUX STATUS: no under-runs detected."); - } -} - -/** - Calculate the packet payload of the output stream at a certain timestamp. -@param strm the output stream -@param buffers the number of buffers -@param PTSstamp presentation time stamp -@param DTSstamp decoding time stamp - */ -unsigned int -OutputStream::PacketPayload (MuxStream & strm, bool buffers, bool PTSstamp, bool DTSstamp) -{ - return psstrm->PacketPayload (strm, sys_header_ptr, pack_header_ptr, buffers, PTSstamp, DTSstamp) - - strm.StreamHeaderSize (); -} - -/*************************************************** - - WritePacket - Write out a normal packet carrying data from one of - the elementary stream being muxed. -@param max_packet_data_size the maximum packet data size allowed -@param strm output mux stream -@param buffers ? -@param PTSstamp presentation time stamp of the packet -@param DTSstamp decoding time stamp of the packet -@param timestamps ? -@param returns the written bytes/packets (?) -***************************************************/ - -unsigned int -OutputStream::WritePacket (unsigned int max_packet_data_size, - MuxStream & strm, - bool buffers, clockticks PTS, clockticks DTS, uint8_t timestamps) -{ - unsigned int written = psstrm->CreateSector (pack_header_ptr, - sys_header_ptr, - max_packet_data_size, - strm, - buffers, - false, - PTS, - DTS, - timestamps); - - NextPosAndSCR (); - return written; -} - -/*************************************************** - * - * WriteRawSector - Write out a packet carrying data for - * a control packet with irregular content. -@param rawsector data for the raw sector -@param length length of the raw sector - ***************************************************/ - -void -OutputStream::WriteRawSector (uint8_t * rawsector, unsigned int length) -{ - // - // Writing raw sectors when packs stretch over multiple sectors - // is a recipe for disaster! - // - assert (packets_per_pack == 1); - psstrm->RawWrite (rawsector, length); - NextPosAndSCR (); - -} - - - -/****************************************************************** - OutputPadding - - generates Pack/Sys Header/Packet information for a - padding stream and saves the sector - - We have to pass in a special flag to cope with appalling mess VCD - makes of audio packets (the last 20 bytes being dropped thing) 0 = - Fill the packet completetely. This include "audio packets" that - include no actual audio, only a system header and padding. -@param vcd_audio_pad flag for VCD audio padding -******************************************************************/ - - -void -OutputStream::OutputPadding (bool vcd_audio_pad) -{ - if (vcd_audio_pad) - psstrm->CreateSector (pack_header_ptr, sys_header_ptr, - 0, vcdapstrm, false, false, 0, 0, TIMESTAMPBITS_NO); - else - psstrm->CreateSector (pack_header_ptr, sys_header_ptr, - 0, pstrm, false, false, 0, 0, TIMESTAMPBITS_NO); - ++pstrm.nsec; - NextPosAndSCR (); - -} - - /****************************************************************** - * OutputGOPControlSector - * DVD System headers are carried in peculiar sectors carrying 2 - * PrivateStream2 packets. We're sticking 0's in the packets - * as we have no idea what's supposed to be in there. - * - * Thanks to Brent Byeler who worked out this work-around. - * - ******************************************************************/ - -void -OutputStream::OutputDVDPriv2 () -{ - uint8_t *packet_size_field; - uint8_t *index; - uint8_t *sector_buf; - unsigned int tozero; - - sector_buf = new uint8_t[sector_size]; - - assert (sector_size == 2048); - PS_Stream::BufferSectorHeader (sector_buf, pack_header_ptr, &sys_header, index); - PS_Stream::BufferPacketHeader (index, PRIVATE_STR_2, 2, // MPEG 2 - false, // No buffers - 0, 0, 0, // No timestamps - 0, TIMESTAMPBITS_NO, packet_size_field, index); - tozero = sector_buf + 1024 - index; - memset (index, 0, tozero); - index += tozero; - PS_Stream::BufferPacketSize (packet_size_field, index); - - PS_Stream::BufferPacketHeader (index, PRIVATE_STR_2, 2, // MPEG 2 - false, // No buffers - 0, 0, 0, // No timestamps - 0, TIMESTAMPBITS_NO, packet_size_field, index); - tozero = sector_buf + 2048 - index; - memset (index, 0, tozero); - index += tozero; - PS_Stream::BufferPacketSize (packet_size_field, index); - - WriteRawSector (sector_buf, sector_size); - - delete sector_buf; -} - - -/* - * Local variables: - * c-file-style: "stroustrup" - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ |