/*
 * ac3.c: Frontend Status Monitor plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * AC3 Audio Header: http://www.atsc.org/standards/a_52a.pdf
 */

#include "tools.h"
#include "ac3.h"

int cFemonAC3::bitrateS[32] =
{
  32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

int cFemonAC3::frequencieS[4] =
{
  480, 441, 320, 0
};

int cFemonAC3::frameS[3][32] =
{
  {64, 80,  96,  112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 640, 768,  896,  1024, 1152, 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {69, 87,  104, 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835,  975,  1114, 1253, 1393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {96, 120, 144, 168, 192, 240, 288, 336, 384, 480, 576, 672, 768, 960, 1152, 1344, 1536, 1728, 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

cFemonAC3::cFemonAC3(cFemonAC3If *audioHandlerP)
: audioHandlerM(audioHandlerP)
{
}

cFemonAC3::~cFemonAC3()
{
}

bool cFemonAC3::processAudio(const uint8_t *bufP, int lenP)
{
  int fscod, frmsizcod, bsmod, acmod;
  int centermixlevel = AUDIO_CENTER_MIX_LEVEL_INVALID;
  int surroundmixlevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
  int dolbysurroundmode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
  cFemonBitStream bs(bufP, lenP * 8);

  if (!audioHandlerM)
     return false;

  // skip PES header
  if (!PesLongEnough(lenP))
      return false;
  bs.SkipBits(8 * PesPayloadOffset(bufP));

  // http://rmworkshop.com/dvd_info/related_info/ac3hdr.htm

  // AC3 audio detection
  if (bs.GetBits(16) != 0x0B77)     // syncword
     return false;

  bs.SkipBits(16);                  // CRC1

  fscod = bs.GetBits(2);            // sampling rate values
  frmsizcod = bs.GetBits(6);        // frame size code

  bs.SkipBits(5);                   // bitstream id
  bsmod = bs.GetBits(3);            // bitstream mode
  acmod = bs.GetBits(3);            // audio coding mode

  // 3 front channels
  if ((acmod & 0x01) && (acmod != 0x01))
     centermixlevel = bs.GetBits(2);

  // if a surround channel exists
  if (acmod & 0x04)
     surroundmixlevel = bs.GetBits(2);

  // if in 2/0 mode
  if (acmod == 0x02)
      dolbysurroundmode = bs.GetBits(2);

  audioHandlerM->SetAC3Bitrate(1000 * bitrateS[frmsizcod >> 1]);
  audioHandlerM->SetAC3SamplingFrequency(100 * frequencieS[fscod]);
  audioHandlerM->SetAC3Bitstream(bsmod);
  audioHandlerM->SetAC3AudioCoding(acmod);
  audioHandlerM->SetAC3CenterMix(centermixlevel);
  audioHandlerM->SetAC3SurroundMix(surroundmixlevel);
  audioHandlerM->SetAC3DolbySurround(dolbysurroundmode);

  audioHandlerM->SetAC3LFE(bs.GetBit());       // low frequency effects on
  audioHandlerM->SetAC3Dialog(bs.GetBits(5));  // dialog normalization

  return true;
}
