/*
 * vdr-podcatcher - A plugin for the Linux Video Disk Recorder
 * Copyright (c) 2006 Tobias Grimm <vdr@e-tobi.net>
 *
 * This program 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.
 *
 * This program 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
 *
 * $Id: pesaudiopacket.cc 3219 2006-04-16 15:06:35Z svntobi $
 *
 */

#include "pesaudiopacket.h"
#include <memory>

using namespace std;

#define PES_PREFIX "\x00\x00\x01"
#define OFFSET_PES_PREFIX 0

#define PES_STREAM_ID "\xBD"
#define OFFSET_PES_STREAM_ID 3

#define OFFSET_PES_PACKET_LENGTH 4

#define PES_EXTENSION "\x87\x00"
#define OFFSET_PES_EXTENSION 6

#define PES_HEADER_DATA_LENGTH "\x00"
#define OFFSET_PES_HEADER_DATA_LENGTH 8

#define LPCM_ID "\xA0"
#define OFFSET_LPCM_ID 9

#define LPCM_UNKNOWN_1 "\xFF\x00\x00\x00"
#define OFFSET_LPCM_UNKNOWN_1 10

#define LPCM_STEREO_48KHZ "\x01"
#define OFFSET_LPCM_STEREO_48KHZ 14

#define LPCM_UNKNOWN_2 "\x80"
#define OFFSET_LPCM_UNKNOWN_2 15

#define PES_AND_LPCM_HEADER_SIZE 16
#define OFFSET_SAMPLES PES_AND_LPCM_HEADER_SIZE

PesAudioPacket::PesAudioPacket(int frameSize)
:frameSize(frameSize)
{
    buffer = (unsigned char*) malloc(frameSize);

    SetFixedPesHeaderFields();
    SetPesAudioPacketLength(10);
    SetFixedLpcmHeaderFields();

    writePtr = buffer + OFFSET_SAMPLES;

    timeIndex = 0;
    totalTime = -1;
}

PesAudioPacket::~PesAudioPacket()
{
    free(buffer);
}

void PesAudioPacket::SetFixedPesHeaderFields()
{

    PutData(OFFSET_PES_PREFIX, (unsigned char*) PES_PREFIX, 3);
    PutData(OFFSET_PES_STREAM_ID, (unsigned char*) PES_STREAM_ID, 1);
    PutData(OFFSET_PES_EXTENSION, (unsigned char*) PES_EXTENSION, 2);
    PutData(OFFSET_PES_HEADER_DATA_LENGTH,
      (unsigned char*) PES_HEADER_DATA_LENGTH, 1);
}

void PesAudioPacket::SetPesAudioPacketLength(unsigned short length)
{
    buffer[OFFSET_PES_PACKET_LENGTH] = (length >> 8) & 0xFF;
    buffer[OFFSET_PES_PACKET_LENGTH + 1] = length & 0xFF;
}

void PesAudioPacket::SetFixedLpcmHeaderFields()
{
    PutData(OFFSET_LPCM_ID, (unsigned char*) LPCM_ID, 1);
    PutData(OFFSET_LPCM_UNKNOWN_1, (unsigned char*) LPCM_UNKNOWN_1, 4);
    PutData(OFFSET_LPCM_STEREO_48KHZ, (unsigned char*) LPCM_STEREO_48KHZ, 1);
    PutData(OFFSET_LPCM_UNKNOWN_2, (unsigned char*) LPCM_UNKNOWN_2, 1);
}

int PesAudioPacket::GetBufferSize()
{
    return writePtr - buffer;
}

unsigned char* PesAudioPacket::GetBufferPtr()
{
    return buffer;
}

bool PesAudioPacket::AddSample(signed int left, signed int right)
{
    int spaceLeft = buffer + frameSize - writePtr;

    if (spaceLeft >= 4)
    {
        PutBigEndianShort(left);
        PutBigEndianShort(right);
        SetPesAudioPacketLength(writePtr - buffer - 6);
        return true;
    }
    else
    {
        return false;
    }
}

void PesAudioPacket::PutData(int offset, const unsigned char* data, int length)
{
    memcpy(buffer + offset, data, length);
}

void PesAudioPacket::PutBigEndianShort(signed int sample)
{
    writePtr[0] = (sample >> 8) & 0xff;
    writePtr[1] = (sample >> 0) & 0xff;
    writePtr = writePtr + 2;
}

void PesAudioPacket::SetTimeIndex(unsigned int index)
{
    timeIndex = index;
}

unsigned int PesAudioPacket::GetTimeIndex()
{
    return timeIndex;
}

void PesAudioPacket::SetTotalTime(int time)
{
    totalTime = time;
}

int PesAudioPacket::GetTotalTime()
{
    return totalTime;
}
