blob: 1abb4d6cd2578e0dbb5f7c7d9e90fba664ff1c18 [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>
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<AsfExtendedStreamPropertiesObject *>::iterator it = mExtendedStreamPropertiesObj.begin(); it != mExtendedStreamPropertiesObj.end(); ++it) {
for (int i = 0; i < (*it)->extensionSystems.size(); i++) {
if ((*it)->extensionSystems[i]->extensionSystemInfo != NULL) {
delete (*it)->extensionSystems[i]->extensionSystemInfo;
(*it)->extensionSystems[i]->extensionSystemInfo = NULL;
}
delete (*it)->extensionSystems[i];
(*it)->extensionSystems[i] = NULL;
}
(*it)->extensionSystems.clear();
delete (*it);
(*it) = NULL;
}
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");
uint64_t playreadyObjSize = obj->objectSize;
PlayreadyHeaderObj *plrdyHdrObj = (PlayreadyHeaderObj*)buffer;
uint8_t* playreadyObjBuf = NULL;
GUID *pldyUuid = (GUID*)plrdyHdrObj->sysId;
memcpy(mPlayreadyUuid, (uint8_t*)pldyUuid, UUIDSIZE);
// Rights Management Header - Record Type = 0x0001
// Traverse till field containing number of records
playreadyObjBuf = buffer + sizeof(PlayreadyHeaderObj);
for (int i = 0; i < plrdyHdrObj->countRecords; i++) {
uint16_t* recordType = (uint16_t*)playreadyObjBuf;
if (*recordType == 0x01) {// Rights management Header
playreadyObjBuf += sizeof(uint16_t);
uint16_t* recordLen = (uint16_t*)playreadyObjBuf;
mPlayreadyHeaderLen = *recordLen;
mPlayreadyHeader = new uint8_t [mPlayreadyHeaderLen];
if (mPlayreadyHeader == NULL) {
return ASF_PARSER_NO_MEMORY;
}
playreadyObjBuf += sizeof(uint16_t);
memcpy(mPlayreadyHeader, playreadyObjBuf, mPlayreadyHeaderLen);
break;
}
}
}
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) {
if (playreadyUuid == NULL || (!mIsProtected))
return ASF_PARSER_FAILED;
memcpy(playreadyUuid, mPlayreadyUuid, UUIDSIZE);
return ASF_PARSER_SUCCESS;
}
int AsfHeaderParser::getPlayreadyHeaderXml(uint8_t *playreadyHeader, uint32_t *playreadyHeaderLen) {
if (playreadyHeader == NULL) {
*playreadyHeaderLen = mPlayreadyHeaderLen;
return ASF_PARSER_NULL_POINTER;
}
memcpy(playreadyHeader, mPlayreadyHeader, mPlayreadyHeaderLen);
*playreadyHeaderLen = 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;
if (bmp->compressionID == FOURCC('Y', 'D', 'R', 'P')) {
// That means PYV content
uint32_t* ptrActCompId = (uint32_t*)((data + sizeof(AsfVideoInfoHeader) + bmp->formatDataSize - sizeof(uint32_t)));
bmp->actualCompressionID = *ptrActCompId;
videoInfo->fourCC = bmp->actualCompressionID;
LOGV("onVideoSpecificData() with bmp->actualCompressionID = %x", bmp->actualCompressionID);
} else {
videoInfo->fourCC = bmp->compressionID;
}
// 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;
LOGV("onAudioSpecificData => format->codecIDFormatTag = %x",format->codecIDFormatTag);
if (format->codecIDFormatTag == 0x5052) {
uint32_t* ptrActCodecId = (uint32_t*)((data + sizeof(AsfWaveFormatEx) + format->codecSpecificDataSize - sizeof(format->codecIDFormatTag)));
format->codecIDFormatTag = *ptrActCodecId;
audioInfo->codecID = format->codecIDFormatTag;
} else {
audioInfo->codecID = 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 *extStrObj = new AsfExtendedStreamPropertiesObject;
if (extStrObj == NULL) {
return ASF_PARSER_NO_MEMORY;
}
AsfExtendedStreamPropertiesObject *obj = (AsfExtendedStreamPropertiesObject *)buffer;
if (obj->objectSize > size) {
ALOGE("Invalid ASF Extended Stream Prop Object size");
delete extStrObj;
return ASF_PARSER_BAD_VALUE;
}
extStrObj->objectID = obj->objectID;
extStrObj->objectSize = obj->objectSize;
extStrObj->startTime = obj->startTime;
extStrObj->endTime = obj->endTime;
extStrObj->dataBitrate = obj->dataBitrate;
extStrObj->bufferSize = obj->bufferSize;
extStrObj->initialBufferFullness = obj->initialBufferFullness;
extStrObj->alternateDataBitrate = obj->alternateDataBitrate;
extStrObj->alternateBufferSize = obj->alternateBufferSize;
extStrObj->alternateInitialBufferFullness = obj->alternateInitialBufferFullness;
extStrObj->maximumObjectSize = obj->maximumObjectSize;
extStrObj->flags = obj->flags;
extStrObj->streamNumber = obj->streamNumber;
extStrObj->streamLanguageIDIndex = obj->streamLanguageIDIndex;
extStrObj->averageTimePerFrame = obj->averageTimePerFrame;
extStrObj->streamNameCount = obj->streamNameCount;
extStrObj->payloadExtensionSystemCount = obj->payloadExtensionSystemCount;
ALOGD("stream number = 0x%08X", obj->streamNumber);
ALOGD("payloadExtensionSystemCount = 0x%08X", obj->payloadExtensionSystemCount);
// Get pointer to buffer where first extension system object starts
buffer = (uint8_t *)&(obj->extensionSystems);
int extSysSize = 0;
for (int i = 0; i < obj->payloadExtensionSystemCount; i++ ) {
extSysSize = 0;
PayloadExtensionSystem *extensionObj = new PayloadExtensionSystem;
PayloadExtensionSystem *extObjData = (PayloadExtensionSystem *)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) {
// TODO: make sure this memory is freed when not reuired.
extensionObj->extensionSystemInfo = new uint8_t [extObjData->extensionSystemInfoLength];
if (extensionObj->extensionSystemInfo == NULL) {
delete extensionObj;
delete extStrObj;
return ASF_PARSER_NO_MEMORY;
}
memcpy(extensionObj->extensionSystemInfo, extObjData->extensionSystemInfo, 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 extSysSize
// to point to next extension object
extSysSize += sizeof(GUID) + sizeof(uint16_t) + sizeof(uint32_t) + extensionObj->extensionSystemInfoLength;
buffer += extSysSize;
// 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::getPayloadExtensionSystems(uint8_t streamNumber, vector<PayloadExtensionSystem *> **extSystems ) {
for (unsigned int i = 0; i < mExtendedStreamPropertiesObj.size(); i++) {
if (streamNumber == mExtendedStreamPropertiesObj[i]->streamNumber) {
*extSystems = &(mExtendedStreamPropertiesObj[i]->extensionSystems);
return ASF_PARSER_SUCCESS;
}
}
return ASF_PARSER_FAILED;
}
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;
}
}