blob: 19821793c9737dcad6d2b1ca771c70d645cbb256 [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 "AsfDataParser.h"
#include "AsfGuids.h"
#include "AsfObjects.h"
#include <string.h>
// Helper fucctions
static inline uint8_t lengthType2Bytes(uint8_t lengthType) {
// lengthType: 0 1 2 3
// bits: 0 8 16 32
// bytes: 0 1 2 4
return 4 >> (3 - (lengthType & 0x03));
}
static inline uint32_t getModuleValue(uint32_t value, uint8_t lengthType) {
switch (lengthType) {
case 0:
return 0; // field does not exist
case 1:
return value % 0x100; // (BYTE)
case 2:
return value % 0x10000; // (WORD)
case 3:
return value; //(DWORD)
}
return value;
}
static inline uint32_t getFieldValue(uint8_t *buffer, uint8_t lengthType) {
switch (lengthType) {
case 0:
return 0; // field does not exist
case 1:
return *buffer;
case 2:
return *(uint16_t*)buffer;
case 3:
return *(uint32_t*)buffer;
}
// This line should not be reached
return 0xffffffff ;
}
static void freePayloadDataInfo(AsfPayloadDataInfo *header) {
while (header) {
AsfPayloadDataInfo *next = header->next;
delete header;
header = next;
}
}
AsfPayloadDataInfoPool::AsfPayloadDataInfoPool()
: mFirstDataInfo(NULL),
mLastDataInfo(NULL) {
}
AsfPayloadDataInfoPool::~AsfPayloadDataInfoPool() {
freePayloadDataInfo(mFirstDataInfo);
}
void AsfPayloadDataInfoPool::releasePayloadDataInfo(AsfPayloadDataInfo *info) {
if (info == NULL) {
return;
}
if (mFirstDataInfo == NULL) {
mFirstDataInfo = info;
} else {
mLastDataInfo->next = info;
}
while (info->next != NULL) {
info = info->next;
}
mLastDataInfo = info;
}
AsfPayloadDataInfo* AsfPayloadDataInfoPool::getPayloadDataInfo() {
AsfPayloadDataInfo *entry;
if (mFirstDataInfo == NULL) {
entry = new AsfPayloadDataInfo;
if (entry == NULL) {
return NULL;
}
} else {
entry = mFirstDataInfo;
mFirstDataInfo = mFirstDataInfo->next;
if (mFirstDataInfo == NULL) {
mLastDataInfo = NULL;
}
}
memset(entry, 0, sizeof(AsfPayloadDataInfo));
return entry;
}
int AsfErrorCorrectionData::parse(uint8_t *buffer, uint32_t size) {
errorCorrectionFlags.value = *buffer;
blockSize = 0;
if (errorCorrectionFlags.bits.errorCorrectionPresent == 0) {
return ASF_PARSER_SUCCESS;
}
blockSize = 1;
// determine if Error Correction Data Length is valid
if (errorCorrectionFlags.bits.errorCorrectionLengthType == 0) {
// Error Correction Data Length is valid only if the value of the Error Correction Length Type is 00
// Error Correction Data Length should be 0010
// Opaque Data Present should be set to 0
blockSize += errorCorrectionFlags.bits.errorCorrectionDataLength;
return ASF_PARSER_SUCCESS;
}
// if Error Correction Length Type is different thant 00, Error Correction Data Length shall be zero.
if (errorCorrectionFlags.bits.errorCorrectionDataLength == 0) {
return ASF_PARSER_SUCCESS;
}
return ASF_PARSER_BAD_VALUE;
}
int AsfPayloadParsingInformation::parse(uint8_t *buffer, uint32_t size) {
lengthTypeFlags.value = *buffer;
propertyFlags.value = *(buffer + 1);
// lengthTypeFlags:
// sequence type should be set to 00
// packet length type should be set to 00 when creating content
// propertyFlags:
// replicated data length type should be set to 01 (BYTE)
// offset into media object shall be set to 11 (DWORD)
// media object number length type shall be set to 01 (BYTE)
// stream number length type shalll be set to 01 (BYTE)
blockSize = 2;
packetLength = getFieldValue(buffer + blockSize, lengthTypeFlags.bits.packetLengthType);
blockSize += lengthType2Bytes(lengthTypeFlags.bits.packetLengthType);
sequence = getFieldValue(buffer + blockSize, lengthTypeFlags.bits.sequenceType);
blockSize += lengthType2Bytes(lengthTypeFlags.bits.sequenceType);
paddingLength = getFieldValue(buffer + blockSize, lengthTypeFlags.bits.paddingLengthType);
blockSize += lengthType2Bytes(lengthTypeFlags.bits.paddingLengthType);
sendTime = *(uint32_t*)(buffer + blockSize);
blockSize += 4;
duration = *(uint16_t*)(buffer + blockSize);
blockSize += 2;
return ASF_PARSER_SUCCESS;
}
int AsfSinglePayloadUncompressed::parse(uint8_t *buffer, uint32_t size, AsfPayloadDataInfo **out) {
// initialize output
*out = NULL;
streamNumber.value = *buffer;
blockSize = 1;
mediaObjectNumber = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.mediaObjectNumberLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.mediaObjectNumberLengthType);
offsetIntoMediaObject = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
replicatedDataLength = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.replicatedDataLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.replicatedDataLengthType);
if (replicatedDataLength == 1) {
// compressed payload
blockSize == 0;
return ASF_PARSER_COMPRESSED_PAYLOAD;
}
if (replicatedDataLength == 0) {
// TODO:
return ASF_PARSER_UNEXPECTED_VALUE;
}
if (replicatedDataLength < 8) {
return ASF_PARSER_BAD_VALUE;
}
AsfPayloadDataInfo *obj = pool->getPayloadDataInfo();
if (obj == NULL) {
return ASF_PARSER_NO_MEMORY;
}
// Replicated data, at least 8 bytes
obj->mediaObjectLength = *(uint32_t*)(buffer + blockSize);
obj->presentationTime = *(uint32_t*)(buffer + blockSize + 4);
blockSize += replicatedDataLength;
obj->payloadData = buffer + blockSize;
// size = packet length - packet header length
// payload size = size - payload header size (blockSize) - padding length
obj->payloadSize = size - blockSize - ppi->paddingLength;
if ((int)obj->payloadSize <= 0) {
delete obj;
return ASF_PARSER_BAD_VALUE;
}
obj->offsetIntoMediaObject = offsetIntoMediaObject;
obj->streamNumber = streamNumber.bits.streamNumber;
obj->mediaObjectNumber = mediaObjectNumber;
obj->keyframe = streamNumber.bits.keyFrameBit;
obj->next = NULL;
// skip padding data
blockSize += ppi->paddingLength;
*out = obj;
return ASF_PARSER_SUCCESS;
}
int AsfSinglePayloadCompressed::parse(uint8_t *buffer, uint32_t size, AsfPayloadDataInfo **out) {
// initialize output
*out = NULL;
streamNumber.value = *buffer;
blockSize = 1;
mediaObjectNumber = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.mediaObjectNumberLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.mediaObjectNumberLengthType);
// presentation time is coded using the value of Offset Into Media Object Length Type
presentationTime= getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
// must be 1
replicatedDataLength = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.replicatedDataLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.replicatedDataLengthType);
presentationTimeDelta = *(buffer + blockSize);
blockSize++;
int payloadLenRemaining = size - blockSize - ppi->paddingLength;
if (payloadLenRemaining <= 0) {
return ASF_PARSER_BAD_VALUE;
}
uint32_t pts = presentationTime;
uint32_t objNumber = mediaObjectNumber;
uint8_t subPayloadDataLength;
AsfPayloadDataInfo *first = NULL, *next = NULL, *last = NULL;
while (payloadLenRemaining > 0) {
subPayloadDataLength = *(buffer + blockSize);
blockSize++;
payloadLenRemaining -= 1;
next = pool->getPayloadDataInfo();
if (next == NULL) {
freePayloadDataInfo(first);
return ASF_PARSER_NO_MEMORY;
}
next->payloadData = buffer + blockSize;
next->payloadSize = subPayloadDataLength;
next->presentationTime = pts;
next->offsetIntoMediaObject = 0;
next->mediaObjectLength = subPayloadDataLength;
next->streamNumber = streamNumber.bits.streamNumber;
next->mediaObjectNumber = getModuleValue(objNumber, ppi->propertyFlags.bits.mediaObjectNumberLengthType);
next->keyframe = streamNumber.bits.keyFrameBit;
next->next = NULL;
if (first == NULL) {
first = next;
last = next;
} else {
last->next = next;
last = next;
}
pts += presentationTimeDelta;
objNumber++;
blockSize += subPayloadDataLength;
payloadLenRemaining -= subPayloadDataLength;
}
if (payloadLenRemaining != 0) {
// TODO:
freePayloadDataInfo(first);
return ASF_PARSER_BAD_VALUE;
}
// skip padding data
blockSize += ppi->paddingLength;
*out = first;
return ASF_PARSER_SUCCESS;
}
int AsfMultiplePayloadsHeader::parse(uint8_t *buffer, uint32_t size) {
payloadFlags.value = *buffer;
blockSize = 1;
// number of payloads must not be 0
if (payloadFlags.bits.numberOfPayloads == 0) {
return ASF_PARSER_BAD_VALUE;
}
// payload length type should be set to 10 (WORD)
return ASF_PARSER_SUCCESS;
}
int AsfMultiplePayloadsUncompressed::parse(uint8_t *buffer, uint32_t size, AsfPayloadDataInfo **out) {
// initialize output
*out = NULL;
streamNumber.value = *buffer;
blockSize = 1;
mediaObjectNumber = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.mediaObjectNumberLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.mediaObjectNumberLengthType);
offsetIntoMediaObject = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
replicatedDataLength = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.replicatedDataLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.replicatedDataLengthType);
if (replicatedDataLength == 1) {
// compressed payload
blockSize == 0;
return ASF_PARSER_COMPRESSED_PAYLOAD;
}
if (replicatedDataLength == 0) {
// TODO:
return ASF_PARSER_UNEXPECTED_VALUE;
}
if (replicatedDataLength < 8) {
return ASF_PARSER_BAD_VALUE;
}
AsfPayloadDataInfo *obj = pool->getPayloadDataInfo();
if (obj == NULL) {
return ASF_PARSER_NO_MEMORY;
}
// at least 8 bytes replicated data
obj->mediaObjectLength = *(uint32_t *)(buffer + blockSize);
obj->presentationTime = *(uint32_t *)(buffer + blockSize + 4);
blockSize += replicatedDataLength;
// payload length must not be 0
payloadLength = getFieldValue(buffer + blockSize, mpHeader->payloadFlags.bits.payloadLengthType);
blockSize += lengthType2Bytes(mpHeader->payloadFlags.bits.payloadLengthType);
if (payloadLength == 0 || payloadLength + blockSize > size) {
delete obj;
return ASF_PARSER_BAD_VALUE;
}
obj->payloadData = buffer + blockSize;
obj->payloadSize = payloadLength;
obj->offsetIntoMediaObject = offsetIntoMediaObject;
obj->streamNumber = streamNumber.bits.streamNumber;
obj->mediaObjectNumber = mediaObjectNumber;
obj->keyframe = streamNumber.bits.keyFrameBit;
obj->next = NULL;
// skip payload data
blockSize += payloadLength;
*out = obj;
return ASF_PARSER_SUCCESS;
}
int AsfMultiplePayloadsCompressed::parse(uint8_t *buffer, uint32_t size, AsfPayloadDataInfo **out) {
// initialize output
*out = NULL;
streamNumber.value = *buffer;
blockSize = 1;
mediaObjectNumber = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.mediaObjectNumberLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.mediaObjectNumberLengthType);
// presentation time is coded using the value of Offset Into Media Object Length Type
presentationTime= getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.offsetIntoMediaObjectLengthType);
// must be 1
replicatedDataLength = getFieldValue(buffer + blockSize, ppi->propertyFlags.bits.replicatedDataLengthType);
blockSize += lengthType2Bytes(ppi->propertyFlags.bits.replicatedDataLengthType);
presentationTimeDelta = *(buffer + blockSize);
blockSize++;
// payload length must not be 0
payloadLength = getFieldValue(buffer + blockSize, mpHeader->payloadFlags.bits.payloadLengthType);
blockSize += lengthType2Bytes(mpHeader->payloadFlags.bits.payloadLengthType);
if (payloadLength == 0 || blockSize + payloadLength > size) {
return ASF_PARSER_BAD_VALUE;
}
// safe to case from uint32_t to int.
int payloadLenRemaining = (int)payloadLength;
uint32_t pts = presentationTime;
uint32_t objNumber = mediaObjectNumber;
uint8_t subPayloadDataLength;
AsfPayloadDataInfo *first = NULL, *next = NULL, *last = NULL;
while (payloadLenRemaining > 0) {
subPayloadDataLength = *(buffer + blockSize);
blockSize++;
payloadLenRemaining -= 1;
next = pool->getPayloadDataInfo();
if (next == NULL) {
freePayloadDataInfo(first);
return ASF_PARSER_NO_MEMORY;
}
next->payloadData = buffer + blockSize;
next->payloadSize = subPayloadDataLength;
next->presentationTime = pts;
next->offsetIntoMediaObject = 0;
next->mediaObjectLength = subPayloadDataLength;
next->streamNumber = streamNumber.bits.streamNumber;
next->mediaObjectNumber = getModuleValue(objNumber, ppi->propertyFlags.bits.mediaObjectNumberLengthType);
next->keyframe = streamNumber.bits.keyFrameBit;
next->next = NULL;
if (first == NULL) {
first = next;
last = next;
} else {
last->next = next;
last = next;
}
pts += presentationTimeDelta;
objNumber++;
blockSize += subPayloadDataLength;
payloadLenRemaining -= subPayloadDataLength;
}
if (payloadLenRemaining < 0) {
// TODO:
freePayloadDataInfo(first);
return ASF_PARSER_BAD_VALUE;
}
// blockSize stays as it is
*out = first;
return ASF_PARSER_SUCCESS;
}
AsfDataParser::AsfDataParser(void)
: mTotalDataPackets(0) {
mSPUncompressed.ppi = &mPPI;
mSPCompressed.ppi = &mPPI;
mMPHeader.ppi = &mPPI;
mMPUncompressed.ppi = &mPPI;
mMPCompressed.ppi = &mPPI;
mMPUncompressed.mpHeader = &mMPHeader;
mMPCompressed.mpHeader = &mMPHeader;
mSPUncompressed.pool = &mPool;
mSPCompressed.pool = &mPool;
mMPUncompressed.pool = &mPool;
mMPCompressed.pool = &mPool;
}
AsfDataParser::~AsfDataParser(void) {
}
int AsfDataParser::parseHeader(uint8_t *buffer, uint32_t size) {
if (size < sizeof(AsfDataObject)) {
return ASF_PARSER_BAD_DATA;
}
AsfDataObject *obj = (AsfDataObject*)buffer;
mTotalDataPackets = obj->totalDataPackets;
return ASF_PARSER_SUCCESS;
}
uint64_t AsfDataParser::getTotalDataPackets() {
return mTotalDataPackets;
}
int AsfDataParser::parsePacket(uint8_t *buffer, uint32_t size, AsfPayloadDataInfo **out) {
int status;
AsfPayloadDataInfo *first = NULL;
status = mECD.parse(buffer, size);
if (status != ASF_PARSER_SUCCESS) {
return status;
}
buffer += mECD.blockSize;
size -= mECD.blockSize;
status = mPPI.parse(buffer, size);
if (status != ASF_PARSER_SUCCESS) {
return status;
}
buffer += mPPI.blockSize;
size -= mPPI.blockSize;
if (mPPI.lengthTypeFlags.bits.multiplePayloadsPresent) {
status = mMPHeader.parse(buffer, size);
if (status != ASF_PARSER_SUCCESS) {
return status;
}
buffer += mMPHeader.blockSize;
size -= mMPHeader.blockSize;
AsfPayloadDataInfo *last = NULL, *next = NULL;
for (int i = 0; i < mMPHeader.payloadFlags.bits.numberOfPayloads; i++) {
status = mMPUncompressed.parse(buffer, size, &next);
if (status == ASF_PARSER_SUCCESS) {
buffer += mMPUncompressed.blockSize;
size -= mMPUncompressed.blockSize;
} else if (status == ASF_PARSER_COMPRESSED_PAYLOAD) {
status = mMPCompressed.parse(buffer, size, &next);
if (status != ASF_PARSER_SUCCESS) {
break;
}
buffer += mMPCompressed.blockSize;
size -= mMPCompressed.blockSize;
}
else {
break;
}
if ((int)size < 0) {
status = ASF_PARSER_BAD_VALUE;
break;
}
// concatenate the payloads.
if (first == NULL) {
first = next;
last = next;
}
else {
while (last->next != NULL) {
last = last->next;
}
last->next = next;
last = next;
}
}
}
else {
status = mSPUncompressed.parse(buffer, size, &first);
if (status == ASF_PARSER_COMPRESSED_PAYLOAD) {
status = mSPCompressed.parse(buffer, size, &first);
}
}
if (status != ASF_PARSER_SUCCESS) {
freePayloadDataInfo(first);
return status;
}
*out = first;
return ASF_PARSER_SUCCESS;
}
void AsfDataParser::releasePayloadDataInfo(AsfPayloadDataInfo *info) {
mPool.releasePayloadDataInfo(info);
}