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


/* 
 * ac3audio.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  
#include  
#include  
 
#include "ac3audio.h" 
#include "startcodes.h" 
 
AC3Audio::AC3Audio() 
{ 
  up = new Unpacketizer(); 
  frame_buffer = new unsigned char[FRAMEBUFFERSIZE]; 
  state = a52_init(0); 
} 
 
AC3Audio::~AC3Audio() 
{ 
  if (state) 
    a52_free(state); 
  if (frame_buffer) 
    delete []frame_buffer; 
  if (up) 
    delete up; 
} 
 
void AC3Audio::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 AC3Audio::GetFrame(short *sample_buffer) 
{ 
  int framesize; 
  float level; 
  int flags; 
  int bit_rate; 
  int i, j; 
  int *int_samples; 
 
  up->Resync(); 
   
restart: 
  GetBytes(frame_buffer, 7); 
 
  while (1) 
  { 
    if ((frame_buffer[0] == 0x0b) && (frame_buffer[1] == 0x77)) { 
      framesize = a52_syncinfo(frame_buffer, &bitstream_flags, 
                               &sample_rate, &bit_rate); 
      if (framesize > 0) 
        break;  
    } 
    for (i = 0; i < 6; i++) 
      frame_buffer[i] = frame_buffer[i + 1]; 
    frame_buffer[6] = GetByte(); 
  } 
 
  if (payload_pos < 7) {  // 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 
  } 
  GetBytes(&frame_buffer[7], framesize - 7); 
 
  flags = A52_DOLBY;			// A52_STEREO; // | A52_ADJUST_LEVEL; 
  level = 1.0; 
  a52_frame(state, frame_buffer, &flags, &level, 384.0); 
  for (i = 0; i < 6; i++) { 
    if (a52_block(state) == 0) { 
      int_samples = (int *)a52_samples(state); 
      for (j = 0; j < 256; j++) {   // MMX would do that faster 
        sample_buffer[j * 2] = Convert(int_samples[j]); 
        sample_buffer[j * 2 + 1] = Convert(int_samples[j + 256]); 
      } 
    } 
    else { 
      for (j = 0; j < 512; j++) 
        sample_buffer[j] = 0; 
    } 
    sample_buffer += 256 * 2; 
  } 
  frame_samples = 256 * 6; 
  extrapolated_pts = frame_pts + (27000000 * (__int64)frame_samples) / 
                                  (__int64)sample_rate; 
  extrapolated_pts_valid = true; 
} 
 
void AC3Audio::SearchPacket() 
{ 
  last_pts = current_pts; 
  last_pts_used = current_pts_used; 
  int frame_offset; 
 
  do { 
    up->NextPacket(); 
  } while ((up->GetStreamID() != PRIVATE_STREAM_1) || 
           (up->GetSubstreamID() != (SUBSTREAM_AC3_0 + stream_id))); 
 
  if (up->HasPTS()) { 
    current_pts = up->GetPTS(); 
    current_pts_used = false; 
  } 
  else 
    current_pts_used = true; 
 
  payload_size = up->GetPayloadSize(); 
 
  if (audio_seek) { 
    frame_offset = up->GetAudioFrameOffset() - 1; 
    up->FlushPayloadBytes(frame_offset); 
    payload_pos = frame_offset; 
    audio_seek = false; 
  } 
  else 
    payload_pos = 0; 
} 
 
unsigned char AC3Audio::GetByte() 
{ 
  unsigned char val; 
 
  if (payload_pos >= payload_size) 
    SearchPacket(); 
 
  val = up->GetPayloadByte(); 
  payload_pos++; 
 
  return val; 
} 
 
void AC3Audio::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; 
    } 
  } 
} 
 
void AC3Audio::GetChannelDescriptor(char *desc) 
{ 
  static const int channels[] = 
  { 
    2, 1, 2, 3, 3, 4, 4, 5, 1, 1, 3, 0, 0, 0, 0, 0  
  }; 
 
  sprintf(desc, "%d.%d", channels[bitstream_flags & A52_CHANNEL_MASK], 
    (bitstream_flags & A52_LFE) != 0 ? 1 : 0); 
}