blob: 795e7eacba1d1c608564a64e6514aab820c02010 [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.
*
*/
#include "AsfHeaderParser.h"
#include <string.h>
AsfHeaderParser::AsfHeaderParser(void)
: mAudioInfo(NULL),
mVideoInfo(NULL),
mFileInfo(NULL),
mNumObjectParsed(0),
mNumberofHeaderObjects(0) {
mFileInfo = new AsfFileMediaInfo;
memset(mFileInfo, 0, sizeof(AsfFileMediaInfo));
}
AsfHeaderParser::~AsfHeaderParser(void) {
delete mFileInfo;
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, uint32_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 (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::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;
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;
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) {
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;
}
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;
}
}