/* ------------------------------------------------------------------
 * Copyright (C) 1998-2010 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.
 * -------------------------------------------------------------------
 */
/*********************************************************************************/
/*     -------------------------------------------------------------------       */
/*                            MPEG-4 MediaAtom Class                             */
/*     -------------------------------------------------------------------       */
/*********************************************************************************/
/*
    This MediaAtom Class contains all the objects that declare information
    about the media data within the stream.
*/


#ifndef MEDIAATOM_H_INCLUDED
#define MEDIAATOM_H_INCLUDED

#ifndef OSCL_FILE_IO_H_INCLUDED
#include "oscl_file_io.h"
#endif

#ifndef ATOM_H_INCLUDED
#include "atom.h"
#endif

#ifndef MEDIAHEADERATOM_H_INCLUDED
#include "mediaheaderatom.h"
#endif

#ifndef HANDLERATOM_H_INCLUDED
#include "handleratom.h"
#endif

#ifndef MEDIAINFORMATIONATOM_H_INCLUDED
#include "mediainformationatom.h"
#endif

#ifndef ESDESCRIPTOR_H_INCLUDED
#include "esdescriptor.h"
#endif

#ifndef OSCL_MEDIA_DATA_H_INCLUDED
#include "oscl_media_data.h"
#endif

#ifndef PV_GAU_H_INCLUDED
#include "pv_gau.h"
#endif

class AVCSampleEntry;

class MediaAtom : public Atom
{

    public:
        MediaAtom(MP4_FF_FILE *fp,
                  OSCL_wString& filename,
                  uint32 size,
                  uint32 type,
                  bool oPVContentDownloadable = false,
                  uint32 parsingMode = 0,
                  bool aOpenFileOncePerTrack = true);

        virtual ~MediaAtom();


        uint32 getMediaHandlerType() const
        {
            if (_phandler != NULL)
            {
                return _phandler->getHandlerType();
            }
            else
            {
                return 0;
            }
        }

