www.pudn.com > mediator15src.zip > unpacketizer.cpp
/* * unpacketizer.cpp * Copyright (C) 2001-2002 Arno Hornberger* * This file is part of MPEG Mediator, a free MPEG stream converter. * * MPEG Mediator is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MPEG Mediator 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 "unpacketizer.h" void Unpacketizer::SetStream(AsyncStream *stream) { bs = stream; mpeg2 = false; Seek(bs->Tell()); } __int64 Unpacketizer::Tell() { if (!sync_pack) return payload_pos; else return seek_pos; } void Unpacketizer::Seek(__int64 pos) { seek_pos = pos; program_mux_base = 0; program_mux_rate = 1; scr_pack = 0; scr_base = 0; scr_offset = 0; sync_pack = true; } void Unpacketizer::Resync() { if (!sync_pack) bs->Seek(payload_pos); else bs->Seek(seek_pos); } void Unpacketizer::GetPayloadBytes(unsigned char *dest, int numbytes) { if (numbytes > payload_bytes - (int)(payload_pos - payload_start)) return; // read only within this packet! bs->GetBytes(dest, numbytes); payload_pos += numbytes; } void Unpacketizer::FlushPayloadBytes(int numbytes) { if (numbytes > payload_bytes - (int)(payload_pos - payload_start)) return; bs->FlushBytes(numbytes); payload_pos += numbytes; } unsigned char Unpacketizer::GetPayloadByte() { unsigned char val; if (payload_pos >= payload_start + payload_bytes) return 0; // read out of bounds val = bs->GetByte(); payload_pos++; return val; } void Unpacketizer::NextPacket() { __int64 scr_pack_old, scr_old; unsigned long code; int header_data_length, packet_length; int i; if (!sync_pack) // Go to next startcode bs->Seek(payload_start + payload_bytes); else bs->Seek(seek_pos); search_packet: code = bs->GetBits(32); if (sync_pack) { try { while (code != ((START_CODE_PREFIX << 8) | PACK_START_CODE)) code = (code << 8) | bs->GetByte(); } catch (DemuxExcept &e) { if (e.WhatCode() == DemuxExcept::END_OF_STREAM) throw DemuxExcept(DemuxExcept::NO_PROGRAM_STREAM); else throw; } mpeg2 = (bs->LookAhead(2) == 1); } else { while (code >> 8 != START_CODE_PREFIX) code = (code << 8) | bs->GetByte(); } stream_id = (int)(code & 0x000000ff); switch (stream_id) { case PACK_START_CODE: if (sync_pack) scr_old = 0; else scr_old = GetSCR(bs->Tell() - 5); bs->GetBits(2); if (!mpeg2) bs->GetBits(2); scr_pack_old = scr_pack; scr_pack = bs->GetBits(3); // SCR[32..30] bs->FlushBit(); // marker_bit scr_pack <<= 15; scr_pack |= bs->GetBits(15); // SCR[29..15] bs->FlushBit(); // marker_bit scr_pack <<= 15; scr_pack |= bs->GetBits(15); // SCR[14..0] // there are encoders out there which // start at negative scr's if ((scr_pack & 0x00000001fff00000) == 0x00000001fff00000) scr_pack |= 0xfffffffe00000000; program_mux_base = bs->Tell(); // should be ok in MPEG-1 and MPEG-2 bs->FlushBit(); // marker_bit scr_pack *= 300; if (mpeg2) { if (scr_pack >= 0) scr_pack += bs->GetBits(9); else scr_pack -= bs->GetBits(9); } if (scr_pack < scr_pack_old) // ensure linear time { scr_base = scr_pack; scr_offset = scr_old; } bs->FlushBit(); // marker_bit program_mux_rate = bs->GetBits(22); if (program_mux_rate == 0) throw DemuxExcept(DemuxExcept::MUXRATE_ZERO_ERROR); bs->FlushBit(); // marker_bit if (mpeg2) { bs->FlushBit(); // marker_bit bs->GetBits(5); // reserved i = (int)(bs->GetBits(3)); // pack_stuffing_length bs->FlushBytes(i); } sync_pack = false; goto search_packet; case SYSTEM_HEADER_START_CODE: i = (int)(bs->GetBits(16)); // header_length bs->FlushBytes(i); goto search_packet; case PROGRAM_END_CODE: throw DemuxExcept(DemuxExcept::END_OF_STREAM); default: packet_length = (int)(bs->GetBits(16)); switch (stream_id) { case PROGRAM_STREAM_MAP: case PRIVATE_STREAM_2: case ECM_STREAM: case EMM_STREAM: case PROGRAM_STREAM_DIRECTORY: case DSMCC_STREAM: case ITUTRECH222TYPEE_STREAM: case PADDING_STREAM: bs->FlushBytes(packet_length); goto search_packet; default: if (mpeg2) { bs->GetByte(); pts_dts_flags = (int)(bs->GetBits(2)); bs->GetBits(6); header_data_length = (int)(bs->GetBits(8)); payload_bytes = packet_length - header_data_length - 3; if (pts_dts_flags == 0) bs->FlushBytes(header_data_length); else { if (pts_dts_flags == 2) { bs->GetBits(4); pts = bs->GetBits(3); // PTS bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts *= 300; if (pts < (scr_pack - 27000000 * 5)) throw DemuxExcept(DemuxExcept::TIMESTAMP_UNDERFLOW); pts -= scr_base; pts += scr_offset; bs->FlushBytes(header_data_length - 5); } else if (pts_dts_flags == 3) { bs->GetBits(4); pts = bs->GetBits(3); // PTS bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts *= 300; if (pts < (scr_pack - 27000000 * 5)) throw DemuxExcept(DemuxExcept::TIMESTAMP_UNDERFLOW); pts -= scr_base; pts += scr_offset; bs->GetBits(4); dts = bs->GetBits(3); // DTS bs->FlushBit(); dts <<= 15; dts |= bs->GetBits(15); bs->FlushBit(); dts <<= 15; dts |= bs->GetBits(15); bs->FlushBit(); dts *= 300; // if (dts < scr_pack) // throw DemuxExcept(DemuxExcept::TIMESTAMP_UNDERFLOW); dts -= scr_base; dts += scr_offset; bs->FlushBytes(header_data_length - 10); } else throw DemuxExcept(DemuxExcept::PROGRAM_STREAM_SYNTAX_ERROR); } } else // MPEG-1 { payload_bytes = packet_length; while (bs->LookAhead(1) == 1) { bs->GetByte(); // remove stuffing bytes payload_bytes--; } if (bs->LookAhead(2) == 1) { bs->GetByte(); // P-STD_buffer_size bs->GetByte(); // and P-STD_buffer_scale payload_bytes -= 2; } if (bs->LookAhead(4) == 2) { bs->GetBits(4); pts = bs->GetBits(3); // PTS bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts *= 300; if (pts < (scr_pack - 27000000 * 5)) throw DemuxExcept(DemuxExcept::TIMESTAMP_UNDERFLOW); pts -= scr_base; pts += scr_offset; pts_dts_flags = 2; payload_bytes -= 5; } else if (bs->LookAhead(4) == 3) { bs->GetBits(4); pts = bs->GetBits(3); // PTS bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts <<= 15; pts |= bs->GetBits(15); bs->FlushBit(); pts *= 300; if (pts < (scr_pack - 27000000 * 5)) throw DemuxExcept(DemuxExcept::TIMESTAMP_UNDERFLOW); pts -= scr_base; pts += scr_offset; bs->GetBits(4); dts = bs->GetBits(3); // DTS bs->FlushBit(); dts <<= 15; dts |= bs->GetBits(15); bs->FlushBit(); dts <<= 15; dts |= bs->GetBits(15); bs->FlushBit(); dts *= 300; // if (dts < scr_pack) // throw DemuxExcept(DemuxExcept::TIMESTAMP_UNDERFLOW); dts -= scr_base; dts += scr_offset; pts_dts_flags = 3; payload_bytes -= 10; } else { if (bs->GetByte() != 0x0f) throw DemuxExcept(DemuxExcept::PROGRAM_STREAM_SYNTAX_ERROR); pts_dts_flags = 0; payload_bytes--; } } if (stream_id == PRIVATE_STREAM_1) { substream_id = (int)(bs->GetByte()); payload_bytes--; if ((substream_id >= SUBSTREAM_AC3_0) && (substream_id <= SUBSTREAM_AC3_7)) { audio_framecount = (int)(bs->GetByte()); audio_frameoffset = (int)(bs->GetBits(16)); payload_bytes -= 3; } else if ((substream_id >= SUBSTREAM_LPCM_0) && (substream_id <= SUBSTREAM_LPCM_7)) { audio_framecount = (int)(bs->GetByte()); audio_frameoffset = (int)(bs->GetBits(16)); // byte 0: LPCM-frames starting in this packet // byte 1,2: start of first LPCM-frame (+ 4 bytes offset?!) // byte 3: unknown (kindof a counter ?) // byte 4,5: format identifier // // format identifier is 0x0180 for 16bit, 48kHz, stereo // framesize in this mode is 80 samples (320 bytes) // // format identifier is 0x4180 for 20bit, 48kHz, stereo // framesize in this mode is 80 samples (400 bytes) // // format identifier is 0x9180 for 24bit, 96kHz, stereo // framesize in this mode is 160 samples (960 bytes) bs->GetByte(); lpcm_type = bs->GetBits(16); payload_bytes -= 6; } else if ((substream_id >= SUBSTREAM_DTS_0) && (substream_id <= SUBSTREAM_DTS_7)) { bs->FlushBytes(3); // meaning of this header unknown payload_bytes -= 3; } } payload_start = bs->Tell(); payload_pos = payload_start; // Prefetch payload, // keep ringbuffer "linear" // (performance issue) bs->FlushBytes(payload_bytes); bs->Seek(payload_start); break; } break; } }