| /* ------------------------------------------------------------------ |
| * 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. |
| * ------------------------------------------------------------------- |
| */ |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // RFC3640_payload_parser.cpp |
| // |
| // Implementation of payload parser for RFC3640 RTP format. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "oscl_mem.h" |
| #include "rfc3640_payload_parser.h" |
| #include "bitstreamparser.h" |
| #include "oscl_byte_order.h" |
| #include "rfc3640_media_info.h" |
| |
| //Until the fileformat node and decoder are re-worked to handle multiple-fragments |
| //per media message, we'll need to use this switch to control the output of the |
| //payload parser |
| #define RFC3640_ONE_FRAGMENT_PER_MEDIA_MSG 1 |
| |
| //Default Values |
| #define AAC_HBR_SIZELENGTH_DEFAULT_VALUE 13 |
| #define AAC_HBR_INDEXLENGTH_DEFAULT_VALUE 3 |
| #define AAC_HBR_INDEXDELTALENGTH_DEFAULT_VALUE 3 |
| #define AAC_HBR_CTSDELTALENGTH_DEFAULT_VALUE 0 |
| #define AAC_HBR_DTSDELTALENGTH_DEFAULT_VALUE 0 |
| #define AAC_HBR_HEADERSLENGTH_DEFAULT_VALUE 16 |
| #define AAC_HBR_AUXDATASIZELENGTH_DEFAULT_VALUE 0 |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Constructor/Destructor |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| OSCL_EXPORT_REF RFC3640PayloadParser::RFC3640PayloadParser() |
| { |
| //Default to no headers at all. |
| //This is just in case Init() is never called. |
| headersPresent = false; |
| headersLength = 0; |
| sizeLength = 0; |
| indexLength = 0; |
| indexDeltaLength = 0; |
| CTSDeltaLength = 0; |
| DTSDeltaLength = 0; |
| randomAccessIndication = false; |
| auxDataSizeLength = 0; |
| } |
| |
| OSCL_EXPORT_REF RFC3640PayloadParser::~RFC3640PayloadParser() |
| { |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Initialization |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| OSCL_EXPORT_REF bool RFC3640PayloadParser::Init(mediaInfo* config) |
| { |
| Oscl_Vector<PayloadSpecificInfoTypeBase*, OsclMemAllocator> payloadInfo; |
| payloadInfo = config->getPayloadSpecificInfoVector(); |
| PayloadSpecificInfoTypeBase* payloadInfoBase = payloadInfo[0]; // is this "0" assumption okay??? |
| RFC3640PayloadSpecificInfoType* r3640PayloadInfo = |
| OSCL_STATIC_CAST(RFC3640PayloadSpecificInfoType*, payloadInfoBase); |
| rfc3640_mediaInfo *r3640m = OSCL_STATIC_CAST(rfc3640_mediaInfo *, config); |
| bool retVal = false; |
| |
| //TODO: Implement other modes (such as CELP-cbr, CELP-vbr, AAC-lbr, etc...). |
| sizeLength = r3640PayloadInfo->getSizeLength(); |
| indexLength = r3640PayloadInfo->getIndexLength(); |
| indexDeltaLength = r3640PayloadInfo->getIndexDeltaLength(); |
| CTSDeltaLength = r3640PayloadInfo->getCTSDeltaLength(); |
| DTSDeltaLength = r3640PayloadInfo->getDTSDeltaLength(); |
| randomAccessIndication = false; |
| |
| //We support AAC-hbr mode only. |
| if (!oscl_strncmp(r3640m->getMode(), "AAC-hbr", oscl_strlen("AAC-hbr"))) |
| { |
| headersPresent = true; |
| headersLength = AAC_HBR_HEADERSLENGTH_DEFAULT_VALUE; |
| auxDataSizeLength = AAC_HBR_AUXDATASIZELENGTH_DEFAULT_VALUE; |
| |
| //do sanity check on values. Only supporting AAC_HBR default fixed values. |
| if ((sizeLength != AAC_HBR_SIZELENGTH_DEFAULT_VALUE) || |
| (indexLength != AAC_HBR_INDEXLENGTH_DEFAULT_VALUE) || |
| (indexDeltaLength != AAC_HBR_INDEXDELTALENGTH_DEFAULT_VALUE)) |
| { |
| retVal = true; |
| } |
| |
| } |
| else |
| { |
| retVal = true; |
| } |
| |
| |
| return retVal; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Payload parsing |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| OSCL_EXPORT_REF PayloadParserStatus |
| RFC3640PayloadParser::Parse(const Payload& inputPacket, |
| Oscl_Vector<Payload, OsclMemAllocator>& vParsedPayloads) |
| { |
| // Many of OsclRefCounterMemFrag's member functions |
| //should be const functions so this casting away constness is not necessary. |
| Payload& input = const_cast<Payload&>(inputPacket); |
| |
| //@TODO: Implement AU de-interleaving |
| |
| Payload out; |
| |
| out.stream = inputPacket.stream; |
| out.marker = inputPacket.marker; |
| out.randAccessPt = inputPacket.randAccessPt; |
| out.sequence = inputPacket.sequence + 1; |
| out.timestamp = inputPacket.timestamp; |
| //Creating a boolean for checking whether RFC3640_ONE_FRAGMENT_PER_MEDIA_MSG is defined or not |
| bool rfc3640_one_fragement_per_media = false; |
| |
| #ifndef RFC3640_ONE_FRAGMENT_PER_MEDIA_MSG |
| rfc3640_one_fragement_per_media = true; |
| #endif |
| |
| // Many functions calls inside this for loop may Leave because of an |
| // overflow. |
| int32 err; |
| OSCL_TRY(err, |
| //Loop through all of the packets. |
| for (uint32 fragmentNumber = 0; fragmentNumber < inputPacket.vfragments.size(); fragmentNumber++) |
| { |
| // |
| // Strip RFC 3640 header section and auxiliary section. |
| // |
| |
| //Establish a pointer to the payload fragment for iterating past the |
| //header and aux section. |
| BitStreamParser fragment((uint8*)input.vfragments[fragmentNumber].getMemFragPtr(), |
| input.vfragments[fragmentNumber].getMemFragSize()); |
| |
| //In some cases, such as with fixed-length AUs, the header is not present. |
| //Only process the header if it is present. |
| uint16 headersLength = 0; |
| if (headersPresent) |
| { |
| //Read the header length from the first 2 octets. |
| //Include the size of this headersLength field in the total length. |
| headersLength = fragment.ReadUInt16() + BITS_PER_UINT16; |
| } |
| |
| uint8 accessUnits = 0; //controls index field interpretation (index or delta) |
| uint32 size = 0; //size of the AU |
| uint32 index = 0; //used for interleaving |
| uint32 indexDelta = 0; //used for interleaving |
| int CTSFlag = 0; //composition time stamp |
| uint32 CTSDelta = 0; //composition time stamp |
| int DTSFlag = 0; //decoding time stamp |
| uint32 DTSDelta = 0; //decoding time stamp |
| int RAPFlag = 0; //random access point - used to mark a key frame |
| uint32 auxDataSize = 0; |
| |
| //Loop through all of the access units in the packet. |
| while (fragment.BitsRead() < headersLength) |
| { |
| //If the header is present, parse it. |
| if (headersLength) |
| { |
| if (0 != sizeLength) |
| { |
| //Read the AU Size field. |
| size = fragment.ReadBits(sizeLength); |
| } |
| |
| //If the index field is present... |
| if (0 != indexLength) |
| { |
| //If this is the first access unit header... |
| if (0 == accessUnits) |
| { |
| //The AU index only occurs in the first header. |
| index = fragment.ReadBits(indexLength); |
| } |
| else |
| { |
| indexDelta = fragment.ReadBits(indexDeltaLength); |
| } |
| } |
| |
| //From RFC3640: "The CTS-flag field MUST be present in each AU-header |
| // if the length of the CTS-delta field is signaled to |
| // be larger than zero." |
| if (0 != CTSDeltaLength) |
| { |
| CTSFlag = fragment.ReadBits(1); |
| if (CTSFlag) |
| { |
| CTSDelta = fragment.ReadBits(CTSDeltaLength); |
| } |
| } |
| |
| if (0 != DTSDeltaLength) |
| { |
| DTSFlag = fragment.ReadBits(1); |
| if (DTSFlag) |
| { |
| DTSDelta = fragment.ReadBits(DTSDeltaLength); |
| } |
| } |
| |
| if (randomAccessIndication) |
| { |
| RAPFlag = fragment.ReadBits(1); |
| } |
| } |
| |
| |
| if (rfc3640_one_fragement_per_media == true) |
| { |
| // At this time the decoder cannot handle multiple fragments. |
| |
| OsclMemoryFragment memfrag; |
| //memfrag.ptr = NULL; //Unknown at this time. |
| memfrag.len = size; |
| input.vfragments[fragmentNumber].getRefCounter()->addRef(); |
| OsclRefCounterMemFrag refCntMemFrag(memfrag, |
| input.vfragments[fragmentNumber].getRefCounter(), |
| memfrag.len); |
| out.vfragments.push_back(refCntMemFrag); |
| } |
| else |
| { |
| // Instead of creating multiple fragments, point to the first fragment, but |
| // increment the size field to span all access units. The decoder is still |
| // getting multiple frames in memory, but the data structure makes it appear as just one. |
| // This only works for non-interleaved access units & can only be a temporary solution |
| if (accessUnits == 0) |
| { |
| OsclMemoryFragment memfrag; |
| memfrag.ptr = (uint8*)(input.vfragments[fragmentNumber].getMemFragPtr()) + (headersLength / 8); |
| memfrag.len = input.vfragments[fragmentNumber].getMemFragSize() - (headersLength / 8); |
| input.vfragments[fragmentNumber].getRefCounter()->addRef(); |
| OsclRefCounterMemFrag refCntMemFrag(memfrag, |
| input.vfragments[fragmentNumber].getRefCounter(), |
| memfrag.len); |
| out.vfragments.push_back(refCntMemFrag); |
| } |
| } |
| |
| accessUnits++; |
| } |
| |
| //Processed the header. Skip past any padding. |
| if (fragment.GetBitPos() != MOST_SIG_BIT) |
| { |
| fragment.NextBits(fragment.GetBitPos() + 1); |
| } |
| |
| //Now skip over the aux data region. |
| if (auxDataSizeLength) |
| { |
| auxDataSize = fragment.ReadBits(auxDataSizeLength); |
| if (auxDataSize) |
| { |
| //Skip over the aux data region. |
| fragment.NextBits(auxDataSize); |
| //Skip past any padding. |
| if (fragment.GetBitPos() != MOST_SIG_BIT) |
| { |
| fragment.NextBits(fragment.GetBitPos() + 1); |
| } |
| } |
| } |
| |
| if (rfc3640_one_fragement_per_media == true) |
| { |
| //Update the fragment pointers with real values now that we have |
| //parsed the headers. |
| //The output vector may contain fragments from previous runs, so |
| //start with the last fragments that we pushed on the back of the vector. |
| for (uint32 i = (out.vfragments.size() - accessUnits); i < out.vfragments.size(); i++) |
| { |
| out.vfragments[i].getMemFrag().ptr = fragment.GetBytePos(); |
| fragment.NextBits(out.vfragments[i].getMemFrag().len * BITS_PER_BYTE); |
| } |
| } |
| |
| } |
| ); // End of OSCL_TRY |
| |
| if (err != OsclErrNone) |
| { |
| return PayloadParserStatus_Failure; |
| } |
| vParsedPayloads.push_back(out); |
| |
| return PayloadParserStatus_Success; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Repositioning related |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| OSCL_EXPORT_REF void RFC3640PayloadParser::Reposition(const bool adjustSequence, const uint32 stream, const uint32 seqnum) |
| { |
| OSCL_UNUSED_ARG(adjustSequence); |
| OSCL_UNUSED_ARG(stream); |
| OSCL_UNUSED_ARG(seqnum); |
| } |
| |
| OSCL_EXPORT_REF uint32 RFC3640PayloadParser::GetMinCurrTimestamp() |
| { |
| return 0; |
| } |