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


/* 
 * audiosync.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 "audiosync.h" 
#include "string.h" 
 
static const int num_denom[][2] = 
{ 
  { 24000, 1001 }, 
  { 24,    1    }, 
  { 25,    1    }, 
  { 30000, 1001 }, 
  { 30,    1    }, 
  { 50,    1    }, 
  { 60000, 1001 }, 
  { 60,    1    } 
}; 
 
AudioSync::AudioSync() 
{ 
  ass_buffer = 0; 
  frm_buffer = 0; 
  max_delta = 27000000 / 20; 
} 
 
AudioSync::~AudioSync() 
{ 
  if (ass_buffer) 
    delete[] ass_buffer; 
  if (frm_buffer) 
    delete[] frm_buffer; 
} 
 
void AudioSync::SetInput(MPEGStream *stream) 
{ 
  int frameratecode; 
  int max_bytes_per_frame; 
   
  this->stream = stream; 
 
  frameratecode = stream->GetFinalFramerateCode(); 
  if ((frameratecode < 1) || (frameratecode > 8)) 
    frameratecode = 3;        // default: 25fps 
 
  rate_numerator = num_denom[frameratecode - 1][0]; 
  rate_denominator = num_denom[frameratecode - 1][1]; 
 
  total_frames = 0; 
  total_samples = 0; 
  start_pts = stream->GetStartPTS(); 
  samplerate = stream->GetSampleRate(); 
  channels = stream->IsStereo() ? 2 : 1; 
  samples_per_frame = (rate_denominator * samplerate) / rate_numerator; 
  frame_duration = (27000000 * (__int64)rate_denominator) / rate_numerator; 
 
  if (samples_per_frame * rate_numerator != samplerate * rate_denominator) 
    samples_per_frame++; 
 
  max_bytes_per_frame = 2 * samples_per_frame * channels + 2 * 2 * channels; 
  ass_buffer = new short[max_bytes_per_frame / 2]; 
  frm_buffer = new short[FRM_BUFFER_SIZE * channels]; 
 
  frm_samplesi = 0; 
  frm_samples = 0; 
  mute_samples = 0; 
  last_frame_size = 0; 
  finished = false; 
} 
 
void AudioSync::Mute(short *samples, int samplecount) 
{ 
  for (int i = 0; i < samplecount * channels; i++) 
    *samples++ = 0; 
} 
 
void AudioSync::GetSameFrame(short ***dest, int *framesize, bool has_alloc) 
{ 
  if (!has_alloc) { 
    out_buffer = ass_buffer; 
    *dest = &out_buffer; 
  } 
  *framesize = last_frame_size; 
} 
 
bool AudioSync::GetFrame(short ***dest, int *framesize, bool has_alloc) 
{ 
  __int64 samples_cont; 
  __int64 pts_slot; 
  int out_samples; 
  int out_samplesi; 
  __int64 frm_pts; 
  __int64 frm_pts_upper; 
 
  if (has_alloc) 
    out_buffer = **dest; 
  else { 
    out_buffer = ass_buffer; 
    *dest = &out_buffer; 
  } 
   
  if (finished) { 
    *framesize = samples_per_frame * channels * 2; 
    return false;  
  } 
   
  pts_slot = 
    ((__int64)total_frames * rate_denominator * 27000000) / rate_numerator; 
  samples_cont = (total_samples * 27000000) / samplerate; 
  out_samplesi = 0; 
  out_samples = (int) 
    (((pts_slot + frame_duration - samples_cont) * samplerate) / 27000000); 
 
  while (out_samplesi != out_samples) 
  { 
    if (mute_samples > 0) 
    { 
      if (mute_samples <= (out_samples - out_samplesi)) { 
        Mute(&out_buffer[out_samplesi * channels], mute_samples); 
        out_samplesi += mute_samples; 
        total_samples += mute_samples; 
        mute_samples = 0; 
      } 
      else { 
        Mute(&out_buffer[out_samplesi * channels], 
             out_samples - out_samplesi); 
        mute_samples -= out_samples - out_samplesi; 
        total_samples += out_samples - out_samplesi; 
        out_samplesi = out_samples; 
      } 
    } 
    else 
    { 
      if (frm_samplesi >= frm_samples) 
      { 
        try { 
          stream->GetAudioFrame(frm_buffer); 
        } 
        catch (...) { 
          finished = true; 
          *framesize = last_frame_size = out_samplesi * 2 * channels; 
          if (out_samplesi != 0) 
            return true; 
          else 
            return false; 
        } 
         
        frm_pts = stream->GetAudioFramePTS(); 
        frm_samples = stream->GetSampleCount(); 
 
        pts_slot = start_pts + (total_samples * 27000000) / samplerate; 
        frm_samplesi = 0; 
 
        if (frm_pts > (pts_slot + max_delta)) 
          mute_samples = (int)(((frm_pts - pts_slot) * samplerate) / 27000000); 
        else if (frm_pts < (pts_slot - max_delta)) 
        { 
          frm_pts_upper = 
            frm_pts + ((frm_samples - 1) * 27000000) / samplerate; 
 
          while (pts_slot > frm_pts_upper) 
          { 
            try { 
              stream->GetAudioFrame(frm_buffer); 
            } 
            catch (...) { 
              finished = true; 
              *framesize = last_frame_size = out_samplesi * 2 * channels; 
              if (out_samplesi != 0) 
                return true; 
              else 
                return false; 
            } 
             
            frm_pts = stream->GetAudioFramePTS(); 
            frm_samples = stream->GetSampleCount(); 
 
            frm_pts_upper = 
              frm_pts + ((frm_samples - 1) * 27000000) / samplerate; 
          } 
          if (frm_pts > pts_slot) 
            mute_samples = (int)(((frm_pts - pts_slot) * samplerate) / 27000000); 
          else 
            frm_samplesi = (int)(((pts_slot - frm_pts) * samplerate) / 27000000); 
        } 
      } 
      else 
      { 
        if ((frm_samples - frm_samplesi) <= (out_samples - out_samplesi)) 
        { 
          memcpy(&out_buffer[out_samplesi * channels], 
                 &frm_buffer[frm_samplesi * channels], 
                 (frm_samples - frm_samplesi) * 2 * channels); 
          out_samplesi += frm_samples - frm_samplesi; 
          total_samples += frm_samples - frm_samplesi; 
          frm_samplesi = frm_samples; 
        } 
        else 
        { 
          memcpy(&out_buffer[out_samplesi * channels], 
                 &frm_buffer[frm_samplesi * channels], 
                 (out_samples - out_samplesi) * 2 * channels); 
          frm_samplesi += out_samples - out_samplesi; 
          total_samples += out_samples - out_samplesi; 
          out_samplesi = out_samples; 
        } 
      } 
    } 
  } 
  total_frames++; 
 
  *framesize = last_frame_size = out_samplesi * 2 * channels; 
 
  return true; 
}