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; 
  } 
}