blob: 4887a53489aaad07875892ff5e21b353178afaf3 [file] [log] [blame]
/* INTEL CONFIDENTIAL
* Copyright (c) 2009 Intel Corporation. All rights reserved.
*
* The source code contained or described herein and all documents
* related to the source code ("Material") are owned by Intel
* Corporation or its suppliers or licensors. Title to the
* Material remains with Intel Corporation or its suppliers and
* licensors. The Material contains trade secrets and proprietary
* and confidential information of Intel or its suppliers and
* licensors. The Material is protected by worldwide copyright and
* trade secret laws and treaty provisions. No part of the Material
* may be used, copied, reproduced, modified, published, uploaded,
* posted, transmitted, distributed, or disclosed in any way without
* Intel's prior express written permission.
*
* No license under any patent, copyright, trade secret or other
* intellectual property right is granted to or conferred upon you
* by disclosure or delivery of the Materials, either expressly, by
* implication, inducement, estoppel or otherwise. Any license
* under such intellectual property rights must be express and
* approved by Intel in writing.
*
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "AsfHeaderParser"
#include <utils/Log.h>
#include "AsfHeaderParser.h"
#include <string.h>
#include <media/stagefright/Utils.h>
#define PRFORMATTAG 0x5052
AsfHeaderParser::AsfHeaderParser(void)
: mAudioInfo(NULL),
mVideoInfo(NULL),
mFileInfo(NULL),
mNumObjectParsed(0),
mIsProtected(false),
mPlayreadyHeader(NULL),
mPlayreadyHeaderLen(0),
mNumberofHeaderObjects(0) {
mFileInfo = new AsfFileMediaInfo;
memset(mFileInfo, 0, sizeof(AsfFileMediaInfo));
}
AsfHeaderParser::~AsfHeaderParser(void) {
delete mFileInfo;
if (mPlayreadyHeader) {
delete mPlayreadyHeader;
mPlayreadyHeader = NULL;
}
// Deleting memory from mExtendedStreamPropertiesObj recursively
for (vector<AsfExtendedStreamPropertiesExObject *>::iterator it = mExtendedStreamPropertiesObj.begin(); it != mExtendedStreamPropertiesObj.end(); ++it) {
for (int i = 0; i < (*it)->streamNames.size(); i++) {
if ((*it)->streamNames[i]->pStreamName != NULL) {
delete (*it)->streamNames[i]->pStreamName;
}
delete (*it)->streamNames[i];
}
(*it)->streamNames.clear();
for (int i = 0; i < (*it)->extensionSystems.size(); i++) {
if ((*it)->extensionSystems[i]->extensionSystemInfo != NULL) {
delete (*it)->extensionSystems[i]->extensionSystemInfo;
}
delete (*it)->extensionSystems[i];
}
(*it)->extensionSystems.clear();
delete (*it);
}
mExtendedStreamPropertiesObj.clear();
resetStreamInfo();
}
AsfAudioStreamInfo* AsfHeaderParser::getAudioInfo() const {
return mAudioInfo;
}
AsfVideoStreamInfo* AsfHeaderParser::getVideoInfo() const {
return mVideoInfo;
}
AsfFileMediaInfo* AsfHeaderParser::getFileInfo() const {
return mFileInfo;
}
uint64_t AsfHeaderParser::getDuration() {
return mFileInfo->duration - mFileInfo->preroll * ASF_SCALE_MS_TO_100NANOSEC;
}
uint32_t AsfHeaderParser::getDataPacketSize() {
return mFileInfo->packetSize;
}
uint32_t AsfHeaderParser::getPreroll() {
// in millisecond unit
return mFileInfo->preroll;
}
uint64_t AsfHeaderParser::getTimeOffset() {
// in 100-nanoseconds unit
if (mAudioInfo) {
return mAudioInfo->timeOffset;
}
if (mVideoInfo) {
return mVideoInfo->timeOffset;
}
return 0;
}
bool AsfHeaderParser::hasVideo() {
return mVideoInfo != NULL;
}
bool AsfHeaderParser::hasAudio() {
return mAudioInfo != NULL;
}
bool AsfHeaderParser::isSeekable() {
return mFileInfo->seekable;
}
int AsfHeaderParser::parse(uint8_t *buffer, uint64_t size) {
int status = ASF_PARSER_SUCCESS;
// reset parser's status
mNumObjectParsed = 0;
resetStreamInfo();
memset(mFileInfo, 0, sizeof(AsfFileMediaInfo));
do {
if (size < sizeof(AsfObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfObject *obj = (AsfObject*)buffer;
if (obj->objectSize > size) {
return ASF_PARSER_BAD_VALUE;
}
if (obj->objectID == ASF_Header_Object) {
if (size < sizeof(AsfHeaderObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfHeaderObject *headerObj = (AsfHeaderObject*)buffer;
mNumberofHeaderObjects = headerObj->numberofHeaderObjects;
size -= sizeof(AsfHeaderObject);
buffer += sizeof(AsfHeaderObject);
} else {
if(obj->objectID == ASF_File_Properties_Object) {
status = onFilePropertiesObject(buffer, size);
} else if(obj->objectID == ASF_Stream_Properties_Object) {
status = onStreamPropertiesObject(buffer, size);
} else if(obj->objectID == ASF_Header_Extension_Object) {
//AsfHeaderExtensionObject *headerExtObj = (AsfHeaderExtensionObject*)buffer;
if (size < sizeof(AsfHeaderExtensionObject)) {
return ASF_PARSER_BAD_DATA;
}
status = parseHeaderExtensionObject(
buffer + sizeof(AsfHeaderExtensionObject),
size - sizeof(AsfHeaderExtensionObject));
} else if(obj->objectID == ASF_Codec_List_Object) {
} else if(obj->objectID == ASF_Script_Command_Object) {
} else if(obj->objectID == ASF_Marker_Object) {
} else if(obj->objectID == ASF_Bitrate_Mutual_Exclusion_Object) {
} else if(obj->objectID == ASF_Error_Correction_Object) {
} else if(obj->objectID == ASF_Content_Description_Object) {
} else if(obj->objectID == ASF_Extended_Content_Description_Object) {
} else if(obj->objectID == ASF_Stream_Bitrate_Properties_Object) {
} else if(obj->objectID == ASF_Content_Branding_Object) {
} else if(obj->objectID == ASF_Content_Encryption_Object) {
} else if(obj->objectID == ASF_Extended_Content_Encryption_Object) {
} else if(obj->objectID == ASF_Digital_Signature_Object) {
} else if(obj->objectID == ASF_Padding_Object) {
} else if(obj->objectID == ASF_Protection_System_Identifier_Object) {
mIsProtected = true;
LOGV("ASF_Protection_System_Identifier_Object");
if (obj->objectSize < sizeof(AsfProtectionSystemIdObj)) {
LOGE("Unsupported Protection System Object");
return ASF_PARSER_BAD_DATA;
}
AsfProtectionSystemIdObj *protectionSysObj = (AsfProtectionSystemIdObj*)buffer;
uint8_t* playreadyObjBuf = NULL;
memcpy(mPlayreadyUuid, protectionSysObj->sysId, UUIDSIZE);
// Rights Management Header - Record Type = 0x0001
// Traverse till field containing number of records
playreadyObjBuf = buffer + sizeof(AsfProtectionSystemIdObj);
uint32_t sizeLeft = obj->objectSize - sizeof(AsfProtectionSystemIdObj); // For Maintaining and checking the left memory in the object
for (int i = 0; i < protectionSysObj->countRecords; i++) {
if (sizeLeft > 4) {
uint16_t recordType = *((uint16_t*)playreadyObjBuf);
playreadyObjBuf += sizeof(uint16_t);
sizeLeft -= sizeof (recordType);
uint16_t recordLen = *((uint16_t*)playreadyObjBuf);
playreadyObjBuf += sizeof(uint16_t);
sizeLeft -= sizeof (recordLen);
if (sizeLeft < recordLen) {
LOGE("Invalid Rec Protection Identifier Object");
status = ASF_PARSER_BAD_DATA;
break;
}
if (recordType == 0x01) {// Rights management Header
mPlayreadyHeaderLen = recordLen;
if (mPlayreadyHeaderLen == 0) {
LOGE("Invalid Protection System Record Length Value");
return ASF_PARSER_BAD_DATA;
}
mPlayreadyHeader = new uint8_t [mPlayreadyHeaderLen];
if (mPlayreadyHeader == NULL) {
return ASF_PARSER_NO_MEMORY;
}
memcpy(mPlayreadyHeader, playreadyObjBuf, mPlayreadyHeaderLen);
break;
}
playreadyObjBuf += recordLen;
sizeLeft -= recordLen;
} else {
LOGE("Invalid sizeLeft");
return ASF_PARSER_BAD_DATA;
}
}
}
if (status != ASF_PARSER_SUCCESS) {
return status;
}
size -= (uint32_t)obj->objectSize;
buffer += obj->objectSize;
mNumObjectParsed++;
if (mNumObjectParsed == mNumberofHeaderObjects) {
return ASF_PARSER_SUCCESS;
}
}
}
while (status == ASF_PARSER_SUCCESS);
return status;
}
int AsfHeaderParser::getPlayreadyUuid(uint8_t playreadyUuid[], uint16_t len) {
if (playreadyUuid == NULL || (!mIsProtected))
return ASF_PARSER_FAILED;
if (len < UUIDSIZE) {
LOGE("Invalid length ");
return ASF_PARSER_FAILED;
}
memcpy(playreadyUuid, mPlayreadyUuid, UUIDSIZE);
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::getPlayreadyHeaderXml(uint8_t *header, uint32_t *len) {
if (header == NULL) {
*len = mPlayreadyHeaderLen;
return ASF_PARSER_NULL_POINTER;
}
memcpy(header, mPlayreadyHeader, mPlayreadyHeaderLen);
*len = mPlayreadyHeaderLen;
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::onFilePropertiesObject(uint8_t *buffer, uint32_t size) {
if (size < sizeof(AsfFilePropertiesObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfFilePropertiesObject *obj = (AsfFilePropertiesObject*)buffer;
mFileInfo->dataPacketsCount = obj->dataPacketsCount;
mFileInfo->duration = obj->playDuration;
mFileInfo->fileSize = obj->fileSize;
mFileInfo->packetSize = obj->maximumDataPacketSize;
if (mFileInfo->packetSize != obj->minimumDataPacketSize) {
return ASF_PARSER_BAD_VALUE;
}
mFileInfo->preroll = obj->preroll;
mFileInfo->seekable = obj->flags.bits.seekableFlag;
if (obj->flags.bits.broadcastFlag) {
// turn off seeking
mFileInfo->seekable = false;
}
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::onStreamPropertiesObject(uint8_t *buffer, uint32_t size) {
int status;
if (size < sizeof(AsfStreamPropertiesObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfStreamPropertiesObject *obj = (AsfStreamPropertiesObject*)buffer;
if (obj->typeSpecificDataLength + obj->errorCorrectionDataLength >
size - sizeof(AsfStreamPropertiesObject)) {
return ASF_PARSER_BAD_VALUE;
}
uint8_t *typeSpecificData = buffer + sizeof(AsfStreamPropertiesObject);
if (obj->streamType == ASF_Video_Media) {
status = onVideoSpecificData(obj, typeSpecificData);
} else if (obj->streamType == ASF_Audio_Media) {
status = onAudioSpecificData(obj, typeSpecificData);
} else {
// ignore other media specific data
status = ASF_PARSER_SUCCESS;
}
return status;
}
int AsfHeaderParser::onVideoSpecificData(AsfStreamPropertiesObject *obj, uint8_t *data) {
// size of codec specific data is obj->typeSpecificDataLength
uint32_t headerLen = sizeof(AsfVideoInfoHeader) + sizeof(AsfBitmapInfoHeader);
if (obj->typeSpecificDataLength < headerLen) {
return ASF_PARSER_BAD_DATA;
}
AsfVideoInfoHeader *info = (AsfVideoInfoHeader*)data;
AsfBitmapInfoHeader *bmp = (AsfBitmapInfoHeader*)(data + sizeof(AsfVideoInfoHeader));
if (info->formatDataSize < sizeof(AsfBitmapInfoHeader)) {
return ASF_PARSER_BAD_VALUE;
}
if (bmp->formatDataSize - sizeof(AsfBitmapInfoHeader) >
obj->typeSpecificDataLength - headerLen) {
// codec specific data is invalid
return ASF_PARSER_BAD_VALUE;
}
AsfVideoStreamInfo *videoInfo = new AsfVideoStreamInfo;
if (videoInfo == NULL) {
return ASF_PARSER_NO_MEMORY;
}
videoInfo->streamNumber = obj->flags.bits.streamNumber;
videoInfo->encryptedContentFlag = obj->flags.bits.encryptedContentFlag;
videoInfo->timeOffset = obj->timeOffset;
videoInfo->width = info->encodedImageWidth;
videoInfo->height = info->encodedImageHeight;
// Following condition taken from Section 2.4.2.2 - Video Media Type, of Playready documentation
if (bmp->compressionID == FOURCC('Y', 'D', 'R', 'P')) {
// That means PYV content, for which Compression Id is
// the last 4 bytes of the codec specific data following the Video format data
uint32_t* ptrActCompId = (uint32_t*)((data + sizeof(AsfVideoInfoHeader) + bmp->formatDataSize - sizeof(uint32_t)));
videoInfo->fourCC = (*ptrActCompId);
} else {
videoInfo->fourCC = bmp->compressionID;
}
LOGV("onVideoSpecificData() with videoInfo->fourCC = %x", videoInfo->fourCC);
// TODO: get aspect ratio from video meta data
videoInfo->aspectX = 1;
videoInfo->aspectY = 1;
videoInfo->codecDataSize = bmp->formatDataSize - sizeof(AsfBitmapInfoHeader);
if (videoInfo->codecDataSize) {
videoInfo->codecData = new uint8_t [videoInfo->codecDataSize];
if (videoInfo->codecData == NULL) {
delete videoInfo;
return ASF_PARSER_NO_MEMORY;
}
memcpy(videoInfo->codecData,
data + headerLen,
videoInfo->codecDataSize);
} else {
videoInfo->codecData = NULL;
}
videoInfo->next = NULL;
if (mVideoInfo == NULL) {
mVideoInfo = videoInfo;
} else {
AsfVideoStreamInfo *last = mVideoInfo;
while (last->next != NULL) {
last = last->next;
}
last->next = videoInfo;
}
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::onAudioSpecificData(AsfStreamPropertiesObject *obj, uint8_t *data) {
if (obj->typeSpecificDataLength < sizeof(AsfWaveFormatEx)) {
return ASF_PARSER_BAD_DATA;
}
AsfWaveFormatEx *format = (AsfWaveFormatEx*)data;
if (format->codecSpecificDataSize >
obj->typeSpecificDataLength - sizeof(AsfWaveFormatEx)) {
return ASF_PARSER_BAD_VALUE;
}
AsfAudioStreamInfo *audioInfo = new AsfAudioStreamInfo;
if (audioInfo == NULL) {
return ASF_PARSER_NO_MEMORY;
}
audioInfo->streamNumber = obj->flags.bits.streamNumber;
audioInfo->encryptedContentFlag = obj->flags.bits.encryptedContentFlag;
audioInfo->timeOffset = obj->timeOffset;
// Codec Id is 0x5052 i.e. ASCII value of 'P', 'R' for Playready -
// [Refer Section 2.4.2.1 - Audio Media Type, of Playready documentation]
if (format->codecIDFormatTag == PRFORMATTAG) {
// That means protected content, for which Codec Id is
// the last 2 bytes of the codec specific data following the Audio format data
uint32_t* ptrActCodecId = (uint32_t*)((data + sizeof(AsfWaveFormatEx) + format->codecSpecificDataSize - sizeof(format->codecIDFormatTag)));
audioInfo->codecID = (*ptrActCodecId);
} else {
audioInfo->codecID = format->codecIDFormatTag;
}
LOGV("onAudioSpecificData => format->codecIDFormatTag = %x",format->codecIDFormatTag);
audioInfo->numChannels = format->numberOfChannels;
audioInfo->sampleRate= format->samplesPerSecond;
audioInfo->avgByteRate = format->averageNumberOfBytesPerSecond;
audioInfo->blockAlignment = format->blockAlignment;
audioInfo->bitsPerSample = format->bitsPerSample;
audioInfo->codecDataSize = format->codecSpecificDataSize;
if (audioInfo->codecDataSize) {
audioInfo->codecData = new uint8_t [audioInfo->codecDataSize];
if (audioInfo->codecData == NULL) {
delete audioInfo;
return ASF_PARSER_NO_MEMORY;
}
memcpy(audioInfo->codecData,
data + sizeof(AsfWaveFormatEx),
audioInfo->codecDataSize);
} else {
audioInfo->codecData = NULL;
}
audioInfo->next = NULL;
if (mAudioInfo == NULL) {
mAudioInfo = audioInfo;
} else {
AsfAudioStreamInfo *last = mAudioInfo;
while (last->next != NULL) {
last = last->next;
}
last->next = audioInfo;
}
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::onExtendedStreamPropertiesObject(uint8_t *buffer, uint32_t size) {
int status = ASF_PARSER_SUCCESS;
if (size < sizeof(AsfObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfExtendedStreamPropertiesObject *fixedLenExtStrPropsObj = (AsfExtendedStreamPropertiesObject *)buffer;
if (fixedLenExtStrPropsObj->objectSize > size) {
ALOGE("Invalid ASF Extended Stream Prop Object size");
return ASF_PARSER_BAD_VALUE;
}
AsfExtendedStreamPropertiesExObject *extStrObj = new AsfExtendedStreamPropertiesExObject;
if (extStrObj == NULL) {
return ASF_PARSER_NO_MEMORY;
}
//copy all fixed length fields first.
memcpy(&(extStrObj->propObj), fixedLenExtStrPropsObj, sizeof(AsfExtendedStreamPropertiesObject));
ALOGD("Stream number = 0x%08X", fixedLenExtStrPropsObj->streamNumber);
ALOGD("PayloadExtensionSystemCount = 0x%08X", fixedLenExtStrPropsObj->payloadExtensionSystemCount);
// Get pointer to buffer where variable length fields might start
buffer += sizeof(AsfExtendedStreamPropertiesObject);
uint32_t streamNameOffset = sizeof(uint16_t) * 2; // languageIDIndex + streamNameLength
//StramNames might start here. depends on streamNameCount.
for (int i = 0; i < fixedLenExtStrPropsObj->streamNameCount; i++) {
AsfStreamName *streamNameObj = new AsfStreamName;
AsfStreamName *StreamNameObjBuffer = (AsfStreamName *)buffer;
// populate the StreamName object from the buffer
streamNameObj->languageIDIndex = StreamNameObjBuffer->languageIDIndex;
streamNameObj->streamNameLength = StreamNameObjBuffer->streamNameLength;
// Allocate space to store StreamName(3rd field) for the StreamName structure
if (streamNameObj->streamNameLength > 0) {
streamNameObj->pStreamName = new uint8_t [StreamNameObjBuffer->streamNameLength];
if (streamNameObj->pStreamName == NULL) {
delete streamNameObj;
delete extStrObj;
return ASF_PARSER_NO_MEMORY;
}
memcpy(streamNameObj->pStreamName, buffer + streamNameOffset, StreamNameObjBuffer->streamNameLength);
} else {
// no streamName
streamNameObj->pStreamName = NULL;
}
// calculate the length of current StreamName entry.
// if there are multiple StreamNames then increment
// buffer by 4 + streamNameLength to point to next StreamName entry
buffer += streamNameOffset + StreamNameObjBuffer->streamNameLength;
extStrObj->streamNames.push_back(streamNameObj);
}
uint32_t systemInfoOffset = sizeof(GUID) + sizeof(uint16_t) + sizeof(uint32_t);
//buffer points to extension systems here depending on payloadExtensionSystemCount in previous Fixed field.
for (int i = 0; i < fixedLenExtStrPropsObj->payloadExtensionSystemCount; i++) {
AsfPayloadExtensionSystem *extensionObj = new AsfPayloadExtensionSystem;
AsfPayloadExtensionSystem *extObjData = (AsfPayloadExtensionSystem *)buffer;
// populate the extension object from the buffer
extensionObj->extensionSystemId = extObjData->extensionSystemId;
extensionObj->extensionDataSize = extObjData->extensionDataSize;
extensionObj->extensionSystemInfoLength = extObjData->extensionSystemInfoLength;
// Allocate space to store extensionSystemInfo
if (extensionObj->extensionSystemInfoLength > 0) {
extensionObj->extensionSystemInfo = new uint8_t [extObjData->extensionSystemInfoLength];
if (extensionObj->extensionSystemInfo == NULL) {
delete extensionObj;
delete extStrObj;
return ASF_PARSER_NO_MEMORY;
}
memcpy(extensionObj->extensionSystemInfo, buffer + systemInfoOffset, extObjData->extensionSystemInfoLength);
} else {
// no extension system info
extensionObj->extensionSystemInfo = NULL;
}
// calculate the length of current extension system.
// if there are multiple extension systems then increment
// buffer by 22 + extensionSystemInfoLength to point to
// next extension object
buffer += systemInfoOffset + extensionObj->extensionSystemInfoLength;
// add the extension object to the extended stream object
extStrObj->extensionSystems.push_back(extensionObj);
}
mExtendedStreamPropertiesObj.push_back(extStrObj);
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::parseHeaderExtensionObject(uint8_t* buffer, uint32_t size) {
// No empty space, padding, leading, or trailing bytes are allowed in the extention data
int status = ASF_PARSER_SUCCESS;
do {
if (size < sizeof(AsfObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfObject *obj = (AsfObject *)buffer;
if (obj->objectSize > size) {
return ASF_PARSER_BAD_VALUE;
}
if(obj->objectID == ASF_Extended_Stream_Properties_Object) {
status = onExtendedStreamPropertiesObject(buffer, size);
} else if(obj->objectID == ASF_Advanced_Mutual_Exclusion_Object) {
} else if(obj->objectID == ASF_Group_Mutual_Exclusion_Object) {
} else if(obj->objectID == ASF_Stream_Prioritization_Object) {
} else if(obj->objectID == ASF_Bandwidth_Sharing_Object) {
} else if(obj->objectID == ASF_Language_List_Object) {
} else if(obj->objectID == ASF_Metadata_Object) {
} else if(obj->objectID == ASF_Metadata_Library_Object) {
} else if(obj->objectID == ASF_Index_Parameters_Object) {
} else if(obj->objectID == ASF_Media_Object_Index_Parameters_Object) {
} else if(obj->objectID == ASF_Timecode_Index_Parameters_Object) {
} else if(obj->objectID == ASF_Compatibility_Object) {
} else if(obj->objectID == ASF_Advanced_Content_Encryption_Object) {
} else {
}
if (status != ASF_PARSER_SUCCESS) {
break;
}
size -= (uint32_t)obj->objectSize;
buffer += obj->objectSize;
if (size == 0) {
break;
}
}
while (status == ASF_PARSER_SUCCESS);
return status;
}
int AsfHeaderParser::parseSampleIDFromReplicatedData(AsfPayloadDataInfo *obj, uint8_t streamNumber) {
vector<AsfPayloadExtensionSystem *> *extSystems = NULL;
// Get handle to extension systems in that stream's Extension Stream Properties object.
for (unsigned int i = 0; i < mExtendedStreamPropertiesObj.size(); i++) {
if (streamNumber == mExtendedStreamPropertiesObj[i]->propObj.streamNumber) {
extSystems = &(mExtendedStreamPropertiesObj[i]->extensionSystems);
break;
}
}
if (extSystems == NULL) {
return ASF_PARSER_FAILED;
}
int replicatedDataOffset = 0;
// Find data correspodning to ASF_Payload_Extension_System_Encryption_Sample_ID which is SampleID
for (int i = 0; i < extSystems->size(); i++) {
// Point to ext system's data in replicated data buffer.
if ((extSystems->at(i)->extensionSystemId) == ASF_Payload_Extension_System_Encryption_Sample_ID) {
if (extSystems->at(i)->extensionDataSize == 0xFFFF) {
uint16_t extensionDataSize = *((uint16_t*) (obj->replicatedData + 8 + replicatedDataOffset));
obj->sampleIDLen = extensionDataSize;
obj->sampleID = obj->replicatedData + 8 + replicatedDataOffset + sizeof(uint16_t); // 2 bytes denote size of this extSystem
} else {
obj->sampleID = obj->replicatedData + 8 + replicatedDataOffset;
obj->sampleIDLen = extSystems->at(i)->extensionDataSize;
}
return ASF_PARSER_SUCCESS;
}
// Some other extension system. Modify the replicatedData offset accordingly to point to next extension system.
if (extSystems->at(i)->extensionDataSize == 0xFFFF) {
uint16_t nSize = *((uint16_t*) (obj->replicatedData + 8 + replicatedDataOffset));
replicatedDataOffset += (sizeof(uint16_t) + nSize);
} else {
replicatedDataOffset += extSystems->at(i)->extensionDataSize;
}
}
return ASF_PARSER_UNEXPECTED_VALUE; // Other extension systems.
}
void AsfHeaderParser::resetStreamInfo() {
while (mAudioInfo) {
AsfAudioStreamInfo *next = mAudioInfo->next;
delete [] mAudioInfo->codecData;
delete mAudioInfo;
mAudioInfo = next;
}
while (mVideoInfo) {
AsfVideoStreamInfo *next = mVideoInfo->next;
delete [] mVideoInfo->codecData;
delete mVideoInfo;
mVideoInfo = next;
}
}