From 2f0cc8ec30e8c26fed7b2c9ac2614c9a7655fb65 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sat, 26 Jul 2003 03:01:58 +0000 Subject: Moved from gst-plugins/ext/mplex/. See that directory for older changelogs. Original commit message from CVS: Moved from gst-plugins/ext/mplex/. See that directory for older changelogs. --- gst-libs/ext/mplex/lpcmstrm_in.cc | 304 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 gst-libs/ext/mplex/lpcmstrm_in.cc (limited to 'gst-libs/ext/mplex/lpcmstrm_in.cc') diff --git a/gst-libs/ext/mplex/lpcmstrm_in.cc b/gst-libs/ext/mplex/lpcmstrm_in.cc new file mode 100644 index 00000000..448094ed --- /dev/null +++ b/gst-libs/ext/mplex/lpcmstrm_in.cc @@ -0,0 +1,304 @@ +/* + * lpcmstrm_in.c: LPCM Audio strem class members handling scanning and + * buffering raw input stream. + * + * Copyright (C) 2001 Andrew Stevens + * Copyright (C) 2000,2001 Brent Byeler for original header-structure + * parsing code. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#include "audiostrm.hh" +#include "outputstream.hh" +#include + + + + +LPCMStream::LPCMStream (IBitStream & ibs, OutputStream & into): +AudioStream (ibs, into) +{ +} + +bool LPCMStream::Probe (IBitStream & bs) +{ + return true; +} + + +/************************************************************************* + * + * Reads initial stream parameters and displays feedback banner to users + * + *************************************************************************/ + + +void +LPCMStream::Init (const int stream_num) +{ + + MuxStream::Init (PRIVATE_STR_1, 1, // Buffer scale + default_buffer_size, + muxinto.vcd_zero_stuffing, + muxinto.buffers_in_audio, muxinto.always_buffers_in_audio); + mjpeg_info ("Scanning for header info: LPCM Audio stream %02x", stream_num); + + InitAUbuffer (); + + AU_start = bs.bitcount (); + + // This is a dummy debug version that simply assumes 48kHz + // two channel 16 bit sample LPCM + samples_per_second = 48000; + channels = 2; + bits_per_sample = 16; + bytes_per_frame = + samples_per_second * channels * bits_per_sample / 8 * ticks_per_frame_90kHz / 90000; + frame_index = 0; + dynamic_range_code = 0x80; + + /* Presentation/decoding time-stamping */ + access_unit.start = AU_start; + access_unit.length = bytes_per_frame; + access_unit.PTS = static_cast < clockticks > (decoding_order) * + (CLOCKS_per_90Kth_sec * ticks_per_frame_90kHz); + access_unit.DTS = access_unit.PTS; + access_unit.dorder = decoding_order; + decoding_order++; + aunits.append (access_unit); + + OutputHdrInfo (); +} + +unsigned int +LPCMStream::NominalBitRate () +{ + return samples_per_second * channels * bits_per_sample; +} + + + +void +LPCMStream::FillAUbuffer (unsigned int frames_to_buffer) +{ + last_buffered_AU += frames_to_buffer; + mjpeg_debug ("Scanning %d MPEG LPCM audio frames to frame %d", + frames_to_buffer, last_buffered_AU); + + static int header_skip = 0; // Initially skipped past 5 bytes of header + int skip; + bool bad_last_frame = false; + + while (!bs.eos () && + decoding_order < last_buffered_AU) { + skip = access_unit.length - header_skip; + mjpeg_debug ("Buffering frame %d (%d bytes)\n", decoding_order - 1, skip); + if (skip & 0x1) + bs.getbits (8); + if (skip & 0x2) + bs.getbits (16); + skip = skip >> 2; + + for (int i = 0; i < skip; i++) { + bs.getbits (32); + } + + prev_offset = AU_start; + AU_start = bs.bitcount (); + if (AU_start - prev_offset != access_unit.length * 8) { + bad_last_frame = true; + break; + } + // Here we would check for header data but LPCM has no headers... + if (bs.eos ()) + break; + + access_unit.start = AU_start; + access_unit.length = bytes_per_frame; + access_unit.PTS = static_cast < clockticks > (decoding_order) * + (CLOCKS_per_90Kth_sec * ticks_per_frame_90kHz); + access_unit.DTS = access_unit.PTS; + access_unit.dorder = decoding_order; + decoding_order++; + aunits.append (access_unit); + num_frames[0]++; + + num_syncword++; + + if (num_syncword >= old_frames + 10) { + mjpeg_debug ("Got %d frame headers.", num_syncword); + old_frames = num_syncword; + } + mjpeg_debug ("Got frame %d\n", decoding_order); + + } + if (bad_last_frame) { + mjpeg_error_exit1 ("Last LPCM frame ended prematurely!\n"); + } + last_buffered_AU = decoding_order; + eoscan = bs.eos (); + +} + + + +void +LPCMStream::Close () +{ + stream_length = AU_start / 8; + mjpeg_info ("AUDIO_STATISTICS: %02x", stream_id); + mjpeg_info ("Audio stream length %lld bytes.", stream_length); + mjpeg_info ("Frames : %8u ", num_frames[0]); + bs.close (); +} + +/************************************************************************* + OutputAudioInfo + gibt gesammelte Informationen zu den Audio Access Units aus. + + Prints information on audio access units +*************************************************************************/ + +void +LPCMStream::OutputHdrInfo () +{ + mjpeg_info ("LPCM AUDIO STREAM:"); + + mjpeg_info ("Bit rate : %8u bytes/sec (%3u kbit/sec)", + NominalBitRate () / 8, NominalBitRate ()); + mjpeg_info ("Channels : %d\n", channels); + mjpeg_info ("Bits per sample: %d\n", bits_per_sample); + mjpeg_info ("Frequency : %d Hz", samples_per_second); + +} + + +unsigned int +LPCMStream::ReadPacketPayload (uint8_t * dst, unsigned int to_read) +{ + unsigned int header_size = LPCMStream::StreamHeaderSize (); + unsigned int bytes_read = bs.read_buffered_bytes (dst + header_size, + to_read - header_size); + clockticks decode_time; + bool starting_frame_found = false; + uint8_t starting_frame_index = 0; + + int starting_frame_offset = (new_au_next_sec || au_unsent > bytes_read) + ? 0 : au_unsent; + + unsigned int frames = 0; + unsigned int bytes_muxed = bytes_read; + + if (bytes_muxed == 0 || MuxCompleted ()) { + goto completion; + } + + + /* Work through what's left of the current frames and the + following frames's updating the info until we reach a point where + an frame had to be split between packets. + + The DTS/PTS field for the packet in this case would have been + given the that for the first AU to start in the packet. + + */ + + decode_time = RequiredDTS (); + while (au_unsent < bytes_muxed) { + assert (bytes_muxed > 1); + bufmodel.Queued (au_unsent, decode_time); + bytes_muxed -= au_unsent; + if (new_au_next_sec) { + ++frames; + if (!starting_frame_found) { + starting_frame_index = static_cast < uint8_t > (au->dorder % 20); + starting_frame_found = true; + } + } + if (!NextAU ()) { + goto completion; + } + new_au_next_sec = true; + decode_time = RequiredDTS (); + }; + + // We've now reached a point where the current AU overran or + // fitted exactly. We need to distinguish the latter case so we + // can record whether the next packet starts with the tail end of + // // an already started frame or a new one. We need this info to + // decide what PTS/DTS info to write at the start of the next + // packet. + + if (au_unsent > bytes_muxed) { + if (new_au_next_sec) + ++frames; + bufmodel.Queued (bytes_muxed, decode_time); + au_unsent -= bytes_muxed; + new_au_next_sec = false; + } else // if (au_unsent == bytes_muxed) + { + bufmodel.Queued (bytes_muxed, decode_time); + if (new_au_next_sec) + ++frames; + new_au_next_sec = NextAU (); + } +completion: + // Generate the LPCM header... + // Note the index counts from the low byte of the offset so + // the smallest value is 1! + dst[0] = LPCM_SUB_STR_0 + stream_num; + dst[1] = frames; + dst[2] = (starting_frame_offset + 1) >> 8; + dst[3] = (starting_frame_offset + 1) & 0xff; + unsigned int bps_code; + + switch (bits_per_sample) { + case 16: + bps_code = 0; + break; + case 20: + bps_code = 1; + break; + case 24: + bps_code = 2; + break; + default: + bps_code = 3; + break; + } + dst[4] = starting_frame_index; + unsigned int bsf_code = (samples_per_second == 48000) ? 0 : 1; + unsigned int channels_code = channels - 1; + + dst[5] = (bps_code << 6) | (bsf_code << 4) | channels_code; + dst[6] = dynamic_range_code; + return bytes_read + header_size; +} + + + +/* + * Local variables: + * c-file-style: "stroustrup" + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.1