/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/*
    This PVA_FF_DecoderConfigDescriptor Class
*/


#define IMPLEMENT_DecoderConfigDescriptor

#include "decoderconfigdescriptor.h"
#include "atomutils.h"
#include "a_atomdefs.h"

typedef Oscl_Vector<PVA_FF_DecoderSpecificInfo*, OsclMemAllocator> PVA_FF_DecoderSpecificInfoVecType;
// Constructor
PVA_FF_DecoderConfigDescriptor::PVA_FF_DecoderConfigDescriptor(int32 streamType, PVA_FF_MP4_CODEC_TYPE codecType)
        : PVA_FF_BaseDescriptor(0x04)
{
    _codecType = codecType;
    iCurrFilePos = 0;
    init(streamType);
    recomputeSize();
}

// Destructor
PVA_FF_DecoderConfigDescriptor::~PVA_FF_DecoderConfigDescriptor()
{
    if (_pdecSpecificInfoVec != NULL)
    {
        for (uint32 i = 0; i < _pdecSpecificInfoVec->size(); i++)
        {
            PV_MP4_FF_DELETE(NULL, PVA_FF_DecoderSpecificInfo, (*_pdecSpecificInfoVec)[i]);
        }
        PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_DecoderSpecificInfoVecType, Oscl_Vector, _pdecSpecificInfoVec);
    }
}

void
PVA_FF_DecoderConfigDescriptor::init(int32 mediaType)
{
    _pdecSpecificInfoVec = NULL;

    switch (mediaType)
    {
        case MEDIA_TYPE_AUDIO:
        {
            switch (_codecType)
            {
                case PVA_FF_MP4_CODEC_TYPE_AAC_AUDIO:
                    _objectTypeIndication = 0x40;
                    break;

                default:
                    _objectTypeIndication = 0xFF;
                    break;
            }
            _streamType = 0x05; // 0x05 for AudioStream

            PV_MP4_FF_NEW(fp->auditCB, PVA_FF_DecoderSpecificInfoVecType, (), _pdecSpecificInfoVec);

        }
        break;
        case MEDIA_TYPE_VISUAL:
        {
            switch (_codecType)
            {
                case PVA_FF_MP4_CODEC_TYPE_BASELINE_H263_VIDEO:
                    _objectTypeIndication = 0xc0; // Simple profile
                    break;

                case PVA_FF_MP4_CODEC_TYPE_MPEG4_VIDEO:
                    _objectTypeIndication = 0x20; // Simple profile
                    break;

                case PVA_FF_MP4_CODEC_TYPE_AVC_VIDEO:
                    _objectTypeIndication = 0x30;
                    break;
                default:
                    break;
            }
            _streamType = 0x04; // 0x04 for VisualStream
            PV_MP4_FF_NEW(fp->auditCB, PVA_FF_DecoderSpecificInfoVecType, (), _pdecSpecificInfoVec);
        }
        break;
        default:
        {
            _objectTypeIndication = 0xFF; // No profile specified
            _streamType = 0x20; // user private
        }
        break;
    }

    _upStream = false;
    _reserved = 1;
    _bufferSizeDB = 0; // Need better default value
    _maxBitrate = 0; // Need better default value
    _avgBitrate = 0; // Need better default value
}

void
PVA_FF_DecoderConfigDescriptor::addDecoderSpecificInfo(PVA_FF_DecoderSpecificInfo *info)
{
    if (_pdecSpecificInfoVec != NULL)
        _pdecSpecificInfoVec->push_back(info);

    info->setParent(this);
    recomputeSize();

    if (_pparent != NULL)
        _pparent->recomputeSize();
}

PVA_FF_DecoderSpecificInfo *
PVA_FF_DecoderConfigDescriptor::getDecoderSpecificInfo() const
{
    if ((_pdecSpecificInfoVec != NULL) && (_pdecSpecificInfoVec->size() > 0))
    {
        return (*_pdecSpecificInfoVec)[(int32)0];
    }
    return NULL;
}


void
PVA_FF_DecoderConfigDescriptor::nextSampleSize(uint32 size)
{
    if (size > _bufferSizeDB)
    {
        _bufferSizeDB = size;
    }
}

// Rendering the Descriptor in proper format (bitlengths, etc.) to an ostream
bool
PVA_FF_DecoderConfigDescriptor::renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP *fp)
{
    int32 rendered = 0; // Keep track of number of bytes rendered

    // Render attributes of the PVA_FF_BaseDescriptor class
    int32 numBytes = renderBaseDescriptorMembers(fp);

    if (numBytes == 0)
    {
        return false;
    }
    rendered += numBytes;

    if (!PVA_FF_AtomUtils::render8(fp, _objectTypeIndication))
    {
        return false;
    }
    rendered += 1;

    // Pack and render stream type, upstream, and reserved
    uint8 data = _reserved; // Initial data byte including reserved bit set
    data |= ((_streamType & 0x3f) << 2);  // 0b00XXXXXX << 2
    if (_upStream)
    {
        data |= 0x02;
    }
    if (!PVA_FF_AtomUtils::render8(fp, data))
    {
        return false;
    }
    rendered += 1;

    iCurrFilePos = PVA_FF_AtomUtils::getCurrentFilePosition(fp);
    if (!PVA_FF_AtomUtils::render24(fp, _bufferSizeDB))
    {
        return false;
    }
    rendered += 3;

    if (!PVA_FF_AtomUtils::render32(fp, _maxBitrate))
    {
        return false;
    }
    rendered += 4;

    if (!PVA_FF_AtomUtils::render32(fp, _avgBitrate))
    {
        return false;
    }
    rendered += 4;

    if (_pdecSpecificInfoVec != NULL)
    {
        for (uint32 i = 0; i < _pdecSpecificInfoVec->size(); i++)
        {
            if (!(*_pdecSpecificInfoVec)[i]->renderToFileStream(fp))
            {
                return false;
            }
            rendered += (*_pdecSpecificInfoVec)[i]->getSizeOfDescriptorObject();
        }
    }

    return true;
}


void
PVA_FF_DecoderConfigDescriptor::recomputeSize()
{
    int32 contents = 0;

    contents += 1; // (8 bits for OTI)
    contents += 1; // (8 bits for Stream type, upStream flag and reserved)
    contents += 3; // (24 bits for buffer size DB)
    contents += 4; // (32 bits for max bitrate)
    contents += 4; // (32 bits for avg bitrate)

    if (_pdecSpecificInfoVec != NULL)
    {
        for (uint32 i = 0; i < _pdecSpecificInfoVec->size(); i++)
        {
            contents += (*_pdecSpecificInfoVec)[i]->getSizeOfDescriptorObject();
        }
    }

    _sizeOfClass = contents;
    _sizeOfSizeField = PVA_FF_AtomUtils::getNumberOfBytesUsedToStoreSizeOfClass(contents);

    // Have the parent descriptor recompute its size based on this update
    if (_pparent != NULL)
    {
        _pparent->recomputeSize();
    }

}

void
PVA_FF_DecoderConfigDescriptor::writeMaxSampleSize(MP4_AUTHOR_FF_FILE_IO_WRAP *_afp)
{
    if (NULL != _afp->_filePtr)
    {
        PVA_FF_AtomUtils::seekFromStart(_afp, iCurrFilePos);
        PVA_FF_AtomUtils::render24(_afp, _bufferSizeDB);
    }
}

