734 lines
17 KiB
C++
734 lines
17 KiB
C++
|
/*
|
||
|
* The contents of this file are subject to the Mozilla Public
|
||
|
* License Version 1.1 (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.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS
|
||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||
|
* implied. See the License for the specific language governing
|
||
|
* rights and limitations under the License.
|
||
|
*
|
||
|
* The Original Code is MPEG4IP.
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is Cisco Systems Inc.
|
||
|
* Portions created by Cisco Systems Inc. are
|
||
|
* Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
* Dave Mackie dmackie@cisco.com
|
||
|
*/
|
||
|
|
||
|
#include "mp4common.h"
|
||
|
|
||
|
MP4Property::MP4Property(const char* name)
|
||
|
{
|
||
|
m_name = name;
|
||
|
m_pParentAtom = NULL;
|
||
|
m_readOnly = false;
|
||
|
m_implicit = false;
|
||
|
}
|
||
|
|
||
|
bool MP4Property::FindProperty(const char* name,
|
||
|
MP4Property** ppProperty, u_int32_t* pIndex)
|
||
|
{
|
||
|
if (name == NULL) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!strcasecmp(m_name, name)) {
|
||
|
if (m_pParentAtom) {
|
||
|
VERBOSE_FIND(m_pParentAtom->GetFile()->GetVerbosity(),
|
||
|
printf("FindProperty: matched %s\n", name));
|
||
|
}
|
||
|
|
||
|
*ppProperty = this;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Integer Property
|
||
|
|
||
|
u_int64_t MP4IntegerProperty::GetValue(u_int32_t index)
|
||
|
{
|
||
|
switch (this->GetType()) {
|
||
|
case Integer8Property:
|
||
|
return ((MP4Integer8Property*)this)->GetValue(index);
|
||
|
case Integer16Property:
|
||
|
return ((MP4Integer16Property*)this)->GetValue(index);
|
||
|
case Integer24Property:
|
||
|
return ((MP4Integer24Property*)this)->GetValue(index);
|
||
|
case Integer32Property:
|
||
|
return ((MP4Integer32Property*)this)->GetValue(index);
|
||
|
case Integer64Property:
|
||
|
return ((MP4Integer64Property*)this)->GetValue(index);
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
void MP4IntegerProperty::SetValue(u_int64_t value, u_int32_t index)
|
||
|
{
|
||
|
switch (this->GetType()) {
|
||
|
case Integer8Property:
|
||
|
((MP4Integer8Property*)this)->SetValue(value, index);
|
||
|
break;
|
||
|
case Integer16Property:
|
||
|
((MP4Integer16Property*)this)->SetValue(value, index);
|
||
|
break;
|
||
|
case Integer24Property:
|
||
|
((MP4Integer24Property*)this)->SetValue(value, index);
|
||
|
break;
|
||
|
case Integer32Property:
|
||
|
((MP4Integer32Property*)this)->SetValue(value, index);
|
||
|
break;
|
||
|
case Integer64Property:
|
||
|
((MP4Integer64Property*)this)->SetValue(value, index);
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4IntegerProperty::InsertValue(u_int64_t value, u_int32_t index)
|
||
|
{
|
||
|
switch (this->GetType()) {
|
||
|
case Integer8Property:
|
||
|
((MP4Integer8Property*)this)->InsertValue(value, index);
|
||
|
break;
|
||
|
case Integer16Property:
|
||
|
((MP4Integer16Property*)this)->InsertValue(value, index);
|
||
|
break;
|
||
|
case Integer24Property:
|
||
|
((MP4Integer24Property*)this)->InsertValue(value, index);
|
||
|
break;
|
||
|
case Integer32Property:
|
||
|
((MP4Integer32Property*)this)->InsertValue(value, index);
|
||
|
break;
|
||
|
case Integer64Property:
|
||
|
((MP4Integer64Property*)this)->InsertValue(value, index);
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4IntegerProperty::DeleteValue(u_int32_t index)
|
||
|
{
|
||
|
switch (this->GetType()) {
|
||
|
case Integer8Property:
|
||
|
((MP4Integer8Property*)this)->DeleteValue(index);
|
||
|
break;
|
||
|
case Integer16Property:
|
||
|
((MP4Integer16Property*)this)->DeleteValue(index);
|
||
|
break;
|
||
|
case Integer24Property:
|
||
|
((MP4Integer24Property*)this)->DeleteValue(index);
|
||
|
break;
|
||
|
case Integer32Property:
|
||
|
((MP4Integer32Property*)this)->DeleteValue(index);
|
||
|
break;
|
||
|
case Integer64Property:
|
||
|
((MP4Integer64Property*)this)->DeleteValue(index);
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4IntegerProperty::IncrementValue(int32_t increment, u_int32_t index)
|
||
|
{
|
||
|
SetValue(GetValue() + increment);
|
||
|
}
|
||
|
|
||
|
// MP4BitfieldProperty
|
||
|
|
||
|
void MP4BitfieldProperty::Read(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
m_values[index] = pFile->ReadBits(m_numBits);
|
||
|
}
|
||
|
|
||
|
void MP4BitfieldProperty::Write(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
pFile->WriteBits(m_values[index], m_numBits);
|
||
|
}
|
||
|
|
||
|
// MP4Float32Property
|
||
|
|
||
|
void MP4Float32Property::Read(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
if (m_useFixed16Format) {
|
||
|
m_values[index] = pFile->ReadFixed16();
|
||
|
} else if (m_useFixed32Format) {
|
||
|
m_values[index] = pFile->ReadFixed32();
|
||
|
} else {
|
||
|
m_values[index] = pFile->ReadFloat();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4Float32Property::Write(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
if (m_useFixed16Format) {
|
||
|
pFile->WriteFixed16(m_values[index]);
|
||
|
} else if (m_useFixed32Format) {
|
||
|
pFile->WriteFixed32(m_values[index]);
|
||
|
} else {
|
||
|
pFile->WriteFloat(m_values[index]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MP4StringProperty
|
||
|
|
||
|
MP4StringProperty::MP4StringProperty(char* name,
|
||
|
bool useCountedFormat, bool useUnicode)
|
||
|
: MP4Property(name)
|
||
|
{
|
||
|
SetCount(1);
|
||
|
m_values[0] = NULL;
|
||
|
m_useCountedFormat = useCountedFormat;
|
||
|
m_useExpandedCount = false;
|
||
|
m_useUnicode = useUnicode;
|
||
|
m_fixedLength = 0; // length not fixed
|
||
|
}
|
||
|
|
||
|
MP4StringProperty::~MP4StringProperty()
|
||
|
{
|
||
|
u_int32_t count = GetCount();
|
||
|
for (u_int32_t i = 0; i < count; i++) {
|
||
|
MP4Free(m_values[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4StringProperty::SetCount(u_int32_t count)
|
||
|
{
|
||
|
u_int32_t oldCount = m_values.Size();
|
||
|
|
||
|
m_values.Resize(count);
|
||
|
|
||
|
for (u_int32_t i = oldCount; i < count; i++) {
|
||
|
m_values[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4StringProperty::SetValue(const char* value, u_int32_t index)
|
||
|
{
|
||
|
if (m_readOnly) {
|
||
|
throw new MP4Error(EACCES, "property is read-only", m_name);
|
||
|
}
|
||
|
|
||
|
MP4Free(m_values[index]);
|
||
|
|
||
|
if (m_fixedLength) {
|
||
|
m_values[index] = (char*)MP4Calloc(m_fixedLength + 1);
|
||
|
if (value) {
|
||
|
strncpy(m_values[index], value, m_fixedLength);
|
||
|
}
|
||
|
} else {
|
||
|
if (value) {
|
||
|
if (m_useUnicode)
|
||
|
m_values[index] = (char *)MP4Stralloc((const uint16_t *)value);
|
||
|
else
|
||
|
m_values[index] = MP4Stralloc(value);
|
||
|
} else {
|
||
|
m_values[index] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4StringProperty::Read(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
if (m_useCountedFormat) {
|
||
|
m_values[index] = pFile->ReadCountedString(
|
||
|
(m_useUnicode ? 2 : 1), m_useExpandedCount);
|
||
|
} else if (m_fixedLength) {
|
||
|
MP4Free(m_values[index]);
|
||
|
m_values[index] = (char*)MP4Calloc(m_fixedLength + 1);
|
||
|
pFile->ReadBytes((u_int8_t*)m_values[index], m_fixedLength);
|
||
|
} else {
|
||
|
if (m_useUnicode)
|
||
|
{
|
||
|
m_values[index] = (char *)pFile->ReadUnicodeString();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char *str = pFile->ReadString();
|
||
|
if (str && str[0] == 0xFF && str[1] == 0xFE)
|
||
|
m_useUnicode = true;
|
||
|
if (str && str[0] == 0xFE && str[1] == 0xFF)
|
||
|
m_useUnicode = true;
|
||
|
m_values[index] = str;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4StringProperty::Write(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
if (m_useCountedFormat) {
|
||
|
pFile->WriteCountedString(m_values[index],
|
||
|
(m_useUnicode ? 2 : 1), m_useExpandedCount);
|
||
|
} else if (m_fixedLength) {
|
||
|
pFile->WriteBytes((u_int8_t*)m_values[index], m_fixedLength);
|
||
|
} else {
|
||
|
if (m_useUnicode)
|
||
|
pFile->WriteUnicodeString((const uint16_t *)m_values[index]);
|
||
|
else
|
||
|
pFile->WriteString(m_values[index]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MP4BytesProperty
|
||
|
|
||
|
MP4BytesProperty::MP4BytesProperty(char* name, u_int32_t valueSize,
|
||
|
u_int32_t defaultValueSize)
|
||
|
: MP4Property(name)
|
||
|
{
|
||
|
SetCount(1);
|
||
|
m_values[0] = (u_int8_t*)MP4Calloc(valueSize);
|
||
|
m_valueSizes[0] = valueSize;
|
||
|
m_fixedValueSize = 0;
|
||
|
m_defaultValueSize = defaultValueSize;
|
||
|
}
|
||
|
|
||
|
MP4BytesProperty::~MP4BytesProperty()
|
||
|
{
|
||
|
u_int32_t count = GetCount();
|
||
|
for (u_int32_t i = 0; i < count; i++) {
|
||
|
MP4Free(m_values[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4BytesProperty::SetCount(u_int32_t count)
|
||
|
{
|
||
|
u_int32_t oldCount = m_values.Size();
|
||
|
|
||
|
m_values.Resize(count);
|
||
|
m_valueSizes.Resize(count);
|
||
|
|
||
|
for (u_int32_t i = oldCount; i < count; i++) {
|
||
|
m_values[i] = NULL;
|
||
|
m_valueSizes[i] = m_defaultValueSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4BytesProperty::SetValue(const u_int8_t* pValue, u_int32_t valueSize,
|
||
|
u_int32_t index)
|
||
|
{
|
||
|
if (m_readOnly) {
|
||
|
throw new MP4Error(EACCES, "property is read-only", m_name);
|
||
|
}
|
||
|
if (m_fixedValueSize) {
|
||
|
if (valueSize > m_fixedValueSize) {
|
||
|
throw new MP4Error("%s.%s value size %d exceeds fixed value size %d",
|
||
|
"MP4BytesProperty::SetValue",
|
||
|
GetParentAtom()->GetType(),
|
||
|
GetName(),
|
||
|
valueSize,
|
||
|
m_fixedValueSize);
|
||
|
}
|
||
|
if (m_values[index] == NULL) {
|
||
|
m_values[index] = (u_int8_t*)MP4Calloc(m_fixedValueSize);
|
||
|
m_valueSizes[index] = m_fixedValueSize;
|
||
|
}
|
||
|
if (pValue) {
|
||
|
memcpy(m_values[index], pValue, valueSize);
|
||
|
}
|
||
|
} else {
|
||
|
MP4Free(m_values[index]);
|
||
|
if (pValue) {
|
||
|
m_values[index] = (u_int8_t*)MP4Malloc(valueSize);
|
||
|
memcpy(m_values[index], pValue, valueSize);
|
||
|
m_valueSizes[index] = valueSize;
|
||
|
} else {
|
||
|
m_values[index] = NULL;
|
||
|
m_valueSizes[index] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4BytesProperty::SetValueSize(u_int32_t valueSize, u_int32_t index)
|
||
|
{
|
||
|
if (m_fixedValueSize) {
|
||
|
throw new MP4Error("can't change size of fixed sized property",
|
||
|
"MP4BytesProperty::SetValueSize");
|
||
|
}
|
||
|
if (m_values[index] != NULL) {
|
||
|
m_values[index] = (u_int8_t*)MP4Realloc(m_values[index], valueSize);
|
||
|
}
|
||
|
m_valueSizes[index] = valueSize;
|
||
|
}
|
||
|
|
||
|
void MP4BytesProperty::SetFixedSize(u_int32_t fixedSize)
|
||
|
{
|
||
|
m_fixedValueSize = 0;
|
||
|
for (u_int32_t i = 0; i < GetCount(); i++) {
|
||
|
SetValueSize(fixedSize, i);
|
||
|
}
|
||
|
m_fixedValueSize = fixedSize;
|
||
|
}
|
||
|
|
||
|
void MP4BytesProperty::Read(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
MP4Free(m_values[index]);
|
||
|
m_values[index] = (u_int8_t*)MP4Malloc(m_valueSizes[index]);
|
||
|
pFile->ReadBytes(m_values[index], m_valueSizes[index]);
|
||
|
}
|
||
|
|
||
|
void MP4BytesProperty::Write(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
pFile->WriteBytes(m_values[index], m_valueSizes[index]);
|
||
|
}
|
||
|
|
||
|
// MP4TableProperty
|
||
|
|
||
|
MP4TableProperty::MP4TableProperty(char* name, MP4IntegerProperty* pCountProperty)
|
||
|
: MP4Property(name)
|
||
|
{
|
||
|
m_pCountProperty = pCountProperty;
|
||
|
m_pCountProperty->SetReadOnly();
|
||
|
}
|
||
|
|
||
|
MP4TableProperty::~MP4TableProperty()
|
||
|
{
|
||
|
for (u_int32_t i = 0; i < m_pProperties.Size(); i++) {
|
||
|
delete m_pProperties[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4TableProperty::AddProperty(MP4Property* pProperty)
|
||
|
{
|
||
|
ASSERT(pProperty);
|
||
|
ASSERT(pProperty->GetType() != TableProperty);
|
||
|
ASSERT(pProperty->GetType() != DescriptorProperty);
|
||
|
m_pProperties.Add(pProperty);
|
||
|
pProperty->SetParentAtom(m_pParentAtom);
|
||
|
pProperty->SetCount(0);
|
||
|
}
|
||
|
|
||
|
bool MP4TableProperty::FindProperty(const char *name,
|
||
|
MP4Property** ppProperty, u_int32_t* pIndex)
|
||
|
{
|
||
|
ASSERT(m_name);
|
||
|
|
||
|
// check if first component of name matches ourselves
|
||
|
if (!MP4NameFirstMatches(m_name, name)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// check if the specified table entry exists
|
||
|
u_int32_t index;
|
||
|
bool haveIndex = MP4NameFirstIndex(name, &index);
|
||
|
if (haveIndex) {
|
||
|
if (index >= GetCount()) {
|
||
|
return false;
|
||
|
}
|
||
|
if (pIndex) {
|
||
|
*pIndex = index;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VERBOSE_FIND(m_pParentAtom->GetFile()->GetVerbosity(),
|
||
|
printf("FindProperty: matched %s\n", name));
|
||
|
|
||
|
// get name of table property
|
||
|
const char *tablePropName = MP4NameAfterFirst(name);
|
||
|
if (tablePropName == NULL) {
|
||
|
if (!haveIndex) {
|
||
|
*ppProperty = this;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// check if this table property exists
|
||
|
return FindContainedProperty(tablePropName, ppProperty, pIndex);
|
||
|
}
|
||
|
|
||
|
bool MP4TableProperty::FindContainedProperty(const char *name,
|
||
|
MP4Property** ppProperty, u_int32_t* pIndex)
|
||
|
{
|
||
|
u_int32_t numProperties = m_pProperties.Size();
|
||
|
|
||
|
for (u_int32_t i = 0; i < numProperties; i++) {
|
||
|
if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void MP4TableProperty::Read(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
ASSERT(index == 0);
|
||
|
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u_int32_t numProperties = m_pProperties.Size();
|
||
|
|
||
|
if (numProperties == 0) {
|
||
|
WARNING(numProperties == 0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u_int32_t numEntries = GetCount();
|
||
|
|
||
|
/* for each property set size */
|
||
|
for (u_int32_t j = 0; j < numProperties; j++) {
|
||
|
m_pProperties[j]->SetCount(numEntries);
|
||
|
}
|
||
|
|
||
|
for (u_int32_t i = 0; i < numEntries; i++) {
|
||
|
ReadEntry(pFile, i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4TableProperty::ReadEntry(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
for (u_int32_t j = 0; j < m_pProperties.Size(); j++) {
|
||
|
m_pProperties[j]->Read(pFile, index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4TableProperty::Write(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
ASSERT(index == 0);
|
||
|
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u_int32_t numProperties = m_pProperties.Size();
|
||
|
|
||
|
if (numProperties == 0) {
|
||
|
WARNING(numProperties == 0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u_int32_t numEntries = GetCount();
|
||
|
|
||
|
if (m_pProperties[0]->GetCount() != numEntries) {
|
||
|
fprintf(stderr, "%s %s \"%s\"table entries %u doesn't match count %u\n",
|
||
|
GetParentAtom() != NULL ? GetParentAtom()->GetType() : "",
|
||
|
GetName(), m_pProperties[0]->GetName(),
|
||
|
m_pProperties[0]->GetCount(), numEntries);
|
||
|
|
||
|
ASSERT(m_pProperties[0]->GetCount() == numEntries);
|
||
|
}
|
||
|
|
||
|
for (u_int32_t i = 0; i < numEntries; i++) {
|
||
|
WriteEntry(pFile, i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4TableProperty::WriteEntry(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
for (u_int32_t j = 0; j < m_pProperties.Size(); j++) {
|
||
|
m_pProperties[j]->Write(pFile, index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MP4DescriptorProperty
|
||
|
|
||
|
MP4DescriptorProperty::MP4DescriptorProperty(char* name,
|
||
|
u_int8_t tagsStart, u_int8_t tagsEnd, bool mandatory, bool onlyOne)
|
||
|
: MP4Property(name)
|
||
|
{
|
||
|
SetTags(tagsStart, tagsEnd);
|
||
|
m_sizeLimit = 0;
|
||
|
m_mandatory = mandatory;
|
||
|
m_onlyOne = onlyOne;
|
||
|
}
|
||
|
|
||
|
MP4DescriptorProperty::~MP4DescriptorProperty()
|
||
|
{
|
||
|
for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) {
|
||
|
delete m_pDescriptors[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4DescriptorProperty::SetParentAtom(MP4Atom* pParentAtom) {
|
||
|
m_pParentAtom = pParentAtom;
|
||
|
for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) {
|
||
|
m_pDescriptors[i]->SetParentAtom(pParentAtom);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MP4Descriptor* MP4DescriptorProperty::AddDescriptor(u_int8_t tag)
|
||
|
{
|
||
|
// check that tag is in expected range
|
||
|
ASSERT(tag >= m_tagsStart && tag <= m_tagsEnd);
|
||
|
|
||
|
MP4Descriptor* pDescriptor = CreateDescriptor(tag);
|
||
|
ASSERT(pDescriptor);
|
||
|
|
||
|
m_pDescriptors.Add(pDescriptor);
|
||
|
pDescriptor->SetParentAtom(m_pParentAtom);
|
||
|
|
||
|
return pDescriptor;
|
||
|
}
|
||
|
|
||
|
void MP4DescriptorProperty::DeleteDescriptor(u_int32_t index)
|
||
|
{
|
||
|
delete m_pDescriptors[index];
|
||
|
m_pDescriptors.Delete(index);
|
||
|
}
|
||
|
|
||
|
void MP4DescriptorProperty::Generate()
|
||
|
{
|
||
|
// generate a default descriptor
|
||
|
// if it is mandatory, and single
|
||
|
if (m_mandatory && m_onlyOne) {
|
||
|
MP4Descriptor* pDescriptor =
|
||
|
AddDescriptor(m_tagsStart);
|
||
|
pDescriptor->Generate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool MP4DescriptorProperty::FindProperty(const char *name,
|
||
|
MP4Property** ppProperty, u_int32_t* pIndex)
|
||
|
{
|
||
|
// we're unnamed, so just check contained properties
|
||
|
if (m_name == NULL || !strcmp(m_name, "")) {
|
||
|
return FindContainedProperty(name, ppProperty, pIndex);
|
||
|
}
|
||
|
|
||
|
// check if first component of name matches ourselves
|
||
|
if (!MP4NameFirstMatches(m_name, name)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// check if the specific descriptor entry exists
|
||
|
u_int32_t descrIndex;
|
||
|
bool haveDescrIndex = MP4NameFirstIndex(name, &descrIndex);
|
||
|
|
||
|
if (haveDescrIndex && descrIndex >= GetCount()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (m_pParentAtom) {
|
||
|
VERBOSE_FIND(m_pParentAtom->GetFile()->GetVerbosity(),
|
||
|
printf("FindProperty: matched %s\n", name));
|
||
|
}
|
||
|
|
||
|
// get name of descriptor property
|
||
|
name = MP4NameAfterFirst(name);
|
||
|
if (name == NULL) {
|
||
|
if (!haveDescrIndex) {
|
||
|
*ppProperty = this;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/* check rest of name */
|
||
|
if (haveDescrIndex) {
|
||
|
return m_pDescriptors[descrIndex]->FindProperty(name,
|
||
|
ppProperty, pIndex);
|
||
|
} else {
|
||
|
return FindContainedProperty(name, ppProperty, pIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool MP4DescriptorProperty::FindContainedProperty(const char *name,
|
||
|
MP4Property** ppProperty, u_int32_t* pIndex)
|
||
|
{
|
||
|
for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) {
|
||
|
if (m_pDescriptors[i]->FindProperty(name, ppProperty, pIndex)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void MP4DescriptorProperty::Read(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
ASSERT(index == 0);
|
||
|
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u_int64_t start = pFile->GetPosition();
|
||
|
|
||
|
while (true) {
|
||
|
// enforce size limitation
|
||
|
if (m_sizeLimit && pFile->GetPosition() >= start + m_sizeLimit) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
u_int8_t tag;
|
||
|
try {
|
||
|
pFile->PeekBytes(&tag, 1);
|
||
|
}
|
||
|
catch (MP4Error* e) {
|
||
|
if (pFile->GetPosition() >= pFile->GetSize()) {
|
||
|
// EOF
|
||
|
delete e;
|
||
|
break;
|
||
|
}
|
||
|
throw e;
|
||
|
}
|
||
|
|
||
|
// check if tag is in desired range
|
||
|
if (tag < m_tagsStart || tag > m_tagsEnd) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
MP4Descriptor* pDescriptor =
|
||
|
AddDescriptor(tag);
|
||
|
|
||
|
pDescriptor->Read(pFile);
|
||
|
}
|
||
|
|
||
|
// warnings
|
||
|
if (m_mandatory && m_pDescriptors.Size() == 0) {
|
||
|
VERBOSE_READ(pFile->GetVerbosity(),
|
||
|
printf("Warning: Mandatory descriptor 0x%02x missing\n",
|
||
|
m_tagsStart));
|
||
|
} else if (m_onlyOne && m_pDescriptors.Size() > 1) {
|
||
|
VERBOSE_READ(pFile->GetVerbosity(),
|
||
|
printf("Warning: Descriptor 0x%02x has more than one instance\n",
|
||
|
m_tagsStart));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MP4DescriptorProperty::Write(MP4File* pFile, u_int32_t index)
|
||
|
{
|
||
|
ASSERT(index == 0);
|
||
|
|
||
|
if (m_implicit) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (u_int32_t i = 0; i < m_pDescriptors.Size(); i++) {
|
||
|
m_pDescriptors[i]->Write(pFile);
|
||
|
}
|
||
|
}
|