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


/* 
 * mpegaudio.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 "mpegaudio.h" 
#include "startcodes.h" 
 
MPEGAudio::MPEGAudio() 
{ 
  up = new Unpacketizer(); 
  frame_buffer = new unsigned char[FRAMEBUFFERSIZE]; 
 
  make_decode_tables(32768);  // initialize mpg123 
  init_layer2(); 
} 
 
MPEGAudio::~MPEGAudio() 
{ 
  if (frame_buffer) 
    delete []frame_buffer; 
  if (up) 
    delete up; 
} 
 
void MPEGAudio::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; 
} 
 
void MPEGAudio::GetFrame(short *sample_buffer) 
{ 
  unsigned long header; 
  bool sync_found; 
  int framesize; 
  int sample_bytes; 
 
  up->Resync(); 
restart: 
  header = 0; 
  sync_found = false; 
 
  do 
  { 
    header <<= 8; 
    header |= GetByte(); 
    if ((header & 0xfff00000) == 0xfff00000) { 
      framesize = decode_header(&fr, header); 
      if (framesize > 0) 
        sync_found = true; 
    } 
  } while (!sync_found); 
 
  if (payload_pos < 4) {  // 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 
  } 
 
  if (fr.error_protection) { 
    GetByte();            // skip crc-sum 
    GetByte(); 
    framesize -= 2; 
  }   
 
  GetBytes(frame_buffer, framesize); 
 
  switch (fr.lay) 
  { 
    case 1: 
      sample_bytes = do_layer1(&fr, frame_buffer, sample_buffer); 
      break; 
    case 2: 
      sample_bytes = do_layer2(&fr, frame_buffer, sample_buffer); 
      break; 
    default: 
      throw MPAExcept(MPAExcept::AUDIO_LAYER_NOT_SUPPORTED); 
  } 
  if (fr.stereo == 2) 
    frame_samples = sample_bytes / 4;  // 2 bytes per sample, 2 channels 
  else 
    frame_samples = sample_bytes / 2;  // 2 bytes per sample, 1 channel 
 
  extrapolated_pts = frame_pts + (27000000 * (__int64)frame_samples) / 
                                  (__int64)fr.sample_rate; 
  extrapolated_pts_valid = true; 
} 
 
void MPEGAudio::SearchPacket() 
{ 
  last_pts = current_pts; 
  last_pts_used = current_pts_used; 
 
  do { 
    up->NextPacket(); 
  } while (up->GetStreamID() != (AUDIO_STREAM_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; 
} 
 
unsigned char MPEGAudio::GetByte() 
{ 
  unsigned char val; 
 
  if (payload_pos >= payload_size) 
    SearchPacket(); 
 
  val = up->GetPayloadByte(); 
  payload_pos++; 
 
  return val; 
} 
 
void MPEGAudio::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; 
    } 
  } 
}