www.pudn.com > mediator15src.zip > lpcmaudio.cpp


/* 
 * lpcmaudio.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 "lpcmaudio.h" 
#include "startcodes.h" 
 
LPCMAudio::LPCMAudio() 
{ 
  up = new Unpacketizer(); 
} 
 
LPCMAudio::~LPCMAudio() 
{ 
  if (up) 
    delete up; 
} 
 
void LPCMAudio::SetInput(AsyncStream *as, int stream_id) 
{ 
  up->SetStream(as); 
  this->stream_id = stream_id; 
  payload_size = 0; 
  payload_pos = 0; 
  extrapolated_pts_valid = false; 
  current_pts_used = true; 
  audio_seek = true; 
} 
 
void LPCMAudio::GetFrame(short *sample_buffer) 
{ 
  unsigned char *sample_bytes, *sample_bytes_2; 
  int i, frame_offset, frame_size; 
  unsigned char tmp; 
 
  up->Resync(); 
 
  if (audio_seek) 
  { 
    frame_offset = SearchPacket(); 
    up->FlushPayloadBytes(frame_offset); 
    payload_pos = frame_offset; 
    lpcm_identifier = up->GetLPCMType(); 
    audio_seek = false; 
  } 
 
restart: 
  if (lpcm_identifier == 0x0180) 
  { 
    frame_size = 320;               // 80 samples, 16 bit, stereo 
    GetBytes((unsigned char *)sample_buffer, frame_size); 
 
    // big-endian to little-endian conversion 
    sample_bytes = (unsigned char *)sample_buffer; 
 
    for (i = 0; i < 80 * 2; i++) { 
      tmp = sample_bytes[0]; 
      sample_bytes[0] = sample_bytes[1]; 
      sample_bytes[1] = tmp; 
 
      sample_bytes += 2; 
    } 
  } 
  else if (lpcm_identifier == 0x9180) 
  { 
    frame_size = 960;               // 160 samples, 24 bit, stereo 
    GetBytes((unsigned char *)sample_buffer, frame_size); 
 
    sample_bytes = sample_bytes_2 = (unsigned char *)sample_buffer; 
 
    for (i = 0; i < 80; i++) { 
      tmp = *sample_bytes_2++; 
      *sample_bytes++ = *sample_bytes_2++; 
      *sample_bytes++ = tmp; 
      tmp = *sample_bytes_2++; 
      *sample_bytes++ = *sample_bytes_2++; 
      *sample_bytes++ = tmp; 
       
      sample_bytes_2 += 8;          // skip lsb's and "resample" to 48kHz 
    } 
  } 
  else if (lpcm_identifier == 0x4180) 
  { 
    frame_size = 400;               // 80 samples, 20 bit, stereo 
    GetBytes((unsigned char *)sample_buffer, frame_size); 
 
    sample_bytes = sample_bytes_2 = (unsigned char *)sample_buffer; 
 
    for (i = 0; i < 40; i++) { 
      tmp = *sample_bytes_2++; 
      *sample_bytes++ = *sample_bytes_2++; 
      *sample_bytes++ = tmp; 
      tmp = *sample_bytes_2++; 
      *sample_bytes++ = *sample_bytes_2++; 
      *sample_bytes++ = tmp; 
 
      tmp = *sample_bytes_2++; 
      *sample_bytes++ = *sample_bytes_2++; 
      *sample_bytes++ = tmp; 
      tmp = *sample_bytes_2++; 
      *sample_bytes++ = *sample_bytes_2++; 
      *sample_bytes++ = tmp; 
 
      sample_bytes_2 += 2;          // skip lsb's 
    } 
  } 
 
  if (payload_pos < frame_size) {   // frame started in previous packet?? 
    if (!last_pts_used) { 
      frame_pts = last_pts; 
      last_pts_used = true; 
    } 
    else if (extrapolated_pts_valid) 
      frame_pts = extrapolated_pts; 
    else 
      goto restart;               // scan frames until we find a pts 
  } 
  else {                          // frame started in current packet.. 
    if (!current_pts_used) { 
      frame_pts = current_pts; 
      current_pts_used = true; 
    } 
    else if (extrapolated_pts_valid) 
      frame_pts = extrapolated_pts; 
    else 
      goto restart;               // scan frames until we find a pts 
  } 
  frame_samples = 80; 
  sample_rate = 48000; 
 
  extrapolated_pts = frame_pts + (27000000 * (__int64)frame_samples) / 
                                  (__int64)sample_rate; 
  extrapolated_pts_valid = true; 
} 
 
int LPCMAudio::SearchPacket() 
{ 
  last_pts = current_pts; 
  last_pts_used = current_pts_used; 
 
  do { 
    up->NextPacket(); 
  } while ((up->GetStreamID() != PRIVATE_STREAM_1) || 
           (up->GetSubstreamID() != (SUBSTREAM_LPCM_0 + stream_id))); 
 
  if (up->HasPTS()) { 
    current_pts = up->GetPTS(); 
    current_pts_used = false; 
  } 
  else 
    current_pts_used = true; 
 
  payload_size = up->GetPayloadSize(); 
  payload_pos = 0; 
 
  return up->GetAudioFrameOffset() - 4; 
} 
 
void LPCMAudio::GetBytes(unsigned char *dest, int count) 
{ 
  while (count > 0) 
  { 
    if (payload_pos >= payload_size) 
      SearchPacket(); 
 
    if (payload_size - payload_pos >= count) { 
      up->GetPayloadBytes(dest, count); 
      payload_pos += count; 
      count = 0; 
    } 
    else { 
      up->GetPayloadBytes(dest, payload_size - payload_pos); 
      dest += payload_size - payload_pos; 
      count -= payload_size - payload_pos; 
      payload_pos = payload_size; 
    } 
  } 
}