        uint32 getSampleProtocol() const
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getSampleProtocol();
            }
            else
            {
                return 0;
            }
        }


        // Return the ESID for the track - undefined if a HINT track
        uint32 getESID() const
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getESID();
            }
            else
            {
                return 0;
            }
        }

        // Return the first ESDescriptor for the track - undefined if a HINT track
        const ESDescriptor *getESDescriptor() const
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getESDescriptor();
            }
            else
            {
                return NULL;
            }
        }

        uint32 getTimeScale() const
        {
            if (_pmediaHeader != NULL)
            {
                return _pmediaHeader->getTimeScale();
            }
            else
            {
                // UNDEFINED VALUE
                return 0xFFFFFFFF;
            }
        }

        int32 updateFileSize(TOsclFileOffset filesize)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->updateFileSize(filesize);
            }
            return DEFAULT_ERROR;
        }

        // Returns next video frame
        int32 getNextSample(uint8 *buf, uint32 &size, uint32 &index, TOsclFileOffset &SampleOffset)
        {
            if (_pmediaInformation == NULL)
            {
                return READ_MEDIA_INFORMATION_ATOM_FAILED;
            }
            return _pmediaInformation->getNextSample(buf, size, index, SampleOffset);
        }

        MP4_ERROR_CODE getKeyMediaSampleNumAt(uint32 aKeySampleNum,
                                              GAU    *pgau)
        {
            if (_pmediaInformation == NULL)
            {
                return READ_MEDIA_INFORMATION_ATOM_FAILED;
            }
            return _pmediaInformation->getKeyMediaSampleNumAt(aKeySampleNum, pgau);
        }

        uint32 getNumKeyFrames()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getNumKeyFrames());
            }
            else
            {
                return 0;
            }
        }

        int32 getPrevKeyMediaSample(uint64 inputtimestamp,
                                    uint32 &aKeySampleNum,
                                    uint32 *n,
                                    GAU    *pgau)
        {
            if (_pmediaInformation == NULL)
            {
                return READ_MEDIA_INFORMATION_ATOM_FAILED;
            }
            return _pmediaInformation->getPrevKeyMediaSample(inputtimestamp, aKeySampleNum, n, pgau);
        }

        int32 getNextKeyMediaSample(uint32 &aKeySampleNum,
                                    uint32 *n,
                                    GAU    *pgau)
        {
            if (_pmediaInformation == NULL)
            {
                return READ_MEDIA_INFORMATION_ATOM_FAILED;
            }
            return _pmediaInformation->getNextKeyMediaSample(aKeySampleNum, n, pgau);
        }

        int32 getMediaSample(uint32 sampleNumber, uint8 *buf, uint32& size, uint32 &index, TOsclFileOffset &SampleOffset)
        {
            if (_pmediaInformation == NULL)
            {
                return READ_MEDIA_INFORMATION_ATOM_FAILED;
            }
            return _pmediaInformation->getMediaSample(sampleNumber, buf, size, index, SampleOffset);
        }

        int32 getOffsetByTime(uint64 ts, TOsclFileOffset* sampleFileOffset)
        {
            if (_pmediaInformation == NULL)
            {
                return DEFAULT_ERROR;
            }
            return _pmediaInformation->getOffsetByTime(ts, sampleFileOffset);
        }

        void resetPlayBack()
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->resetPlayBack();
            }
        }

        void resetTrackToEOT()
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->resetTrackToEOT();
            }
        }

        uint64 resetPlayBack(uint64 time, bool oDependsOn)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->resetPlayBack(time, oDependsOn);
            }
            else
            {
                return 0;
            }
        }

        uint64 queryRepositionTime(uint64 time, bool oDependsOn, bool bBeforeRequestedTime)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->queryRepositionTime(time, oDependsOn, bBeforeRequestedTime);
            }
            else
            {
                return 0;
            }
        }

        int32 IsResetNeeded(uint64 time)
        {
            if (_pmediaInformation == NULL)
                return READ_MEDIA_INFORMATION_ATOM_FAILED;
            return _pmediaInformation->IsResetNeeded(time);
        }

        MP4_ERROR_CODE getTimestampForSampleNumber(uint32 sampleNumber, uint64& aTimeStamp)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getTimestampForSampleNumber(sampleNumber, aTimeStamp);
            }
            else
            {
                return READ_FAILED;
            }
        }

        MP4_ERROR_CODE getSampleSizeAt(int32 sampleNum, uint32& aSampleSize)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getSampleSizeAt(sampleNum, aSampleSize);
            }
            else
            {
                return DEFAULT_ERROR;
            }
        }


        // Returns the timestamp  from the last video sample
        // This is mainly to be used when seeking in the bitstream - you request a video frame at timestamp
        // X, but the actual frame you get is Y, this method returns the timestamp for Y so you know which
        // audio sample to request.
        uint64 getTimestampForCurrentSample()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getTimestampForCurrentSample();
            }
            else
            {
                return 0;
            }
        }

        // Returns the sample number of the last samplle returned
        // Used when requesting a hint sample for a specific randomly accessed sample
        int32 getSampleNumberForCurrentSample()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getSampleNumberForCurrentSample();
            }
            else
            {
                return 0;
            }
        }

        void advance()
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->advance();
            }
        } // Advances the currentPlayback number

        void advance(int32 sampleNum)
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->advance(sampleNum);
            }
        } // Advances the currentPlayback number to sampleNum

        void seek(int32 baseLayerSampleNum)
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->seek(baseLayerSampleNum);
            }
        } // Seeks to the base-layer sample in the hint track



        // From MediaHeader
        uint64 getMediaDuration()
        {
            if (_pmediaHeader != NULL)
            {
                return _pmediaHeader->getDuration();
            }
            else
            {
                return 0;
            }
        } // in terms of the media timescale

        uint32 getMediaTimescale()
        {
            if (_pmediaHeader != NULL)
            {
                return _pmediaHeader->getTimeScale();
            }
            else
            {
                return 0;
            }
        }

        uint16 getLanguageCode()
        {
            if (_pmediaHeader != NULL)
            {
                return _pmediaHeader->getLanguage();
            }
            else
            {
                return (0xFFFF);
            }

        }


        // From Handler
        uint32 getTrackStreamType()
        {
            if (_phandler != NULL)
            {
                return _phandler->getHandlerType();
            }
            else
            {
                return 0;
            }
        }

        // From SampleDescription
        uint32 getNumSampleEntries()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getNumSampleEntries();
            }
            else
            {
                return 0;
            }
        }

        //From DecoderConfigDescriptor
        // Getting and setting the Mpeg4 VOL header
        DecoderSpecificInfo *getDecoderSpecificInfo() const
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getDecoderSpecificInfo();
            }
            else
            {
                return NULL;
            }
        }

        DecoderSpecificInfo *getDecoderSpecificInfoForSDI(uint32 index) const
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getDecoderSpecificInfoForSDI(index);
            }
            else
            {
                return NULL;
            }
        }

        void getMIMEType(OSCL_String& aMimeType)
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->getMIMEType(aMimeType);
            }
        }

        uint8  getObjectTypeIndication()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getObjectTypeIndication();
            }
            else
            {
                return 0;
            }
        }

        // Get the max size buffer needed to retrieve the media samples
        uint32 getMaxBufferSizeDB() const
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getMaxBufferSizeDB();
            }
            else
            {
                return 0;
            }
        }

        int32 getAverageBitrate()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getAverageBitrate();
            }
            else
            {
                return 0;
            }
        }

        int32 getHeight()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getHeight();
            }
            else
            {
                return 0;
            }

        }

        int32 getWidth()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getWidth();
            }
            else
            {
                return 0;
            }
        }

        //PASP box
        uint32 getHspacing()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getHspacing();
            }
            else
            {
                return 0;
            }
        }

        uint32 getVspacing()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getVspacing();
            }
            else
            {
                return 0;
            }
        }

        // TS offset value for the start of the media track.  The STTS
        // Atom only holds TS deltas.  For a track that does not begin at 0s, we need to hold an
        // offset timestamp value.
        void setEditListInfo(Oscl_Vector<int32, OsclMemAllocator> *aEditListTime,
                             Oscl_Vector<uint32, OsclMemAllocator> *aEditListDuration,
                             uint32 aMovieTimeScale, uint32 aTrackMediaTS)
        {
            if (_pmediaInformation != NULL)
            {
                _pmediaInformation->setEditListInfo(aEditListTime, aEditListDuration, aMovieTimeScale, aTrackMediaTS);
            }
        }

        uint32 getSampleDescriptionIndex()
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getSampleDescriptionIndex();
            }
            else
            {
                return (0xFFFFFFFF);
            }
        }

        int32 getNextBundledAccessUnits(uint32 *n,
                                        GAU    *pgau)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getNextBundledAccessUnits(n, pgau);
            }
            else
            {
                return -1;
            }
        }

        int32 peekNextBundledAccessUnits(uint32 *n,
                                         MediaMetaInfo *mInfo)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->peekNextBundledAccessUnits(n, mInfo);
            }
            else
            {
                return -1;
            }
        }

        uint32 getSampleCount()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getSampleCount());
            }
            else
            {
                return 0;
            }
        }

        SampleEntry *getTextSampleEntryAt(uint32 index)
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation-> getTextSampleEntryAt(index));
            }
            else
            {
                return NULL;
            }
        }

        int32 getTimestampForRandomAccessPoints(uint32 *num, uint64 *tsBuf, uint32* numBuf, TOsclFileOffset *offsetBuf)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getTimestampForRandomAccessPoints(num, tsBuf, numBuf, offsetBuf);
            }
            else
            {
                return 0;
            }
        }

        int32 getTimestampForRandomAccessPointsBeforeAfter(uint64 ts, uint64 *tsBuf, uint32* numBuf,
                uint32& numsamplestoget,
                uint32 howManyKeySamples)
        {
            if (_pmediaInformation != NULL)
            {
                return _pmediaInformation->getTimestampForRandomAccessPointsBeforeAfter(ts, tsBuf, numBuf, numsamplestoget, howManyKeySamples);
            }
            else
            {
                return 0;
            }

        }


        int32 getNumAMRFramesPerSample()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getNumAMRFramesPerSample());
            }
            else
            {
                return 0;
            }
        }

        MP4_ERROR_CODE getMaxTrackTimeStamp(TOsclFileOffset fileSize, uint64& timeStamp)
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getMaxTrackTimeStamp(fileSize, timeStamp));
            }
            else
            {
                return DEFAULT_ERROR;
            }
        }

        MP4_ERROR_CODE getSampleNumberClosestToTimeStamp(uint32 &sampleNumber,
                uint64 timeStamp,
                TOsclFileOffset sampleOffset = 0)
        {
            if (_pmediaInformation != NULL)
            {
                return
                    (_pmediaInformation->getSampleNumberClosestToTimeStamp(sampleNumber,
                            timeStamp,
                            sampleOffset));
            }
            else
            {
                return (READ_FAILED);
            }
        }

        AVCSampleEntry* getAVCSampleEntry(uint32 index)
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getAVCSampleEntry(index));
            }
            return (NULL);
        }

        uint32 getAVCNALLengthSize(uint32 index)
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getAVCNALLengthSize(index));
            }
            return 0;
        }

        uint32 getNumAVCSampleEntries()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getNumAVCSampleEntries());
            }
            return 0;
        }

        uint32 getTrackLevelOMA2DRMInfoSize()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getTrackLevelOMA2DRMInfoSize());
            }
            return 0;
        }

        uint8* getTrackLevelOMA2DRMInfo()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->getTrackLevelOMA2DRMInfo());
            }
            return NULL;
        }

        bool isMultipleSampleDescriptionAvailable()
        {
            if (_pmediaInformation != NULL)
            {
                return (_pmediaInformation->isMultipleSampleDescriptionAvailable());
            }
            return 0;
        }

    private:
        MediaHeaderAtom *_pmediaHeader;
        HandlerAtom *_phandler;
        MediaInformationAtom *_pmediaInformation;

        uint32 _trackStartOffset;
};

#endif // MEDIAATOM_H_INCLUDED

