aboutsummaryrefslogtreecommitdiff
path: root/src/mp4property.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mp4property.cpp')
-rw-r--r--src/mp4property.cpp1237
1 files changed, 1237 insertions, 0 deletions
diff --git a/src/mp4property.cpp b/src/mp4property.cpp
new file mode 100644
index 0000000..063a273
--- /dev/null
+++ b/src/mp4property.cpp
@@ -0,0 +1,1237 @@
+/*
+ * 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
+ * Kona Blend kona8lend@@gmail.com
+ */
+
+#include "src/impl.h"
+
+namespace mp4v2 { namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+
+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, uint32_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
+
+uint64_t MP4IntegerProperty::GetValue(uint32_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(uint64_t value, uint32_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(uint64_t value, uint32_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(uint32_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, uint32_t index)
+{
+ SetValue(GetValue() + increment);
+}
+
+void MP4Integer8Property::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u] = %u (0x%02x)\n",
+ m_name, index, m_values[index], m_values[index]);
+ else
+ fprintf(pFile, "%s = %u (0x%02x)\n",
+ m_name, m_values[index], m_values[index]);
+ fflush(pFile);
+}
+
+void MP4Integer16Property::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u] = %u (0x%04x)\n",
+ m_name, index, m_values[index], m_values[index]);
+ else
+ fprintf(pFile, "%s = %u (0x%04x)\n",
+ m_name, m_values[index], m_values[index]);
+ fflush(pFile);
+}
+
+void MP4Integer24Property::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u] = %u (0x%06x)\n",
+ m_name, index, m_values[index], m_values[index]);
+ else
+ fprintf(pFile, "%s = %u (0x%06x)\n",
+ m_name, m_values[index], m_values[index]);
+ fflush(pFile);
+}
+
+void MP4Integer32Property::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u] = %u (0x%08x)\n",
+ m_name, index, m_values[index], m_values[index]);
+ else
+ fprintf(pFile, "%s = %u (0x%08x)\n",
+ m_name, m_values[index], m_values[index]);
+ fflush(pFile);
+}
+
+void MP4Integer64Property::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u] = %" PRIu64 " (0x%016" PRIx64 ")\n",
+ m_name, index, m_values[index], m_values[index]);
+ else
+ fprintf(pFile,
+ "%s = %" PRIu64 " (0x%016" PRIx64 ")\n",
+ m_name, m_values[index], m_values[index]);
+ fflush(pFile);
+}
+
+// MP4BitfieldProperty
+
+void MP4BitfieldProperty::Read(MP4File* pFile, uint32_t index)
+{
+ if (m_implicit) {
+ return;
+ }
+ m_values[index] = pFile->ReadBits(m_numBits);
+}
+
+void MP4BitfieldProperty::Write(MP4File* pFile, uint32_t index)
+{
+ if (m_implicit) {
+ return;
+ }
+ pFile->WriteBits(m_values[index], m_numBits);
+}
+
+void MP4BitfieldProperty::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+
+ uint8_t hexWidth = m_numBits / 4;
+ if (hexWidth == 0 || (m_numBits % 4)) {
+ hexWidth++;
+ }
+ if (index != 0)
+ fprintf(pFile,
+ "%s[%u] = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits>\n",
+ m_name, index, m_values[index], (int)hexWidth, m_values[index], m_numBits);
+ else
+ fprintf(pFile,
+ "%s = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits>\n",
+ m_name, m_values[index], (int)hexWidth, m_values[index], m_numBits);
+ fflush(pFile);
+}
+
+// MP4Float32Property
+
+void MP4Float32Property::Read(MP4File* pFile, uint32_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, uint32_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]);
+ }
+}
+
+void MP4Float32Property::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u] = %f\n",
+ m_name, index, m_values[index]);
+ else
+ fprintf(pFile, "%s = %f\n",
+ m_name, m_values[index]);
+ fflush(pFile);
+}
+
+// MP4StringProperty
+
+MP4StringProperty::MP4StringProperty(
+ const char* name,
+ bool useCountedFormat,
+ bool useUnicode,
+ bool arrayMode )
+
+ : MP4Property( name )
+ , m_arrayMode ( arrayMode )
+ , m_useCountedFormat ( useCountedFormat )
+ , m_useExpandedCount ( false )
+ , m_useUnicode ( useUnicode )
+ , m_fixedLength ( 0 )
+ , m_fixedLengthSet ( false )
+{
+ SetCount( 1 );
+ m_values[0] = NULL;
+}
+
+MP4StringProperty::~MP4StringProperty()
+{
+ uint32_t count = GetCount();
+ for (uint32_t i = 0; i < count; i++) {
+ MP4Free(m_values[i]);
+ }
+}
+
+void MP4StringProperty::SetCount(uint32_t count)
+{
+ uint32_t oldCount = m_values.Size();
+
+ m_values.Resize(count);
+
+ for (uint32_t i = oldCount; i < count; i++) {
+ m_values[i] = NULL;
+ }
+}
+
+void MP4StringProperty::SetValue(const char* value, uint32_t index)
+{
+ if (m_readOnly) {
+ throw new MP4Error(EACCES, "property is read-only", m_name);
+ }
+
+ MP4Free(m_values[index]);
+
+ if (m_fixedLengthSet) {
+ m_values[index] = (char*)MP4Calloc(m_fixedLength + 1);
+ if (value) {
+ strncpy(m_values[index], value, m_fixedLength);
+ }
+ } else {
+ if (value) {
+ m_values[index] = MP4Stralloc(value);
+ } else {
+ m_values[index] = NULL;
+ }
+ }
+}
+
+void MP4StringProperty::Read( MP4File* pFile, uint32_t index )
+{
+ if( m_implicit )
+ return;
+
+ uint32_t begin = index;
+ uint32_t max = index + 1;
+
+ if( m_arrayMode ) {
+ begin = 0;
+ max = GetCount();
+ }
+
+ for( uint32_t i = begin; i < max; i++ ) {
+ char*& value = m_values[i];
+
+ if( m_useCountedFormat ) {
+ value = pFile->ReadCountedString( (m_useUnicode ? 2 : 1), m_useExpandedCount, m_fixedLength );
+ }
+ else if( m_fixedLengthSet ) {
+ // gfinlayson
+ // Handle the case where a fixed length of 0 was set, in as defensive a way
+ // as possible
+ MP4Free( value );
+ value = (char*)MP4Calloc( m_fixedLength + 1 );
+ if ( m_fixedLength ) {
+ pFile->ReadBytes( (uint8_t*)value, m_fixedLength );
+ }
+ }
+ else {
+ value = pFile->ReadString();
+ }
+ }
+}
+
+void MP4StringProperty::Write( MP4File* pFile, uint32_t index )
+{
+ if( m_implicit )
+ return;
+
+ uint32_t begin = index;
+ uint32_t max = index + 1;
+
+ if( m_arrayMode ) {
+ begin = 0;
+ max = GetCount();
+ }
+
+ for( uint32_t i = begin; i < max; i++ ) {
+ char*& value = m_values[i];
+
+ if( m_useCountedFormat ) {
+ pFile->WriteCountedString( value, (m_useUnicode ? 2 : 1), m_useExpandedCount, m_fixedLength );
+ }
+ else if( m_fixedLength ) {
+ pFile->WriteBytes( (uint8_t*)value, m_fixedLength );
+ }
+ else {
+ pFile->WriteString( value );
+ }
+ }
+}
+
+void MP4StringProperty::Dump( FILE* pFile, uint8_t indent, bool dumpImplicits, uint32_t index )
+{
+ if( m_implicit && !dumpImplicits )
+ return;
+
+ if( !m_arrayMode ) {
+ char indexd[32];
+ if( index != 0 )
+ snprintf( indexd, 32, "[%u]", index );
+ else
+ indexd[0] = '\0';
+
+ Indent( pFile, indent );
+ if( m_useUnicode )
+ fprintf( pFile, "%s%s = %ls\n", m_name, indexd, (wchar_t*)m_values[index] );
+ else
+ fprintf( pFile, "%s%s = %s\n", m_name, indexd, m_values[index] );
+ }
+ else if( !m_pParentAtom ||
+ !m_pParentAtom->GetFile() ||
+ (m_pParentAtom->GetFile()->GetVerbosity() & MP4_DETAILS_TABLE) )
+ {
+ const uint32_t max = GetCount();
+
+ Indent( pFile, indent );
+ fprintf( pFile, "%s (size=%u)\n", m_name, max );
+
+ for( uint32_t i = 0; i < max; i++ ) {
+ char*& value = m_values[i];
+
+ Indent( pFile, indent );
+ if( m_useUnicode )
+ fprintf( pFile, "%s[%u] = %ls\n", m_name, i, (wchar_t*)value );
+ else
+ fprintf( pFile, "%s[%u] = %s\n", m_name, i, value );
+ }
+ }
+ else {
+ Indent( pFile, indent );
+ fprintf( pFile, "<table entries suppressed>\n" );
+ }
+
+ fflush( pFile );
+}
+
+// MP4BytesProperty
+
+MP4BytesProperty::MP4BytesProperty(const char* name, uint32_t valueSize,
+ uint32_t defaultValueSize)
+ : MP4Property(name)
+ , m_fixedValueSize(0)
+ , m_defaultValueSize(defaultValueSize)
+{
+ SetCount(1);
+ m_values[0] = (uint8_t*)MP4Calloc(valueSize);
+ m_valueSizes[0] = valueSize;
+}
+
+MP4BytesProperty::~MP4BytesProperty()
+{
+ uint32_t count = GetCount();
+ for (uint32_t i = 0; i < count; i++) {
+ MP4Free(m_values[i]);
+ }
+}
+
+void MP4BytesProperty::SetCount(uint32_t count)
+{
+ uint32_t oldCount = m_values.Size();
+
+ m_values.Resize(count);
+ m_valueSizes.Resize(count);
+ m_valueStart.Resize(count);
+
+ for (uint32_t i = oldCount; i < count; i++) {
+ m_values[i] = NULL;
+ m_valueSizes[i] = m_defaultValueSize;
+ }
+}
+
+void MP4BytesProperty::SetValue(const uint8_t* pValue, uint32_t valueSize,
+ uint32_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] = (uint8_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] = (uint8_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(uint32_t valueSize, uint32_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] = (uint8_t*)MP4Realloc(m_values[index], valueSize);
+ }
+ m_valueSizes[index] = valueSize;
+}
+
+void MP4BytesProperty::SetFixedSize(uint32_t fixedSize)
+{
+ m_fixedValueSize = 0;
+ for (uint32_t i = 0; i < GetCount(); i++) {
+ SetValueSize(fixedSize, i);
+ }
+ m_fixedValueSize = fixedSize;
+}
+
+void MP4BytesProperty::Read(MP4File* pFile, uint32_t index)
+{
+ if (m_implicit) {
+ return;
+ }
+ MP4Free(m_values[index]);
+ m_valueStart[index] = pFile->GetPosition();
+ m_values[index] = (uint8_t*)MP4Malloc(m_valueSizes[index]);
+ pFile->ReadBytes(m_values[index], m_valueSizes[index]);
+}
+
+void MP4BytesProperty::Write(MP4File* pFile, uint32_t index)
+{
+ if (m_implicit) {
+ return;
+ }
+ pFile->WriteBytes(m_values[index], m_valueSizes[index]);
+}
+
+void MP4BytesProperty::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ if( m_implicit && !dumpImplicits )
+ return;
+
+ const uint32_t size = m_valueSizes[index];
+ const uint8_t* const value = m_values[index];
+
+ Indent( pFile, indent );
+ fprintf( pFile, "%s = <%u bytes>", m_name, size );
+
+ if( size == 0 ) {
+ fprintf( pFile, "\n" );
+ fflush( pFile );
+ return;
+ }
+
+ if( size <= 16 ) {
+ ostringstream oss;
+ ostringstream text;
+
+ oss << " ";
+ for( uint32_t i = 0; i < size; i++ ) {
+ if( i )
+ oss << ' ';
+ oss << hex << setw(2) << setfill('0') << right << static_cast<uint32_t>(value[i]);
+ text << (isprint( static_cast<int>(value[i]) ) ? static_cast<char>(value[i]) : '.');
+ }
+
+ oss << " |" << text.str() << "|\n";
+
+ fprintf( pFile, oss.str().c_str() );
+ fflush( pFile );
+ return;
+ }
+
+ uint32_t adjsize;
+ bool supressed;
+
+ if( size < 128 ||
+ !m_pParentAtom ||
+ !m_pParentAtom->GetFile() ||
+ (m_pParentAtom->GetFile()->GetVerbosity() & MP4_DETAILS_TABLE) )
+ {
+ adjsize = size;
+ supressed = false;
+ }
+ else {
+ adjsize = 128;
+ supressed = true;
+ }
+
+ ostringstream oss;
+ ostringstream text;
+
+ string s;
+ for( uint32_t i = 0; i < adjsize; i++ ) {
+ if( i % 16 == 0 ) {
+ // not safe to use format because bytes may contain format specifies
+ s = oss.str();
+ fwrite( s.c_str(), s.length(), 1, pFile );
+
+ oss.str( "" );
+ oss << '\n'
+ << setw(indent) << setfill(' ') << ""
+ << hex << setw(8) << setfill('0') << right << i;
+
+ if( i > 0 ) {
+ fprintf( pFile, " |" );
+
+ // not safe to use format because bytes may contain format specifies
+ s = text.str();
+ fwrite( s.c_str(), s.length(), 1, pFile );
+
+ fprintf( pFile, "|" );
+ text.str( "" );
+ }
+
+ fflush( pFile );
+ }
+
+ if( i % 8 == 0 )
+ oss << ' ';
+
+ oss << ' ' << hex << setw(2) << setfill('0') << right << static_cast<uint32_t>(value[i]);
+ text << (isprint( static_cast<int>(value[i]) ) ? static_cast<char>(value[i]) : '.');
+ }
+
+ const string stext = text.str();
+ if( !stext.empty() ) {
+ const string::size_type deficit = 16 - stext.length();
+ if( deficit > 7 )
+ oss << ' ';
+
+ oss << setfill(' ') << setw( deficit*3 ) << "" << " |" << stext << '|';
+ }
+
+ oss << "\n";
+
+ if( supressed ) {
+ oss << setw(indent) << setfill(' ') << ""
+ << "<remaining bytes supressed>\n";
+ }
+
+ // not safe to use format because bytes may contain format specifies
+ s = oss.str();
+ fwrite( s.c_str(), s.length(), 1, pFile );
+
+ fflush( pFile );
+}
+
+// MP4TableProperty
+
+MP4TableProperty::MP4TableProperty(const char* name, MP4IntegerProperty* pCountProperty)
+ : MP4Property(name)
+{
+ m_pCountProperty = pCountProperty;
+ m_pCountProperty->SetReadOnly();
+}
+
+MP4TableProperty::~MP4TableProperty()
+{
+ for (uint32_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, uint32_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
+ uint32_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, uint32_t* pIndex)
+{
+ uint32_t numProperties = m_pProperties.Size();
+
+ for (uint32_t i = 0; i < numProperties; i++) {
+ if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void MP4TableProperty::Read(MP4File* pFile, uint32_t index)
+{
+ ASSERT(index == 0);
+
+ if (m_implicit) {
+ return;
+ }
+
+ uint32_t numProperties = m_pProperties.Size();
+
+ if (numProperties == 0) {
+ WARNING(numProperties == 0);
+ return;
+ }
+
+ uint32_t numEntries = GetCount();
+
+ /* for each property set size */
+ for (uint32_t j = 0; j < numProperties; j++) {
+ m_pProperties[j]->SetCount(numEntries);
+ }
+
+ for (uint32_t i = 0; i < numEntries; i++) {
+ ReadEntry(pFile, i);
+ }
+}
+
+void MP4TableProperty::ReadEntry(MP4File* pFile, uint32_t index)
+{
+ for (uint32_t j = 0; j < m_pProperties.Size(); j++) {
+ m_pProperties[j]->Read(pFile, index);
+ }
+}
+
+void MP4TableProperty::Write(MP4File* pFile, uint32_t index)
+{
+ ASSERT(index == 0);
+
+ if (m_implicit) {
+ return;
+ }
+
+ uint32_t numProperties = m_pProperties.Size();
+
+ if (numProperties == 0) {
+ WARNING(numProperties == 0);
+ return;
+ }
+
+ uint32_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 (uint32_t i = 0; i < numEntries; i++) {
+ WriteEntry(pFile, i);
+ }
+}
+
+void MP4TableProperty::WriteEntry(MP4File* pFile, uint32_t index)
+{
+ for (uint32_t j = 0; j < m_pProperties.Size(); j++) {
+ m_pProperties[j]->Write(pFile, index);
+ }
+}
+
+void MP4TableProperty::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ ASSERT(index == 0);
+
+ // implicit tables just can't be dumped
+ if (m_implicit) {
+ return;
+ }
+
+ uint32_t numProperties = m_pProperties.Size();
+
+ if (numProperties == 0) {
+ WARNING(numProperties == 0);
+ return;
+ }
+
+ uint32_t numEntries = GetCount();
+
+ for (uint32_t i = 0; i < numEntries; i++) {
+ for (uint32_t j = 0; j < numProperties; j++) {
+ m_pProperties[j]->Dump(pFile, indent + 1, dumpImplicits, i);
+ }
+ }
+}
+
+// MP4DescriptorProperty
+
+MP4DescriptorProperty::MP4DescriptorProperty(const char* name,
+ uint8_t tagsStart, uint8_t tagsEnd, bool mandatory, bool onlyOne)
+ : MP4Property(name)
+{
+ SetTags(tagsStart, tagsEnd);
+ m_sizeLimit = 0;
+ m_mandatory = mandatory;
+ m_onlyOne = onlyOne;
+}
+
+MP4DescriptorProperty::~MP4DescriptorProperty()
+{
+ for (uint32_t i = 0; i < m_pDescriptors.Size(); i++) {
+ delete m_pDescriptors[i];
+ }
+}
+
+void MP4DescriptorProperty::SetParentAtom(MP4Atom* pParentAtom) {
+ m_pParentAtom = pParentAtom;
+ for (uint32_t i = 0; i < m_pDescriptors.Size(); i++) {
+ m_pDescriptors[i]->SetParentAtom(pParentAtom);
+ }
+}
+
+MP4Descriptor* MP4DescriptorProperty::AddDescriptor(uint8_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(uint32_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, uint32_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
+ uint32_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, uint32_t* pIndex)
+{
+ for (uint32_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, uint32_t index)
+{
+ ASSERT(index == 0);
+
+ if (m_implicit) {
+ return;
+ }
+
+ uint64_t start = pFile->GetPosition();
+
+ while (true) {
+ // enforce size limitation
+ if (m_sizeLimit && pFile->GetPosition() >= start + m_sizeLimit) {
+ break;
+ }
+
+ uint8_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, uint32_t index)
+{
+ ASSERT(index == 0);
+
+ if (m_implicit) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < m_pDescriptors.Size(); i++) {
+ m_pDescriptors[i]->Write(pFile);
+ }
+}
+
+void MP4DescriptorProperty::Dump(FILE* pFile, uint8_t indent,
+ bool dumpImplicits, uint32_t index)
+{
+ ASSERT(index == 0);
+
+ if (m_implicit && !dumpImplicits) {
+ return;
+ }
+
+ if (m_name) {
+ Indent(pFile, indent);
+ if (index != 0)
+ fprintf(pFile, "%s[%u]\n", m_name, index);
+ else
+ fprintf(pFile, "%s\n", m_name);
+ indent++;
+ }
+
+ for (uint32_t i = 0; i < m_pDescriptors.Size(); i++) {
+ m_pDescriptors[i]->Dump(pFile, indent, dumpImplicits);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+MP4LanguageCodeProperty::MP4LanguageCodeProperty( const char* name, bmff::LanguageCode value )
+ : MP4Property( name )
+{
+ SetValue( value );
+}
+
+MP4LanguageCodeProperty::MP4LanguageCodeProperty( const char* name, const string& code )
+ : MP4Property( name )
+{
+ SetValue( bmff::enumLanguageCode.toType( code ));
+}
+
+void
+MP4LanguageCodeProperty::Dump( FILE* file, uint8_t indent, bool dumpImplicits, uint32_t index )
+{
+ Indent( file, indent );
+
+ uint16_t data = 0;
+
+ string svalue;
+ bmff::enumLanguageCode.toString( _value, svalue );
+ if( svalue.length() == 3 ) {
+ data = (((svalue[0] - 0x60) & 0x001f) << 10)
+ | (((svalue[1] - 0x60) & 0x001f) << 5)
+ | (((svalue[2] - 0x60) & 0x001f) );
+ }
+
+ fprintf( file, "%s = %s (0x%04x)\n", m_name, bmff::enumLanguageCode.toString( _value, true ).c_str(), data );
+}
+
+uint32_t
+MP4LanguageCodeProperty::GetCount()
+{
+ return 1;
+}
+
+MP4PropertyType
+MP4LanguageCodeProperty::GetType()
+{
+ return LanguageCodeProperty;
+}
+
+bmff::LanguageCode
+MP4LanguageCodeProperty::GetValue()
+{
+ return _value;
+}
+
+void
+MP4LanguageCodeProperty::Read( MP4File* file, uint32_t index )
+{
+ uint16_t data = file->ReadBits( 16 );
+
+ char code[3];
+ code[0] = ((data & 0x7c00) >> 10) + 0x60;
+ code[1] = ((data & 0x03e0) >> 5) + 0x60;
+ code[2] = ((data & 0x001f) ) + 0x60;
+
+ SetValue( bmff::enumLanguageCode.toType( string( code, sizeof(code) )));
+}
+
+void
+MP4LanguageCodeProperty::SetCount( uint32_t count )
+{
+ // do nothing; count is always 1
+}
+
+void
+MP4LanguageCodeProperty::SetValue( bmff::LanguageCode value )
+{
+ _value = value;
+}
+
+void
+MP4LanguageCodeProperty::Write( MP4File* file, uint32_t index )
+{
+ uint16_t data = 0;
+
+ string svalue;
+ bmff::enumLanguageCode.toString( _value, svalue );
+ if( svalue.length() == 3 ) {
+ data = (((svalue[0] - 0x60) & 0x001f) << 10)
+ | (((svalue[1] - 0x60) & 0x001f) << 5)
+ | (((svalue[2] - 0x60) & 0x001f) );
+ }
+
+ file->WriteBits( data, 16 );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+MP4BasicTypeProperty::MP4BasicTypeProperty( const char* name, itmf::BasicType type )
+ : MP4Property( name )
+{
+ SetValue( type );
+}
+
+void
+MP4BasicTypeProperty::Dump( FILE* file, uint8_t indent, bool dumpImplicits, uint32_t index )
+{
+ Indent( file, indent );
+ fprintf( file, "%s = %s (0x%02x)\n", m_name, itmf::enumBasicType.toString( _value, true ).c_str(), _value );
+}
+
+uint32_t
+MP4BasicTypeProperty::GetCount()
+{
+ return 1;
+}
+
+MP4PropertyType
+MP4BasicTypeProperty::GetType()
+{
+ return BasicTypeProperty;
+}
+
+itmf::BasicType
+MP4BasicTypeProperty::GetValue()
+{
+ return _value;
+}
+
+void
+MP4BasicTypeProperty::Read( MP4File* file, uint32_t index )
+{
+ SetValue( static_cast<itmf::BasicType>( file->ReadBits( 8 )));
+}
+
+void
+MP4BasicTypeProperty::SetCount( uint32_t count )
+{
+ // do nothing; count is always 1
+}
+
+void
+MP4BasicTypeProperty::SetValue( itmf::BasicType value )
+{
+ _value = value;
+}
+
+void
+MP4BasicTypeProperty::Write( MP4File* file, uint32_t index )
+{
+ file->WriteBits( _value, 8 );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+}} // namespace mp4v2::impl