diff options
Diffstat (limited to 'debian/mp4v2/mp4v2-2.0.0~dfsg0/src')
121 files changed, 36085 insertions, 0 deletions
diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/3gp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/3gp.cpp new file mode 100644 index 00000000..f6ec12e6 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/3gp.cpp @@ -0,0 +1,69 @@ +/* + * 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. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +#define _3GP_MAJOR_BRAND "3gp5" +#define _3GP_MINOR_VERSION 0x0001 + +void MP4File::Make3GPCompliant(const char* fileName, char* majorBrand, uint32_t minorVersion, char** supportedBrands, uint32_t supportedBrandsCount, bool deleteIodsAtom) +{ + char brand[5] = "3gp5"; + char* _3gpSupportedBrands[1] = { (char*)&brand }; + + if (majorBrand) { + if (!supportedBrands || !supportedBrandsCount) { + throw new Exception("Invalid parameters", __FILE__, __LINE__, __FUNCTION__); + } + } + + MakeFtypAtom( + majorBrand ? majorBrand : (char*)brand, + majorBrand ? minorVersion : _3GP_MINOR_VERSION, + majorBrand ? supportedBrands : (char**)_3gpSupportedBrands, + majorBrand ? supportedBrandsCount : 1); + + if (deleteIodsAtom) { + // Delete the iods atom, if it exists.... + MP4Atom* iodsAtom = m_pRootAtom->FindAtom("moov.iods"); + if (iodsAtom) { + MP4Atom* moovAtom = m_pRootAtom->FindAtom("moov"); + ASSERT(moovAtom); + + moovAtom->DeleteChildAtom(iodsAtom); + } + } + +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ac3.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ac3.cpp new file mode 100644 index 00000000..300f4c11 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ac3.cpp @@ -0,0 +1,71 @@ +/* + * 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. + * + * See ETSI TS 102 366 V1.2.1 Annex F for how to put Ac3 in MP4. + * + * Contributor(s): + * Edward Groenendaal [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Ac3Atom::MP4Ac3Atom(MP4File &file) + : MP4Atom(file, "ac-3") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this,"dataReferenceIndex")); + + AddReserved(*this,"reserved2", 8); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this,"channelCount")); + + AddProperty( /* 4 */ + new MP4Integer16Property(*this,"sampleSize")); + + AddReserved(*this,"reserved3", 4); /* 5 */ + + AddProperty( /* 6 */ + new MP4Integer16Property(*this,"samplingRate")); + + AddReserved(*this,"reserved4", 2); /* 7 */ + + ExpectChildAtom("dac3", Required, OnlyOne); +} + +void MP4Ac3Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); // data-reference-index + ((MP4Integer16Property*)m_pProperties[3])->SetValue(2); // channelCount - ignored + ((MP4Integer16Property*)m_pProperties[4])->SetValue(0x0010); // sampleSize - ignored + + // The user should set the samplingRate as appropriate - and create the dac3 atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_amr.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_amr.cpp new file mode 100644 index 00000000..b2a21b3a --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_amr.cpp @@ -0,0 +1,75 @@ +/* + * 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. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4AmrAtom::MP4AmrAtom(MP4File &file, const char *type) + : MP4Atom(file, type) +{ + AddReserved(*this,"reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this,"dataReferenceIndex")); + + AddReserved(*this,"reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this,"timeScale")); + + AddReserved(*this,"reserved3", 2); /* 4 */ + + ExpectChildAtom("damr", Required, OnlyOne); +} + +void MP4AmrAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static uint8_t reserved2[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[2]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[2])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[2]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_avc1.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_avc1.cpp new file mode 100644 index 00000000..3599f3ee --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_avc1.cpp @@ -0,0 +1,93 @@ +/* + * 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. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Avc1Atom::MP4Avc1Atom(MP4File &file) + : MP4Atom(file, "avc1") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "width")); + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "height")); + + AddReserved(*this, "reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty(*this, "compressorName"); + pProp->SetFixedLength(32); + pProp->SetCountedFormat(true); + pProp->SetValue("JVT/AVC Coding"); + AddProperty(pProp); /* 6 */ + + AddReserved(*this, "reserved4", 4); /* 7 */ + + ExpectChildAtom("avcC", Required, OnlyOne); + ExpectChildAtom("btrt", Optional, OnlyOne); + ExpectChildAtom("colr", Optional, OnlyOne); + ExpectChildAtom("pasp", Optional, OnlyOne); + // for now ExpectChildAtom("m4ds", Optional, OnlyOne); +} + +void MP4Avc1Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static uint8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static uint8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_avcC.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_avcC.cpp new file mode 100644 index 00000000..ac477a2d --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_avcC.cpp @@ -0,0 +1,273 @@ +/* + * 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. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +/* + * SizeTableProperty is a special version of the MP4TableProperty - + * the BytesProperty will need to set the value before it can read + * from the file + */ +class SizeTableProperty : public MP4TableProperty +{ +public: + SizeTableProperty(MP4Atom& parentAtom, const char *name, MP4IntegerProperty *pCountProperty) : + MP4TableProperty(parentAtom, name, pCountProperty) {}; +protected: + void ReadEntry(MP4File& file, uint32_t index) { + // Each table has a size, followed by the length field + // first, read the length + m_pProperties[0]->Read(file, index); + MP4IntegerProperty *pIntProp = (MP4IntegerProperty *)m_pProperties[0]; + // set the size in the bytes property + MP4BytesProperty *pBytesProp = (MP4BytesProperty *)m_pProperties[1]; + pBytesProp->SetValueSize(pIntProp->GetValue(index), index); + // And read the bytes + m_pProperties[1]->Read(file, index); + }; +private: + SizeTableProperty(); + SizeTableProperty ( const SizeTableProperty &src ); + SizeTableProperty &operator= ( const SizeTableProperty &src ); +}; + +MP4AvcCAtom::MP4AvcCAtom(MP4File &file) + : MP4Atom(file, "avcC") +{ + MP4BitfieldProperty *pCount; + MP4TableProperty *pTable; + + AddProperty( new MP4Integer8Property(*this,"configurationVersion")); /* 0 */ + + AddProperty( new MP4Integer8Property(*this,"AVCProfileIndication")); /* 1 */ + + AddProperty( new MP4Integer8Property(*this,"profile_compatibility")); /* 2 */ + + AddProperty( new MP4Integer8Property(*this,"AVCLevelIndication")); /* 3 */ + + AddProperty( new MP4BitfieldProperty(*this,"reserved", 6)); /* 4 */ + AddProperty( new MP4BitfieldProperty(*this,"lengthSizeMinusOne", 2)); /* 5 */ + AddProperty( new MP4BitfieldProperty(*this,"reserved1", 3)); /* 6 */ + pCount = new MP4BitfieldProperty(*this,"numOfSequenceParameterSets", 5); + AddProperty(pCount); /* 7 */ + + pTable = new SizeTableProperty(*this,"sequenceEntries", pCount); + AddProperty(pTable); /* 8 */ + pTable->AddProperty(new MP4Integer16Property(pTable->GetParentAtom(),"sequenceParameterSetLength")); + pTable->AddProperty(new MP4BytesProperty(pTable->GetParentAtom(),"sequenceParameterSetNALUnit")); + + MP4Integer8Property *pCount2 = new MP4Integer8Property(*this,"numOfPictureParameterSets"); + AddProperty(pCount2); /* 9 */ + + pTable = new SizeTableProperty(*this,"pictureEntries", pCount2); + AddProperty(pTable); /* 10 */ + pTable->AddProperty(new MP4Integer16Property(pTable->GetParentAtom(),"pictureParameterSetLength")); + pTable->AddProperty(new MP4BytesProperty(pTable->GetParentAtom(),"pictureParameterSetNALUnit")); +} + +void MP4AvcCAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer8Property*)m_pProperties[0])->SetValue(1); + + m_pProperties[4]->SetReadOnly(false); + ((MP4BitfieldProperty*)m_pProperties[4])->SetValue(0x3f); + m_pProperties[4]->SetReadOnly(true); + + m_pProperties[6]->SetReadOnly(false); + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(0x7); + m_pProperties[6]->SetReadOnly(true); +#if 0 + // property reserved4 has non-zero fixed values + static uint8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +#endif +} + +// +// Clone - clone my properties to destination atom +// +// this method simplifies duplicating avcC atom properties from +// source to destination file using a single API rather than +// having to copy each property. This API encapsulates the object +// so the application layer need not concern with each property +// thereby isolating any future changes to atom properties. +// +// ---------------------------------------- +// property description +// ---------------------------------------- +// +// 0 configurationVersion +// 1 AVCProfileIndication +// 2 profile_compatibility +// 3 AVCLevelIndication +// 4 reserved +// 5 lengthSizeMinusOne +// 6 reserved +// 7 number of SPS +// 8 SPS entries +// 9 number of PPS +// 10 PPS entries +// +// +void MP4AvcCAtom::Clone(MP4AvcCAtom *dstAtom) +{ + + MP4Property *dstProperty; + MP4TableProperty *pTable; + uint16_t i16; + uint64_t i32; + uint64_t i64; + uint8_t *tmp; + + // source pointer Property I16 + MP4Integer16Property *spPI16; + // source pointer Property Bytes + MP4BytesProperty *spPB; + + // dest pointer Property I16 + MP4Integer16Property *dpPI16; + // dest pointer Property Bytes + MP4BytesProperty *dpPB; + + + // start with defaults and reserved fields + dstAtom->Generate(); + + // 0, 4, 6 are now generated from defaults + // leaving 1, 2, 3, 5, 7, 8, 9, 10 to export + + dstProperty=dstAtom->GetProperty(1); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[1])->GetValue()); + + dstProperty=dstAtom->GetProperty(2); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[2])->GetValue()); + + dstProperty=dstAtom->GetProperty(3); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[3])->GetValue()); + + dstProperty=dstAtom->GetProperty(5); + ((MP4BitfieldProperty *)dstProperty)->SetValue( + ((MP4BitfieldProperty *)m_pProperties[5])->GetValue()); + + // + // 7 and 8 are related SPS (one set of sequence parameters) + // + // first the count bitfield + // + dstProperty=dstAtom->GetProperty(7); + dstProperty->SetReadOnly(false); + ((MP4BitfieldProperty *)dstProperty)->SetValue( + ((MP4BitfieldProperty *)m_pProperties[7])->GetValue()); + dstProperty->SetReadOnly(true); + + // next export SPS Length and NAL bytes */ + + // first source pointers + pTable = (MP4TableProperty *) m_pProperties[8]; + spPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + spPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // now dest pointers + dstProperty=dstAtom->GetProperty(8); + pTable = (MP4TableProperty *) dstProperty; + dpPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + dpPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // sps length + i16 = spPI16->GetValue(); + i64 = i16; + // FIXME - this leaves m_maxNumElements =2 + // but src atom m_maxNumElements is 1 + dpPI16->InsertValue(i64, 0); + + // export byte array + i32 = i16; + // copy bytes to local buffer + tmp = (uint8_t *)MP4Malloc(i32); + ASSERT(tmp != NULL); + spPB->CopyValue(tmp, 0); + // set element count + dpPB->SetCount(1); + // copy bytes + dpPB->SetValue(tmp, i32, 0); + MP4Free((void *)tmp); + + // + // 9 and 10 are related PPS (one set of picture parameters) + // + // first the integer8 count + // + dstProperty=dstAtom->GetProperty(9); + dstProperty->SetReadOnly(false); + ((MP4Integer8Property *)dstProperty)->SetValue( + ((MP4Integer8Property *)m_pProperties[9])->GetValue()); + dstProperty->SetReadOnly(true); + + // next export PPS Length and NAL bytes */ + + // first source pointers + pTable = (MP4TableProperty *) m_pProperties[10]; + spPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + spPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // now dest pointers + dstProperty=dstAtom->GetProperty(10); + pTable = (MP4TableProperty *) dstProperty; + dpPI16 = (MP4Integer16Property *)pTable->GetProperty(0); + dpPB = (MP4BytesProperty *)pTable->GetProperty(1); + + // pps length + i16 = spPI16->GetValue(); + i64 = i16; + dpPI16->InsertValue(i64, 0); + + // export byte array + i32 = i16; + // copy bytes to local buffer + tmp = (uint8_t *)MP4Malloc(i32); + ASSERT(tmp != NULL); + spPB->CopyValue(tmp, 0); + // set element count + dpPB->SetCount(1); + // copy bytes + dpPB->SetValue(tmp, i32, 0); + MP4Free((void *)tmp); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_chpl.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_chpl.cpp new file mode 100644 index 00000000..d4eea2b7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_chpl.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +// MP4ChplAtom is for Nero chapter list atom which is a child of udta +MP4ChplAtom::MP4ChplAtom (MP4File &file) + : MP4Atom(file, "chpl") +{ + // it is not completely clear if version, flags, reserved and chaptercount + // have the right sizes but + // one thing is clear: chaptercount is not only 8-bit it is at least 16-bit + + // add the version + AddVersionAndFlags(); + + // add reserved bytes + AddReserved(*this,"reserved", 1); + + // define the chaptercount + MP4Integer32Property * counter = new MP4Integer32Property(*this,"chaptercount"); + AddProperty(counter); + + // define the chapterlist + MP4TableProperty * list = new MP4TableProperty(*this,"chapters", counter); + + // the start time as 100 nanoseconds units + list->AddProperty(new MP4Integer64Property(*this,"starttime")); + + // the chapter name as UTF-8 + list->AddProperty(new MP4StringProperty(*this,"title", true)); + + // add the chapterslist + AddProperty(list); +} + +void MP4ChplAtom::Generate () +{ + SetVersion(1); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_colr.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_colr.cpp new file mode 100644 index 00000000..965173ea --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_colr.cpp @@ -0,0 +1,55 @@ +/* + * 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. + * + * Contributer has declined to give copyright information, and gives + * it freely to the world. + * + * Contributor(s): + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4ColrAtom::MP4ColrAtom(MP4File &file) + : MP4Atom(file, "colr") +{ + MP4StringProperty* cpt = new MP4StringProperty(*this,"colorParameterType"); + cpt->SetFixedLength(4); + AddProperty(cpt); /* 0 */ + + AddProperty( /* 1 */ new MP4Integer16Property(*this,"primariesIndex")); + + AddProperty( /* 2 */ new MP4Integer16Property(*this,"transferFunctionIndex")); + + AddProperty( /* 3 */ new MP4Integer16Property(*this,"matrixIndex")); +} + +void MP4ColrAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4StringProperty*)m_pProperties[0])->SetValue("nclc"); + // default to ITU BT.709 values + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[3])->SetValue(1); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_d263.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_d263.cpp new file mode 100644 index 00000000..66e78edf --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_d263.cpp @@ -0,0 +1,98 @@ +/* + * 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. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +#define H263_VENDOR 0x6d346970 + +MP4D263Atom::MP4D263Atom(MP4File &file) + : MP4Atom(file, "d263") +{ + AddProperty( /* 0 */ + new MP4Integer32Property(*this, "vendor")); + + AddProperty( /* 1 */ + new MP4Integer8Property(*this, "decoderVersion")); + + AddProperty( /* 2 */ + new MP4Integer8Property(*this, "h263Level")); + + AddProperty( /* 3 */ + new MP4Integer8Property(*this, "h263Profile")); + + ExpectChildAtom("bitr", Optional, OnlyOne); + +} + +void MP4D263Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer32Property*)m_pProperties[0])->SetValue(H263_VENDOR); + ((MP4Integer8Property*)m_pProperties[1])->SetValue(1); + +} + +void MP4D263Atom::Write() +{ + // Check whether we have valid values in the bitr atom + // (if it exists, of course) + MP4Atom* bitrAtom = FindAtom("d263.bitr"); + if (bitrAtom) { + uint32_t avgBitrate; + uint32_t maxBitrate; + + MP4Integer32Property* pProp; + bitrAtom->FindProperty("bitr.avgBitrate", + (MP4Property**)&pProp, + NULL); + ASSERT(pProp); + avgBitrate = pProp->GetValue(); + + bitrAtom->FindProperty("bitr.maxBitrate", + (MP4Property**)&pProp, + NULL); + ASSERT(pProp); + maxBitrate = pProp->GetValue(); + + if (!maxBitrate && !avgBitrate) { + DeleteChildAtom(bitrAtom); + } + } + + MP4Atom::Write(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_dac3.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_dac3.cpp new file mode 100644 index 00000000..32f7e62f --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_dac3.cpp @@ -0,0 +1,245 @@ +/* + * 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. + * + * See ETSI TS 102 366 V1.2.1 Annex F for how to put Ac3 in MP4. + * + * Contributor(s): + * Edward Groenendaal [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + + +MP4DAc3Atom::MP4DAc3Atom(MP4File &file) + : MP4Atom(file, "dac3") +{ + AddProperty( new MP4BitfieldProperty(*this, "fscod", 2)); /* 0 */ + AddProperty( new MP4BitfieldProperty(*this, "bsid", 5)); /* 1 */ + AddProperty( new MP4BitfieldProperty(*this, "bsmod", 3)); /* 2 */ + AddProperty( new MP4BitfieldProperty(*this, "acmod", 3)); /* 3 */ + AddProperty( new MP4BitfieldProperty(*this, "lfeon", 1)); /* 4 */ + AddProperty( new MP4BitfieldProperty(*this, "bit_rate_code", 5)); /* 5 */ + AddProperty( new MP4BitfieldProperty(*this, "reserved", 5)); /* 6 */ + m_pProperties[6]->SetReadOnly(true); +} + +void MP4DAc3Atom::Generate() +{ + MP4Atom::Generate(); + + +} + +/* + * Normalling the Dump of the atom looks like the following, we want to spruce + * this up a bit to give more information. + * + * type = dac3 + * fscod = 0 (0x0) <2 bits> + * bsid = 8 (0x08) <5 bits> + * bsmod = 0 (0x0) <3 bits> + * acmod = 7 (0x7) <3 bits> + * lfeon = 1 (0x1) <1 bits> + * bit_rate_code = 15 (0x0f) <5 bits> + * reserved = 0 (0x00) <5 bits> + * + * into: + * type = dac3 + * fscod = 0 (0x0) <2 bits> [48 kHz] + * bsid = 8 (0x08) <5 bits> + * bsmod = 0 (0x0) <3 bits> [Main audio service: complete main (CM)] + * acmod = 7 (0x7) <3 bits> [3/2 (L, C, R, SL, SR)] + * lfeon = 1 (0x1) <1 bits> [ENABLED] + * bit_rate_code = 15 (0x0f) <5 bits> [448 kbit/s] + * reserved = 0 (0x00) <5 bits> + * + */ +void MP4DAc3Atom::Dump(uint8_t indent, bool dumpImplicits) +{ + + MP4BitfieldProperty* fscodProp = ((MP4BitfieldProperty*)m_pProperties[0]); + MP4BitfieldProperty* bsidProp = ((MP4BitfieldProperty*)m_pProperties[1]); + MP4BitfieldProperty* bsmodProp = ((MP4BitfieldProperty*)m_pProperties[2]); + MP4BitfieldProperty* acmodProp = ((MP4BitfieldProperty*)m_pProperties[3]); + MP4BitfieldProperty* lfeonProp = ((MP4BitfieldProperty*)m_pProperties[4]); + MP4BitfieldProperty* brcProp = ((MP4BitfieldProperty*)m_pProperties[5]); + MP4BitfieldProperty* resProp = ((MP4BitfieldProperty*)m_pProperties[6]); + + log.dump(indent++, MP4_LOG_VERBOSE2, "\"%s\": type = dac3", + GetFile().GetFilename().c_str() ); + + if (fscodProp) { + uint64_t fscod = 0xFF; + const char* fscodString; + const char* fscods[] = { + "48", "44.1", "32", "Reserved", + }; + + fscod = fscodProp->GetValue(); + + if (fscod < (sizeof(fscods) / sizeof(fscods[0]))) { + fscodString = fscods[fscod]; + } else { + fscodString = "Invalid value"; + } + + uint8_t hexWidth = fscodProp->GetNumBits() / 4; + if (hexWidth == 0 || (fscodProp->GetNumBits() % 4)) { + hexWidth++; + } + + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": fscod = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s kHz]", + GetFile().GetFilename().c_str(), + fscod, (int)hexWidth, fscod, fscodProp->GetNumBits(), fscodString); + } + if (bsidProp) bsidProp->Dump(indent, dumpImplicits); + + if (bsmodProp) { + uint64_t bsmod = 0xFF; + const char* bsmodString; + const char* bsmods[] = { + "Main audio service: complete main (CM)", + "Main audio srrvice: music and effects (ME)", + "Associated service: visually impaired (VI)", + "Associated service: hearing impaired (HI)", + "Associated service: dialogue (D)", + "Associated service: commentary (C)", + "Associated service: emergency (E)", + "Associated service: voice over (VO) or Main audio service: karaoke", + }; + + bsmod = bsmodProp->GetValue(); + + if (bsmod < (sizeof(bsmods) / sizeof(bsmods[0]))) { + bsmodString = bsmods[bsmod]; + } else { + bsmodString = "Invalid value"; + } + + uint8_t hexWidth = bsmodProp->GetNumBits() / 4; + if (hexWidth == 0 || (bsmodProp->GetNumBits() % 4)) { + hexWidth++; + } + + log.dump(indent, MP4_LOG_VERBOSE2, + "\"%s\": bsmod = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s]", + GetFile().GetFilename().c_str(), + bsmod, (int)hexWidth, bsmod, bsmodProp->GetNumBits(), bsmodString); + } + + if (acmodProp) { + uint64_t acmod = 0xFF; + const char* acmodString; + + const char* acmods[] = { + "1 + 1 (Ch1, Ch2)", + "1/0 (C)", + "2/0 (L, R)", + "3/0 (L, C, R)", + "2/1 (L, R, S)", + "3/1 (L, C, R, S)", + "2/2 (L, R, SL, SR)", + "3/2 (L, C, R, SL, SR)", + }; + + acmod = acmodProp->GetValue(); + + if (acmod < (sizeof(acmods) / sizeof(acmods[0]))) { + acmodString = acmods[acmod]; + } else { + acmodString = "Invalid value"; + } + + uint8_t hexWidth = acmodProp->GetNumBits() / 4; + if (hexWidth == 0 || (acmodProp->GetNumBits() % 4)) { + hexWidth++; + } + + log.dump(indent, MP4_LOG_VERBOSE2, + "\"%s\": acmod = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s]", + GetFile().GetFilename().c_str(), + acmod, (int)hexWidth, acmod, acmodProp->GetNumBits(), acmodString); + } + + if (lfeonProp) { + uint64_t lfeon = lfeonProp->GetValue(); + uint8_t hexWidth = lfeonProp->GetNumBits() / 4; + + if (hexWidth == 0 || (lfeonProp->GetNumBits() % 4)) { + hexWidth++; + } + + log.dump(indent, MP4_LOG_VERBOSE2, + "\"%s\": lfeon = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%s]", + GetFile().GetFilename().c_str(), lfeon, (int)hexWidth, lfeon, + lfeonProp->GetNumBits(), lfeon ? "ENABLED" : "DISABLED"); + } + + if (brcProp) { + uint32_t bit_rate_codes[] = { + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 384, + 448, + 512, + 576, + 640, + }; + uint64_t bit_rate_code = brcProp->GetValue(); + uint32_t bit_rate; + + if (bit_rate_code < (sizeof(bit_rate_codes) / sizeof(bit_rate_codes[0]))) { + bit_rate = bit_rate_codes[bit_rate_code]; + } else { + bit_rate = 0; + } + + uint8_t hexWidth = brcProp->GetNumBits() / 4; + if (hexWidth == 0 || (brcProp->GetNumBits() % 4)) { + hexWidth++; + } + + log.dump(indent, MP4_LOG_VERBOSE2, + "\"%s\": bit_rate_code = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits> [%" PRIu32 " kbit/s]", + GetFile().GetFilename().c_str(), + bit_rate_code, (int)hexWidth, bit_rate_code, + brcProp->GetNumBits(), bit_rate); + } + if (resProp) resProp->Dump(indent, dumpImplicits); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_damr.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_damr.cpp new file mode 100644 index 00000000..16177823 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_damr.cpp @@ -0,0 +1,69 @@ +/* + * 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. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +#define AMR_VENDOR 0x6d346970 + +MP4DamrAtom::MP4DamrAtom(MP4File &file) + : MP4Atom(file, "damr") +{ + AddProperty( /* 0 */ + new MP4Integer32Property(*this, "vendor")); + + AddProperty( /* 1 */ + new MP4Integer8Property(*this, "decoderVersion")); + + AddProperty( /* 2 */ + new MP4Integer16Property(*this, "modeSet")); + + AddProperty( /* 3 */ + new MP4Integer8Property(*this, "modeChangePeriod")); + + AddProperty( /* 4 */ + new MP4Integer8Property(*this, "framesPerSample")); + +} + +void MP4DamrAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer32Property*)m_pProperties[0])->SetValue(AMR_VENDOR); + ((MP4Integer8Property*)m_pProperties[1])->SetValue(1); + +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_dref.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_dref.cpp new file mode 100644 index 00000000..b174c7a4 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_dref.cpp @@ -0,0 +1,67 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4DrefAtom::MP4DrefAtom(MP4File &file) + : MP4Atom(file, "dref") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + pCount->SetReadOnly(); + AddProperty(pCount); + + ExpectChildAtom("url ", Optional, Many); + ExpectChildAtom("urn ", Optional, Many); + ExpectChildAtom("alis", Optional, Many); +} + +void MP4DrefAtom::Read() +{ + /* do the usual read */ + MP4Atom::Read(); + + // check that number of children == entryCount + MP4Integer32Property* pCount = + (MP4Integer32Property*)m_pProperties[2]; + + if (m_pChildAtoms.Size() != pCount->GetValue()) { + log.warningf("%s: \"%s\": dref inconsistency with number of entries", + __FUNCTION__, GetFile().GetFilename().c_str() ); + + /* fix it */ + pCount->SetReadOnly(false); + pCount->SetValue(m_pChildAtoms.Size()); + pCount->SetReadOnly(true); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_elst.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_elst.cpp new file mode 100644 index 00000000..cadc1072 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_elst.cpp @@ -0,0 +1,89 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4ElstAtom::MP4ElstAtom(MP4File &file) + : MP4Atom(file, "elst") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); +} + +void MP4ElstAtom::AddProperties(uint8_t version) +{ + MP4TableProperty* pTable = (MP4TableProperty*)m_pProperties[3]; + + if (version == 1) { + pTable->AddProperty( + new MP4Integer64Property(pTable->GetParentAtom(), "segmentDuration")); + pTable->AddProperty( + new MP4Integer64Property(pTable->GetParentAtom(), "mediaTime")); + } else { + pTable->AddProperty( + new MP4Integer32Property(pTable->GetParentAtom(), "segmentDuration")); + pTable->AddProperty( + new MP4Integer32Property(pTable->GetParentAtom(), "mediaTime")); + } + + pTable->AddProperty( + new MP4Integer16Property(pTable->GetParentAtom(), "mediaRate")); + pTable->AddProperty( + new MP4Integer16Property(pTable->GetParentAtom(), "reserved")); +} + +void MP4ElstAtom::Generate() +{ + SetVersion(0); + AddProperties(GetVersion()); + + MP4Atom::Generate(); +} + +void MP4ElstAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_enca.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_enca.cpp new file mode 100644 index 00000000..700fa574 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_enca.cpp @@ -0,0 +1,71 @@ +/* + * 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 [email protected] + * Alix Marchandise-Franquet [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4EncaAtom::MP4EncaAtom(MP4File &file) + : MP4Atom(file, "enca") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "timeScale")); + + AddReserved(*this, "reserved3", 2); /* 4 */ + + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("sinf", Required, OnlyOne); +} + +void MP4EncaAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static uint8_t reserved2[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[2]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[2])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[2]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_encv.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_encv.cpp new file mode 100644 index 00000000..ce97ece7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_encv.cpp @@ -0,0 +1,91 @@ +/* + * 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 [email protected] + * Alix Marchandise-Franquet [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4EncvAtom::MP4EncvAtom(MP4File &file) + : MP4Atom(file, "encv") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "width")); + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "height")); + + AddReserved(*this, "reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty(*this, "compressorName"); + pProp->SetFixedLength(32); + pProp->SetCountedFormat(true); + pProp->SetValue(""); + AddProperty(pProp); /* 6 */ + AddReserved(*this, "reserved4", 4); /* 7 */ + + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("sinf", Required, OnlyOne); + ExpectChildAtom("avcC", Optional, OnlyOne); +} + +void MP4EncvAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static uint8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static uint8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_free.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_free.cpp new file mode 100644 index 00000000..5450e046 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_free.cpp @@ -0,0 +1,56 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4FreeAtom::MP4FreeAtom( MP4File &file, const char* type ) + : MP4Atom( file, type ? type : "free" ) +{ +} + +void MP4FreeAtom::Read() +{ + Skip(); +} + +void MP4FreeAtom::Write() +{ + bool use64 = (GetSize() > (0xFFFFFFFF - 8)); + BeginWrite(use64); +#if 1 + for (uint64_t ix = 0; ix < GetSize(); ix++) { + m_File.WriteUInt8(0); + } +#else + m_File.SetPosition(m_File.GetPosition() + GetSize()); +#endif + FinishWrite(use64); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ftab.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ftab.cpp new file mode 100644 index 00000000..1a1ea057 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ftab.cpp @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4FtabAtom::MP4FtabAtom(MP4File &file) + : MP4Atom(file, "ftab") +{ + MP4Integer16Property* pCount = new MP4Integer16Property(*this, "entryCount"); /* 0 */ + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "fontEntries", pCount); /* 1 */ + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer16Property(pTable->GetParentAtom(), "fontID")); /* 0 */ + pTable->AddProperty(new MP4StringProperty(pTable->GetParentAtom(), "name", true)); /* 1 */ +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ftyp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ftyp.cpp new file mode 100644 index 00000000..92b47d60 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ftyp.cpp @@ -0,0 +1,62 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4FtypAtom::MP4FtypAtom(MP4File &file) + : MP4Atom( file, "ftyp" ) + , majorBrand ( *new MP4StringProperty( *this, "majorBrand" )) + , minorVersion ( *new MP4Integer32Property( *this, "minorVersion" )) + , compatibleBrands ( *new MP4StringProperty( *this, "compatibleBrands", false, false, true )) +{ + majorBrand.SetFixedLength( 4 ); + compatibleBrands.SetFixedLength( 4 ); + + AddProperty( &majorBrand ); + AddProperty( &minorVersion ); + AddProperty( &compatibleBrands ); +} + +void MP4FtypAtom::Generate() +{ + MP4Atom::Generate(); + + majorBrand.SetValue( "mp42" ); + minorVersion.SetValue( 0 ); + + compatibleBrands.SetCount( 2 ); + compatibleBrands.SetValue( "mp42", 0 ); + compatibleBrands.SetValue( "isom", 1 ); +} + +void MP4FtypAtom::Read() +{ + compatibleBrands.SetCount( (m_size - 8) / 4 ); // brands array fills rest of atom + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_gmin.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_gmin.cpp new file mode 100644 index 00000000..cb94a1e6 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_gmin.cpp @@ -0,0 +1,58 @@ +/* + * 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. + * + * Contributer has declined to give copyright information, and gives + * it freely to the world. + * + * Contributor(s): + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4GminAtom::MP4GminAtom(MP4File &file) + : MP4Atom(file, "gmin") +{ + + AddVersionAndFlags(); /* 0, 1 */ + + AddProperty(new MP4Integer16Property(*this, "graphicsMode")); /* 2 */ + AddProperty(new MP4Integer16Property(*this, "opColorRed")); /* 3 */ + AddProperty(new MP4Integer16Property(*this, "opColorGreen")); /* 4 */ + AddProperty(new MP4Integer16Property(*this, "opColorBlue")); /* 5 */ + AddProperty(new MP4Integer16Property(*this, "balance")); /* 6 */ + AddReserved(*this, "reserved", 2); /* 7 */ + +} + +void MP4GminAtom::Generate() +{ + + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[2])->SetValue(0x0040); + ((MP4Integer16Property*)m_pProperties[3])->SetValue(0x8000); + ((MP4Integer16Property*)m_pProperties[4])->SetValue(0x8000); + ((MP4Integer16Property*)m_pProperties[5])->SetValue(0x8000); + ((MP4Integer16Property*)m_pProperties[6])->SetValue(0x0000); + +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hdlr.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hdlr.cpp new file mode 100644 index 00000000..db33e7e5 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hdlr.cpp @@ -0,0 +1,95 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4HdlrAtom::MP4HdlrAtom(MP4File &file) + : MP4Atom(file, "hdlr") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddReserved(*this, "reserved1", 4); /* 2 */ + MP4StringProperty* pProp = new MP4StringProperty(*this, "handlerType"); + pProp->SetFixedLength(4); + AddProperty(pProp); /* 3 */ + AddReserved(*this, "reserved2", 12); /* 4 */ + AddProperty( /* 5 */ + new MP4StringProperty(*this, "name")); +} + +// There is a spec incompatiblity between QT and MP4 +// QT says name field is a counted string +// MP4 says name field is a null terminated string +// Here we attempt to make all things work +void MP4HdlrAtom::Read() +{ + // read all the properties but the "name" field + ReadProperties(0, 5); + + uint64_t pos = m_File.GetPosition(); + uint64_t end = GetEnd(); + if (pos == end) { + // A hdlr atom with missing "name". + // Apparently that's what some of the iTunes m4p files have. + return; + } + + // take a peek at the next byte + uint8_t strLength; + m_File.PeekBytes(&strLength, 1); + // if the value matches the remaining atom length + if (pos + strLength + 1 == end) { + // read a counted string + MP4StringProperty* pNameProp = + (MP4StringProperty*)m_pProperties[5]; + pNameProp->SetCountedFormat(true); + ReadProperties(5); + pNameProp->SetCountedFormat(false); + } else { + // read a null terminated string + try { + // Unfortunately, there are some invalid mp4 writers that don't + // null the hdlr name string. Generally this will be "automatically" + // terminated for them by the size field of the subsequent atom. So if + // our size is off by one...let it slide. otherwise, rethrow. + // The Skip() call will set our start to the correct location + // for the next Atom. See issue #52 + ReadProperties(5); + } + catch(Exception* x) { + if( m_File.GetPosition() - GetEnd() == 1 ) + delete x; + else + throw x; + } + } + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hinf.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hinf.cpp new file mode 100644 index 00000000..5f6f8d70 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hinf.cpp @@ -0,0 +1,64 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4HinfAtom::MP4HinfAtom(MP4File &file) + : MP4Atom(file, "hinf") +{ + ExpectChildAtom("trpy", Optional, OnlyOne); + ExpectChildAtom("nump", Optional, OnlyOne); + ExpectChildAtom("tpyl", Optional, OnlyOne); + ExpectChildAtom("maxr", Optional, Many); + ExpectChildAtom("dmed", Optional, OnlyOne); + ExpectChildAtom("dimm", Optional, OnlyOne); + ExpectChildAtom("drep", Optional, OnlyOne); + ExpectChildAtom("tmin", Optional, OnlyOne); + ExpectChildAtom("tmax", Optional, OnlyOne); + ExpectChildAtom("pmax", Optional, OnlyOne); + ExpectChildAtom("dmax", Optional, OnlyOne); + ExpectChildAtom("payt", Optional, OnlyOne); +} + +void MP4HinfAtom::Generate() +{ + // hinf is special in that although all it's child atoms + // are optional (on read), if we generate it for writing + // we really want all the children + + for (uint32_t i = 0; i < m_pChildAtomInfos.Size(); i++) { + MP4Atom* pChildAtom = + CreateAtom(m_File, this, m_pChildAtomInfos[i]->m_name); + + AddChildAtom(pChildAtom); + + // and ask it to self generate + pChildAtom->Generate(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hnti.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hnti.cpp new file mode 100644 index 00000000..9f2cac1f --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_hnti.cpp @@ -0,0 +1,50 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4HntiAtom::MP4HntiAtom(MP4File &file) + : MP4Atom(file, "hnti") +{ +} + +void MP4HntiAtom::Read() +{ + MP4Atom* grandParent = m_pParentAtom->GetParentAtom(); + ASSERT(grandParent); + if (ATOMID(grandParent->GetType()) == ATOMID("trak")) { + ExpectChildAtom("sdp ", Optional, OnlyOne); + } else { + ExpectChildAtom("rtp ", Optional, OnlyOne); + } + + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_href.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_href.cpp new file mode 100644 index 00000000..a15fe790 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_href.cpp @@ -0,0 +1,50 @@ +/* + * 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. 2005. All Rights Reserved. + * + * Contributor(s): + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4HrefAtom::MP4HrefAtom(MP4File &file) + : MP4Atom(file, "href") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + ExpectChildAtom("burl", Optional, OnlyOne); +} + +void MP4HrefAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mdat.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mdat.cpp new file mode 100644 index 00000000..fe50cb90 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mdat.cpp @@ -0,0 +1,48 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4MdatAtom::MP4MdatAtom(MP4File &file) + : MP4Atom(file, "mdat") +{ +} + +void MP4MdatAtom::Read() +{ + Skip(); +} + +void MP4MdatAtom::Write() +{ + // should never get here + ASSERT(false); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mdhd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mdhd.cpp new file mode 100644 index 00000000..28f28887 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mdhd.cpp @@ -0,0 +1,98 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4MdhdAtom::MP4MdhdAtom(MP4File &file) + : MP4Atom(file, "mdhd") +{ + AddVersionAndFlags(); +} + +void MP4MdhdAtom::AddProperties(uint8_t version) +{ + if (version == 1) { + AddProperty( + new MP4Integer64Property(*this, "creationTime")); + AddProperty( + new MP4Integer64Property(*this, "modificationTime")); + } else { + AddProperty( + new MP4Integer32Property(*this, "creationTime")); + AddProperty( + new MP4Integer32Property(*this, "modificationTime")); + } + + AddProperty( + new MP4Integer32Property(*this, "timeScale")); + + if (version == 1) { + AddProperty( + new MP4Integer64Property(*this, "duration")); + } else { + AddProperty( + new MP4Integer32Property(*this, "duration")); + } + + AddProperty( new MP4LanguageCodeProperty(*this, "language" )); + AddReserved(*this, "reserved", 2); +} + +void MP4MdhdAtom::Generate() +{ + uint8_t version = m_File.Use64Bits(GetType()) ? 1 : 0; + SetVersion(version); + AddProperties(version); + + MP4Atom::Generate(); + + // set creation and modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + if (version == 1) { + ((MP4Integer64Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer64Property*)m_pProperties[3])->SetValue(now); + } else { + ((MP4Integer32Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(now); + } +} + +void MP4MdhdAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_meta.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_meta.cpp new file mode 100644 index 00000000..9e6f1a68 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_meta.cpp @@ -0,0 +1,153 @@ +/* + * 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): + * M. Bakker mbakker at nero.com + * + * Apple iTunes META data + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4DataAtom::MP4DataAtom(MP4File &file) + : MP4Atom ( file, "data" ) + , typeReserved ( *new MP4Integer16Property( *this, "typeReserved" )) + , typeSetIdentifier ( *new MP4Integer8Property( *this, "typeSetIdentifier" )) + , typeCode ( *new MP4BasicTypeProperty( *this, "typeCode" )) + , locale ( *new MP4Integer32Property( *this, "locale" )) + , metadata ( *new MP4BytesProperty( *this, "metadata" )) +{ + AddProperty( &typeReserved ); + AddProperty( &typeSetIdentifier ); + AddProperty( &typeCode ); + AddProperty( &locale ); + AddProperty( &metadata ); +} + +void +MP4DataAtom::Read() +{ + // calculate size of the metadata from the atom size + metadata.SetValueSize( m_size - 8 ); + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4FullAtom::MP4FullAtom( MP4File &file, const char* type ) + : MP4Atom ( file, type ) + , version ( *new MP4Integer8Property( *this, "version" )) + , flags ( *new MP4Integer24Property( *this, "flags" )) +{ + AddProperty( &version ); + AddProperty( &flags ); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItemAtom::MP4ItemAtom( MP4File &file, const char* type ) + : MP4Atom( file, type ) +{ + ExpectChildAtom( "mean", Optional, OnlyOne ); + ExpectChildAtom( "name", Optional, OnlyOne ); + ExpectChildAtom( "data", Required, Many ); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfHdlrAtom::MP4ItmfHdlrAtom(MP4File &file) + : MP4FullAtom ( file, "hdlr" ) + , reserved1 ( *new MP4Integer32Property( *this, "reserved1" )) + , handlerType ( *new MP4BytesProperty( *this, "handlerType", 4 )) + , reserved2 ( *new MP4BytesProperty( *this, "reserved2", 12 )) + , name ( *new MP4BytesProperty( *this, "name", 1 )) +{ + AddProperty( &reserved1 ); + AddProperty( &handlerType ); + AddProperty( &reserved2 ); + AddProperty( &name ); + + const uint8_t htData[] = { 'm', 'd', 'i', 'r' }; + handlerType.SetValue( htData, sizeof( htData )); + + const uint8_t nameData[] = { 0 }; + name.SetValue( nameData, sizeof( nameData )); +} + +void +MP4ItmfHdlrAtom::Read() +{ + name.SetValueSize( m_size - 24 ); + MP4FullAtom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4MeanAtom::MP4MeanAtom(MP4File &file) + : MP4FullAtom ( file, "mean" ) + , value ( *new MP4BytesProperty( *this, "value" )) +{ + AddProperty( &value ); +} + +void +MP4MeanAtom::Read() +{ + value.SetValueSize( m_size - 4 ); + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4NameAtom::MP4NameAtom(MP4File &file) + : MP4FullAtom ( file, "name" ) + , value ( *new MP4BytesProperty( *this, "value" )) +{ + AddProperty( &value ); +} + +void +MP4NameAtom::Read() +{ + value.SetValueSize( m_size - 4 ); + MP4FullAtom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4UdtaElementAtom::MP4UdtaElementAtom( MP4File &file, const char* type ) + : MP4Atom ( file, type ) + , value ( *new MP4BytesProperty( *this, "value" )) +{ + AddProperty( &value ); +} + +void +MP4UdtaElementAtom::Read() +{ + // calculate size of the metadata from the atom size + value.SetValueSize( m_size ); + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mp4s.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mp4s.cpp new file mode 100644 index 00000000..293a5546 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mp4s.cpp @@ -0,0 +1,49 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Mp4sAtom::MP4Mp4sAtom(MP4File &file) + : MP4Atom(file, "mp4s") +{ + AddReserved(*this, "reserved1", 6); + AddProperty( + new MP4Integer16Property(*this, "dataReferenceIndex")); + + ExpectChildAtom("esds", Required, OnlyOne); +} + +void MP4Mp4sAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mp4v.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mp4v.cpp new file mode 100644 index 00000000..9cf64441 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mp4v.cpp @@ -0,0 +1,91 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Mp4vAtom::MP4Mp4vAtom(MP4File &file) + : MP4Atom(file, "mp4v") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "width")); + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "height")); + + AddReserved(*this, "reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty(*this, "compressorName"); + pProp->SetFixedLength(32); + pProp->SetCountedFormat(true); + pProp->SetValue(""); + AddProperty(pProp); /* 6 */ + + AddReserved(*this, "reserved4", 4); /* 7 */ + + ExpectChildAtom("colr", Optional, OnlyOne); + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("pasp", Optional, OnlyOne); +} + +void MP4Mp4vAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static uint8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static uint8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mvhd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mvhd.cpp new file mode 100644 index 00000000..f3863de2 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_mvhd.cpp @@ -0,0 +1,146 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4MvhdAtom::MP4MvhdAtom(MP4File &file) + : MP4Atom(file, "mvhd") +{ + AddVersionAndFlags(); +} + +void MP4MvhdAtom::AddProperties(uint8_t version) +{ + if (version == 1) { + AddProperty( /* 2 */ + new MP4Integer64Property(*this, "creationTime")); + AddProperty( /* 3 */ + new MP4Integer64Property(*this, "modificationTime")); + } else { + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "creationTime")); + AddProperty( /* 3 */ + new MP4Integer32Property(*this, "modificationTime")); + } + + AddProperty( /* 4 */ + new MP4Integer32Property(*this, "timeScale")); + + if (version == 1) { + AddProperty( /* 5 */ + new MP4Integer64Property(*this, "duration")); + } else { + AddProperty( /* 5 */ + new MP4Integer32Property(*this, "duration")); + } + + MP4Float32Property* pProp; + + pProp = new MP4Float32Property(*this, "rate"); + pProp->SetFixed32Format(); + AddProperty(pProp); /* 6 */ + + pProp = new MP4Float32Property(*this, "volume"); + pProp->SetFixed16Format(); + AddProperty(pProp); /* 7 */ + + AddReserved(*this, "reserved1", 70); /* 8 */ + + AddProperty( /* 9 */ + new MP4Integer32Property(*this, "nextTrackId")); +} + +void MP4MvhdAtom::Generate() +{ + uint8_t version = m_File.Use64Bits(GetType()) ? 1 : 0; + SetVersion(version); + AddProperties(version); + + MP4Atom::Generate(); + + // set creation and modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + if (version == 1) { + ((MP4Integer64Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer64Property*)m_pProperties[3])->SetValue(now); + } else { + ((MP4Integer32Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(now); + } + + ((MP4Integer32Property*)m_pProperties[4])->SetValue(1000); + + ((MP4Float32Property*)m_pProperties[6])->SetValue(1.0); + ((MP4Float32Property*)m_pProperties[7])->SetValue(1.0); + + // property reserved has non-zero fixed values + static uint8_t reserved[70] = { + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + m_pProperties[8]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[8])-> + SetValue(reserved, sizeof(reserved)); + m_pProperties[8]->SetReadOnly(true); + + // set next track id + ((MP4Integer32Property*)m_pProperties[9])->SetValue(1); +} + +void MP4MvhdAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_nmhd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_nmhd.cpp new file mode 100644 index 00000000..8e3a52d2 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_nmhd.cpp @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4NmhdAtom::MP4NmhdAtom(MP4File &file) + : MP4Atom(file, "nmhd") +{ + AddVersionAndFlags(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ohdr.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ohdr.cpp new file mode 100644 index 00000000..5652c16d --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_ohdr.cpp @@ -0,0 +1,106 @@ +/** \file atom_ohdr.cpp + + \author Danijel Kopcinovic ([email protected]) +*/ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +/*! \brief Patch class for read/write operations when string is 0-length. + + We want to use string property, but mpeg4ip doesn't support ohdr way of + encoding of string (in ohdr atom we first have 3 lengths of 3 strings and + then their string values, and it cannot be simulated with any of the + current mpeg4ip string property parameters), so we have to write our own + Read() and Write() routines. +*/ +class OhdrMP4StringProperty: public MP4StringProperty { +public: + /*! \brief Constructor. + + \param name name of the property. + \param useCountedFormat counted format flag. + \param useUnicode unicode flag. + */ + OhdrMP4StringProperty(MP4Atom& parentAtom, const char* name, bool useCountedFormat = false, + bool useUnicode = false): MP4StringProperty(parentAtom, name, useCountedFormat, + useUnicode) { + } + + /*! \brief Read property from file. + + \param pFile input, file handle. + \param index input, index to read. + */ + void Read(MP4File& file, uint32_t index = 0) { + MP4Free(m_values[index]); + m_values[index] = (char*)MP4Calloc(m_fixedLength + 1); + (void)file.ReadBytes((uint8_t*)m_values[index], m_fixedLength); + } + + /*! \brief Write property to file. + + \param pFile input, file handle. + \param index input, index to write. + */ + void Write(MP4File& file, uint32_t index = 0) { + file.WriteBytes((uint8_t*)m_values[index], m_fixedLength); + } +private: + OhdrMP4StringProperty(); + OhdrMP4StringProperty ( const OhdrMP4StringProperty &src ); + OhdrMP4StringProperty &operator= ( const OhdrMP4StringProperty &src ); +}; + +/*! \brief OMA DRM headers atom. + + Contained in OMA DRM key management atom. It must contain content identifier. +*/ +/*! \brief Constructor. +*/ +MP4OhdrAtom::MP4OhdrAtom(MP4File &file): MP4Atom(file, "ohdr") { + AddVersionAndFlags(); + + AddProperty(new MP4Integer8Property(*this, "EncryptionMethod")); + AddProperty(new MP4Integer8Property(*this, "EncryptionPadding")); + AddProperty(new MP4Integer64Property(*this, "PlaintextLength")); + AddProperty(new MP4Integer16Property(*this, "ContentIDLength")); + AddProperty(new MP4Integer16Property(*this, "RightsIssuerURLLength")); + AddProperty(new MP4Integer16Property(*this, "TextualHeadersLength")); + AddProperty(new OhdrMP4StringProperty(*this, "ContentID")); + AddProperty(new OhdrMP4StringProperty(*this, "RightsIssuerURL")); + AddProperty(new MP4BytesProperty(*this, "TextualHeaders")); +} + +MP4OhdrAtom::~MP4OhdrAtom() { +} + +/*! \brief Read atom. +*/ +void MP4OhdrAtom::Read() { + ReadProperties(0, 8); + MP4Property* lProperty; + MP4Property* property; + lProperty = GetProperty(5); + property = GetProperty(8); + ((OhdrMP4StringProperty*)property)->SetFixedLength( + ((MP4Integer16Property*)lProperty)->GetValue()); + lProperty = GetProperty(6); + property = GetProperty(9); + ((OhdrMP4StringProperty*)property)->SetFixedLength( + ((MP4Integer16Property*)lProperty)->GetValue()); + lProperty = GetProperty(7); + property = GetProperty(10); + ((MP4BytesProperty*)property)->SetFixedSize( + ((MP4Integer16Property*)lProperty)->GetValue()); + ReadProperties(8, 3); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_pasp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_pasp.cpp new file mode 100644 index 00000000..0ecebf27 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_pasp.cpp @@ -0,0 +1,52 @@ +/* + * 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. + * + * Contributer has declined to give copyright information, and gives + * it freely to the world. + * + * Contributor(s): + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4PaspAtom::MP4PaspAtom(MP4File &file) + : MP4Atom(file, "pasp") +{ + + AddProperty( /* 0 */ + new MP4Integer32Property(*this, "hSpacing")); + + AddProperty( /* 1 */ + new MP4Integer32Property(*this, "vSpacing")); + +} + +void MP4PaspAtom::Generate() +{ + + MP4Atom::Generate(); + + ((MP4Integer32Property*)m_pProperties[0])->SetValue(1); + ((MP4Integer32Property*)m_pProperties[1])->SetValue(1); + +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_root.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_root.cpp new file mode 100644 index 00000000..4702bb95 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_root.cpp @@ -0,0 +1,160 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4RootAtom::MP4RootAtom(MP4File &file) + : MP4Atom( file, NULL ) + , m_rewrite_ftyp ( NULL ) + , m_rewrite_ftypPosition ( 0 ) + , m_rewrite_free ( NULL ) + , m_rewrite_freePosition ( 0 ) +{ + ExpectChildAtom( "moov", Required, OnlyOne ); + ExpectChildAtom( "ftyp", Optional, OnlyOne ); + ExpectChildAtom( "mdat", Optional, Many ); + ExpectChildAtom( "free", Optional, Many ); + ExpectChildAtom( "skip", Optional, Many ); + ExpectChildAtom( "udta", Optional, Many ); + ExpectChildAtom( "moof", Optional, Many ); +} + +void MP4RootAtom::BeginWrite(bool use64) +{ + m_rewrite_ftyp = (MP4FtypAtom*)FindChildAtom( "ftyp" ); + if( m_rewrite_ftyp ) { + m_rewrite_free = (MP4FreeAtom*)MP4Atom::CreateAtom( m_File, NULL, "free" ); + m_rewrite_free->SetSize( 32*4 ); // room for 32 additional brands + AddChildAtom( m_rewrite_free ); + + m_rewrite_ftypPosition = m_File.GetPosition(); + m_rewrite_ftyp->Write(); + + m_rewrite_freePosition = m_File.GetPosition(); + m_rewrite_free->Write(); + } + + m_pChildAtoms[GetLastMdatIndex()]->BeginWrite( m_File.Use64Bits( "mdat" )); +} + +void MP4RootAtom::Write() +{ + // no-op +} + +void MP4RootAtom::FinishWrite(bool use64) +{ + if( m_rewrite_ftyp ) { + const uint64_t savepos = m_File.GetPosition(); + m_File.SetPosition( m_rewrite_ftypPosition ); + m_rewrite_ftyp->Write(); + + const uint64_t newpos = m_File.GetPosition(); + if( newpos > m_rewrite_freePosition ) + m_rewrite_free->SetSize( m_rewrite_free->GetSize() - (newpos - m_rewrite_freePosition) ); // shrink + else if( newpos < m_rewrite_freePosition ) + m_rewrite_free->SetSize( m_rewrite_free->GetSize() + (m_rewrite_freePosition - newpos) ); // grow + + m_rewrite_free->Write(); + m_File.SetPosition( savepos ); + } + + // finish writing last mdat atom + const uint32_t mdatIndex = GetLastMdatIndex(); + m_pChildAtoms[mdatIndex]->FinishWrite( m_File.Use64Bits( "mdat" )); + + // write all atoms after last mdat + const uint32_t size = m_pChildAtoms.Size(); + for ( uint32_t i = mdatIndex + 1; i < size; i++ ) + m_pChildAtoms[i]->Write(); +} + +void MP4RootAtom::BeginOptimalWrite() +{ + WriteAtomType("ftyp", OnlyOne); + WriteAtomType("moov", OnlyOne); + WriteAtomType("udta", Many); + + m_pChildAtoms[GetLastMdatIndex()]->BeginWrite(m_File.Use64Bits("mdat")); +} + +void MP4RootAtom::FinishOptimalWrite() +{ + // finish writing mdat + m_pChildAtoms[GetLastMdatIndex()]->FinishWrite(m_File.Use64Bits("mdat")); + + // find moov atom + uint32_t size = m_pChildAtoms.Size(); + MP4Atom* pMoovAtom = NULL; + + uint32_t i; + for (i = 0; i < size; i++) { + if (!strcmp("moov", m_pChildAtoms[i]->GetType())) { + pMoovAtom = m_pChildAtoms[i]; + break; + } + } + ASSERT(i < size); + ASSERT(pMoovAtom != NULL); + + // rewrite moov so that updated chunkOffsets are written to disk + m_File.SetPosition(pMoovAtom->GetStart()); + uint64_t oldSize = pMoovAtom->GetSize(); + + pMoovAtom->Write(); + + // sanity check + uint64_t newSize = pMoovAtom->GetSize(); + ASSERT(oldSize == newSize); +} + +uint32_t MP4RootAtom::GetLastMdatIndex() +{ + for (int32_t i = m_pChildAtoms.Size() - 1; i >= 0; i--) { + if (!strcmp("mdat", m_pChildAtoms[i]->GetType())) { + return i; + } + } + ASSERT(false); + return (uint32_t)-1; +} + +void MP4RootAtom::WriteAtomType(const char* type, bool onlyOne) +{ + uint32_t size = m_pChildAtoms.Size(); + + for (uint32_t i = 0; i < size; i++) { + if (!strcmp(type, m_pChildAtoms[i]->GetType())) { + m_pChildAtoms[i]->Write(); + if (onlyOne) { + break; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_rtp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_rtp.cpp new file mode 100644 index 00000000..af459edb --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_rtp.cpp @@ -0,0 +1,158 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4RtpAtom::MP4RtpAtom(MP4File &file) + : MP4Atom(file, "rtp ") +{ + // The atom type "rtp " is used in two complete unrelated ways + // i.e. it's real two atoms with the same name + // To handle that we need to postpone property creation until + // we know who our parent atom is (stsd or hnti) which gives us + // the context info we need to know who we are +} + +void MP4RtpAtom::AddPropertiesStsdType() +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddProperty( /* 2 */ + new MP4Integer16Property(*this, "hintTrackVersion")); + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "highestCompatibleVersion")); + AddProperty( /* 4 */ + new MP4Integer32Property(*this, "maxPacketSize")); + + ExpectChildAtom("tims", Required, OnlyOne); + ExpectChildAtom("tsro", Optional, OnlyOne); + ExpectChildAtom("snro", Optional, OnlyOne); +} + +void MP4RtpAtom::AddPropertiesHntiType() +{ + MP4StringProperty* pProp = + new MP4StringProperty(*this, "descriptionFormat"); + pProp->SetFixedLength(4); + AddProperty(pProp); /* 0 */ + + AddProperty( /* 1 */ + new MP4StringProperty(*this, "sdpText")); +} + +void MP4RtpAtom::Generate() +{ + ASSERT(m_pParentAtom); + if (!strcmp(m_pParentAtom->GetType(), "stsd")) { + AddPropertiesStsdType(); + GenerateStsdType(); + } else if (!strcmp(m_pParentAtom->GetType(), "hnti")) { + AddPropertiesHntiType(); + GenerateHntiType(); + } else { + log.warningf("%s: \"%s\": rtp atom in unexpected context, can not generate", + __FUNCTION__, GetFile().GetFilename().c_str() ); + } +} + +void MP4RtpAtom::GenerateStsdType() +{ + // generate children + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[3])->SetValue(1); +} + +void MP4RtpAtom::GenerateHntiType() +{ + MP4Atom::Generate(); + + ((MP4StringProperty*)m_pProperties[0])->SetValue("sdp "); +} + +void MP4RtpAtom::Read() +{ + ASSERT(m_pParentAtom); + if (!strcmp(m_pParentAtom->GetType(), "stsd")) { + AddPropertiesStsdType(); + ReadStsdType(); + } else if (!strcmp(m_pParentAtom->GetType(), "hnti")) { + AddPropertiesHntiType(); + ReadHntiType(); + } else { + log.verbose1f("rtp atom in unexpected context, can not read"); + } + + Skip(); // to end of atom +} + +void MP4RtpAtom::ReadStsdType() +{ + MP4Atom::Read(); +} + +void MP4RtpAtom::ReadHntiType() +{ + ReadProperties(0, 1); + + // read sdp string, length is implicit in size of atom + uint64_t size = GetEnd() - m_File.GetPosition(); + char* data = (char*)MP4Malloc(size + 1); + ASSERT(data != NULL); + m_File.ReadBytes((uint8_t*)data, size); + data[size] = '\0'; + ((MP4StringProperty*)m_pProperties[1])->SetValue(data); + MP4Free(data); +} + +void MP4RtpAtom::Write() +{ + if (!strcmp(m_pParentAtom->GetType(), "hnti")) { + WriteHntiType(); + } else { + MP4Atom::Write(); + } +} + +void MP4RtpAtom::WriteHntiType() +{ + // since length of string is implicit in size of atom + // we need to handle this specially, and not write the terminating \0 + MP4StringProperty* pSdp = (MP4StringProperty*)m_pProperties[1]; + pSdp->SetFixedLength((uint32_t)strlen(pSdp->GetValue())); + MP4Atom::Write(); + pSdp->SetFixedLength(0); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_s263.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_s263.cpp new file mode 100644 index 00000000..c53e00a8 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_s263.cpp @@ -0,0 +1,88 @@ +/* + * 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. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4S263Atom::MP4S263Atom(MP4File &file) + : MP4Atom(file, "s263") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "width")); + + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "height")); + + AddReserved(*this, "reserved3", 50); /* 5 */ + + + ExpectChildAtom("d263", Required, OnlyOne); +} + +void MP4S263Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved2 has non-zero fixed values + static uint8_t reserved3[50] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, + 0xFF, 0xFF + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sdp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sdp.cpp new file mode 100644 index 00000000..386a0a13 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sdp.cpp @@ -0,0 +1,63 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4SdpAtom::MP4SdpAtom(MP4File &file) : MP4Atom(file, "sdp ") +{ + AddProperty( + new MP4StringProperty(*this, "sdpText")); +} + +void MP4SdpAtom::Read() +{ + // read sdp string, length is implicit in size of atom + uint64_t size = GetEnd() - m_File.GetPosition(); + char* data = (char*)MP4Malloc(size + 1); + ASSERT(data != NULL); + m_File.ReadBytes((uint8_t*)data, size); + data[size] = '\0'; + ((MP4StringProperty*)m_pProperties[0])->SetValue(data); + MP4Free(data); +} + +void MP4SdpAtom::Write() +{ + // since length of string is implicit in size of atom + // we need to handle this specially, and not write the terminating \0 + MP4StringProperty* pSdp = (MP4StringProperty*)m_pProperties[0]; + const char* sdpText = pSdp->GetValue(); + if (sdpText) { + pSdp->SetFixedLength((uint32_t)strlen(sdpText)); + } + MP4Atom::Write(); + pSdp->SetFixedLength(0); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sdtp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sdtp.cpp new file mode 100644 index 00000000..4afe6536 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sdtp.cpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4SdtpAtom::MP4SdtpAtom(MP4File &file) + : MP4FullAtom ( file, "sdtp" ) + , data ( *new MP4BytesProperty( *this, "data" )) +{ + AddProperty( &data ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void MP4SdtpAtom::Read() +{ + data.SetValueSize( m_size - 4 ); + MP4FullAtom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_smi.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_smi.cpp new file mode 100644 index 00000000..348b9ab1 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_smi.cpp @@ -0,0 +1,50 @@ +/* + * 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. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May [email protected] + * + * Apple iTunes META data + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4SmiAtom::MP4SmiAtom(MP4File &file) + : MP4Atom(file, "meta") +{ + + AddProperty( new MP4BytesProperty(*this, "metadata")); + +} + +void MP4SmiAtom::Read() +{ + // calculate size of the metadata from the atom size + ((MP4BytesProperty*)m_pProperties[0])->SetValueSize(m_size); + + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sound.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sound.cpp new file mode 100644 index 00000000..368f4318 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_sound.cpp @@ -0,0 +1,139 @@ +/* + * 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. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4SoundAtom::MP4SoundAtom(MP4File &file, const char *atomid) + : MP4Atom(file, atomid) +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + AddProperty( /* 2 */ + new MP4Integer16Property(*this, "soundVersion")); + AddReserved( *this, "reserved2", 6); /* 3 */ + + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "channels")); + AddProperty( /* 5 */ + new MP4Integer16Property(*this, "sampleSize")); + AddProperty( /* 6 */ + new MP4Integer16Property(*this, "compressionId")); + AddProperty( /* 7 */ + new MP4Integer16Property(*this, "packetSize")); + AddProperty( /* 8 */ + new MP4Integer32Property(*this, "timeScale")); + + if (ATOMID(atomid) == ATOMID("mp4a")) { + ExpectChildAtom("esds", Required, OnlyOne); + ExpectChildAtom("wave", Optional, OnlyOne); + } else if (ATOMID(atomid) == ATOMID("alac")) { + ExpectChildAtom("alac", Optional, Optional); + //AddProperty( new MP4BytesProperty(*this, "alacInfo", 36)); + } +} + +void MP4SoundAtom::AddProperties (uint8_t version) +{ + if (version > 0) { + AddProperty( /* 9 */ + new MP4Integer32Property(*this, "samplesPerPacket")); + AddProperty( /* 10 */ + new MP4Integer32Property(*this, "bytesPerPacket")); + AddProperty( /* 11 */ + new MP4Integer32Property(*this, "bytesPerFrame")); + AddProperty( /* 12 */ + new MP4Integer32Property(*this, "bytesPerSample")); + } + if (version == 2) { + AddReserved(*this, "reserved4", 20); + } +} +void MP4SoundAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(0); + + // property reserved2 has non-zero fixed values + static const uint8_t reserved2[6] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + }; + m_pProperties[3]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[3])-> + SetValue(reserved2, sizeof(reserved2)); + m_pProperties[3]->SetReadOnly(true); + ((MP4Integer16Property*)m_pProperties[4])->SetValue(2); + ((MP4Integer16Property*)m_pProperties[5])->SetValue(0x0010); + ((MP4Integer16Property*)m_pProperties[6])->SetValue(0); + +} + +void MP4SoundAtom::Read() +{ + MP4Atom *parent = GetParentAtom(); + if (ATOMID(parent->GetType()) != ATOMID("stsd")) { + // Quicktime has an interesting thing - they'll put an mp4a atom + // which is blank inside a wave atom, which is inside an mp4a atom + // we have a mp4a inside an wave inside an mp4a - delete all properties + for(int i = 0; i < 9; ++ i) + delete m_pProperties[i]; // make sure we delete the properties themselves, then remove from m_pProperties + + m_pProperties.Delete(8); + m_pProperties.Delete(7); + m_pProperties.Delete(6); + m_pProperties.Delete(5); + m_pProperties.Delete(4); + m_pProperties.Delete(3); + m_pProperties.Delete(2); + m_pProperties.Delete(1); + m_pProperties.Delete(0); + + if (ATOMID(GetType()) == ATOMID("alac")) { + AddProperty(new MP4BytesProperty(*this, "decoderConfig", m_size)); + ReadProperties(); + } + if (m_pChildAtomInfos.Size() > 0) { + ReadChildAtoms(); + } + } else { + ReadProperties(0, 3); // read first 3 properties + AddProperties(((MP4IntegerProperty *)m_pProperties[2])->GetValue()); + ReadProperties(3); // continue + if (m_pChildAtomInfos.Size() > 0) { + ReadChildAtoms(); + } + } + Skip(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_standard.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_standard.cpp new file mode 100644 index 00000000..ba567fde --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_standard.cpp @@ -0,0 +1,420 @@ +/* + * 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. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May (from others work). + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4StandardAtom::MP4StandardAtom (MP4File &file, const char *type) : MP4Atom(file, type) +{ + /* + * This is a big if else loop. Make sure that you don't break it + * when adding new atoms, or you will set the unknown type flag + * + * Try to keep it in alphabetical order - it should only be called + * 1 time per atom, so it's not that urgent. + */ + if (ATOMID(type) == ATOMID("bitr")) { + AddProperty( /* 0 */ + new MP4Integer32Property(*this, "avgBitrate")); + + AddProperty( /* 1 */ + new MP4Integer32Property(*this, "maxBitrate")); + + } else if (ATOMID(type) == ATOMID("btrt")) { + AddProperty( new MP4Integer32Property(*this, "bufferSizeDB")); /* 0 */ + AddProperty( new MP4Integer32Property(*this, "avgBitrate")); /* 1 */ + AddProperty( new MP4Integer32Property(*this, "maxBitrate")); /* 2 */ + } else if (ATOMID(type) == ATOMID("burl")) { + AddProperty( new MP4StringProperty(*this, "base_url")); + /* + * c??? + */ + } else if (ATOMID(type) == ATOMID("co64")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer64Property(*this, "chunkOffset")); + } else if (ATOMID(type) == ATOMID("ctts")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "sampleCount")); + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "sampleOffset")); + /* + * d??? + */ + } else if (ATOMID(type) == ATOMID("dinf")) { + ExpectChildAtom("dref", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("dimm")) { + AddProperty( // bytes of immediate data + new MP4Integer64Property(*this, "bytes")); + + } else if (ATOMID(type) == ATOMID("dmax")) { + AddProperty( // max packet duration + new MP4Integer32Property(*this, "milliSecs")); + + } else if (ATOMID(type) == ATOMID("dmed")) { + AddProperty( // bytes sent from media data + new MP4Integer64Property(*this, "bytes")); + + } else if (ATOMID(type) == ATOMID("drep")) { + AddProperty( // bytes of repeated data + new MP4Integer64Property(*this, "bytes")); + /* + * e??? + */ + } else if (ATOMID(type) == ATOMID("edts")) { + ExpectChildAtom("elst", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("esds")) { + AddVersionAndFlags(); + AddProperty( + new MP4DescriptorProperty(*this, NULL, MP4ESDescrTag, 0, + Required, OnlyOne)); + /* + * f??? + */ + } else if (ATOMID(type) == ATOMID("frma")) { + AddProperty( /* 0 */ + new MP4Integer32Property(*this, "data-format")); + /* + * g??? + */ + } else if (ATOMID(type) == ATOMID("gmhd")) { + ExpectChildAtom("gmin", Required, OnlyOne); + ExpectChildAtom("tmcd", Optional, OnlyOne); + ExpectChildAtom("text", Optional, OnlyOne); + } else if (ATOMID(type) == ATOMID("hmhd")) { + AddVersionAndFlags(); + + AddProperty(new MP4Integer16Property(*this, "maxPduSize")); + AddProperty(new MP4Integer16Property(*this, "avgPduSize")); + AddProperty(new MP4Integer32Property(*this, "maxBitRate")); + AddProperty(new MP4Integer32Property(*this, "avgBitRate")); + AddProperty(new MP4Integer32Property(*this, "slidingAvgBitRate")); + /* + * i??? + */ + } else if (ATOMID(type) == ATOMID("iKMS")) { + AddVersionAndFlags(); /* 0, 1 */ + MP4StringProperty* pProp = new MP4StringProperty(*this, "kms_URI"); + AddProperty(pProp); /* 2 */ + + } else if (ATOMID(type) == ATOMID("iSFM")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4BitfieldProperty(*this, "selective-encryption", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(*this, "reserved", 7)); + AddProperty( /* 4 */ + new MP4Integer8Property(*this, "key-indicator-length")); + AddProperty( /* 5 */ + new MP4Integer8Property(*this, "IV-length")); + + } else if (ATOMID(type) == ATOMID("ilst")) { + ExpectChildAtom("\251nam", Optional, OnlyOne); /* name */ + ExpectChildAtom("\251ART", Optional, OnlyOne); /* artist */ + ExpectChildAtom("\251wrt", Optional, OnlyOne); /* writer */ + ExpectChildAtom("\251alb", Optional, OnlyOne); /* album */ + ExpectChildAtom("\251day", Optional, OnlyOne); /* date */ + ExpectChildAtom("\251too", Optional, OnlyOne); /* tool */ + ExpectChildAtom("\251cmt", Optional, OnlyOne); /* comment */ + ExpectChildAtom("\251gen", Optional, OnlyOne); /* custom genre */ + ExpectChildAtom("trkn", Optional, OnlyOne); /* tracknumber */ + ExpectChildAtom("disk", Optional, OnlyOne); /* disknumber */ + ExpectChildAtom("gnre", Optional, OnlyOne); /* genre (ID3v1 index + 1) */ + ExpectChildAtom("cpil", Optional, OnlyOne); /* compilation */ + ExpectChildAtom("tmpo", Optional, OnlyOne); /* BPM */ + ExpectChildAtom("covr", Optional, OnlyOne); /* cover art */ + ExpectChildAtom("aART", Optional, OnlyOne); /* album artist */ + ExpectChildAtom("----", Optional, Many); /* ---- free form */ + ExpectChildAtom("pgap", Optional, OnlyOne); /* part of gapless album */ + ExpectChildAtom("tvsh", Optional, OnlyOne); /* TV show */ + ExpectChildAtom("tvsn", Optional, OnlyOne); /* TV season */ + ExpectChildAtom("tven", Optional, OnlyOne); /* TV episode number */ + ExpectChildAtom("tvnn", Optional, OnlyOne); /* TV network name */ + ExpectChildAtom("tves", Optional, OnlyOne); /* TV epsidoe */ + ExpectChildAtom("desc", Optional, OnlyOne); /* description */ + ExpectChildAtom("ldes", Optional, OnlyOne); /* long description */ + ExpectChildAtom("soal", Optional, OnlyOne); /* sort album */ + ExpectChildAtom("soar", Optional, OnlyOne); /* sort artist */ + ExpectChildAtom("soaa", Optional, OnlyOne); /* sort album artist */ + ExpectChildAtom("sonm", Optional, OnlyOne); /* sort name */ + ExpectChildAtom("soco", Optional, OnlyOne); /* sort composer */ + ExpectChildAtom("sosn", Optional, OnlyOne); /* sort show */ + ExpectChildAtom("hdvd", Optional, OnlyOne); /* HD video */ + ExpectChildAtom("�enc", Optional, OnlyOne); /* Encoded by */ + ExpectChildAtom("pcst", Optional, OnlyOne); /* Podcast flag */ + ExpectChildAtom("keyw", Optional, OnlyOne); /* Keywords (for podcasts?) */ + ExpectChildAtom("catg", Optional, OnlyOne); /* Category (for podcasts?) */ + ExpectChildAtom("purl", Optional, OnlyOne); /* Podcast URL */ + ExpectChildAtom("egid", Optional, OnlyOne); /* Podcast episode global unique ID */ + ExpectChildAtom("rtng", Optional, OnlyOne); /* Content Rating */ + ExpectChildAtom("stik", Optional, OnlyOne); /* MediaType */ + ExpectChildAtom("\251grp", Optional, OnlyOne); /* Grouping */ + ExpectChildAtom("\251lyr", Optional, OnlyOne); /* Lyrics */ + ExpectChildAtom("cprt", Optional, OnlyOne); /* Copyright */ + ExpectChildAtom("apID", Optional, OnlyOne); /* iTunes Account */ + ExpectChildAtom("akID", Optional, OnlyOne); /* iTunes Account Type */ + ExpectChildAtom("sfID", Optional, OnlyOne); /* iTunes Country */ + ExpectChildAtom("cnID", Optional, OnlyOne); /* Content ID */ + ExpectChildAtom("atID", Optional, OnlyOne); /* Artist ID */ + ExpectChildAtom("plID", Optional, OnlyOne); /* Playlist ID */ + ExpectChildAtom("geID", Optional, OnlyOne); /* Genre ID */ + ExpectChildAtom("cmID", Optional, OnlyOne); /* Composer ID */ + ExpectChildAtom("xid ", Optional, OnlyOne); /* XID */ + + } else if (ATOMID(type) == ATOMID("imif")) { + AddVersionAndFlags(); + AddProperty(new MP4DescriptorProperty(*this, "ipmp_desc", MP4IPMPDescrTag, + MP4IPMPDescrTag, Required, Many)); + } else if (ATOMID(type) == ATOMID("iods")) { + AddVersionAndFlags(); + AddProperty( + new MP4DescriptorProperty(*this, NULL, MP4FileIODescrTag, + MP4FileODescrTag, + Required, OnlyOne)); + /* + * m??? + */ + } else if (ATOMID(type) == ATOMID("maxr")) { + AddProperty(new MP4Integer32Property(*this, "granularity")); + AddProperty(new MP4Integer32Property(*this, "bytes")); + + } else if (ATOMID(type) == ATOMID("mdia")) { + ExpectChildAtom("mdhd", Required, OnlyOne); + ExpectChildAtom("hdlr", Required, OnlyOne); + ExpectChildAtom("minf", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("meta")) { // iTunes + AddVersionAndFlags(); /* 0, 1 */ + ExpectChildAtom("hdlr", Required, OnlyOne); + ExpectChildAtom("ilst", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("mfhd")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "sequenceNumber")); + + } else if (ATOMID(type) == ATOMID("minf")) { + ExpectChildAtom("vmhd", Optional, OnlyOne); + ExpectChildAtom("smhd", Optional, OnlyOne); + ExpectChildAtom("hmhd", Optional, OnlyOne); + ExpectChildAtom("nmhd", Optional, OnlyOne); + ExpectChildAtom("gmhd", Optional, OnlyOne); + ExpectChildAtom("dinf", Required, OnlyOne); + ExpectChildAtom("stbl", Required, OnlyOne); + + } else if (ATOMID(type) == ATOMID("moof")) { + ExpectChildAtom("mfhd", Required, OnlyOne); + ExpectChildAtom("traf", Optional, Many); + + } else if (ATOMID(type) == ATOMID("moov")) { + ExpectChildAtom("mvhd", Required, OnlyOne); + ExpectChildAtom("iods", Optional, OnlyOne); + ExpectChildAtom("trak", Required, Many); + ExpectChildAtom("udta", Optional, Many); + ExpectChildAtom("mvex", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("mvex")) { + ExpectChildAtom("trex", Required, Many); + + /* + * n??? + */ + } else if (ATOMID(type) == ATOMID("nmhd")) { + AddVersionAndFlags(); + + } else if (ATOMID(type) == ATOMID("nump")) { + AddProperty( // packets sent + new MP4Integer64Property(*this, "packets")); + /* + * o??? + */ + } else if (ATOMID(type) == ATOMID("odkm")) { + AddVersionAndFlags(); + ExpectChildAtom("ohdr", Required, OnlyOne); + /* + * p??? + */ + } else if (ATOMID(type) == ATOMID("payt")) { + AddProperty(new MP4Integer32Property(*this, "payloadNumber")); + AddProperty(new MP4StringProperty(*this, "rtpMap", Counted)); + + } else if (ATOMID(type) == ATOMID("pinf")) { + ExpectChildAtom("frma", Required, OnlyOne); + } else if (ATOMID(type) == ATOMID("pmax")) { + AddProperty( // max packet size + new MP4Integer32Property(*this, "bytes")); + } else if (ATOMID(type) == ATOMID("schi")) { + // not sure if this is child atoms or table of boxes + // get clarification on spec 9.1.2.5 + ExpectChildAtom("odkm", Optional, OnlyOne); + ExpectChildAtom("iKMS", Optional, OnlyOne); + ExpectChildAtom("iSFM", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("schm")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "scheme_type")); + AddProperty( /* 3 */ + new MP4Integer32Property(*this, "scheme_version")); + // browser URI if flags set, TODO + + } else if (ATOMID(type) == ATOMID("sinf")) { + ExpectChildAtom("frma", Required, OnlyOne); + ExpectChildAtom("imif", Optional, OnlyOne); + ExpectChildAtom("schm", Optional, OnlyOne); + ExpectChildAtom("schi", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("smhd")) { + AddVersionAndFlags(); + AddReserved(*this, "reserved", 4); + + } else if (ATOMID(type) == ATOMID("snro")) { + AddProperty(new MP4Integer32Property(*this, "offset")); + + } else if (ATOMID(type) == ATOMID("stco")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "chunkOffset")); + + } else if (ATOMID(type) == ATOMID("stsh")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "shadowedSampleNumber")); + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "syncSampleNumber")); + + } else if (ATOMID(type) == ATOMID("stss")) { + AddVersionAndFlags(); + + MP4Integer32Property* pCount = new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "sampleNumber")); + + } else if (ATOMID(type) == ATOMID("stts")) { + AddVersionAndFlags(); + MP4Integer32Property* pCount = new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "sampleCount")); + pTable->AddProperty(new MP4Integer32Property(pTable->GetParentAtom(), "sampleDelta")); + } else if (ATOMID(type) == ATOMID("tims")) { + AddProperty( + new MP4Integer32Property(*this, "timeScale")); + + } else if (ATOMID(type) == ATOMID("tmin")) { + AddProperty( // min relative xmit time + new MP4Integer32Property(*this, "milliSecs")); + + } else if (ATOMID(type) == ATOMID("tmax")) { + AddProperty( // max relative xmit time + new MP4Integer32Property(*this, "milliSecs")); + + } else if (ATOMID(type) == ATOMID("traf")) { + ExpectChildAtom("tfhd", Required, OnlyOne); + ExpectChildAtom("trun", Optional, Many); + + } else if (ATOMID(type) == ATOMID("trak")) { + ExpectChildAtom("tkhd", Required, OnlyOne); + ExpectChildAtom("tref", Optional, OnlyOne); + ExpectChildAtom("edts", Optional, OnlyOne); + ExpectChildAtom("mdia", Required, OnlyOne); + ExpectChildAtom("udta", Optional, Many); + + } else if (ATOMID(type) == ATOMID("tref")) { + ExpectChildAtom("chap", Optional, OnlyOne); + ExpectChildAtom("dpnd", Optional, OnlyOne); + ExpectChildAtom("hint", Optional, OnlyOne); + ExpectChildAtom("ipir", Optional, OnlyOne); + ExpectChildAtom("mpod", Optional, OnlyOne); + ExpectChildAtom("sync", Optional, OnlyOne); + + } else if (ATOMID(type) == ATOMID("trex")) { + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "trackId")); + AddProperty( /* 3 */ + new MP4Integer32Property(*this, "defaultSampleDesriptionIndex")); + AddProperty( /* 4 */ + new MP4Integer32Property(*this, "defaultSampleDuration")); + AddProperty( /* 5 */ + new MP4Integer32Property(*this, "defaultSampleSize")); + AddProperty( /* 6 */ + new MP4Integer32Property(*this, "defaultSampleFlags")); + + } else if (ATOMID(type) == ATOMID("trpy") || + ATOMID(type) == ATOMID("tpyl")) { + AddProperty( // bytes sent including RTP headers + new MP4Integer64Property(*this, "bytes")); + + } else if (ATOMID(type) == ATOMID("tsro")) { + AddProperty( + new MP4Integer32Property(*this, "offset")); + } else if (ATOMID(type) == ATOMID("wave")) { + ExpectChildAtom("esds", Required, OnlyOne); + } else { + /* + * default - unknown type + */ + SetUnknownType(true); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stbl.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stbl.cpp new file mode 100644 index 00000000..ca63dd91 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stbl.cpp @@ -0,0 +1,66 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4StblAtom::MP4StblAtom(MP4File &file) + : MP4Atom(file, "stbl") +{ + ExpectChildAtom("stsd", Required, OnlyOne); + ExpectChildAtom("stts", Required, OnlyOne); + ExpectChildAtom("ctts", Optional, OnlyOne); + ExpectChildAtom("stsz", Required, OnlyOne); + ExpectChildAtom("stz2", Optional, OnlyOne); + ExpectChildAtom("stsc", Required, OnlyOne); + ExpectChildAtom("stco", Optional, OnlyOne); + ExpectChildAtom("co64", Optional, OnlyOne); + ExpectChildAtom("stss", Optional, OnlyOne); + ExpectChildAtom("stsh", Optional, OnlyOne); + ExpectChildAtom("stdp", Optional, OnlyOne); + ExpectChildAtom("sdtp", Optional, OnlyOne); +} + +void MP4StblAtom::Generate() +{ + // as usual + MP4Atom::Generate(); + + // but we also need one of the chunk offset atoms + MP4Atom* pChunkOffsetAtom; + if (m_File.Use64Bits(GetType())) { + pChunkOffsetAtom = CreateAtom(m_File, this, "co64"); + } else { + pChunkOffsetAtom = CreateAtom(m_File, this, "stco"); + } + + AddChildAtom(pChunkOffsetAtom); + + // and ask it to self generate + pChunkOffsetAtom->Generate(); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stdp.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stdp.cpp new file mode 100644 index 00000000..daac9fe6 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stdp.cpp @@ -0,0 +1,59 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4StdpAtom::MP4StdpAtom(MP4File &file) + : MP4Atom(file, "stdp") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + pCount->SetImplicit(); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer16Property(pTable->GetParentAtom(), "priority")); +} + +void MP4StdpAtom::Read() +{ + // table entry count computed from atom size + ((MP4Integer32Property*)m_pProperties[2])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[2])->SetValue((m_size - 4) / 2); + ((MP4Integer32Property*)m_pProperties[2])->SetReadOnly(true); + + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsc.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsc.cpp new file mode 100644 index 00000000..6dbecfde --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsc.cpp @@ -0,0 +1,88 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4StscAtom::MP4StscAtom(MP4File &file) + : MP4Atom(file, "stsc") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer32Property(pTable->GetParentAtom(), "firstChunk")); + pTable->AddProperty( + new MP4Integer32Property(pTable->GetParentAtom(), "samplesPerChunk")); + pTable->AddProperty( + new MP4Integer32Property(pTable->GetParentAtom(), "sampleDescriptionIndex")); + + // As an optimization we add an implicit property to this table, + // "firstSample" that corresponds to the first sample of the firstChunk + MP4Integer32Property* pSample = + new MP4Integer32Property(*this, "firstSample"); + pSample->SetImplicit(); + pTable->AddProperty(pSample); +} + +void MP4StscAtom::Read() +{ + // Read as usual + MP4Atom::Read(); + + // Compute the firstSample values for later use + uint32_t count = + ((MP4Integer32Property*)m_pProperties[2])->GetValue(); + + MP4Integer32Property* pFirstChunk = (MP4Integer32Property*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(0); + MP4Integer32Property* pSamplesPerChunk = (MP4Integer32Property*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(1); + MP4Integer32Property* pFirstSample = (MP4Integer32Property*) + ((MP4TableProperty*)m_pProperties[3])->GetProperty(3); + + MP4SampleId sampleId = 1; + + for (uint32_t i = 0; i < count; i++) { + pFirstSample->SetValue(sampleId, i); + + if (i < count - 1) { + sampleId += + (pFirstChunk->GetValue(i+1) - pFirstChunk->GetValue(i)) + * pSamplesPerChunk->GetValue(i); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsd.cpp new file mode 100644 index 00000000..bf995d8a --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsd.cpp @@ -0,0 +1,85 @@ +/* + * 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 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4StsdAtom::MP4StsdAtom(MP4File &file) + : MP4Atom(file, "stsd") +{ + AddVersionAndFlags(); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + pCount->SetReadOnly(); + AddProperty(pCount); + + ExpectChildAtom("mp4a", Optional, Many); + ExpectChildAtom("enca", Optional, Many); + ExpectChildAtom("mp4s", Optional, Many); + ExpectChildAtom("mp4v", Optional, Many); + ExpectChildAtom("encv", Optional, Many); + ExpectChildAtom("rtp ", Optional, Many); + ExpectChildAtom("samr", Optional, Many); // For AMR-NB + ExpectChildAtom("sawb", Optional, Many); // For AMR-WB + ExpectChildAtom("s263", Optional, Many); // For H.263 + ExpectChildAtom("avc1", Optional, Many); + ExpectChildAtom("alac", Optional, Many); + ExpectChildAtom("text", Optional, Many); + ExpectChildAtom("ac-3", Optional, Many); +} + +void MP4StsdAtom::Read() +{ + /* do the usual read */ + MP4Atom::Read(); + + // check that number of children == entryCount + MP4Integer32Property* pCount = + (MP4Integer32Property*)m_pProperties[2]; + + if (m_pChildAtoms.Size() != pCount->GetValue()) { + log.warningf("%s: \"%s\": stsd inconsistency with number of entries", + __FUNCTION__, GetFile().GetFilename().c_str() ); + + /* fix it */ + pCount->SetReadOnly(false); + pCount->SetValue(m_pChildAtoms.Size()); + pCount->SetReadOnly(true); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsz.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsz.cpp new file mode 100644 index 00000000..2a054faf --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stsz.cpp @@ -0,0 +1,79 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4StszAtom::MP4StszAtom(MP4File &file) + : MP4Atom(file, "stsz") +{ + AddVersionAndFlags(); /* 0, 1 */ + + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "sampleSize")); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "sampleCount"); + AddProperty(pCount); /* 3 */ + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); /* 4 */ + + pTable->AddProperty( /* 4/0 */ + new MP4Integer32Property(pTable->GetParentAtom(), "entrySize")); +} + +void MP4StszAtom::Read() +{ + ReadProperties(0, 4); + + uint32_t sampleSize = + ((MP4Integer32Property*)m_pProperties[2])->GetValue(); + + // only attempt to read entries table if sampleSize is zero + // i.e sample size is not constant + m_pProperties[4]->SetImplicit(sampleSize != 0); + + ReadProperties(4); + + Skip(); // to end of atom +} + +void MP4StszAtom::Write() +{ + uint32_t sampleSize = + ((MP4Integer32Property*)m_pProperties[2])->GetValue(); + + // only attempt to write entries table if sampleSize is zero + // i.e sample size is not constant + m_pProperties[4]->SetImplicit(sampleSize != 0); + + MP4Atom::Write(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stz2.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stz2.cpp new file mode 100644 index 00000000..30a1946c --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_stz2.cpp @@ -0,0 +1,108 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +/* + * This is used for the 4 bit sample size below. We need the sampleCount + * to be correct for the number of samples, but the table size needs to + * be correct to read and write it. + */ + +class MP4HalfSizeTableProperty : public MP4TableProperty +{ +public: + MP4HalfSizeTableProperty(MP4Atom& parentAtom, const char *name, MP4IntegerProperty *pCountProperty) : + MP4TableProperty(parentAtom, name, pCountProperty) {}; + + // The count is half the actual size + uint32_t GetCount() { + return (m_pCountProperty->GetValue() + 1)/ 2; + }; + void SetCount(uint32_t count) { + m_pCountProperty->SetValue(count * 2); + }; +private: + MP4HalfSizeTableProperty(); + MP4HalfSizeTableProperty ( const MP4HalfSizeTableProperty &src ); + MP4HalfSizeTableProperty &operator= ( const MP4HalfSizeTableProperty &src ); +}; + + +MP4Stz2Atom::MP4Stz2Atom(MP4File &file) + : MP4Atom(file, "stz2") +{ + AddVersionAndFlags(); /* 0, 1 */ + + AddReserved(*this, "reserved", 3); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer8Property(*this, "fieldSize")); + + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "sampleCount"); + AddProperty(pCount); /* 4 */ + +} + +void MP4Stz2Atom::Read() +{ + ReadProperties(0, 4); + + uint8_t fieldSize = + ((MP4Integer8Property *)m_pProperties[3])->GetValue(); + // uint32_t sampleCount = 0; + + MP4Integer32Property* pCount = + (MP4Integer32Property *)m_pProperties[4]; + + MP4TableProperty *pTable; + if (fieldSize != 4) { + pTable = new MP4TableProperty(*this, "entries", pCount); + } else { + // 4 bit field size uses a special table. + pTable = new MP4HalfSizeTableProperty(*this, "entries", pCount); + } + + AddProperty(pTable); + + if (fieldSize == 16) { + pTable->AddProperty( /* 5/0 */ + new MP4Integer16Property(*this, "entrySize")); + } else { + pTable->AddProperty( /* 5/0 */ + new MP4Integer8Property(*this, "entrySize")); + } + + ReadProperties(4); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_text.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_text.cpp new file mode 100644 index 00000000..454d4050 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_text.cpp @@ -0,0 +1,147 @@ +/* + * 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. + * + * Contributer has declined to give copyright information, and gives + * it freely to the world. + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4TextAtom::MP4TextAtom(MP4File &file) + : MP4Atom(file, "text") +{ + // The atom type "text" is used in two complete unrelated ways + // i.e. it's real two atoms with the same name + // To handle that we need to postpone property creation until + // we know who our parent atom is (stsd or gmhd) which gives us + // the context info we need to know who we are +} + +void MP4TextAtom::AddPropertiesStsdType() +{ + + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty(new MP4Integer16Property(*this, "dataReferenceIndex"));/* 1 */ + + AddProperty(new MP4Integer32Property(*this, "displayFlags")); /* 2 */ + AddProperty(new MP4Integer32Property(*this, "textJustification")); /* 3 */ + + AddProperty(new MP4Integer16Property(*this, "bgColorRed")); /* 4 */ + AddProperty(new MP4Integer16Property(*this, "bgColorGreen")); /* 5 */ + AddProperty(new MP4Integer16Property(*this, "bgColorBlue")); /* 6 */ + + AddProperty(new MP4Integer16Property(*this, "defTextBoxTop")); /* 7 */ + AddProperty(new MP4Integer16Property(*this, "defTextBoxLeft")); /* 8 */ + AddProperty(new MP4Integer16Property(*this, "defTextBoxBottom")); /* 9 */ + AddProperty(new MP4Integer16Property(*this, "defTextBoxRight")); /* 10 */ + + AddReserved(*this, "reserved2", 8); /* 11 */ + + AddProperty(new MP4Integer16Property(*this, "fontNumber")); /* 12 */ + AddProperty(new MP4Integer16Property(*this, "fontFace")); /* 13 */ + + AddReserved(*this, "reserved3", 1); /* 14 */ + AddReserved(*this, "reserved4", 2); /* 15 */ + + AddProperty(new MP4Integer16Property(*this, "foreColorRed")); /* 16 */ + AddProperty(new MP4Integer16Property(*this, "foreColorGreen")); /* 17 */ + AddProperty(new MP4Integer16Property(*this, "foreColorBlue")); /* 18 */ + +} + +void MP4TextAtom::AddPropertiesGmhdType() +{ + + AddProperty(new MP4BytesProperty(*this, "textData", 36)); /* 0 */ + +} + + +void MP4TextAtom::Generate() +{ + ASSERT(m_pParentAtom); + if (ATOMID(m_pParentAtom->GetType()) == ATOMID("stsd")) { + AddPropertiesStsdType(); + GenerateStsdType(); + } else if (ATOMID(m_pParentAtom->GetType()) == ATOMID("gmhd")) { + AddPropertiesGmhdType(); + GenerateGmhdType(); + } else { + log.warningf("%s: \"%s\": text atom in unexpected context, can not generate", __FUNCTION__, + GetFile().GetFilename().c_str()); + } + +} + +void MP4TextAtom::GenerateStsdType() +{ + // generate children + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + ((MP4Integer32Property*)m_pProperties[2])->SetValue(1); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(1); + +} + +void MP4TextAtom::GenerateGmhdType() +{ + MP4Atom::Generate(); + + // property 0 has non-zero fixed values + static uint8_t textData[36] = { + 0x00, 0x01, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x40, 0x00, + 0x00, 0x00, + }; + ((MP4BytesProperty*)m_pProperties[0])->SetValue(textData, sizeof(textData)); + +} + +void MP4TextAtom::Read () +{ + if (ATOMID(m_pParentAtom->GetType()) == ATOMID("stsd")) { + AddPropertiesStsdType(); + } else if (ATOMID(m_pParentAtom->GetType()) == ATOMID("gmhd")) { + AddPropertiesGmhdType(); + } + + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tfhd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tfhd.cpp new file mode 100644 index 00000000..ddfc579e --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tfhd.cpp @@ -0,0 +1,79 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4TfhdAtom::MP4TfhdAtom(MP4File &file) + : MP4Atom(file, "tfhd") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "trackId")); +} + +void MP4TfhdAtom::AddProperties(uint32_t flags) +{ + if (flags & 0x01) { + // note this property is signed 64! + AddProperty( + new MP4Integer64Property(*this, "baseDataOffset")); + } + if (flags & 0x02) { + AddProperty( + new MP4Integer32Property(*this, "sampleDescriptionIndex")); + } + if (flags & 0x08) { + AddProperty( + new MP4Integer32Property(*this, "defaultSampleDuration")); + } + if (flags & 0x10) { + AddProperty( + new MP4Integer32Property(*this, "defaultSampleSize")); + } + if (flags & 0x20) { + AddProperty( + new MP4Integer32Property(*this, "defaultSampleFlags")); + } +} + +void MP4TfhdAtom::Read() +{ + /* read atom version, flags, and trackId */ + ReadProperties(0, 3); + + /* need to create the properties based on the atom flags */ + AddProperties(GetFlags()); + + /* now we can read the remaining properties */ + ReadProperties(3); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tkhd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tkhd.cpp new file mode 100644 index 00000000..3e9de35d --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tkhd.cpp @@ -0,0 +1,145 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4TkhdAtom::MP4TkhdAtom(MP4File &file) + : MP4Atom(file, "tkhd") +{ + AddVersionAndFlags(); +} + +void MP4TkhdAtom::AddProperties(uint8_t version) +{ + if (version == 1) { + AddProperty( /* 2 */ + new MP4Integer64Property(*this, "creationTime")); + AddProperty( /* 3 */ + new MP4Integer64Property(*this, "modificationTime")); + } else { // version == 0 + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "creationTime")); + AddProperty( /* 3 */ + new MP4Integer32Property(*this, "modificationTime")); + } + + AddProperty( /* 4 */ + new MP4Integer32Property(*this, "trackId")); + AddReserved(*this, "reserved1", 4); /* 5 */ + + if (version == 1) { + AddProperty( /* 6 */ + new MP4Integer64Property(*this, "duration")); + } else { + AddProperty( /* 6 */ + new MP4Integer32Property(*this, "duration")); + } + + AddReserved(*this, "reserved2", 8); /* 7 */ + + AddProperty( /* 8 */ + new MP4Integer16Property(*this, "layer")); + AddProperty( /* 9 */ + new MP4Integer16Property(*this, "alternate_group")); + + MP4Float32Property* pProp; + + pProp = new MP4Float32Property(*this, "volume"); + pProp->SetFixed16Format(); + AddProperty(pProp); /* 10 */ + + AddReserved(*this, "reserved3", 2); /* 11 */ + + AddProperty(new MP4BytesProperty(*this, "matrix", 36)); /* 12 */ + + pProp = new MP4Float32Property(*this, "width"); + pProp->SetFixed32Format(); + AddProperty(pProp); /* 13 */ + + pProp = new MP4Float32Property(*this, "height"); + pProp->SetFixed32Format(); + AddProperty(pProp); /* 14 */ +} + +void MP4TkhdAtom::Generate() +{ + uint8_t version = m_File.Use64Bits(GetType()) ? 1 : 0; + SetVersion(version); + AddProperties(version); + + MP4Atom::Generate(); + + // set creation and modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + if (version == 1) { + ((MP4Integer64Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer64Property*)m_pProperties[3])->SetValue(now); + } else { + ((MP4Integer32Property*)m_pProperties[2])->SetValue(now); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(now); + } + + // property "matrix" has non-zero fixed values + // this default identity matrix indicates no transformation, i.e. + // 1, 0, 0 + // 0, 1, 0 + // 0, 0, 1 + // see http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_4.html + + static uint8_t matrix[36] = { + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, + }; + + ((MP4BytesProperty*)m_pProperties[12])-> + SetValue(matrix, sizeof(matrix)); +} + +void MP4TkhdAtom::Read() +{ + /* read atom version */ + ReadProperties(0, 1); + + /* need to create the properties based on the atom version */ + AddProperties(GetVersion()); + + /* now we can read the remaining properties */ + ReadProperties(1); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_treftype.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_treftype.cpp new file mode 100644 index 00000000..6a7ff92a --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_treftype.cpp @@ -0,0 +1,57 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4TrefTypeAtom::MP4TrefTypeAtom(MP4File &file, const char* type) + : MP4Atom(file, type) +{ + MP4Integer32Property* pCount = + new MP4Integer32Property(*this, "entryCount"); + pCount->SetImplicit(); + AddProperty(pCount); /* 0 */ + + MP4TableProperty* pTable = new MP4TableProperty(*this, "entries", pCount); + AddProperty(pTable); /* 1 */ + + pTable->AddProperty( /* 1, 0 */ + new MP4Integer32Property(pTable->GetParentAtom(), "trackId")); +} + +void MP4TrefTypeAtom::Read() +{ + // table entry count computed from atom size + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[0])->SetValue(m_size / 4); + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(true); + + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_trun.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_trun.cpp new file mode 100644 index 00000000..765e4179 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_trun.cpp @@ -0,0 +1,89 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4TrunAtom::MP4TrunAtom(MP4File &file) + : MP4Atom(file, "trun") +{ + AddVersionAndFlags(); /* 0, 1 */ + AddProperty( /* 2 */ + new MP4Integer32Property(*this, "sampleCount")); +} + +void MP4TrunAtom::AddProperties(uint32_t flags) +{ + if (flags & 0x01) { + // Note this is a signed 32 value + AddProperty( + new MP4Integer32Property(*this, "dataOffset")); + } + if (flags & 0x04) { + AddProperty( + new MP4Integer32Property(*this, "firstSampleFlags")); + } + + MP4TableProperty* pTable = + new MP4TableProperty(*this, "samples", + (MP4Integer32Property *)m_pProperties[2]); + AddProperty(pTable); + + if (flags & 0x100) { + pTable->AddProperty( + new MP4Integer32Property(*this, "sampleDuration")); + } + if (flags & 0x200) { + pTable->AddProperty( + new MP4Integer32Property(*this, "sampleSize")); + } + if (flags & 0x400) { + pTable->AddProperty( + new MP4Integer32Property(*this, "sampleFlags")); + } + if (flags & 0x800) { + pTable->AddProperty( + new MP4Integer32Property(*this, "sampleCompositionTimeOffset")); + } +} + +void MP4TrunAtom::Read() +{ + /* read atom version, flags, and sampleCount */ + ReadProperties(0, 3); + + /* need to create the properties based on the atom flags */ + AddProperties(GetFlags()); + + /* now we can read the remaining properties */ + ReadProperties(3); + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tx3g.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tx3g.cpp new file mode 100644 index 00000000..a54dd6be --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_tx3g.cpp @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Tx3gAtom::MP4Tx3gAtom(MP4File &file) + : MP4Atom(file, "tx3g") +{ + AddReserved(*this, "reserved1", 4); /* 0 */ + AddReserved(*this, "reserved2", 2); /* 1 */ + + AddProperty(new MP4Integer16Property(*this, "dataReferenceIndex"));/* 2 */ + + AddProperty(new MP4Integer32Property(*this, "displayFlags")); /* 3 */ + AddProperty(new MP4Integer8Property(*this, "horizontalJustification")); /* 4 */ + AddProperty(new MP4Integer8Property(*this, "verticalJustification")); /* 5 */ + + AddProperty(new MP4Integer8Property(*this, "bgColorRed")); /* 6 */ + AddProperty(new MP4Integer8Property(*this, "bgColorGreen")); /* 7 */ + AddProperty(new MP4Integer8Property(*this, "bgColorBlue")); /* 8 */ + AddProperty(new MP4Integer8Property(*this, "bgColorAlpha")); /* 9 */ + + AddProperty(new MP4Integer16Property(*this, "defTextBoxTop")); /* 10 */ + AddProperty(new MP4Integer16Property(*this, "defTextBoxLeft")); /* 11 */ + AddProperty(new MP4Integer16Property(*this, "defTextBoxBottom")); /* 12 */ + AddProperty(new MP4Integer16Property(*this, "defTextBoxRight")); /* 13 */ + + AddProperty(new MP4Integer16Property(*this, "startChar")); /* 14 */ + AddProperty(new MP4Integer16Property(*this, "endChar")); /* 15 */ + AddProperty(new MP4Integer16Property(*this, "fontID")); /* 16 */ + AddProperty(new MP4Integer8Property(*this, "fontFace")); /* 17 */ + AddProperty(new MP4Integer8Property(*this, "fontSize")); /* 18 */ + + AddProperty(new MP4Integer8Property(*this, "fontColorRed")); /* 19 */ + AddProperty(new MP4Integer8Property(*this, "fontColorGreen")); /* 20 */ + AddProperty(new MP4Integer8Property(*this, "fontColorBlue")); /* 21 */ + AddProperty(new MP4Integer8Property(*this, "fontColorAlpha")); /* 22 */ + + ExpectChildAtom("ftab", Optional, Many); +} + +void MP4Tx3gAtom::Generate() +{ + // generate children + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[2])->SetValue(1); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_udta.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_udta.cpp new file mode 100644 index 00000000..eff4dfa1 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_udta.cpp @@ -0,0 +1,56 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4UdtaAtom::MP4UdtaAtom(MP4File &file) + : MP4Atom(file, "udta") +{ + ExpectChildAtom("chpl", Optional, OnlyOne); + ExpectChildAtom("cprt", Optional, Many); + ExpectChildAtom("hnti", Optional, OnlyOne); + ExpectChildAtom("meta", Optional, OnlyOne); + ExpectChildAtom("\251cpy", Optional, OnlyOne); + ExpectChildAtom("\251des", Optional, OnlyOne); + ExpectChildAtom("\251nam", Optional, OnlyOne); + ExpectChildAtom("\251cmt", Optional, OnlyOne); + ExpectChildAtom("\251prd", Optional, OnlyOne); +} + +void MP4UdtaAtom::Read() +{ + if (ATOMID(m_pParentAtom->GetType()) == ATOMID("trak")) { + ExpectChildAtom("hinf", Optional, OnlyOne); + ExpectChildAtom("name", Optional, OnlyOne); + } + + MP4Atom::Read(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_url.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_url.cpp new file mode 100644 index 00000000..4d47d34b --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_url.cpp @@ -0,0 +1,73 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4UrlAtom::MP4UrlAtom(MP4File &file, const char *type) + : MP4Atom(file, type) +{ + AddVersionAndFlags(); + AddProperty(new MP4StringProperty(*this, "location")); +} + +void MP4UrlAtom::Read() +{ + // read the version and flags properties + ReadProperties(0, 2); + + // check if self-contained flag is set + if (!(GetFlags() & 1)) { + // if not then read url location + ReadProperties(2); + } + + Skip(); // to end of atom +} + +void MP4UrlAtom::Write() +{ + MP4StringProperty* pLocationProp = + (MP4StringProperty*)m_pProperties[2]; + + // if no url location has been set + // then set self-contained flag + // and don't attempt to write anything + if (pLocationProp->GetValue() == NULL) { + SetFlags(GetFlags() | 1); + pLocationProp->SetImplicit(true); + } else { + SetFlags(GetFlags() & 0xFFFFFE); + pLocationProp->SetImplicit(false); + } + + // write atom as usual + MP4Atom::Write(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_urn.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_urn.cpp new file mode 100644 index 00000000..f3da3e87 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_urn.cpp @@ -0,0 +1,54 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4UrnAtom::MP4UrnAtom(MP4File &file) + : MP4Atom(file, "urn ") +{ + AddVersionAndFlags(); + AddProperty(new MP4StringProperty(*this, "name")); + AddProperty(new MP4StringProperty(*this, "location")); +} + +void MP4UrnAtom::Read() +{ + // read the version, flags, and name properties + ReadProperties(0, 3); + + // check if location is present + if (m_File.GetPosition() < GetEnd()) { + // read it + ReadProperties(3); + } + + Skip(); // to end of atom +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_uuid.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_uuid.cpp new file mode 100644 index 00000000..c2839602 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_uuid.cpp @@ -0,0 +1,50 @@ +/* + * 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): + * + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +IPodUUIDAtom::IPodUUIDAtom(MP4File &file) + : MP4Atom(file, "uuid") +{ + // + // This is a hack, the contents of this atom need to be well defined. + // + static uint8_t ipod_magic[] = { + 0x6b, 0x68, 0x40, 0xf2, 0x5f, 0x24, 0x4f, 0xc5, + 0xba, 0x39, 0xa5, 0x1b, 0xcf, 0x03, 0x23, 0xf3 + }; + + SetExtendedType(ipod_magic); + + MP4Integer32Property* value = new MP4Integer32Property(*this, "value"); + value->SetValue(1); + AddProperty(value); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_video.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_video.cpp new file mode 100644 index 00000000..aeabd735 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_video.cpp @@ -0,0 +1,88 @@ +/* + * 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. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4VideoAtom::MP4VideoAtom (MP4File &file, const char *type) + : MP4Atom(file, type) +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "width")); + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "height")); + + AddReserved(*this, "reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty(*this, "compressorName"); + pProp->SetFixedLength(32); + pProp->SetCountedFormat(true); + pProp->SetValue(""); + AddProperty(pProp); /* 6 */ + + AddProperty(/* 7 */ + new MP4Integer16Property(*this, "depth")); + AddProperty(/* 8 */ + new MP4Integer16Property(*this, "colorTableId")); + ExpectChildAtom("smi ", Optional, OnlyOne); +} + +void MP4VideoAtom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static uint8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // depth and color table id values - should be set later + // as far as depth - color table is most likely 0xff + ((MP4IntegerProperty *)m_pProperties[7])->SetValue(0x18); + ((MP4IntegerProperty *)m_pProperties[8])->SetValue(0xffff); + +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_vmhd.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_vmhd.cpp new file mode 100644 index 00000000..eb06a26b --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atom_vmhd.cpp @@ -0,0 +1,46 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4VmhdAtom::MP4VmhdAtom(MP4File &file) + : MP4Atom(file, "vmhd") +{ + AddVersionAndFlags(); + AddReserved(*this, "reserved", 8); +} + +void MP4VmhdAtom::Generate() +{ + MP4Atom::Generate(); + + SetFlags(1); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atoms.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atoms.h new file mode 100644 index 00000000..382706f7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/atoms.h @@ -0,0 +1,829 @@ +/* + * 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 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Ximpo Group Ltd. [email protected] + * Bill May [email protected] + */ + +#ifndef MP4V2_IMPL_ATOMS_H +#define MP4V2_IMPL_ATOMS_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +class MP4FtypAtom; +class MP4FreeAtom; + +/// ISO base media full-atom. +class MP4FullAtom : public MP4Atom +{ +public: + MP4FullAtom( MP4File &file, const char* type ); + + MP4Integer8Property& version; + MP4Integer24Property& flags; +private: + MP4FullAtom(); + MP4FullAtom( const MP4FullAtom &src ); + MP4FullAtom &operator= ( const MP4FullAtom &src ); +}; + +// declare all the atom subclasses +// i.e. spare us atom_xxxx.h for all the atoms +// +// The majority of atoms just need their own constructor declared +// Some atoms have a few special needs +// A small minority of atoms need lots of special handling + +class MP4RootAtom : public MP4Atom +{ +public: + MP4RootAtom(MP4File &file); + void BeginWrite(bool use64 = false); + void Write(); + void FinishWrite(bool use64 = false); + + void BeginOptimalWrite(); + void FinishOptimalWrite(); + +protected: + uint32_t GetLastMdatIndex(); + void WriteAtomType(const char* type, bool onlyOne); + +private: + MP4RootAtom(); + MP4RootAtom( const MP4RootAtom &src ); + MP4RootAtom &operator= ( const MP4RootAtom &src ); + + MP4FtypAtom* m_rewrite_ftyp; + uint64_t m_rewrite_ftypPosition; + MP4FreeAtom* m_rewrite_free; + uint64_t m_rewrite_freePosition; +}; + +/*********************************************************************** + * Common atom classes - standard for anything that just contains atoms + * and non-maleable properties, treftype and url + ***********************************************************************/ +class MP4StandardAtom : public MP4Atom { +public: + MP4StandardAtom(MP4File &file, const char *name); +private: + MP4StandardAtom(); + MP4StandardAtom( const MP4StandardAtom &src ); + MP4StandardAtom &operator= ( const MP4StandardAtom &src ); +}; + +class MP4TrefTypeAtom : public MP4Atom { +public: + MP4TrefTypeAtom(MP4File &file, const char* type); + void Read(); +private: + MP4TrefTypeAtom(); + MP4TrefTypeAtom( const MP4TrefTypeAtom &src ); + MP4TrefTypeAtom &operator= ( const MP4TrefTypeAtom &src ); +}; + +class MP4UrlAtom : public MP4Atom { +public: + MP4UrlAtom(MP4File &file, const char *type="url "); + void Read(); + void Write(); +private: + MP4UrlAtom(); + MP4UrlAtom( const MP4UrlAtom &src ); + MP4UrlAtom &operator= ( const MP4UrlAtom &src ); +}; + +/*********************************************************************** + * Sound and Video atoms - use the generic atoms when possible + * (MP4SoundAtom and MP4VideoAtom) + ***********************************************************************/ +class MP4SoundAtom : public MP4Atom { +public: + MP4SoundAtom(MP4File &file, const char *atomid); + void Generate(); + void Read(); +protected: + void AddProperties(uint8_t version); +private: + MP4SoundAtom(); + MP4SoundAtom( const MP4SoundAtom &src ); + MP4SoundAtom &operator= ( const MP4SoundAtom &src ); +}; + +class MP4VideoAtom : public MP4Atom { +public: + MP4VideoAtom(MP4File &file, const char *atomid); + void Generate(); +private: + MP4VideoAtom(); + MP4VideoAtom( const MP4VideoAtom &src ); + MP4VideoAtom &operator= ( const MP4VideoAtom &src ); +}; + +class MP4AmrAtom : public MP4Atom { +public: + MP4AmrAtom(MP4File &file, const char *type); + void Generate(); +private: + MP4AmrAtom(); + MP4AmrAtom( const MP4AmrAtom &src ); + MP4AmrAtom &operator= ( const MP4AmrAtom &src ); +}; + +// H.264 atoms + +class MP4Avc1Atom : public MP4Atom { +public: + MP4Avc1Atom(MP4File &file); + void Generate(); +private: + MP4Avc1Atom(); + MP4Avc1Atom( const MP4Avc1Atom &src ); + MP4Avc1Atom &operator= ( const MP4Avc1Atom &src ); +}; + +class MP4AvcCAtom : public MP4Atom { +public: + MP4AvcCAtom(MP4File &file); + void Generate(); + void Clone(MP4AvcCAtom *dstAtom); +private: + MP4AvcCAtom(); + MP4AvcCAtom( const MP4AvcCAtom &src ); + MP4AvcCAtom &operator= ( const MP4AvcCAtom &src ); +}; + + +class MP4D263Atom : public MP4Atom { +public: + MP4D263Atom(MP4File &file); + void Generate(); + void Write(); +private: + MP4D263Atom(); + MP4D263Atom( const MP4D263Atom &src ); + MP4D263Atom &operator= ( const MP4D263Atom &src ); +}; + +class MP4DamrAtom : public MP4Atom { +public: + MP4DamrAtom(MP4File &file); + void Generate(); +private: + MP4DamrAtom(); + MP4DamrAtom( const MP4DamrAtom &src ); + MP4DamrAtom &operator= ( const MP4DamrAtom &src ); +}; + +class MP4EncaAtom : public MP4Atom { +public: + MP4EncaAtom(MP4File &file); + void Generate(); +private: + MP4EncaAtom(); + MP4EncaAtom( const MP4EncaAtom &src ); + MP4EncaAtom &operator= ( const MP4EncaAtom &src ); +}; + +class MP4EncvAtom : public MP4Atom { +public: + MP4EncvAtom(MP4File &file); + void Generate(); +private: + MP4EncvAtom(); + MP4EncvAtom( const MP4EncvAtom &src ); + MP4EncvAtom &operator= ( const MP4EncvAtom &src ); +}; + +class MP4Mp4aAtom : public MP4Atom { +public: + MP4Mp4aAtom(MP4File &file); + void Generate(); +private: + MP4Mp4aAtom(); + MP4Mp4aAtom( const MP4Mp4aAtom &src ); + MP4Mp4aAtom &operator= ( const MP4Mp4aAtom &src ); +}; + +class MP4Ac3Atom : public MP4Atom { +public: + MP4Ac3Atom(MP4File &file); + void Generate(); +private: + MP4Ac3Atom(); + MP4Ac3Atom( const MP4Ac3Atom &src ); + MP4Ac3Atom &operator= ( const MP4Ac3Atom &src ); +}; + +class MP4DAc3Atom : public MP4Atom { +public: + MP4DAc3Atom(MP4File &file); + void Generate(); + void Dump(uint8_t indent, bool dumpImplicits); +private: + MP4DAc3Atom(); + MP4DAc3Atom( const MP4DAc3Atom &src ); + MP4DAc3Atom &operator= ( const MP4DAc3Atom &src ); +}; + +class MP4Mp4sAtom : public MP4Atom { +public: + MP4Mp4sAtom(MP4File &file); + void Generate(); +private: + MP4Mp4sAtom(); + MP4Mp4sAtom( const MP4Mp4sAtom &src ); + MP4Mp4sAtom &operator= ( const MP4Mp4sAtom &src ); +}; + +class MP4Mp4vAtom : public MP4Atom { +public: + MP4Mp4vAtom(MP4File &file); + void Generate(); +private: + MP4Mp4vAtom(); + MP4Mp4vAtom( const MP4Mp4vAtom &src ); + MP4Mp4vAtom &operator= ( const MP4Mp4vAtom &src ); +}; + + +class MP4S263Atom : public MP4Atom { +public: + MP4S263Atom(MP4File &file); + void Generate(); +private: + MP4S263Atom(); + MP4S263Atom( const MP4S263Atom &src ); + MP4S263Atom &operator= ( const MP4S263Atom &src ); +}; + + + +/************************************************************************ + * Specialized Atoms + ************************************************************************/ + +class MP4DrefAtom : public MP4Atom { +public: + MP4DrefAtom(MP4File &file); + void Read(); +private: + MP4DrefAtom(); + MP4DrefAtom( const MP4DrefAtom &src ); + MP4DrefAtom &operator= ( const MP4DrefAtom &src ); +}; + +class MP4ElstAtom : public MP4Atom { +public: + MP4ElstAtom(MP4File &file); + void Generate(); + void Read(); +protected: + void AddProperties(uint8_t version); +private: + MP4ElstAtom(); + MP4ElstAtom( const MP4ElstAtom &src ); + MP4ElstAtom &operator= ( const MP4ElstAtom &src ); +}; + +class MP4FreeAtom : public MP4Atom { +public: + MP4FreeAtom( MP4File &file, const char* = NULL ); + void Read(); + void Write(); +private: + MP4FreeAtom(); + MP4FreeAtom( const MP4FreeAtom &src ); + MP4FreeAtom &operator= ( const MP4FreeAtom &src ); +}; + +class MP4FtypAtom : public MP4Atom { +public: + MP4FtypAtom(MP4File &file); + void Generate(); + void Read(); + + MP4StringProperty& majorBrand; + MP4Integer32Property& minorVersion; + MP4StringProperty& compatibleBrands; +private: + MP4FtypAtom(); + MP4FtypAtom( const MP4FtypAtom &src ); + MP4FtypAtom &operator= ( const MP4FtypAtom &src ); +}; + +class MP4GminAtom : public MP4Atom { +public: + MP4GminAtom(MP4File &file); + void Generate(); +private: + MP4GminAtom(); + MP4GminAtom( const MP4GminAtom &src ); + MP4GminAtom &operator= ( const MP4GminAtom &src ); +}; + +class MP4HdlrAtom : public MP4Atom { +public: + MP4HdlrAtom(MP4File &file); + void Read(); +private: + MP4HdlrAtom(); + MP4HdlrAtom( const MP4HdlrAtom &src ); + MP4HdlrAtom &operator= ( const MP4HdlrAtom &src ); +}; + +class MP4HinfAtom : public MP4Atom { +public: + MP4HinfAtom(MP4File &file); + void Generate(); +private: + MP4HinfAtom(); + MP4HinfAtom( const MP4HinfAtom &src ); + MP4HinfAtom &operator= ( const MP4HinfAtom &src ); +}; + +class MP4HntiAtom : public MP4Atom { +public: + MP4HntiAtom(MP4File &file); + void Read(); +private: + MP4HntiAtom(); + MP4HntiAtom( const MP4HntiAtom &src ); + MP4HntiAtom &operator= ( const MP4HntiAtom &src ); +}; + + +class MP4MdatAtom : public MP4Atom { +public: + MP4MdatAtom(MP4File &file); + void Read(); + void Write(); +private: + MP4MdatAtom(); + MP4MdatAtom( const MP4MdatAtom &src ); + MP4MdatAtom &operator= ( const MP4MdatAtom &src ); +}; + +class MP4MdhdAtom : public MP4Atom { +public: + MP4MdhdAtom(MP4File &file); + void Generate(); + void Read(); +protected: + void AddProperties(uint8_t version); +private: + MP4MdhdAtom(); + MP4MdhdAtom( const MP4MdhdAtom &src ); + MP4MdhdAtom &operator= ( const MP4MdhdAtom &src ); +}; + +class MP4MvhdAtom : public MP4Atom { +public: + MP4MvhdAtom(MP4File &file); + void Generate(); + void Read(); +protected: + void AddProperties(uint8_t version); +private: + MP4MvhdAtom(); + MP4MvhdAtom( const MP4MvhdAtom &src ); + MP4MvhdAtom &operator= ( const MP4MvhdAtom &src ); +}; + +class MP4OhdrAtom : public MP4Atom { +public: + MP4OhdrAtom(MP4File &file); + ~MP4OhdrAtom(); + void Read(); +private: + MP4OhdrAtom(); + MP4OhdrAtom( const MP4OhdrAtom &src ); + MP4OhdrAtom &operator= ( const MP4OhdrAtom &src ); +}; + +class MP4RtpAtom : public MP4Atom { +public: + MP4RtpAtom(MP4File &file); + void Generate(); + void Read(); + void Write(); + +protected: + void AddPropertiesStsdType(); + void AddPropertiesHntiType(); + + void GenerateStsdType(); + void GenerateHntiType(); + + void ReadStsdType(); + void ReadHntiType(); + + void WriteHntiType(); + +private: + MP4RtpAtom(); + MP4RtpAtom( const MP4RtpAtom &src ); + MP4RtpAtom &operator= ( const MP4RtpAtom &src ); +}; + +class MP4SdpAtom : public MP4Atom { +public: + MP4SdpAtom(MP4File &file); + void Read(); + void Write(); +private: + MP4SdpAtom(); + MP4SdpAtom( const MP4SdpAtom &src ); + MP4SdpAtom &operator= ( const MP4SdpAtom &src ); +}; + +// sdtp - Independent and Disposable Samples Atom. +class MP4SdtpAtom : public MP4FullAtom { +public: + MP4SdtpAtom(MP4File &file); + void Read(); + + // raw bytes; one byte for each sample. + // number of bytes == stsz.sampleCount. + MP4BytesProperty& data; +private: + MP4SdtpAtom(); + MP4SdtpAtom( const MP4SdtpAtom &src ); + MP4SdtpAtom &operator= ( const MP4SdtpAtom &src ); +}; + +class MP4SmiAtom : public MP4Atom { +public: + MP4SmiAtom(MP4File &file); + void Read(); +private: + MP4SmiAtom(); + MP4SmiAtom( const MP4SmiAtom &src ); + MP4SmiAtom &operator= ( const MP4SmiAtom &src ); +}; + +class MP4StblAtom : public MP4Atom { +public: + MP4StblAtom(MP4File &file); + void Generate(); +private: + MP4StblAtom(); + MP4StblAtom( const MP4StblAtom &src ); + MP4StblAtom &operator= ( const MP4StblAtom &src ); +}; + +class MP4StdpAtom : public MP4Atom { +public: + MP4StdpAtom(MP4File &file); + void Read(); +private: + MP4StdpAtom(); + MP4StdpAtom( const MP4StdpAtom &src ); + MP4StdpAtom &operator= ( const MP4StdpAtom &src ); +}; + +class MP4StscAtom : public MP4Atom { +public: + MP4StscAtom(MP4File &file); + void Read(); +private: + MP4StscAtom(); + MP4StscAtom( const MP4StscAtom &src ); + MP4StscAtom &operator= ( const MP4StscAtom &src ); +}; + +class MP4StsdAtom : public MP4Atom { +public: + MP4StsdAtom(MP4File &file); + void Read(); +private: + MP4StsdAtom(); + MP4StsdAtom( const MP4StsdAtom &src ); + MP4StsdAtom &operator= ( const MP4StsdAtom &src ); +}; + +class MP4StszAtom : public MP4Atom { +public: + MP4StszAtom(MP4File &file); + void Read(); + void Write(); +private: + MP4StszAtom(); + MP4StszAtom( const MP4StszAtom &src ); + MP4StszAtom &operator= ( const MP4StszAtom &src ); +}; + +class MP4Stz2Atom : public MP4Atom { +public: + MP4Stz2Atom(MP4File &file); + void Read(); +private: + MP4Stz2Atom(); + MP4Stz2Atom( const MP4Stz2Atom &src ); + MP4Stz2Atom &operator= ( const MP4Stz2Atom &src ); +}; + +class MP4TextAtom : public MP4Atom { +public: + MP4TextAtom(MP4File &file); + void Generate(); + void Read(); +protected: + void AddPropertiesStsdType(); + void AddPropertiesGmhdType(); + + void GenerateStsdType(); + void GenerateGmhdType(); +private: + MP4TextAtom(); + MP4TextAtom( const MP4TextAtom &src ); + MP4TextAtom &operator= ( const MP4TextAtom &src ); +}; + +class MP4Tx3gAtom : public MP4Atom { +public: + MP4Tx3gAtom(MP4File &file); + void Generate(); +private: + MP4Tx3gAtom(); + MP4Tx3gAtom( const MP4Tx3gAtom &src ); + MP4Tx3gAtom &operator= ( const MP4Tx3gAtom &src ); +}; + +class MP4FtabAtom : public MP4Atom { +public: + MP4FtabAtom(MP4File &file); +private: + MP4FtabAtom(); + MP4FtabAtom( const MP4FtabAtom &src ); + MP4FtabAtom &operator= ( const MP4FtabAtom &src ); +}; + +class MP4TfhdAtom : public MP4Atom { +public: + MP4TfhdAtom(MP4File &file); + void Read(); +protected: + void AddProperties(uint32_t flags); +private: + MP4TfhdAtom(); + MP4TfhdAtom( const MP4TfhdAtom &src ); + MP4TfhdAtom &operator= ( const MP4TfhdAtom &src ); +}; + +class MP4TkhdAtom : public MP4Atom { +public: + MP4TkhdAtom(MP4File &file); + void Generate(); + void Read(); +protected: + void AddProperties(uint8_t version); +private: + MP4TkhdAtom(); + MP4TkhdAtom( const MP4TkhdAtom &src ); + MP4TkhdAtom &operator= ( const MP4TkhdAtom &src ); +}; + +class MP4TrunAtom : public MP4Atom { +public: + MP4TrunAtom(MP4File &file); + void Read(); +protected: + void AddProperties(uint32_t flags); +private: + MP4TrunAtom(); + MP4TrunAtom( const MP4TrunAtom &src ); + MP4TrunAtom &operator= ( const MP4TrunAtom &src ); +}; + +class MP4UdtaAtom : public MP4Atom { +public: + MP4UdtaAtom(MP4File &file); + void Read(); +private: + MP4UdtaAtom(); + MP4UdtaAtom( const MP4UdtaAtom &src ); + MP4UdtaAtom &operator= ( const MP4UdtaAtom &src ); +}; + +class MP4UrnAtom : public MP4Atom { +public: + MP4UrnAtom(MP4File &file); + void Read(); +private: + MP4UrnAtom(); + MP4UrnAtom( const MP4UrnAtom &src ); + MP4UrnAtom &operator= ( const MP4UrnAtom &src ); +}; + +class MP4VmhdAtom : public MP4Atom { +public: + MP4VmhdAtom(MP4File &file); + void Generate(); +private: + MP4VmhdAtom(); + MP4VmhdAtom( const MP4VmhdAtom &src ); + MP4VmhdAtom &operator= ( const MP4VmhdAtom &src ); +}; + +class MP4HrefAtom : public MP4Atom { +public: + MP4HrefAtom(MP4File &file); + void Generate(void); +private: + MP4HrefAtom(); + MP4HrefAtom( const MP4HrefAtom &src ); + MP4HrefAtom &operator= ( const MP4HrefAtom &src ); +}; + +class MP4PaspAtom : public MP4Atom { +public: + MP4PaspAtom(MP4File &file); + void Generate(); +private: + MP4PaspAtom(); + MP4PaspAtom( const MP4PaspAtom &src ); + MP4PaspAtom &operator= ( const MP4PaspAtom &src ); +}; + +class MP4ColrAtom : public MP4Atom { +public: + MP4ColrAtom(MP4File &file); + void Generate(); +private: + MP4ColrAtom(); + MP4ColrAtom( const MP4ColrAtom &src ); + MP4ColrAtom &operator= ( const MP4ColrAtom &src ); +}; + +class IPodUUIDAtom : public MP4Atom { +public: + IPodUUIDAtom(MP4File &file); +private: + IPodUUIDAtom(); + IPodUUIDAtom( const IPodUUIDAtom &src ); + IPodUUIDAtom &operator= ( const IPodUUIDAtom &src ); +}; + +class MP4NmhdAtom : public MP4Atom { +public: + MP4NmhdAtom(MP4File &file); +private: + MP4NmhdAtom(); + MP4NmhdAtom( const MP4NmhdAtom &src ); + MP4NmhdAtom &operator= ( const MP4NmhdAtom &src ); +}; + +/*! Nero Chapter List. + * This atom defines the structure of a Nero chapter list. + * Although it is not completely clear if this structure is + * correct it is complete enough to successfully read and write + * the chapter list so that even Nero's software accepts it. + * + * The assumed format is as follows: + * - MP4Integer8Property("version") + * - MP4Integer24Property("flags") + * - MP4BytesProperty("reserved", 1) + * - MP4Integer32Property("chaptercount")\n + * - MP4TableProperty("chapters", "ref to chaptercount"); + * - MP4Integer64Property("starttime")\n + * The start time of the chapter expressed in 100 nanosecond units + * - MP4StringProperty("title", true)\n + * The title of the chapter encoded in UTF-8 + * + * The chapter title only accepts strings of 255 bytes so if a string + * only contains simple (two-byte) UTF-8 chars the maximum length is + * 127 chars. + */ +class MP4ChplAtom : public MP4Atom { +public: + MP4ChplAtom(MP4File &file); + void Generate(); +private: + MP4ChplAtom(); + MP4ChplAtom( const MP4ChplAtom &src ); + MP4ChplAtom &operator= ( const MP4ChplAtom &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +/// iTMF hdlr-atom. +class MP4ItmfHdlrAtom : public MP4FullAtom +{ +public: + MP4ItmfHdlrAtom(MP4File &file); + void Read(); + + MP4Integer32Property& reserved1; + MP4BytesProperty& handlerType; + MP4BytesProperty& reserved2; + MP4BytesProperty& name; +private: + MP4ItmfHdlrAtom(); + MP4ItmfHdlrAtom( const MP4ItmfHdlrAtom &src ); + MP4ItmfHdlrAtom &operator= ( const MP4ItmfHdlrAtom &src ); +}; + +/// iTMF item-atom. +class MP4ItemAtom : public MP4Atom +{ +public: + MP4ItemAtom( MP4File &file, const char* type ); +private: + MP4ItemAtom(); + MP4ItemAtom( const MP4ItemAtom &src ); + MP4ItemAtom &operator= ( const MP4ItemAtom &src ); +}; + +/// iTMF meaning-atom. +class MP4MeanAtom : public MP4FullAtom +{ +public: + MP4MeanAtom(MP4File &file); + void Read(); + + MP4BytesProperty& value; +private: + MP4MeanAtom(); + MP4MeanAtom( const MP4MeanAtom &src ); + MP4MeanAtom &operator= ( const MP4MeanAtom &src ); +}; + +/// iTMF name-atom. +class MP4NameAtom : public MP4FullAtom +{ +public: + MP4NameAtom(MP4File &file); + void Read(); + + MP4BytesProperty& value; +private: + MP4NameAtom(); + MP4NameAtom( const MP4NameAtom &src ); + MP4NameAtom &operator= ( const MP4NameAtom &src ); +}; + +/// iTMF data-atom. +class MP4DataAtom : public MP4Atom +{ +public: + MP4DataAtom(MP4File &file); + void Read(); + + MP4Integer16Property& typeReserved; + MP4Integer8Property& typeSetIdentifier; + MP4BasicTypeProperty& typeCode; + MP4Integer32Property& locale; + MP4BytesProperty& metadata; +private: + MP4DataAtom(); + MP4DataAtom( const MP4DataAtom &src ); + MP4DataAtom &operator= ( const MP4DataAtom &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +/// QTFF udta data element-atom. +class MP4UdtaElementAtom : public MP4Atom +{ +public: + MP4UdtaElementAtom( MP4File &file, const char* type ); + void Read(); + + MP4BytesProperty& value; +private: + MP4UdtaElementAtom(); + MP4UdtaElementAtom( const MP4UdtaElementAtom &src ); + MP4UdtaElementAtom &operator= ( const MP4UdtaElementAtom &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_ATOMS_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/bmff.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/bmff.h new file mode 100644 index 00000000..8fa3020c --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/bmff.h @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_BMFF_BMFF_H +#define MP4V2_IMPL_BMFF_BMFF_H + +/// @namespace mp4v2::impl::bmff (private) ISO base media file format. +/// <b>WARNING: THIS IS A PRIVATE NAMESPACE. NOT FOR PUBLIC CONSUMPTION.</b> +/// +/// This namespace implements some features that are specified by +/// ISO base media file format, ISO/IEC 14496-12:2005(E). +/// +namespace mp4v2 { namespace impl { namespace bmff { + ; +}}} + +/////////////////////////////////////////////////////////////////////////////// + +//#include "type.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_BMFF_BMFF_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/impl.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/impl.h new file mode 100644 index 00000000..b2478072 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/impl.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_BMFF_IMPL_H +#define MP4V2_IMPL_BMFF_IMPL_H + +/////////////////////////////////////////////////////////////////////////////// + +#include "src/impl.h" +#include "bmff.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_BMFF_IMPL_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/typebmff.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/typebmff.cpp new file mode 100644 index 00000000..e027a451 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/typebmff.cpp @@ -0,0 +1,531 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const bmff::EnumLanguageCode::Entry bmff::EnumLanguageCode::data[] = { + { mp4v2::impl::bmff::ILC_AAR, "aar", "Afar" }, + { mp4v2::impl::bmff::ILC_ABK, "abk", "Abkhazian" }, + { mp4v2::impl::bmff::ILC_ACE, "ace", "Achinese" }, + { mp4v2::impl::bmff::ILC_ACH, "ach", "Acoli" }, + { mp4v2::impl::bmff::ILC_ADA, "ada", "Adangme" }, + { mp4v2::impl::bmff::ILC_ADY, "ady", "Adyghe; Adygei" }, + { mp4v2::impl::bmff::ILC_AFA, "afa", "Afro-Asiatic (Other)" }, + { mp4v2::impl::bmff::ILC_AFH, "afh", "Afrihili" }, + { mp4v2::impl::bmff::ILC_AFR, "afr", "Afrikaans" }, + { mp4v2::impl::bmff::ILC_AIN, "ain", "Ainu" }, + { mp4v2::impl::bmff::ILC_AKA, "aka", "Akan" }, + { mp4v2::impl::bmff::ILC_AKK, "akk", "Akkadian" }, + { mp4v2::impl::bmff::ILC_SQI, "sqi", "Albanian" }, + { mp4v2::impl::bmff::ILC_ALE, "ale", "Aleut" }, + { mp4v2::impl::bmff::ILC_ALG, "alg", "Algonquian languages" }, + { mp4v2::impl::bmff::ILC_ALT, "alt", "Southern Altai" }, + { mp4v2::impl::bmff::ILC_AMH, "amh", "Amharic" }, + { mp4v2::impl::bmff::ILC_ANG, "ang", "English, Old (ca.450-1100)" }, + { mp4v2::impl::bmff::ILC_ANP, "anp", "Angika" }, + { mp4v2::impl::bmff::ILC_APA, "apa", "Apache languages" }, + { mp4v2::impl::bmff::ILC_ARA, "ara", "Arabic" }, + { mp4v2::impl::bmff::ILC_ARC, "arc", "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)" }, + { mp4v2::impl::bmff::ILC_ARG, "arg", "Aragonese" }, + { mp4v2::impl::bmff::ILC_HYE, "hye", "Armenian" }, + { mp4v2::impl::bmff::ILC_ARN, "arn", "Mapudungun; Mapuche" }, + { mp4v2::impl::bmff::ILC_ARP, "arp", "Arapaho" }, + { mp4v2::impl::bmff::ILC_ART, "art", "Artificial (Other)" }, + { mp4v2::impl::bmff::ILC_ARW, "arw", "Arawak" }, + { mp4v2::impl::bmff::ILC_ASM, "asm", "Assamese" }, + { mp4v2::impl::bmff::ILC_AST, "ast", "Asturian; Bable; Leonese; Asturleonese" }, + { mp4v2::impl::bmff::ILC_ATH, "ath", "Athapascan languages" }, + { mp4v2::impl::bmff::ILC_AUS, "aus", "Australian languages" }, + { mp4v2::impl::bmff::ILC_AVA, "ava", "Avaric" }, + { mp4v2::impl::bmff::ILC_AVE, "ave", "Avestan" }, + { mp4v2::impl::bmff::ILC_AWA, "awa", "Awadhi" }, + { mp4v2::impl::bmff::ILC_AYM, "aym", "Aymara" }, + { mp4v2::impl::bmff::ILC_AZE, "aze", "Azerbaijani" }, + { mp4v2::impl::bmff::ILC_BAD, "bad", "Banda languages" }, + { mp4v2::impl::bmff::ILC_BAI, "bai", "Bamileke languages" }, + { mp4v2::impl::bmff::ILC_BAK, "bak", "Bashkir" }, + { mp4v2::impl::bmff::ILC_BAL, "bal", "Baluchi" }, + { mp4v2::impl::bmff::ILC_BAM, "bam", "Bambara" }, + { mp4v2::impl::bmff::ILC_BAN, "ban", "Balinese" }, + { mp4v2::impl::bmff::ILC_EUS, "eus", "Basque" }, + { mp4v2::impl::bmff::ILC_BAS, "bas", "Basa" }, + { mp4v2::impl::bmff::ILC_BAT, "bat", "Baltic (Other)" }, + { mp4v2::impl::bmff::ILC_BEJ, "bej", "Beja; Bedawiyet" }, + { mp4v2::impl::bmff::ILC_BEL, "bel", "Belarusian" }, + { mp4v2::impl::bmff::ILC_BEM, "bem", "Bemba" }, + { mp4v2::impl::bmff::ILC_BEN, "ben", "Bengali" }, + { mp4v2::impl::bmff::ILC_BER, "ber", "Berber (Other)" }, + { mp4v2::impl::bmff::ILC_BHO, "bho", "Bhojpuri" }, + { mp4v2::impl::bmff::ILC_BIH, "bih", "Bihari" }, + { mp4v2::impl::bmff::ILC_BIK, "bik", "Bikol" }, + { mp4v2::impl::bmff::ILC_BIN, "bin", "Bini; Edo" }, + { mp4v2::impl::bmff::ILC_BIS, "bis", "Bislama" }, + { mp4v2::impl::bmff::ILC_BLA, "bla", "Siksika" }, + { mp4v2::impl::bmff::ILC_BNT, "bnt", "Bantu (Other)" }, + { mp4v2::impl::bmff::ILC_BOS, "bos", "Bosnian" }, + { mp4v2::impl::bmff::ILC_BRA, "bra", "Braj" }, + { mp4v2::impl::bmff::ILC_BRE, "bre", "Breton" }, + { mp4v2::impl::bmff::ILC_BTK, "btk", "Batak languages" }, + { mp4v2::impl::bmff::ILC_BUA, "bua", "Buriat" }, + { mp4v2::impl::bmff::ILC_BUG, "bug", "Buginese" }, + { mp4v2::impl::bmff::ILC_BUL, "bul", "Bulgarian" }, + { mp4v2::impl::bmff::ILC_MYA, "mya", "Burmese" }, + { mp4v2::impl::bmff::ILC_BYN, "byn", "Blin; Bilin" }, + { mp4v2::impl::bmff::ILC_CAD, "cad", "Caddo" }, + { mp4v2::impl::bmff::ILC_CAI, "cai", "Central American Indian (Other)" }, + { mp4v2::impl::bmff::ILC_CAR, "car", "Galibi Carib" }, + { mp4v2::impl::bmff::ILC_CAT, "cat", "Catalan; Valencian" }, + { mp4v2::impl::bmff::ILC_CAU, "cau", "Caucasian (Other)" }, + { mp4v2::impl::bmff::ILC_CEB, "ceb", "Cebuano" }, + { mp4v2::impl::bmff::ILC_CEL, "cel", "Celtic (Other)" }, + { mp4v2::impl::bmff::ILC_CHA, "cha", "Chamorro" }, + { mp4v2::impl::bmff::ILC_CHB, "chb", "Chibcha" }, + { mp4v2::impl::bmff::ILC_CHE, "che", "Chechen" }, + { mp4v2::impl::bmff::ILC_CHG, "chg", "Chagatai" }, + { mp4v2::impl::bmff::ILC_ZHO, "zho", "Chinese" }, + { mp4v2::impl::bmff::ILC_CHK, "chk", "Chuukese" }, + { mp4v2::impl::bmff::ILC_CHM, "chm", "Mari" }, + { mp4v2::impl::bmff::ILC_CHN, "chn", "Chinook jargon" }, + { mp4v2::impl::bmff::ILC_CHO, "cho", "Choctaw" }, + { mp4v2::impl::bmff::ILC_CHP, "chp", "Chipewyan; Dene Suline" }, + { mp4v2::impl::bmff::ILC_CHR, "chr", "Cherokee" }, + { mp4v2::impl::bmff::ILC_CHU, "chu", "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic" }, + { mp4v2::impl::bmff::ILC_CHV, "chv", "Chuvash" }, + { mp4v2::impl::bmff::ILC_CHY, "chy", "Cheyenne" }, + { mp4v2::impl::bmff::ILC_CMC, "cmc", "Chamic languages" }, + { mp4v2::impl::bmff::ILC_COP, "cop", "Coptic" }, + { mp4v2::impl::bmff::ILC_COR, "cor", "Cornish" }, + { mp4v2::impl::bmff::ILC_COS, "cos", "Corsican" }, + { mp4v2::impl::bmff::ILC_CPE, "cpe", "Creoles and pidgins, English based (Other)" }, + { mp4v2::impl::bmff::ILC_CPF, "cpf", "Creoles and pidgins, French-based (Other)" }, + { mp4v2::impl::bmff::ILC_CPP, "cpp", "Creoles and pidgins, Portuguese-based (Other)" }, + { mp4v2::impl::bmff::ILC_CRE, "cre", "Cree" }, + { mp4v2::impl::bmff::ILC_CRH, "crh", "Crimean Tatar; Crimean Turkish" }, + { mp4v2::impl::bmff::ILC_CRP, "crp", "Creoles and pidgins (Other)" }, + { mp4v2::impl::bmff::ILC_CSB, "csb", "Kashubian" }, + { mp4v2::impl::bmff::ILC_CUS, "cus", "Cushitic (Other)" }, + { mp4v2::impl::bmff::ILC_CES, "ces", "Czech" }, + { mp4v2::impl::bmff::ILC_DAK, "dak", "Dakota" }, + { mp4v2::impl::bmff::ILC_DAN, "dan", "Danish" }, + { mp4v2::impl::bmff::ILC_DAR, "dar", "Dargwa" }, + { mp4v2::impl::bmff::ILC_DAY, "day", "Land Dayak languages" }, + { mp4v2::impl::bmff::ILC_DEL, "del", "Delaware" }, + { mp4v2::impl::bmff::ILC_DEN, "den", "Slave (Athapascan)" }, + { mp4v2::impl::bmff::ILC_DGR, "dgr", "Dogrib" }, + { mp4v2::impl::bmff::ILC_DIN, "din", "Dinka" }, + { mp4v2::impl::bmff::ILC_DIV, "div", "Divehi; Dhivehi; Maldivian" }, + { mp4v2::impl::bmff::ILC_DOI, "doi", "Dogri" }, + { mp4v2::impl::bmff::ILC_DRA, "dra", "Dravidian (Other)" }, + { mp4v2::impl::bmff::ILC_DSB, "dsb", "Lower Sorbian" }, + { mp4v2::impl::bmff::ILC_DUA, "dua", "Duala" }, + { mp4v2::impl::bmff::ILC_DUM, "dum", "Dutch, Middle (ca.1050-1350)" }, + { mp4v2::impl::bmff::ILC_NLD, "nld", "Dutch; Flemish" }, + { mp4v2::impl::bmff::ILC_DYU, "dyu", "Dyula" }, + { mp4v2::impl::bmff::ILC_DZO, "dzo", "Dzongkha" }, + { mp4v2::impl::bmff::ILC_EFI, "efi", "Efik" }, + { mp4v2::impl::bmff::ILC_EGY, "egy", "Egyptian (Ancient)" }, + { mp4v2::impl::bmff::ILC_EKA, "eka", "Ekajuk" }, + { mp4v2::impl::bmff::ILC_ELX, "elx", "Elamite" }, + { mp4v2::impl::bmff::ILC_ENG, "eng", "English" }, + { mp4v2::impl::bmff::ILC_ENM, "enm", "English, Middle (1100-1500)" }, + { mp4v2::impl::bmff::ILC_EPO, "epo", "Esperanto" }, + { mp4v2::impl::bmff::ILC_EST, "est", "Estonian" }, + { mp4v2::impl::bmff::ILC_EWE, "ewe", "Ewe" }, + { mp4v2::impl::bmff::ILC_EWO, "ewo", "Ewondo" }, + { mp4v2::impl::bmff::ILC_FAN, "fan", "Fang" }, + { mp4v2::impl::bmff::ILC_FAO, "fao", "Faroese" }, + { mp4v2::impl::bmff::ILC_FAT, "fat", "Fanti" }, + { mp4v2::impl::bmff::ILC_FIJ, "fij", "Fijian" }, + { mp4v2::impl::bmff::ILC_FIL, "fil", "Filipino; Pilipino" }, + { mp4v2::impl::bmff::ILC_FIN, "fin", "Finnish" }, + { mp4v2::impl::bmff::ILC_FIU, "fiu", "Finno-Ugrian (Other)" }, + { mp4v2::impl::bmff::ILC_FON, "fon", "Fon" }, + { mp4v2::impl::bmff::ILC_FRA, "fra", "French" }, + { mp4v2::impl::bmff::ILC_FRM, "frm", "French, Middle (ca.1400-1600)" }, + { mp4v2::impl::bmff::ILC_FRO, "fro", "French, Old (842-ca.1400)" }, + { mp4v2::impl::bmff::ILC_FRR, "frr", "Northern Frisian" }, + { mp4v2::impl::bmff::ILC_FRS, "frs", "Eastern Frisian" }, + { mp4v2::impl::bmff::ILC_FRY, "fry", "Western Frisian" }, + { mp4v2::impl::bmff::ILC_FUL, "ful", "Fulah" }, + { mp4v2::impl::bmff::ILC_FUR, "fur", "Friulian" }, + { mp4v2::impl::bmff::ILC_GAA, "gaa", "Ga" }, + { mp4v2::impl::bmff::ILC_GAY, "gay", "Gayo" }, + { mp4v2::impl::bmff::ILC_GBA, "gba", "Gbaya" }, + { mp4v2::impl::bmff::ILC_GEM, "gem", "Germanic (Other)" }, + { mp4v2::impl::bmff::ILC_KAT, "kat", "Georgian" }, + { mp4v2::impl::bmff::ILC_DEU, "deu", "German" }, + { mp4v2::impl::bmff::ILC_GEZ, "gez", "Geez" }, + { mp4v2::impl::bmff::ILC_GIL, "gil", "Gilbertese" }, + { mp4v2::impl::bmff::ILC_GLA, "gla", "Gaelic; Scottish Gaelic" }, + { mp4v2::impl::bmff::ILC_GLE, "gle", "Irish" }, + { mp4v2::impl::bmff::ILC_GLG, "glg", "Galician" }, + { mp4v2::impl::bmff::ILC_GLV, "glv", "Manx" }, + { mp4v2::impl::bmff::ILC_GMH, "gmh", "German, Middle High (ca.1050-1500)" }, + { mp4v2::impl::bmff::ILC_GOH, "goh", "German, Old High (ca.750-1050)" }, + { mp4v2::impl::bmff::ILC_GON, "gon", "Gondi" }, + { mp4v2::impl::bmff::ILC_GOR, "gor", "Gorontalo" }, + { mp4v2::impl::bmff::ILC_GOT, "got", "Gothic" }, + { mp4v2::impl::bmff::ILC_GRB, "grb", "Grebo" }, + { mp4v2::impl::bmff::ILC_GRC, "grc", "Greek, Ancient (to 1453)" }, + { mp4v2::impl::bmff::ILC_ELL, "ell", "Greek, Modern (1453-)" }, + { mp4v2::impl::bmff::ILC_GRN, "grn", "Guarani" }, + { mp4v2::impl::bmff::ILC_GSW, "gsw", "Swiss German; Alemannic; Alsatian" }, + { mp4v2::impl::bmff::ILC_GUJ, "guj", "Gujarati" }, + { mp4v2::impl::bmff::ILC_GWI, "gwi", "Gwich'in" }, + { mp4v2::impl::bmff::ILC_HAI, "hai", "Haida" }, + { mp4v2::impl::bmff::ILC_HAT, "hat", "Haitian; Haitian Creole" }, + { mp4v2::impl::bmff::ILC_HAU, "hau", "Hausa" }, + { mp4v2::impl::bmff::ILC_HAW, "haw", "Hawaiian" }, + { mp4v2::impl::bmff::ILC_HEB, "heb", "Hebrew" }, + { mp4v2::impl::bmff::ILC_HER, "her", "Herero" }, + { mp4v2::impl::bmff::ILC_HIL, "hil", "Hiligaynon" }, + { mp4v2::impl::bmff::ILC_HIM, "him", "Himachali" }, + { mp4v2::impl::bmff::ILC_HIN, "hin", "Hindi" }, + { mp4v2::impl::bmff::ILC_HIT, "hit", "Hittite" }, + { mp4v2::impl::bmff::ILC_HMN, "hmn", "Hmong" }, + { mp4v2::impl::bmff::ILC_HMO, "hmo", "Hiri Motu" }, + { mp4v2::impl::bmff::ILC_HRV, "hrv", "Croatian" }, + { mp4v2::impl::bmff::ILC_HSB, "hsb", "Upper Sorbian" }, + { mp4v2::impl::bmff::ILC_HUN, "hun", "Hungarian" }, + { mp4v2::impl::bmff::ILC_HUP, "hup", "Hupa" }, + { mp4v2::impl::bmff::ILC_IBA, "iba", "Iban" }, + { mp4v2::impl::bmff::ILC_IBO, "ibo", "Igbo" }, + { mp4v2::impl::bmff::ILC_ISL, "isl", "Icelandic" }, + { mp4v2::impl::bmff::ILC_IDO, "ido", "Ido" }, + { mp4v2::impl::bmff::ILC_III, "iii", "Sichuan Yi; Nuosu" }, + { mp4v2::impl::bmff::ILC_IJO, "ijo", "Ijo languages" }, + { mp4v2::impl::bmff::ILC_IKU, "iku", "Inuktitut" }, + { mp4v2::impl::bmff::ILC_ILE, "ile", "Interlingue; Occidental" }, + { mp4v2::impl::bmff::ILC_ILO, "ilo", "Iloko" }, + { mp4v2::impl::bmff::ILC_INA, "ina", "Interlingua (International Auxiliary Language Association)" }, + { mp4v2::impl::bmff::ILC_INC, "inc", "Indic (Other)" }, + { mp4v2::impl::bmff::ILC_IND, "ind", "Indonesian" }, + { mp4v2::impl::bmff::ILC_INE, "ine", "Indo-European (Other)" }, + { mp4v2::impl::bmff::ILC_INH, "inh", "Ingush" }, + { mp4v2::impl::bmff::ILC_IPK, "ipk", "Inupiaq" }, + { mp4v2::impl::bmff::ILC_IRA, "ira", "Iranian (Other)" }, + { mp4v2::impl::bmff::ILC_IRO, "iro", "Iroquoian languages" }, + { mp4v2::impl::bmff::ILC_ITA, "ita", "Italian" }, + { mp4v2::impl::bmff::ILC_JAV, "jav", "Javanese" }, + { mp4v2::impl::bmff::ILC_JBO, "jbo", "Lojban" }, + { mp4v2::impl::bmff::ILC_JPN, "jpn", "Japanese" }, + { mp4v2::impl::bmff::ILC_JPR, "jpr", "Judeo-Persian" }, + { mp4v2::impl::bmff::ILC_JRB, "jrb", "Judeo-Arabic" }, + { mp4v2::impl::bmff::ILC_KAA, "kaa", "Kara-Kalpak" }, + { mp4v2::impl::bmff::ILC_KAB, "kab", "Kabyle" }, + { mp4v2::impl::bmff::ILC_KAC, "kac", "Kachin; Jingpho" }, + { mp4v2::impl::bmff::ILC_KAL, "kal", "Kalaallisut; Greenlandic" }, + { mp4v2::impl::bmff::ILC_KAM, "kam", "Kamba" }, + { mp4v2::impl::bmff::ILC_KAN, "kan", "Kannada" }, + { mp4v2::impl::bmff::ILC_KAR, "kar", "Karen languages" }, + { mp4v2::impl::bmff::ILC_KAS, "kas", "Kashmiri" }, + { mp4v2::impl::bmff::ILC_KAU, "kau", "Kanuri" }, + { mp4v2::impl::bmff::ILC_KAW, "kaw", "Kawi" }, + { mp4v2::impl::bmff::ILC_KAZ, "kaz", "Kazakh" }, + { mp4v2::impl::bmff::ILC_KBD, "kbd", "Kabardian" }, + { mp4v2::impl::bmff::ILC_KHA, "kha", "Khasi" }, + { mp4v2::impl::bmff::ILC_KHI, "khi", "Khoisan (Other)" }, + { mp4v2::impl::bmff::ILC_KHM, "khm", "Central Khmer" }, + { mp4v2::impl::bmff::ILC_KHO, "kho", "Khotanese; Sakan" }, + { mp4v2::impl::bmff::ILC_KIK, "kik", "Kikuyu; Gikuyu" }, + { mp4v2::impl::bmff::ILC_KIN, "kin", "Kinyarwanda" }, + { mp4v2::impl::bmff::ILC_KIR, "kir", "Kirghiz; Kyrgyz" }, + { mp4v2::impl::bmff::ILC_KMB, "kmb", "Kimbundu" }, + { mp4v2::impl::bmff::ILC_KOK, "kok", "Konkani" }, + { mp4v2::impl::bmff::ILC_KOM, "kom", "Komi" }, + { mp4v2::impl::bmff::ILC_KON, "kon", "Kongo" }, + { mp4v2::impl::bmff::ILC_KOR, "kor", "Korean" }, + { mp4v2::impl::bmff::ILC_KOS, "kos", "Kosraean" }, + { mp4v2::impl::bmff::ILC_KPE, "kpe", "Kpelle" }, + { mp4v2::impl::bmff::ILC_KRC, "krc", "Karachay-Balkar" }, + { mp4v2::impl::bmff::ILC_KRL, "krl", "Karelian" }, + { mp4v2::impl::bmff::ILC_KRO, "kro", "Kru languages" }, + { mp4v2::impl::bmff::ILC_KRU, "kru", "Kurukh" }, + { mp4v2::impl::bmff::ILC_KUA, "kua", "Kuanyama; Kwanyama" }, + { mp4v2::impl::bmff::ILC_KUM, "kum", "Kumyk" }, + { mp4v2::impl::bmff::ILC_KUR, "kur", "Kurdish" }, + { mp4v2::impl::bmff::ILC_KUT, "kut", "Kutenai" }, + { mp4v2::impl::bmff::ILC_LAD, "lad", "Ladino" }, + { mp4v2::impl::bmff::ILC_LAH, "lah", "Lahnda" }, + { mp4v2::impl::bmff::ILC_LAM, "lam", "Lamba" }, + { mp4v2::impl::bmff::ILC_LAO, "lao", "Lao" }, + { mp4v2::impl::bmff::ILC_LAT, "lat", "Latin" }, + { mp4v2::impl::bmff::ILC_LAV, "lav", "Latvian" }, + { mp4v2::impl::bmff::ILC_LEZ, "lez", "Lezghian" }, + { mp4v2::impl::bmff::ILC_LIM, "lim", "Limburgan; Limburger; Limburgish" }, + { mp4v2::impl::bmff::ILC_LIN, "lin", "Lingala" }, + { mp4v2::impl::bmff::ILC_LIT, "lit", "Lithuanian" }, + { mp4v2::impl::bmff::ILC_LOL, "lol", "Mongo" }, + { mp4v2::impl::bmff::ILC_LOZ, "loz", "Lozi" }, + { mp4v2::impl::bmff::ILC_LTZ, "ltz", "Luxembourgish; Letzeburgesch" }, + { mp4v2::impl::bmff::ILC_LUA, "lua", "Luba-Lulua" }, + { mp4v2::impl::bmff::ILC_LUB, "lub", "Luba-Katanga" }, + { mp4v2::impl::bmff::ILC_LUG, "lug", "Ganda" }, + { mp4v2::impl::bmff::ILC_LUI, "lui", "Luiseno" }, + { mp4v2::impl::bmff::ILC_LUN, "lun", "Lunda" }, + { mp4v2::impl::bmff::ILC_LUO, "luo", "Luo (Kenya and Tanzania)" }, + { mp4v2::impl::bmff::ILC_LUS, "lus", "Lushai" }, + { mp4v2::impl::bmff::ILC_MKD, "mkd", "Macedonian" }, + { mp4v2::impl::bmff::ILC_MAD, "mad", "Madurese" }, + { mp4v2::impl::bmff::ILC_MAG, "mag", "Magahi" }, + { mp4v2::impl::bmff::ILC_MAH, "mah", "Marshallese" }, + { mp4v2::impl::bmff::ILC_MAI, "mai", "Maithili" }, + { mp4v2::impl::bmff::ILC_MAK, "mak", "Makasar" }, + { mp4v2::impl::bmff::ILC_MAL, "mal", "Malayalam" }, + { mp4v2::impl::bmff::ILC_MAN, "man", "Mandingo" }, + { mp4v2::impl::bmff::ILC_MRI, "mri", "Maori" }, + { mp4v2::impl::bmff::ILC_MAP, "map", "Austronesian (Other)" }, + { mp4v2::impl::bmff::ILC_MAR, "mar", "Marathi" }, + { mp4v2::impl::bmff::ILC_MAS, "mas", "Masai" }, + { mp4v2::impl::bmff::ILC_MSA, "msa", "Malay" }, + { mp4v2::impl::bmff::ILC_MDF, "mdf", "Moksha" }, + { mp4v2::impl::bmff::ILC_MDR, "mdr", "Mandar" }, + { mp4v2::impl::bmff::ILC_MEN, "men", "Mende" }, + { mp4v2::impl::bmff::ILC_MGA, "mga", "Irish, Middle (900-1200)" }, + { mp4v2::impl::bmff::ILC_MIC, "mic", "Mi'kmaq; Micmac" }, + { mp4v2::impl::bmff::ILC_MIN, "min", "Minangkabau" }, + { mp4v2::impl::bmff::ILC_MIS, "mis", "Uncoded languages" }, + { mp4v2::impl::bmff::ILC_MKH, "mkh", "Mon-Khmer (Other)" }, + { mp4v2::impl::bmff::ILC_MLG, "mlg", "Malagasy" }, + { mp4v2::impl::bmff::ILC_MLT, "mlt", "Maltese" }, + { mp4v2::impl::bmff::ILC_MNC, "mnc", "Manchu" }, + { mp4v2::impl::bmff::ILC_MNI, "mni", "Manipuri" }, + { mp4v2::impl::bmff::ILC_MNO, "mno", "Manobo languages" }, + { mp4v2::impl::bmff::ILC_MOH, "moh", "Mohawk" }, + { mp4v2::impl::bmff::ILC_MON, "mon", "Mongolian" }, + { mp4v2::impl::bmff::ILC_MOS, "mos", "Mossi" }, + { mp4v2::impl::bmff::ILC_MUL, "mul", "Multiple languages" }, + { mp4v2::impl::bmff::ILC_MUN, "mun", "Munda languages" }, + { mp4v2::impl::bmff::ILC_MUS, "mus", "Creek" }, + { mp4v2::impl::bmff::ILC_MWL, "mwl", "Mirandese" }, + { mp4v2::impl::bmff::ILC_MWR, "mwr", "Marwari" }, + { mp4v2::impl::bmff::ILC_MYN, "myn", "Mayan languages" }, + { mp4v2::impl::bmff::ILC_MYV, "myv", "Erzya" }, + { mp4v2::impl::bmff::ILC_NAH, "nah", "Nahuatl languages" }, + { mp4v2::impl::bmff::ILC_NAI, "nai", "North American Indian" }, + { mp4v2::impl::bmff::ILC_NAP, "nap", "Neapolitan" }, + { mp4v2::impl::bmff::ILC_NAU, "nau", "Nauru" }, + { mp4v2::impl::bmff::ILC_NAV, "nav", "Navajo; Navaho" }, + { mp4v2::impl::bmff::ILC_NBL, "nbl", "Ndebele, South; South Ndebele" }, + { mp4v2::impl::bmff::ILC_NDE, "nde", "Ndebele, North; North Ndebele" }, + { mp4v2::impl::bmff::ILC_NDO, "ndo", "Ndonga" }, + { mp4v2::impl::bmff::ILC_NDS, "nds", "Low German; Low Saxon; German, Low; Saxon, Low" }, + { mp4v2::impl::bmff::ILC_NEP, "nep", "Nepali" }, + { mp4v2::impl::bmff::ILC_NEW, "new", "Nepal Bhasa; Newari" }, + { mp4v2::impl::bmff::ILC_NIA, "nia", "Nias" }, + { mp4v2::impl::bmff::ILC_NIC, "nic", "Niger-Kordofanian (Other)" }, + { mp4v2::impl::bmff::ILC_NIU, "niu", "Niuean" }, + { mp4v2::impl::bmff::ILC_NNO, "nno", "Norwegian Nynorsk; Nynorsk, Norwegian" }, + { mp4v2::impl::bmff::ILC_NOB, "nob", "BokmÃ¥l, Norwegian; Norwegian BokmÃ¥l" }, + { mp4v2::impl::bmff::ILC_NOG, "nog", "Nogai" }, + { mp4v2::impl::bmff::ILC_NON, "non", "Norse, Old" }, + { mp4v2::impl::bmff::ILC_NOR, "nor", "Norwegian" }, + { mp4v2::impl::bmff::ILC_NQO, "nqo", "N'Ko" }, + { mp4v2::impl::bmff::ILC_NSO, "nso", "Pedi; Sepedi; Northern Sotho" }, + { mp4v2::impl::bmff::ILC_NUB, "nub", "Nubian languages" }, + { mp4v2::impl::bmff::ILC_NWC, "nwc", "Classical Newari; Old Newari; Classical Nepal Bhasa" }, + { mp4v2::impl::bmff::ILC_NYA, "nya", "Chichewa; Chewa; Nyanja" }, + { mp4v2::impl::bmff::ILC_NYM, "nym", "Nyamwezi" }, + { mp4v2::impl::bmff::ILC_NYN, "nyn", "Nyankole" }, + { mp4v2::impl::bmff::ILC_NYO, "nyo", "Nyoro" }, + { mp4v2::impl::bmff::ILC_NZI, "nzi", "Nzima" }, + { mp4v2::impl::bmff::ILC_OCI, "oci", "Occitan (post 1500); Provençal" }, + { mp4v2::impl::bmff::ILC_OJI, "oji", "Ojibwa" }, + { mp4v2::impl::bmff::ILC_ORI, "ori", "Oriya" }, + { mp4v2::impl::bmff::ILC_ORM, "orm", "Oromo" }, + { mp4v2::impl::bmff::ILC_OSA, "osa", "Osage" }, + { mp4v2::impl::bmff::ILC_OSS, "oss", "Ossetian; Ossetic" }, + { mp4v2::impl::bmff::ILC_OTA, "ota", "Turkish, Ottoman (1500-1928)" }, + { mp4v2::impl::bmff::ILC_OTO, "oto", "Otomian languages" }, + { mp4v2::impl::bmff::ILC_PAA, "paa", "Papuan (Other)" }, + { mp4v2::impl::bmff::ILC_PAG, "pag", "Pangasinan" }, + { mp4v2::impl::bmff::ILC_PAL, "pal", "Pahlavi" }, + { mp4v2::impl::bmff::ILC_PAM, "pam", "Pampanga; Kapampangan" }, + { mp4v2::impl::bmff::ILC_PAN, "pan", "Panjabi; Punjabi" }, + { mp4v2::impl::bmff::ILC_PAP, "pap", "Papiamento" }, + { mp4v2::impl::bmff::ILC_PAU, "pau", "Palauan" }, + { mp4v2::impl::bmff::ILC_PEO, "peo", "Persian, Old (ca.600-400 B.C.)" }, + { mp4v2::impl::bmff::ILC_FAS, "fas", "Persian" }, + { mp4v2::impl::bmff::ILC_PHI, "phi", "Philippine (Other)" }, + { mp4v2::impl::bmff::ILC_PHN, "phn", "Phoenician" }, + { mp4v2::impl::bmff::ILC_PLI, "pli", "Pali" }, + { mp4v2::impl::bmff::ILC_POL, "pol", "Polish" }, + { mp4v2::impl::bmff::ILC_PON, "pon", "Pohnpeian" }, + { mp4v2::impl::bmff::ILC_POR, "por", "Portuguese" }, + { mp4v2::impl::bmff::ILC_PRA, "pra", "Prakrit languages" }, + { mp4v2::impl::bmff::ILC_PRO, "pro", "Provençal, Old (to 1500)" }, + { mp4v2::impl::bmff::ILC_PUS, "pus", "Pushto; Pashto" }, + { mp4v2::impl::bmff::ILC_QUE, "que", "Quechua" }, + { mp4v2::impl::bmff::ILC_RAJ, "raj", "Rajasthani" }, + { mp4v2::impl::bmff::ILC_RAP, "rap", "Rapanui" }, + { mp4v2::impl::bmff::ILC_RAR, "rar", "Rarotongan; Cook Islands Maori" }, + { mp4v2::impl::bmff::ILC_ROA, "roa", "Romance (Other)" }, + { mp4v2::impl::bmff::ILC_ROH, "roh", "Romansh" }, + { mp4v2::impl::bmff::ILC_ROM, "rom", "Romany" }, + { mp4v2::impl::bmff::ILC_RON, "ron", "Romanian; Moldavian; Moldovan" }, + { mp4v2::impl::bmff::ILC_RUN, "run", "Rundi" }, + { mp4v2::impl::bmff::ILC_RUP, "rup", "Aromanian; Arumanian; Macedo-Romanian" }, + { mp4v2::impl::bmff::ILC_RUS, "rus", "Russian" }, + { mp4v2::impl::bmff::ILC_SAD, "sad", "Sandawe" }, + { mp4v2::impl::bmff::ILC_SAG, "sag", "Sango" }, + { mp4v2::impl::bmff::ILC_SAH, "sah", "Yakut" }, + { mp4v2::impl::bmff::ILC_SAI, "sai", "South American Indian (Other)" }, + { mp4v2::impl::bmff::ILC_SAL, "sal", "Salishan languages" }, + { mp4v2::impl::bmff::ILC_SAM, "sam", "Samaritan Aramaic" }, + { mp4v2::impl::bmff::ILC_SAN, "san", "Sanskrit" }, + { mp4v2::impl::bmff::ILC_SAS, "sas", "Sasak" }, + { mp4v2::impl::bmff::ILC_SAT, "sat", "Santali" }, + { mp4v2::impl::bmff::ILC_SCN, "scn", "Sicilian" }, + { mp4v2::impl::bmff::ILC_SCO, "sco", "Scots" }, + { mp4v2::impl::bmff::ILC_SEL, "sel", "Selkup" }, + { mp4v2::impl::bmff::ILC_SEM, "sem", "Semitic (Other)" }, + { mp4v2::impl::bmff::ILC_SGA, "sga", "Irish, Old (to 900)" }, + { mp4v2::impl::bmff::ILC_SGN, "sgn", "Sign Languages" }, + { mp4v2::impl::bmff::ILC_SHN, "shn", "Shan" }, + { mp4v2::impl::bmff::ILC_SID, "sid", "Sidamo" }, + { mp4v2::impl::bmff::ILC_SIN, "sin", "Sinhala; Sinhalese" }, + { mp4v2::impl::bmff::ILC_SIO, "sio", "Siouan languages" }, + { mp4v2::impl::bmff::ILC_SIT, "sit", "Sino-Tibetan (Other)" }, + { mp4v2::impl::bmff::ILC_SLA, "sla", "Slavic (Other)" }, + { mp4v2::impl::bmff::ILC_SLK, "slk", "Slovak" }, + { mp4v2::impl::bmff::ILC_SLV, "slv", "Slovenian" }, + { mp4v2::impl::bmff::ILC_SMA, "sma", "Southern Sami" }, + { mp4v2::impl::bmff::ILC_SME, "sme", "Northern Sami" }, + { mp4v2::impl::bmff::ILC_SMI, "smi", "Sami languages (Other)" }, + { mp4v2::impl::bmff::ILC_SMJ, "smj", "Lule Sami" }, + { mp4v2::impl::bmff::ILC_SMN, "smn", "Inari Sami" }, + { mp4v2::impl::bmff::ILC_SMO, "smo", "Samoan" }, + { mp4v2::impl::bmff::ILC_SMS, "sms", "Skolt Sami" }, + { mp4v2::impl::bmff::ILC_SNA, "sna", "Shona" }, + { mp4v2::impl::bmff::ILC_SND, "snd", "Sindhi" }, + { mp4v2::impl::bmff::ILC_SNK, "snk", "Soninke" }, + { mp4v2::impl::bmff::ILC_SOG, "sog", "Sogdian" }, + { mp4v2::impl::bmff::ILC_SOM, "som", "Somali" }, + { mp4v2::impl::bmff::ILC_SON, "son", "Songhai languages" }, + { mp4v2::impl::bmff::ILC_SOT, "sot", "Sotho, Southern" }, + { mp4v2::impl::bmff::ILC_SPA, "spa", "Spanish; Castilian" }, + { mp4v2::impl::bmff::ILC_SRD, "srd", "Sardinian" }, + { mp4v2::impl::bmff::ILC_SRN, "srn", "Sranan Tongo" }, + { mp4v2::impl::bmff::ILC_SRP, "srp", "Serbian" }, + { mp4v2::impl::bmff::ILC_SRR, "srr", "Serer" }, + { mp4v2::impl::bmff::ILC_SSA, "ssa", "Nilo-Saharan (Other)" }, + { mp4v2::impl::bmff::ILC_SSW, "ssw", "Swati" }, + { mp4v2::impl::bmff::ILC_SUK, "suk", "Sukuma" }, + { mp4v2::impl::bmff::ILC_SUN, "sun", "Sundanese" }, + { mp4v2::impl::bmff::ILC_SUS, "sus", "Susu" }, + { mp4v2::impl::bmff::ILC_SUX, "sux", "Sumerian" }, + { mp4v2::impl::bmff::ILC_SWA, "swa", "Swahili" }, + { mp4v2::impl::bmff::ILC_SWE, "swe", "Swedish" }, + { mp4v2::impl::bmff::ILC_SYC, "syc", "Classical Syriac" }, + { mp4v2::impl::bmff::ILC_SYR, "syr", "Syriac" }, + { mp4v2::impl::bmff::ILC_TAH, "tah", "Tahitian" }, + { mp4v2::impl::bmff::ILC_TAI, "tai", "Tai (Other)" }, + { mp4v2::impl::bmff::ILC_TAM, "tam", "Tamil" }, + { mp4v2::impl::bmff::ILC_TAT, "tat", "Tatar" }, + { mp4v2::impl::bmff::ILC_TEL, "tel", "Telugu" }, + { mp4v2::impl::bmff::ILC_TEM, "tem", "Timne" }, + { mp4v2::impl::bmff::ILC_TER, "ter", "Tereno" }, + { mp4v2::impl::bmff::ILC_TET, "tet", "Tetum" }, + { mp4v2::impl::bmff::ILC_TGK, "tgk", "Tajik" }, + { mp4v2::impl::bmff::ILC_TGL, "tgl", "Tagalog" }, + { mp4v2::impl::bmff::ILC_THA, "tha", "Thai" }, + { mp4v2::impl::bmff::ILC_BOD, "bod", "Tibetan" }, + { mp4v2::impl::bmff::ILC_TIG, "tig", "Tigre" }, + { mp4v2::impl::bmff::ILC_TIR, "tir", "Tigrinya" }, + { mp4v2::impl::bmff::ILC_TIV, "tiv", "Tiv" }, + { mp4v2::impl::bmff::ILC_TKL, "tkl", "Tokelau" }, + { mp4v2::impl::bmff::ILC_TLH, "tlh", "Klingon; tlhIngan-Hol" }, + { mp4v2::impl::bmff::ILC_TLI, "tli", "Tlingit" }, + { mp4v2::impl::bmff::ILC_TMH, "tmh", "Tamashek" }, + { mp4v2::impl::bmff::ILC_TOG, "tog", "Tonga (Nyasa)" }, + { mp4v2::impl::bmff::ILC_TON, "ton", "Tonga (Tonga Islands)" }, + { mp4v2::impl::bmff::ILC_TPI, "tpi", "Tok Pisin" }, + { mp4v2::impl::bmff::ILC_TSI, "tsi", "Tsimshian" }, + { mp4v2::impl::bmff::ILC_TSN, "tsn", "Tswana" }, + { mp4v2::impl::bmff::ILC_TSO, "tso", "Tsonga" }, + { mp4v2::impl::bmff::ILC_TUK, "tuk", "Turkmen" }, + { mp4v2::impl::bmff::ILC_TUM, "tum", "Tumbuka" }, + { mp4v2::impl::bmff::ILC_TUP, "tup", "Tupi languages" }, + { mp4v2::impl::bmff::ILC_TUR, "tur", "Turkish" }, + { mp4v2::impl::bmff::ILC_TUT, "tut", "Altaic (Other)" }, + { mp4v2::impl::bmff::ILC_TVL, "tvl", "Tuvalu" }, + { mp4v2::impl::bmff::ILC_TWI, "twi", "Twi" }, + { mp4v2::impl::bmff::ILC_TYV, "tyv", "Tuvinian" }, + { mp4v2::impl::bmff::ILC_UDM, "udm", "Udmurt" }, + { mp4v2::impl::bmff::ILC_UGA, "uga", "Ugaritic" }, + { mp4v2::impl::bmff::ILC_UIG, "uig", "Uighur; Uyghur" }, + { mp4v2::impl::bmff::ILC_UKR, "ukr", "Ukrainian" }, + { mp4v2::impl::bmff::ILC_UMB, "umb", "Umbundu" }, + { mp4v2::impl::bmff::ILC_UND, "und", "Undetermined" }, + { mp4v2::impl::bmff::ILC_URD, "urd", "Urdu" }, + { mp4v2::impl::bmff::ILC_UZB, "uzb", "Uzbek" }, + { mp4v2::impl::bmff::ILC_VAI, "vai", "Vai" }, + { mp4v2::impl::bmff::ILC_VEN, "ven", "Venda" }, + { mp4v2::impl::bmff::ILC_VIE, "vie", "Vietnamese" }, + { mp4v2::impl::bmff::ILC_VOL, "vol", "Volapük" }, + { mp4v2::impl::bmff::ILC_VOT, "vot", "Votic" }, + { mp4v2::impl::bmff::ILC_WAK, "wak", "Wakashan languages" }, + { mp4v2::impl::bmff::ILC_WAL, "wal", "Walamo" }, + { mp4v2::impl::bmff::ILC_WAR, "war", "Waray" }, + { mp4v2::impl::bmff::ILC_WAS, "was", "Washo" }, + { mp4v2::impl::bmff::ILC_CYM, "cym", "Welsh" }, + { mp4v2::impl::bmff::ILC_WEN, "wen", "Sorbian languages" }, + { mp4v2::impl::bmff::ILC_WLN, "wln", "Walloon" }, + { mp4v2::impl::bmff::ILC_WOL, "wol", "Wolof" }, + { mp4v2::impl::bmff::ILC_XAL, "xal", "Kalmyk; Oirat" }, + { mp4v2::impl::bmff::ILC_XHO, "xho", "Xhosa" }, + { mp4v2::impl::bmff::ILC_YAO, "yao", "Yao" }, + { mp4v2::impl::bmff::ILC_YAP, "yap", "Yapese" }, + { mp4v2::impl::bmff::ILC_YID, "yid", "Yiddish" }, + { mp4v2::impl::bmff::ILC_YOR, "yor", "Yoruba" }, + { mp4v2::impl::bmff::ILC_YPK, "ypk", "Yupik languages" }, + { mp4v2::impl::bmff::ILC_ZAP, "zap", "Zapotec" }, + { mp4v2::impl::bmff::ILC_ZBL, "zbl", "Blissymbols; Blissymbolics; Bliss" }, + { mp4v2::impl::bmff::ILC_ZEN, "zen", "Zenaga" }, + { mp4v2::impl::bmff::ILC_ZHA, "zha", "Zhuang; Chuang" }, + { mp4v2::impl::bmff::ILC_ZND, "znd", "Zande languages" }, + { mp4v2::impl::bmff::ILC_ZUL, "zul", "Zulu" }, + { mp4v2::impl::bmff::ILC_ZUN, "zun", "Zuni" }, + { mp4v2::impl::bmff::ILC_ZXX, "zxx", "No linguistic content; Not applicable" }, + { mp4v2::impl::bmff::ILC_ZZA, "zza", "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki" }, + + { mp4v2::impl::bmff::ILC_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +namespace bmff { + +/////////////////////////////////////////////////////////////////////////////// + +// must come after static data init +const EnumLanguageCode enumLanguageCode; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::bmff diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/typebmff.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/typebmff.h new file mode 100644 index 00000000..4b69b7e2 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/bmff/typebmff.h @@ -0,0 +1,528 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_BMFF_TYPE_H +#define MP4V2_IMPL_BMFF_TYPE_H + +namespace mp4v2 { namespace impl { namespace bmff { + +/////////////////////////////////////////////////////////////////////////////// + +/// enumerated ISO-639-2/T language codes. +enum LanguageCode { + ILC_UNDEFINED = 0, + + ILC_AAR, + ILC_ABK, + ILC_ACE, + ILC_ACH, + ILC_ADA, + ILC_ADY, + ILC_AFA, + ILC_AFH, + ILC_AFR, + ILC_AIN, + ILC_AKA, + ILC_AKK, + ILC_SQI, + ILC_ALE, + ILC_ALG, + ILC_ALT, + ILC_AMH, + ILC_ANG, + ILC_ANP, + ILC_APA, + ILC_ARA, + ILC_ARC, + ILC_ARG, + ILC_HYE, + ILC_ARN, + ILC_ARP, + ILC_ART, + ILC_ARW, + ILC_ASM, + ILC_AST, + ILC_ATH, + ILC_AUS, + ILC_AVA, + ILC_AVE, + ILC_AWA, + ILC_AYM, + ILC_AZE, + ILC_BAD, + ILC_BAI, + ILC_BAK, + ILC_BAL, + ILC_BAM, + ILC_BAN, + ILC_EUS, + ILC_BAS, + ILC_BAT, + ILC_BEJ, + ILC_BEL, + ILC_BEM, + ILC_BEN, + ILC_BER, + ILC_BHO, + ILC_BIH, + ILC_BIK, + ILC_BIN, + ILC_BIS, + ILC_BLA, + ILC_BNT, + ILC_BOS, + ILC_BRA, + ILC_BRE, + ILC_BTK, + ILC_BUA, + ILC_BUG, + ILC_BUL, + ILC_MYA, + ILC_BYN, + ILC_CAD, + ILC_CAI, + ILC_CAR, + ILC_CAT, + ILC_CAU, + ILC_CEB, + ILC_CEL, + ILC_CHA, + ILC_CHB, + ILC_CHE, + ILC_CHG, + ILC_ZHO, + ILC_CHK, + ILC_CHM, + ILC_CHN, + ILC_CHO, + ILC_CHP, + ILC_CHR, + ILC_CHU, + ILC_CHV, + ILC_CHY, + ILC_CMC, + ILC_COP, + ILC_COR, + ILC_COS, + ILC_CPE, + ILC_CPF, + ILC_CPP, + ILC_CRE, + ILC_CRH, + ILC_CRP, + ILC_CSB, + ILC_CUS, + ILC_CES, + ILC_DAK, + ILC_DAN, + ILC_DAR, + ILC_DAY, + ILC_DEL, + ILC_DEN, + ILC_DGR, + ILC_DIN, + ILC_DIV, + ILC_DOI, + ILC_DRA, + ILC_DSB, + ILC_DUA, + ILC_DUM, + ILC_NLD, + ILC_DYU, + ILC_DZO, + ILC_EFI, + ILC_EGY, + ILC_EKA, + ILC_ELX, + ILC_ENG, + ILC_ENM, + ILC_EPO, + ILC_EST, + ILC_EWE, + ILC_EWO, + ILC_FAN, + ILC_FAO, + ILC_FAT, + ILC_FIJ, + ILC_FIL, + ILC_FIN, + ILC_FIU, + ILC_FON, + ILC_FRA, + ILC_FRM, + ILC_FRO, + ILC_FRR, + ILC_FRS, + ILC_FRY, + ILC_FUL, + ILC_FUR, + ILC_GAA, + ILC_GAY, + ILC_GBA, + ILC_GEM, + ILC_KAT, + ILC_DEU, + ILC_GEZ, + ILC_GIL, + ILC_GLA, + ILC_GLE, + ILC_GLG, + ILC_GLV, + ILC_GMH, + ILC_GOH, + ILC_GON, + ILC_GOR, + ILC_GOT, + ILC_GRB, + ILC_GRC, + ILC_ELL, + ILC_GRN, + ILC_GSW, + ILC_GUJ, + ILC_GWI, + ILC_HAI, + ILC_HAT, + ILC_HAU, + ILC_HAW, + ILC_HEB, + ILC_HER, + ILC_HIL, + ILC_HIM, + ILC_HIN, + ILC_HIT, + ILC_HMN, + ILC_HMO, + ILC_HRV, + ILC_HSB, + ILC_HUN, + ILC_HUP, + ILC_IBA, + ILC_IBO, + ILC_ISL, + ILC_IDO, + ILC_III, + ILC_IJO, + ILC_IKU, + ILC_ILE, + ILC_ILO, + ILC_INA, + ILC_INC, + ILC_IND, + ILC_INE, + ILC_INH, + ILC_IPK, + ILC_IRA, + ILC_IRO, + ILC_ITA, + ILC_JAV, + ILC_JBO, + ILC_JPN, + ILC_JPR, + ILC_JRB, + ILC_KAA, + ILC_KAB, + ILC_KAC, + ILC_KAL, + ILC_KAM, + ILC_KAN, + ILC_KAR, + ILC_KAS, + ILC_KAU, + ILC_KAW, + ILC_KAZ, + ILC_KBD, + ILC_KHA, + ILC_KHI, + ILC_KHM, + ILC_KHO, + ILC_KIK, + ILC_KIN, + ILC_KIR, + ILC_KMB, + ILC_KOK, + ILC_KOM, + ILC_KON, + ILC_KOR, + ILC_KOS, + ILC_KPE, + ILC_KRC, + ILC_KRL, + ILC_KRO, + ILC_KRU, + ILC_KUA, + ILC_KUM, + ILC_KUR, + ILC_KUT, + ILC_LAD, + ILC_LAH, + ILC_LAM, + ILC_LAO, + ILC_LAT, + ILC_LAV, + ILC_LEZ, + ILC_LIM, + ILC_LIN, + ILC_LIT, + ILC_LOL, + ILC_LOZ, + ILC_LTZ, + ILC_LUA, + ILC_LUB, + ILC_LUG, + ILC_LUI, + ILC_LUN, + ILC_LUO, + ILC_LUS, + ILC_MKD, + ILC_MAD, + ILC_MAG, + ILC_MAH, + ILC_MAI, + ILC_MAK, + ILC_MAL, + ILC_MAN, + ILC_MRI, + ILC_MAP, + ILC_MAR, + ILC_MAS, + ILC_MSA, + ILC_MDF, + ILC_MDR, + ILC_MEN, + ILC_MGA, + ILC_MIC, + ILC_MIN, + ILC_MIS, + ILC_MKH, + ILC_MLG, + ILC_MLT, + ILC_MNC, + ILC_MNI, + ILC_MNO, + ILC_MOH, + ILC_MON, + ILC_MOS, + ILC_MUL, + ILC_MUN, + ILC_MUS, + ILC_MWL, + ILC_MWR, + ILC_MYN, + ILC_MYV, + ILC_NAH, + ILC_NAI, + ILC_NAP, + ILC_NAU, + ILC_NAV, + ILC_NBL, + ILC_NDE, + ILC_NDO, + ILC_NDS, + ILC_NEP, + ILC_NEW, + ILC_NIA, + ILC_NIC, + ILC_NIU, + ILC_NNO, + ILC_NOB, + ILC_NOG, + ILC_NON, + ILC_NOR, + ILC_NQO, + ILC_NSO, + ILC_NUB, + ILC_NWC, + ILC_NYA, + ILC_NYM, + ILC_NYN, + ILC_NYO, + ILC_NZI, + ILC_OCI, + ILC_OJI, + ILC_ORI, + ILC_ORM, + ILC_OSA, + ILC_OSS, + ILC_OTA, + ILC_OTO, + ILC_PAA, + ILC_PAG, + ILC_PAL, + ILC_PAM, + ILC_PAN, + ILC_PAP, + ILC_PAU, + ILC_PEO, + ILC_FAS, + ILC_PHI, + ILC_PHN, + ILC_PLI, + ILC_POL, + ILC_PON, + ILC_POR, + ILC_PRA, + ILC_PRO, + ILC_PUS, + ILC_QUE, + ILC_RAJ, + ILC_RAP, + ILC_RAR, + ILC_ROA, + ILC_ROH, + ILC_ROM, + ILC_RON, + ILC_RUN, + ILC_RUP, + ILC_RUS, + ILC_SAD, + ILC_SAG, + ILC_SAH, + ILC_SAI, + ILC_SAL, + ILC_SAM, + ILC_SAN, + ILC_SAS, + ILC_SAT, + ILC_SCN, + ILC_SCO, + ILC_SEL, + ILC_SEM, + ILC_SGA, + ILC_SGN, + ILC_SHN, + ILC_SID, + ILC_SIN, + ILC_SIO, + ILC_SIT, + ILC_SLA, + ILC_SLK, + ILC_SLV, + ILC_SMA, + ILC_SME, + ILC_SMI, + ILC_SMJ, + ILC_SMN, + ILC_SMO, + ILC_SMS, + ILC_SNA, + ILC_SND, + ILC_SNK, + ILC_SOG, + ILC_SOM, + ILC_SON, + ILC_SOT, + ILC_SPA, + ILC_SRD, + ILC_SRN, + ILC_SRP, + ILC_SRR, + ILC_SSA, + ILC_SSW, + ILC_SUK, + ILC_SUN, + ILC_SUS, + ILC_SUX, + ILC_SWA, + ILC_SWE, + ILC_SYC, + ILC_SYR, + ILC_TAH, + ILC_TAI, + ILC_TAM, + ILC_TAT, + ILC_TEL, + ILC_TEM, + ILC_TER, + ILC_TET, + ILC_TGK, + ILC_TGL, + ILC_THA, + ILC_BOD, + ILC_TIG, + ILC_TIR, + ILC_TIV, + ILC_TKL, + ILC_TLH, + ILC_TLI, + ILC_TMH, + ILC_TOG, + ILC_TON, + ILC_TPI, + ILC_TSI, + ILC_TSN, + ILC_TSO, + ILC_TUK, + ILC_TUM, + ILC_TUP, + ILC_TUR, + ILC_TUT, + ILC_TVL, + ILC_TWI, + ILC_TYV, + ILC_UDM, + ILC_UGA, + ILC_UIG, + ILC_UKR, + ILC_UMB, + ILC_UND, + ILC_URD, + ILC_UZB, + ILC_VAI, + ILC_VEN, + ILC_VIE, + ILC_VOL, + ILC_VOT, + ILC_WAK, + ILC_WAL, + ILC_WAR, + ILC_WAS, + ILC_CYM, + ILC_WEN, + ILC_WLN, + ILC_WOL, + ILC_XAL, + ILC_XHO, + ILC_YAO, + ILC_YAP, + ILC_YID, + ILC_YOR, + ILC_YPK, + ILC_ZAP, + ILC_ZBL, + ILC_ZEN, + ILC_ZHA, + ILC_ZND, + ILC_ZUL, + ILC_ZUN, + ILC_ZXX, + ILC_ZZA, +}; + +typedef Enum<LanguageCode,ILC_UNDEFINED> EnumLanguageCode; +MP4V2_EXPORT extern const EnumLanguageCode enumLanguageCode; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::bmff + +#endif // MP4V2_IMPL_BMFF_TYPE_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/cmeta.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/cmeta.cpp new file mode 100644 index 00000000..b6a7d574 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/cmeta.cpp @@ -0,0 +1,1558 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// Portions created by David Byron are Copyright (C) 2009, 2010, 2011. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// Rouven Wessling, [email protected] +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#include "src/impl.h" + +using namespace mp4v2::impl; + +extern "C" { + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsAddArtwork( const MP4Tags* tags, MP4TagArtwork* artwork ) +{ + if( !tags || !tags->__handle || !artwork ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(tags->__handle); + MP4Tags* c = const_cast<MP4Tags*>(tags); + + try { + cpp.c_addArtwork( c, *artwork ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +const MP4Tags* +MP4TagsAlloc() +{ + MP4Tags* result = NULL; + itmf::Tags* m = NULL; + + try { + m = new itmf::Tags(); + m->c_alloc( result ); + return result; + } + catch( std::bad_alloc ) { + // This could be a failure to allocate itmf::Tags or + // a failure to allocate inside c_alloc. + mp4v2::impl::log.errorf("%s: memory allocation error", __FUNCTION__); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + if( result ) + delete result; + + if( m ) + delete m; + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +MP4TagsFree( const MP4Tags* tags ) +{ + if( !tags || !tags->__handle ) + return; + + itmf::Tags* cpp = static_cast<itmf::Tags*>(tags->__handle); + MP4Tags* c = const_cast<MP4Tags*>(tags); + + try { + cpp->c_free( c ); + delete cpp; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsFetch( const MP4Tags* tags, MP4FileHandle hFile ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + if( !tags || !tags->__handle ) + return false; + + itmf::Tags* cpp = static_cast<itmf::Tags*>(tags->__handle); + MP4Tags* c = const_cast<MP4Tags*>(tags); + + try { + cpp->c_fetch( c, hFile ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsHasMetadata ( const MP4Tags* tags, bool *hasMetadata ) +{ + if( !tags || !tags->__handle || !hasMetadata ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(tags->__handle); + + (*hasMetadata) = cpp.hasMetadata; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsRemoveArtwork( const MP4Tags* tags, uint32_t index ) +{ + if( !tags || !tags->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(tags->__handle); + MP4Tags* c = const_cast<MP4Tags*>(tags); + + try { + cpp.c_removeArtwork( c, index ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsSetArtwork( const MP4Tags* tags, uint32_t index, MP4TagArtwork* artwork ) +{ + if( !tags || !tags->__handle || !artwork) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(tags->__handle); + MP4Tags* c = const_cast<MP4Tags*>(tags); + + try { + cpp.c_setArtwork( c, index, *artwork ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsStore( const MP4Tags* tags, MP4FileHandle hFile ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + if( !tags || !tags->__handle ) + return false; + + itmf::Tags* cpp = static_cast<itmf::Tags*>(tags->__handle); + MP4Tags* c = const_cast<MP4Tags*>(tags); + + try { + cpp->c_store( c, hFile ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4TagsSetName( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.name, c.name ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetArtist( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.artist, c.artist ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetAlbumArtist( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.albumArtist, c.albumArtist ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetAlbum( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.album, c.album ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetGrouping( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.grouping, c.grouping ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetComposer( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.composer, c.composer ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetComments( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.comments, c.comments ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetGenre( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.genre, c.genre ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetGenreType( const MP4Tags* m, const uint16_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.genreType, c.genreType ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetReleaseDate( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.releaseDate, c.releaseDate ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTrack( const MP4Tags* m, const MP4TagTrack* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setTrack( value, cpp.track, c.track ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetDisk( const MP4Tags* m, const MP4TagDisk* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setDisk( value, cpp.disk, c.disk ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTempo( const MP4Tags* m, const uint16_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.tempo, c.tempo ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetCompilation( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.compilation, c.compilation ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTVShow( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.tvShow, c.tvShow ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTVNetwork( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.tvNetwork, c.tvNetwork ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTVEpisodeID( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.tvEpisodeID, c.tvEpisodeID ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTVSeason( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.tvSeason, c.tvSeason ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetTVEpisode( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.tvEpisode, c.tvEpisode ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetSortName( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.sortName, c.sortName ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetSortArtist( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.sortArtist, c.sortArtist ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetSortAlbumArtist( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.sortAlbumArtist, c.sortAlbumArtist ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetSortAlbum( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.sortAlbum, c.sortAlbum ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetSortComposer( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.sortComposer, c.sortComposer ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetSortTVShow( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.sortTVShow, c.sortTVShow ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetDescription( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.description, c.description ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetLongDescription( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.longDescription, c.longDescription ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetLyrics( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.lyrics, c.lyrics ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetCopyright( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.copyright, c.copyright ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetEncodingTool( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.encodingTool, c.encodingTool ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetEncodedBy( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.encodedBy, c.encodedBy ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetPurchaseDate( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.purchaseDate, c.purchaseDate ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetPodcast( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.podcast, c.podcast ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetKeywords( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.keywords, c.keywords ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetCategory( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.category, c.category ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetHDVideo( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.hdVideo, c.hdVideo ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetMediaType( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.mediaType, c.mediaType ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetContentRating( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.contentRating, c.contentRating ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetGapless( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.gapless, c.gapless ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetITunesAccount( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.iTunesAccount, c.iTunesAccount ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetITunesAccountType( const MP4Tags* m, const uint8_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.iTunesAccountType, c.iTunesAccountType ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetITunesCountry( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.iTunesCountry, c.iTunesCountry ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetContentID( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.contentID, c.contentID ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetArtistID( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.artistID, c.artistID ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetPlaylistID( const MP4Tags* m, const uint64_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.playlistID, c.playlistID ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetGenreID( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.genreID, c.genreID ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetComposerID( const MP4Tags* m, const uint32_t* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setInteger( value, cpp.composerID, c.composerID ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +bool +MP4TagsSetXID( const MP4Tags* m, const char* value ) +{ + if( !m || !m->__handle ) + return false; + + itmf::Tags& cpp = *static_cast<itmf::Tags*>(m->__handle); + MP4Tags& c = *const_cast<MP4Tags*>(m); + + try { + cpp.c_setString( value, cpp.xid, c.xid ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItem* +MP4ItmfItemAlloc( const char* code, uint32_t numData ) +{ + return itmf::genericItemAlloc( code, numData ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +MP4ItmfItemFree( MP4ItmfItem* item ) +{ + itmf::genericItemFree( item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +MP4ItmfItemListFree( MP4ItmfItemList* list ) +{ + itmf::genericItemListFree( list ); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +MP4ItmfGetItems( MP4FileHandle hFile ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return NULL; + + try { + return itmf::genericGetItems( *(MP4File*)hFile ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +MP4ItmfGetItemsByCode( MP4FileHandle hFile, const char* code ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return NULL; + + try { + return itmf::genericGetItemsByCode( *(MP4File*)hFile, code ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed",__FUNCTION__); + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +MP4ItmfGetItemsByMeaning( MP4FileHandle hFile, const char* meaning, const char* name ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return NULL; + + if( !meaning ) + return NULL; + + try { + return itmf::genericGetItemsByMeaning( *(MP4File*)hFile, meaning, name ? name : "" ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4ItmfAddItem( MP4FileHandle hFile, const MP4ItmfItem* item ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return itmf::genericAddItem( *(MP4File*)hFile, item ); + } + catch( Exception* x) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4ItmfSetItem( MP4FileHandle hFile, const MP4ItmfItem* item ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return itmf::genericSetItem( *(MP4File*)hFile, item ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +MP4ItmfRemoveItem( MP4FileHandle hFile, const MP4ItmfItem* item ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return itmf::genericRemoveItem( *(MP4File*)hFile, item ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +} // extern "C" diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/descriptors.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/descriptors.cpp new file mode 100644 index 00000000..e83fc66f --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/descriptors.cpp @@ -0,0 +1,616 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4BaseDescriptor::MP4BaseDescriptor (MP4Atom& parentAtom, uint8_t tag) : MP4Descriptor(parentAtom, tag) +{ + switch (tag) { + case MP4ESIDIncDescrTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "id")); + break; + case MP4ESIDRefDescrTag: + AddProperty( /* 0 */ + new MP4Integer16Property(parentAtom, "refIndex")); + break; + case MP4IPIPtrDescrTag: + AddProperty( /* 0 */ + new MP4Integer16Property(parentAtom, "IPIESId")); + break; + case MP4SupplContentIdDescrTag: + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "languageCode", 3)); + AddProperty( /* 1 */ + new MP4StringProperty(parentAtom, "title", Counted)); + AddProperty( /* 2 */ + new MP4StringProperty(parentAtom, "value", Counted)); + break; + case MP4IPMPPtrDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "IPMPDescriptorId")); + break; + case MP4ExtProfileLevelDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "profileLevelIndicationIndex")); + AddProperty( /* 1 */ + new MP4Integer8Property(parentAtom, "ODProfileLevelIndication")); + AddProperty( /* 2 */ + new MP4Integer8Property(parentAtom, "sceneProfileLevelIndication")); + AddProperty( /* 3 */ + new MP4Integer8Property(parentAtom, "audioProfileLevelIndication")); + AddProperty( /* 4 */ + new MP4Integer8Property(parentAtom, "visualProfileLevelIndication")); + AddProperty( /* 5 */ + new MP4Integer8Property(parentAtom, "graphicsProfileLevelIndication")); + AddProperty( /* 6 */ + new MP4Integer8Property(parentAtom, "MPEGJProfileLevelIndication")); + break; + default: + log.errorf("%s: \"%s\": error in base descriptor - tag %u", __FUNCTION__, + m_parentAtom.GetFile().GetFilename().c_str(), tag); + break; + + } +} + +MP4BytesDescriptor::MP4BytesDescriptor (MP4Atom& parentAtom, uint8_t tag) : MP4Descriptor(parentAtom, tag) +{ + m_size_offset = 0; + m_bytes_index = 0; + if (tag >= MP4ExtDescrTagsStart && tag <= MP4ExtDescrTagsEnd) { + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "data")); + } else { + switch (tag) { + case MP4DecSpecificDescrTag: + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "info")); + // no change to m_size + break; + case MP4IPMPDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "IPMPDescriptorId")); + AddProperty( /* 1 */ + new MP4Integer16Property(parentAtom, "IPMPSType")); + AddProperty( /* 2 */ + new MP4BytesProperty(parentAtom, "IPMPData")); + /* note: if IPMPSType == 0, IPMPData is an URL */ + m_size_offset = 3; + m_bytes_index = 2; + break; + case MP4RegistrationDescrTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "formatIdentifier")); + AddProperty( /* 1 */ + new MP4BytesProperty(parentAtom, "additionalIdentificationInfo")); + m_size_offset = 4; + m_bytes_index = 1; + break; + default: + log.errorf("%s: \"%s\": error in bytes descriptor - tag %u", __FUNCTION__, + m_parentAtom.GetFile().GetFilename().c_str(), tag); + break; + } + } +} + +void MP4BytesDescriptor::Read(MP4File& file) +{ + ReadHeader(file); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[m_bytes_index])->SetValueSize(m_size - m_size_offset); + + ReadProperties(file); +} +MP4IODescriptor::MP4IODescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4FileIODescrTag) +{ + /* N.B. other member functions depend on the property indicies */ + AddProperty( /* 0 */ + new MP4BitfieldProperty(parentAtom, "objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "URLFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "includeInlineProfileLevelFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(parentAtom, "reserved", 4)); + AddProperty( /* 4 */ + new MP4StringProperty(parentAtom, "URL", Counted)); + AddProperty( /* 5 */ + new MP4Integer8Property(parentAtom, "ODProfileLevelId")); + AddProperty( /* 6 */ + new MP4Integer8Property(parentAtom, "sceneProfileLevelId")); + AddProperty( /* 7 */ + new MP4Integer8Property(parentAtom, "audioProfileLevelId")); + AddProperty( /* 8 */ + new MP4Integer8Property(parentAtom, "visualProfileLevelId")); + AddProperty( /* 9 */ + new MP4Integer8Property(parentAtom, "graphicsProfileLevelId")); + AddProperty( /* 10 */ + new MP4DescriptorProperty(parentAtom, "esIds", + MP4ESIDIncDescrTag, 0, Required, Many)); + AddProperty( /* 11 */ + new MP4DescriptorProperty(parentAtom, "ociDescr", + MP4OCIDescrTagsStart, MP4OCIDescrTagsEnd, Optional, Many)); + AddProperty( /* 12 */ + new MP4DescriptorProperty(parentAtom, "ipmpDescrPtr", + MP4IPMPPtrDescrTag, 0, Optional, Many)); + AddProperty( /* 13 */ + new MP4DescriptorProperty(parentAtom, "extDescr", + MP4ExtDescrTagsStart, MP4ExtDescrTagsEnd, Optional, Many)); + + SetReadMutate(2); +} + +void MP4IODescriptor::Generate() +{ + ((MP4BitfieldProperty*)m_pProperties[0])->SetValue(1); + ((MP4BitfieldProperty*)m_pProperties[3])->SetValue(0xF); + for (uint32_t i = 5; i <= 9; i++) { + ((MP4Integer8Property*)m_pProperties[i])->SetValue(0xFF); + } +} + +void MP4IODescriptor::Mutate() +{ + bool urlFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + m_pProperties[4]->SetImplicit(!urlFlag); + for (uint32_t i = 5; i <= 12; i++) { + m_pProperties[i]->SetImplicit(urlFlag); + } +} + +MP4ODescriptor::MP4ODescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4FileODescrTag) +{ + /* N.B. other member functions depend on the property indicies */ + AddProperty( /* 0 */ + new MP4BitfieldProperty(parentAtom, "objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "URLFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "reserved", 5)); + AddProperty( /* 3 */ + new MP4StringProperty(parentAtom, "URL", Counted)); + AddProperty( /* 4 */ + new MP4DescriptorProperty(parentAtom, "esIds", + MP4ESIDRefDescrTag, 0, Required, Many)); + AddProperty( /* 5 */ + new MP4DescriptorProperty(parentAtom, "ociDescr", + MP4OCIDescrTagsStart, MP4OCIDescrTagsEnd, Optional, Many)); + AddProperty( /* 6 */ + new MP4DescriptorProperty(parentAtom, "ipmpDescrPtr", + MP4IPMPPtrDescrTag, 0, Optional, Many)); + AddProperty( /* 7 */ + new MP4DescriptorProperty(parentAtom, "extDescr", + MP4ExtDescrTagsStart, MP4ExtDescrTagsEnd, Optional, Many)); + + SetReadMutate(2); +} + +void MP4ODescriptor::Generate() +{ + ((MP4BitfieldProperty*)m_pProperties[2])->SetValue(0x1F); +} + +void MP4ODescriptor::Mutate() +{ + bool urlFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + m_pProperties[3]->SetImplicit(!urlFlag); + for (uint32_t i = 4; i <= 6; i++) { + m_pProperties[i]->SetImplicit(urlFlag); + } +} + +MP4ESDescriptor::MP4ESDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4ESDescrTag) +{ + /* N.B. other class functions depend on the property indicies */ + AddProperty( /* 0 */ + new MP4Integer16Property(parentAtom, "ESID")); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "streamDependenceFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "URLFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(parentAtom, "OCRstreamFlag", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty(parentAtom, "streamPriority", 5)); + AddProperty( /* 5 */ + new MP4Integer16Property(parentAtom, "dependsOnESID")); + AddProperty( /* 6 */ + new MP4StringProperty(parentAtom, "URL", Counted)); + AddProperty( /* 7 */ + new MP4Integer16Property(parentAtom, "OCRESID")); + AddProperty( /* 8 */ + new MP4DescriptorProperty(parentAtom, "decConfigDescr", + MP4DecConfigDescrTag, 0, Required, OnlyOne)); + AddProperty( /* 9 */ + new MP4DescriptorProperty(parentAtom, "slConfigDescr", + MP4SLConfigDescrTag, 0, Required, OnlyOne)); + AddProperty( /* 10 */ + new MP4DescriptorProperty(parentAtom, "ipiPtr", + MP4IPIPtrDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 11 */ + new MP4DescriptorProperty(parentAtom, "ipIds", + MP4ContentIdDescrTag, MP4SupplContentIdDescrTag, Optional, Many)); + AddProperty( /* 12 */ + new MP4DescriptorProperty(parentAtom, "ipmpDescrPtr", + MP4IPMPPtrDescrTag, 0, Optional, Many)); + AddProperty( /* 13 */ + new MP4DescriptorProperty(parentAtom, "langDescr", + MP4LanguageDescrTag, 0, Optional, Many)); + AddProperty( /* 14 */ + new MP4DescriptorProperty(parentAtom, "qosDescr", + MP4QosDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 15 */ + new MP4DescriptorProperty(parentAtom, "regDescr", + MP4RegistrationDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 16 */ + new MP4DescriptorProperty(parentAtom, "extDescr", + MP4ExtDescrTagsStart, MP4ExtDescrTagsEnd, Optional, Many)); + + SetReadMutate(5); +} + +void MP4ESDescriptor::Mutate() +{ + bool streamDependFlag = + ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + m_pProperties[5]->SetImplicit(!streamDependFlag); + + bool urlFlag = + ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); + m_pProperties[6]->SetImplicit(!urlFlag); + + bool ocrFlag = + ((MP4BitfieldProperty*)m_pProperties[3])->GetValue(); + m_pProperties[7]->SetImplicit(!ocrFlag); +} + +MP4DecConfigDescriptor::MP4DecConfigDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4DecConfigDescrTag) +{ + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "objectTypeId")); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "streamType", 6)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "upStream", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(parentAtom, "reserved", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty(parentAtom, "bufferSizeDB", 24)); + AddProperty( /* 5 */ + new MP4Integer32Property(parentAtom, "maxBitrate")); + AddProperty( /* 6 */ + new MP4Integer32Property(parentAtom, "avgBitrate")); + AddProperty( /* 7 */ + new MP4DescriptorProperty(parentAtom, "decSpecificInfo", + MP4DecSpecificDescrTag, 0, Optional, OnlyOne)); + AddProperty( /* 8 */ + new MP4DescriptorProperty(parentAtom, "profileLevelIndicationIndexDescr", + MP4ExtProfileLevelDescrTag, 0, Optional, Many)); +} + +void MP4DecConfigDescriptor::Generate() +{ + ((MP4BitfieldProperty*)m_pProperties[3])->SetValue(1); +} + +MP4SLConfigDescriptor::MP4SLConfigDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4SLConfigDescrTag) +{ + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "predefined")); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "useAccessUnitStartFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "useAccessUnitEndFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(parentAtom, "useRandomAccessPointFlag", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty(parentAtom, "hasRandomAccessUnitsOnlyFlag", 1)); + AddProperty( /* 5 */ + new MP4BitfieldProperty(parentAtom, "usePaddingFlag", 1)); + AddProperty( /* 6 */ + new MP4BitfieldProperty(parentAtom, "useTimeStampsFlag", 1)); + AddProperty( /* 7 */ + new MP4BitfieldProperty(parentAtom, "useIdleFlag", 1)); + AddProperty( /* 8 */ + new MP4BitfieldProperty(parentAtom, "durationFlag", 1)); + AddProperty( /* 9 */ + new MP4Integer32Property(parentAtom, "timeStampResolution")); + AddProperty( /* 10 */ + new MP4Integer32Property(parentAtom, "OCRResolution")); + AddProperty( /* 11 */ + new MP4Integer8Property(parentAtom, "timeStampLength")); + AddProperty( /* 12 */ + new MP4Integer8Property(parentAtom, "OCRLength")); + AddProperty( /* 13 */ + new MP4Integer8Property(parentAtom, "AULength")); + AddProperty( /* 14 */ + new MP4Integer8Property(parentAtom, "instantBitrateLength")); + AddProperty( /* 15 */ + new MP4BitfieldProperty(parentAtom, "degradationPriortyLength", 4)); + AddProperty( /* 16 */ + new MP4BitfieldProperty(parentAtom, "AUSeqNumLength", 5)); + AddProperty( /* 17 */ + new MP4BitfieldProperty(parentAtom, "packetSeqNumLength", 5)); + AddProperty( /* 18 */ + new MP4BitfieldProperty(parentAtom, "reserved", 2)); + + // if durationFlag + AddProperty( /* 19 */ + new MP4Integer32Property(parentAtom, "timeScale")); + AddProperty( /* 20 */ + new MP4Integer16Property(parentAtom, "accessUnitDuration")); + AddProperty( /* 21 */ + new MP4Integer16Property(parentAtom, "compositionUnitDuration")); + + // if !useTimeStampsFlag + AddProperty( /* 22 */ + new MP4BitfieldProperty(parentAtom, "startDecodingTimeStamp", 64)); + AddProperty( /* 23 */ + new MP4BitfieldProperty(parentAtom, "startCompositionTimeStamp", 64)); +} + +void MP4SLConfigDescriptor::Generate() +{ + // by default all tracks in an mp4 file + // use predefined SLConfig descriptor == 2 + ((MP4Integer8Property*)m_pProperties[0])->SetValue(2); + + // which implies UseTimestampsFlag = 1 + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(1); + + // reserved = 3 + ((MP4BitfieldProperty*)m_pProperties[18])->SetValue(3); +} + +void MP4SLConfigDescriptor::Read(MP4File& file) +{ + ReadHeader(file); + + // read the first property, 'predefined' + ReadProperties(file, 0, 1); + + // if predefined == 0 + if (((MP4Integer8Property*)m_pProperties[0])->GetValue() == 0) { + + /* read the next 18 properties */ + ReadProperties(file, 1, 18); + } + + // now mutate + Mutate(); + + // and read the remaining properties + ReadProperties(file, 19); +} + +void MP4SLConfigDescriptor::Mutate() +{ + uint32_t i; + uint8_t predefined = + ((MP4Integer8Property*)m_pProperties[0])->GetValue(); + + if (predefined) { + // properties 1-18 are implicit + for (i = 1; i < m_pProperties.Size(); i++) { + m_pProperties[i]->SetImplicit(true); + } + + if (predefined == 1) { + // UseTimestampsFlag = 0 + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(0); + + // TimestampResolution = 1000 + ((MP4Integer32Property*)m_pProperties[9])->SetValue(1000); + + // TimeStampLength = 32 + ((MP4Integer8Property*)m_pProperties[11])->SetValue(32); + + } else if (predefined == 2) { + // UseTimestampsFlag = 1 + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(1); + } + } else { +#if 1 + for (i = 1; i <= 18; i++) { + m_pProperties[i]->SetImplicit(false); + } + ((MP4BitfieldProperty*)m_pProperties[18])->SetValue(3); +#endif + } + + bool durationFlag = + ((MP4BitfieldProperty*)m_pProperties[8])->GetValue(); + + for (i = 19; i <= 21; i++) { + m_pProperties[i]->SetImplicit(!durationFlag); + } + + bool useTimeStampsFlag = + ((MP4BitfieldProperty*)m_pProperties[6])->GetValue(); + + for (i = 22; i <= 23; i++) { + m_pProperties[i]->SetImplicit(useTimeStampsFlag); + + uint8_t timeStampLength = min((uint8_t)64, + ((MP4Integer8Property*)m_pProperties[11])->GetValue()); + + ((MP4BitfieldProperty*)m_pProperties[i])->SetNumBits(timeStampLength); + + // handle a nonsensical situation gracefully + if (timeStampLength == 0) { + m_pProperties[i]->SetImplicit(true); + } + } +} + +MP4ContentIdDescriptor::MP4ContentIdDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4ContentIdDescrTag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty(parentAtom, "compatibility", 2)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "contentTypeFlag", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "contentIdFlag", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(parentAtom, "protectedContent", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty(parentAtom, "reserved", 3)); + AddProperty( /* 5 */ + new MP4Integer8Property(parentAtom, "contentType")); + AddProperty( /* 6 */ + new MP4Integer8Property(parentAtom, "contentIdType")); + AddProperty( /* 7 */ + new MP4BytesProperty(parentAtom, "contentId")); +} + +void MP4ContentIdDescriptor::Read(MP4File& file) +{ + ReadHeader(file); + + /* read the first property, 'compatiblity' */ + ReadProperties(file, 0, 1); + + /* if compatiblity != 0 */ + if (((MP4Integer8Property*)m_pProperties[0])->GetValue() != 0) { + /* we don't understand it */ + log.verbose1f("incompatible content id descriptor"); + return; + } + + /* read the next four properties */ + ReadProperties(file, 1, 4); + + /* which allows us to reconfigure ourselves */ + Mutate(); + + bool contentTypeFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + bool contentIdFlag = ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); + + if (contentIdFlag) { + + uint32_t cIdOffset = 2; + + if (contentTypeFlag) { + + cIdOffset++; + + } + + ((MP4BytesProperty*)m_pProperties[7])->SetValueSize(m_size - cIdOffset); + + } + + + + /* read the remaining properties */ + ReadProperties(file, 5); +} + +void MP4ContentIdDescriptor::Mutate() +{ + bool contentTypeFlag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + m_pProperties[5]->SetImplicit(!contentTypeFlag); + + bool contentIdFlag = ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); + m_pProperties[6]->SetImplicit(!contentIdFlag); + m_pProperties[7]->SetImplicit(!contentIdFlag); + +} + +MP4Descriptor* MP4DescriptorProperty::CreateDescriptor(MP4Atom& parentAtom, uint8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + + switch (tag) { + case MP4ESDescrTag: + pDescriptor = new MP4ESDescriptor(parentAtom); + break; + case MP4DecConfigDescrTag: + pDescriptor = new MP4DecConfigDescriptor(parentAtom); + break; + case MP4DecSpecificDescrTag: + case MP4IPMPDescrTag: + case MP4RegistrationDescrTag: + pDescriptor = new MP4BytesDescriptor(parentAtom, tag); + break; + case MP4SLConfigDescrTag: + pDescriptor = new MP4SLConfigDescriptor(parentAtom); + break; + case MP4ContentIdDescrTag: + pDescriptor = new MP4ContentIdDescriptor(parentAtom); + break; + case MP4ESIDIncDescrTag: + case MP4ESIDRefDescrTag: + case MP4IPIPtrDescrTag: + case MP4SupplContentIdDescrTag: + case MP4IPMPPtrDescrTag: + case MP4ExtProfileLevelDescrTag: + pDescriptor = new MP4BaseDescriptor(parentAtom, tag); + break; + case MP4QosDescrTag: + pDescriptor = new MP4QosDescriptorBase(parentAtom, MP4QosDescrTag); + break; + case MP4IODescrTag: + case MP4FileIODescrTag: + pDescriptor = new MP4IODescriptor(parentAtom); + pDescriptor->SetTag(tag); + break; + case MP4ODescrTag: + case MP4FileODescrTag: + pDescriptor = new MP4ODescriptor(parentAtom); + pDescriptor->SetTag(tag); + break; + } + + if (pDescriptor == NULL) { + if (tag >= MP4OCIDescrTagsStart && tag <= MP4OCIDescrTagsEnd) { + pDescriptor = CreateOCIDescriptor(parentAtom, tag); + } + + if (tag >= MP4ExtDescrTagsStart && tag <= MP4ExtDescrTagsEnd) { + pDescriptor = new MP4BytesDescriptor(parentAtom, tag); + } + } + + return pDescriptor; +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/descriptors.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/descriptors.h new file mode 100644 index 00000000..6f1cf2eb --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/descriptors.h @@ -0,0 +1,178 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_DESCRIPTORS_H +#define MP4V2_IMPL_DESCRIPTORS_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +const uint8_t MP4ODescrTag = 0x01; +const uint8_t MP4IODescrTag = 0x02; +const uint8_t MP4ESDescrTag = 0x03; +const uint8_t MP4DecConfigDescrTag = 0x04; +const uint8_t MP4DecSpecificDescrTag = 0x05; +const uint8_t MP4SLConfigDescrTag = 0x06; +const uint8_t MP4ContentIdDescrTag = 0x07; +const uint8_t MP4SupplContentIdDescrTag = 0x08; +const uint8_t MP4IPIPtrDescrTag = 0x09; +const uint8_t MP4IPMPPtrDescrTag = 0x0A; +const uint8_t MP4IPMPDescrTag = 0x0B; +const uint8_t MP4RegistrationDescrTag = 0x0D; +const uint8_t MP4ESIDIncDescrTag = 0x0E; +const uint8_t MP4ESIDRefDescrTag = 0x0F; +const uint8_t MP4FileIODescrTag = 0x10; +const uint8_t MP4FileODescrTag = 0x11; +const uint8_t MP4ExtProfileLevelDescrTag = 0x13; +const uint8_t MP4ExtDescrTagsStart = 0x80; +const uint8_t MP4ExtDescrTagsEnd = 0xFE; + +class MP4BaseDescriptor : public MP4Descriptor { +public: + MP4BaseDescriptor(MP4Atom& parentAtom, uint8_t tag); +private: + MP4BaseDescriptor(); + MP4BaseDescriptor ( const MP4BaseDescriptor &src ); + MP4BaseDescriptor &operator= ( const MP4BaseDescriptor &src ); +}; + +class MP4BytesDescriptor : public MP4Descriptor { +public: + MP4BytesDescriptor(MP4Atom& parentAtom, uint8_t tag); + void Read(MP4File& file); +protected: + uint32_t m_size_offset; // size to adjust the size for the bytes property + uint32_t m_bytes_index; // index into properties for bytes property +private: + MP4BytesDescriptor(); + MP4BytesDescriptor ( const MP4BytesDescriptor &src ); + MP4BytesDescriptor &operator= ( const MP4BytesDescriptor &src ); +}; + +class MP4IODescriptor : public MP4Descriptor { +public: + MP4IODescriptor(MP4Atom& parentAtom); + void Generate(); +protected: + void Mutate(); +private: + MP4IODescriptor(); + MP4IODescriptor ( const MP4IODescriptor &src ); + MP4IODescriptor &operator= ( const MP4IODescriptor &src ); +}; + +class MP4ODescriptor : public MP4Descriptor { +public: + MP4ODescriptor(MP4Atom& parentAtom); + void Generate(); +protected: + void Mutate(); +private: + MP4ODescriptor(); + MP4ODescriptor ( const MP4ODescriptor &src ); + MP4ODescriptor &operator= ( const MP4ODescriptor &src ); +}; + + +class MP4ESDescriptor : public MP4Descriptor { +public: + MP4ESDescriptor(MP4Atom& parentAtom); +protected: + void Mutate(); +private: + MP4ESDescriptor(); + MP4ESDescriptor ( const MP4ESDescriptor &src ); + MP4ESDescriptor &operator= ( const MP4ESDescriptor &src ); +}; + +class MP4DecConfigDescriptor : public MP4Descriptor { +public: + MP4DecConfigDescriptor(MP4Atom& parentAtom); + void Generate(); +private: + MP4DecConfigDescriptor(); + MP4DecConfigDescriptor ( const MP4DecConfigDescriptor &src ); + MP4DecConfigDescriptor &operator= ( const MP4DecConfigDescriptor &src ); +}; + + +class MP4SLConfigDescriptor : public MP4Descriptor { +public: + MP4SLConfigDescriptor(MP4Atom& parentAtom); + void Generate(); + void Read(MP4File& file); +protected: + void Mutate(); +private: + MP4SLConfigDescriptor(); + MP4SLConfigDescriptor ( const MP4SLConfigDescriptor &src ); + MP4SLConfigDescriptor &operator= ( const MP4SLConfigDescriptor &src ); +}; + +class MP4IPIPtrDescriptor : public MP4Descriptor { +public: + MP4IPIPtrDescriptor(MP4Atom& parentAtom); +private: + MP4IPIPtrDescriptor(); + MP4IPIPtrDescriptor ( const MP4IPIPtrDescriptor &src ); + MP4IPIPtrDescriptor &operator= ( const MP4IPIPtrDescriptor &src ); +}; + +class MP4ContentIdDescriptor : public MP4Descriptor { +public: + MP4ContentIdDescriptor(MP4Atom& parentAtom); + void Read(MP4File& file); +protected: + void Mutate(); +private: + MP4ContentIdDescriptor(); + MP4ContentIdDescriptor ( const MP4ContentIdDescriptor &src ); + MP4ContentIdDescriptor &operator= ( const MP4ContentIdDescriptor &src ); +}; + +// associated values in descriptors + +// ES objectTypeId +const uint8_t MP4SystemsV1ObjectType = 0x01; +const uint8_t MP4SystemsV2ObjectType = 0x02; +const uint8_t MP4SubpicObjectType = 0xe0; + +// ES streamType +const uint8_t MP4ObjectDescriptionStreamType = 0x01; +const uint8_t MP4ClockReferenceStreamType = 0x02; +const uint8_t MP4SceneDescriptionStreamType = 0x03; +const uint8_t MP4VisualStreamType = 0x04; +const uint8_t MP4AudioStreamType = 0x05; +const uint8_t MP4Mpeg7StreamType = 0x06; +const uint8_t MP4IPMPStreamType = 0x07; +const uint8_t MP4OCIStreamType = 0x08; +const uint8_t MP4MPEGJStreamType = 0x09; +const uint8_t MP4UserPrivateStreamType = 0x20; +const uint8_t MP4NeroSubpicStreamType = 0x38; + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_DESCRIPTORS_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/enum.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/enum.h new file mode 100644 index 00000000..af5b6d48 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/enum.h @@ -0,0 +1,110 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ENUM_H +#define MP4V2_IMPL_ENUM_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +/// class Template to support enums with to/from string conversions. +/// +/// This class template is meant only to add support for enums which have +/// useful string equivalents. The model is that each enum value has +/// two string equivalents: compact and formal. <b>compact</b> is a short, +/// compact string which usually excludes spaces and punctuation and makes it +/// suitable for use with command-line arguments or any situation where +/// superfluous characters make parsing needlessly complicated. <b>formal</b> +/// is a string suitable for use in human-readable situations where spaces, +/// punctuation and even case is desirable. +/// +/// For end usability, enums will have the full list of enums available +/// which is suitable for help-usage scenerios. And all values will be +/// convertable from enum to string, or from string to enum. When converting +/// from enum to string, you may optionally specify a boolean value which +/// will return the <b>formal</b> string value; otherwise a <b>compact</b> +/// value is returned. +/// +/// Conversion from string to enum (integral) value will always assume +/// <b>compact</b> string is used as it makes little sense to convert formal +/// strings to enum. Furthermore, the string conversion is optimized to +/// ignore case, and in the case an exact full-string match is not found, +/// a <b>best-match</b> is then checked for. Basically this means that if +/// enough beginning characters are used to match exactly 1 string-enum, +/// it is considered a match. +/// +/// The template has 2 strict requirements. First, the enum must be a true +/// enum type; ie: not just some integer constants. Second, the enum must have +/// a value which indicates an undefined or illegal value; which is used as +/// a return value by string-to-enum conversion to indicate the string did +/// not match. +/// +/// This template implementation itself should never be exposed. That is +/// to say, the .tcc file must not be used by code outside this library. +/// +/// WARNING: since enum types are typically made static file scope, +/// care must be taken to make sure Entry data[] initialization occurs +/// in the <b>same file</b> and <b>before</b> instantiation. +/// +template <typename T, T UNDEFINED> +class Enum +{ +public: + struct MP4V2_EXPORT Entry + { + T type; + const string compact; + const string formal; + }; + + typedef map<string,const Entry*,LessIgnoreCase> MapToType; + typedef map<T,const Entry*> MapToString; + +public: + static const Entry data[]; + +private: + MapToType _mapToType; + MapToString _mapToString; + +public: + const MapToType& mapToType; + const MapToString& mapToString; + +public: + Enum(); + ~Enum(); + + T toType ( const string& ) const; + string toString ( T, bool = false ) const; + string& toString ( T, string&, bool = false ) const; +}; + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#include "enum.tcc" + +#endif // MP4V2_IMPL_ENUM_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/enum.tcc b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/enum.tcc new file mode 100644 index 00000000..1f3395a9 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/enum.tcc @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ENUM_TCC +#define MP4V2_IMPL_ENUM_TCC + +#include <sstream> + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +template <typename T, T UNDEFINED> +Enum<T,UNDEFINED>::Enum() + : mapToType ( _mapToType ) + , mapToString ( _mapToString ) +{ + for( const Entry* p = data; p->type != UNDEFINED; p++ ) { + _mapToType.insert( typename MapToType::value_type( p->compact, p )); + _mapToString.insert( typename MapToString::value_type( p->type, p )); + } +} + +////////////////////////////////////////////////////////////////////////////// + +template <typename T, T UNDEFINED> +Enum<T,UNDEFINED>::~Enum() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +template <typename T, T UNDEFINED> +string +Enum<T,UNDEFINED>::toString( T value, bool formal ) const +{ + string buffer; + return toString( value, buffer, formal ); +} + +////////////////////////////////////////////////////////////////////////////// + +template <typename T, T UNDEFINED> +string& +Enum<T,UNDEFINED>::toString( T value, string& buffer, bool formal ) const +{ + const typename MapToString::const_iterator found = _mapToString.find( value ); + if( found != _mapToString.end() ) { + const Entry& entry = *(found->second); + buffer = formal ? entry.formal : entry.compact; + return buffer; + } + + ostringstream oss; + oss << "UNDEFINED(" << value << ")"; + buffer = oss.str(); + return buffer; +} + +////////////////////////////////////////////////////////////////////////////// + +template <typename T, T UNDEFINED> +T +Enum<T,UNDEFINED>::toType( const string& value ) const +{ + // if number perform enum lookup + int ivalue; + istringstream iss( value ); + iss >> ivalue; + if( iss.rdstate() == ios::eofbit ) { + const typename MapToString::const_iterator found = _mapToString.find( static_cast<T>(ivalue) ); + if( found != _mapToString.end() ) + return found->second->type; + } + + // exact match + const typename MapToType::const_iterator found = _mapToType.find( value ); + if( found != _mapToType.end() ) + return found->second->type; + + // partial match + int matches = 0; + T matched = static_cast<T>( 0 ); + + const typename MapToType::const_iterator ie = _mapToType.end(); + for( typename MapToType::const_iterator it = _mapToType.begin(); it != ie; it++ ) { + const Entry& entry = *(it->second); + if( entry.compact.find( value ) == 0 ) { + matches++; + matched = entry.type; + } + } + + return (matches == 1) ? matched : UNDEFINED; +} + +////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_ENUM_TCC diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/exception.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/exception.cpp new file mode 100644 index 00000000..ddc60d75 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/exception.cpp @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// Portions created by David Byron are Copyright (C) 2009. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +Exception::Exception( const string& what_, + const char *file_, + int line_, + const char *function_ ) + : what(what_) + , file(file_) + , line(line_) + , function(function_) +{ + ASSERT(file_); + ASSERT(function_); +} + +/////////////////////////////////////////////////////////////////////////////// + +Exception::~Exception() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +string +Exception::msg() const +{ + ostringstream retval; + + retval << function << ": " << what << " (" << file << "," << line << ")"; + + return retval.str(); +} + +/////////////////////////////////////////////////////////////////////////////// + +PlatformException::PlatformException( const string& what_, + int errno_, + const char *file_, + int line_, + const char *function_ ) + : Exception(what_,file_,line_,function_) + , m_errno(errno_) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +PlatformException::~PlatformException() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +string +PlatformException::msg() const +{ + ostringstream retval; + + retval << function << ": " << what << ": errno: " << m_errno << " (" << + file << "," << line << ")"; + + return retval.str(); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/exception.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/exception.h new file mode 100644 index 00000000..f0e2e4e7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/exception.h @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_MP4EXCEPTION_H +#define MP4V2_IMPL_MP4EXCEPTION_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +class MP4V2_EXPORT Exception +{ +public: + explicit Exception( const string& what_, + const char *file_, + int line_, + const char *function_ ); + virtual ~Exception(); + + virtual string msg() const; + +public: + const string what; + const string file; + const int line; + const string function; +}; + +class MP4V2_EXPORT PlatformException : public Exception +{ +public: + explicit PlatformException( const string& what_, + int errno_, + const char *file_, + int line_, + const char *function_ ); + virtual ~PlatformException(); + + virtual string msg() const; + +public: + const int m_errno; +}; + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4EXCEPTION_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/impl.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/impl.h new file mode 100644 index 00000000..f35e3fee --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/impl.h @@ -0,0 +1,10 @@ +#ifndef MP4V2_IMPL_IMPL_H +#define MP4V2_IMPL_IMPL_H + +/////////////////////////////////////////////////////////////////////////////// + +#include "src.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_IMPL_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/isma.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/isma.cpp new file mode 100644 index 00000000..007455d7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/isma.cpp @@ -0,0 +1,967 @@ +/* + * 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 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +static const uint8_t BifsV2Config[3] = { + 0x00, 0x00, 0x60 // IsCommandStream = 1, PixelMetric = 1 +}; + +void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + if (m_useIsma) { + // already done + return; + } + + // find first audio and/or video tracks + + MP4TrackId audioTrackId = MP4_INVALID_TRACK_ID; + try { + audioTrackId = FindTrackId(0, MP4_AUDIO_TRACK_TYPE); + } + catch ( Exception *x ) { + log.errorf(*x); + delete x; + } + MP4TrackId videoTrackId = MP4_INVALID_TRACK_ID; + try { + videoTrackId = FindTrackId(0, MP4_VIDEO_TRACK_TYPE); + } + catch (Exception* x) { + log.errorf(*x); + delete x; + } + if (audioTrackId == MP4_INVALID_TRACK_ID && + videoTrackId == MP4_INVALID_TRACK_ID) return; + + const char *audio_media_data_name, *video_media_data_name; + uint8_t videoProfile = 0xff; + if (audioTrackId != MP4_INVALID_TRACK_ID) { + audio_media_data_name = MP4GetTrackMediaDataName(this, audioTrackId); + if (!(ATOMID(audio_media_data_name) == ATOMID("mp4a") || + ATOMID(audio_media_data_name) == ATOMID("enca"))) { + log.errorf("%s: \"%s\": can't make ISMA compliant when file contains an %s track", + __FUNCTION__, GetFilename().c_str(), audio_media_data_name); + return; + } + } + // + // Note - might have to check for avc1 here... + if (videoTrackId != MP4_INVALID_TRACK_ID) { + video_media_data_name = MP4GetTrackMediaDataName(this, videoTrackId); + if (!(ATOMID(video_media_data_name) == ATOMID("mp4v") || + ATOMID(video_media_data_name) == ATOMID("encv"))) { + log.errorf("%s: \"%s\": can't make ISMA compliant when file contains an %s track", __FUNCTION__, + GetFilename().c_str(), video_media_data_name); + return; + } + MP4LogLevel verb = log.verbosity; + log.setVerbosity(MP4_LOG_NONE); + videoProfile = MP4GetVideoProfileLevel(this, videoTrackId); + log.setVerbosity(verb); + } + + m_useIsma = true; + + uint64_t fileMsDuration = 0; + fileMsDuration = + ConvertFromMovieDuration(GetDuration(), MP4_MSECS_TIME_SCALE); + + // delete any existing OD track + if (m_odTrackId != MP4_INVALID_TRACK_ID) { + DeleteTrack(m_odTrackId); + } + + if (m_pRootAtom->FindAtom("moov.iods") == NULL) { + (void)AddChildAtom("moov", "iods"); + } + (void)AddODTrack(); + SetODProfileLevel(0xFF); + + if (audioTrackId != MP4_INVALID_TRACK_ID) { + AddTrackToOd(audioTrackId); + MP4SetAudioProfileLevel(this, 0xf); + } + if (videoTrackId != MP4_INVALID_TRACK_ID) { + AddTrackToOd(videoTrackId); + MP4SetVideoProfileLevel(this, videoProfile); + } + + // delete any existing scene track + MP4TrackId sceneTrackId = MP4_INVALID_TRACK_ID; + try { + sceneTrackId = FindTrackId(0, MP4_SCENE_TRACK_TYPE); + } + catch (Exception *x) { + log.errorf(*x); + delete x; + } + if (sceneTrackId != MP4_INVALID_TRACK_ID) { + DeleteTrack(sceneTrackId); + } + + // add scene track + sceneTrackId = AddSceneTrack(); + SetSceneProfileLevel(0xFF); + SetGraphicsProfileLevel(0xFF); + SetTrackIntegerProperty(sceneTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", + MP4SystemsV2ObjectType); + + SetTrackESConfiguration(sceneTrackId, + BifsV2Config, sizeof(BifsV2Config)); + + uint8_t* pBytes = NULL; + uint64_t numBytes = 0; + + // write OD Update Command + CreateIsmaODUpdateCommandFromFileForFile( + m_odTrackId, + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + WriteSample(m_odTrackId, pBytes, numBytes, fileMsDuration); + + MP4Free(pBytes); + pBytes = NULL; + + // write BIFS Scene Replace Command + CreateIsmaSceneCommand( + MP4_IS_VALID_TRACK_ID(audioTrackId), + MP4_IS_VALID_TRACK_ID(videoTrackId), + &pBytes, + &numBytes); + + WriteSample(sceneTrackId, pBytes, numBytes, fileMsDuration); + + MP4Free(pBytes); + pBytes = NULL; + + // add session level sdp + CreateIsmaIodFromFile( + m_odTrackId, + sceneTrackId, + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + char* iodBase64 = MP4ToBase64(pBytes, numBytes); + + uint32_t sdpBufLen = (uint32_t)strlen(iodBase64) + 256; + uint32_t used; + char* sdpBuf = (char*)MP4Calloc(sdpBufLen); + + if (addIsmaComplianceSdp) { + strncpy(sdpBuf, "a=isma-compliance:1,1.0,1\015\012", sdpBufLen); + } + + used = (uint32_t)strlen(sdpBuf); + sdpBufLen -= used; + snprintf(&sdpBuf[used], sdpBufLen, + "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042\015\012", + iodBase64); + + SetSessionSdp(sdpBuf); + + log.verbose1f("\"%s\": IOD SDP = %s", GetFilename().c_str(), sdpBuf); + + MP4Free(iodBase64); + iodBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + MP4Free(sdpBuf); + sdpBuf = NULL; +} + +static void CloneIntegerProperty( + MP4Descriptor* pDest, + MP4DescriptorProperty* pSrc, + const char* name) +{ + MP4IntegerProperty* pGetProperty; + MP4IntegerProperty* pSetProperty; + + if (!pSrc->FindProperty(name, (MP4Property**)&pGetProperty)) return; + if (!pDest->FindProperty(name, (MP4Property**)&pSetProperty)) return; + pSetProperty->SetValue(pGetProperty->GetValue()); +} + +void MP4File::CreateIsmaIodFromFile( + MP4TrackId odTrackId, + MP4TrackId sceneTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + uint8_t** ppBytes, + uint64_t* pNumBytes) +{ + MP4Atom* pIodsAtom = FindAtom("moov.iods"); + ASSERT(pIodsAtom); + MP4DescriptorProperty* pSrcIod = + (MP4DescriptorProperty*)pIodsAtom->GetProperty(2); + + MP4Descriptor* pIod = new MP4IODescriptor(*pIodsAtom); + pIod->SetTag(MP4IODescrTag); + pIod->Generate(); + + CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId"); + CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId"); + CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId"); + + // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag + MP4DescriptorProperty* pEsProperty; + if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return; + pEsProperty->SetTags(MP4ESDescrTag); + + MP4IntegerProperty* pSetProperty; + MP4IntegerProperty* pSceneESID; + MP4IntegerProperty* pOdESID; + + // OD + MP4Descriptor* pOdEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pOdEsd->Generate(); + + if (!pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID)) return; + + // we set the OD ESID to a non-zero unique value + pOdESID->SetValue(m_odTrackId); + + if (pOdEsd->FindProperty("URLFlag", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + uint8_t* pBytes; + uint64_t numBytes; + + CreateIsmaODUpdateCommandFromFileForStream( + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + log.hexDump(0, MP4_LOG_VERBOSE1, pBytes, numBytes, "\"%s\": OD data", + GetFilename().c_str() ); + + char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); + + uint32_t urlBufLen = (uint32_t)strlen(odCmdBase64) + 64; + char* urlBuf = (char*)MP4Malloc(urlBufLen); + + snprintf(urlBuf, urlBufLen, + "data:application/mpeg4-od-au;base64,%s", + odCmdBase64); + + MP4StringProperty* pUrlProperty; + if (pOdEsd->FindProperty("URL", + (MP4Property**)&pUrlProperty)) + pUrlProperty->SetValue(urlBuf); + + log.verbose1f("\"%s\": OD data URL = \042%s\042", GetFilename().c_str(), + urlBuf); + + MP4Free(odCmdBase64); + odCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + MP4Free(urlBuf); + urlBuf = NULL; + + MP4DescriptorProperty* pSrcDcd = NULL; + + // HACK temporarily point to scene decoder config + (void)FindProperty(MakeTrackName(odTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), + (MP4Property**)&pSrcDcd); + ASSERT(pSrcDcd); + MP4Property* pOrgOdEsdProperty = + pOdEsd->GetProperty(8); + pOdEsd->SetProperty(8, pSrcDcd); + + // bufferSizeDB needs to be set appropriately + MP4BitfieldProperty* pBufferSizeProperty = NULL; + if (pOdEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + ASSERT(pBufferSizeProperty); + pBufferSizeProperty->SetValue(numBytes); + } + + // SL config needs to change from 2 (file) to 1 (null) + if (pOdEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + + // Scene + MP4Descriptor* pSceneEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pSceneEsd->Generate(); + + if (pSceneEsd->FindProperty("ESID", + (MP4Property**)&pSceneESID)) { + // we set the Scene ESID to a non-zero unique value + pSceneESID->SetValue(sceneTrackId); + } + + if (pSceneEsd->FindProperty("URLFlag", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + CreateIsmaSceneCommand( + MP4_IS_VALID_TRACK_ID(audioTrackId), + MP4_IS_VALID_TRACK_ID(videoTrackId), + &pBytes, + &numBytes); + + log.hexDump(0, MP4_LOG_VERBOSE1, pBytes, numBytes, "\"%s\": Scene data", + GetFilename().c_str() ); + + char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); + + urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); + snprintf(urlBuf, strlen(sceneCmdBase64) + 64, + "data:application/mpeg4-bifs-au;base64,%s", + sceneCmdBase64); + + if (pSceneEsd->FindProperty("URL", + (MP4Property**)&pUrlProperty)) + pUrlProperty->SetValue(urlBuf); + + log.verbose1f("\"%s\": Scene data URL = \042%s\042", + GetFilename().c_str(), urlBuf); + + MP4Free(sceneCmdBase64); + sceneCmdBase64 = NULL; + MP4Free(urlBuf); + urlBuf = NULL; + MP4Free(pBytes); + pBytes = NULL; + + // HACK temporarily point to scene decoder config + ASSERT(FindProperty(MakeTrackName(sceneTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), + (MP4Property**)&pSrcDcd)); + ASSERT(pSrcDcd); + MP4Property* pOrgSceneEsdProperty = + pSceneEsd->GetProperty(8); + pSceneEsd->SetProperty(8, pSrcDcd); + + // bufferSizeDB needs to be set + pBufferSizeProperty = NULL; + if (pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + ASSERT(pBufferSizeProperty); + pBufferSizeProperty->SetValue(numBytes); + } + + // SL config needs to change from 2 (file) to 1 (null) + if (pSceneEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + + // finally get the whole thing written to a memory + pIod->WriteToMemory(*this, ppBytes, pNumBytes); + + + // now carefully replace esd properties before destroying + pOdEsd->SetProperty(8, pOrgOdEsdProperty); + pSceneEsd->SetProperty(8, pOrgSceneEsdProperty); + pSceneESID->SetValue(0); // restore 0 value + pOdESID->SetValue(0); + + delete pIod; + + log.hexDump(0, MP4_LOG_VERBOSE1, *ppBytes, *pNumBytes, "\"%s\": IOD data", + GetFilename().c_str() ); +} + +void MP4File::CreateIsmaIodFromParams( + uint8_t videoProfile, + uint32_t videoBitrate, + uint8_t* videoConfig, + uint32_t videoConfigLength, + uint8_t audioProfile, + uint32_t audioBitrate, + uint8_t* audioConfig, + uint32_t audioConfigLength, + uint8_t** ppIodBytes, + uint64_t* pIodNumBytes) +{ + MP4IntegerProperty* pInt; + uint8_t* pBytes = NULL; + uint64_t numBytes; + + // Descriptor constructors need a parent atom. In this + // case we don't have one so create a dummy one. This + // is OK as we only build the descriptor and then dump + // its contents to a buffer + MP4Atom dummyParent(*this); + + // Create the IOD + MP4Descriptor* pIod = new MP4IODescriptor(dummyParent); + pIod->SetTag(MP4IODescrTag); + pIod->Generate(); + + // Set audio and video profileLevels + if (pIod->FindProperty("audioProfileLevelId", + (MP4Property**)&pInt)) + pInt->SetValue(audioProfile); + + if (pIod->FindProperty("visualProfileLevelId", + (MP4Property**)&pInt)) + pInt->SetValue(videoProfile); + + // Mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag + MP4DescriptorProperty* pEsProperty; + if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return; + pEsProperty->SetTags(MP4ESDescrTag); + + // Add ES Descriptors + + // Scene + CreateIsmaSceneCommand( + (audioProfile != 0xFF), + (videoProfile != 0xFF), + &pBytes, + &numBytes); + + log.hexDump(0, MP4_LOG_VERBOSE1, pBytes, numBytes, "\"%s\": Scene data", + GetFilename().c_str() ); + + char* sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); + + char* urlBuf = + (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); + snprintf(urlBuf, strlen(sceneCmdBase64) + 64, + "data:application/mpeg4-bifs-au;base64,%s", + sceneCmdBase64); + + log.verbose1f("\"%s\": Scene data URL = \042%s\042", GetFilename().c_str(), + urlBuf); + + /* MP4Descriptor* pSceneEsd = */ + CreateESD( + pEsProperty, + 201, // esid + MP4SystemsV2ObjectType, + MP4SceneDescriptionStreamType, + numBytes, // bufferSize + numBytes * 8, // bitrate + BifsV2Config, + sizeof(BifsV2Config), + urlBuf); + MP4Free(urlBuf); + urlBuf = NULL; + + MP4Free(sceneCmdBase64); + sceneCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + + // OD + + // Video + MP4DescriptorProperty* pVideoEsdProperty = + new MP4DescriptorProperty(dummyParent); + pVideoEsdProperty->SetTags(MP4ESDescrTag); + + /* MP4Descriptor* pVideoEsd = */ + CreateESD( + pVideoEsdProperty, + 20, // esid + MP4_MPEG4_VIDEO_TYPE, + MP4VisualStreamType, + videoBitrate / 8, // bufferSize + videoBitrate, + videoConfig, + videoConfigLength, + NULL); + + // Audio + MP4DescriptorProperty* pAudioEsdProperty = + new MP4DescriptorProperty(dummyParent); + pAudioEsdProperty->SetTags(MP4ESDescrTag); + + /* MP4Descriptor* pAudioEsd = */ + CreateESD( + pAudioEsdProperty, + 10, // esid + MP4_MPEG4_AUDIO_TYPE, + MP4AudioStreamType, + audioBitrate / 8, // bufferSize + audioBitrate, + audioConfig, + audioConfigLength, + NULL); + + CreateIsmaODUpdateCommandForStream( + pAudioEsdProperty, + pVideoEsdProperty, + &pBytes, + &numBytes); + + // cleanup temporary descriptor properties + delete pAudioEsdProperty; + delete pVideoEsdProperty; + + log.hexDump(0, MP4_LOG_VERBOSE1,pBytes, numBytes,"\"%s\": OD data = %" PRIu64 " bytes", + GetFilename().c_str(), numBytes); + + char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); + + urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); + if (urlBuf != NULL) { + snprintf(urlBuf, strlen(odCmdBase64) + 64, + "data:application/mpeg4-od-au;base64,%s", + odCmdBase64); + + log.verbose1f("\"%s\": OD data URL = \042%s\042", GetFilename().c_str(), urlBuf); + + /* MP4Descriptor* pOdEsd = */ + CreateESD( + pEsProperty, + 101, + MP4SystemsV1ObjectType, + MP4ObjectDescriptionStreamType, + numBytes, // bufferSize + numBytes * 8, // bitrate + NULL, // config + 0, // configLength + urlBuf); + + MP4Free(urlBuf); + urlBuf = NULL; + } + MP4Free(odCmdBase64); + odCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + + // finally get the whole thing written to a memory + pIod->WriteToMemory(*this, ppIodBytes, pIodNumBytes); + + delete pIod; + + log.hexDump(0, MP4_LOG_VERBOSE1, *ppIodBytes, *pIodNumBytes,"\"%s\": IOD data", + GetFilename().c_str() ); +} + +void MP4File::CreateESD( + MP4DescriptorProperty* pEsProperty, + uint32_t esid, + uint8_t objectType, + uint8_t streamType, + uint32_t bufferSize, + uint32_t bitrate, + const uint8_t* pConfig, + uint32_t configLength, + char* url) +{ + MP4IntegerProperty* pInt; + MP4StringProperty* pString; + MP4BytesProperty* pBytes; + MP4BitfieldProperty* pBits; + + MP4Descriptor* pEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pEsd->Generate(); + + if (pEsd->FindProperty("ESID", + (MP4Property**)&pInt)) + pInt->SetValue(esid); + + if (pEsd->FindProperty("decConfigDescr.objectTypeId", + (MP4Property**)&pInt)) + pInt->SetValue(objectType); + + if (pEsd->FindProperty("decConfigDescr.streamType", + (MP4Property**)&pInt)) + pInt->SetValue(streamType); + + if (pEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pInt)) + pInt->SetValue(bufferSize); + + if (pEsd->FindProperty("decConfigDescr.maxBitrate", + (MP4Property**)&pInt)) + pInt->SetValue(bitrate); + + if (pEsd->FindProperty("decConfigDescr.avgBitrate", + (MP4Property**)&pInt)) + pInt->SetValue(bitrate); + + MP4DescriptorProperty* pConfigDescrProperty; + if (pEsd->FindProperty("decConfigDescr.decSpecificInfo", + (MP4Property**)&pConfigDescrProperty)) { + + MP4Descriptor* pConfigDescr = + pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag); + pConfigDescr->Generate(); + + if (pConfigDescrProperty->FindProperty("decSpecificInfo[0].info", + (MP4Property**)&pBytes)) + pBytes->SetValue(pConfig, configLength); + } + + if (pEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pInt)) + // changed 12/5/02 from plugfest to value 0 + pInt->SetValue(0); + + if (pEsd->FindProperty("slConfig.useAccessUnitEndFlag", + (MP4Property **)&pBits)) + pBits->SetValue(1); + + if (url) { + if (pEsd->FindProperty("URLFlag", + (MP4Property**)&pInt)) + pInt->SetValue(1); + + if (pEsd->FindProperty("URL", + (MP4Property**)&pString)) + pString->SetValue(url); + } + + //return pEsd; +} + +void MP4File::CreateIsmaODUpdateCommandFromFileForFile( + MP4TrackId odTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + uint8_t** ppBytes, + uint64_t* pNumBytes) +{ + // Descriptor constructors need a parent atom. In this + // case we don't have one so create a dummy one. This + // is OK as we only build the descriptor and then dump + // its contents to a buffer + MP4Atom dummyParent(*this); + MP4Descriptor* pCommand = CreateODCommand(dummyParent, MP4ODUpdateODCommandTag); + pCommand->Generate(); + + for (uint8_t i = 0; i < 2; i++) { + MP4TrackId trackId; + uint16_t odId; + + if (i == 0) { + trackId = audioTrackId; + odId = 10; + } else { + trackId = videoTrackId; + odId = 20; + } + + if (trackId == MP4_INVALID_TRACK_ID) { + continue; + } + + MP4DescriptorProperty* pOdDescrProperty = + (MP4DescriptorProperty*)(pCommand->GetProperty(0)); + + pOdDescrProperty->SetTags(MP4FileODescrTag); + + MP4Descriptor* pOd = + pOdDescrProperty->AddDescriptor(MP4FileODescrTag); + + pOd->Generate(); + + MP4BitfieldProperty* pOdIdProperty = NULL; + if (pOd->FindProperty("objectDescriptorId", + (MP4Property**)&pOdIdProperty)) + pOdIdProperty->SetValue(odId); + + MP4DescriptorProperty* pEsIdsDescriptorProperty = NULL; + ASSERT(pOd->FindProperty("esIds", + (MP4Property**)&pEsIdsDescriptorProperty)); + ASSERT(pEsIdsDescriptorProperty); + + pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag); + + MP4Descriptor *pRefDescriptor = + pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag); + pRefDescriptor->Generate(); + + MP4Integer16Property* pRefIndexProperty = NULL; + ASSERT(pRefDescriptor->FindProperty("refIndex", + (MP4Property**)&pRefIndexProperty)); + ASSERT(pRefIndexProperty); + + uint32_t mpodIndex = FindTrackReference( + MakeTrackName(odTrackId, "tref.mpod"), trackId); + ASSERT(mpodIndex != 0); + + pRefIndexProperty->SetValue(mpodIndex); + } + + pCommand->WriteToMemory(*this, ppBytes, pNumBytes); + + delete pCommand; +} + +void MP4File::CreateIsmaODUpdateCommandFromFileForStream( + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + uint8_t** ppBytes, + uint64_t* pNumBytes) +{ + MP4DescriptorProperty* pAudioEsd = NULL; + MP4Integer8Property* pAudioSLConfigPredef = NULL; + MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL; + int oldAudioUnitEndFlagValue = 0; + MP4DescriptorProperty* pVideoEsd = NULL; + MP4Integer8Property* pVideoSLConfigPredef = NULL; + MP4BitfieldProperty* pVideoAccessUnitEndFlag = NULL; + int oldVideoUnitEndFlagValue = 0; + MP4IntegerProperty* pAudioEsdId = NULL; + MP4IntegerProperty* pVideoEsdId = NULL; + + if (audioTrackId != MP4_INVALID_TRACK_ID) { + // changed mp4a to * to handle enca case + MP4Atom* pEsdsAtom = + FindAtom(MakeTrackName(audioTrackId, + "mdia.minf.stbl.stsd.*.esds")); + ASSERT(pEsdsAtom); + + pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); + // ESID is 0 for file, stream needs to be non-ze + ASSERT(pAudioEsd->FindProperty("ESID", + (MP4Property**)&pAudioEsdId)); + + ASSERT(pAudioEsdId); + pAudioEsdId->SetValue(audioTrackId); + + // SL config needs to change from 2 (file) to 1 (null) + if (pAudioEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pAudioSLConfigPredef)) { + ASSERT(pAudioSLConfigPredef); + pAudioSLConfigPredef->SetValue(0); + } + + if (pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", + (MP4Property **)&pAudioAccessUnitEndFlag)) { + oldAudioUnitEndFlagValue = + pAudioAccessUnitEndFlag->GetValue(); + pAudioAccessUnitEndFlag->SetValue(1); + } + } + + if (videoTrackId != MP4_INVALID_TRACK_ID) { + // changed mp4v to * to handle encv case + MP4Atom* pEsdsAtom = + FindAtom(MakeTrackName(videoTrackId, + "mdia.minf.stbl.stsd.*.esds")); + ASSERT(pEsdsAtom); + + pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); + ASSERT(pVideoEsd->FindProperty("ESID", + (MP4Property**)&pVideoEsdId)); + + ASSERT(pVideoEsdId); + pVideoEsdId->SetValue(videoTrackId); + + // SL config needs to change from 2 (file) to 1 (null) + ASSERT(pVideoEsd->FindProperty("slConfigDescr.predefined", + (MP4Property **)&pVideoSLConfigPredef)); + ASSERT(pVideoSLConfigPredef); + pVideoSLConfigPredef->SetValue(0); + + if (pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", + (MP4Property **)&pVideoAccessUnitEndFlag)) { + oldVideoUnitEndFlagValue = + pVideoAccessUnitEndFlag->GetValue(); + pVideoAccessUnitEndFlag->SetValue(1); + } + } + + CreateIsmaODUpdateCommandForStream( + pAudioEsd, pVideoEsd, ppBytes, pNumBytes); + log.hexDump(0, MP4_LOG_VERBOSE1, *ppBytes, *pNumBytes, + "\"%s\": After CreateImsaODUpdateCommandForStream len %" PRIu64, + GetFilename().c_str(), *pNumBytes); + + // return SL config values to 2 (file) + // return ESID values to 0 + if (pAudioSLConfigPredef) { + pAudioSLConfigPredef->SetValue(2); + } + if (pAudioEsdId) { + pAudioEsdId->SetValue(0); + } + if (pAudioAccessUnitEndFlag) { + pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue ); + } + if (pVideoEsdId) { + pVideoEsdId->SetValue(0); + } + if (pVideoSLConfigPredef) { + pVideoSLConfigPredef->SetValue(2); + } + if (pVideoAccessUnitEndFlag) { + pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue ); + } +} + +void MP4File::CreateIsmaODUpdateCommandForStream( + MP4DescriptorProperty* pAudioEsdProperty, + MP4DescriptorProperty* pVideoEsdProperty, + uint8_t** ppBytes, + uint64_t* pNumBytes) +{ + MP4Descriptor* pAudioOd = NULL; + MP4Descriptor* pVideoOd = NULL; + + // Descriptor constructors need a parent atom. In this + // case we don't have one so create a dummy one. This + // is OK as we only build the descriptor and then dump + // its contents to a buffer + MP4Atom dummyParent(*this); + MP4Descriptor* pCommand = + CreateODCommand(dummyParent, MP4ODUpdateODCommandTag); + pCommand->Generate(); + + for (uint8_t i = 0; i < 2; i++) { + uint16_t odId; + MP4DescriptorProperty* pEsdProperty = NULL; + + if (i == 0) { + odId = 10; + pEsdProperty = pAudioEsdProperty; + } else { + odId = 20; + pEsdProperty = pVideoEsdProperty; + } + + if (pEsdProperty == NULL) { + continue; + } + + MP4DescriptorProperty* pOdDescrProperty = + (MP4DescriptorProperty*)(pCommand->GetProperty(0)); + + pOdDescrProperty->SetTags(MP4ODescrTag); + + MP4Descriptor* pOd = + pOdDescrProperty->AddDescriptor(MP4ODescrTag); + pOd->Generate(); + + if (i == 0) { + pAudioOd = pOd; + } else { + pVideoOd = pOd; + } + + MP4BitfieldProperty* pOdIdProperty = NULL; + if (pOd->FindProperty("objectDescriptorId", + (MP4Property**)&pOdIdProperty)) { + pOdIdProperty->SetValue(odId); + } + + delete (MP4DescriptorProperty*)pOd->GetProperty(4); + pOd->SetProperty(4, pEsdProperty); + } + + // serialize OD command + pCommand->WriteToMemory(*this, ppBytes, pNumBytes); + + // detach from esd descriptor params + if (pAudioOd) { + pAudioOd->SetProperty(4, NULL); + } + if (pVideoOd) { + pVideoOd->SetProperty(4, NULL); + } + + // then destroy + delete pCommand; +} + +void MP4File::CreateIsmaSceneCommand( + bool hasAudio, + bool hasVideo, + uint8_t** ppBytes, + uint64_t* pNumBytes) +{ + // from ISMA 1.0 Tech Spec Appendix E + static const uint8_t bifsAudioOnly[] = { + 0xC0, 0x10, 0x12, + 0x81, 0x30, 0x2A, 0x05, 0x6D, 0xC0 + }; + static const uint8_t bifsVideoOnly[] = { + 0xC0, 0x10, 0x12, + 0x61, 0x04, + 0x1F, 0xC0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, + 0x44, 0x28, 0x22, 0x82, 0x9F, 0x80 + }; + static const uint8_t bifsAudioVideo[] = { + 0xC0, 0x10, 0x12, + 0x81, 0x30, 0x2A, 0x05, 0x6D, 0x26, + 0x10, 0x41, 0xFC, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0x04, 0x42, 0x82, 0x28, 0x29, 0xF8 + }; + + if (hasAudio && hasVideo) { + *pNumBytes = sizeof(bifsAudioVideo); + *ppBytes = (uint8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsAudioVideo, sizeof(bifsAudioVideo)); + + } else if (hasAudio) { + *pNumBytes = sizeof(bifsAudioOnly); + *ppBytes = (uint8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsAudioOnly, sizeof(bifsAudioOnly)); + + } else if (hasVideo) { + *pNumBytes = sizeof(bifsVideoOnly); + *ppBytes = (uint8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsVideoOnly, sizeof(bifsVideoOnly)); + } else { + *pNumBytes = 0; + *ppBytes = NULL; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/CoverArtBox.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/CoverArtBox.cpp new file mode 100644 index 00000000..01253624 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/CoverArtBox.cpp @@ -0,0 +1,261 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +CoverArtBox::Item::Item() + : type ( BT_UNDEFINED ) + , buffer ( NULL ) + , size ( 0 ) + , autofree ( false ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +CoverArtBox::Item::Item( const Item& rhs ) + : type ( BT_UNDEFINED ) + , buffer ( NULL ) + , size ( 0 ) + , autofree ( false ) +{ + operator=( rhs ); +} + +/////////////////////////////////////////////////////////////////////////////// + +CoverArtBox::Item::~Item() +{ + reset(); +} + +/////////////////////////////////////////////////////////////////////////////// + +CoverArtBox::Item& +CoverArtBox::Item::operator=( const Item& rhs ) +{ + type = rhs.type; + size = rhs.size; + autofree = rhs.autofree; + + if( rhs.autofree ) { + buffer = (uint8_t*)MP4Malloc(rhs.size); + memcpy( buffer, rhs.buffer, rhs.size ); + } + else { + buffer = rhs.buffer; + } + + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +CoverArtBox::Item::reset() +{ + if( autofree && buffer ) + MP4Free( buffer ); + + type = BT_UNDEFINED; + buffer = NULL; + size = 0; + autofree = false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +CoverArtBox::add( MP4FileHandle hFile, const Item& item ) +{ + MP4File& file = *((MP4File*)hFile); + + const char* const covr_name = "moov.udta.meta.ilst.covr"; + MP4Atom* covr = file.FindAtom( covr_name ); + if( !covr ) { + file.AddDescendantAtoms( "moov", "udta.meta.ilst.covr" ); + + covr = file.FindAtom( covr_name ); + if( !covr ) + return true; + } + + // use empty data atom if one exists + MP4Atom* data = NULL; + uint32_t index = 0; + const uint32_t atomc = covr->GetNumberOfChildAtoms(); + for( uint32_t i = 0; i < atomc; i++ ) { + MP4Atom* atom = covr->GetChildAtom( i ); + + MP4BytesProperty* metadata = NULL; + if( !atom->FindProperty( "data.metadata", (MP4Property**)&metadata )) + continue; + + if( metadata->GetCount() ) + continue; + + data = atom; + index = i; + break; + } + + // no empty atom found, create one. + if( !data ) { + data = MP4Atom::CreateAtom( file, covr, "data" ); + covr->AddChildAtom( data ); + data->Generate(); + index = covr->GetNumberOfChildAtoms() - 1; + } + + return set( hFile, item, index ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +CoverArtBox::get( MP4FileHandle hFile, Item& item, uint32_t index ) +{ + item.reset(); + MP4File& file = *((MP4File*)hFile); + + MP4Atom* covr = file.FindAtom( "moov.udta.meta.ilst.covr" ); + if( !covr ) + return true; + + if( !(index < covr->GetNumberOfChildAtoms()) ) + return true; + + MP4DataAtom* data = static_cast<MP4DataAtom*>( covr->GetChildAtom( index )); + if( !data ) + return true; + + MP4BytesProperty* metadata = NULL; + if ( !data->FindProperty( "data.metadata", (MP4Property**)&metadata )) + return true; + + metadata->GetValue( &item.buffer, &item.size ); + item.autofree = true; + item.type = data->typeCode.GetValue(); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +CoverArtBox::list( MP4FileHandle hFile, ItemList& out ) +{ + out.clear(); + MP4File& file = *((MP4File*)hFile); + MP4ItmfItemList* itemList = genericGetItemsByCode( file, "covr" ); // alloc + + if( itemList->size ) { + MP4ItmfDataList& dataList = itemList->elements[0].dataList; + out.resize( dataList.size ); + for( uint32_t i = 0; i < dataList.size; i++ ) + get( hFile, out[i], i ); + } + + genericItemListFree( itemList ); // free + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +CoverArtBox::remove( MP4FileHandle hFile, uint32_t index ) +{ + MP4File& file = *((MP4File*)hFile); + + MP4Atom* covr = file.FindAtom( "moov.udta.meta.ilst.covr" ); + if( !covr ) + return true; + + // wildcard mode: delete covr and all images + if( index == numeric_limits<uint32_t>::max() ) { + covr->GetParentAtom()->DeleteChildAtom( covr ); + delete covr; + return false; + } + + if( !(index < covr->GetNumberOfChildAtoms()) ) + return true; + + MP4Atom* data = covr->GetChildAtom( index ); + if( !data ) + return true; + + // delete single image + covr->DeleteChildAtom( data ); + delete data; + + // delete empty covr + if( covr->GetNumberOfChildAtoms() == 0 ) { + covr->GetParentAtom()->DeleteChildAtom( covr ); + delete covr; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +CoverArtBox::set( MP4FileHandle hFile, const Item& item, uint32_t index ) +{ + MP4File& file = *((MP4File*)hFile); + + MP4Atom* covr = file.FindAtom( "moov.udta.meta.ilst.covr" ); + if( !covr ) + return true; + + if( !(index < covr->GetNumberOfChildAtoms()) ) + return true; + + MP4DataAtom* data = static_cast<MP4DataAtom*>( covr->GetChildAtom( index )); + if( !data ) + return true; + + MP4BytesProperty* metadata = NULL; + if ( !data->FindProperty( "data.metadata", (MP4Property**)&metadata )) + return true; + + // autodetect type if BT_UNDEFINED + const BasicType final_type = (item.type == BT_UNDEFINED) + ? computeBasicType( item.buffer, item.size ) + : item.type; + + // set type; note: not really flags due to b0rked atom structure + data->typeCode.SetValue( final_type ); + metadata->SetValue( item.buffer, item.size ); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/CoverArtBox.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/CoverArtBox.h new file mode 100644 index 00000000..023e3c90 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/CoverArtBox.h @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ITMF_COVERARTBOX_H +#define MP4V2_IMPL_ITMF_COVERARTBOX_H + +namespace mp4v2 { namespace impl { namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +/// Functional class for covr-box (Cover-art Box) support. +/// +class MP4V2_EXPORT CoverArtBox +{ +public: + /// Data object for covr-box item. + /// This object correlates to one covr->data atom and offers automatic + /// memory freeing when <b>autofree</b> is true. + /// + class MP4V2_EXPORT Item + { + public: + Item(); + Item( const Item& ); + ~Item(); + + Item& operator=( const Item& ); + + /// Reset to state of newly constructed object. + /// If <b>buffer</b> is not NULL and <b>autofree</b> is true the + /// buffer will be free'd. + void reset(); + + BasicType type; ///< covr-box type. + uint8_t* buffer; ///< buffer point to raw covr-box data. + uint32_t size; ///< size of covr-box buffer size in bytes. + bool autofree; ///< when true invoke free(buffer) upon destruction. + }; + + /// Object representing a list of covr-box items. + typedef vector<Item> ItemList; + + /// Fetch list of covr-box items from file. + /// + /// @param hFile on which to operate. + /// @param out vector of ArtItem objects. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool list( MP4FileHandle hFile, ItemList& out ); + + /// Add covr-box item to file. + /// Any necessary metadata atoms are first created. + /// Additionally, if an empty data-atom exists it will be used, + /// otherwise a new data-atom is added to <b>covr-atom</b>. + /// + /// @param hFile on which to operate. + /// @param item covr-box object to place in file. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool add( MP4FileHandle hFile, const Item& item ); + + /// Replace covr-box item in file. + /// + /// @param hFile on which to operate. + /// @param item covr-box object to place in file. + /// @param index 0-based index of image to replace. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool set( MP4FileHandle hFile, const Item& item, uint32_t index ); + + /// Fetch covr-box item from file. + /// + /// @param hFile on which to operate. + /// @param item covr-box object populated with data. + /// The resulting object owns the malloc'd buffer and <b>item.autofree</b> + /// is set to true for convenient memory management. + /// @param index 0-based index of image to fetch. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool get( MP4FileHandle hFile, Item& item, uint32_t index ); + + /// Remove covr-box item from file. + /// + /// @param hFile on which to operate. + /// @param index 0-based index of image to remove. + /// Default value indicates wildcard behavior to remove all items. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool remove( MP4FileHandle hFile, uint32_t index = numeric_limits<uint32_t>::max() ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf + +#endif // MP4V2_IMPL_ITMF_COVERARTBOX_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/Tags.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/Tags.cpp new file mode 100644 index 00000000..e8ca4816 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/Tags.cpp @@ -0,0 +1,897 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// Portions created by David Byron are Copyright (C) 2011. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// Rouven Wessling, [email protected] +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +Tags::Tags() + : hasMetadata(false) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +Tags::~Tags() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_addArtwork( MP4Tags*& tags, MP4TagArtwork& c_artwork ) +{ + artwork.resize( artwork.size() + 1 ); + c_setArtwork( tags, (uint32_t)artwork.size() - 1, c_artwork ); + updateArtworkShadow( tags ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_alloc( MP4Tags*& tags ) +{ + tags = new MP4Tags(); + memset( tags, 0, sizeof(MP4Tags) ); // safe: pure C-struct + tags->__handle = this; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_fetch( MP4Tags*& tags, MP4FileHandle hFile ) +{ + MP4Tags& c = *tags; + MP4File& file = *static_cast<MP4File*>(hFile); + + MP4ItmfItemList* itemList = genericGetItems( file ); // alloc + + hasMetadata = (itemList->size > 0); + + /* create code -> item map. + * map will only be used for items which do not repeat; we do not care if + * cover-art is inserted multiple times. + */ + CodeItemMap cim; + for( uint32_t i = 0; i < itemList->size; i++ ) { + MP4ItmfItem& item = itemList->elements[i]; + cim.insert( CodeItemMap::value_type( item.code, &item )); + } + + fetchString( cim, CODE_NAME, name, c.name ); + fetchString( cim, CODE_ARTIST, artist, c.artist ); + fetchString( cim, CODE_ALBUMARTIST, albumArtist, c.albumArtist ); + fetchString( cim, CODE_ALBUM, album, c.album ); + fetchString( cim, CODE_GROUPING, grouping, c.grouping ); + fetchString( cim, CODE_COMPOSER, composer, c.composer ); + fetchString( cim, CODE_COMMENTS, comments, c.comments ); + + fetchString( cim, CODE_GENRE, genre, c.genre ); + fetchGenre( cim, genreType, c.genreType ); + + fetchString( cim, CODE_RELEASEDATE, releaseDate, c.releaseDate ); + fetchTrack( cim, track, c.track ); + fetchDisk( cim, disk, c.disk ); + fetchInteger( cim, CODE_TEMPO, tempo, c.tempo ); + fetchInteger( cim, CODE_COMPILATION, compilation, c.compilation ); + + fetchString( cim, CODE_TVSHOW, tvShow, c.tvShow ); + fetchString( cim, CODE_TVNETWORK, tvNetwork, c.tvNetwork ); + fetchString( cim, CODE_TVEPISODEID, tvEpisodeID, c.tvEpisodeID ); + fetchInteger( cim, CODE_TVSEASON, tvSeason, c.tvSeason ); + fetchInteger( cim, CODE_TVEPISODE, tvEpisode, c.tvEpisode ); + + fetchString( cim, CODE_SORTNAME, sortName, c.sortName ); + fetchString( cim, CODE_SORTARTIST, sortArtist, c.sortArtist ); + fetchString( cim, CODE_SORTALBUMARTIST, sortAlbumArtist, c.sortAlbumArtist ); + fetchString( cim, CODE_SORTALBUM, sortAlbum, c.sortAlbum ); + fetchString( cim, CODE_SORTCOMPOSER, sortComposer, c.sortComposer ); + fetchString( cim, CODE_SORTTVSHOW, sortTVShow, c.sortTVShow ); + + fetchString( cim, CODE_DESCRIPTION, description, c.description ); + fetchString( cim, CODE_LONGDESCRIPTION, longDescription, c.longDescription ); + fetchString( cim, CODE_LYRICS, lyrics, c.lyrics ); + + fetchString( cim, CODE_COPYRIGHT, copyright, c.copyright ); + fetchString( cim, CODE_ENCODINGTOOL, encodingTool, c.encodingTool ); + fetchString( cim, CODE_ENCODEDBY, encodedBy, c.encodedBy ); + fetchString( cim, CODE_PURCHASEDATE, purchaseDate, c.purchaseDate ); + + fetchInteger( cim, CODE_PODCAST, podcast, c.podcast ); + fetchString( cim, CODE_KEYWORDS, keywords, c.keywords ); + fetchString( cim, CODE_CATEGORY, category, c.category ); + + fetchInteger( cim, CODE_HDVIDEO, hdVideo, c.hdVideo ); + fetchInteger( cim, CODE_MEDIATYPE, mediaType, c.mediaType ); + fetchInteger( cim, CODE_CONTENTRATING, contentRating, c.contentRating ); + fetchInteger( cim, CODE_GAPLESS, gapless, c.gapless ); + + fetchString( cim, CODE_ITUNESACCOUNT, iTunesAccount, c.iTunesAccount ); + fetchInteger( cim, CODE_ITUNESACCOUNTTYPE, iTunesAccountType, c.iTunesAccountType ); + fetchInteger( cim, CODE_ITUNESCOUNTRY, iTunesCountry, c.iTunesCountry ); + + fetchInteger( cim, CODE_CONTENTID, contentID, c.contentID ); + fetchInteger( cim, CODE_ARTISTID, artistID, c.artistID ); + fetchInteger( cim, CODE_PLAYLISTID, playlistID, c.playlistID ); + fetchInteger( cim, CODE_GENREID, genreID, c.genreID ); + fetchInteger( cim, CODE_COMPOSERID, composerID, c.composerID ); + fetchString( cim, CODE_XID, xid, c.xid ); + + genericItemListFree( itemList ); // free + + // fetch full list and overwrite our copy, otherwise clear + { + CoverArtBox::ItemList items; + if( CoverArtBox::list( hFile, items )) + artwork.clear(); + else + artwork = items; + + updateArtworkShadow( tags ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_free( MP4Tags*& tags ) +{ + MP4Tags* c = const_cast<MP4Tags*>(tags); + + delete[] c->artwork; + delete c; + + tags = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_removeArtwork( MP4Tags*& tags, uint32_t index ) +{ + if( !(index < artwork.size()) ) + return; + + artwork.erase( artwork.begin() + index ); + updateArtworkShadow( tags ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setArtwork( MP4Tags*& tags, uint32_t index, MP4TagArtwork& c_artwork ) +{ + if( !(index < artwork.size()) ) + return; + + CoverArtBox::Item& item = artwork[index]; + + switch( c_artwork.type ) { + case MP4_ART_BMP: + item.type = BT_BMP; + break; + + case MP4_ART_GIF: + item.type = BT_GIF; + break; + + case MP4_ART_JPEG: + item.type = BT_JPEG; + break; + + case MP4_ART_PNG: + item.type = BT_PNG; + break; + + case MP4_ART_UNDEFINED: + default: + item.type = computeBasicType( c_artwork.data, c_artwork.size ); + break; + } + + item.buffer = (uint8_t*)malloc( c_artwork.size ); + item.size = c_artwork.size; + item.autofree = true; + + memcpy( item.buffer, c_artwork.data, c_artwork.size ); + updateArtworkShadow( tags ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setInteger( const uint8_t* value, uint8_t& cpp, const uint8_t*& c ) +{ + if( !value ) { + cpp = 0; + c = NULL; + } + else { + cpp = *value; + c = &cpp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setInteger( const uint16_t* value, uint16_t& cpp, const uint16_t*& c ) +{ + if( !value ) { + cpp = 0; + c = NULL; + } + else { + cpp = *value; + c = &cpp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setInteger( const uint32_t* value, uint32_t& cpp, const uint32_t*& c ) +{ + if( !value ) { + cpp = 0; + c = NULL; + } + else { + cpp = *value; + c = &cpp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setInteger( const uint64_t* value, uint64_t& cpp, const uint64_t*& c ) +{ + if( !value ) { + cpp = 0; + c = NULL; + } + else { + cpp = *value; + c = &cpp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setString( const char* value, string& cpp, const char*& c ) +{ + if( !value ) { + cpp.clear(); + c = NULL; + } + else { + cpp = value; + c = cpp.c_str(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setTrack( const MP4TagTrack* value, MP4TagTrack& cpp, const MP4TagTrack*& c ) +{ + if( !value ) { + cpp.index = 0; + cpp.total = 0; + c = NULL; + } + else { + cpp.index = value->index; + cpp.total = value->total; + c = &cpp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_setDisk( const MP4TagDisk* value, MP4TagDisk& cpp, const MP4TagDisk*& c ) +{ + if( !value ) { + cpp.index = 0; + cpp.total = 0; + c = NULL; + } + else { + cpp.index = value->index; + cpp.total = value->total; + c = &cpp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::c_store( MP4Tags*& tags, MP4FileHandle hFile ) +{ + MP4Tags& c = *tags; + MP4File& file = *static_cast<MP4File*>(hFile); + + storeString( file, CODE_NAME, name, c.name ); + storeString( file, CODE_ARTIST, artist, c.artist ); + storeString( file, CODE_ALBUMARTIST, albumArtist, c.albumArtist ); + storeString( file, CODE_ALBUM, album, c.album ); + storeString( file, CODE_GROUPING, grouping, c.grouping ); + storeString( file, CODE_COMPOSER, composer, c.composer ); + storeString( file, CODE_COMMENTS, comments, c.comments ); + + storeString( file, CODE_GENRE, genre, c.genre ); + storeGenre( file, genreType, c.genreType ); + + storeString( file, CODE_RELEASEDATE, releaseDate, c.releaseDate ); + storeTrack( file, track, c.track ); + storeDisk( file, disk, c.disk ); + storeInteger( file, CODE_TEMPO, tempo, c.tempo ); + storeInteger( file, CODE_COMPILATION, compilation, c.compilation ); + + storeString( file, CODE_TVSHOW, tvShow, c.tvShow ); + storeString( file, CODE_TVNETWORK, tvNetwork, c.tvNetwork ); + storeString( file, CODE_TVEPISODEID, tvEpisodeID, c.tvEpisodeID ); + storeInteger( file, CODE_TVSEASON, tvSeason, c.tvSeason ); + storeInteger( file, CODE_TVEPISODE, tvEpisode, c.tvEpisode ); + + storeString( file, CODE_SORTNAME, sortName, c.sortName ); + storeString( file, CODE_SORTARTIST, sortArtist, c.sortArtist ); + storeString( file, CODE_SORTALBUMARTIST, sortAlbumArtist, c.sortAlbumArtist ); + storeString( file, CODE_SORTALBUM, sortAlbum, c.sortAlbum ); + storeString( file, CODE_SORTCOMPOSER, sortComposer, c.sortComposer ); + storeString( file, CODE_SORTTVSHOW, sortTVShow, c.sortTVShow ); + + storeString( file, CODE_DESCRIPTION, description, c.description ); + storeString( file, CODE_LONGDESCRIPTION, longDescription, c.longDescription ); + storeString( file, CODE_LYRICS, lyrics, c.lyrics ); + + storeString( file, CODE_COPYRIGHT, copyright, c.copyright ); + storeString( file, CODE_ENCODINGTOOL, encodingTool, c.encodingTool ); + storeString( file, CODE_ENCODEDBY, encodedBy, c.encodedBy ); + storeString( file, CODE_PURCHASEDATE, purchaseDate, c.purchaseDate ); + + storeInteger( file, CODE_PODCAST, podcast, c.podcast ); + storeString( file, CODE_KEYWORDS, keywords, c.keywords ); + storeString( file, CODE_CATEGORY, category, c.category ); + + storeInteger( file, CODE_HDVIDEO, hdVideo, c.hdVideo ); + storeInteger( file, CODE_MEDIATYPE, mediaType, c.mediaType ); + storeInteger( file, CODE_CONTENTRATING, contentRating, c.contentRating ); + storeInteger( file, CODE_GAPLESS, gapless, c.gapless ); + + storeString( file, CODE_ITUNESACCOUNT, iTunesAccount, c.iTunesAccount ); + storeInteger( file, CODE_ITUNESACCOUNTTYPE, iTunesAccountType, c.iTunesAccountType ); + storeInteger( file, CODE_ITUNESCOUNTRY, iTunesCountry, c.iTunesCountry ); + + storeInteger( file, CODE_CONTENTID, contentID, c.contentID ); + storeInteger( file, CODE_ARTISTID, artistID, c.artistID ); + storeInteger( file, CODE_PLAYLISTID, playlistID, c.playlistID ); + storeInteger( file, CODE_GENREID, genreID, c.genreID ); + storeInteger( file, CODE_COMPOSERID, composerID, c.composerID ); + storeString( file, CODE_XID, xid, c.xid ); + + // destroy all cover-art then add each + { + CoverArtBox::remove( hFile ); + const CoverArtBox::ItemList::size_type max = artwork.size(); + for( CoverArtBox::ItemList::size_type i = 0; i < max; i++ ) + CoverArtBox::add( hFile, artwork[i] ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchGenre( const CodeItemMap& cim, uint16_t& cpp, const uint16_t*& c ) +{ + cpp = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( CODE_GENRETYPE ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + if( NULL == data.value ) + return; + + cpp = (uint16_t(data.value[0]) << 8) + | (uint16_t(data.value[1]) ); + + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchDisk( const CodeItemMap& cim, MP4TagDisk& cpp, const MP4TagDisk*& c ) +{ + cpp.index = 0; + cpp.total = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( CODE_DISK ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + + if( NULL == data.value ) + return; + + cpp.index = (uint16_t(data.value[2]) << 8) + | (uint16_t(data.value[3]) ); + + cpp.total = (uint16_t(data.value[4]) << 8) + | (uint16_t(data.value[5]) ); + + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchTrack( const CodeItemMap& cim, MP4TagTrack& cpp, const MP4TagTrack*& c ) +{ + cpp.index = 0; + cpp.total = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( CODE_TRACK ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + + if( NULL == data.value ) + return; + + cpp.index = (uint16_t(data.value[2]) << 8) + | (uint16_t(data.value[3]) ); + + cpp.total = (uint16_t(data.value[4]) << 8) + | (uint16_t(data.value[5]) ); + + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchInteger( const CodeItemMap& cim, const string& code, uint8_t& cpp, const uint8_t*& c ) +{ + cpp = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( code ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + if( NULL == data.value ) + return; + + cpp = data.value[0]; + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchInteger( const CodeItemMap& cim, const string& code, uint16_t& cpp, const uint16_t*& c ) +{ + cpp = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( code ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + + if( NULL == data.value ) + return; + + cpp = (uint16_t(data.value[0]) << 8) + | (uint16_t(data.value[1]) ); + + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchInteger( const CodeItemMap& cim, const string& code, uint32_t& cpp, const uint32_t*& c ) +{ + cpp = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( code ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + + if( NULL == data.value ) + return; + + cpp = (uint32_t(data.value[0]) << 24) + | (uint32_t(data.value[1]) << 16) + | (uint32_t(data.value[2]) << 8) + | (uint32_t(data.value[3]) ); + + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchInteger( const CodeItemMap& cim, const string& code, uint64_t& cpp, const uint64_t*& c ) +{ + cpp = 0; + c = NULL; + + CodeItemMap::const_iterator f = cim.find( code ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + + if( NULL == data.value ) + return; + + cpp = (uint64_t(data.value[0]) << 56) + | (uint64_t(data.value[1]) << 48) + | (uint64_t(data.value[2]) << 40) + | (uint64_t(data.value[3]) << 32) + | (uint64_t(data.value[4]) << 24) + | (uint64_t(data.value[5]) << 16) + | (uint64_t(data.value[6]) << 8) + | (uint64_t(data.value[7]) ); + + c = &cpp; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::fetchString( const CodeItemMap& cim, const string& code, string& cpp, const char*& c ) +{ + cpp.clear(); + c = NULL; + + CodeItemMap::const_iterator f = cim.find( code ); + if( f == cim.end() || 0 == f->second->dataList.size ) + return; + + MP4ItmfData& data = f->second->dataList.elements[0]; + + if( NULL == data.value ) + return; + + cpp.append( reinterpret_cast<char*>( data.value ), data.valueSize ); + c = cpp.c_str(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::remove( MP4File& file, const string& code ) +{ + MP4ItmfItemList* itemList = genericGetItemsByCode( file, code ); // alloc + + if( itemList->size ) + genericRemoveItem( file, &itemList->elements[0] ); + + genericItemListFree( itemList ); // free +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::store( MP4File& file, const string& code, MP4ItmfBasicType basicType, const void* buffer, uint32_t size ) +{ + // remove existing item + remove( file, code ); + + // add item + MP4ItmfItem& item = *genericItemAlloc( code, 1 ); // alloc + MP4ItmfData& data = item.dataList.elements[0]; + + data.typeCode = basicType; + data.valueSize = size; + data.value = (uint8_t*)malloc( data.valueSize ); + memcpy( data.value, buffer, data.valueSize ); + + genericAddItem( file, &item ); + genericItemFree( &item ); // free +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeGenre( MP4File& file, uint16_t cpp, const uint16_t* c ) +{ + if( c ) { + uint8_t buf[2]; + + buf[0] = uint8_t((cpp & 0xff00) >> 8); + buf[1] = uint8_t((cpp & 0x00ff) ); + + // it's not clear if you must use implicit in these situations and iirc iTunes and other software are not consistent in this regard. + // many other tags must be integer type yet no issues there. Silly that iTunes insists it must be implict, which is then hardcoded + // to interpret as genres anyways. + store( file, CODE_GENRETYPE, MP4_ITMF_BT_IMPLICIT, buf, sizeof(buf) ); + } + else { + remove( file, CODE_GENRETYPE ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeDisk( MP4File& file, const MP4TagDisk& cpp, const MP4TagDisk* c ) +{ + if( c ) { + uint8_t buf[6]; + memset( buf, 0, sizeof(buf) ); + + buf[2] = uint8_t((cpp.index & 0xff00) >> 8); + buf[3] = uint8_t((cpp.index & 0x00ff) ); + buf[4] = uint8_t((cpp.total & 0xff00) >> 8); + buf[5] = uint8_t((cpp.total & 0x00ff) ); + + store( file, CODE_DISK, MP4_ITMF_BT_IMPLICIT, buf, sizeof(buf) ); + } + else { + remove( file, CODE_DISK ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeTrack( MP4File& file, const MP4TagTrack& cpp, const MP4TagTrack* c ) +{ + if( c ) { + uint8_t buf[8]; // iTMF spec says 7 but iTunes media is 8 + memset( buf, 0, sizeof(buf) ); + + buf[2] = uint8_t((cpp.index & 0xff00) >> 8); + buf[3] = uint8_t((cpp.index & 0x00ff) ); + buf[4] = uint8_t((cpp.total & 0xff00) >> 8); + buf[5] = uint8_t((cpp.total & 0x00ff) ); + + store( file, CODE_TRACK, MP4_ITMF_BT_IMPLICIT, buf, sizeof(buf) ); + } + else { + remove( file, CODE_TRACK ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeInteger( MP4File& file, const string& code, uint8_t cpp, const uint8_t* c ) +{ + if( c ) + store( file, code, MP4_ITMF_BT_INTEGER, &cpp, sizeof(cpp) ); + else + remove( file, code ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeInteger( MP4File& file, const string& code, uint16_t cpp, const uint16_t* c ) +{ + if( c ) { + uint8_t buf[2]; + + buf[0] = uint8_t((cpp & 0xff00) >> 8); + buf[1] = uint8_t((cpp & 0x00ff) ); + + store( file, code, MP4_ITMF_BT_INTEGER, buf, sizeof(buf) ); + } + else { + remove( file, code ); + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeInteger( MP4File& file, const string& code, uint32_t cpp, const uint32_t* c ) +{ + if( c ) { + uint8_t buf[4]; + + buf[0] = uint8_t((cpp & 0xff000000) >> 24 ); + buf[1] = uint8_t((cpp & 0x00ff0000) >> 16 ); + buf[2] = uint8_t((cpp & 0x0000ff00) >> 8 ); + buf[3] = uint8_t((cpp & 0x000000ff) ); + + store( file, code, MP4_ITMF_BT_INTEGER, buf, sizeof(buf) ); + } + else { + remove( file, code ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeInteger( MP4File& file, const string& code, uint64_t cpp, const uint64_t* c ) +{ + if( c ) { + uint8_t buf[8]; + + buf[0] = uint8_t((cpp & 0xff00000000000000LL) >> 56 ); + buf[1] = uint8_t((cpp & 0x00ff000000000000LL) >> 48 ); + buf[2] = uint8_t((cpp & 0x0000ff0000000000LL) >> 40 ); + buf[3] = uint8_t((cpp & 0x000000ff00000000LL) >> 32 ); + buf[4] = uint8_t((cpp & 0x00000000ff000000LL) >> 24 ); + buf[5] = uint8_t((cpp & 0x0000000000ff0000LL) >> 16 ); + buf[6] = uint8_t((cpp & 0x000000000000ff00LL) >> 8 ); + buf[7] = uint8_t((cpp & 0x00000000000000ffLL) ); + + store( file, code, MP4_ITMF_BT_INTEGER, buf, sizeof(buf) ); + } + else { + remove( file, code ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::storeString( MP4File& file, const string& code, const string& cpp, const char* c ) +{ + if( c ) + store( file, code, MP4_ITMF_BT_UTF8, cpp.c_str(), (uint32_t)cpp.size() ); + else + remove( file, code ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +Tags::updateArtworkShadow( MP4Tags*& tags ) +{ + if( tags->artwork ) { + delete[] tags->artwork; + tags->artwork = NULL; + tags->artworkCount = 0; + } + + if( artwork.empty() ) + return; + + MP4TagArtwork* const cartwork = new MP4TagArtwork[ artwork.size() ]; + uint32_t max = (uint32_t)artwork.size(); + + for( uint32_t i = 0; i < max; i++ ) { + MP4TagArtwork& a = cartwork[i]; + CoverArtBox::Item& item = artwork[i]; + + a.data = item.buffer; + a.size = item.size; + + switch( item.type ) { + case BT_BMP: + a.type = MP4_ART_BMP; + break; + + case BT_GIF: + a.type = MP4_ART_GIF; + break; + + case BT_JPEG: + a.type = MP4_ART_JPEG; + break; + + case BT_PNG: + a.type = MP4_ART_PNG; + break; + + default: + a.type = MP4_ART_UNDEFINED; + break; + } + } + + tags->artwork = cartwork; + tags->artworkCount = max; +} + +/////////////////////////////////////////////////////////////////////////////// + +const string Tags::CODE_NAME = "\xa9" "nam"; +const string Tags::CODE_ARTIST = "\xa9" "ART"; +const string Tags::CODE_ALBUMARTIST = "aART"; +const string Tags::CODE_ALBUM = "\xa9" "alb"; +const string Tags::CODE_GROUPING = "\xa9" "grp"; +const string Tags::CODE_COMPOSER = "\xa9" "wrt"; +const string Tags::CODE_COMMENTS = "\xa9" "cmt"; +const string Tags::CODE_GENRE = "\xa9" "gen"; +const string Tags::CODE_GENRETYPE = "gnre"; +const string Tags::CODE_RELEASEDATE = "\xa9" "day"; +const string Tags::CODE_TRACK = "trkn"; +const string Tags::CODE_DISK = "disk"; +const string Tags::CODE_TEMPO = "tmpo"; +const string Tags::CODE_COMPILATION = "cpil"; + +const string Tags::CODE_TVSHOW = "tvsh"; +const string Tags::CODE_TVNETWORK = "tvnn"; +const string Tags::CODE_TVEPISODEID = "tven"; +const string Tags::CODE_TVSEASON = "tvsn"; +const string Tags::CODE_TVEPISODE = "tves"; + +const string Tags::CODE_DESCRIPTION = "desc"; +const string Tags::CODE_LONGDESCRIPTION = "ldes"; +const string Tags::CODE_LYRICS = "\xa9" "lyr"; + +const string Tags::CODE_SORTNAME = "sonm"; +const string Tags::CODE_SORTARTIST = "soar"; +const string Tags::CODE_SORTALBUMARTIST = "soaa"; +const string Tags::CODE_SORTALBUM = "soal"; +const string Tags::CODE_SORTCOMPOSER = "soco"; +const string Tags::CODE_SORTTVSHOW = "sosn"; + +const string Tags::CODE_COPYRIGHT = "cprt"; +const string Tags::CODE_ENCODINGTOOL = "\xa9" "too"; +const string Tags::CODE_ENCODEDBY = "\xa9" "enc"; +const string Tags::CODE_PURCHASEDATE = "purd"; + +const string Tags::CODE_PODCAST = "pcst"; +const string Tags::CODE_KEYWORDS = "keyw"; +const string Tags::CODE_CATEGORY = "catg"; + +const string Tags::CODE_HDVIDEO = "hdvd"; +const string Tags::CODE_MEDIATYPE = "stik"; +const string Tags::CODE_CONTENTRATING = "rtng"; +const string Tags::CODE_GAPLESS = "pgap"; + +const string Tags::CODE_ITUNESACCOUNT = "apID"; +const string Tags::CODE_ITUNESACCOUNTTYPE = "akID"; +const string Tags::CODE_ITUNESCOUNTRY = "sfID"; +const string Tags::CODE_CONTENTID = "cnID"; +const string Tags::CODE_ARTISTID = "atID"; +const string Tags::CODE_PLAYLISTID = "plID"; +const string Tags::CODE_GENREID = "geID"; +const string Tags::CODE_COMPOSERID = "cmID"; +const string Tags::CODE_XID = "xid "; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/Tags.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/Tags.h new file mode 100644 index 00000000..57ef82cb --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/Tags.h @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// Portions created by David Byron are Copyright (C) 2011. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, [email protected] +// Rouven Wessling, [email protected] +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ITMF_TAGS_H +#define MP4V2_IMPL_ITMF_TAGS_H + +namespace mp4v2 { namespace impl { namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +class Tags +{ +public: + static const string CODE_NAME; + static const string CODE_ARTIST; + static const string CODE_ALBUMARTIST; + static const string CODE_ALBUM; + static const string CODE_GROUPING; + static const string CODE_COMPOSER; + static const string CODE_COMMENTS; + static const string CODE_GENRE; + static const string CODE_GENRETYPE; + static const string CODE_RELEASEDATE; + static const string CODE_TRACK; + static const string CODE_DISK; + static const string CODE_TEMPO; + static const string CODE_COMPILATION; + + static const string CODE_TVSHOW; + static const string CODE_TVNETWORK; + static const string CODE_TVEPISODEID; + static const string CODE_TVSEASON; + static const string CODE_TVEPISODE; + + static const string CODE_DESCRIPTION; + static const string CODE_LONGDESCRIPTION; + static const string CODE_LYRICS; + + static const string CODE_SORTNAME; + static const string CODE_SORTARTIST; + static const string CODE_SORTALBUMARTIST; + static const string CODE_SORTALBUM; + static const string CODE_SORTCOMPOSER; + static const string CODE_SORTTVSHOW; + + static const string CODE_COPYRIGHT; + static const string CODE_ENCODINGTOOL; + static const string CODE_ENCODEDBY; + static const string CODE_PURCHASEDATE; + + static const string CODE_PODCAST; + static const string CODE_KEYWORDS; + static const string CODE_CATEGORY; + + static const string CODE_HDVIDEO; + static const string CODE_MEDIATYPE; + static const string CODE_CONTENTRATING; + static const string CODE_GAPLESS; + + static const string CODE_ITUNESACCOUNT; + static const string CODE_ITUNESACCOUNTTYPE; + static const string CODE_ITUNESCOUNTRY; + static const string CODE_CONTENTID; + static const string CODE_ARTISTID; + static const string CODE_PLAYLISTID; + static const string CODE_GENREID; + static const string CODE_COMPOSERID; + static const string CODE_XID; + +public: + string name; + string artist; + string albumArtist; + string album; + string grouping; + string composer; + string comments; + string genre; + uint16_t genreType; + string releaseDate; + MP4TagTrack track; + MP4TagDisk disk; + uint16_t tempo; + uint8_t compilation; + + string tvShow; + string tvEpisodeID; + uint32_t tvSeason; + uint32_t tvEpisode; + string tvNetwork; + + string description; + string longDescription; + string lyrics; + + string sortName; + string sortArtist; + string sortAlbumArtist; + string sortAlbum; + string sortComposer; + string sortTVShow; + + CoverArtBox::ItemList artwork; + + string copyright; + string encodingTool; + string encodedBy; + string purchaseDate; + + uint8_t podcast; + string keywords; + string category; + + uint8_t hdVideo; + uint8_t mediaType; + uint8_t contentRating; + uint8_t gapless; + + string iTunesAccount; + uint8_t iTunesAccountType; + uint32_t iTunesCountry; + uint32_t contentID; + uint32_t artistID; + uint64_t playlistID; + uint32_t genreID; + uint32_t composerID; + string xid; + + bool hasMetadata; + +public: + Tags(); + ~Tags(); + + void c_alloc ( MP4Tags*& ); + void c_fetch ( MP4Tags*&, MP4FileHandle ); + void c_store ( MP4Tags*&, MP4FileHandle ); + void c_free ( MP4Tags*& ); + + void c_addArtwork ( MP4Tags*&, MP4TagArtwork& ); + void c_setArtwork ( MP4Tags*&, uint32_t, MP4TagArtwork& ); + void c_removeArtwork ( MP4Tags*&, uint32_t ); + + void c_setString ( const char*, string&, const char*& ); + void c_setInteger ( const uint8_t*, uint8_t&, const uint8_t*& ); + void c_setInteger ( const uint16_t*, uint16_t&, const uint16_t*& ); + void c_setInteger ( const uint32_t*, uint32_t&, const uint32_t*& ); + void c_setInteger ( const uint64_t*, uint64_t&, const uint64_t*& ); + + void c_setTrack ( const MP4TagTrack*, MP4TagTrack&, const MP4TagTrack*& ); + void c_setDisk ( const MP4TagDisk*, MP4TagDisk&, const MP4TagDisk*& ); + +private: + typedef map<string,MP4ItmfItem*> CodeItemMap; + +private: + void fetchString ( const CodeItemMap&, const string&, string&, const char*& ); + void fetchInteger ( const CodeItemMap&, const string&, uint8_t&, const uint8_t*& ); + void fetchInteger ( const CodeItemMap&, const string&, uint16_t&, const uint16_t*& ); + void fetchInteger ( const CodeItemMap&, const string&, uint32_t&, const uint32_t*& ); + void fetchInteger ( const CodeItemMap&, const string&, uint64_t&, const uint64_t*& ); + + void fetchGenre ( const CodeItemMap&, uint16_t&, const uint16_t*& ); + void fetchTrack ( const CodeItemMap&, MP4TagTrack&, const MP4TagTrack*& ); + void fetchDisk ( const CodeItemMap&, MP4TagDisk&, const MP4TagDisk*& ); + + void storeString ( MP4File&, const string&, const string&, const char* ); + void storeInteger ( MP4File&, const string&, uint8_t, const uint8_t* ); + void storeInteger ( MP4File&, const string&, uint16_t, const uint16_t* ); + void storeInteger ( MP4File&, const string&, uint32_t, const uint32_t* ); + void storeInteger ( MP4File&, const string&, uint64_t, const uint64_t* ); + + void storeGenre ( MP4File&, uint16_t, const uint16_t* ); + void storeTrack ( MP4File&, const MP4TagTrack&, const MP4TagTrack* ); + void storeDisk ( MP4File&, const MP4TagDisk&, const MP4TagDisk* ); + + void remove ( MP4File&, const string& ); + void store ( MP4File&, const string&, MP4ItmfBasicType, const void*, uint32_t ); + + void updateArtworkShadow( MP4Tags*& ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf + +#endif // MP4V2_IMPL_ITMF_TAGS_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/generic.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/generic.cpp new file mode 100644 index 00000000..184cd74b --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/generic.cpp @@ -0,0 +1,476 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { namespace itmf { namespace { + +/////////////////////////////////////////////////////////////////////////////// + +void +__dataInit( MP4ItmfData& data ) +{ + data.typeSetIdentifier = 0; + data.typeCode = MP4_ITMF_BT_IMPLICIT; + data.locale = 0; + data.value = NULL; + data.valueSize = 0; +} + +void +__dataClear( MP4ItmfData& data ) +{ + if( data.value ) + free( data.value ); + __dataInit( data ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +__dataListInit( MP4ItmfDataList& list ) +{ + list.elements = NULL; + list.size = 0; +} + +void +__dataListClear( MP4ItmfDataList& list ) +{ + if( list.elements ) { + for( uint32_t i = 0; i < list.size; i++ ) + __dataClear( list.elements[i] ); + free( list.elements ); + } + + __dataListInit( list ); +} + +void +__dataListResize( MP4ItmfDataList& list, uint32_t size ) +{ + __dataListClear( list ); + + list.elements = (MP4ItmfData*)malloc( sizeof( MP4ItmfData ) * size ); + list.size = size; + + for( uint32_t i = 0; i < size; i++ ) + __dataInit( list.elements[i] ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +__itemInit( MP4ItmfItem& item ) +{ + item.__handle = NULL; + item.code = NULL; + item.mean = NULL; + item.name = NULL; + + __dataListInit( item.dataList ); +} + +void +__itemClear( MP4ItmfItem& item ) +{ + if( item.code ) + free( item.code ); + if( item.mean ) + free( item.mean ); + if( item.name ) + free( item.name ); + + __dataListClear( item.dataList ); + __itemInit( item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +__itemListInit( MP4ItmfItemList& list ) +{ + list.elements = NULL; + list.size = 0; +} + +void +__itemListClear( MP4ItmfItemList& list ) +{ + if( list.elements ) { + for( uint32_t i = 0; i < list.size; i++ ) + __itemClear( list.elements[i] ); + free( list.elements ); + } + + __itemListInit( list ); +} + +void +__itemListResize( MP4ItmfItemList& list, uint32_t size ) +{ + __itemListClear( list ); + if( !size ) + return; + + list.elements = (MP4ItmfItem*)malloc( sizeof( MP4ItmfItem ) * size ); + list.size = size; + + for( uint32_t i = 0; i < size; i++ ) + __itemInit( list.elements[i] ); +} + +MP4ItmfItemList* +__itemListAlloc() +{ + MP4ItmfItemList& list = *(MP4ItmfItemList*)malloc( sizeof( MP4ItmfItemList )); + __itemListInit( list ); + return &list; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool +__itemAtomToModel( MP4ItemAtom& item_atom, MP4ItmfItem& model ) +{ + __itemClear( model ); + model.__handle = &item_atom; + model.code = strdup( item_atom.GetType() ); + + // handle special meaning atom + if( ATOMID( item_atom.GetType() ) == ATOMID( "----" )) { + // meaning is mandatory + MP4MeanAtom* mean = (MP4MeanAtom*)item_atom.FindAtom( "----.mean" ); + if( !mean ) + return true; + + // copy atom UTF-8 value (not NULL-terminated) to model (NULL-terminated) + model.mean = mean->value.GetValueStringAlloc(); + + // name is optional + MP4NameAtom* name = (MP4NameAtom*)item_atom.FindAtom( "----.name" ); + if( name ) { + // copy atom UTF-8 value (not NULL-terminated) to model (NULL-terminated) + model.name = name->value.GetValueStringAlloc(); + } + } + + // pass 1: count data atoms + const uint32_t childCount = item_atom.GetNumberOfChildAtoms(); + uint32_t dataCount = 0; + for( uint32_t i = 0; i < childCount; i++ ) { + if( ATOMID( item_atom.GetChildAtom( i )->GetType() ) != ATOMID( "data" )) + continue; + dataCount++; + } + + // one or more data atoms is mandatory + if( dataCount < 1 ) + return true; + + __dataListResize( model.dataList, dataCount ); + + // pass 2: populate data model + for( uint32_t i = 0, idata = 0; i < childCount; i++ ) { + MP4Atom* atom = item_atom.GetChildAtom( i ); + if( ATOMID( atom->GetType() ) != ATOMID( "data" )) + continue; + + MP4DataAtom& data_atom = *(MP4DataAtom*)atom; + MP4ItmfData& data_model = model.dataList.elements[idata]; + + data_model.typeSetIdentifier = data_atom.typeSetIdentifier.GetValue(); + data_model.typeCode = (MP4ItmfBasicType)data_atom.typeCode.GetValue(); + data_model.locale = data_atom.locale.GetValue(); + + data_atom.metadata.GetValue( &data_model.value, &data_model.valueSize ); + idata++; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool +__itemModelToAtom( const MP4ItmfItem& model, MP4ItemAtom& atom ) +{ + if( ATOMID( atom.GetType() ) == ATOMID( "----" )) { + ASSERT( model.mean ); // mandatory + MP4MeanAtom& meanAtom = *(MP4MeanAtom*)MP4Atom::CreateAtom( atom.GetFile(), &atom, "mean" ); + atom.AddChildAtom( &meanAtom ); + meanAtom.value.SetValue( (const uint8_t*)model.mean, (uint32_t)strlen( model.mean )); + + if( model.name ) { + MP4NameAtom& nameAtom = *(MP4NameAtom*)MP4Atom::CreateAtom( atom.GetFile(), &atom, "name" ); + atom.AddChildAtom( &nameAtom ); + nameAtom.value.SetValue( (const uint8_t*)model.name, (uint32_t)strlen( model.name )); + } + } + + for( uint32_t i = 0; i < model.dataList.size; i++ ) { + MP4ItmfData& dataModel = model.dataList.elements[i]; + MP4DataAtom& dataAtom = *(MP4DataAtom*)MP4Atom::CreateAtom( atom.GetFile(), &atom, "data" ); + atom.AddChildAtom( &dataAtom ); + + dataAtom.typeSetIdentifier.SetValue( dataModel.typeSetIdentifier ); + dataAtom.typeCode.SetValue( (itmf::BasicType)dataModel.typeCode ); + dataAtom.locale.SetValue( dataModel.locale ); + dataAtom.metadata.SetValue( dataModel.value, dataModel.valueSize ); + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace anonymous + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItem* +genericItemAlloc( const string& code, uint32_t numData ) +{ + MP4ItmfItem* item = (MP4ItmfItem*)malloc( sizeof( MP4ItmfItem )); + if( !item ) + return NULL; + + __itemInit( *item ); + item->code = strdup( code.c_str() ); + + // always create array size of 1 + __dataListResize( item->dataList, numData ); + + return item; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +genericItemFree( MP4ItmfItem* item ) +{ + if( !item ) + return; + + __itemClear( *item ); + free( item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void +genericItemListFree( MP4ItmfItemList* list ) +{ + if( !list ) + return; + + __itemListClear( *list ); + free( list ); +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +genericGetItems( MP4File& file ) +{ + MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); + if( !ilst ) + return __itemListAlloc(); + + const uint32_t itemCount = ilst->GetNumberOfChildAtoms(); + if( itemCount < 1 ) + return __itemListAlloc(); + + MP4ItmfItemList& list = *__itemListAlloc(); + __itemListResize( list, itemCount ); + + for( uint32_t i = 0; i < list.size; i++ ) + __itemAtomToModel( *(MP4ItemAtom*)ilst->GetChildAtom( i ), list.elements[i] ); + + return &list; +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +genericGetItemsByCode( MP4File& file, const string& code ) +{ + MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); + if( !ilst ) + return __itemListAlloc(); + + // pass 1: filter by code and populate indexList + const uint32_t childCount = ilst->GetNumberOfChildAtoms(); + vector<uint32_t> indexList; + for( uint32_t i = 0; i < childCount; i++ ) { + if( ATOMID( ilst->GetChildAtom( i )->GetType() ) != ATOMID( code.c_str() )) + continue; + indexList.push_back( i ); + } + + if( indexList.size() < 1 ) + return __itemListAlloc(); + + MP4ItmfItemList& list = *__itemListAlloc(); + __itemListResize( list, (uint32_t)indexList.size() ); + + // pass 2: process each atom + const vector<uint32_t>::size_type max = indexList.size(); + for( vector<uint32_t>::size_type i = 0; i < max; i++ ) { + uint32_t& aidx = indexList[i]; + __itemAtomToModel( *(MP4ItemAtom*)ilst->GetChildAtom( aidx ), list.elements[i] ); + } + + return &list; +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +genericGetItemsByMeaning( MP4File& file, const string& meaning, const string& name ) +{ + MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); + if( !ilst ) + return __itemListAlloc(); + + // pass 1: filter by code and populate indexList + const uint32_t childCount = ilst->GetNumberOfChildAtoms(); + vector<uint32_t> indexList; + for( uint32_t i = 0; i < childCount; i++ ) { + MP4Atom& atom = *ilst->GetChildAtom( i ); + if( ATOMID( atom.GetType() ) != ATOMID( "----" )) + continue; + + // filter-out meaning mismatch + MP4MeanAtom* meanAtom = (MP4MeanAtom*)atom.FindAtom( "----.mean" ); + if( !meanAtom ) + continue; + if( meanAtom->value.CompareToString( meaning )) + continue; + + if( !name.empty() ) { + // filter-out name mismatch + MP4MeanAtom* nameAtom = (MP4MeanAtom*)atom.FindAtom( "----.name" ); + if( !nameAtom ) + continue; + if( nameAtom->value.CompareToString( name )) + continue; + } + + indexList.push_back( i ); + } + + if( indexList.size() < 1 ) + return __itemListAlloc(); + + MP4ItmfItemList& list = *__itemListAlloc(); + __itemListResize( list, (uint32_t)indexList.size() ); + + // pass 2: process each atom + const vector<uint32_t>::size_type max = indexList.size(); + for( vector<uint32_t>::size_type i = 0; i < max; i++ ) { + uint32_t& aidx = indexList[i]; + __itemAtomToModel( *(MP4ItemAtom*)ilst->GetChildAtom( aidx ), list.elements[i] ); + } + + return &list; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +genericAddItem( MP4File& file, const MP4ItmfItem* item ) +{ + if( !item ) + return false; + + MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); + if( !ilst ) { + file.AddDescendantAtoms( "moov", "udta.meta.ilst" ); + ilst = file.FindAtom( "moov.udta.meta.ilst" ); + ASSERT( ilst ); + } + + MP4ItemAtom& itemAtom = *(MP4ItemAtom*)MP4Atom::CreateAtom( file, ilst, item->code ); + ilst->AddChildAtom( &itemAtom ); + + return __itemModelToAtom( *item, itemAtom ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +genericSetItem( MP4File& file, const MP4ItmfItem* item ) +{ + if( !item || !item->__handle ) + return false; + + MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); + if( !ilst ) + return false; + + MP4ItemAtom* const old = static_cast<MP4ItemAtom*>(item->__handle); + const uint32_t childCount = ilst->GetNumberOfChildAtoms(); + uint32_t fidx = numeric_limits<uint32_t>::max(); + for( uint32_t i = 0; i < childCount; i++ ) { + MP4Atom* atom = ilst->GetChildAtom( i ); + if( atom == old ) { + fidx = i; + break; + } + } + + if( fidx == numeric_limits<uint32_t>::max() ) + return false; + + ilst->DeleteChildAtom( old ); + delete old; + + MP4ItemAtom& itemAtom = *(MP4ItemAtom*)MP4Atom::CreateAtom( file, ilst, item->code ); + ilst->InsertChildAtom( &itemAtom, fidx ); + + return __itemModelToAtom( *item, itemAtom ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +genericRemoveItem( MP4File& file, const MP4ItmfItem* item ) +{ + if( !item || !item->__handle ) + return false; + + MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); + if( !ilst ) + return false; + + MP4ItemAtom* const old = static_cast<MP4ItemAtom*>(item->__handle); + ilst->DeleteChildAtom( old ); + delete old; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/generic.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/generic.h new file mode 100644 index 00000000..9edc7eb6 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/generic.h @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// KonaBlend, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ITMF_GENERIC_H +#define MP4V2_IMPL_ITMF_GENERIC_H + +namespace mp4v2 { namespace impl { namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItem* +genericItemAlloc( const string& code, uint32_t numData ); + +void +genericItemFree( MP4ItmfItem* item ); + +void +genericItemListFree( MP4ItmfItemList* list ); + +/////////////////////////////////////////////////////////////////////////////// + +MP4ItmfItemList* +genericGetItems( MP4File& file ); + +MP4ItmfItemList* +genericGetItemsByCode( MP4File& file, const string& code ); + +MP4ItmfItemList* +genericGetItemsByMeaning( MP4File& file, const string& meaning, const string& name ); + +/////////////////////////////////////////////////////////////////////////////// + +bool +genericAddItem( MP4File& file, const MP4ItmfItem* item ); + +bool +genericSetItem( MP4File& file, const MP4ItmfItem* item ); + +bool +genericRemoveItem( MP4File& file, const MP4ItmfItem* item ); + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf + +#endif // MP4V2_IMPL_ITMF_GENERIC_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/impl.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/impl.h new file mode 100644 index 00000000..9c7eb44f --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/impl.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ITMF_IMPL_H +#define MP4V2_IMPL_ITMF_IMPL_H + +/////////////////////////////////////////////////////////////////////////////// + +#include "src/impl.h" +#include "itmf.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_ITMF_IMPL_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/itmf.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/itmf.h new file mode 100644 index 00000000..cad38ed0 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/itmf.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ITMF_ITMF_H +#define MP4V2_IMPL_ITMF_ITMF_H + +/// @namespace mp4v2::impl::itmf (private) iTunes Metadata Format. +/// <b>WARNING: THIS IS A PRIVATE NAMESPACE. NOT FOR PUBLIC CONSUMPTION.</b> +/// +/// This namespace implements some features that are specified by the +/// iTunes Metadata Format Specification, revision 2008-04-16. +/// +namespace mp4v2 { namespace impl { namespace itmf { + ; +}}} + +/////////////////////////////////////////////////////////////////////////////// + +#include "CoverArtBox.h" +#include "Tags.h" +#include "generic.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_ITMF_ITMF_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/type.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/type.cpp new file mode 100644 index 00000000..44254f8d --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/type.cpp @@ -0,0 +1,314 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// Rouven Wessling, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const itmf::EnumBasicType::Entry itmf::EnumBasicType::data[] = { + { mp4v2::impl::itmf::BT_IMPLICIT, "implicit", "implicit" }, + { mp4v2::impl::itmf::BT_UTF8, "utf8", "UTF-8" }, + { mp4v2::impl::itmf::BT_UTF16, "utf16", "UTF-16" }, + { mp4v2::impl::itmf::BT_SJIS, "sjis", "S/JIS" }, + { mp4v2::impl::itmf::BT_HTML, "html", "HTML" }, + { mp4v2::impl::itmf::BT_XML, "xml", "XML" }, + { mp4v2::impl::itmf::BT_UUID, "uuid", "UUID" }, + { mp4v2::impl::itmf::BT_ISRC, "isrc", "ISRC" }, + { mp4v2::impl::itmf::BT_MI3P, "mi3p", "MI3P" }, + { mp4v2::impl::itmf::BT_GIF, "gif", "GIF" }, + { mp4v2::impl::itmf::BT_JPEG, "jpeg", "JPEG" }, + { mp4v2::impl::itmf::BT_PNG, "png", "PNG" }, + { mp4v2::impl::itmf::BT_URL, "url", "URL" }, + { mp4v2::impl::itmf::BT_DURATION, "duration", "duration" }, + { mp4v2::impl::itmf::BT_DATETIME, "datetime", "date/time" }, + { mp4v2::impl::itmf::BT_GENRES, "genres", "genres" }, + { mp4v2::impl::itmf::BT_INTEGER, "integer", "integer" }, + { mp4v2::impl::itmf::BT_RIAA_PA, "riaapa", "RIAA-PA" }, + { mp4v2::impl::itmf::BT_UPC, "upc", "UPC" }, + { mp4v2::impl::itmf::BT_BMP, "bmp", "BMP" }, + + { mp4v2::impl::itmf::BT_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const itmf::EnumGenreType::Entry itmf::EnumGenreType::data[] = { + { mp4v2::impl::itmf::GENRE_BLUES, "blues", "Blues" }, + { mp4v2::impl::itmf::GENRE_CLASSIC_ROCK, "classicrock", "Classic Rock" }, + { mp4v2::impl::itmf::GENRE_COUNTRY, "country", "Country" }, + { mp4v2::impl::itmf::GENRE_DANCE, "dance", "Dance" }, + { mp4v2::impl::itmf::GENRE_DISCO, "disco", "Disco" }, + { mp4v2::impl::itmf::GENRE_FUNK, "funk", "Funk" }, + { mp4v2::impl::itmf::GENRE_GRUNGE, "grunge", "Grunge" }, + { mp4v2::impl::itmf::GENRE_HIP_HOP, "hiphop", "Hop-Hop" }, + { mp4v2::impl::itmf::GENRE_JAZZ, "jazz", "Jazz" }, + { mp4v2::impl::itmf::GENRE_METAL, "metal", "Metal" }, + { mp4v2::impl::itmf::GENRE_NEW_AGE, "newage", "New Age" }, + { mp4v2::impl::itmf::GENRE_OLDIES, "oldies", "Oldies" }, + { mp4v2::impl::itmf::GENRE_OTHER, "other", "Other" }, + { mp4v2::impl::itmf::GENRE_POP, "pop", "Pop" }, + { mp4v2::impl::itmf::GENRE_R_AND_B, "rand_b", "R&B" }, + { mp4v2::impl::itmf::GENRE_RAP, "rap", "Rap" }, + { mp4v2::impl::itmf::GENRE_REGGAE, "reggae", "Reggae" }, + { mp4v2::impl::itmf::GENRE_ROCK, "rock", "Rock" }, + { mp4v2::impl::itmf::GENRE_TECHNO, "techno", "Techno" }, + { mp4v2::impl::itmf::GENRE_INDUSTRIAL, "industrial", "Industrial" }, + { mp4v2::impl::itmf::GENRE_ALTERNATIVE, "alternative", "Alternative" }, + { mp4v2::impl::itmf::GENRE_SKA, "ska", "Ska" }, + { mp4v2::impl::itmf::GENRE_DEATH_METAL, "deathmetal", "Death Metal" }, + { mp4v2::impl::itmf::GENRE_PRANKS, "pranks", "Pranks" }, + { mp4v2::impl::itmf::GENRE_SOUNDTRACK, "soundtrack", "Soundtrack" }, + { mp4v2::impl::itmf::GENRE_EURO_TECHNO, "eurotechno", "Euro-Techno" }, + { mp4v2::impl::itmf::GENRE_AMBIENT, "ambient", "Ambient" }, + { mp4v2::impl::itmf::GENRE_TRIP_HOP, "triphop", "Trip-Hop" }, + { mp4v2::impl::itmf::GENRE_VOCAL, "vocal", "Vocal" }, + { mp4v2::impl::itmf::GENRE_JAZZ_FUNK, "jazzfunk", "Jazz+Funk" }, + { mp4v2::impl::itmf::GENRE_FUSION, "fusion", "Fusion" }, + { mp4v2::impl::itmf::GENRE_TRANCE, "trance", "Trance" }, + { mp4v2::impl::itmf::GENRE_CLASSICAL, "classical", "Classical" }, + { mp4v2::impl::itmf::GENRE_INSTRUMENTAL, "instrumental", "Instrumental" }, + { mp4v2::impl::itmf::GENRE_ACID, "acid", "Acid" }, + { mp4v2::impl::itmf::GENRE_HOUSE, "house", "House" }, + { mp4v2::impl::itmf::GENRE_GAME, "game", "Game" }, + { mp4v2::impl::itmf::GENRE_SOUND_CLIP, "soundclip", "Sound Clip" }, + { mp4v2::impl::itmf::GENRE_GOSPEL, "gospel", "Gospel" }, + { mp4v2::impl::itmf::GENRE_NOISE, "noise", "Noise" }, + { mp4v2::impl::itmf::GENRE_ALTERNROCK, "alternrock", "AlternRock" }, + { mp4v2::impl::itmf::GENRE_BASS, "bass", "Bass" }, + { mp4v2::impl::itmf::GENRE_SOUL, "soul", "Soul" }, + { mp4v2::impl::itmf::GENRE_PUNK, "punk", "Punk" }, + { mp4v2::impl::itmf::GENRE_SPACE, "space", "Space" }, + { mp4v2::impl::itmf::GENRE_MEDITATIVE, "meditative", "Meditative" }, + { mp4v2::impl::itmf::GENRE_INSTRUMENTAL_POP, "instrumentalpop", "Instrumental Pop" }, + { mp4v2::impl::itmf::GENRE_INSTRUMENTAL_ROCK, "instrumentalrock", "Instrumental Rock" }, + { mp4v2::impl::itmf::GENRE_ETHNIC, "ethnic", "Ethnic" }, + { mp4v2::impl::itmf::GENRE_GOTHIC, "gothic", "Gothic" }, + { mp4v2::impl::itmf::GENRE_DARKWAVE, "darkwave", "Darkwave" }, + { mp4v2::impl::itmf::GENRE_TECHNO_INDUSTRIAL, "technoindustrial", "Techno-Industrial" }, + { mp4v2::impl::itmf::GENRE_ELECTRONIC, "electronic", "Electronic" }, + { mp4v2::impl::itmf::GENRE_POP_FOLK, "popfolk", "Pop-Folk" }, + { mp4v2::impl::itmf::GENRE_EURODANCE, "eurodance", "Eurodance" }, + { mp4v2::impl::itmf::GENRE_DREAM, "dream", "Dream" }, + { mp4v2::impl::itmf::GENRE_SOUTHERN_ROCK, "southernrock", "Southern Rock" }, + { mp4v2::impl::itmf::GENRE_COMEDY, "comedy", "Comedy" }, + { mp4v2::impl::itmf::GENRE_CULT, "cult", "Cult" }, + { mp4v2::impl::itmf::GENRE_GANGSTA, "gangsta", "Gangsta" }, + { mp4v2::impl::itmf::GENRE_TOP_40, "top40", "Top 40" }, + { mp4v2::impl::itmf::GENRE_CHRISTIAN_RAP, "christianrap", "Christian Rap" }, + { mp4v2::impl::itmf::GENRE_POP_FUNK, "popfunk", "Pop/Funk" }, + { mp4v2::impl::itmf::GENRE_JUNGLE, "jungle", "Jungle" }, + { mp4v2::impl::itmf::GENRE_NATIVE_AMERICAN, "nativeamerican", "Native American" }, + { mp4v2::impl::itmf::GENRE_CABARET, "cabaret", "Cabaret" }, + { mp4v2::impl::itmf::GENRE_NEW_WAVE, "newwave", "New Wave" }, + { mp4v2::impl::itmf::GENRE_PSYCHEDELIC, "psychedelic", "Psychedelic" }, + { mp4v2::impl::itmf::GENRE_RAVE, "rave", "Rave" }, + { mp4v2::impl::itmf::GENRE_SHOWTUNES, "showtunes", "Showtunes" }, + { mp4v2::impl::itmf::GENRE_TRAILER, "trailer", "Trailer" }, + { mp4v2::impl::itmf::GENRE_LO_FI, "lofi", "Lo-Fi" }, + { mp4v2::impl::itmf::GENRE_TRIBAL, "tribal", "Tribal" }, + { mp4v2::impl::itmf::GENRE_ACID_PUNK, "acidpunk", "Acid Punk" }, + { mp4v2::impl::itmf::GENRE_ACID_JAZZ, "acidjazz", "Acid Jazz" }, + { mp4v2::impl::itmf::GENRE_POLKA, "polka", "Polka" }, + { mp4v2::impl::itmf::GENRE_RETRO, "retro", "Retro" }, + { mp4v2::impl::itmf::GENRE_MUSICAL, "musical", "Musical" }, + { mp4v2::impl::itmf::GENRE_ROCK_AND_ROLL, "rockand_roll", "Rock & Roll" }, + + { mp4v2::impl::itmf::GENRE_HARD_ROCK, "hardrock", "Hard Rock" }, + { mp4v2::impl::itmf::GENRE_FOLK, "folk", "Folk" }, + { mp4v2::impl::itmf::GENRE_FOLK_ROCK, "folkrock", "Folk-Rock" }, + { mp4v2::impl::itmf::GENRE_NATIONAL_FOLK, "nationalfolk", "National Folk" }, + { mp4v2::impl::itmf::GENRE_SWING, "swing", "Swing" }, + { mp4v2::impl::itmf::GENRE_FAST_FUSION, "fastfusion", "Fast Fusion" }, + { mp4v2::impl::itmf::GENRE_BEBOB, "bebob", "Bebob" }, + { mp4v2::impl::itmf::GENRE_LATIN, "latin", "Latin" }, + { mp4v2::impl::itmf::GENRE_REVIVAL, "revival", "Revival" }, + { mp4v2::impl::itmf::GENRE_CELTIC, "celtic", "Celtic" }, + { mp4v2::impl::itmf::GENRE_BLUEGRASS, "bluegrass", "Bluegrass" }, + { mp4v2::impl::itmf::GENRE_AVANTGARDE, "avantgarde", "Avantgarde" }, + { mp4v2::impl::itmf::GENRE_GOTHIC_ROCK, "gothicrock", "Gothic Rock" }, + { mp4v2::impl::itmf::GENRE_PROGRESSIVE_ROCK, "progressiverock", "Progresive Rock" }, + { mp4v2::impl::itmf::GENRE_PSYCHEDELIC_ROCK, "psychedelicrock", "Psychedelic Rock" }, + { mp4v2::impl::itmf::GENRE_SYMPHONIC_ROCK, "symphonicrock", "SYMPHONIC_ROCK" }, + { mp4v2::impl::itmf::GENRE_SLOW_ROCK, "slowrock", "Slow Rock" }, + { mp4v2::impl::itmf::GENRE_BIG_BAND, "bigband", "Big Band" }, + { mp4v2::impl::itmf::GENRE_CHORUS, "chorus", "Chorus" }, + { mp4v2::impl::itmf::GENRE_EASY_LISTENING, "easylistening", "Easy Listening" }, + { mp4v2::impl::itmf::GENRE_ACOUSTIC, "acoustic", "Acoustic" }, + { mp4v2::impl::itmf::GENRE_HUMOUR, "humour", "Humor" }, + { mp4v2::impl::itmf::GENRE_SPEECH, "speech", "Speech" }, + { mp4v2::impl::itmf::GENRE_CHANSON, "chanson", "Chason" }, + { mp4v2::impl::itmf::GENRE_OPERA, "opera", "Opera" }, + { mp4v2::impl::itmf::GENRE_CHAMBER_MUSIC, "chambermusic", "Chamber Music" }, + { mp4v2::impl::itmf::GENRE_SONATA, "sonata", "Sonata" }, + { mp4v2::impl::itmf::GENRE_SYMPHONY, "symphony", "Symphony" }, + { mp4v2::impl::itmf::GENRE_BOOTY_BASS, "bootybass", "Booty Bass" }, + { mp4v2::impl::itmf::GENRE_PRIMUS, "primus", "Primus" }, + { mp4v2::impl::itmf::GENRE_PORN_GROOVE, "porngroove", "Porn Groove" }, + { mp4v2::impl::itmf::GENRE_SATIRE, "satire", "Satire" }, + { mp4v2::impl::itmf::GENRE_SLOW_JAM, "slowjam", "Slow Jam" }, + { mp4v2::impl::itmf::GENRE_CLUB, "club", "Club" }, + { mp4v2::impl::itmf::GENRE_TANGO, "tango", "Tango" }, + { mp4v2::impl::itmf::GENRE_SAMBA, "samba", "Samba" }, + { mp4v2::impl::itmf::GENRE_FOLKLORE, "folklore", "Folklore" }, + { mp4v2::impl::itmf::GENRE_BALLAD, "ballad", "Ballad" }, + { mp4v2::impl::itmf::GENRE_POWER_BALLAD, "powerballad", "Power Ballad" }, + { mp4v2::impl::itmf::GENRE_RHYTHMIC_SOUL, "rhythmicsoul", "Rhythmic Soul" }, + { mp4v2::impl::itmf::GENRE_FREESTYLE, "freestyle", "Freestyle" }, + { mp4v2::impl::itmf::GENRE_DUET, "duet", "Duet" }, + { mp4v2::impl::itmf::GENRE_PUNK_ROCK, "punkrock", "Punk Rock" }, + { mp4v2::impl::itmf::GENRE_DRUM_SOLO, "drumsolo", "Drum Solo" }, + { mp4v2::impl::itmf::GENRE_A_CAPELLA, "acapella", "A capella" }, + { mp4v2::impl::itmf::GENRE_EURO_HOUSE, "eurohouse", "Euro-House" }, + { mp4v2::impl::itmf::GENRE_DANCE_HALL, "dancehall", "Dance Hall" }, + { mp4v2::impl::itmf::GENRE_NONE, "none", "none" }, + + { mp4v2::impl::itmf::GENRE_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const itmf::EnumStikType::Entry itmf::EnumStikType::data[] = { + { mp4v2::impl::itmf::STIK_OLD_MOVIE, "oldmovie", "Movie" }, + { mp4v2::impl::itmf::STIK_NORMAL, "normal", "Normal" }, + { mp4v2::impl::itmf::STIK_AUDIOBOOK, "audiobook", "Audio Book" }, + { mp4v2::impl::itmf::STIK_MUSIC_VIDEO, "musicvideo", "Music Video" }, + { mp4v2::impl::itmf::STIK_MOVIE, "movie", "Movie" }, + { mp4v2::impl::itmf::STIK_TV_SHOW, "tvshow", "TV Show" }, + { mp4v2::impl::itmf::STIK_BOOKLET, "booklet", "Booklet" }, + { mp4v2::impl::itmf::STIK_RINGTONE, "ringtone", "Ringtone" }, + + { mp4v2::impl::itmf::STIK_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const itmf::EnumAccountType::Entry itmf::EnumAccountType::data[] = { + { mp4v2::impl::itmf::AT_ITUNES, "itunes", "iTunes" }, + { mp4v2::impl::itmf::AT_AOL, "aol", "AOL" }, + + { mp4v2::impl::itmf::AT_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const itmf::EnumCountryCode::Entry itmf::EnumCountryCode::data[] = { + { mp4v2::impl::itmf::CC_USA, "usa", "United States" }, + { mp4v2::impl::itmf::CC_USA, "fra", "France" }, + { mp4v2::impl::itmf::CC_DEU, "ger", "Germany" }, + { mp4v2::impl::itmf::CC_GBR, "gbr", "United Kingdom" }, + { mp4v2::impl::itmf::CC_AUT, "aut", "Austria" }, + { mp4v2::impl::itmf::CC_BEL, "bel", "Belgium" }, + { mp4v2::impl::itmf::CC_FIN, "fin", "Finland" }, + { mp4v2::impl::itmf::CC_GRC, "grc", "Greece" }, + { mp4v2::impl::itmf::CC_IRL, "irl", "Ireland" }, + { mp4v2::impl::itmf::CC_ITA, "ita", "Italy" }, + { mp4v2::impl::itmf::CC_LUX, "lux", "Luxembourg" }, + { mp4v2::impl::itmf::CC_NLD, "nld", "Netherlands" }, + { mp4v2::impl::itmf::CC_PRT, "prt", "Portugal" }, + { mp4v2::impl::itmf::CC_ESP, "esp", "Spain" }, + { mp4v2::impl::itmf::CC_CAN, "can", "Canada" }, + { mp4v2::impl::itmf::CC_SWE, "swe", "Sweden" }, + { mp4v2::impl::itmf::CC_NOR, "nor", "Norway" }, + { mp4v2::impl::itmf::CC_DNK, "dnk", "Denmark" }, + { mp4v2::impl::itmf::CC_CHE, "che", "Switzerland" }, + { mp4v2::impl::itmf::CC_AUS, "aus", "Australia" }, + { mp4v2::impl::itmf::CC_NZL, "nzl", "New Zealand" }, + { mp4v2::impl::itmf::CC_JPN, "jpn", "Japan" }, + + { mp4v2::impl::itmf::CC_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +template <> +const itmf::EnumContentRating::Entry itmf::EnumContentRating::data[] = { + { mp4v2::impl::itmf::CR_NONE, "none", "None" }, + { mp4v2::impl::itmf::CR_CLEAN, "clean", "Clean" }, + { mp4v2::impl::itmf::CR_EXPLICIT, "explicit", "Explicit" }, + + { mp4v2::impl::itmf::CR_UNDEFINED } // must be last +}; + +/////////////////////////////////////////////////////////////////////////////// + +namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +// must come after static data init +const EnumBasicType enumBasicType; +const EnumGenreType enumGenreType; +const EnumStikType enumStikType; +const EnumAccountType enumAccountType; +const EnumCountryCode enumCountryCode; +const EnumContentRating enumContentRating; + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + struct ImageHeader { + BasicType type; + string data; + }; + + // POD static init does not need singletons + static ImageHeader IMAGE_HEADERS[] = { + { BT_BMP, "\x42\x4d" }, + { BT_GIF, "GIF87a" }, + { BT_GIF, "GIF89a" }, + { BT_JPEG, "\xff\xd8\xff\xe0" }, + { BT_PNG, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" }, + { BT_UNDEFINED } // must be last + }; +} + +BasicType +computeBasicType( const void* buffer, uint32_t size ) +{ + ImageHeader* found = NULL; + for( ImageHeader* p = IMAGE_HEADERS; p->type != BT_UNDEFINED; p++ ) { + ImageHeader& h = *p; + + if( size < h.data.size() ) + continue; + + if( memcmp(h.data.data(), buffer, h.data.size()) == 0 ) { + found = &h; + break; + } + } + + return found ? found->type : BT_IMPLICIT; +} + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/type.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/type.h new file mode 100644 index 00000000..484c241c --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/itmf/type.h @@ -0,0 +1,296 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// Rouven Wessling, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_ITMF_TYPE_H +#define MP4V2_IMPL_ITMF_TYPE_H + +namespace mp4v2 { namespace impl { namespace itmf { + +/////////////////////////////////////////////////////////////////////////////// + +/// Basic set of types as detailed in spec. +enum BasicType { + BT_IMPLICIT = 0, ///< for use with tags for which no type needs to be indicated + BT_UTF8 = 1, ///< without any count or null terminator + BT_UTF16 = 2, ///< also known as UTF-16BE + BT_SJIS = 3, ///< deprecated unless it is needed for special Japanese characters + BT_HTML = 6, ///< the HTML file header specifies which HTML version + BT_XML = 7, ///< the XML header must identify the DTD or schemas + BT_UUID = 8, ///< also known as GUID; stored as 16 bytes in binary (valid as an ID) + BT_ISRC = 9, ///< stored as UTF-8 text (valid as an ID) + BT_MI3P = 10, ///< stored as UTF-8 text (valid as an ID) + BT_GIF = 12, ///< (deprecated) a GIF image + BT_JPEG = 13, ///< a JPEG image + BT_PNG = 14, ///< a PNG image + BT_URL = 15, ///< absolute, in UTF-8 characters + BT_DURATION = 16, ///< in milliseconds, 32-bit integer + BT_DATETIME = 17, ///< in UTC, counting seconds since midnight, January 1, 1904; 32 or 64-bits + BT_GENRES = 18, ///< a list of enumerated values, see #Genre + BT_INTEGER = 21, ///< a signed big-endian integer with length one of { 1,2,3,4,8 } bytes + BT_RIAA_PA = 24, ///< RIAA parental advisory; { -1=no, 1=yes, 0=unspecified }, 8-bit ingteger + BT_UPC = 25, ///< Universal Product Code, in text UTF-8 format (valid as an ID) + BT_BMP = 27, ///< Windows bitmap image + + BT_UNDEFINED = 255 +}; + +typedef Enum<BasicType,BT_UNDEFINED> EnumBasicType; +MP4V2_EXPORT extern const EnumBasicType enumBasicType; + +/////////////////////////////////////////////////////////////////////////////// + +/// enumerated genre as defined in ID3v1 specification but +1 as per iTMF spec. +/// Note values 80 and higher are Winamp extensions. +enum GenreType { + GENRE_UNDEFINED = 0, + + /* ID3v1 standard */ + GENRE_BLUES = 1, + GENRE_CLASSIC_ROCK = 2, + GENRE_COUNTRY = 3, + GENRE_DANCE = 4, + GENRE_DISCO = 5, + GENRE_FUNK = 6, + GENRE_GRUNGE = 7, + GENRE_HIP_HOP = 8, + GENRE_JAZZ = 9, + GENRE_METAL = 10, + GENRE_NEW_AGE = 11, + GENRE_OLDIES = 12, + GENRE_OTHER = 13, + GENRE_POP = 14, + GENRE_R_AND_B = 15, + GENRE_RAP = 16, + GENRE_REGGAE = 17, + GENRE_ROCK = 18, + GENRE_TECHNO = 19, + GENRE_INDUSTRIAL = 20, + GENRE_ALTERNATIVE = 21, + GENRE_SKA = 22, + GENRE_DEATH_METAL = 23, + GENRE_PRANKS = 24, + GENRE_SOUNDTRACK = 25, + GENRE_EURO_TECHNO = 26, + GENRE_AMBIENT = 27, + GENRE_TRIP_HOP = 28, + GENRE_VOCAL = 29, + GENRE_JAZZ_FUNK = 30, + GENRE_FUSION = 31, + GENRE_TRANCE = 32, + GENRE_CLASSICAL = 33, + GENRE_INSTRUMENTAL = 34, + GENRE_ACID = 35, + GENRE_HOUSE = 36, + GENRE_GAME = 37, + GENRE_SOUND_CLIP = 38, + GENRE_GOSPEL = 39, + GENRE_NOISE = 40, + GENRE_ALTERNROCK = 41, + GENRE_BASS = 42, + GENRE_SOUL = 43, + GENRE_PUNK = 44, + GENRE_SPACE = 45, + GENRE_MEDITATIVE = 46, + GENRE_INSTRUMENTAL_POP = 47, + GENRE_INSTRUMENTAL_ROCK = 48, + GENRE_ETHNIC = 49, + GENRE_GOTHIC = 50, + GENRE_DARKWAVE = 51, + GENRE_TECHNO_INDUSTRIAL = 52, + GENRE_ELECTRONIC = 53, + GENRE_POP_FOLK = 54, + GENRE_EURODANCE = 55, + GENRE_DREAM = 56, + GENRE_SOUTHERN_ROCK = 57, + GENRE_COMEDY = 58, + GENRE_CULT = 59, + GENRE_GANGSTA = 60, + GENRE_TOP_40 = 61, + GENRE_CHRISTIAN_RAP = 62, + GENRE_POP_FUNK = 63, + GENRE_JUNGLE = 64, + GENRE_NATIVE_AMERICAN = 65, + GENRE_CABARET = 66, + GENRE_NEW_WAVE = 67, + GENRE_PSYCHEDELIC = 68, + GENRE_RAVE = 69, + GENRE_SHOWTUNES = 70, + GENRE_TRAILER = 71, + GENRE_LO_FI = 72, + GENRE_TRIBAL = 73, + GENRE_ACID_PUNK = 74, + GENRE_ACID_JAZZ = 75, + GENRE_POLKA = 76, + GENRE_RETRO = 77, + GENRE_MUSICAL = 78, + GENRE_ROCK_AND_ROLL = 79, + + /* Winamp extension */ + GENRE_HARD_ROCK = 80, + GENRE_FOLK = 81, + GENRE_FOLK_ROCK = 82, + GENRE_NATIONAL_FOLK = 83, + GENRE_SWING = 84, + GENRE_FAST_FUSION = 85, + GENRE_BEBOB = 86, + GENRE_LATIN = 87, + GENRE_REVIVAL = 88, + GENRE_CELTIC = 89, + GENRE_BLUEGRASS = 90, + GENRE_AVANTGARDE = 91, + GENRE_GOTHIC_ROCK = 92, + GENRE_PROGRESSIVE_ROCK = 93, + GENRE_PSYCHEDELIC_ROCK = 94, + GENRE_SYMPHONIC_ROCK = 95, + GENRE_SLOW_ROCK = 96, + GENRE_BIG_BAND = 97, + GENRE_CHORUS = 98, + GENRE_EASY_LISTENING = 99, + GENRE_ACOUSTIC = 100, + GENRE_HUMOUR = 101, + GENRE_SPEECH = 102, + GENRE_CHANSON = 103, + GENRE_OPERA = 104, + GENRE_CHAMBER_MUSIC = 105, + GENRE_SONATA = 106, + GENRE_SYMPHONY = 107, + GENRE_BOOTY_BASS = 108, + GENRE_PRIMUS = 109, + GENRE_PORN_GROOVE = 110, + GENRE_SATIRE = 111, + GENRE_SLOW_JAM = 112, + GENRE_CLUB = 113, + GENRE_TANGO = 114, + GENRE_SAMBA = 115, + GENRE_FOLKLORE = 116, + GENRE_BALLAD = 117, + GENRE_POWER_BALLAD = 118, + GENRE_RHYTHMIC_SOUL = 119, + GENRE_FREESTYLE = 120, + GENRE_DUET = 121, + GENRE_PUNK_ROCK = 122, + GENRE_DRUM_SOLO = 123, + GENRE_A_CAPELLA = 124, + GENRE_EURO_HOUSE = 125, + GENRE_DANCE_HALL = 126, + + GENRE_NONE = 255 +}; + +typedef Enum<GenreType,GENRE_UNDEFINED> EnumGenreType; +MP4V2_EXPORT extern const EnumGenreType enumGenreType; + +/////////////////////////////////////////////////////////////////////////////// + +/// enumerated 8-bit Video Type used by iTunes. +/// Note values are not formally defined in any specification. +enum StikType { + STIK_OLD_MOVIE = 0, + STIK_NORMAL = 1, + STIK_AUDIOBOOK = 2, + STIK_MUSIC_VIDEO = 6, + STIK_MOVIE = 9, + STIK_TV_SHOW = 10, + STIK_BOOKLET = 11, + STIK_RINGTONE = 14, + + STIK_UNDEFINED = 255 +}; + +typedef Enum<StikType,STIK_UNDEFINED> EnumStikType; +MP4V2_EXPORT extern const EnumStikType enumStikType; + +/////////////////////////////////////////////////////////////////////////////// + +/// enumerated 8-bit Account Type used by the iTunes Store. +/// Note values are not formally defined in any specification. +enum AccountType { + AT_ITUNES = 0, + AT_AOL = 1, + + AT_UNDEFINED = 255 +}; + +typedef Enum<AccountType,AT_UNDEFINED> EnumAccountType; +MP4V2_EXPORT extern const EnumAccountType enumAccountType; + +/////////////////////////////////////////////////////////////////////////////// + +/// enumerated 32-bit Country Code used by the iTunes Store. +/// Note values are not formally defined in any specification. +enum CountryCode { + CC_USA = 143441, + CC_FRA = 143442, + CC_DEU = 143443, + CC_GBR = 143444, + CC_AUT = 143445, + CC_BEL = 143446, + CC_FIN = 143447, + CC_GRC = 143448, + CC_IRL = 143449, + CC_ITA = 143450, + CC_LUX = 143451, + CC_NLD = 143452, + CC_PRT = 143453, + CC_ESP = 143454, + CC_CAN = 143455, + CC_SWE = 143456, + CC_NOR = 143457, + CC_DNK = 143458, + CC_CHE = 143459, + CC_AUS = 143460, + CC_NZL = 143461, + CC_JPN = 143462, + + CC_UNDEFINED = 0 +}; + +typedef Enum<CountryCode,CC_UNDEFINED> EnumCountryCode; +MP4V2_EXPORT extern const EnumCountryCode enumCountryCode; + +/////////////////////////////////////////////////////////////////////////////// + +/// enumerated 8-bit Content Rating used by iTunes. +/// Note values are not formally defined in any specification. +enum ContentRating { + CR_NONE = 0, + CR_CLEAN = 2, + CR_EXPLICIT = 4, + + CR_UNDEFINED = 255 +}; + +typedef Enum<ContentRating,CR_UNDEFINED> EnumContentRating; +MP4V2_EXPORT extern const EnumContentRating enumContentRating; + +/////////////////////////////////////////////////////////////////////////////// +/// compute BasicType by examining raw bytes header. +MP4V2_EXPORT BasicType +computeBasicType( const void* buffer, uint32_t size ); + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::itmf + +#endif // MP4V2_IMPL_ITMF_TYPE_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/log.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/log.cpp new file mode 100644 index 00000000..26eea6b5 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/log.cpp @@ -0,0 +1,534 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is David Byron. +// Portions created by David Byron are Copyright (C) 2009, 2010, 2011. +// All Rights Reserved. +// +// Contributors: +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#include <iomanip> +#include <iostream> +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +MP4LogCallback Log::_cb_func = NULL; + +// There's no mechanism to set the log level at runtime at +// the moment so construct this so it only logs important +// stuff. +Log log(MP4_LOG_WARNING); + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log class constructor + */ +Log::Log( MP4LogLevel verbosity_ /* = MP4_LOG_NONE */ ) + : _verbosity ( verbosity_ ) + , verbosity ( _verbosity ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log class destructor + */ +Log::~Log() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Mutator for the callback function + * + * @param value the function to call + */ +void +Log::setLogCallback( MP4LogCallback value ) +{ + Log::_cb_func = value; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Mutator for the verbosity + * + * @param value the verbosity to use + */ +void +Log::setVerbosity( MP4LogLevel value ) +{ + _verbosity = value; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log an error message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::errorf( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_ERROR,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a warning message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::warningf( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_WARNING,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log an info message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::infof( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_INFO,format,ap); + va_end(ap); +} + +/** + * Log a verbose1 message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::verbose1f( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_VERBOSE1,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a verbose2 message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::verbose2f( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_VERBOSE2,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a verbose3 message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::verbose3f( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_VERBOSE3,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a verbose4 message + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::verbose4f( const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(MP4_LOG_VERBOSE4,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Dump info to the console or a callback + * + * @param indent the number of spaces to indent the info + * + * @param verbosity the level of detail the message contains + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::dump ( uint8_t indent, + MP4LogLevel verbosity_, + const char* format, ... ) +{ + va_list ap; + + va_start(ap,format); + this->vdump(indent,verbosity,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Dump info if it has appropriate verbosity, either to + * standard out (with a newline appended to @p format) or to + * the callback function (with no newline appended). + * + * @param indent the number of spaces to indent the info + * + * @param verbosity the level of detail the message contains + * + * @param format the format string to use to process @p ap. + * @p format should not contain a newline. + * + * @param ap varargs to build the message + */ +void +Log::vdump( uint8_t indent, + MP4LogLevel verbosity_, + const char* format, + va_list ap ) +{ + // Make sure nothing gets logged with MP4_LOG_NONE. + // That way people who ask for nothing to get logged + // won't get anything logged. + ASSERT(verbosity_ != MP4_LOG_NONE); + ASSERT(format); + ASSERT(format[0] != '\0'); + + if (verbosity_ > this->_verbosity) + { + // We're not set verbose enough to log this + return; + } + + if (Log::_cb_func) + { + ostringstream new_format; + + if (indent > 0) + { + string indent_str(indent,' '); + // new_format << setw(indent) << setfill(' ') << "" << setw(0); + // new_format << format; + new_format << indent_str << format; + Log::_cb_func(verbosity_,new_format.str().c_str(),ap); + return; + } + + Log::_cb_func(verbosity_,format,ap); + return; + } + + // No callback set so log to standard out. + if (indent > 0) + { + ::fprintf(stdout,"%*c",indent,' '); + } + ::vfprintf(stdout,format,ap); + ::fprintf(stdout,"\n"); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a message + * + * @param verbosity the level of detail the message contains + * + * @param format the format string to use to process the + * remaining arguments. @p format should not contain a + * newline. + */ +void +Log::printf( MP4LogLevel verbosity, + const char* format, + ... ) +{ + va_list ap; + + va_start(ap,format); + this->vprintf(verbosity,format,ap); + va_end(ap); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a message if it has appropriate verbosity, either to + * standard out (with a newline appended to @p format) or to + * the callback function (with no newline appended). + * + * @param verbosity the level of detail the message contains + * + * @param format the format string to use to process @p ap. + * @p format should not contain a newline. + * + * @param ap varargs to build the message + */ +void +Log::vprintf( MP4LogLevel verbosity_, + const char* format, + va_list ap ) +{ + // Make sure nothing gets logged with MP4_LOG_NONE. + // That way people who ask for nothing to get logged + // won't get anything logged. + ASSERT(verbosity_ != MP4_LOG_NONE); + ASSERT(format); + + if (verbosity_ > this->_verbosity) + { + // We're not set verbose enough to log this + return; + } + + if (Log::_cb_func) + { + Log::_cb_func(verbosity_,format,ap); + return; + } + + // No callback set so log to standard out. + ::vfprintf(stdout,format,ap); + ::fprintf(stdout,"\n"); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log a buffer as ascii-hex + * + * @param indent the number of spaces to indent the buffer + * + * @param verbosity the level of detail the message contains + * + * @param pBytes the buffer to log + * + * @param numBytes the number of bytes to log + * + * @param format the format string to use to process the + * remaining arguments, where the format + remaining args + * describe @p pBytes. The resulting string should not + * contain a newline. Only the first 255 characters of the + * resulting string (not including the NUL terminator) make + * it to the log callback or stdout. + */ +void +Log::hexDump( uint8_t indent, + MP4LogLevel verbosity_, + const uint8_t* pBytes, + uint32_t numBytes, + const char* format, + ... ) +{ + va_list ap; + + ASSERT(pBytes || (numBytes == 0)); + ASSERT(format); + + if (verbosity_ > this->_verbosity) + { + // We're not set verbose enough to log this + return; + } + + // Build the description by processing format and the + // remaining args. Since we don't have asprintf, pick + // an arbitrary length for the string and use snprintf. + // To save a memory allocation, only do this if there's + // a non-empty format string or non-zero indent + char *desc = NULL; + if (format[0] || indent) + { + desc = (char *)MP4Calloc(256 + indent); + sprintf(desc,"%*c",indent,' '); + va_start(ap,format); + vsnprintf(desc + indent,255,format,ap); + va_end(ap); + } + + // From here we can use the C++ standard lib classes and + // build a string for each line + for (uint32_t i = 0;(i < numBytes);i += 16) + { + // ios_base::ate means at end. With out this desc + // gets overwritten with each << operation + ostringstream oneLine(desc ? desc : "",ios_base::ate); + + // Append the byte offset this line starts with as + // an 8 character, leading 0, hex number. Leave the + // fill character set to 0 for the remaining + // operations + oneLine << ':' << hex << setw(8) << setfill('0') << + std::right << i << setw(0) << setfill(' ') << ": "; + + uint32_t curlen = min((uint32_t)16,numBytes - i); + const uint8_t *b = pBytes + i; + uint32_t j; + + for (j = 0;(j < curlen);j++) + { + oneLine << hex << setw(2) << setfill('0') << right << static_cast<uint32_t>(b[j]); + oneLine << setw(0) << setfill(' ') << ' '; + } + + for (; j < 16; j++) + { + oneLine << " "; + } + + b = pBytes + i; + for (j = 0;(j < curlen);j++) + { + if (isprint(static_cast<int>(b[j]))) + { + oneLine << static_cast<char>(b[j]); + } + else + { + oneLine << '.'; + } + } + + // We can either call the callback directly or use + // the Log::printf function. To call the callback + // directly, we need a va_list. (I think) we need + // and extra function call to build that, so we may + // as well call Log::printf. It's going to + // double-check the verbosity and the callback + // function pointer, but that seems OK (13-feb-09, + // dbyron) + this->printf(verbosity_,"%s",oneLine.str().c_str()); + } + + if (desc) + { + MP4Free(desc); + desc = NULL; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Log an Exception as an error + * + * @param x the exception to log + */ +void +Log::errorf ( const Exception& x ) +{ + this->printf(MP4_LOG_ERROR,"%s",x.msg().c_str()); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +using namespace mp4v2::impl; + +extern "C" +void MP4SetLogCallback( MP4LogCallback cb_func ) +{ + Log::setLogCallback(cb_func); +} + +extern "C" +MP4LogLevel MP4LogGetLevel(void) +{ + return mp4v2::impl::log.verbosity; +} + +extern "C" +void MP4LogSetLevel( MP4LogLevel verbosity ) +{ + try + { + mp4v2::impl::log.setVerbosity(verbosity); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } +} + diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/log.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/log.h new file mode 100644 index 00000000..e7a6e001 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/log.h @@ -0,0 +1,93 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is David Byron. +// Portions created by David Byron are Copyright (C) 2009, 2010, 2011. +// All Rights Reserved. +// +// Contributors: +// David Byron, [email protected] +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_LOG_H +#define MP4V2_IMPL_LOG_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Handle logging either to standard out or to a callback + * function + */ +class MP4V2_EXPORT Log { +private: + MP4LogLevel _verbosity; + static MP4LogCallback _cb_func; + +public: + const MP4LogLevel& verbosity; + +public: + Log( MP4LogLevel = MP4_LOG_NONE ); + virtual ~Log(); + + static void setLogCallback ( MP4LogCallback ); + + void setVerbosity ( MP4LogLevel ); + + void errorf ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + void warningf ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + void infof ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + void verbose1f ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + void verbose2f ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + void verbose3f ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + void verbose4f ( const char* format, ... ) MP4V2_WFORMAT_PRINTF(2,3); + + void dump ( uint8_t indent, + MP4LogLevel verbosity_, + const char* format, ... ) MP4V2_WFORMAT_PRINTF(4,5); + void vdump ( uint8_t indent, + MP4LogLevel verbosity_, + const char* format, va_list ap ); + void printf ( MP4LogLevel verbosity_, + const char* format, ... ) MP4V2_WFORMAT_PRINTF(3,4); + void vprintf ( MP4LogLevel verbosity_, + const char* format, va_list ap ); + + void hexDump ( uint8_t indent, + MP4LogLevel verbosity_, + const uint8_t* pBytes, + uint32_t numBytes, + const char* format, ... ) MP4V2_WFORMAT_PRINTF(6,7); + + void errorf ( const Exception& x ); + +private: + Log ( const Log &src ); + Log &operator= ( const Log &src ); +}; + +/** + * A global (at least to mp4v2) log object for code that + * needs to log something but doesn't otherwise have access + * to one + */ +extern Log log; +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_LOG_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4.cpp new file mode 100644 index 00000000..36052986 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4.cpp @@ -0,0 +1,4563 @@ +/* + * 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 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + * Bill May [email protected] + */ + +/* + * MP4 library API functions + * + * These are wrapper functions that provide C linkage conventions + * to the library, and catch any internal errors, ensuring that + * a proper return value is given. + */ + +#include "src/impl.h" + +using namespace mp4v2::impl; + +static MP4File *ConstructMP4File ( void ) +{ + MP4File* pFile = NULL; + try { + pFile = new MP4File(); + } + catch( std::bad_alloc ) { + mp4v2::impl::log.errorf("%s: unable to allocate MP4File", __FUNCTION__); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: unknown exception constructing MP4File", __FUNCTION__ ); + } + + return pFile; +} + +extern "C" { + +const char* MP4GetFilename( MP4FileHandle hFile ) +{ + if (!MP4_IS_VALID_FILE_HANDLE(hFile)) + return NULL; + try + { + ASSERT(hFile); + MP4File& file = *static_cast<MP4File*>(hFile); + ASSERT(file.GetFilename().c_str()); + return file.GetFilename().c_str(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: unknown exception accessing MP4File " + "filename", __FUNCTION__ ); + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4FileHandle MP4Read( const char* fileName ) +{ + if (!fileName) + return MP4_INVALID_FILE_HANDLE; + + MP4File *pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try + { + ASSERT(pFile); + pFile->Read( fileName, NULL ); + return (MP4FileHandle)pFile; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: \"%s\": failed", __FUNCTION__, + fileName ); + } + + if (pFile) + delete pFile; + return MP4_INVALID_FILE_HANDLE; +} + +MP4FileHandle MP4ReadProvider( const char* fileName, const MP4FileProvider* fileProvider ) +{ + if (!fileName) + return MP4_INVALID_FILE_HANDLE; + + MP4File *pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try { + pFile->Read( fileName, fileProvider ); + return (MP4FileHandle)pFile; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: \"%s\": failed", __FUNCTION__, + fileName ); + } + + if (pFile) + delete pFile; + return MP4_INVALID_FILE_HANDLE; +} + +/////////////////////////////////////////////////////////////////////////////// + + MP4FileHandle MP4Create (const char* fileName, + uint32_t flags) + { + return MP4CreateEx(fileName, flags); + } + + MP4FileHandle MP4CreateEx (const char* fileName, + uint32_t flags, + int add_ftyp, + int add_iods, + char* majorBrand, + uint32_t minorVersion, + char** supportedBrands, + uint32_t supportedBrandsCount) + { + if (!fileName) + return MP4_INVALID_FILE_HANDLE; + + MP4File* pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try { + ASSERT(pFile); + // LATER useExtensibleFormat, moov first, then mvex's + pFile->Create(fileName, flags, add_ftyp, add_iods, + majorBrand, minorVersion, + supportedBrands, supportedBrandsCount); + return (MP4FileHandle)pFile; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: \"%s\": failed", __FUNCTION__, + fileName ); + } + + if (pFile) + delete pFile; + return MP4_INVALID_FILE_HANDLE; + } + + MP4FileHandle MP4Modify(const char* fileName, + uint32_t flags) + { + if (!fileName) + return MP4_INVALID_FILE_HANDLE; + + MP4File* pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try { + ASSERT(pFile); + // LATER useExtensibleFormat, moov first, then mvex's + if (pFile->Modify(fileName)) + return (MP4FileHandle)pFile; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: \"%s\": failed", __FUNCTION__, + fileName ); + } + + if (pFile) + delete pFile; + return MP4_INVALID_FILE_HANDLE; + } + + bool MP4Optimize(const char* fileName, + const char* newFileName) + { + // Must at least have fileName for in-place optimize; newFileName + // can be null, however. + if (fileName == NULL) + return false; + + MP4File* pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try { + ASSERT(pFile); + pFile->Optimize(fileName, newFileName); + delete pFile; + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s(%s,%s) failed", __FUNCTION__, + fileName, newFileName ); + } + + if (pFile) + delete pFile; + return false; + } + + void MP4Close(MP4FileHandle hFile, uint32_t flags) + { + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return; + + MP4File& f = *(MP4File*)hFile; + try { + f.Close(flags); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + + delete &f; + } + + bool MP4Dump( + MP4FileHandle hFile, + bool dumpImplicits) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->Dump(dumpImplicits); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + MP4Duration MP4GetDuration(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetDuration(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + uint32_t MP4GetTimeScale(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTimeScale(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4SetTimeScale(MP4FileHandle hFile, uint32_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTimeScale(value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint8_t MP4GetODProfileLevel(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetODProfileLevel(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4SetODProfileLevel(MP4FileHandle hFile, uint8_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetODProfileLevel(value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint8_t MP4GetSceneProfileLevel(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSceneProfileLevel(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4SetSceneProfileLevel(MP4FileHandle hFile, uint8_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetSceneProfileLevel(value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint8_t MP4GetVideoProfileLevel(MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetVideoProfileLevel(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + if (MP4_IS_VALID_TRACK_ID(trackId)) { + uint8_t *foo; + uint32_t bufsize; + uint8_t type; + // for mpeg4 video tracks, try to look for the VOSH header, + // which has this info. + type = MP4GetTrackEsdsObjectTypeId(hFile, trackId); + if (type == MP4_MPEG4_VIDEO_TYPE) { + if (MP4GetTrackESConfiguration(hFile, + trackId, + &foo, + &bufsize)) { + uint8_t *ptr = foo; + while (bufsize > 0) { + if (MP4V2_HTONL(*(uint32_t *)ptr) == 0x1b0) { + uint8_t ret = ptr[4]; + free(foo); + return ret; + } + ptr++; + bufsize--; + } + free(foo); + } + } + } + + } + return 0; + } + + void MP4SetVideoProfileLevel(MP4FileHandle hFile, uint8_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetVideoProfileLevel(value); + return ; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return ; + } + + uint8_t MP4GetAudioProfileLevel(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetAudioProfileLevel(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + void MP4SetAudioProfileLevel(MP4FileHandle hFile, uint8_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetAudioProfileLevel(value); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + uint8_t MP4GetGraphicsProfileLevel(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetGraphicsProfileLevel(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4SetGraphicsProfileLevel(MP4FileHandle hFile, uint8_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetGraphicsProfileLevel(value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + /* generic file properties */ + + bool MP4HaveAtom (MP4FileHandle hFile, const char *atomName) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File *)hFile)->FindAtom(atomName) != NULL; + } catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetIntegerProperty( + MP4FileHandle hFile, const char* propName, uint64_t *retvalue) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetIntegerProperty(propName); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetFloatProperty( + MP4FileHandle hFile, const char* propName, float *retvalue) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetFloatProperty(propName); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetStringProperty( + MP4FileHandle hFile, const char* propName, + const char **retvalue) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetStringProperty(propName); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetBytesProperty( + MP4FileHandle hFile, const char* propName, + uint8_t** ppValue, uint32_t* pValueSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetBytesProperty(propName, ppValue, pValueSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + *ppValue = NULL; + *pValueSize = 0; + return false; + } + + bool MP4SetIntegerProperty( + MP4FileHandle hFile, const char* propName, int64_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetIntegerProperty(propName, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetFloatProperty( + MP4FileHandle hFile, const char* propName, float value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetFloatProperty(propName, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetStringProperty( + MP4FileHandle hFile, const char* propName, const char* value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetStringProperty(propName, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetBytesProperty( + MP4FileHandle hFile, const char* propName, + const uint8_t* pValue, uint32_t valueSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetBytesProperty(propName, pValue, valueSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + /* track operations */ + + MP4TrackId MP4AddTrack( + MP4FileHandle hFile, const char* type,uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSystemsTrack(type, timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddSystemsTrack( + MP4FileHandle hFile, const char* type) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSystemsTrack(type); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddODTrack(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddODTrack(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddSceneTrack(MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSceneTrack(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddULawAudioTrack( + MP4FileHandle hFile, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddULawAudioTrack(timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddALawAudioTrack( + MP4FileHandle hFile, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddALawAudioTrack(timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddAudioTrack( + MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint8_t audioType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddAudioTrack(timeScale, sampleDuration, audioType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + +// +// API to initialize ismacryp properties to sensible defaults. +// if the input pointer is null then an ismacryp params is malloc'd. +// caller must see to it that it is properly disposed of. +// + mp4v2_ismacrypParams *MP4DefaultISMACrypParams(mp4v2_ismacrypParams *ptr) + { + try + { + if (ptr == NULL) { + ptr = (mp4v2_ismacrypParams *)MP4Malloc(sizeof(mp4v2_ismacrypParams)); + } + memset(ptr, 0, sizeof(*ptr)); + return ptr; + } + + catch (...) { + return MP4_INVALID_TRACK_ID; + } + } + + + MP4TrackId MP4AddAC3AudioTrack( + MP4FileHandle hFile, + uint32_t samplingRate, + uint8_t fscod, + uint8_t bsid, + uint8_t bsmod, + uint8_t acmod, + uint8_t lfeon, + uint8_t bit_rate_code) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddAC3AudioTrack(samplingRate, fscod, bsid, bsmod, acmod, lfeon, bit_rate_code); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddEncAudioTrack(MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + mp4v2_ismacrypParams *icPp, + uint8_t audioType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + if (icPp == NULL) { + return ((MP4File*)hFile)-> + AddEncAudioTrack(timeScale, sampleDuration, audioType, + 0, 0, + 0, 0, + false, NULL, false); + } else { + return ((MP4File*)hFile)-> + AddEncAudioTrack(timeScale, sampleDuration, audioType, + icPp->scheme_type, icPp->scheme_version, + icPp->key_ind_len, icPp->iv_len, + icPp->selective_enc, icPp->kms_uri, true); + } + } catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + MP4TrackId MP4AddAmrAudioTrack( + MP4FileHandle hFile, + uint32_t timeScale, + uint16_t modeSet, + uint8_t modeChangePeriod, + uint8_t framesPerSample, + bool isAmrWB) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddAmrAudioTrack(timeScale, modeSet, modeChangePeriod, framesPerSample, isAmrWB); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + void MP4SetAmrVendor( + MP4FileHandle hFile, + MP4TrackId trackId, + uint32_t vendor) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetAmrVendor(trackId, vendor); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + void MP4SetAmrDecoderVersion( + MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t decoderVersion) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetAmrDecoderVersion(trackId, decoderVersion); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + void MP4SetAmrModeSet( + MP4FileHandle hFile, + MP4TrackId trackId, + uint16_t modeSet) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetAmrModeSet(trackId, modeSet); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + uint16_t MP4GetAmrModeSet( + MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetAmrModeSet(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + MP4TrackId MP4AddHrefTrack (MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddHrefTrack(timeScale, + sampleDuration, + base_url); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + const char *MP4GetHrefTrackBaseUrl (MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackStringProperty(trackId, + "mdia.minf.stbl.stsd.href.burl.base_url"); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + + MP4TrackId MP4AddVideoTrack( + MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t videoType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddMP4VideoTrack(timeScale, + sampleDuration, + width, + height, + videoType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddEncVideoTrack(MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + mp4v2_ismacrypParams *icPp, + uint8_t videoType, + const char *oFormat) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + // test for valid ismacrypt session descriptor + if (icPp == NULL) { + return MP4_INVALID_TRACK_ID; + } + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddEncVideoTrack(timeScale, + sampleDuration, + width, + height, + videoType, + icPp, + oFormat); + + } catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddColr( + MP4FileHandle hFile, MP4TrackId refTrackId, uint16_t pri, uint16_t tran, uint16_t mat) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddColr(refTrackId, pri, tran, mat); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + + MP4TrackId MP4AddH264VideoTrack(MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + return pFile->AddH264VideoTrack(timeScale, + sampleDuration, + width, + height, + AVCProfileIndication, + profile_compat, + AVCLevelIndication, + sampleLenFieldSizeMinusOne); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddEncH264VideoTrack( + MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp + ) + + { + MP4Atom *srcAtom; + MP4File *pFile; + + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + pFile = (MP4File *)srcFile; + srcAtom = pFile->FindTrackAtom(srcTrackId, "mdia.minf.stbl.stsd.avc1.avcC"); + if (srcAtom == NULL) + return MP4_INVALID_TRACK_ID; + + pFile = (MP4File *)hFile; + + return pFile->AddEncH264VideoTrack(timeScale, + sampleDuration, + width, + height, + srcAtom, + icPp); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + void MP4AddH264SequenceParameterSet (MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + pFile->AddH264SequenceParameterSet(trackId, + pSequence, + sequenceLen); + return; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return; + } + void MP4AddH264PictureParameterSet (MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t *pPict, + uint16_t pictLen) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File *pFile = (MP4File *)hFile; + + pFile->AddH264PictureParameterSet(trackId, + pPict, + pictLen); + return; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return; + } + + MP4TrackId MP4AddH263VideoTrack( + MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t h263Level, + uint8_t h263Profile, + uint32_t avgBitrate, + uint32_t maxBitrate) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + AddH263VideoTrack(timeScale, sampleDuration, width, height, h263Level, h263Profile, avgBitrate, maxBitrate); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + + return MP4_INVALID_TRACK_ID; + } + + void MP4SetH263Vendor( + MP4FileHandle hFile, + MP4TrackId trackId, + uint32_t vendor) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)-> + SetH263Vendor(trackId, vendor); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + void MP4SetH263DecoderVersion( + MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t decoderVersion) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + + try { + ((MP4File*)hFile)-> + SetH263DecoderVersion(trackId, decoderVersion); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + void MP4SetH263Bitrates( + MP4FileHandle hFile, + MP4TrackId trackId, + uint32_t avgBitrate, + uint32_t maxBitrate) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + + try { + ((MP4File*)hFile)-> + SetH263Bitrates(trackId, avgBitrate, maxBitrate); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + MP4TrackId MP4AddHintTrack( + MP4FileHandle hFile, MP4TrackId refTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddHintTrack(refTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddTextTrack( + MP4FileHandle hFile, MP4TrackId refTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddTextTrack(refTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddSubtitleTrack(MP4FileHandle hFile, + uint32_t timescale, + uint16_t width, + uint16_t height) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSubtitleTrack(timescale, width, height); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddSubpicTrack(MP4FileHandle hFile, + uint32_t timescale, + uint16_t width, + uint16_t height) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddSubpicTrack(timescale, width, height); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddChapterTextTrack( + MP4FileHandle hFile, MP4TrackId refTrackId, uint32_t timescale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddChapterTextTrack(refTrackId, timescale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + MP4TrackId MP4AddPixelAspectRatio( + MP4FileHandle hFile, MP4TrackId refTrackId, uint32_t hSpacing, uint32_t vSpacing) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->AddPixelAspectRatio(refTrackId, hSpacing, vSpacing); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + void MP4AddChapter( + MP4FileHandle hFile, MP4TrackId chapterTrackId, MP4Duration chapterDuration, const char *chapterTitle) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddChapter(chapterTrackId, chapterDuration, chapterTitle); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + void MP4AddNeroChapter( + MP4FileHandle hFile, MP4Timestamp chapterStart, const char *chapterTitle) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddNeroChapter(chapterStart, chapterTitle); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + MP4ChapterType MP4ConvertChapters( + MP4FileHandle hFile, MP4ChapterType toChapterType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) + { + try { + return ((MP4File*)hFile)->ConvertChapters(toChapterType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4ChapterTypeNone; + } + + MP4ChapterType MP4DeleteChapters( + MP4FileHandle hFile, MP4ChapterType fromChapterType, MP4TrackId chapterTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->DeleteChapters(fromChapterType, chapterTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4ChapterTypeNone; + } + + MP4ChapterType MP4GetChapters( + MP4FileHandle hFile, MP4Chapter_t ** chapterList, uint32_t * chapterCount, MP4ChapterType fromChapterType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetChapters(chapterList, chapterCount, fromChapterType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4ChapterTypeNone; + } + + MP4ChapterType MP4SetChapters( + MP4FileHandle hFile, MP4Chapter_t * chapterList, uint32_t chapterCount, MP4ChapterType toChapterType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->SetChapters(chapterList, chapterCount, toChapterType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4ChapterTypeNone; + } + + void MP4ChangeMovieTimeScale( + MP4FileHandle hFile, uint32_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ChangeMovieTimeScale(value); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + } + + MP4TrackId MP4CloneTrack (MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4FileHandle dstFile, + MP4TrackId dstHintTrackReferenceTrack) + { + MP4TrackId dstTrackId = MP4_INVALID_TRACK_ID; + + if (dstFile == NULL) { + dstFile = srcFile; + } + + const char* trackType = + MP4GetTrackType(srcFile, srcTrackId); + + if (!trackType) { + return dstTrackId; + } + + const char *media_data_name = + MP4GetTrackMediaDataName(srcFile, srcTrackId); + if (media_data_name == NULL) return dstTrackId; + + if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + if (ATOMID(media_data_name) == ATOMID("mp4v")) { + MP4SetVideoProfileLevel(dstFile, + MP4GetVideoProfileLevel(srcFile)); + dstTrackId = MP4AddVideoTrack( + dstFile, + MP4GetTrackTimeScale(srcFile, + srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, + srcTrackId), + MP4GetTrackVideoWidth(srcFile, + srcTrackId), + MP4GetTrackVideoHeight(srcFile, + srcTrackId), + MP4GetTrackEsdsObjectTypeId(srcFile, + srcTrackId)); + } else if (ATOMID(media_data_name) == ATOMID("avc1")) { + uint8_t AVCProfileIndication; + uint8_t profile_compat; + uint8_t AVCLevelIndication; + uint32_t sampleLenFieldSizeMinusOne; + uint64_t temp; + + if (MP4GetTrackH264ProfileLevel(srcFile, srcTrackId, + &AVCProfileIndication, + &AVCLevelIndication) == false) { + return dstTrackId; + } + if (MP4GetTrackH264LengthSize(srcFile, srcTrackId, + &sampleLenFieldSizeMinusOne) == false) { + return dstTrackId; + } + sampleLenFieldSizeMinusOne--; + if (MP4GetTrackIntegerProperty(srcFile, srcTrackId, + "mdia.minf.stbl.stsd.*[0].avcC.profile_compatibility", + &temp) == false) return dstTrackId; + profile_compat = temp & 0xff; + + dstTrackId = MP4AddH264VideoTrack(dstFile, + MP4GetTrackTimeScale(srcFile, + srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, + srcTrackId), + MP4GetTrackVideoWidth(srcFile, + srcTrackId), + MP4GetTrackVideoHeight(srcFile, + srcTrackId), + AVCProfileIndication, + profile_compat, + AVCLevelIndication, + sampleLenFieldSizeMinusOne); + uint8_t **seqheader, **pictheader; + uint32_t *pictheadersize, *seqheadersize; + uint32_t ix; + MP4GetTrackH264SeqPictHeaders(srcFile, srcTrackId, + &seqheader, &seqheadersize, + &pictheader, &pictheadersize); + for (ix = 0; seqheadersize[ix] != 0; ix++) { + MP4AddH264SequenceParameterSet(dstFile, dstTrackId, + seqheader[ix], seqheadersize[ix]); + free(seqheader[ix]); + } + free(seqheader); + free(seqheadersize); + for (ix = 0; pictheadersize[ix] != 0; ix++) { + MP4AddH264PictureParameterSet(dstFile, dstTrackId, + pictheader[ix], pictheadersize[ix]); + free(pictheader[ix]); + } + free(pictheader); + free(pictheadersize); + } else + return dstTrackId; + } else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) { + if (ATOMID(media_data_name) != ATOMID("mp4a")) return dstTrackId; + MP4SetAudioProfileLevel(dstFile, + MP4GetAudioProfileLevel(srcFile)); + dstTrackId = MP4AddAudioTrack( + dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, srcTrackId), + MP4GetTrackEsdsObjectTypeId(srcFile, srcTrackId)); + + } else if (MP4_IS_OD_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddODTrack(dstFile); + + } else if (MP4_IS_SCENE_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSceneTrack(dstFile); + + } else if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + if (dstHintTrackReferenceTrack == MP4_INVALID_TRACK_ID) { + dstTrackId = MP4_INVALID_TRACK_ID; + } else { + dstTrackId = MP4AddHintTrack( + dstFile, + dstHintTrackReferenceTrack); + } + + } else if (MP4_IS_SYSTEMS_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSystemsTrack(dstFile, trackType); + + } else { + dstTrackId = MP4AddTrack(dstFile, trackType); + } + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + MP4SetTrackTimeScale( + dstFile, + dstTrackId, + MP4GetTrackTimeScale(srcFile, srcTrackId)); + + if (MP4_IS_AUDIO_TRACK_TYPE(trackType) + || MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + // copy track ES configuration + uint8_t* pConfig = NULL; + uint32_t configSize = 0; + MP4LogLevel verb = mp4v2::impl::log.verbosity; + mp4v2::impl::log.setVerbosity(MP4_LOG_NONE); + bool haveEs = MP4GetTrackESConfiguration(srcFile, + srcTrackId, + &pConfig, + &configSize); + mp4v2::impl::log.setVerbosity(verb); + if (haveEs && + pConfig != NULL && configSize != 0) { + if (!MP4SetTrackESConfiguration( + dstFile, + dstTrackId, + pConfig, + configSize)) { + free(pConfig); + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + + free(pConfig); + } + } + + if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + // probably not exactly what is wanted + // but caller can adjust later to fit their desires + + char* payloadName = NULL; + char *encodingParms = NULL; + uint8_t payloadNumber; + uint16_t maxPayloadSize; + + if (MP4GetHintTrackRtpPayload( + srcFile, + srcTrackId, + &payloadName, + &payloadNumber, + &maxPayloadSize, + &encodingParms)) { + + if (MP4SetHintTrackRtpPayload( + dstFile, + dstTrackId, + payloadName, + &payloadNumber, + maxPayloadSize, + encodingParms) == false) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + } +#if 0 + MP4SetHintTrackSdp( + dstFile, + dstTrackId, + MP4GetHintTrackSdp(srcFile, srcTrackId)); +#endif + } + + return dstTrackId; + } + +// Given a track, make an encrypted clone of it in the dest. file + MP4TrackId MP4EncAndCloneTrack(MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp, + MP4FileHandle dstFile, + MP4TrackId dstHintTrackReferenceTrack + ) + { + const char *oFormat; + + MP4TrackId dstTrackId = MP4_INVALID_TRACK_ID; + + if (dstFile == NULL) { + dstFile = srcFile; + } + + const char* trackType = MP4GetTrackType(srcFile, srcTrackId); + + if (!trackType) { + return dstTrackId; + } + + if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + + // test source file format for avc1 + oFormat = MP4GetTrackMediaDataName(srcFile, srcTrackId); + if (!strcasecmp(oFormat, "avc1")) + { + dstTrackId = MP4AddEncH264VideoTrack(dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, srcTrackId), + MP4GetTrackVideoWidth(srcFile, srcTrackId), + MP4GetTrackVideoHeight(srcFile, srcTrackId), + srcFile, + srcTrackId, + icPp + ); + } + else + { + MP4SetVideoProfileLevel(dstFile, MP4GetVideoProfileLevel(srcFile)); + dstTrackId = MP4AddEncVideoTrack(dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, srcTrackId), + MP4GetTrackVideoWidth(srcFile, srcTrackId), + MP4GetTrackVideoHeight(srcFile, srcTrackId), + icPp, + MP4GetTrackEsdsObjectTypeId(srcFile, srcTrackId), + oFormat + ); + } + + } else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) { + MP4SetAudioProfileLevel(dstFile, MP4GetAudioProfileLevel(srcFile)); + dstTrackId = MP4AddEncAudioTrack(dstFile, + MP4GetTrackTimeScale(srcFile, srcTrackId), + MP4GetTrackFixedSampleDuration(srcFile, + srcTrackId), + icPp, + MP4GetTrackEsdsObjectTypeId(srcFile, + srcTrackId) + ); + + } else if (MP4_IS_OD_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddODTrack(dstFile); + + } else if (MP4_IS_SCENE_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSceneTrack(dstFile); + + } else if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + if (dstHintTrackReferenceTrack == MP4_INVALID_TRACK_ID) { + dstTrackId = MP4_INVALID_TRACK_ID; + } else { + dstTrackId = MP4AddHintTrack(dstFile, + MP4GetHintTrackReferenceTrackId(srcFile, + srcTrackId)); + } + } else if (MP4_IS_SYSTEMS_TRACK_TYPE(trackType)) { + dstTrackId = MP4AddSystemsTrack(dstFile, trackType); + + } else { + dstTrackId = MP4AddTrack(dstFile, trackType); + } + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + MP4SetTrackTimeScale(dstFile, + dstTrackId, + MP4GetTrackTimeScale(srcFile, srcTrackId)); + + if (MP4_IS_AUDIO_TRACK_TYPE(trackType) + || MP4_IS_VIDEO_TRACK_TYPE(trackType)) { + // copy track ES configuration + uint8_t* pConfig = NULL; + uint32_t configSize = 0; + if (MP4GetTrackESConfiguration(srcFile, srcTrackId, + &pConfig, &configSize)) { + + if (pConfig != NULL) { + MP4SetTrackESConfiguration(dstFile, dstTrackId, + pConfig, configSize); + } + } + if (pConfig != NULL) + free(pConfig); + } + + // Bill's change to MP4CloneTrack + if (MP4_IS_HINT_TRACK_TYPE(trackType)) { + // probably not exactly what is wanted + // but caller can adjust later to fit their desires + + char* payloadName = NULL; + char *encodingParms = NULL; + uint8_t payloadNumber; + uint16_t maxPayloadSize; + + if (MP4GetHintTrackRtpPayload( + srcFile, + srcTrackId, + &payloadName, + &payloadNumber, + &maxPayloadSize, + &encodingParms)) { + + (void)MP4SetHintTrackRtpPayload( + dstFile, + dstTrackId, + payloadName, + &payloadNumber, + maxPayloadSize, + encodingParms); + } +#if 0 + MP4SetHintTrackSdp( + dstFile, + dstTrackId, + MP4GetHintTrackSdp(srcFile, srcTrackId)); +#endif + } + + return dstTrackId; + } + + MP4TrackId MP4CopyTrack(MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4FileHandle dstFile, + bool applyEdits, + MP4TrackId dstHintTrackReferenceTrack) + { + bool copySamples = true; // LATER allow false => reference samples + + MP4TrackId dstTrackId = + MP4CloneTrack(srcFile, srcTrackId, dstFile, dstHintTrackReferenceTrack); + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + bool viaEdits = + applyEdits && MP4GetTrackNumberOfEdits(srcFile, srcTrackId); + + MP4SampleId sampleId = 0; + MP4SampleId numSamples = + MP4GetTrackNumberOfSamples(srcFile, srcTrackId); + + MP4Timestamp when = 0; + MP4Duration editsDuration = + MP4GetTrackEditTotalDuration(srcFile, srcTrackId); + + while (true) { + MP4Duration sampleDuration = MP4_INVALID_DURATION; + + if (viaEdits) { + sampleId = MP4GetSampleIdFromEditTime( + srcFile, + srcTrackId, + when, + NULL, + &sampleDuration); + + // in theory, this shouldn't happen + if (sampleId == MP4_INVALID_SAMPLE_ID) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + + when += sampleDuration; + + if (when >= editsDuration) { + break; + } + } else { + sampleId++; + if (sampleId > numSamples) { + break; + } + } + + bool rc = false; + + if (copySamples) { + rc = MP4CopySample( + srcFile, + srcTrackId, + sampleId, + dstFile, + dstTrackId, + sampleDuration); + + } else { + rc = MP4ReferenceSample( + srcFile, + srcTrackId, + sampleId, + dstFile, + dstTrackId, + sampleDuration); + } + + if (!rc) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + } + + return dstTrackId; + } + +// Given a source track in a source file, make an encrypted copy of +// the track in the destination file, including sample encryption + MP4TrackId MP4EncAndCopyTrack(MP4FileHandle srcFile, + MP4TrackId srcTrackId, + mp4v2_ismacrypParams *icPp, + encryptFunc_t encfcnp, + uint32_t encfcnparam1, + MP4FileHandle dstFile, + bool applyEdits, + MP4TrackId dstHintTrackReferenceTrack + ) + { + bool copySamples = true; // LATER allow false => reference samples + + MP4TrackId dstTrackId = + MP4EncAndCloneTrack(srcFile, srcTrackId, + icPp, + dstFile, dstHintTrackReferenceTrack); + + if (dstTrackId == MP4_INVALID_TRACK_ID) { + return dstTrackId; + } + + bool viaEdits = + applyEdits && MP4GetTrackNumberOfEdits(srcFile, srcTrackId); + + MP4SampleId sampleId = 0; + MP4SampleId numSamples = + MP4GetTrackNumberOfSamples(srcFile, srcTrackId); + + MP4Timestamp when = 0; + MP4Duration editsDuration = + MP4GetTrackEditTotalDuration(srcFile, srcTrackId); + + while (true) { + MP4Duration sampleDuration = MP4_INVALID_DURATION; + + if (viaEdits) { + sampleId = MP4GetSampleIdFromEditTime(srcFile, + srcTrackId, + when, + NULL, + &sampleDuration); + + // in theory, this shouldn't happen + if (sampleId == MP4_INVALID_SAMPLE_ID) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + + when += sampleDuration; + + if (when >= editsDuration) { + break; + } + } else { + sampleId++; + if (sampleId > numSamples) { + break; + } + } + + bool rc = false; + + if (copySamples) { + // encrypt and copy + rc = MP4EncAndCopySample(srcFile, + srcTrackId, + sampleId, + encfcnp, + encfcnparam1, + dstFile, + dstTrackId, + sampleDuration); + + } else { + // not sure what these are - encrypt? + rc = MP4ReferenceSample(srcFile, + srcTrackId, + sampleId, + dstFile, + dstTrackId, + sampleDuration); + } + + if (!rc) { + MP4DeleteTrack(dstFile, dstTrackId); + return MP4_INVALID_TRACK_ID; + } + } + + return dstTrackId; + } + + bool MP4DeleteTrack( + MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->DeleteTrack(trackId); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint32_t MP4GetNumberOfTracks( + MP4FileHandle hFile, + const char* type, + uint8_t subType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetNumberOfTracks(type, subType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + MP4TrackId MP4FindTrackId( + MP4FileHandle hFile, + uint16_t index, + const char* type, + uint8_t subType) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->FindTrackId(index, type, subType); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + uint16_t MP4FindTrackIndex( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->FindTrackIndex(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return (uint16_t)-1; + } + + /* specific track properties */ + + const char* MP4GetTrackType( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackType(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + const char* MP4GetTrackMediaDataName( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackMediaDataName(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + + bool MP4GetTrackMediaDataOriginalFormat( + MP4FileHandle hFile, MP4TrackId trackId, char *originalFormat, + uint32_t buflen) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + return ((MP4File*)hFile)->GetTrackMediaDataOriginalFormat(trackId, + originalFormat, buflen); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + MP4Duration MP4GetTrackDuration( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackDuration(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + uint32_t MP4GetTrackTimeScale( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackTimeScale(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4SetTrackTimeScale( + MP4FileHandle hFile, MP4TrackId trackId, uint32_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackTimeScale(trackId, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint8_t MP4GetTrackAudioMpeg4Type( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackAudioMpeg4Type(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + + + +// Replacement to MP4GetTrackVideoType and MP4GetTrackAudioType +// Basically does the same thing but with a more self-explanatory name + uint8_t MP4GetTrackEsdsObjectTypeId( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + + return ((MP4File*)hFile)->GetTrackEsdsObjectTypeId(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_AUDIO_TYPE; + } + + MP4Duration MP4GetTrackFixedSampleDuration( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackFixedSampleDuration(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + uint32_t MP4GetTrackBitRate( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + MP4File *pFile = (MP4File *)hFile; + try { + return pFile->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate"); + } + catch( Exception* x ) { + //mp4v2::impl::log.errorf(*x); we don't really need to print this. + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + // if we're here, we can't get the bitrate from above - + // lets calculate it + try { + MP4Duration trackDur; + trackDur = MP4GetTrackDuration(hFile, trackId); + uint64_t msDuration = + pFile->ConvertFromTrackDuration(trackId, trackDur, + MP4_MSECS_TIME_SCALE); + if (msDuration == 0) return 0; + + MP4Track *pTrack = pFile->GetTrack(trackId); + uint64_t bytes = pTrack->GetTotalOfSampleSizes(); + bytes *= UINT64_C(8000); // 8 * 1000 + bytes /= msDuration; + return (uint32_t)bytes; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4GetTrackESConfiguration( + MP4FileHandle hFile, MP4TrackId trackId, + uint8_t** ppConfig, uint32_t* pConfigSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackESConfiguration( + trackId, ppConfig, pConfigSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + *ppConfig = NULL; + *pConfigSize = 0; + return false; + } + bool MP4GetTrackVideoMetadata( + MP4FileHandle hFile, MP4TrackId trackId, + uint8_t** ppConfig, uint32_t* pConfigSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackVideoMetadata( + trackId, ppConfig, pConfigSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + *ppConfig = NULL; + *pConfigSize = 0; + return false; + } + + bool MP4SetTrackESConfiguration( + MP4FileHandle hFile, MP4TrackId trackId, + const uint8_t* pConfig, uint32_t configSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackESConfiguration( + trackId, pConfig, configSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetTrackH264ProfileLevel (MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t *pProfile, + uint8_t *pLevel) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *pProfile = + ((MP4File *)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].avcC.AVCProfileIndication"); + *pLevel = + ((MP4File *)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].avcC.AVCLevelIndication"); + + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetTrackH264SeqPictHeaders (MP4FileHandle hFile, + MP4TrackId trackId, + uint8_t ***pSeqHeader, + uint32_t **pSeqHeaderSize, + uint8_t ***pPictHeader, + uint32_t **pPictHeaderSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackH264SeqPictHeaders(trackId, + pSeqHeader, + pSeqHeaderSize, + pPictHeader, + pPictHeaderSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + bool MP4GetTrackH264LengthSize (MP4FileHandle hFile, + MP4TrackId trackId, + uint32_t *pLength) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *pLength = 1 + + ((MP4File*) hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].avcC.lengthSizeMinusOne"); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + MP4SampleId MP4GetTrackNumberOfSamples( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackNumberOfSamples(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + uint16_t MP4GetTrackVideoWidth( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.width"); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + uint16_t MP4GetTrackVideoHeight( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.height"); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + double MP4GetTrackVideoFrameRate( + MP4FileHandle hFile, MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackVideoFrameRate(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0.0; + } + + int MP4GetTrackAudioChannels (MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackAudioChannels(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return -1; + } + +// returns true if the track is a media track encrypted according to ismacryp + bool MP4IsIsmaCrypMediaTrack( + MP4FileHandle hFile, MP4TrackId trackId) + { + bool retval = false; + MP4LogLevel verb = mp4v2::impl::log.verbosity; + mp4v2::impl::log.setVerbosity(MP4_LOG_NONE); + + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + retval = ((MP4File*)hFile)->IsIsmaCrypMediaTrack(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + mp4v2::impl::log.setVerbosity(verb); + return retval; + } + + + /* generic track properties */ + + bool MP4HaveTrackAtom (MP4FileHandle hFile, + MP4TrackId trackId, + const char *atomName) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->FindTrackAtom(trackId, atomName) != NULL; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetTrackIntegerProperty ( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, + uint64_t *retvalue) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetTrackIntegerProperty(trackId, + propName); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetTrackFloatProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, + float *retvalue) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetTrackFloatProperty(trackId, propName); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetTrackStringProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, + const char **retvalue) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + *retvalue = ((MP4File*)hFile)->GetTrackStringProperty(trackId, propName); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4GetTrackBytesProperty( + MP4FileHandle hFile, MP4TrackId trackId, const char* propName, + uint8_t** ppValue, uint32_t* pValueSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetTrackBytesProperty( + trackId, propName, ppValue, pValueSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + *ppValue = NULL; + *pValueSize = 0; + return false; + } + + bool MP4SetTrackIntegerProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, int64_t value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackIntegerProperty(trackId, + propName, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetTrackFloatProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, float value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackFloatProperty(trackId, propName, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetTrackStringProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, const char* value) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackStringProperty(trackId, propName, value); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetTrackBytesProperty( + MP4FileHandle hFile, MP4TrackId trackId, + const char* propName, const uint8_t* pValue, uint32_t valueSize) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackBytesProperty( + trackId, propName, pValue, valueSize); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + /* sample operations */ + + bool MP4ReadSample( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId, + /* output parameters */ + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ReadSample( + trackId, + sampleId, + ppBytes, + pNumBytes, + pStartTime, + pDuration, + pRenderingOffset, + pIsSyncSample); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + *pNumBytes = 0; + return false; + } + + bool MP4ReadSampleFromTime( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + /* output parameters */ + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4SampleId sampleId = + ((MP4File*)hFile)->GetSampleIdFromTime( + trackId, when, false); + + ((MP4File*)hFile)->ReadSample( + trackId, + sampleId, + ppBytes, + pNumBytes, + pStartTime, + pDuration, + pRenderingOffset, + pIsSyncSample); + + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + *pNumBytes = 0; + return false; + } + + bool MP4WriteSample( + MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample ) + { + if( MP4_IS_VALID_FILE_HANDLE( hFile )) { + try { + ((MP4File*)hFile)->WriteSample( + trackId, + pBytes, + numBytes, + duration, + renderingOffset, + isSyncSample ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4WriteSampleDependency( + MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample, + uint32_t dependencyFlags ) + { + if( MP4_IS_VALID_FILE_HANDLE( hFile )) { + try { + ((MP4File*)hFile)->WriteSampleDependency( + trackId, + pBytes, + numBytes, + duration, + renderingOffset, + isSyncSample, + dependencyFlags ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4CopySample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration ) + { + if( !MP4_IS_VALID_FILE_HANDLE( srcFile )) + return false; + + try { + MP4File::CopySample( + (MP4File*)srcFile, + srcTrackId, + srcSampleId, + (MP4File*)dstFile, + dstTrackId, + dstSampleDuration ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + + return false; + } + + bool MP4EncAndCopySample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + encryptFunc_t encfcnp, + uint32_t encfcnparam1, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration) + { + if( !MP4_IS_VALID_FILE_HANDLE( srcFile )) + return false; + + try { + MP4File::EncAndCopySample( + (MP4File*)srcFile, + srcTrackId, + srcSampleId, + encfcnp, + encfcnparam1, + (MP4File*)dstFile, + dstTrackId, + dstSampleDuration ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + + return false; + } + + bool MP4ReferenceSample( + MP4FileHandle srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4FileHandle dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration) + { + // LATER Not yet implemented + return false; + } + + uint32_t MP4GetSampleSize( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleSize( + trackId, sampleId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + uint32_t MP4GetTrackMaxSampleSize( + MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackMaxSampleSize(trackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + MP4SampleId MP4GetSampleIdFromTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + bool wantSyncSample) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleIdFromTime( + trackId, when, wantSyncSample); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_SAMPLE_ID; + } + + MP4Timestamp MP4GetSampleTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleTime( + trackId, sampleId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TIMESTAMP; + } + + MP4Duration MP4GetSampleDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleDuration( + trackId, sampleId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + MP4Duration MP4GetSampleRenderingOffset( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleRenderingOffset( + trackId, sampleId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + bool MP4SetSampleRenderingOffset( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId, + MP4Duration renderingOffset) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetSampleRenderingOffset( + trackId, sampleId, renderingOffset); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + int8_t MP4GetSampleSync( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4SampleId sampleId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleSync( + trackId, sampleId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return -1; + } + + + uint64_t MP4ConvertFromMovieDuration( + MP4FileHandle hFile, + MP4Duration duration, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertFromMovieDuration( + duration, timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return (uint64_t)MP4_INVALID_DURATION; + } + + uint64_t MP4ConvertFromTrackTimestamp( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp timeStamp, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertFromTrackTimestamp( + trackId, timeStamp, timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return (uint64_t)MP4_INVALID_TIMESTAMP; + } + + MP4Timestamp MP4ConvertToTrackTimestamp( + MP4FileHandle hFile, + MP4TrackId trackId, + uint64_t timeStamp, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertToTrackTimestamp( + trackId, timeStamp, timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TIMESTAMP; + } + + uint64_t MP4ConvertFromTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Duration duration, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertFromTrackDuration( + trackId, duration, timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return (uint64_t)MP4_INVALID_DURATION; + } + + MP4Duration MP4ConvertToTrackDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + uint64_t duration, + uint32_t timeScale) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->ConvertToTrackDuration( + trackId, duration, timeScale); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + bool MP4GetHintTrackRtpPayload( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + char** ppPayloadName, + uint8_t* pPayloadNumber, + uint16_t* pMaxPayloadSize, + char **ppEncodingParams) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->GetHintTrackRtpPayload( + hintTrackId, ppPayloadName, pPayloadNumber, pMaxPayloadSize, + ppEncodingParams); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4SetHintTrackRtpPayload( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* pPayloadName, + uint8_t* pPayloadNumber, + uint16_t maxPayloadSize, + const char *encode_params, + bool include_rtp_map, + bool include_mpeg4_esid) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetHintTrackRtpPayload( + hintTrackId, pPayloadName, pPayloadNumber, maxPayloadSize, encode_params, + include_rtp_map, include_mpeg4_esid); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + const char* MP4GetSessionSdp( + MP4FileHandle hFile) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSessionSdp(); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + + bool MP4SetSessionSdp( + MP4FileHandle hFile, + const char* sdpString) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetSessionSdp(sdpString); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AppendSessionSdp( + MP4FileHandle hFile, + const char* sdpString) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AppendSessionSdp(sdpString); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + const char* MP4GetHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetHintTrackSdp(hintTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + + bool MP4SetHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* sdpString) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetHintTrackSdp(hintTrackId, sdpString); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AppendHintTrackSdp( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const char* sdpString) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AppendHintTrackSdp(hintTrackId, sdpString); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + MP4TrackId MP4GetHintTrackReferenceTrackId( + MP4FileHandle hFile, + MP4TrackId hintTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetHintTrackReferenceTrackId(hintTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TRACK_ID; + } + + bool MP4ReadRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + uint16_t* pNumPackets) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ReadRtpHint( + hintTrackId, hintSampleId, pNumPackets); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint16_t MP4GetRtpHintNumberOfPackets( + MP4FileHandle hFile, + MP4TrackId hintTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetRtpHintNumberOfPackets(hintTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + int8_t MP4GetRtpPacketBFrame( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + uint16_t packetIndex) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetRtpPacketBFrame(hintTrackId, packetIndex); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return -1; + } + + int32_t MP4GetRtpPacketTransmitOffset( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + uint16_t packetIndex) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)-> + GetRtpPacketTransmitOffset(hintTrackId, packetIndex); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + bool MP4ReadRtpPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + uint16_t packetIndex, + uint8_t** ppBytes, + uint32_t* pNumBytes, + uint32_t ssrc, + bool includeHeader, + bool includePayload) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->ReadRtpPacket( + hintTrackId, packetIndex, + ppBytes, pNumBytes, + ssrc, includeHeader, includePayload); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + MP4Timestamp MP4GetRtpTimestampStart( + MP4FileHandle hFile, + MP4TrackId hintTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetRtpTimestampStart(hintTrackId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TIMESTAMP; + } + + bool MP4SetRtpTimestampStart( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4Timestamp rtpStart) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetRtpTimestampStart( + hintTrackId, rtpStart); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AddRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId) + { + return MP4AddRtpVideoHint(hFile, hintTrackId, false, 0); + } + + bool MP4AddRtpVideoHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + bool isBframe, + uint32_t timestampOffset) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpHint(hintTrackId, + isBframe, timestampOffset); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AddRtpPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + bool setMbit, + int32_t transmitOffset) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpPacket( + hintTrackId, setMbit, transmitOffset); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AddRtpImmediateData( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + const uint8_t* pBytes, + uint32_t numBytes) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpImmediateData(hintTrackId, + pBytes, numBytes); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AddRtpSampleData( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4SampleId sampleId, + uint32_t dataOffset, + uint32_t dataLength) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpSampleData( + hintTrackId, sampleId, dataOffset, dataLength); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4AddRtpESConfigurationPacket( + MP4FileHandle hFile, + MP4TrackId hintTrackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->AddRtpESConfigurationPacket(hintTrackId); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4WriteRtpHint( + MP4FileHandle hFile, + MP4TrackId hintTrackId, + MP4Duration duration, + bool isSyncSample) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->WriteRtpHint( + hintTrackId, duration, isSyncSample); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf( "%s: failed", __FUNCTION__ ); + } + } + return false; + } + /* 3GPP specific operations */ + + bool MP4Make3GPCompliant( + const char* fileName, + char* majorBrand, + uint32_t minorVersion, + char** supportedBrands, + uint32_t supportedBrandsCount, + bool deleteIodsAtom) + { + if (!fileName) + return false; + + MP4File* pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try { + ASSERT(pFile); + pFile->Modify(fileName); + pFile->Make3GPCompliant(fileName, majorBrand, minorVersion, supportedBrands, supportedBrandsCount, deleteIodsAtom); + pFile->Close(); + delete pFile; + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + if (pFile) + delete pFile; + return false; + } + + /* ISMA specific operations */ + + bool MP4MakeIsmaCompliant( + const char* fileName, + bool addIsmaComplianceSdp) + { + if (!fileName) + return false; + + MP4File* pFile = ConstructMP4File(); + if (!pFile) + return MP4_INVALID_FILE_HANDLE; + + try { + ASSERT(pFile); + pFile->Modify(fileName); + pFile->MakeIsmaCompliant(addIsmaComplianceSdp); + pFile->Close(); + delete pFile; + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: \"%s\": failed", __FUNCTION__, + fileName ); + } + + if (pFile) + delete pFile; + return false; + } + + char* MP4MakeIsmaSdpIod( + uint8_t videoProfile, + uint32_t videoBitrate, + uint8_t* videoConfig, + uint32_t videoConfigLength, + uint8_t audioProfile, + uint32_t audioBitrate, + uint8_t* audioConfig, + uint32_t audioConfigLength) + + { + MP4File* pFile = ConstructMP4File(); + if (!pFile) + return NULL; + + try { + uint8_t* pBytes = NULL; + uint64_t numBytes = 0; + + ASSERT(pFile); + pFile->CreateIsmaIodFromParams( + videoProfile, + videoBitrate, + videoConfig, + videoConfigLength, + audioProfile, + audioBitrate, + audioConfig, + audioConfigLength, + &pBytes, + &numBytes); + + char* iodBase64 = + MP4ToBase64(pBytes, numBytes); + MP4Free(pBytes); + + char* sdpIod = + (char*)MP4Malloc(strlen(iodBase64) + 64); + snprintf(sdpIod, strlen(iodBase64) + 64, + "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042", + iodBase64); + MP4Free(iodBase64); + + delete pFile; + + return sdpIod; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + if (pFile) + delete pFile; + return NULL; + } + + /* Edit list */ + + MP4EditId MP4AddTrackEdit( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime, + MP4Duration duration, + bool dwell) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4EditId newEditId = + ((MP4File*)hFile)->AddTrackEdit(trackId, editId); + + if (newEditId != MP4_INVALID_EDIT_ID) { + ((MP4File*)hFile)->SetTrackEditMediaStart( + trackId, newEditId, startTime); + ((MP4File*)hFile)->SetTrackEditDuration( + trackId, newEditId, duration); + ((MP4File*)hFile)->SetTrackEditDwell( + trackId, newEditId, dwell); + } + + return newEditId; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_EDIT_ID; + } + + bool MP4DeleteTrackEdit( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->DeleteTrackEdit(trackId, editId); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return false; + } + + uint32_t MP4GetTrackNumberOfEdits( + MP4FileHandle hFile, + MP4TrackId trackId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackNumberOfEdits(trackId); + } + catch( Exception* x ) { + //mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return 0; + } + + MP4Timestamp MP4GetTrackEditMediaStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditMediaStart( + trackId, editId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_TIMESTAMP; + } + + MP4Duration MP4GetTrackEditTotalDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditTotalDuration( + trackId, editId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + bool MP4SetTrackEditMediaStart( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackEditMediaStart( + trackId, editId, startTime); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return false; + } + + MP4Duration MP4GetTrackEditDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditDuration(trackId, editId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_DURATION; + } + + bool MP4SetTrackEditDuration( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackEditDuration(trackId, editId, duration); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return false; + } + + int8_t MP4GetTrackEditDwell( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetTrackEditDwell(trackId, editId); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return -1; + } + + bool MP4SetTrackEditDwell( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4EditId editId, + bool dwell) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + ((MP4File*)hFile)->SetTrackEditDwell(trackId, editId, dwell); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return false; + } + + bool MP4ReadSampleFromEditTime( + /* input parameters */ + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + /* output parameters */ + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample) + { + MP4SampleId sampleId = + MP4GetSampleIdFromEditTime( + hFile, + trackId, + when, + pStartTime, + pDuration); + + return MP4ReadSample( + hFile, + trackId, + sampleId, + ppBytes, + pNumBytes, + NULL, + NULL, + pRenderingOffset, + pIsSyncSample); + } + + MP4SampleId MP4GetSampleIdFromEditTime( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + return ((MP4File*)hFile)->GetSampleIdFromEditTime( + trackId, when, pStartTime, pDuration); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return MP4_INVALID_SAMPLE_ID; + } + + /* Utlities */ + + char* MP4BinaryToBase16( + const uint8_t* pData, + uint32_t dataSize) + { + if (pData || dataSize == 0) { + try { + return MP4ToBase16(pData, dataSize); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + + char* MP4BinaryToBase64( + const uint8_t* pData, + uint32_t dataSize) + { + if (pData || dataSize == 0) { + try { + return MP4ToBase64(pData, dataSize); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + } + return NULL; + } + + void MP4Free (void *p) + { + if (p != NULL) + free(p); + } + + bool MP4AddIPodUUID (MP4FileHandle hFile, MP4TrackId trackId) + { + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + MP4Track* track = NULL; + MP4Atom* avc1 = NULL; + + try + { + track = ((MP4File*)hFile)->GetTrack(trackId); + ASSERT(track); + avc1 = track->GetTrakAtom().FindChildAtom("mdia.minf.stbl.stsd.avc1"); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + return false; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + return false; + } + + IPodUUIDAtom *ipod_uuid = NULL; + try + { + ipod_uuid = new IPodUUIDAtom(*(MP4File*)hFile); + } + catch( std::bad_alloc ) { + mp4v2::impl::log.errorf("%s: unable to allocate IPodUUIDAtom", __FUNCTION__); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + return false; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: unknown exception constructing IPodUUIDAtom", __FUNCTION__ ); + return false; + } + + try + { + ASSERT(avc1); + ASSERT(ipod_uuid); + avc1->AddChildAtom(ipod_uuid); + return true; + } + catch( Exception* x ) { + delete ipod_uuid; + ipod_uuid = NULL; + mp4v2::impl::log.errorf(*x); + delete x; + return false; + } + catch( ... ) { + delete ipod_uuid; + ipod_uuid = NULL; + mp4v2::impl::log.errorf("%s: unknown exception adding IPodUUIDAtom", __FUNCTION__ ); + return false; + } + + return false; + } + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4GetTrackLanguage( + MP4FileHandle hFile, + MP4TrackId trackId, + char* code ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return ((MP4File*)hFile)->GetTrackLanguage( trackId, code ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4SetTrackLanguage( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* code ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return ((MP4File*)hFile)->SetTrackLanguage( trackId, code ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4GetTrackName( + MP4FileHandle hFile, + MP4TrackId trackId, + char** name ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return ((MP4File*)hFile)->GetTrackName( trackId, name ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4SetTrackName( + MP4FileHandle hFile, + MP4TrackId trackId, + const char* code ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + return ((MP4File*)hFile)->SetTrackName( trackId, code ); + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4GetTrackDurationPerChunk( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Duration* duration ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + if (!duration) + return false; + + try { + *duration = ((MP4File*)hFile)->GetTrackDurationPerChunk( trackId ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4SetTrackDurationPerChunk( + MP4FileHandle hFile, + MP4TrackId trackId, + MP4Duration duration ) +{ + if( !MP4_IS_VALID_FILE_HANDLE( hFile )) + return false; + + try { + ((MP4File*)hFile)->SetTrackDurationPerChunk( trackId, duration ); + return true; + } + catch( Exception* x ) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch( ... ) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__ ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +} // extern "C" diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4array.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4array.h new file mode 100644 index 00000000..c49d59ba --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4array.h @@ -0,0 +1,145 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_MP4ARRAY_H +#define MP4V2_IMPL_MP4ARRAY_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +typedef uint32_t MP4ArrayIndex; + +class MP4Array { +public: + MP4Array() { + m_numElements = 0; + m_maxNumElements = 0; + } + + inline bool ValidIndex(MP4ArrayIndex index) { + return (index < m_numElements); + } + + inline MP4ArrayIndex Size(void) { + return m_numElements; + } + + inline MP4ArrayIndex MaxSize(void) { + return m_maxNumElements; + } + +protected: + MP4ArrayIndex m_numElements; + MP4ArrayIndex m_maxNumElements; +}; + +// macro to generate subclasses +// we use this as an alternative to templates +// due to the excessive compile time price of extensive template usage + +#define MP4ARRAY_DECL(name, type) \ + class name##Array : public MP4Array { \ + public: \ + name##Array() { \ + m_elements = NULL; \ + } \ + \ + ~name##Array() { \ + MP4Free(m_elements); \ + } \ + \ + inline void Add(type newElement) { \ + Insert(newElement, m_numElements); \ + } \ + \ + void Insert(type newElement, MP4ArrayIndex newIndex) { \ + if (newIndex > m_numElements) { \ + throw new PlatformException("illegal array index", ERANGE, __FILE__, __LINE__, __FUNCTION__); \ + } \ + if (m_numElements == m_maxNumElements) { \ + m_maxNumElements = max(m_maxNumElements, (MP4ArrayIndex)1) * 2; \ + m_elements = (type*)MP4Realloc(m_elements, \ + m_maxNumElements * sizeof(type)); \ + } \ + memmove(&m_elements[newIndex + 1], &m_elements[newIndex], \ + (m_numElements - newIndex) * sizeof(type)); \ + m_elements[newIndex] = newElement; \ + m_numElements++; \ + } \ + \ + void Delete(MP4ArrayIndex index) { \ + if (!ValidIndex(index)) { \ + ostringstream msg; \ + msg << "illegal array index: " << index << " of " << m_numElements; \ + throw new PlatformException(msg.str().c_str(), ERANGE, __FILE__, __LINE__, __FUNCTION__); \ + } \ + m_numElements--; \ + if (index < m_numElements) { \ + memmove(&m_elements[index], &m_elements[index + 1], \ + (m_numElements - index) * sizeof(type)); \ + } \ + } \ + void Resize(MP4ArrayIndex newSize) { \ + m_numElements = newSize; \ + m_maxNumElements = newSize; \ + m_elements = (type*)MP4Realloc(m_elements, \ + m_maxNumElements * sizeof(type)); \ + } \ + \ + type& operator[](MP4ArrayIndex index) { \ + if (ValidIndex(index)) { \ + return m_elements[index]; \ + } \ + else { \ + ostringstream msg; \ + msg << "illegal array index: " << index << " of " << m_numElements; \ + throw new PlatformException(msg.str().c_str(), ERANGE, __FILE__, __LINE__, __FUNCTION__ ); \ + } \ + } \ + \ + protected: \ + type* m_elements; \ + }; + +MP4ARRAY_DECL(MP4Integer8, uint8_t) + +MP4ARRAY_DECL(MP4Integer16, uint16_t) + +MP4ARRAY_DECL(MP4Integer32, uint32_t) + +MP4ARRAY_DECL(MP4Integer64, uint64_t) + +MP4ARRAY_DECL(MP4Float32, float) + +MP4ARRAY_DECL(MP4Float64, double) + +MP4ARRAY_DECL(MP4String, char*) + +MP4ARRAY_DECL(MP4Bytes, uint8_t*) + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4ARRAY_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4atom.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4atom.cpp new file mode 100644 index 00000000..520cbc87 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4atom.cpp @@ -0,0 +1,1017 @@ +/* + * 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 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Portions created by Adnecto d.o.o. are + * Copyright (C) Adnecto d.o.o. 2005. All Rights Reserved + * + * Contributor(s): + * Dave Mackie [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + * Danijel Kopcinovic [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4AtomInfo::MP4AtomInfo(const char* name, bool mandatory, bool onlyOne) +{ + m_name = name; + m_mandatory = mandatory; + m_onlyOne = onlyOne; + m_count = 0; +} + +MP4Atom::MP4Atom(MP4File& file, const char* type) + : m_File(file) +{ + SetType(type); + m_unknownType = false; + m_start = 0; + m_end = 0; + m_largesizeMode = false; + m_size = 0; + m_pParentAtom = NULL; + m_depth = 0xFF; +} + +MP4Atom::~MP4Atom() +{ + uint32_t i; + + for (i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } + for (i = 0; i < m_pChildAtomInfos.Size(); i++) { + delete m_pChildAtomInfos[i]; + } + for (i = 0; i < m_pChildAtoms.Size(); i++) { + delete m_pChildAtoms[i]; + } +} + +MP4Atom* MP4Atom::CreateAtom( MP4File &file, MP4Atom* parent, const char* type ) +{ + MP4Atom* atom = factory( file, parent, type ); + ASSERT( atom ); + return atom; +} + +// generate a skeletal self + +void MP4Atom::Generate() +{ + uint32_t i; + + // for all properties + for (i = 0; i < m_pProperties.Size(); i++) { + // ask it to self generate + m_pProperties[i]->Generate(); + } + + // for all mandatory, single child atom types + for (i = 0; i < m_pChildAtomInfos.Size(); i++) { + if (m_pChildAtomInfos[i]->m_mandatory + && m_pChildAtomInfos[i]->m_onlyOne) { + + // create the mandatory, single child atom + MP4Atom* pChildAtom = + CreateAtom(m_File, this, m_pChildAtomInfos[i]->m_name); + + AddChildAtom(pChildAtom); + + // and ask it to self generate + pChildAtom->Generate(); + } + } +} + +MP4Atom* MP4Atom::ReadAtom(MP4File& file, MP4Atom* pParentAtom) +{ + uint8_t hdrSize = 8; + uint8_t extendedType[16]; + + uint64_t pos = file.GetPosition(); + + log.verbose1f("\"%s\": pos = 0x%" PRIx64, file.GetFilename().c_str(), pos); + + uint64_t dataSize = file.ReadUInt32(); + + char type[5]; + file.ReadBytes((uint8_t*)&type[0], 4); + type[4] = '\0'; + + // extended size + const bool largesizeMode = (dataSize == 1); + if (dataSize == 1) { + dataSize = file.ReadUInt64(); + hdrSize += 8; + file.Check64BitStatus(type); + } + + // extended type + if (ATOMID(type) == ATOMID("uuid")) { + file.ReadBytes(extendedType, sizeof(extendedType)); + hdrSize += sizeof(extendedType); + } + + if (dataSize == 0) { + // extends to EOF + dataSize = file.GetSize() - pos; + } + + dataSize -= hdrSize; + + log.verbose1f("\"%s\": type = \"%s\" data-size = %" PRIu64 " (0x%" PRIx64 ") hdr %u", + file.GetFilename().c_str(), type, dataSize, dataSize, hdrSize); + + if (pos + hdrSize + dataSize > pParentAtom->GetEnd()) { + log.errorf("%s: \"%s\": invalid atom size, extends outside parent atom - skipping to end of \"%s\" \"%s\" %" PRIu64 " vs %" PRIu64, + __FUNCTION__, file.GetFilename().c_str(), pParentAtom->GetType(), type, + pos + hdrSize + dataSize, + pParentAtom->GetEnd()); + log.verbose1f("\"%s\": parent %s (%" PRIu64 ") pos %" PRIu64 " hdr %d data %" PRIu64 " sum %" PRIu64, + file.GetFilename().c_str(), pParentAtom->GetType(), + pParentAtom->GetEnd(), + pos, + hdrSize, + dataSize, + pos + hdrSize + dataSize); + + // skip to end of atom + dataSize = pParentAtom->GetEnd() - pos - hdrSize; + } + + MP4Atom* pAtom = CreateAtom(file, pParentAtom, type); + // pAtom->SetFile(pFile); + pAtom->SetStart(pos); + pAtom->SetEnd(pos + hdrSize + dataSize); + pAtom->SetLargesizeMode(largesizeMode); + pAtom->SetSize(dataSize); + if (ATOMID(type) == ATOMID("uuid")) { + pAtom->SetExtendedType(extendedType); + } + if (pAtom->IsUnknownType()) { + if (!IsReasonableType(pAtom->GetType())) { + log.warningf("%s: \"%s\": atom type %s is suspect", __FUNCTION__, file.GetFilename().c_str(), + pAtom->GetType()); + } else { + log.verbose1f("\"%s\": Info: atom type %s is unknown", file.GetFilename().c_str(), + pAtom->GetType()); + } + + if (dataSize > 0) { + pAtom->AddProperty( + new MP4BytesProperty(*pAtom, "data", dataSize)); + } + } + + pAtom->SetParentAtom(pParentAtom); + + try { + pAtom->Read(); + } + catch (Exception* x) { + // delete atom and rethrow so we don't leak memory. + delete pAtom; + throw x; + } + + + return pAtom; +} + +bool MP4Atom::IsReasonableType(const char* type) +{ + // Unwound this. Pricy when called a lot. + if( isalnum((unsigned char) type[0])) { + if( isalnum((unsigned char) type[1])) { + if( isalnum((unsigned char) type[2])) { + if( isalnum((unsigned char) type[3]) || type[3] == ' ' ) { + return true; + } + } + } + } + + return false; +} + +// generic read +void MP4Atom::Read() +{ + if (ATOMID(m_type) != 0 && m_size > 1000000) { + log.verbose1f("%s: \"%s\": %s atom size %" PRIu64 " is suspect", __FUNCTION__, + m_File.GetFilename().c_str(), m_type, m_size); + } + + ReadProperties(); + + // read child atoms, if we expect there to be some + if (m_pChildAtomInfos.Size() > 0) { + ReadChildAtoms(); + } + + Skip(); // to end of atom +} + +void MP4Atom::Skip() +{ + if (m_File.GetPosition() != m_end) { + log.verbose1f("\"%s\": Skip: %" PRIu64 " bytes", + m_File.GetFilename().c_str(), m_end - m_File.GetPosition()); + } + m_File.SetPosition(m_end); +} + +MP4Atom* MP4Atom::FindAtom(const char* name) +{ + if (!IsMe(name)) { + return NULL; + } + + if (!IsRootAtom()) { + log.verbose1f("\"%s\": FindAtom: matched %s", + GetFile().GetFilename().c_str(), name); + + name = MP4NameAfterFirst(name); + + // I'm the sought after atom + if (name == NULL) { + return this; + } + } + + // else it's one of my children + return FindChildAtom(name); +} + +bool MP4Atom::FindProperty(const char *name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!IsMe(name)) { + return false; + } + + if (!IsRootAtom()) { + log.verbose1f("\"%s\": FindProperty: matched %s", + GetFile().GetFilename().c_str(), name); + + name = MP4NameAfterFirst(name); + + // no property name given + if (name == NULL) { + return false; + } + } + + return FindContainedProperty(name, ppProperty, pIndex); +} + +bool MP4Atom::IsMe(const char* name) +{ + if (name == NULL) { + return false; + } + + // root atom always matches + if (!strcmp(m_type, "")) { + return true; + } + + // check if our atom name is specified as the first component + if (!MP4NameFirstMatches(m_type, name)) { + return false; + } + + return true; +} + +MP4Atom* MP4Atom::FindChildAtom(const char* name) +{ + uint32_t atomIndex = 0; + + // get the index if we have one, e.g. moov.trak[2].mdia... + (void)MP4NameFirstIndex(name, &atomIndex); + + // need to get to the index'th child atom of the right type + for (uint32_t i = 0; i < m_pChildAtoms.Size(); i++) { + if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { + if (atomIndex == 0) { + // this is the one, ask it to match + return m_pChildAtoms[i]->FindAtom(name); + } + atomIndex--; + } + } + + return NULL; +} + +bool MP4Atom::FindContainedProperty(const char *name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + uint32_t numProperties = m_pProperties.Size(); + uint32_t i; + // check all of our properties + for (i = 0; i < numProperties; i++) { + if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) { + return true; + } + } + + // not one of our properties, + // presumably one of our children's properties + // check child atoms... + + // check if we have an index, e.g. trak[2].mdia... + uint32_t atomIndex = 0; + (void)MP4NameFirstIndex(name, &atomIndex); + + // need to get to the index'th child atom of the right type + for (i = 0; i < m_pChildAtoms.Size(); i++) { + if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { + if (atomIndex == 0) { + // this is the one, ask it to match + return m_pChildAtoms[i]->FindProperty(name, ppProperty, pIndex); + } + atomIndex--; + } + } + + log.verbose1f("\"%s\": FindProperty: no match for %s", + GetFile().GetFilename().c_str(), name); + return false; +} + +void MP4Atom::ReadProperties(uint32_t startIndex, uint32_t count) +{ + uint32_t numProperties = min(count, m_pProperties.Size() - startIndex); + + // read any properties of the atom + for (uint32_t i = startIndex; i < startIndex + numProperties; i++) { + + m_pProperties[i]->Read(m_File); + + if (m_File.GetPosition() > m_end) { + log.verbose1f("ReadProperties: insufficient data for property: %s pos 0x%" PRIx64 " atom end 0x%" PRIx64, + m_pProperties[i]->GetName(), + m_File.GetPosition(), m_end); + + ostringstream oss; + oss << "atom '" << GetType() << "' is too small; overrun at property: " << m_pProperties[i]->GetName(); + throw new Exception( oss.str().c_str(), __FILE__, __LINE__, __FUNCTION__ ); + } + + MP4LogLevel thisVerbosity = + (m_pProperties[i]->GetType() == TableProperty) ? + MP4_LOG_VERBOSE2 : MP4_LOG_VERBOSE1; + + if (log.verbosity >= thisVerbosity) { + // log.printf(thisVerbosity,"Read: "); + m_pProperties[i]->Dump(0, true); + } + } +} + +void MP4Atom::ReadChildAtoms() +{ + bool this_is_udta = ATOMID(m_type) == ATOMID("udta"); + + log.verbose1f("\"%s\": of %s", m_File.GetFilename().c_str(), m_type[0] ? m_type : "root"); + for (uint64_t position = m_File.GetPosition(); + position < m_end; + position = m_File.GetPosition()) { + // make sure that we have enough to read at least 8 bytes + // size and type. + if (m_end - position < 2 * sizeof(uint32_t)) { + // if we're reading udta, it's okay to have 4 bytes of 0 + if (this_is_udta && + m_end - position == sizeof(uint32_t)) { + uint32_t mbz = m_File.ReadUInt32(); + if (mbz != 0) { + log.warningf("%s: \"%s\": In udta atom, end value is not zero %x", __FUNCTION__, + m_File.GetFilename().c_str(), mbz); + } + continue; + } + // otherwise, output a warning, but don't care + log.warningf("%s: \"%s\": In %s atom, extra %" PRId64 " bytes at end of atom", __FUNCTION__, + m_File.GetFilename().c_str(), m_type, (m_end - position)); + for (uint64_t ix = 0; ix < m_end - position; ix++) { + (void)m_File.ReadUInt8(); + } + continue; + } + MP4Atom* pChildAtom = MP4Atom::ReadAtom(m_File, this); + + AddChildAtom(pChildAtom); + + MP4AtomInfo* pChildAtomInfo = FindAtomInfo(pChildAtom->GetType()); + + // if child atom is of known type + // but not expected here print warning + if (pChildAtomInfo == NULL && !pChildAtom->IsUnknownType()) { + log.verbose1f("%s: \"%s\": In atom %s unexpected child atom %s", __FUNCTION__, + m_File.GetFilename().c_str(), GetType(), pChildAtom->GetType()); + } + + // if child atoms should have just one instance + // and this is more than one, print warning + if (pChildAtomInfo) { + pChildAtomInfo->m_count++; + + if (pChildAtomInfo->m_onlyOne && pChildAtomInfo->m_count > 1) { + log.warningf("%s: \"%s\": In atom %s multiple child atoms %s", __FUNCTION__, + m_File.GetFilename().c_str(), GetType(), pChildAtom->GetType()); + } + } + + } + + // if mandatory child atom doesn't exist, print warning + uint32_t numAtomInfo = m_pChildAtomInfos.Size(); + for (uint32_t i = 0; i < numAtomInfo; i++) { + if (m_pChildAtomInfos[i]->m_mandatory + && m_pChildAtomInfos[i]->m_count == 0) { + log.warningf("%s: \"%s\": In atom %s missing child atom %s", __FUNCTION__, + m_File.GetFilename().c_str(), GetType(), m_pChildAtomInfos[i]->m_name); + } + } + + log.verbose1f("\"%s\": finished %s", m_File.GetFilename().c_str(), m_type); +} + +MP4AtomInfo* MP4Atom::FindAtomInfo(const char* name) +{ + uint32_t numAtomInfo = m_pChildAtomInfos.Size(); + for (uint32_t i = 0; i < numAtomInfo; i++) { + if (ATOMID(m_pChildAtomInfos[i]->m_name) == ATOMID(name)) { + return m_pChildAtomInfos[i]; + } + } + return NULL; +} + +// generic write +void MP4Atom::Write() +{ + BeginWrite(); + + WriteProperties(); + + WriteChildAtoms(); + + FinishWrite(); +} + +void MP4Atom::Rewrite() +{ + if (!m_end) { + // This atom hasn't been written yet... + return; + } + + uint64_t fPos = m_File.GetPosition(); + m_File.SetPosition(GetStart()); + Write(); + m_File.SetPosition(fPos); +} + +void MP4Atom::BeginWrite(bool use64) +{ + m_start = m_File.GetPosition(); + //use64 = m_File.Use64Bits(); + if (use64) { + m_File.WriteUInt32(1); + } else { + m_File.WriteUInt32(0); + } + m_File.WriteBytes((uint8_t*)&m_type[0], 4); + if (use64) { + m_File.WriteUInt64(0); + } + if (ATOMID(m_type) == ATOMID("uuid")) { + m_File.WriteBytes(m_extendedType, sizeof(m_extendedType)); + } +} + +void MP4Atom::FinishWrite(bool use64) +{ + m_end = m_File.GetPosition(); + m_size = (m_end - m_start); + + log.verbose1f("end: type %s %" PRIu64 " %" PRIu64 " size %" PRIu64, + m_type,m_start, m_end, m_size); + //use64 = m_File.Use64Bits(); + if (use64) { + m_File.SetPosition(m_start + 8); + m_File.WriteUInt64(m_size); + } else { + ASSERT(m_size <= (uint64_t)0xFFFFFFFF); + m_File.SetPosition(m_start); + m_File.WriteUInt32(m_size); + } + m_File.SetPosition(m_end); + + // adjust size to just reflect data portion of atom + m_size -= (use64 ? 16 : 8); + if (ATOMID(m_type) == ATOMID("uuid")) { + m_size -= sizeof(m_extendedType); + } +} + +void MP4Atom::WriteProperties(uint32_t startIndex, uint32_t count) +{ + uint32_t numProperties = min(count, m_pProperties.Size() - startIndex); + + log.verbose1f("Write: \"%s\": type %s", m_File.GetFilename().c_str(), m_type); + + for (uint32_t i = startIndex; i < startIndex + numProperties; i++) { + m_pProperties[i]->Write(m_File); + + MP4LogLevel thisVerbosity = + (m_pProperties[i]->GetType() == TableProperty) ? + MP4_LOG_VERBOSE2 : MP4_LOG_VERBOSE1; + + if (log.verbosity >= thisVerbosity) { + log.printf(thisVerbosity,"Write: "); + m_pProperties[i]->Dump(0, false); + } + } +} + +void MP4Atom::WriteChildAtoms() +{ + uint32_t size = m_pChildAtoms.Size(); + for (uint32_t i = 0; i < size; i++) { + m_pChildAtoms[i]->Write(); + } + + log.verbose1f("Write: \"%s\": finished %s", m_File.GetFilename().c_str(), m_type); +} + +void MP4Atom::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + m_pProperties.Add(pProperty); +} + +void MP4Atom::AddVersionAndFlags() +{ + AddProperty(new MP4Integer8Property(*this, "version")); + AddProperty(new MP4Integer24Property(*this, "flags")); +} + +void MP4Atom::AddReserved(MP4Atom& parentAtom, const char* name, uint32_t size) +{ + MP4BytesProperty* pReserved = new MP4BytesProperty(parentAtom, name, size); + pReserved->SetReadOnly(); + AddProperty(pReserved); +} + +void MP4Atom::ExpectChildAtom(const char* name, bool mandatory, bool onlyOne) +{ + m_pChildAtomInfos.Add(new MP4AtomInfo(name, mandatory, onlyOne)); +} + +uint8_t MP4Atom::GetVersion() +{ + if (strcmp("version", m_pProperties[0]->GetName())) { + return 0; + } + return ((MP4Integer8Property*)m_pProperties[0])->GetValue(); +} + +void MP4Atom::SetVersion(uint8_t version) +{ + if (strcmp("version", m_pProperties[0]->GetName())) { + return; + } + ((MP4Integer8Property*)m_pProperties[0])->SetValue(version); +} + +uint32_t MP4Atom::GetFlags() +{ + if (strcmp("flags", m_pProperties[1]->GetName())) { + return 0; + } + return ((MP4Integer24Property*)m_pProperties[1])->GetValue(); +} + +void MP4Atom::SetFlags(uint32_t flags) +{ + if (strcmp("flags", m_pProperties[1]->GetName())) { + return; + } + ((MP4Integer24Property*)m_pProperties[1])->SetValue(flags); +} + +void MP4Atom::Dump(uint8_t indent, bool dumpImplicits) +{ + if ( m_type[0] != '\0' ) { + // create list of ancestors + list<string> tlist; + for( MP4Atom* atom = this; atom; atom = atom->GetParentAtom() ) { + const char* const type = atom->GetType(); + if( type && type[0] != '\0' ) + tlist.push_front( type ); + } + + // create contextual atom-name + string can; + const list<string>::iterator ie = tlist.end(); + for( list<string>::iterator it = tlist.begin(); it != ie; it++ ) + can += *it + '.'; + if( can.length() ) + can.resize( can.length() - 1 ); + + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": type %s (%s)", + GetFile().GetFilename().c_str(), + m_type, can.c_str() ); + } + + uint32_t i; + uint32_t size; + + // dump our properties + size = m_pProperties.Size(); + for (i = 0; i < size; i++) { + + /* skip details of tables unless we're told to be verbose */ + if (m_pProperties[i]->GetType() == TableProperty + && (log.verbosity < MP4_LOG_VERBOSE2)) { + log.dump(indent + 1, MP4_LOG_VERBOSE1, "\"%s\": <table entries suppressed>", + GetFile().GetFilename().c_str() ); + continue; + } + + m_pProperties[i]->Dump(indent + 1, dumpImplicits); + } + + // dump our children + size = m_pChildAtoms.Size(); + for (i = 0; i < size; i++) { + m_pChildAtoms[i]->Dump(indent + 1, dumpImplicits); + } +} + +uint8_t MP4Atom::GetDepth() +{ + if (m_depth < 0xFF) { + return m_depth; + } + + MP4Atom *pAtom = this; + m_depth = 0; + + while ((pAtom = pAtom->GetParentAtom()) != NULL) { + m_depth++; + ASSERT(m_depth < 255); + } + return m_depth; +} + +bool MP4Atom::GetLargesizeMode() +{ + return m_largesizeMode; +} + +void MP4Atom::SetLargesizeMode( bool mode ) +{ + m_largesizeMode = mode; +} + +bool +MP4Atom::descendsFrom( MP4Atom* parent, const char* type ) +{ + const uint32_t id = ATOMID( type ); + for( MP4Atom* atom = parent; atom; atom = atom->GetParentAtom() ) { + if( id == ATOMID(atom->GetType()) ) + return true; + } + return false; +} + +// UDTA child atom types to be constructed as MP4UdtaElementAtom. +// List gleaned from QTFF 2007-09-04. +static const char* const UDTA_ELEMENTS[] = { + "\xA9" "arg", + "\xA9" "ark", + "\xA9" "cok", + "\xA9" "com", + "\xA9" "cpy", + "\xA9" "day", + "\xA9" "dir", + "\xA9" "ed1", + "\xA9" "ed2", + "\xA9" "ed3", + "\xA9" "ed4", + "\xA9" "ed5", + "\xA9" "ed6", + "\xA9" "ed7", + "\xA9" "ed8", + "\xA9" "ed9", + "\xA9" "fmt", + "\xA9" "inf", + "\xA9" "isr", + "\xA9" "lab", + "\xA9" "lal", + "\xA9" "mak", + "\xA9" "nak", + "\xA9" "nam", + "\xA9" "pdk", + "\xA9" "phg", + "\xA9" "prd", + "\xA9" "prf", + "\xA9" "prk", + "\xA9" "prl", + "\xA9" "req", + "\xA9" "snk", + "\xA9" "snm", + "\xA9" "src", + "\xA9" "swf", + "\xA9" "swk", + "\xA9" "swr", + "\xA9" "wrt", + "Allf", + "name", + "LOOP", + "ptv ", + "SelO", + "WLOC", + NULL // must be last +}; + +MP4Atom* +MP4Atom::factory( MP4File &file, MP4Atom* parent, const char* type ) +{ + // type may be NULL only in case of root-atom + if( !type ) + return new MP4RootAtom(file); + + // construct atoms which are context-savvy + if( parent ) { + const char* const ptype = parent->GetType(); + + if( descendsFrom( parent, "ilst" )) { + if( ATOMID( ptype ) == ATOMID( "ilst" )) + return new MP4ItemAtom( file, type ); + + if( ATOMID( type ) == ATOMID( "data" )) + return new MP4DataAtom(file); + + if( ATOMID( ptype ) == ATOMID( "----" )) { + if( ATOMID( type ) == ATOMID( "mean" )) + return new MP4MeanAtom(file); + if( ATOMID( type ) == ATOMID( "name" )) + return new MP4NameAtom(file); + } + } + else if( ATOMID( ptype ) == ATOMID( "meta" )) { + if( ATOMID( type ) == ATOMID( "hdlr" )) + return new MP4ItmfHdlrAtom(file); + } + else if( ATOMID( ptype ) == ATOMID( "udta" )) { + if( ATOMID( type ) == ATOMID( "hnti" )) + return new MP4HntiAtom(file); + if( ATOMID( type ) == ATOMID( "hinf" )) + return new MP4HinfAtom(file); + for( const char* const* p = UDTA_ELEMENTS; *p; p++ ) + if( !strcmp( type, *p )) + return new MP4UdtaElementAtom( file, type ); + } + } + + // no-context construction (old-style) + switch( (uint8_t)type[0] ) { + case 'S': + if( ATOMID(type) == ATOMID("SVQ3") ) + return new MP4VideoAtom( file, type ); + if( ATOMID(type) == ATOMID("SMI ") ) + return new MP4SmiAtom(file); + break; + + case 'a': + if( ATOMID(type) == ATOMID("avc1") ) + return new MP4Avc1Atom(file); + if( ATOMID(type) == ATOMID("ac-3") ) + return new MP4Ac3Atom(file); + if( ATOMID(type) == ATOMID("avcC") ) + return new MP4AvcCAtom(file); + if( ATOMID(type) == ATOMID("alis") ) + return new MP4UrlAtom( file, type ); + if( ATOMID(type) == ATOMID("alaw") ) + return new MP4SoundAtom( file, type ); + if( ATOMID(type) == ATOMID("alac") ) + return new MP4SoundAtom( file, type ); + break; + + case 'c': + if( ATOMID(type) == ATOMID("chap") ) + return new MP4TrefTypeAtom( file, type ); + if( ATOMID(type) == ATOMID("chpl") ) + return new MP4ChplAtom(file); + if( ATOMID(type) == ATOMID("colr") ) + return new MP4ColrAtom(file); + break; + + case 'd': + if( ATOMID(type) == ATOMID("d263") ) + return new MP4D263Atom(file); + if( ATOMID(type) == ATOMID("damr") ) + return new MP4DamrAtom(file); + if( ATOMID(type) == ATOMID("dref") ) + return new MP4DrefAtom(file); + if( ATOMID(type) == ATOMID("dpnd") ) + return new MP4TrefTypeAtom( file, type ); + if( ATOMID(type) == ATOMID("dac3") ) + return new MP4DAc3Atom(file); + break; + + case 'e': + if( ATOMID(type) == ATOMID("elst") ) + return new MP4ElstAtom(file); + if( ATOMID(type) == ATOMID("enca") ) + return new MP4EncaAtom(file); + if( ATOMID(type) == ATOMID("encv") ) + return new MP4EncvAtom(file); + break; + + case 'f': + if( ATOMID(type) == ATOMID("free") ) + return new MP4FreeAtom(file); + if( ATOMID(type) == ATOMID("ftyp") ) + return new MP4FtypAtom(file); + if( ATOMID(type) == ATOMID("ftab") ) + return new MP4FtabAtom(file); + break; + + case 'g': + if( ATOMID(type) == ATOMID("gmin") ) + return new MP4GminAtom(file); + break; + + case 'h': + if( ATOMID(type) == ATOMID("hdlr") ) + return new MP4HdlrAtom(file); + if( ATOMID(type) == ATOMID("hint") ) + return new MP4TrefTypeAtom( file, type ); + if( ATOMID(type) == ATOMID("h263") ) + return new MP4VideoAtom( file, type ); + if( ATOMID(type) == ATOMID("href") ) + return new MP4HrefAtom(file); + break; + + case 'i': + if( ATOMID(type) == ATOMID("ipir") ) + return new MP4TrefTypeAtom( file, type ); + if( ATOMID(type) == ATOMID("ima4") ) + return new MP4SoundAtom( file, type ); + break; + + case 'j': + if( ATOMID(type) == ATOMID("jpeg") ) + return new MP4VideoAtom(file, "jpeg"); + break; + + case 'm': + if( ATOMID(type) == ATOMID("mdhd") ) + return new MP4MdhdAtom(file); + if( ATOMID(type) == ATOMID("mvhd") ) + return new MP4MvhdAtom(file); + if( ATOMID(type) == ATOMID("mdat") ) + return new MP4MdatAtom(file); + if( ATOMID(type) == ATOMID("mpod") ) + return new MP4TrefTypeAtom( file, type ); + if( ATOMID(type) == ATOMID("mp4a") ) + return new MP4SoundAtom( file, type ); + if( ATOMID(type) == ATOMID("mp4s") ) + return new MP4Mp4sAtom(file); + if( ATOMID(type) == ATOMID("mp4v") ) + return new MP4Mp4vAtom(file); + break; + + case 'n': + if( ATOMID(type) == ATOMID("nmhd") ) + return new MP4NmhdAtom(file); + break; + + case 'o': + if( ATOMID(type) == ATOMID("ohdr") ) + return new MP4OhdrAtom(file); + break; + + case 'p': + if( ATOMID(type) == ATOMID("pasp") ) + return new MP4PaspAtom(file); + break; + + case 'r': + if( ATOMID(type) == ATOMID("rtp ") ) + return new MP4RtpAtom(file); + if( ATOMID(type) == ATOMID("raw ") ) + return new MP4VideoAtom( file, type ); + break; + + case 's': + if( ATOMID(type) == ATOMID("s263") ) + return new MP4S263Atom(file); + if( ATOMID(type) == ATOMID("samr") ) + return new MP4AmrAtom( file, type ); + if( ATOMID(type) == ATOMID("sawb") ) + return new MP4AmrAtom( file, type ); + if( ATOMID(type) == ATOMID("sdtp") ) + return new MP4SdtpAtom(file); + if( ATOMID(type) == ATOMID("stbl") ) + return new MP4StblAtom(file); + if( ATOMID(type) == ATOMID("stsd") ) + return new MP4StsdAtom(file); + if( ATOMID(type) == ATOMID("stsz") ) + return new MP4StszAtom(file); + if( ATOMID(type) == ATOMID("stsc") ) + return new MP4StscAtom(file); + if( ATOMID(type) == ATOMID("stz2") ) + return new MP4Stz2Atom(file); + if( ATOMID(type) == ATOMID("stdp") ) + return new MP4StdpAtom(file); + if( ATOMID(type) == ATOMID("sdp ") ) + return new MP4SdpAtom(file); + if( ATOMID(type) == ATOMID("sync") ) + return new MP4TrefTypeAtom( file, type ); + if( ATOMID(type) == ATOMID("skip") ) + return new MP4FreeAtom( file, type ); + if (ATOMID(type) == ATOMID("sowt") ) + return new MP4SoundAtom( file, type ); + break; + + case 't': + if( ATOMID(type) == ATOMID("text") ) + return new MP4TextAtom(file); + if( ATOMID(type) == ATOMID("tx3g") ) + return new MP4Tx3gAtom(file); + if( ATOMID(type) == ATOMID("tkhd") ) + return new MP4TkhdAtom(file); + if( ATOMID(type) == ATOMID("tfhd") ) + return new MP4TfhdAtom(file); + if( ATOMID(type) == ATOMID("trun") ) + return new MP4TrunAtom(file); + if( ATOMID(type) == ATOMID("twos") ) + return new MP4SoundAtom( file, type ); + break; + + case 'u': + if( ATOMID(type) == ATOMID("udta") ) + return new MP4UdtaAtom(file); + if( ATOMID(type) == ATOMID("url ") ) + return new MP4UrlAtom(file); + if( ATOMID(type) == ATOMID("urn ") ) + return new MP4UrnAtom(file); + if( ATOMID(type) == ATOMID("ulaw") ) + return new MP4SoundAtom( file, type ); + break; + + case 'v': + if( ATOMID(type) == ATOMID("vmhd") ) + return new MP4VmhdAtom(file); + break; + + case 'y': + if( ATOMID(type) == ATOMID("yuv2") ) + return new MP4VideoAtom( file, type ); + break; + + default: + break; + } + + // default to MP4StandardAtom implementation + return new MP4StandardAtom( file, type ); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4atom.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4atom.h new file mode 100644 index 00000000..b504c75b --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4atom.h @@ -0,0 +1,263 @@ +/* + * 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 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Ximpo Group Ltd. [email protected] + */ + +#ifndef MP4V2_IMPL_MP4ATOM_H +#define MP4V2_IMPL_MP4ATOM_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +class MP4Atom; +MP4ARRAY_DECL(MP4Atom, MP4Atom*); + +#define Required true +#define Optional false +#define OnlyOne true +#define Many false +#define Counted true + +/* helper class */ +class MP4AtomInfo { +public: + MP4AtomInfo() { + m_name = NULL; + } + MP4AtomInfo(const char* name, bool mandatory, bool onlyOne); + + const char* m_name; + bool m_mandatory; + bool m_onlyOne; + uint32_t m_count; +}; + +MP4ARRAY_DECL(MP4AtomInfo, MP4AtomInfo*); + +class MP4Atom +{ +public: + static MP4Atom* ReadAtom( MP4File& file, MP4Atom* pParentAtom ); + static MP4Atom* CreateAtom( MP4File& file, MP4Atom* parent, const char* type ); + static bool IsReasonableType( const char* type ); + +private: + static MP4Atom* factory( MP4File &file, MP4Atom* parent, const char* type ); + static bool descendsFrom( MP4Atom* parent, const char* type ); + +public: + MP4Atom(MP4File& file, const char* type = NULL); + virtual ~MP4Atom(); + + MP4File& GetFile() { + return m_File; + }; + + uint64_t GetStart() { + return m_start; + }; + void SetStart(uint64_t pos) { + m_start = pos; + }; + + uint64_t GetEnd() { + return m_end; + }; + void SetEnd(uint64_t pos) { + m_end = pos; + }; + + uint64_t GetSize() { + return m_size; + } + void SetSize(uint64_t size) { + m_size = size; + } + + const char* GetType() { + return m_type; + }; + void SetType(const char* type) { + if (type && *type != '\0') { + // not needed ASSERT(strlen(type) == 4); + memcpy(m_type, type, 4); + m_type[4] = '\0'; + } else { + memset(m_type, 0, 5); + } + } + + void GetExtendedType(uint8_t* pExtendedType) { + memcpy(pExtendedType, m_extendedType, sizeof(m_extendedType)); + }; + void SetExtendedType(uint8_t* pExtendedType) { + memcpy(m_extendedType, pExtendedType, sizeof(m_extendedType)); + }; + + bool IsUnknownType() { + return m_unknownType; + } + void SetUnknownType(bool unknownType = true) { + m_unknownType = unknownType; + } + + bool IsRootAtom() { + return m_type[0] == '\0'; + } + + MP4Atom* GetParentAtom() { + return m_pParentAtom; + } + void SetParentAtom(MP4Atom* pParentAtom) { + m_pParentAtom = pParentAtom; + } + + void AddChildAtom(MP4Atom* pChildAtom) { + pChildAtom->SetParentAtom(this); + m_pChildAtoms.Add(pChildAtom); + } + + void InsertChildAtom(MP4Atom* pChildAtom, uint32_t index) { + pChildAtom->SetParentAtom(this); + m_pChildAtoms.Insert(pChildAtom, index); + } + + void DeleteChildAtom(MP4Atom* pChildAtom) { + for (MP4ArrayIndex i = 0; i < m_pChildAtoms.Size(); i++) { + if (m_pChildAtoms[i] == pChildAtom) { + m_pChildAtoms.Delete(i); + return; + } + } + } + + uint32_t GetNumberOfChildAtoms() { + return m_pChildAtoms.Size(); + } + + MP4Atom* GetChildAtom(uint32_t index) { + return m_pChildAtoms[index]; + } + + MP4Property* GetProperty(uint32_t index) { + return m_pProperties[index]; + } + + uint32_t GetCount() { + return m_pProperties.Size(); + } + + MP4Atom* FindAtom(const char* name); + + MP4Atom* FindChildAtom(const char* name); + + bool FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + uint32_t GetFlags(); + void SetFlags(uint32_t flags); + + uint8_t GetDepth(); + + void Skip(); + + virtual void Generate(); + virtual void Read(); + virtual void BeginWrite(bool use64 = false); + virtual void Write(); + virtual void Rewrite(); + virtual void FinishWrite(bool use64 = false); + virtual void Dump(uint8_t indent, bool dumpImplicits); + + bool GetLargesizeMode(); + +protected: + void AddProperty(MP4Property* pProperty); + + void AddVersionAndFlags(); + + void AddReserved(MP4Atom& parentAtom, const char* name, uint32_t size); + + void ExpectChildAtom(const char* name, + bool mandatory, bool onlyOne = true); + + MP4AtomInfo* FindAtomInfo(const char* name); + + bool IsMe(const char* name); + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex); + + void ReadProperties( + uint32_t startIndex = 0, uint32_t count = 0xFFFFFFFF); + void ReadChildAtoms(); + + void WriteProperties( + uint32_t startIndex = 0, uint32_t count = 0xFFFFFFFF); + void WriteChildAtoms(); + + uint8_t GetVersion(); + void SetVersion(uint8_t version); + + void SetLargesizeMode( bool ); + +protected: + MP4File& m_File; + uint64_t m_start; + uint64_t m_end; + bool m_largesizeMode; // true if largesize mode + uint64_t m_size; + char m_type[5]; + bool m_unknownType; + uint8_t m_extendedType[16]; + + MP4Atom* m_pParentAtom; + uint8_t m_depth; + + MP4PropertyArray m_pProperties; + MP4AtomInfoArray m_pChildAtomInfos; + MP4AtomArray m_pChildAtoms; +private: + MP4Atom(); + MP4Atom( const MP4Atom &src ); + MP4Atom &operator= ( const MP4Atom &src ); +}; + +inline uint32_t ATOMID(const char* type) { + return STRTOINT32(type); +} + +// inverse ATOMID - 32 bit id to string +inline void IDATOM(uint32_t type, char *s) { + INT32TOSTR(type, s); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4ATOM_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4container.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4container.cpp new file mode 100644 index 00000000..acfbd29f --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4container.cpp @@ -0,0 +1,228 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Container::~MP4Container() +{ + for (uint32_t i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } +} + +void MP4Container::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + m_pProperties.Add(pProperty); +} + +bool MP4Container::FindProperty(const char *name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (pIndex) { + *pIndex = 0; // set the default answer for index + } + + 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 MP4Container::FindIntegerProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new Exception("no such property", __FILE__, __LINE__, __FUNCTION__); + } + + switch ((*ppProperty)->GetType()) { + case Integer8Property: + case Integer16Property: + case Integer24Property: + case Integer32Property: + case Integer64Property: + break; + default: + throw new Exception("type mismatch", __FILE__, __LINE__, __FUNCTION__); + } +} + +uint64_t MP4Container::GetIntegerProperty(const char* name) +{ + MP4Property* pProperty; + uint32_t index; + + FindIntegerProperty(name, &pProperty, &index); + + return ((MP4IntegerProperty*)pProperty)->GetValue(index); +} + +void MP4Container::SetIntegerProperty(const char* name, uint64_t value) +{ + MP4Property* pProperty = NULL; + uint32_t index = 0; + + FindIntegerProperty(name, &pProperty, &index); + + ((MP4IntegerProperty*)pProperty)->SetValue(value, index); +} + +void MP4Container::FindFloatProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new Exception("no such property", __FILE__, __LINE__, __FUNCTION__); + } + if ((*ppProperty)->GetType() != Float32Property) { + throw new Exception("type mismatch", __FILE__, __LINE__, __FUNCTION__); + } +} + +float MP4Container::GetFloatProperty(const char* name) +{ + MP4Property* pProperty; + uint32_t index; + + FindFloatProperty(name, &pProperty, &index); + + return ((MP4Float32Property*)pProperty)->GetValue(index); +} + +void MP4Container::SetFloatProperty(const char* name, float value) +{ + MP4Property* pProperty; + uint32_t index; + + FindFloatProperty(name, &pProperty, &index); + + ((MP4Float32Property*)pProperty)->SetValue(value, index); +} + +void MP4Container::FindStringProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new Exception("no such property", __FILE__, __LINE__, __FUNCTION__); + } + if ((*ppProperty)->GetType() != StringProperty) { + throw new Exception("type mismatch", __FILE__, __LINE__, __FUNCTION__); + } +} + +const char* MP4Container::GetStringProperty(const char* name) +{ + MP4Property* pProperty; + uint32_t index; + + FindStringProperty(name, &pProperty, &index); + + return ((MP4StringProperty*)pProperty)->GetValue(index); +} + +void MP4Container::SetStringProperty(const char* name, const char* value) +{ + MP4Property* pProperty; + uint32_t index; + + FindStringProperty(name, &pProperty, &index); + + ((MP4StringProperty*)pProperty)->SetValue(value, index); +} + +void MP4Container::FindBytesProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + throw new Exception("no such property", __FILE__, __LINE__, __FUNCTION__); + } + if ((*ppProperty)->GetType() != BytesProperty) { + throw new Exception("type mismatch", __FILE__, __LINE__, __FUNCTION__); + } +} + +void MP4Container::GetBytesProperty(const char* name, + uint8_t** ppValue, uint32_t* pValueSize) +{ + MP4Property* pProperty; + uint32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index); +} + +void MP4Container::SetBytesProperty(const char* name, + const uint8_t* pValue, uint32_t valueSize) +{ + MP4Property* pProperty; + uint32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index); +} + +void MP4Container::Read(MP4File& file) +{ + uint32_t numProperties = m_pProperties.Size(); + + for (uint32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Read(file); + } +} + +void MP4Container::Write(MP4File& file) +{ + uint32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + + for (uint32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Write(file); + } +} + +void MP4Container::Dump(uint8_t indent, bool dumpImplicits) +{ + uint32_t numProperties = m_pProperties.Size(); + + for (uint32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Dump(indent, dumpImplicits); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4container.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4container.h new file mode 100644 index 00000000..100d94ff --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4container.h @@ -0,0 +1,94 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_MP4CONTAINER_H +#define MP4V2_IMPL_MP4CONTAINER_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +// base class - container of mp4 properties +class MP4Container { +public: + MP4Container() { } + + virtual ~MP4Container(); + + void AddProperty(MP4Property* pProperty); + + virtual void Read(MP4File& file); + + virtual void Write(MP4File& file); + + virtual void Dump(uint8_t indent, bool dumpImplicits); + + MP4Property* GetProperty(uint32_t index) { + return m_pProperties[index]; + } + + // LATER MP4Property* GetProperty(const char* name); throw on error + // LATER MP4Property* FindProperty(const char* name, uint32_t* pIndex = NULL); returns NULL on error + + bool FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + void FindIntegerProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + uint64_t GetIntegerProperty(const char* name); + + void SetIntegerProperty(const char* name, uint64_t value); + + void FindFloatProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + float GetFloatProperty(const char* name); + + void SetFloatProperty(const char* name, float value); + + void FindStringProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + const char* GetStringProperty(const char* name); + + void SetStringProperty(const char* name, const char* value); + + void FindBytesProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + void GetBytesProperty(const char* name, + uint8_t** ppValue, uint32_t* pValueSize); + + void SetBytesProperty(const char* name, + const uint8_t* pValue, uint32_t valueSize); + +protected: + MP4PropertyArray m_pProperties; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4CONTAINER_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4descriptor.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4descriptor.cpp new file mode 100644 index 00000000..202deb15 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4descriptor.cpp @@ -0,0 +1,215 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Descriptor::MP4Descriptor(MP4Atom& parentAtom, uint8_t tag) + : m_parentAtom(parentAtom) +{ + m_tag = tag; + m_start = 0; + m_size = 0; + m_readMutatePoint = 0; +} + +MP4Descriptor::~MP4Descriptor() +{ + for (uint32_t i = 0; i < m_pProperties.Size(); i++) { + delete m_pProperties[i]; + } +} + +void MP4Descriptor::AddProperty(MP4Property* pProperty) +{ + ASSERT(pProperty); + m_pProperties.Add(pProperty); +} + +bool MP4Descriptor::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 MP4Descriptor::Generate() +{ + // generate properties + for (uint32_t i = 0; i < m_pProperties.Size(); i++) { + m_pProperties[i]->Generate(); + } +} + +void MP4Descriptor::Read(MP4File& file) +{ + ReadHeader(file); + + ReadProperties(file, 0, m_readMutatePoint); + + Mutate(); + + ReadProperties(file, m_readMutatePoint); + + // flush any leftover read bits + file.FlushReadBits(); +} + +void MP4Descriptor::ReadHeader(MP4File& file) +{ + log.verbose1f("\"%s\": ReadDescriptor: pos = 0x%" PRIx64, file.GetFilename().c_str(), + file.GetPosition()); + + // read tag and length + uint8_t tag = file.ReadUInt8(); + if (m_tag) { + ASSERT(tag == m_tag); + } else { + m_tag = tag; + } + m_size = file.ReadMpegLength(); + m_start = file.GetPosition(); + + log.verbose1f("\"%s\": ReadDescriptor: tag 0x%02x data size %u (0x%x)", + file.GetFilename().c_str(), m_tag, m_size, m_size); +} + +void MP4Descriptor::ReadProperties(MP4File& file, + uint32_t propStartIndex, uint32_t propCount) +{ + uint32_t numProperties = min(propCount, + m_pProperties.Size() - propStartIndex); + + for (uint32_t i = propStartIndex; + i < propStartIndex + numProperties; i++) { + + MP4Property* pProperty = m_pProperties[i]; + + int32_t remaining = m_size - (file.GetPosition() - m_start); + + if (pProperty->GetType() == DescriptorProperty) { + if (remaining > 0) { + // place a limit on how far this sub-descriptor looks + ((MP4DescriptorProperty*)pProperty)->SetSizeLimit(remaining); + pProperty->Read(file); + } // else do nothing, empty descriptor + } else { + // non-descriptor property + if (remaining >= 0) { + pProperty->Read(file); + + MP4LogLevel thisVerbosity = + (pProperty->GetType() == TableProperty) ? + MP4_LOG_VERBOSE2 : MP4_LOG_VERBOSE1; + + if (log.verbosity >= thisVerbosity) { + // log.printf(thisVerbosity,"Read: "); + pProperty->Dump(0, true); + } + } else { + log.errorf("%s: \"%s\": Overran descriptor, tag %u data size %u property %u", + __FUNCTION__, file.GetFilename().c_str(), m_tag, m_size, i); + throw new Exception("overran descriptor",__FILE__, __LINE__, __FUNCTION__); + } + } + } +} + +void MP4Descriptor::Write(MP4File& file) +{ + // call virtual function to adapt properties before writing + Mutate(); + + uint32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + + // write tag and length placeholder + file.WriteUInt8(m_tag); + uint64_t lengthPos = file.GetPosition(); + file.WriteMpegLength(0); + uint64_t startPos = file.GetPosition(); + + for (uint32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Write(file); + } + + // align with byte boundary (rarely necessary) + file.PadWriteBits(); + + // go back and write correct length + uint64_t endPos = file.GetPosition(); + file.SetPosition(lengthPos); + file.WriteMpegLength(endPos - startPos); + file.SetPosition(endPos); +} + +void MP4Descriptor::WriteToMemory(MP4File& file, + uint8_t** ppBytes, uint64_t* pNumBytes) +{ + // use memory buffer to save descriptor in memory + // instead of going directly to disk + + file.EnableMemoryBuffer(); + + Write(file); + + file.DisableMemoryBuffer(ppBytes, pNumBytes); +} + +void MP4Descriptor::Dump(uint8_t indent, bool dumpImplicits) +{ + // call virtual function to adapt properties before dumping + Mutate(); + + uint32_t numProperties = m_pProperties.Size(); + + if (numProperties == 0) { + WARNING(numProperties == 0); + return; + } + for (uint32_t i = 0; i < numProperties; i++) { + m_pProperties[i]->Dump(indent, dumpImplicits); + } +} + +uint8_t MP4Descriptor::GetDepth() +{ + return m_parentAtom.GetDepth(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4descriptor.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4descriptor.h new file mode 100644 index 00000000..160c5cf8 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4descriptor.h @@ -0,0 +1,104 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_MP4DESCRIPTOR_H +#define MP4V2_IMPL_MP4DESCRIPTOR_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +class MP4Descriptor { +public: + MP4Descriptor(MP4Atom& parentAtom, uint8_t tag = 0); + + virtual ~MP4Descriptor(); + + uint8_t GetTag() { + return m_tag; + } + void SetTag(uint8_t tag) { + m_tag = tag; + } + + void AddProperty(MP4Property* pProperty); + + virtual void Generate(); + virtual void Read(MP4File& file); + virtual void Write(MP4File& file); + virtual void Dump(uint8_t indent, bool dumpImplicits); + + MP4Property* GetProperty(uint32_t index) { + return m_pProperties[index]; + } + + // use with extreme caution + void SetProperty(uint32_t index, MP4Property* pProperty) { + m_pProperties[index] = pProperty; + } + + bool FindProperty( const char* name, MP4Property** ppProperty, + uint32_t* pIndex = NULL) + { + return FindContainedProperty(name, ppProperty, pIndex); + } + + void WriteToMemory(MP4File& file, + uint8_t** ppBytes, uint64_t* pNumBytes); + +protected: + void SetReadMutate(uint32_t propIndex) { + m_readMutatePoint = propIndex; + } + + void ReadHeader(MP4File& file); + void ReadProperties(MP4File& file, + uint32_t startIndex = 0, uint32_t count = 0xFFFFFFFF); + + virtual void Mutate() { + // default is a no-op + }; + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex); + + uint8_t GetDepth(); + +protected: + MP4Atom& m_parentAtom; + uint8_t m_tag; + uint64_t m_start; + uint32_t m_size; + MP4PropertyArray m_pProperties; + uint32_t m_readMutatePoint; +private: + MP4Descriptor(); + MP4Descriptor ( const MP4Descriptor &src ); + MP4Descriptor &operator= ( const MP4Descriptor &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4DESCRIPTOR_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file.cpp new file mode 100644 index 00000000..25e241f7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file.cpp @@ -0,0 +1,4364 @@ +/* + * 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 - 2005. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4File::MP4File( ) : + m_file ( NULL ) + , m_fileOriginalSize ( 0 ) + , m_createFlags ( 0 ) +{ + this->Init(); +} + +/** + * Initialize member variables (shared among constructors) + */ +void MP4File::Init() +{ + m_pRootAtom = NULL; + m_odTrackId = MP4_INVALID_TRACK_ID; + + m_useIsma = false; + + m_pModificationProperty = NULL; + m_pTimeScaleProperty = NULL; + m_pDurationProperty = NULL; + + m_memoryBuffer = NULL; + m_memoryBufferSize = 0; + m_memoryBufferPosition = 0; + + m_numReadBits = 0; + m_bufReadBits = 0; + m_numWriteBits = 0; + m_bufWriteBits = 0; + m_editName = NULL; + m_trakName[0] = '\0'; +} + +MP4File::~MP4File() +{ + delete m_pRootAtom; + for( uint32_t i = 0; i < m_pTracks.Size(); i++ ) + delete m_pTracks[i]; + MP4Free( m_memoryBuffer ); // just in case + CHECK_AND_FREE( m_editName ); + delete m_file; +} + +const std::string & +MP4File::GetFilename() const +{ + // No one should call this unless Read, etc. has + // succeeded and m_file exists since this method really + // only exists for the public API. This helps us + // guarantee that MP4GetFilename always returns a valid + // string given a valid MP4FileHandle + ASSERT(m_file); + return m_file->name; +} + +void MP4File::Read( const char* name, const MP4FileProvider* provider ) +{ + Open( name, File::MODE_READ, provider ); + ReadFromFile(); + CacheProperties(); +} + +void MP4File::Create( const char* fileName, + uint32_t flags, + int add_ftyp, + int add_iods, + char* majorBrand, + uint32_t minorVersion, + char** supportedBrands, + uint32_t supportedBrandsCount ) +{ + m_createFlags = flags; + Open( fileName, File::MODE_CREATE, NULL ); + + // generate a skeletal atom tree + m_pRootAtom = MP4Atom::CreateAtom(*this, NULL, NULL); + m_pRootAtom->Generate(); + + if (add_ftyp != 0) { + MakeFtypAtom(majorBrand, minorVersion, + supportedBrands, supportedBrandsCount); + } + + CacheProperties(); + + // create mdat, and insert it after ftyp, and before moov + (void)InsertChildAtom(m_pRootAtom, "mdat", + add_ftyp != 0 ? 1 : 0); + + // start writing + m_pRootAtom->BeginWrite(); + if (add_iods != 0) { + (void)AddChildAtom("moov", "iods"); + } +} + +bool MP4File::Use64Bits (const char *atomName) +{ + uint32_t atomid = ATOMID(atomName); + if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) { + return (m_createFlags & MP4_CREATE_64BIT_DATA) == MP4_CREATE_64BIT_DATA; + } + if (atomid == ATOMID("mvhd") || + atomid == ATOMID("tkhd") || + atomid == ATOMID("mdhd")) { + return (m_createFlags & MP4_CREATE_64BIT_TIME) == MP4_CREATE_64BIT_TIME; + } + return false; +} + +void MP4File::Check64BitStatus (const char *atomName) +{ + uint32_t atomid = ATOMID(atomName); + + if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) { + m_createFlags |= MP4_CREATE_64BIT_DATA; + } else if (atomid == ATOMID("mvhd") || + atomid == ATOMID("tkhd") || + atomid == ATOMID("mdhd")) { + m_createFlags |= MP4_CREATE_64BIT_TIME; + } +} + + +bool MP4File::Modify( const char* fileName ) +{ + Open( fileName, File::MODE_MODIFY, NULL ); + ReadFromFile(); + + // find the moov atom + MP4Atom* pMoovAtom = m_pRootAtom->FindAtom("moov"); + uint32_t numAtoms; + + if (pMoovAtom == NULL) { + // there isn't one, odd but we can still proceed + log.warningf("%s: \"%s\": no moov atom, can't modify", + __FUNCTION__, GetFilename().c_str()); + return false; + //pMoovAtom = AddChildAtom(m_pRootAtom, "moov"); + } else { + numAtoms = m_pRootAtom->GetNumberOfChildAtoms(); + + // work backwards thru the top level atoms + int32_t i; + bool lastAtomIsMoov = true; + MP4Atom* pLastAtom = NULL; + + for (i = numAtoms - 1; i >= 0; i--) { + MP4Atom* pAtom = m_pRootAtom->GetChildAtom(i); + const char* type = pAtom->GetType(); + + // get rid of any trailing free or skips + if (!strcmp(type, "free") || !strcmp(type, "skip")) { + m_pRootAtom->DeleteChildAtom(pAtom); + continue; + } + + if (strcmp(type, "moov")) { + if (pLastAtom == NULL) { + pLastAtom = pAtom; + lastAtomIsMoov = false; + } + continue; + } + + // now at moov atom + + // multiple moov atoms?!? + if (pAtom != pMoovAtom) { + throw new Exception( + "Badly formed mp4 file, multiple moov atoms", + __FILE__,__LINE__,__FUNCTION__); + } + + if (lastAtomIsMoov) { + // position to start of moov atom, + // effectively truncating file + // prior to adding new mdat + SetPosition(pMoovAtom->GetStart()); + + } else { // last atom isn't moov + // need to place a free atom + MP4Atom* pFreeAtom = MP4Atom::CreateAtom(*this, NULL, "free"); + + // in existing position of the moov atom + m_pRootAtom->InsertChildAtom(pFreeAtom, i); + m_pRootAtom->DeleteChildAtom(pMoovAtom); + m_pRootAtom->AddChildAtom(pMoovAtom); + + // write free atom to disk + SetPosition(pMoovAtom->GetStart()); + pFreeAtom->SetSize(pMoovAtom->GetSize()); + pFreeAtom->Write(); + + // finally set our file position to the end of the last atom + SetPosition(pLastAtom->GetEnd()); + } + + break; + } + ASSERT(i != -1); + } + + CacheProperties(); // of moov atom + + numAtoms = m_pRootAtom->GetNumberOfChildAtoms(); + + // insert another mdat prior to moov atom (the last atom) + MP4Atom* pMdatAtom = InsertChildAtom(m_pRootAtom, "mdat", numAtoms - 1); + + // start writing new mdat + pMdatAtom->BeginWrite(Use64Bits("mdat")); + return true; +} + +void MP4File::Optimize( const char* srcFileName, const char* dstFileName ) +{ + File* src = NULL; + File* dst = NULL; + + // compute destination filename + string dname; + if( dstFileName ) { + dname = dstFileName; + } else { + // No destination given, so let's kludge together a temporary file. + // We'll try to create it in the same directory as the srcFileName, since + // it's more likely that directory is writable. In the absence of that, + // we'll create it in "./", which is the default pathnameTemp() provides. + string s(srcFileName); + size_t pos = s.find_last_of("\\/"); + const char *d; + if (pos == string::npos) { + d = "."; + } else { + s = s.substr(0, pos); + d = s.c_str(); + } + FileSystem::pathnameTemp( dname, d, "tmp", ".mp4" ); + } + + try { + // file source to optimize + Open( srcFileName, File::MODE_READ, NULL ); + ReadFromFile(); + CacheProperties(); // of moov atom + + src = m_file; + m_file = NULL; + + // optimized file destination + Open( dname.c_str(), File::MODE_CREATE, NULL ); + dst = m_file; + + SetIntegerProperty( "moov.mvhd.modificationTime", MP4GetAbsTimestamp() ); + + // writing meta info in the optimal order + ((MP4RootAtom*)m_pRootAtom)->BeginOptimalWrite(); + + // write data in optimal order + RewriteMdat( *src, *dst ); + + // finish writing + ((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite(); + + } + catch (...) { + // cleanup and rethrow. Without this, we'd leak memory and an open file handle(s). + if(src == NULL && dst == NULL) + delete m_file;// We didn't make it far enough to have m_file go to src or dst. + + m_file = NULL; + delete dst; + delete src; + throw; + } + + // cleanup + delete dst; + delete src; + m_file = NULL; + + // move temporary file into place + if( !dstFileName ) + Rename( dname.c_str(), srcFileName ); +} + +void MP4File::RewriteMdat( File& src, File& dst ) +{ + uint32_t numTracks = m_pTracks.Size(); + + MP4ChunkId* chunkIds = new MP4ChunkId[numTracks]; + MP4ChunkId* maxChunkIds = new MP4ChunkId[numTracks]; + MP4Timestamp* nextChunkTimes = new MP4Timestamp[numTracks]; + + for( uint32_t i = 0; i < numTracks; i++ ) { + chunkIds[i] = 1; + maxChunkIds[i] = m_pTracks[i]->GetNumberOfChunks(); + nextChunkTimes[i] = MP4_INVALID_TIMESTAMP; + } + + for( ;; ) { + uint32_t nextTrackIndex = (uint32_t)-1; + MP4Timestamp nextTime = MP4_INVALID_TIMESTAMP; + + for( uint32_t i = 0; i < numTracks; i++ ) { + if( chunkIds[i] > maxChunkIds[i] ) + continue; + + if( nextChunkTimes[i] == MP4_INVALID_TIMESTAMP ) { + MP4Timestamp chunkTime = m_pTracks[i]->GetChunkTime( chunkIds[i] ); + nextChunkTimes[i] = MP4ConvertTime( chunkTime, m_pTracks[i]->GetTimeScale(), GetTimeScale() ); + } + + // time is not earliest so far + if( nextChunkTimes[i] > nextTime ) + continue; + + // prefer hint tracks to media tracks if times are equal + if( nextChunkTimes[i] == nextTime && strcmp( m_pTracks[i]->GetType(), MP4_HINT_TRACK_TYPE )) + continue; + + // this is our current choice of tracks + nextTime = nextChunkTimes[i]; + nextTrackIndex = i; + } + + if( nextTrackIndex == (uint32_t)-1 ) + break; + + uint8_t* pChunk; + uint32_t chunkSize; + + // point into original mp4 file for read chunk call + m_file = &src; + m_pTracks[nextTrackIndex]->ReadChunk( chunkIds[nextTrackIndex], &pChunk, &chunkSize ); + + // point back at the new mp4 file for write chunk + m_file = &dst; + m_pTracks[nextTrackIndex]->RewriteChunk( chunkIds[nextTrackIndex], pChunk, chunkSize ); + + MP4Free( pChunk ); + + chunkIds[nextTrackIndex]++; + nextChunkTimes[nextTrackIndex] = MP4_INVALID_TIMESTAMP; + } + + delete [] chunkIds; + delete [] maxChunkIds; + delete [] nextChunkTimes; +} + +void MP4File::Open( const char* name, File::Mode mode, const MP4FileProvider* provider ) +{ + ASSERT( !m_file ); + + m_file = new File( name, mode, provider ? new io::CustomFileProvider( *provider ) : NULL ); + if( m_file->open() ) { + ostringstream msg; + msg << "open(" << name << ") failed"; + throw new Exception( msg.str(), __FILE__, __LINE__, __FUNCTION__); + } + + switch( mode ) { + case File::MODE_READ: + case File::MODE_MODIFY: + m_fileOriginalSize = m_file->size; + break; + + case File::MODE_CREATE: + default: + m_fileOriginalSize = 0; + break; + } +} + +void MP4File::ReadFromFile() +{ + // ensure we start at beginning of file + SetPosition(0); + + // create a new root atom + ASSERT(m_pRootAtom == NULL); + m_pRootAtom = MP4Atom::CreateAtom(*this, NULL, NULL); + + uint64_t fileSize = GetSize(); + + m_pRootAtom->SetStart(0); + m_pRootAtom->SetSize(fileSize); + m_pRootAtom->SetEnd(fileSize); + + m_pRootAtom->Read(); + + // create MP4Track's for any tracks in the file + GenerateTracks(); +} + +void MP4File::GenerateTracks() +{ + uint32_t trackIndex = 0; + + while (true) { + char trackName[32]; + snprintf(trackName, sizeof(trackName), "moov.trak[%u]", trackIndex); + + // find next trak atom + MP4Atom* pTrakAtom = m_pRootAtom->FindAtom(trackName); + + // done, no more trak atoms + if (pTrakAtom == NULL) { + break; + } + + // find track id property + MP4Integer32Property* pTrackIdProperty = NULL; + (void)pTrakAtom->FindProperty( + "trak.tkhd.trackId", + (MP4Property**)&pTrackIdProperty); + + // find track type property + MP4StringProperty* pTypeProperty = NULL; + (void)pTrakAtom->FindProperty( + "trak.mdia.hdlr.handlerType", + (MP4Property**)&pTypeProperty); + + // ensure we have the basics properties + if (pTrackIdProperty && pTypeProperty) { + + m_trakIds.Add(pTrackIdProperty->GetValue()); + + MP4Track* pTrack = NULL; + try { + if (!strcmp(pTypeProperty->GetValue(), MP4_HINT_TRACK_TYPE)) { + pTrack = new MP4RtpHintTrack(*this, *pTrakAtom); + } else { + pTrack = new MP4Track(*this, *pTrakAtom); + } + m_pTracks.Add(pTrack); + } + catch( Exception* x ) { + log.errorf(*x); + delete x; + } + + // remember when we encounter the OD track + if (pTrack && !strcmp(pTrack->GetType(), MP4_OD_TRACK_TYPE)) { + if (m_odTrackId == MP4_INVALID_TRACK_ID) { + m_odTrackId = pTrackIdProperty->GetValue(); + } else { + log.warningf("%s: \"%s\": multiple OD tracks present", + __FUNCTION__, GetFilename().c_str() ); + } + } + } else { + m_trakIds.Add(0); + } + + trackIndex++; + } +} + +void MP4File::CacheProperties() +{ + FindIntegerProperty("moov.mvhd.modificationTime", + (MP4Property**)&m_pModificationProperty); + + FindIntegerProperty("moov.mvhd.timeScale", + (MP4Property**)&m_pTimeScaleProperty); + + FindIntegerProperty("moov.mvhd.duration", + (MP4Property**)&m_pDurationProperty); +} + +void MP4File::BeginWrite() +{ + m_pRootAtom->BeginWrite(); +} + +void MP4File::FinishWrite(uint32_t options) +{ + // remove empty moov.udta.meta.ilst + { + MP4Atom* ilst = FindAtom( "moov.udta.meta.ilst" ); + if( ilst ) { + if( ilst->GetNumberOfChildAtoms() == 0 ) { + ilst->GetParentAtom()->DeleteChildAtom( ilst ); + delete ilst; + } + } + } + + // remove empty moov.udta.meta + { + MP4Atom* meta = FindAtom( "moov.udta.meta" ); + if( meta ) { + if( meta->GetNumberOfChildAtoms() == 0 ) { + meta->GetParentAtom()->DeleteChildAtom( meta ); + delete meta; + } + else if( meta->GetNumberOfChildAtoms() == 1 ) { + if( ATOMID( meta->GetChildAtom( 0 )->GetType() ) == ATOMID( "hdlr" )) { + meta->GetParentAtom()->DeleteChildAtom( meta ); + delete meta; + } + } + } + } + + // remove empty moov.udta.name + { + MP4Atom* name = FindAtom( "moov.udta.name" ); + if( name ) { + unsigned char *val = NULL; + uint32_t valSize = 0; + GetBytesProperty("moov.udta.name.value", (uint8_t**)&val, &valSize); + if( valSize == 0 ) { + name->GetParentAtom()->DeleteChildAtom( name ); + delete name; + } + } + } + + // remove empty moov.udta + { + MP4Atom* udta = FindAtom( "moov.udta" ); + if( udta ) { + if( udta->GetNumberOfChildAtoms() == 0 ) { + udta->GetParentAtom()->DeleteChildAtom( udta ); + delete udta; + } + } + } + + // for all tracks, flush chunking buffers + for( uint32_t i = 0; i < m_pTracks.Size(); i++ ) { + ASSERT( m_pTracks[i] ); + m_pTracks[i]->FinishWrite(options); + } + + // ask root atom to write + m_pRootAtom->FinishWrite(); + + // finished all writes, if position < size then file has shrunk and + // we mark remaining bytes as free atom; otherwise trailing garbage remains. + if( GetPosition() < GetSize() ) { + MP4RootAtom* root = (MP4RootAtom*)FindAtom( "" ); + ASSERT( root ); + + // compute size of free atom; always has 8 bytes of overhead + uint64_t size = GetSize() - GetPosition(); + if( size < 8 ) + size = 0; + else + size -= 8; + + MP4FreeAtom* freeAtom = (MP4FreeAtom*)MP4Atom::CreateAtom( *this, NULL, "free" ); + ASSERT( freeAtom ); + freeAtom->SetSize( size ); + root->AddChildAtom( freeAtom ); + freeAtom->Write(); + } +} + +void MP4File::UpdateDuration(MP4Duration duration) +{ + MP4Duration currentDuration = GetDuration(); + if (duration > currentDuration) { + SetDuration(duration); + } +} + +void MP4File::Dump( bool dumpImplicits ) +{ + log.dump(0, MP4_LOG_VERBOSE1, "\"%s\": Dumping meta-information...", m_file->name.c_str() ); + m_pRootAtom->Dump( 0, dumpImplicits); +} + +void MP4File::Close(uint32_t options) +{ + if( IsWriteMode() ) { + SetIntegerProperty( "moov.mvhd.modificationTime", MP4GetAbsTimestamp() ); + FinishWrite(options); + } + + delete m_file; + m_file = NULL; +} + +void MP4File::Rename(const char* oldFileName, const char* newFileName) +{ + if( FileSystem::rename( oldFileName, newFileName )) + throw new PlatformException( sys::getLastErrorStr(), sys::getLastError(), __FILE__, __LINE__, __FUNCTION__ ); +} + +void MP4File::ProtectWriteOperation(const char* file, + int line, + const char* func ) +{ + if( !IsWriteMode() ) + throw new Exception( "operation not permitted in read mode", file, line, func ); +} + +MP4Track* MP4File::GetTrack(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]; +} + +MP4Atom* MP4File::FindAtom(const char* name) +{ + MP4Atom* pAtom = NULL; + if (!name || !strcmp(name, "")) { + pAtom = m_pRootAtom; + } else { + pAtom = m_pRootAtom->FindAtom(name); + } + return pAtom; +} + +MP4Atom* MP4File::AddChildAtom( + const char* parentName, + const char* childName) +{ + return AddChildAtom(FindAtom(parentName), childName); +} + +MP4Atom* MP4File::AddChildAtom( + MP4Atom* pParentAtom, + const char* childName) +{ + return InsertChildAtom(pParentAtom, childName, + pParentAtom->GetNumberOfChildAtoms()); +} + +MP4Atom* MP4File::InsertChildAtom( + const char* parentName, + const char* childName, + uint32_t index) +{ + return InsertChildAtom(FindAtom(parentName), childName, index); +} + +MP4Atom* MP4File::InsertChildAtom( + MP4Atom* pParentAtom, + const char* childName, + uint32_t index) +{ + MP4Atom* pChildAtom = MP4Atom::CreateAtom(*this, pParentAtom, childName); + + ASSERT(pParentAtom); + pParentAtom->InsertChildAtom(pChildAtom, index); + + pChildAtom->Generate(); + + return pChildAtom; +} + +MP4Atom* MP4File::AddDescendantAtoms( + const char* ancestorName, + const char* descendantNames) +{ + return AddDescendantAtoms(FindAtom(ancestorName), descendantNames); +} + +MP4Atom* MP4File::AddDescendantAtoms( + MP4Atom* pAncestorAtom, const char* descendantNames) +{ + ASSERT(pAncestorAtom); + + MP4Atom* pParentAtom = pAncestorAtom; + MP4Atom* pChildAtom = NULL; + + while (true) { + char* childName = MP4NameFirst(descendantNames); + + if (childName == NULL) { + break; + } + + descendantNames = MP4NameAfterFirst(descendantNames); + + pChildAtom = pParentAtom->FindChildAtom(childName); + + if (pChildAtom == NULL) { + pChildAtom = AddChildAtom(pParentAtom, childName); + } + + pParentAtom = pChildAtom; + + MP4Free(childName); + } + + return pChildAtom; +} + +bool MP4File::FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if( pIndex ) + *pIndex = 0; // set the default answer for index + return m_pRootAtom->FindProperty(name, ppProperty, pIndex); +} + +void MP4File::FindIntegerProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + ostringstream msg; + msg << "no such property - " << name; + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } + + switch ((*ppProperty)->GetType()) { + case Integer8Property: + case Integer16Property: + case Integer24Property: + case Integer32Property: + case Integer64Property: + break; + default: + ostringstream msg; + msg << "type mismatch - property " << name << " type " << (*ppProperty)->GetType(); + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } +} + +uint64_t MP4File::GetIntegerProperty(const char* name) +{ + MP4Property* pProperty; + uint32_t index; + + FindIntegerProperty(name, &pProperty, &index); + + return ((MP4IntegerProperty*)pProperty)->GetValue(index); +} + +void MP4File::SetIntegerProperty(const char* name, uint64_t value) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Property* pProperty = NULL; + uint32_t index = 0; + + FindIntegerProperty(name, &pProperty, &index); + + ((MP4IntegerProperty*)pProperty)->SetValue(value, index); +} + +void MP4File::FindFloatProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + ostringstream msg; + msg << "no such property - " << name; + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } + if ((*ppProperty)->GetType() != Float32Property) { + ostringstream msg; + msg << "type mismatch - property " << name << " type " << (*ppProperty)->GetType(); + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } +} + +float MP4File::GetFloatProperty(const char* name) +{ + MP4Property* pProperty; + uint32_t index; + + FindFloatProperty(name, &pProperty, &index); + + return ((MP4Float32Property*)pProperty)->GetValue(index); +} + +void MP4File::SetFloatProperty(const char* name, float value) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Property* pProperty; + uint32_t index; + + FindFloatProperty(name, &pProperty, &index); + + ((MP4Float32Property*)pProperty)->SetValue(value, index); +} + +void MP4File::FindStringProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + ostringstream msg; + msg << "no such property - " << name; + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } + if ((*ppProperty)->GetType() != StringProperty) { + ostringstream msg; + msg << "type mismatch - property " << name << " type " << (*ppProperty)->GetType(); + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } +} + +const char* MP4File::GetStringProperty(const char* name) +{ + MP4Property* pProperty; + uint32_t index; + + FindStringProperty(name, &pProperty, &index); + + return ((MP4StringProperty*)pProperty)->GetValue(index); +} + +void MP4File::SetStringProperty(const char* name, const char* value) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Property* pProperty; + uint32_t index; + + FindStringProperty(name, &pProperty, &index); + + ((MP4StringProperty*)pProperty)->SetValue(value, index); +} + +void MP4File::FindBytesProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex) +{ + if (!FindProperty(name, ppProperty, pIndex)) { + ostringstream msg; + msg << "no such property " << name; + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } + if ((*ppProperty)->GetType() != BytesProperty) { + ostringstream msg; + msg << "type mismatch - property " << name << " - type " << (*ppProperty)->GetType(); + throw new Exception(msg.str(), __FILE__, __LINE__, __FUNCTION__); + } +} + +void MP4File::GetBytesProperty(const char* name, + uint8_t** ppValue, uint32_t* pValueSize) +{ + MP4Property* pProperty; + uint32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index); +} + +void MP4File::SetBytesProperty(const char* name, + const uint8_t* pValue, uint32_t valueSize) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Property* pProperty; + uint32_t index; + + FindBytesProperty(name, &pProperty, &index); + + ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index); +} + + +// track functions + +MP4TrackId MP4File::AddTrack(const char* type, uint32_t timeScale) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + // create and add new trak atom + MP4Atom* pTrakAtom = AddChildAtom("moov", "trak"); + ASSERT(pTrakAtom); + + // allocate a new track id + MP4TrackId trackId = AllocTrackId(); + + m_trakIds.Add(trackId); + + // set track id + MP4Integer32Property* pInteger32Property = NULL; + (void)pTrakAtom->FindProperty("trak.tkhd.trackId", + (MP4Property**)&pInteger32Property); + ASSERT(pInteger32Property); + pInteger32Property->SetValue(trackId); + + // set track type + const char* normType = MP4NormalizeTrackType(type); + + // sanity check for user defined types + if (strlen(normType) > 4) { + log.warningf("%s: \"%s\": type truncated to four characters", + __FUNCTION__, GetFilename().c_str()); + // StringProperty::SetValue() will do the actual truncation + } + + MP4StringProperty* pStringProperty = NULL; + (void)pTrakAtom->FindProperty("trak.mdia.hdlr.handlerType", + (MP4Property**)&pStringProperty); + ASSERT(pStringProperty); + pStringProperty->SetValue(normType); + + // set track time scale + pInteger32Property = NULL; + (void)pTrakAtom->FindProperty("trak.mdia.mdhd.timeScale", + (MP4Property**)&pInteger32Property); + ASSERT(pInteger32Property); + pInteger32Property->SetValue(timeScale ? timeScale : 1000); + + // now have enough to create MP4Track object + MP4Track* pTrack = NULL; + if (!strcmp(normType, MP4_HINT_TRACK_TYPE)) { + pTrack = new MP4RtpHintTrack(*this, *pTrakAtom); + } else { + pTrack = new MP4Track(*this, *pTrakAtom); + } + m_pTracks.Add(pTrack); + + // mark non-hint tracks as enabled + if (strcmp(normType, MP4_HINT_TRACK_TYPE)) { + SetTrackIntegerProperty(trackId, "tkhd.flags", 1); + } + + // mark track as contained in this file + // LATER will provide option for external data references + AddDataReference(trackId, NULL); + + return trackId; +} + +void MP4File::AddTrackToIod(MP4TrackId trackId) +{ + MP4DescriptorProperty* pDescriptorProperty = NULL; + (void)m_pRootAtom->FindProperty("moov.iods.esIds", + (MP4Property**)&pDescriptorProperty); + ASSERT(pDescriptorProperty); + + MP4Descriptor* pDescriptor = + pDescriptorProperty->AddDescriptor(MP4ESIDIncDescrTag); + ASSERT(pDescriptor); + + MP4Integer32Property* pIdProperty = NULL; + (void)pDescriptor->FindProperty("id", + (MP4Property**)&pIdProperty); + ASSERT(pIdProperty); + + pIdProperty->SetValue(trackId); +} + +void MP4File::RemoveTrackFromIod(MP4TrackId trackId, bool shallHaveIods) +{ + MP4DescriptorProperty* pDescriptorProperty = NULL; + if (!m_pRootAtom->FindProperty("moov.iods.esIds",(MP4Property**)&pDescriptorProperty) + || pDescriptorProperty == NULL) + return; + + for (uint32_t i = 0; i < pDescriptorProperty->GetCount(); i++) { + /* static */ + char name[32]; + snprintf(name, sizeof(name), "esIds[%u].id", i); + + MP4Integer32Property* pIdProperty = NULL; + (void)pDescriptorProperty->FindProperty(name, + (MP4Property**)&pIdProperty); + // wmay ASSERT(pIdProperty); + + if (pIdProperty != NULL && + pIdProperty->GetValue() == trackId) { + pDescriptorProperty->DeleteDescriptor(i); + break; + } + } +} + +void MP4File::AddTrackToOd(MP4TrackId trackId) +{ + if (!m_odTrackId) { + return; + } + + AddTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId); +} + +void MP4File::RemoveTrackFromOd(MP4TrackId trackId) +{ + if (!m_odTrackId) { + return; + } + + RemoveTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId); +} + +/* + * Try to obtain the properties of this reference track, if not found then return + * NULL in *ppCountProperty and *ppTrackIdProperty. + */ +void MP4File::GetTrackReferenceProperties(const char* trefName, + MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty) +{ + char propName[1024]; + + snprintf(propName, sizeof(propName), "%s.%s", trefName, "entryCount"); + (void)m_pRootAtom->FindProperty(propName, ppCountProperty); + + snprintf(propName, sizeof(propName), "%s.%s", trefName, "entries.trackId"); + (void)m_pRootAtom->FindProperty(propName, ppTrackIdProperty); +} + +void MP4File::AddTrackReference(const char* trefName, MP4TrackId refTrackId) +{ + MP4Integer32Property* pCountProperty = NULL; + MP4Integer32Property* pTrackIdProperty = NULL; + + GetTrackReferenceProperties(trefName, + (MP4Property**)&pCountProperty, + (MP4Property**)&pTrackIdProperty); + + if (pCountProperty && pTrackIdProperty) { + pTrackIdProperty->AddValue(refTrackId); + pCountProperty->IncrementValue(); + } +} + +uint32_t MP4File::FindTrackReference(const char* trefName, + MP4TrackId refTrackId) +{ + MP4Integer32Property* pCountProperty = NULL; + MP4Integer32Property* pTrackIdProperty = NULL; + + GetTrackReferenceProperties(trefName, + (MP4Property**)&pCountProperty, + (MP4Property**)&pTrackIdProperty); + + if (pCountProperty && pTrackIdProperty) { + for (uint32_t i = 0; i < pCountProperty->GetValue(); i++) { + if (refTrackId == pTrackIdProperty->GetValue(i)) { + return i + 1; // N.B. 1 not 0 based index + } + } + } + return 0; +} + +void MP4File::RemoveTrackReference(const char* trefName, MP4TrackId refTrackId) +{ + MP4Integer32Property* pCountProperty = NULL; + MP4Integer32Property* pTrackIdProperty = NULL; + + GetTrackReferenceProperties(trefName, + (MP4Property**)&pCountProperty, + (MP4Property**)&pTrackIdProperty); + + if (pCountProperty && pTrackIdProperty) { + for (uint32_t i = 0; i < pCountProperty->GetValue(); i++) { + if (refTrackId == pTrackIdProperty->GetValue(i)) { + pTrackIdProperty->DeleteValue(i); + pCountProperty->IncrementValue(-1); + } + } + } +} + +void MP4File::AddDataReference(MP4TrackId trackId, const char* url) +{ + MP4Atom* pDrefAtom = + FindAtom(MakeTrackName(trackId, "mdia.minf.dinf.dref")); + ASSERT(pDrefAtom); + + MP4Integer32Property* pCountProperty = NULL; + (void)pDrefAtom->FindProperty("dref.entryCount", + (MP4Property**)&pCountProperty); + ASSERT(pCountProperty); + pCountProperty->IncrementValue(); + + MP4Atom* pUrlAtom = AddChildAtom(pDrefAtom, "url "); + + if (url && url[0] != '\0') { + pUrlAtom->SetFlags(pUrlAtom->GetFlags() & 0xFFFFFE); + + MP4StringProperty* pUrlProperty = NULL; + (void)pUrlAtom->FindProperty("url .location", + (MP4Property**)&pUrlProperty); + ASSERT(pUrlProperty); + pUrlProperty->SetValue(url); + } else { + pUrlAtom->SetFlags(pUrlAtom->GetFlags() | 1); + } +} + +MP4TrackId MP4File::AddSystemsTrack(const char* type, uint32_t timeScale) +{ + const char* normType = MP4NormalizeTrackType(type); + + // TBD if user type, fix name to four chars, and warn + + MP4TrackId trackId = AddTrack(type, timeScale); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s"); + + AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.name"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4s atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.ESID", + 0 + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", + MP4SystemsV1ObjectType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType", + ConvertTrackTypeToStreamType(normType)); + + return trackId; +} + +MP4TrackId MP4File::AddODTrack() +{ + // until a demonstrated need emerges + // we limit ourselves to one object description track + if (m_odTrackId != MP4_INVALID_TRACK_ID) { + throw new Exception("object description track already exists",__FILE__, __LINE__, __FUNCTION__); + } + + m_odTrackId = AddSystemsTrack(MP4_OD_TRACK_TYPE); + + AddTrackToIod(m_odTrackId); + + (void)AddDescendantAtoms(MakeTrackName(m_odTrackId, NULL), "tref.mpod"); + + return m_odTrackId; +} + +MP4TrackId MP4File::AddSceneTrack() +{ + MP4TrackId trackId = AddSystemsTrack(MP4_SCENE_TRACK_TYPE); + + AddTrackToIod(trackId); + AddTrackToOd(trackId); + + return trackId; +} + +bool MP4File::ShallHaveIods() +{ + // NULL terminated list of brands which require the IODS atom + const char* brandsWithIods[] = { + "mp42", + "isom", + NULL + }; + + MP4FtypAtom* ftyp = (MP4FtypAtom*)m_pRootAtom->FindAtom( "ftyp" ); + if( !ftyp ) + return false; + + // check major brand + const char* brand = ftyp->majorBrand.GetValue(); + for( uint32_t i = 0; brandsWithIods[i] != NULL; i++ ) { + if( !strcasecmp( brandsWithIods[i], brand )) + return true; + } + + // check compatible brands + uint32_t max = ftyp->compatibleBrands.GetCount(); + for( uint32_t i = 0; i < max; i++ ) { + brand = ftyp->compatibleBrands.GetValue( i ); + for( uint32_t j = 0; brandsWithIods[j] != NULL ; j++) { + if( !strcasecmp( brandsWithIods[j], brand )) + return true; + } + } + + return false; +} + +void MP4File::SetAmrVendor( + MP4TrackId trackId, + uint32_t vendor) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.vendor", + vendor); +} + +void MP4File::SetAmrDecoderVersion( + MP4TrackId trackId, + uint8_t decoderVersion) +{ + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.decoderVersion", + decoderVersion); +} + +void MP4File::SetAmrModeSet( + MP4TrackId trackId, + uint16_t modeSet) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeSet", + modeSet); +} +uint16_t MP4File::GetAmrModeSet(MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeSet"); +} + +MP4TrackId MP4File::AddAmrAudioTrack( + uint32_t timeScale, + uint16_t modeSet, + uint8_t modeChangePeriod, + uint8_t framesPerSample, + bool isAmrWB) +{ + + uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample + + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), isAmrWB ? "sawb" : "samr"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.timeScale", + timeScale); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeSet", + modeSet); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.modeChangePeriod", + modeChangePeriod); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.damr.framesPerSample", + framesPerSample); + + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(fixedSampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddULawAudioTrack( uint32_t timeScale) +{ + uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample + + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "ulaw"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.ulaw.timeScale", + timeScale<<16); + + m_pTracks[FindTrackIndex(trackId)]->SetFixedSampleDuration(fixedSampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddALawAudioTrack( uint32_t timeScale) +{ + uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample + + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "alaw"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.alaw.timeScale", + timeScale<<16); + + m_pTracks[FindTrackIndex(trackId)]->SetFixedSampleDuration(fixedSampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddAudioTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint8_t audioType) +{ + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4a"); + + AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.name"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.timeScale", timeScale << 16); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.esds.ESID", + 0 + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId", + audioType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.streamType", + MP4AudioStreamType); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddAC3AudioTrack( + uint32_t samplingRate, + uint8_t fscod, + uint8_t bsid, + uint8_t bsmod, + uint8_t acmod, + uint8_t lfeon, + uint8_t bit_rate_code) +{ + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, samplingRate); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "ac-3"); + + // Set Ac3 settings + MP4Integer16Property* pSampleRateProperty = NULL; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.samplingRate"), + (MP4Property**)&pSampleRateProperty); + if (pSampleRateProperty) { + pSampleRateProperty->SetValue(samplingRate); + } else { + throw new Exception("no ac-3.samplingRate property", __FILE__, __LINE__, __FUNCTION__); + } + + MP4BitfieldProperty* pBitfieldProperty = NULL; + + FindProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.dac3.fscod"), + (MP4Property**)&pBitfieldProperty); + if (pBitfieldProperty) { + pBitfieldProperty->SetValue(fscod); + pBitfieldProperty = NULL; + } else { + throw new Exception("no dac3.fscod property", __FILE__, __LINE__, __FUNCTION__); + } + + FindProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.dac3.bsid"), + (MP4Property**)&pBitfieldProperty); + if (pBitfieldProperty) { + pBitfieldProperty->SetValue(bsid); + pBitfieldProperty = NULL; + } else { + throw new Exception("no dac3.bsid property", __FILE__, __LINE__, __FUNCTION__); + } + + FindProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.dac3.bsmod"), + (MP4Property**)&pBitfieldProperty); + if (pBitfieldProperty) { + pBitfieldProperty->SetValue(bsmod); + pBitfieldProperty = NULL; + } else { + throw new Exception("no dac3.bsmod property", __FILE__, __LINE__, __FUNCTION__); + } + + FindProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.dac3.acmod"), + (MP4Property**)&pBitfieldProperty); + if (pBitfieldProperty) { + pBitfieldProperty->SetValue(acmod); + pBitfieldProperty = NULL; + } else { + throw new Exception("no dac3.acmod property", __FILE__, __LINE__, __FUNCTION__); + } + + FindProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.dac3.lfeon"), + (MP4Property**)&pBitfieldProperty); + if (pBitfieldProperty) { + pBitfieldProperty->SetValue(lfeon); + pBitfieldProperty = NULL; + } else { + throw new Exception("no dac3.lfeon property", __FILE__, __LINE__, __FUNCTION__); + } + + FindProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.ac-3.dac3.bit_rate_code"), + (MP4Property**)&pBitfieldProperty); + if (pBitfieldProperty) { + pBitfieldProperty->SetValue(bit_rate_code); + pBitfieldProperty = NULL; + } else { + throw new Exception("no dac3.bit_rate_code property", __FILE__, __LINE__, __FUNCTION__); + } + + AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.name"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4a atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(1536); + + return trackId; +} + +MP4TrackId MP4File::AddEncAudioTrack(uint32_t timeScale, + MP4Duration sampleDuration, + uint8_t audioType, + uint32_t scheme_type, + uint16_t scheme_version, + uint8_t key_ind_len, + uint8_t iv_len, + bool selective_enc, + const char *kms_uri, + bool use_ismacryp + ) +{ + uint32_t original_fmt = 0; + + MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.volume", 1.0); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "enca"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the enca atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + + /* set all the ismacryp-specific values */ + // original format is mp4a + if (use_ismacryp) { + original_fmt = ATOMID("mp4a"); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.frma.data-format", + original_fmt); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf"), + "schm"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf"), + "schi"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf.schi"), + "iKMS"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf.schi"), + "iSFM"); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schm.scheme_type", + scheme_type); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schm.scheme_version", + scheme_version); + + SetTrackStringProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iKMS.kms_URI", + kms_uri); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.selective-encryption", + selective_enc); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.key-indicator-length", + key_ind_len); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.IV-length", + iv_len); + /* end ismacryp */ + } + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.timeScale", timeScale); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.esds.ESID", + 0 + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.esds.decConfigDescr.objectTypeId", + audioType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.enca.esds.decConfigDescr.streamType", + MP4AudioStreamType); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddCntlTrackDefault (uint32_t timeScale, + MP4Duration sampleDuration, + const char *type) +{ + MP4TrackId trackId = AddTrack(MP4_CNTL_TRACK_TYPE, timeScale); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), type); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4v atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsz.sampleSize", sampleDuration); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} + +MP4TrackId MP4File::AddHrefTrack (uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url) +{ + MP4TrackId trackId = AddCntlTrackDefault(timeScale, sampleDuration, "href"); + + if (base_url != NULL) { + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.href"), + "burl"); + SetTrackStringProperty(trackId, "mdia.minf.stbl.stsd.href.burl.base_url", + base_url); + } + + return trackId; +} + +MP4TrackId MP4File::AddVideoTrackDefault( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + const char *videoType) +{ + MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale); + + AddTrackToOd(trackId); + + SetTrackFloatProperty(trackId, "tkhd.width", width); + SetTrackFloatProperty(trackId, "tkhd.height", height); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), videoType); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4v atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsz.sampleSize", sampleDuration); + + m_pTracks[FindTrackIndex(trackId)]-> + SetFixedSampleDuration(sampleDuration); + + return trackId; +} +MP4TrackId MP4File::AddMP4VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t videoType) +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "mp4v"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.height", height); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.esds.ESID", + 0 + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId", + videoType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.streamType", + MP4VisualStreamType); + + return trackId; +} + +// ismacrypted +MP4TrackId MP4File::AddEncVideoTrack(uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t videoType, + mp4v2_ismacrypParams *icPp, + const char *oFormat + ) +{ + uint32_t original_fmt = 0; + + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "encv"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.height", height); + + /* set all the ismacryp-specific values */ + + original_fmt = ATOMID(oFormat); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.frma.data-format", + original_fmt); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), + "schm"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), + "schi"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), + "iKMS"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), + "iSFM"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_type", + icPp->scheme_type); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_version", + icPp->scheme_version); + + SetTrackStringProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iKMS.kms_URI", + icPp->kms_uri); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.selective-encryption", + icPp->selective_enc); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.key-indicator-length", + icPp->key_ind_len); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.IV-length", + icPp->iv_len); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.esds.ESID", + 0 + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.objectTypeId", + videoType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.streamType", + MP4VisualStreamType); + + return trackId; +} + +MP4TrackId MP4File::AddH264VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne) +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "avc1"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.height", height); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.AVCProfileIndication", + AVCProfileIndication); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.profile_compatibility", + profile_compat); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.AVCLevelIndication", + AVCLevelIndication); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.avc1.avcC.lengthSizeMinusOne", + sampleLenFieldSizeMinusOne); + + return trackId; +} + +MP4TrackId MP4File::AddEncH264VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + MP4Atom *srcAtom, + mp4v2_ismacrypParams *icPp) + +{ + + uint32_t original_fmt = 0; + MP4Atom *avcCAtom; + + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "encv"); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.width", width); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.height", height); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv"), "avcC"); + + // create default values + avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC")); + + // export source atom + ((MP4AvcCAtom *) srcAtom)->Clone((MP4AvcCAtom *)avcCAtom); + + /* set all the ismacryp-specific values */ + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), "schm"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), "schi"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), "iKMS"); + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), "iSFM"); + + // per ismacrypt E&A V1.1 section 9.1.2.1 'avc1' is renamed '264b' + // avc1 must not appear as a sample entry name or original format name + original_fmt = ATOMID("264b"); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.frma.data-format", + original_fmt); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_type", + icPp->scheme_type); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_version", + icPp->scheme_version); + + SetTrackStringProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iKMS.kms_URI", + icPp->kms_uri); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.selective-encryption", + icPp->selective_enc); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.key-indicator-length", + icPp->key_ind_len); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.IV-length", + icPp->iv_len); + + + return trackId; +} + + +void MP4File::AddH264SequenceParameterSet (MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen) +{ + const char *format; + MP4Atom *avcCAtom; + + // get 4cc media format - can be avc1 or encv for ismacrypted track + format = GetTrackMediaDataName(trackId); + + if (!strcasecmp(format, "avc1")) + avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC")); + else if (!strcasecmp(format, "encv")) + avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC")); + else + // huh? unknown track format + return; + + + MP4BitfieldProperty *pCount; + MP4Integer16Property *pLength; + MP4BytesProperty *pUnit; + if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets", + (MP4Property **)&pCount) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength", + (MP4Property **)&pLength) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit", + (MP4Property **)&pUnit) == false)) { + log.errorf("%s: \"%s\": Could not find avcC properties", + __FUNCTION__, GetFilename().c_str() ); + return; + } + uint32_t count = pCount->GetValue(); + + if (count > 0) { + // see if we already exist + for (uint32_t index = 0; index < count; index++) { + if (pLength->GetValue(index) == sequenceLen) { + uint8_t *seq; + uint32_t seqlen; + pUnit->GetValue(&seq, &seqlen, index); + if (memcmp(seq, pSequence, sequenceLen) == 0) { + free(seq); + return; + } + free(seq); + } + } + } + pLength->AddValue(sequenceLen); + pUnit->AddValue(pSequence, sequenceLen); + pCount->IncrementValue(); + + return; +} +void MP4File::AddH264PictureParameterSet (MP4TrackId trackId, + const uint8_t *pPict, + uint16_t pictLen) +{ + MP4Atom *avcCAtom = + FindAtom(MakeTrackName(trackId, + "mdia.minf.stbl.stsd.avc1.avcC")); + MP4Integer8Property *pCount; + MP4Integer16Property *pLength; + MP4BytesProperty *pUnit; + if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets", + (MP4Property **)&pCount) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength", + (MP4Property **)&pLength) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit", + (MP4Property **)&pUnit) == false)) { + log.errorf("%s: \"%s\": Could not find avcC picture table properties", + __FUNCTION__, GetFilename().c_str()); + return; + } + + ASSERT(pCount); + uint32_t count = pCount->GetValue(); + + if (count > 0) { + // see if we already exist + for (uint32_t index = 0; index < count; index++) { + if (pLength->GetValue(index) == pictLen) { + uint8_t *seq; + uint32_t seqlen; + pUnit->GetValue(&seq, &seqlen, index); + if (memcmp(seq, pPict, pictLen) == 0) { + log.verbose1f("\"%s\": picture matches %d", + GetFilename().c_str(), index); + free(seq); + return; + } + free(seq); + } + } + } + pLength->AddValue(pictLen); + pUnit->AddValue(pPict, pictLen); + pCount->IncrementValue(); + log.verbose1f("\"%s\": new picture added %d", GetFilename().c_str(), + pCount->GetValue()); + + return; +} +void MP4File::SetH263Vendor( + MP4TrackId trackId, + uint32_t vendor) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.vendor", + vendor); +} + +void MP4File::SetH263DecoderVersion( + MP4TrackId trackId, + uint8_t decoderVersion) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.decoderVersion", + decoderVersion); +} + +void MP4File::SetH263Bitrates( + MP4TrackId trackId, + uint32_t avgBitrate, + uint32_t maxBitrate) +{ + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.avgBitrate", + avgBitrate); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.maxBitrate", + maxBitrate); + +} + +MP4TrackId MP4File::AddH263VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t h263Level, + uint8_t h263Profile, + uint32_t avgBitrate, + uint32_t maxBitrate) + +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "s263"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.height", height); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.h263Level", h263Level); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.h263Profile", h263Profile); + + // Add the bitr atom + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.s263.d263"), + "bitr"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.avgBitrate", avgBitrate); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.s263.d263.bitr.maxBitrate", maxBitrate); + + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsz.sampleSize", sampleDuration); + + return trackId; + +} + +MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId) +{ + // validate reference track id + (void)FindTrackIndex(refTrackId); + + MP4TrackId trackId = + AddTrack(MP4_HINT_TRACK_TYPE, GetTrackTimeScale(refTrackId)); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "hmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "rtp "); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the rtp atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.rtp .tims.timeScale", + GetTrackTimeScale(trackId)); + + (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "tref.hint"); + + AddTrackReference(MakeTrackName(trackId, "tref.hint"), refTrackId); + + (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hnti.sdp "); + + (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hinf"); + + return trackId; +} + +MP4TrackId MP4File::AddTextTrack(MP4TrackId refTrackId) +{ + // validate reference track id + (void)FindTrackIndex(refTrackId); + + MP4TrackId trackId = + AddTrack(MP4_TEXT_TRACK_TYPE, GetTrackTimeScale(refTrackId)); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "text"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the text atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + return trackId; +} + +MP4TrackId MP4File::AddSubtitleTrack(uint32_t timescale, + uint16_t width, + uint16_t height) +{ + MP4TrackId trackId = + AddTrack(MP4_SUBTITLE_TRACK_TYPE, timescale); + + InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0); + + AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "tx3g"); + + SetTrackFloatProperty(trackId, "tkhd.width", width); + SetTrackFloatProperty(trackId, "tkhd.height", height); + + // Hardcoded crap... add the ftab atom and add one font entry + MP4Atom* pFtabAtom = AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.tx3g"), "ftab"); + + ((MP4Integer16Property*)pFtabAtom->GetProperty(0))->IncrementValue(); + + MP4Integer16Property* pfontID = (MP4Integer16Property*)((MP4TableProperty*)pFtabAtom->GetProperty(1))->GetProperty(0); + pfontID->AddValue(1); + + MP4StringProperty* pName = (MP4StringProperty*)((MP4TableProperty*)pFtabAtom->GetProperty(1))->GetProperty(1); + pName->AddValue("Arial"); + + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.tx3g.fontID", 1); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the tx3g atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + return trackId; +} + +MP4TrackId MP4File::AddSubpicTrack(uint32_t timescale, + uint16_t width, + uint16_t height) +{ + MP4TrackId trackId = + AddTrack(MP4_SUBPIC_TRACK_TYPE, timescale); + + InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s"); + + SetTrackFloatProperty(trackId, "tkhd.width", width); + SetTrackFloatProperty(trackId, "tkhd.height", height); + SetTrackIntegerProperty(trackId, "tkhd.layer", 0); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the mp4s atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.ESID", + 0 + ); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", + MP4SubpicObjectType); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType", + MP4NeroSubpicStreamType); + return trackId; +} + +MP4TrackId MP4File::AddChapterTextTrack(MP4TrackId refTrackId, uint32_t timescale) +{ + // validate reference track id + (void)FindTrackIndex(refTrackId); + + if (0 == timescale) + { + timescale = GetTrackTimeScale(refTrackId); + } + + MP4TrackId trackId = AddTrack(MP4_TEXT_TRACK_TYPE, timescale); + + (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0); + + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "text"); + + // stsd is a unique beast in that it has a count of the number + // of child atoms that needs to be incremented after we add the text atom + MP4Integer32Property* pStsdCountProperty; + FindIntegerProperty( + MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"), + (MP4Property**)&pStsdCountProperty); + pStsdCountProperty->IncrementValue(); + + // add a "text" atom to the generic media header + // this is different to the stsd "text" atom added above + // truth be told, it's not clear what this second "text" atom does, + // but all iTunes Store movies (with chapter markers) have it, + // as do all movies with chapter tracks made by hand in QuickTime Pro + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.gmhd"), "text"); + + // disable the chapter text track + // it won't display anyway, as it has zero display size, + // but nonetheless it's good to disable it + // the track still operates as a chapter track when disabled + MP4Atom *pTkhdAtom = FindAtom(MakeTrackName(trackId, "tkhd")); + if (pTkhdAtom) { + pTkhdAtom->SetFlags(0xE); + } + + // add a "chapter" track reference to our reference track, + // pointing to this new chapter track + (void)AddDescendantAtoms(MakeTrackName(refTrackId, NULL), "tref.chap"); + AddTrackReference(MakeTrackName(refTrackId, "tref.chap"), trackId); + + return trackId; +} + +MP4TrackId MP4File::AddPixelAspectRatio(MP4TrackId trackId, uint32_t hSpacing, uint32_t vSpacing) +{ + // validate reference track id + (void)FindTrackIndex(trackId); + const char *format = GetTrackMediaDataName (trackId); + + if (!strcasecmp(format, "avc1")) + { + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1"), "pasp"); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.avc1.pasp.hSpacing", hSpacing); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.avc1.pasp.vSpacing", vSpacing); + } + else if (!strcasecmp(format, "mp4v")) + { + (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.mp4v"), "pasp"); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.mp4v.pasp.hSpacing", hSpacing); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.mp4v.pasp.vSpacing", vSpacing); + } + + return trackId; +} + +MP4TrackId MP4File::AddColr(MP4TrackId trackId, + uint16_t primariesIndex, + uint16_t transferFunctionIndex, + uint16_t matrixIndex) +{ + // validate reference track id + (void)FindTrackIndex(trackId); + const char *format = GetTrackMediaDataName (trackId); + + if (!strcasecmp(format, "avc1")) + { + AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1"), "colr"); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.avc1.colr.primariesIndex", primariesIndex); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.avc1.colr.transferFunctionIndex", transferFunctionIndex); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.avc1.colr.matrixIndex", matrixIndex); + } + else if (!strcasecmp(format, "mp4v")) + { + AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.mp4v"), "colr"); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.mp4v.colr.primariesIndex", primariesIndex); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.mp4v.colr.transferFunctionIndex", transferFunctionIndex); + SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.mp4v.colr.matrixIndex", matrixIndex); + } + + return trackId; +} + + +void MP4File::AddChapter(MP4TrackId chapterTrackId, MP4Duration chapterDuration, const char *chapterTitle) +{ + if (MP4_INVALID_TRACK_ID == chapterTrackId) + { + throw new Exception("No chapter track given",__FILE__, __LINE__, __FUNCTION__); + } + + uint32_t sampleLength = 0; + uint8_t sample[1040] = {0}; + int textLen = 0; + char *text = (char *)&(sample[2]); + + if(chapterTitle != NULL) + { + textLen = min((uint32_t)strlen(chapterTitle), (uint32_t)MP4V2_CHAPTER_TITLE_MAX); + if (0 < textLen) + { + strncpy(text, chapterTitle, textLen); + } + } + else + { + MP4Track * pChapterTrack = GetTrack(chapterTrackId); + snprintf( text, 1023, "Chapter %03d", pChapterTrack->GetNumberOfSamples() + 1 ); + textLen = (uint32_t)strlen(text); + } + + sampleLength = textLen + 2 + 12; // Account for text length code and other marker + + // 2-byte length marker + sample[0] = (textLen >> 8) & 0xff; + sample[1] = textLen & 0xff; + + int x = 2 + textLen; + + // Modifier Length Marker + sample[x] = 0x00; + sample[x+1] = 0x00; + sample[x+2] = 0x00; + sample[x+3] = 0x0C; + + // Modifier Type Code + sample[x+4] = 'e'; + sample[x+5] = 'n'; + sample[x+6] = 'c'; + sample[x+7] = 'd'; + + // Modifier Value + sample[x+8] = 0x00; + sample[x+9] = 0x00; + sample[x+10] = (256 >> 8) & 0xff; + sample[x+11] = 256 & 0xff; + + WriteSample(chapterTrackId, sample, sampleLength, chapterDuration); +} + +void MP4File::AddNeroChapter(MP4Timestamp chapterStart, const char * chapterTitle) +{ + MP4Atom * pChpl = FindAtom("moov.udta.chpl"); + if (!pChpl) + { + pChpl = AddDescendantAtoms("", "moov.udta.chpl"); + } + + MP4Integer32Property * pCount = (MP4Integer32Property*)pChpl->GetProperty(3); + pCount->IncrementValue(); + + char buffer[256]; + + if (0 == chapterTitle) + { + snprintf( buffer, 255, "Chapter %03d", pCount->GetValue() ); + } + else + { + int len = min((uint32_t)strlen(chapterTitle), (uint32_t)255); + strncpy( buffer, chapterTitle, len ); + buffer[len] = 0; + } + + MP4TableProperty * pTable; + if (pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) + { + MP4Integer64Property * pStartTime = (MP4Integer64Property *) pTable->GetProperty(0); + MP4StringProperty * pName = (MP4StringProperty *) pTable->GetProperty(1); + if (pStartTime && pTable) + { + pStartTime->AddValue(chapterStart); + pName->AddValue(buffer); + } + } +} + +MP4TrackId MP4File::FindChapterReferenceTrack(MP4TrackId chapterTrackId, char * trackName, int trackNameSize) +{ + for (uint32_t i = 0; i < m_pTracks.Size(); i++) + { + if( MP4_IS_VIDEO_TRACK_TYPE( m_pTracks[i]->GetType() ) || + MP4_IS_AUDIO_TRACK_TYPE( m_pTracks[i]->GetType() ) ) + { + MP4TrackId refTrackId = m_pTracks[i]->GetId(); + char *name = MakeTrackName(refTrackId, "tref.chap"); + if( FindTrackReference( name, chapterTrackId ) ) + { + if( 0 != trackName ) + { + int nameLen = min((uint32_t)strlen(name), (uint32_t)trackNameSize); + strncpy(trackName, name, nameLen); + trackName[nameLen] = 0; + } + + return m_pTracks[i]->GetId(); + } + } + } + + return MP4_INVALID_TRACK_ID; +} + +MP4TrackId MP4File::FindChapterTrack(char * trackName, int trackNameSize) +{ + for (uint32_t i = 0; i < m_pTracks.Size(); i++) + { + if( !strcasecmp(MP4_TEXT_TRACK_TYPE, m_pTracks[i]->GetType()) ) + { + MP4TrackId refTrackId = FindChapterReferenceTrack(m_pTracks[i]->GetId(), trackName, trackNameSize); + if (MP4_INVALID_TRACK_ID != refTrackId) + { + return m_pTracks[i]->GetId(); + } + } + } + + return MP4_INVALID_TRACK_ID; +} + +MP4ChapterType MP4File::DeleteChapters(MP4ChapterType chapterType, MP4TrackId chapterTrackId) +{ + MP4ChapterType deletedType = MP4ChapterTypeNone; + + if (MP4ChapterTypeAny == chapterType || MP4ChapterTypeNero == chapterType) + { + MP4Atom * pChpl = FindAtom("moov.udta.chpl"); + if (pChpl) + { + MP4Atom * pParent = pChpl->GetParentAtom(); + pParent->DeleteChildAtom(pChpl); + deletedType = MP4ChapterTypeNero; + } + } + + if (MP4ChapterTypeAny == chapterType || MP4ChapterTypeQt == chapterType) + { + char trackName[128] = {0}; + + // no text track given, find a suitable + if (MP4_INVALID_TRACK_ID == chapterTrackId) + { + chapterTrackId = FindChapterTrack(trackName, 127); + } + + if (MP4_INVALID_TRACK_ID != chapterTrackId) + { + FindChapterReferenceTrack(chapterTrackId, trackName, 127); + } + + if (MP4_INVALID_TRACK_ID != chapterTrackId && 0 != trackName[0]) + { + // remove the reference + MP4Atom * pChap = FindAtom( trackName ); + if( pChap ) + { + MP4Atom * pTref = pChap->GetParentAtom(); + if( pTref ) + { + pTref->DeleteChildAtom( pChap ); + + MP4Atom* pParent = pTref->GetParentAtom(); + pParent->DeleteChildAtom( pTref ); + } + } + + // remove the chapter track + DeleteTrack(chapterTrackId); + deletedType = MP4ChapterTypeNone == deletedType ? MP4ChapterTypeQt : MP4ChapterTypeAny; + } + } + return deletedType; +} + +MP4ChapterType MP4File::GetChapters(MP4Chapter_t ** chapterList, uint32_t * chapterCount, MP4ChapterType fromChapterType) +{ + *chapterList = 0; + *chapterCount = 0; + + if (MP4ChapterTypeAny == fromChapterType || MP4ChapterTypeQt == fromChapterType) + { + uint8_t * sample = 0; + uint32_t sampleSize = 0; + MP4Timestamp startTime = 0; + MP4Duration duration = 0; + + // get the chapter track + MP4TrackId chapterTrackId = FindChapterTrack(); + if (MP4_INVALID_TRACK_ID == chapterTrackId) + { + if (MP4ChapterTypeQt == fromChapterType) + { + return MP4ChapterTypeNone; + } + } + else + { + // get infos about the chapters + MP4Track * pChapterTrack = GetTrack(chapterTrackId); + uint32_t counter = pChapterTrack->GetNumberOfSamples(); + + if (0 < counter) + { + uint32_t timescale = pChapterTrack->GetTimeScale(); + MP4Chapter_t * chapters = (MP4Chapter_t*)MP4Malloc(sizeof(MP4Chapter_t) * counter); + + // process all chapter sample + for (uint32_t i = 0; i < counter; ++i) + { + // get the sample corresponding to the starttime + MP4SampleId sampleId = pChapterTrack->GetSampleIdFromTime(startTime + duration, true); + pChapterTrack->ReadSample(sampleId, &sample, &sampleSize); + + // get the starttime and duration + pChapterTrack->GetSampleTimes(sampleId, &startTime, &duration); + + // we know that sample+2 contains the title (sample[0] and sample[1] is the length) + const char * title = (const char *)&(sample[2]); + int titleLen = min((uint32_t)((sample[0] << 8) | sample[1]), (uint32_t)MP4V2_CHAPTER_TITLE_MAX); + strncpy(chapters[i].title, title, titleLen); + chapters[i].title[titleLen] = 0; + + // write the duration (in milliseconds) + chapters[i].duration = MP4ConvertTime(duration, timescale, MP4_MILLISECONDS_TIME_SCALE); + + // we're done with this sample + MP4Free(sample); + sample = 0; + } + + *chapterList = chapters; + *chapterCount = counter; + + // we got chapters so we are done + return MP4ChapterTypeQt; + } + } + } + + if (MP4ChapterTypeAny == fromChapterType || MP4ChapterTypeNero == fromChapterType) + { + MP4Atom * pChpl = FindAtom("moov.udta.chpl"); + if (!pChpl) + { + return MP4ChapterTypeNone; + } + + MP4Integer32Property * pCounter = 0; + if (!pChpl->FindProperty("chpl.chaptercount", (MP4Property **)&pCounter)) + { + log.warningf("%s: \"%s\": Nero chapter count does not exist", + __FUNCTION__, GetFilename().c_str()); + return MP4ChapterTypeNone; + } + + uint32_t counter = pCounter->GetValue(); + if (0 == counter) + { + log.warningf("%s: \"%s\": No Nero chapters available", + __FUNCTION__, GetFilename().c_str()); + return MP4ChapterTypeNone; + } + + MP4TableProperty * pTable = 0; + MP4Integer64Property * pStartTime = 0; + MP4StringProperty * pName = 0; + MP4Duration chapterDurationSum = 0; + const char * name = 0; + + if (!pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) + { + log.warningf("%s: \"%s\": Nero chapter list does not exist", + __FUNCTION__, GetFilename().c_str()); + return MP4ChapterTypeNone; + } + + if (0 == (pStartTime = (MP4Integer64Property *) pTable->GetProperty(0))) + { + log.warningf("%s: \"%s\": List of Chapter starttimes does not exist", + __FUNCTION__, GetFilename().c_str()); + return MP4ChapterTypeNone; + } + if (0 == (pName = (MP4StringProperty *) pTable->GetProperty(1))) + { + log.warningf("%s: \"%s\": List of Chapter titles does not exist", + __FUNCTION__, GetFilename().c_str()); + return MP4ChapterTypeNone; + } + + MP4Chapter_t * chapters = (MP4Chapter_t*)MP4Malloc(sizeof(MP4Chapter_t) * counter); + + // get the name of the first chapter + name = pName->GetValue(); + + // process remaining chapters + uint32_t i, j; + for (i = 0, j = 1; i < counter; ++i, ++j) + { + // insert the chapter title + uint32_t len = min((uint32_t)strlen(name), (uint32_t)MP4V2_CHAPTER_TITLE_MAX); + strncpy(chapters[i].title, name, len); + chapters[i].title[len] = 0; + + // calculate the duration + MP4Duration duration = 0; + if (j < counter) + { + duration = MP4ConvertTime(pStartTime->GetValue(j), + (MP4_NANOSECONDS_TIME_SCALE / 100), + MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum; + + // now get the name of the chapter (to be written next) + name = pName->GetValue(j); + } + else + { + // last chapter + duration = MP4ConvertTime(GetDuration(), GetTimeScale(), MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum; + } + + // sum up the chapter duration + chapterDurationSum += duration; + + // insert the chapter duration + chapters[i].duration = duration; + } + + *chapterList = chapters; + *chapterCount = counter; + + return MP4ChapterTypeNero; + } + + return MP4ChapterTypeNone; +} + +MP4ChapterType MP4File::SetChapters(MP4Chapter_t * chapterList, uint32_t chapterCount, MP4ChapterType toChapterType) +{ + MP4ChapterType setType = MP4ChapterTypeNone; + + // first remove any existing chapters + DeleteChapters(toChapterType, MP4_INVALID_TRACK_ID); + + if( MP4ChapterTypeAny == toChapterType || MP4ChapterTypeNero == toChapterType ) + { + MP4Duration duration = 0; + for( uint32_t i = 0; i < chapterCount; ++i ) + { + AddNeroChapter(duration, chapterList[i].title); + duration += 10 * MP4_MILLISECONDS_TIME_SCALE * chapterList[i].duration; + } + + setType = MP4ChapterTypeNero; + } + + if (MP4ChapterTypeAny == toChapterType || MP4ChapterTypeQt == toChapterType) + { + // find the first video or audio track + MP4TrackId refTrack = MP4_INVALID_TRACK_ID; + for( uint32_t i = 0; i < m_pTracks.Size(); i++ ) + { + if( MP4_IS_VIDEO_TRACK_TYPE( m_pTracks[i]->GetType() ) || + MP4_IS_AUDIO_TRACK_TYPE( m_pTracks[i]->GetType() ) ) + { + refTrack = m_pTracks[i]->GetId(); + break; + } + } + + if( refTrack == MP4_INVALID_TRACK_ID ) + { + return setType; + } + + // create the chapter track + MP4TrackId chapterTrack = AddChapterTextTrack(refTrack, MP4_MILLISECONDS_TIME_SCALE); + + for( uint32_t i = 0 ; i < chapterCount; ++i ) + { + // create and write the chapter track sample + AddChapter( chapterTrack, chapterList[i].duration, chapterList[i].title ); + } + + setType = MP4ChapterTypeNone == setType ? MP4ChapterTypeQt : MP4ChapterTypeAny; + } + + return setType; +} + +MP4ChapterType MP4File::ConvertChapters(MP4ChapterType toChapterType) +{ + MP4ChapterType sourceType = MP4ChapterTypeNone; + const char* errMsg = 0; + + if( MP4ChapterTypeQt == toChapterType ) + { + sourceType = MP4ChapterTypeNero; + errMsg = "Could not find Nero chapter markers"; + } + else if( MP4ChapterTypeNero == toChapterType ) + { + sourceType = MP4ChapterTypeQt; + errMsg = "Could not find QuickTime chapter markers"; + } + else + { + return MP4ChapterTypeNone; + } + + MP4Chapter_t * chapters = 0; + uint32_t chapterCount = 0; + + GetChapters(&chapters, &chapterCount, sourceType); + if (0 == chapterCount) + { + log.warningf("%s: \"%s\": %s", __FUNCTION__, GetFilename().c_str(), + errMsg); + return MP4ChapterTypeNone; + } + + SetChapters(chapters, chapterCount, toChapterType); + + MP4Free(chapters); + + return toChapterType; +} + +void MP4File::ChangeMovieTimeScale(uint32_t timescale) +{ + uint32_t origTimeScale = GetTimeScale(); + if (timescale == origTimeScale) { + // already done + return; + } + + MP4Duration movieDuration = GetDuration(); + + // set movie header timescale and duration + SetTimeScale(timescale); + SetDuration(MP4ConvertTime(movieDuration, origTimeScale, timescale)); + + // set track header duration (calculated with movie header timescale) + uint32_t trackCount = GetNumberOfTracks(); + for (uint32_t i = 0; i < trackCount; ++i) + { + MP4Track * track = GetTrack(FindTrackId(i)); + MP4Atom & trackAtom = track->GetTrakAtom(); + MP4IntegerProperty * duration; + + if (trackAtom.FindProperty("trak.tkhd.duration", (MP4Property**)&duration)) + { + duration->SetValue(MP4ConvertTime(duration->GetValue(), origTimeScale, timescale)); + } + } +} + +void MP4File::DeleteTrack(MP4TrackId trackId) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + uint32_t trakIndex = FindTrakAtomIndex(trackId); + uint16_t trackIndex = FindTrackIndex(trackId); + MP4Track* pTrack = m_pTracks[trackIndex]; + + MP4Atom& trakAtom = pTrack->GetTrakAtom(); + + MP4Atom* pMoovAtom = FindAtom("moov"); + ASSERT(pMoovAtom); + + RemoveTrackFromIod(trackId, ShallHaveIods()); + RemoveTrackFromOd(trackId); + + if (trackId == m_odTrackId) { + m_odTrackId = 0; + } + + pMoovAtom->DeleteChildAtom(&trakAtom); + + m_trakIds.Delete(trakIndex); + + m_pTracks.Delete(trackIndex); + + delete pTrack; + delete &trakAtom; +} + +uint32_t MP4File::GetNumberOfTracks(const char* type, uint8_t subType) +{ + if (type == NULL) { + return m_pTracks.Size(); + } + + uint32_t typeSeen = 0; + const char* normType = MP4NormalizeTrackType(type); + + for (uint32_t i = 0; i < m_pTracks.Size(); i++) { + if (!strcmp(normType, m_pTracks[i]->GetType())) { + if (subType) { + if (strcmp(normType, MP4_AUDIO_TRACK_TYPE) == 0) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } else if (strcmp(normType, MP4_VIDEO_TRACK_TYPE)) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } + // else unknown subtype, ignore it + } + typeSeen++; + } + } + return typeSeen; +} + +MP4TrackId MP4File::AllocTrackId() +{ + MP4TrackId trackId = + GetIntegerProperty("moov.mvhd.nextTrackId"); + + if (trackId <= 0xFFFF) { + // check that nextTrackid is correct + try { + (void)FindTrackIndex(trackId); + // ERROR, this trackId is in use + } + catch (Exception* x) { + // OK, this trackId is not in use, proceed + delete x; + SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1); + return trackId; + } + } + + // we need to search for a track id + for (trackId = 1; trackId <= 0xFFFF; trackId++) { + try { + (void)FindTrackIndex(trackId); + // KEEP LOOKING, this trackId is in use + } + catch (Exception* x) { + // OK, this trackId is not in use, proceed + delete x; + return trackId; + } + } + + // extreme case where mp4 file has 2^16 tracks in it + throw new Exception("too many existing tracks", __FILE__, __LINE__, __FUNCTION__); + return MP4_INVALID_TRACK_ID; // to keep MSVC happy +} + +MP4TrackId MP4File::FindTrackId(uint16_t trackIndex, + const char* type, uint8_t subType) +{ + if (type == NULL) { + return m_pTracks[trackIndex]->GetId(); + } + + uint32_t typeSeen = 0; + const char* normType = MP4NormalizeTrackType(type); + + for (uint32_t i = 0; i < m_pTracks.Size(); i++) { + if (!strcmp(normType, m_pTracks[i]->GetType())) { + if (subType) { + if (strcmp(normType, MP4_AUDIO_TRACK_TYPE) == 0) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } else if (strcmp(normType, MP4_VIDEO_TRACK_TYPE) == 0) { + if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) { + continue; + } + } + // else unknown subtype, ignore it + } + + if (trackIndex == typeSeen) { + return m_pTracks[i]->GetId(); + } + + typeSeen++; + } + } + + ostringstream msg; + msg << "Track index doesn't exist - track " << trackIndex << " type " << type; + throw new Exception(msg.str(),__FILE__, __LINE__, __FUNCTION__); + return MP4_INVALID_TRACK_ID; // satisfy MS compiler +} + +uint16_t MP4File::FindTrackIndex(MP4TrackId trackId) +{ + for (uint32_t i = 0; i < m_pTracks.Size() && i <= 0xFFFF; i++) { + if (m_pTracks[i]->GetId() == trackId) { + return (uint16_t)i; + } + } + + ostringstream msg; + msg << "Track id " << trackId << " doesn't exist"; + throw new Exception(msg.str(),__FILE__, __LINE__, __FUNCTION__); + return (uint16_t)-1; // satisfy MS compiler +} + +uint16_t MP4File::FindTrakAtomIndex(MP4TrackId trackId) +{ + if (trackId) { + for (uint32_t i = 0; i < m_trakIds.Size(); i++) { + if (m_trakIds[i] == trackId) { + return i; + } + } + } + + ostringstream msg; + msg << "Track id " << trackId << " doesn't exist"; + throw new Exception(msg.str(),__FILE__, __LINE__, __FUNCTION__); + return (uint16_t)-1; // satisfy MS compiler +} + +uint32_t MP4File::GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetSampleSize(sampleId); +} + +uint32_t MP4File::GetTrackMaxSampleSize(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetMaxSampleSize(); +} + +MP4SampleId MP4File::GetSampleIdFromTime(MP4TrackId trackId, + MP4Timestamp when, bool wantSyncSample) +{ + return m_pTracks[FindTrackIndex(trackId)]-> + GetSampleIdFromTime(when, wantSyncSample); +} + +MP4Timestamp MP4File::GetSampleTime( + MP4TrackId trackId, MP4SampleId sampleId) +{ + MP4Timestamp timestamp; + m_pTracks[FindTrackIndex(trackId)]-> + GetSampleTimes(sampleId, ×tamp, NULL); + return timestamp; +} + +MP4Duration MP4File::GetSampleDuration( + MP4TrackId trackId, MP4SampleId sampleId) +{ + MP4Duration duration; + m_pTracks[FindTrackIndex(trackId)]-> + GetSampleTimes(sampleId, NULL, &duration); + return duration; +} + +MP4Duration MP4File::GetSampleRenderingOffset( + MP4TrackId trackId, MP4SampleId sampleId) +{ + return m_pTracks[FindTrackIndex(trackId)]-> + GetSampleRenderingOffset(sampleId); +} + +bool MP4File::GetSampleSync(MP4TrackId trackId, MP4SampleId sampleId) +{ + return m_pTracks[FindTrackIndex(trackId)]->IsSyncSample(sampleId); +} + +void MP4File::ReadSample( + MP4TrackId trackId, + MP4SampleId sampleId, + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample, + bool* hasDependencyFlags, + uint32_t* dependencyFlags ) +{ + m_pTracks[FindTrackIndex(trackId)]->ReadSample( + sampleId, + ppBytes, + pNumBytes, + pStartTime, + pDuration, + pRenderingOffset, + pIsSyncSample, + hasDependencyFlags, + dependencyFlags ); +} + +void MP4File::WriteSample( + MP4TrackId trackId, + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample ) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + m_pTracks[FindTrackIndex(trackId)]->WriteSample( + pBytes, numBytes, duration, renderingOffset, isSyncSample ); + m_pModificationProperty->SetValue( MP4GetAbsTimestamp() ); +} + +void MP4File::WriteSampleDependency( + MP4TrackId trackId, + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample, + uint32_t dependencyFlags ) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + m_pTracks[FindTrackIndex(trackId)]->WriteSampleDependency( + pBytes, numBytes, duration, renderingOffset, isSyncSample, dependencyFlags ); + m_pModificationProperty->SetValue( MP4GetAbsTimestamp() ); +} + +void MP4File::SetSampleRenderingOffset(MP4TrackId trackId, + MP4SampleId sampleId, MP4Duration renderingOffset) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + m_pTracks[FindTrackIndex(trackId)]-> + SetSampleRenderingOffset(sampleId, renderingOffset); + + m_pModificationProperty->SetValue(MP4GetAbsTimestamp()); +} + +void MP4File::MakeFtypAtom( + char* majorBrand, + uint32_t minorVersion, + char** compatibleBrands, + uint32_t compatibleBrandsCount) +{ + MP4FtypAtom* ftyp = (MP4FtypAtom*)m_pRootAtom->FindAtom( "ftyp" ); + if (ftyp == NULL) + ftyp = (MP4FtypAtom*)InsertChildAtom( m_pRootAtom, "ftyp", 0 ); + + // bail if majorbrand is not specified; defaults suffice. + if (majorBrand == NULL) + return; + + ftyp->majorBrand.SetValue( majorBrand ); + ftyp->minorVersion.SetValue( minorVersion ); + + ftyp->compatibleBrands.SetCount( compatibleBrandsCount ); + for( uint32_t i = 0; i < compatibleBrandsCount; i++ ) + ftyp->compatibleBrands.SetValue( compatibleBrands[i], i ); +} + +char* MP4File::MakeTrackName(MP4TrackId trackId, const char* name) +{ + uint16_t trakIndex = FindTrakAtomIndex(trackId); + + if (name == NULL || name[0] == '\0') { + snprintf(m_trakName, sizeof(m_trakName), + "moov.trak[%u]", trakIndex); + } else { + snprintf(m_trakName, sizeof(m_trakName), + "moov.trak[%u].%s", trakIndex, name); + } + return m_trakName; +} + +MP4Atom *MP4File::FindTrackAtom (MP4TrackId trackId, const char *name) +{ + return FindAtom(MakeTrackName(trackId, name)); +} + +uint64_t MP4File::GetTrackIntegerProperty(MP4TrackId trackId, const char* name) +{ + return GetIntegerProperty(MakeTrackName(trackId, name)); +} + +void MP4File::SetTrackIntegerProperty(MP4TrackId trackId, const char* name, + int64_t value) +{ + SetIntegerProperty(MakeTrackName(trackId, name), value); +} + +float MP4File::GetTrackFloatProperty(MP4TrackId trackId, const char* name) +{ + return GetFloatProperty(MakeTrackName(trackId, name)); +} + +void MP4File::SetTrackFloatProperty(MP4TrackId trackId, const char* name, + float value) +{ + SetFloatProperty(MakeTrackName(trackId, name), value); +} + +const char* MP4File::GetTrackStringProperty(MP4TrackId trackId, const char* name) +{ + return GetStringProperty(MakeTrackName(trackId, name)); +} + +void MP4File::SetTrackStringProperty(MP4TrackId trackId, const char* name, + const char* value) +{ + SetStringProperty(MakeTrackName(trackId, name), value); +} + +void MP4File::GetTrackBytesProperty(MP4TrackId trackId, const char* name, + uint8_t** ppValue, uint32_t* pValueSize) +{ + GetBytesProperty(MakeTrackName(trackId, name), ppValue, pValueSize); +} + +void MP4File::SetTrackBytesProperty(MP4TrackId trackId, const char* name, + const uint8_t* pValue, uint32_t valueSize) +{ + SetBytesProperty(MakeTrackName(trackId, name), pValue, valueSize); +} + +bool MP4File::GetTrackLanguage( MP4TrackId trackId, char* code ) +{ + ostringstream oss; + oss << "moov.trak[" << FindTrakAtomIndex(trackId) << "].mdia.mdhd.language"; + + MP4Property* prop; + if( !m_pRootAtom->FindProperty( oss.str().c_str(), &prop )) + return false; + + if( prop->GetType() != LanguageCodeProperty ) + return false; + + MP4LanguageCodeProperty& lang = *static_cast<MP4LanguageCodeProperty*>(prop); + string slang; + bmff::enumLanguageCode.toString( lang.GetValue(), slang ); + if( slang.length() != 3 ) { + memset( code, '\0', 4 ); + } + else { + memcpy( code, slang.c_str(), 3 ); + code[3] = '\0'; + } + + return true; +} + +bool MP4File::SetTrackLanguage( MP4TrackId trackId, const char* code ) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + ostringstream oss; + oss << "moov.trak[" << FindTrakAtomIndex(trackId) << "].mdia.mdhd.language"; + + MP4Property* prop; + if( !m_pRootAtom->FindProperty( oss.str().c_str(), &prop )) + return false; + + if( prop->GetType() != LanguageCodeProperty ) + return false; + + MP4LanguageCodeProperty& lang = *static_cast<MP4LanguageCodeProperty*>(prop); + lang.SetValue( bmff::enumLanguageCode.toType( code )); + + return true; +} + + +bool MP4File::GetTrackName( MP4TrackId trackId, char** name ) +{ + unsigned char *val = NULL; + uint32_t valSize = 0; + MP4Atom *pMetaAtom; + + pMetaAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId,"udta.name")); + + if (pMetaAtom) + { + GetBytesProperty(MakeTrackName(trackId,"udta.name.value"), (uint8_t**)&val, &valSize); + } + if (valSize > 0) + { + *name = (char*)malloc((valSize+1)*sizeof(char)); + if (*name == NULL) { + free(val); + return false; + } + memcpy(*name, val, valSize*sizeof(unsigned char)); + free(val); + (*name)[valSize] = '\0'; + return true; + } + + return false; +} + +bool MP4File::SetTrackName( MP4TrackId trackId, const char* name ) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + char atomstring[40]; + MP4Atom *pMetaAtom; + MP4BytesProperty *pMetadataProperty = NULL; + snprintf(atomstring, 40, "%s", MakeTrackName(trackId,"udta.name")); + + pMetaAtom = m_pRootAtom->FindAtom(atomstring); + + if (!pMetaAtom) + { + if (!AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.name")) + return false; + + pMetaAtom = m_pRootAtom->FindAtom(atomstring); + if (pMetaAtom == NULL) return false; + } + + ASSERT(pMetaAtom->FindProperty("name.value", + (MP4Property**)&pMetadataProperty)); + ASSERT(pMetadataProperty); + + pMetadataProperty->SetValue((uint8_t*)name, (uint32_t)strlen(name)); + + return true; +} + +// file level convenience functions + +MP4Duration MP4File::GetDuration() +{ + return m_pDurationProperty->GetValue(); +} + +void MP4File::SetDuration(MP4Duration value) +{ + m_pDurationProperty->SetValue(value); +} + +uint32_t MP4File::GetTimeScale() +{ + return m_pTimeScaleProperty->GetValue(); +} + +void MP4File::SetTimeScale(uint32_t value) +{ + if (value == 0) { + throw new Exception("invalid value", __FILE__, __LINE__, __FUNCTION__); + } + m_pTimeScaleProperty->SetValue(value); +} + +uint8_t MP4File::GetODProfileLevel() +{ + return GetIntegerProperty("moov.iods.ODProfileLevelId"); +} + +void MP4File::SetODProfileLevel(uint8_t value) +{ + SetIntegerProperty("moov.iods.ODProfileLevelId", value); +} + +uint8_t MP4File::GetSceneProfileLevel() +{ + return GetIntegerProperty("moov.iods.sceneProfileLevelId"); +} + +void MP4File::SetSceneProfileLevel(uint8_t value) +{ + SetIntegerProperty("moov.iods.sceneProfileLevelId", value); +} + +uint8_t MP4File::GetVideoProfileLevel() +{ + return GetIntegerProperty("moov.iods.visualProfileLevelId"); +} + +void MP4File::SetVideoProfileLevel(uint8_t value) +{ + SetIntegerProperty("moov.iods.visualProfileLevelId", value); +} + +uint8_t MP4File::GetAudioProfileLevel() +{ + return GetIntegerProperty("moov.iods.audioProfileLevelId"); +} + +void MP4File::SetAudioProfileLevel(uint8_t value) +{ + SetIntegerProperty("moov.iods.audioProfileLevelId", value); +} + +uint8_t MP4File::GetGraphicsProfileLevel() +{ + return GetIntegerProperty("moov.iods.graphicsProfileLevelId"); +} + +void MP4File::SetGraphicsProfileLevel(uint8_t value) +{ + SetIntegerProperty("moov.iods.graphicsProfileLevelId", value); +} + +const char* MP4File::GetSessionSdp() +{ + return GetStringProperty("moov.udta.hnti.rtp .sdpText"); +} + +void MP4File::SetSessionSdp(const char* sdpString) +{ + (void)AddDescendantAtoms("moov", "udta.hnti.rtp "); + + SetStringProperty("moov.udta.hnti.rtp .sdpText", sdpString); +} + +void MP4File::AppendSessionSdp(const char* sdpFragment) +{ + const char* oldSdpString = NULL; + try { + oldSdpString = GetSessionSdp(); + } + catch (Exception* x) { + delete x; + SetSessionSdp(sdpFragment); + return; + } + + char* newSdpString = + (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1); + strcpy(newSdpString, oldSdpString); + strcat(newSdpString, sdpFragment); + SetSessionSdp(newSdpString); + MP4Free(newSdpString); +} + +// +// ismacrypt API - retrieve OriginalFormatBox +// +// parameters are assumed to have been sanity tested in mp4.cpp +// don't call this unless media data name is 'encv', +// results may otherwise be unpredictable. +// +// input: +// trackID - valid encv track ID for this file +// buflen - length of oFormat, minimum is 5 (4cc plus null terminator) +// +// output: +// oFormat - buffer to return null terminated string containing +// track original format +// return: +// 0 - original format returned OK +// 1 - buffer length error or problem retrieving track property +// +// +bool MP4File::GetTrackMediaDataOriginalFormat(MP4TrackId trackId, + char *originalFormat, uint32_t buflen) +{ + uint32_t format; + + if (buflen < 5) + return false; + + format = GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.sinf.frma.data-format"); + + IDATOM(format, originalFormat); + return true; + +} + + +// track level convenience functions + +MP4SampleId MP4File::GetTrackNumberOfSamples(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfSamples(); +} + +const char* MP4File::GetTrackType(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetType(); +} + +const char *MP4File::GetTrackMediaDataName (MP4TrackId trackId) +{ + MP4Atom *pChild; + MP4Atom *pAtom = + FindAtom(MakeTrackName(trackId, + "mdia.minf.stbl.stsd")); + if (pAtom->GetNumberOfChildAtoms() != 1) { + log.errorf("%s: \"%s\": track %d has more than 1 child atoms in stsd", + __FUNCTION__, GetFilename().c_str(), trackId); + return NULL; + } + pChild = pAtom->GetChildAtom(0); + return pChild->GetType(); +} + + +uint32_t MP4File::GetTrackTimeScale(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetTimeScale(); +} + +void MP4File::SetTrackTimeScale(MP4TrackId trackId, uint32_t value) +{ + if (value == 0) { + throw new Exception("invalid value", __FILE__, __LINE__, __FUNCTION__); + } + SetTrackIntegerProperty(trackId, "mdia.mdhd.timeScale", value); +} + +MP4Duration MP4File::GetTrackDuration(MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration"); +} + +uint8_t MP4File::GetTrackEsdsObjectTypeId(MP4TrackId trackId) +{ + // changed mp4a to * to handle enca case + try { + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.esds.decConfigDescr.objectTypeId"); + } catch (Exception *x) { + delete x; + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.*.esds.decConfigDescr.objectTypeId"); + } +} + +uint8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId) +{ + // verify that track is an MPEG-4 audio track + if (GetTrackEsdsObjectTypeId(trackId) != MP4_MPEG4_AUDIO_TYPE) { + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + + uint8_t* pEsConfig = NULL; + uint32_t esConfigSize; + + // The Mpeg4 audio type (AAC, CELP, HXVC, ...) + // is the first 5 bits of the ES configuration + + GetTrackESConfiguration(trackId, &pEsConfig, &esConfigSize); + + if (esConfigSize < 1) { + free(pEsConfig); + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + + uint8_t mpeg4Type = ((pEsConfig[0] >> 3) & 0x1f); + // TTTT TXXX XXX potentially 6 bits of extension. + if (mpeg4Type == 0x1f) { + if (esConfigSize < 2) { + free(pEsConfig); + return MP4_MPEG4_INVALID_AUDIO_TYPE; + } + mpeg4Type = 32 + + (((pEsConfig[0] & 0x7) << 3) | ((pEsConfig[1] >> 5) & 0x7)); + } + + free(pEsConfig); + + return mpeg4Type; +} + + +MP4Duration MP4File::GetTrackFixedSampleDuration(MP4TrackId trackId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration(); +} + +double MP4File::GetTrackVideoFrameRate(MP4TrackId trackId) +{ + MP4SampleId numSamples = + GetTrackNumberOfSamples(trackId); + uint64_t + msDuration = + ConvertFromTrackDuration(trackId, + GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE); + + if (msDuration == 0) { + return 0.0; + } + + return ((double)numSamples / double(msDuration)) * MP4_MSECS_TIME_SCALE; +} + +int MP4File::GetTrackAudioChannels (MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*[0].channels"); +} + +// true if media track encrypted according to ismacryp +bool MP4File::IsIsmaCrypMediaTrack(MP4TrackId trackId) +{ + if (GetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.*.sinf.frma.data-format") + != (uint64_t)-1) { + return true; + } + return false; +} + +bool MP4File::IsWriteMode() +{ + if( !m_file ) + return false; + + switch( m_file->mode ) { + case File::MODE_READ: + return false; + + case File::MODE_MODIFY: + case File::MODE_CREATE: + default: + break; + } + + return true; +} + +void MP4File::GetTrackESConfiguration(MP4TrackId trackId, + uint8_t** ppConfig, uint32_t* pConfigSize) +{ + try { + GetTrackBytesProperty(trackId, + "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo[0].info", + ppConfig, pConfigSize); + } catch (Exception *x) { + delete x; + GetTrackBytesProperty(trackId, + "mdia.minf.stbl.stsd.*[0].*.esds.decConfigDescr.decSpecificInfo[0].info", + ppConfig, pConfigSize); + } +} + +void MP4File::GetTrackVideoMetadata(MP4TrackId trackId, + uint8_t** ppConfig, uint32_t* pConfigSize) +{ + GetTrackBytesProperty(trackId, + "mdia.minf.stbl.stsd.*[0].*.metadata", + ppConfig, pConfigSize); +} + +void MP4File::SetTrackESConfiguration(MP4TrackId trackId, + const uint8_t* pConfig, uint32_t configSize) +{ + // get a handle on the track decoder config descriptor + MP4DescriptorProperty* pConfigDescrProperty = NULL; + if (FindProperty(MakeTrackName(trackId, + "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo"), + (MP4Property**)&pConfigDescrProperty) == false || + pConfigDescrProperty == NULL) { + // probably trackId refers to a hint track + throw new Exception("no such property", __FILE__, __LINE__, __FUNCTION__); + } + + // lookup the property to store the configuration + MP4BytesProperty* pInfoProperty = NULL; + (void)pConfigDescrProperty->FindProperty("decSpecificInfo[0].info", + (MP4Property**)&pInfoProperty); + + // configuration being set for the first time + if (pInfoProperty == NULL) { + // need to create a new descriptor to hold it + MP4Descriptor* pConfigDescr = + pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag); + pConfigDescr->Generate(); + + (void)pConfigDescrProperty->FindProperty( + "decSpecificInfo[0].info", + (MP4Property**)&pInfoProperty); + ASSERT(pInfoProperty); + } + + // set the value + pInfoProperty->SetValue(pConfig, configSize); +} + + +void MP4File::GetTrackH264SeqPictHeaders (MP4TrackId trackId, + uint8_t ***pppSeqHeader, + uint32_t **ppSeqHeaderSize, + uint8_t ***pppPictHeader, + uint32_t **ppPictHeaderSize) +{ + uint32_t count; + const char *format; + MP4Atom *avcCAtom; + + *pppSeqHeader = NULL; + *pppPictHeader = NULL; + *ppSeqHeaderSize = NULL; + *ppPictHeaderSize = NULL; + + // get 4cc media format - can be avc1 or encv for ismacrypted track + format = GetTrackMediaDataName (trackId); + + if (!strcasecmp(format, "avc1")) + avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC")); + else if (!strcasecmp(format, "encv")) + avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC")); + else + // huh? unknown track format + return; + + MP4BitfieldProperty *pSeqCount; + MP4IntegerProperty *pSeqLen, *pPictCount, *pPictLen; + MP4BytesProperty *pSeqVal, *pPictVal; + + if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets", + (MP4Property **)&pSeqCount) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength", + (MP4Property **)&pSeqLen) == false) || + (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit", + (MP4Property **)&pSeqVal) == false)) { + log.errorf("%s: \"%s\": Could not find avcC properties", __FUNCTION__, GetFilename().c_str()); + return ; + } + uint8_t **ppSeqHeader = + (uint8_t **)malloc((pSeqCount->GetValue() + 1) * sizeof(uint8_t *)); + if (ppSeqHeader == NULL) return; + *pppSeqHeader = ppSeqHeader; + + uint32_t *pSeqHeaderSize = + (uint32_t *)malloc((pSeqCount->GetValue() + 1) * sizeof(uint32_t *)); + + if (pSeqHeaderSize == NULL) return; + + *ppSeqHeaderSize = pSeqHeaderSize; + for (count = 0; count < pSeqCount->GetValue(); count++) { + pSeqVal->GetValue(&(ppSeqHeader[count]), &(pSeqHeaderSize[count]), + count); + } + ppSeqHeader[count] = NULL; + pSeqHeaderSize[count] = 0; + + if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets", + (MP4Property **)&pPictCount) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength", + (MP4Property **)&pPictLen) == false) || + (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit", + (MP4Property **)&pPictVal) == false)) { + log.errorf("%s: \"%s\": Could not find avcC picture table properties", + __FUNCTION__, GetFilename().c_str()); + return ; + } + uint8_t + **ppPictHeader = + (uint8_t **)malloc((pPictCount->GetValue() + 1) * sizeof(uint8_t *)); + if (ppPictHeader == NULL) return; + uint32_t *pPictHeaderSize = + (uint32_t *)malloc((pPictCount->GetValue() + 1)* sizeof(uint32_t *)); + if (pPictHeaderSize == NULL) { + free(ppPictHeader); + return; + } + *pppPictHeader = ppPictHeader; + *ppPictHeaderSize = pPictHeaderSize; + + for (count = 0; count < pPictCount->GetValue(); count++) { + pPictVal->GetValue(&(ppPictHeader[count]), &(pPictHeaderSize[count]), + count); + } + ppPictHeader[count] = NULL; + pPictHeaderSize[count] = 0; + return ; +} + + + +const char* MP4File::GetHintTrackSdp(MP4TrackId hintTrackId) +{ + return GetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText"); +} + +void MP4File::SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + + (void)AddDescendantAtoms( + MakeTrackName(hintTrackId, NULL), "udta.hnti.sdp "); + + SetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText", sdpString); +} + +void MP4File::AppendHintTrackSdp(MP4TrackId hintTrackId, + const char* sdpFragment) +{ + const char* oldSdpString = NULL; + try { + oldSdpString = GetHintTrackSdp(hintTrackId); + } + catch (Exception* x) { + delete x; + SetHintTrackSdp(hintTrackId, sdpFragment); + return; + } + + char* newSdpString = + (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1); + strcpy(newSdpString, oldSdpString); + strcat(newSdpString, sdpFragment); + SetHintTrackSdp(hintTrackId, newSdpString); + MP4Free(newSdpString); +} + +void MP4File::GetHintTrackRtpPayload( + MP4TrackId hintTrackId, + char** ppPayloadName, + uint8_t* pPayloadNumber, + uint16_t* pMaxPayloadSize, + char **ppEncodingParams) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + + ((MP4RtpHintTrack*)pTrack)->GetPayload( + ppPayloadName, pPayloadNumber, pMaxPayloadSize, ppEncodingParams); +} + +void MP4File::SetHintTrackRtpPayload(MP4TrackId hintTrackId, + const char* payloadName, uint8_t* pPayloadNumber, uint16_t maxPayloadSize, + const char *encoding_params, + bool include_rtp_map, + bool include_mpeg4_esid) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + + uint8_t payloadNumber; + if (pPayloadNumber && *pPayloadNumber != MP4_SET_DYNAMIC_PAYLOAD) { + payloadNumber = *pPayloadNumber; + } else { + payloadNumber = AllocRtpPayloadNumber(); + if (pPayloadNumber) { + *pPayloadNumber = payloadNumber; + } + } + + ((MP4RtpHintTrack*)pTrack)->SetPayload( + payloadName, payloadNumber, maxPayloadSize, encoding_params, + include_rtp_map, include_mpeg4_esid); +} + +uint8_t MP4File::AllocRtpPayloadNumber() +{ + MP4Integer32Array usedPayloads; + uint32_t i; + + // collect rtp payload numbers in use by existing tracks + for (i = 0; i < m_pTracks.Size(); i++) { + MP4Atom& trakAtom = m_pTracks[i]->GetTrakAtom(); + + MP4Integer32Property* pPayloadProperty = NULL; + if (trakAtom.FindProperty("trak.udta.hinf.payt.payloadNumber", + (MP4Property**)&pPayloadProperty) && + pPayloadProperty) { + usedPayloads.Add(pPayloadProperty->GetValue()); + } + } + + // search dynamic payload range for an available slot + uint8_t payload; + for (payload = 96; payload < 128; payload++) { + for (i = 0; i < usedPayloads.Size(); i++) { + if (payload == usedPayloads[i]) { + break; + } + } + if (i == usedPayloads.Size()) { + break; + } + } + + if (payload >= 128) { + throw new Exception("no more available rtp payload numbers", + __FILE__, __LINE__, __FUNCTION__); + } + + return payload; +} + +MP4TrackId MP4File::GetHintTrackReferenceTrackId( + MP4TrackId hintTrackId) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + + MP4Track* pRefTrack = ((MP4RtpHintTrack*)pTrack)->GetRefTrack(); + + if (pRefTrack == NULL) { + return MP4_INVALID_TRACK_ID; + } + return pRefTrack->GetId(); +} + +void MP4File::ReadRtpHint( + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + uint16_t* pNumPackets) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)-> + ReadHint(hintSampleId, pNumPackets); +} + +uint16_t MP4File::GetRtpHintNumberOfPackets( + MP4TrackId hintTrackId) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + return ((MP4RtpHintTrack*)pTrack)->GetHintNumberOfPackets(); +} + +int8_t MP4File::GetRtpPacketBFrame( + MP4TrackId hintTrackId, + uint16_t packetIndex) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + return ((MP4RtpHintTrack*)pTrack)->GetPacketBFrame(packetIndex); +} + +int32_t MP4File::GetRtpPacketTransmitOffset( + MP4TrackId hintTrackId, + uint16_t packetIndex) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + return ((MP4RtpHintTrack*)pTrack)->GetPacketTransmitOffset(packetIndex); +} + +void MP4File::ReadRtpPacket( + MP4TrackId hintTrackId, + uint16_t packetIndex, + uint8_t** ppBytes, + uint32_t* pNumBytes, + uint32_t ssrc, + bool includeHeader, + bool includePayload) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->ReadPacket( + packetIndex, ppBytes, pNumBytes, + ssrc, includeHeader, includePayload); +} + +MP4Timestamp MP4File::GetRtpTimestampStart( + MP4TrackId hintTrackId) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + return ((MP4RtpHintTrack*)pTrack)->GetRtpTimestampStart(); +} + +void MP4File::SetRtpTimestampStart( + MP4TrackId hintTrackId, + MP4Timestamp rtpStart) +{ + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->SetRtpTimestampStart(rtpStart); +} + +void MP4File::AddRtpHint(MP4TrackId hintTrackId, + bool isBframe, uint32_t timestampOffset) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->AddHint(isBframe, timestampOffset); +} + +void MP4File::AddRtpPacket( + MP4TrackId hintTrackId, bool setMbit, int32_t transmitOffset) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->AddPacket(setMbit, transmitOffset); +} + +void MP4File::AddRtpImmediateData(MP4TrackId hintTrackId, + const uint8_t* pBytes, uint32_t numBytes) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->AddImmediateData(pBytes, numBytes); +} + +void MP4File::AddRtpSampleData(MP4TrackId hintTrackId, + MP4SampleId sampleId, uint32_t dataOffset, uint32_t dataLength) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->AddSampleData( + sampleId, dataOffset, dataLength); +} + +void MP4File::AddRtpESConfigurationPacket(MP4TrackId hintTrackId) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->AddESConfigurationPacket(); +} + +void MP4File::WriteRtpHint(MP4TrackId hintTrackId, + MP4Duration duration, bool isSyncSample) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + + MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)]; + + if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) { + throw new Exception("track is not a hint track", + __FILE__, __LINE__, __FUNCTION__); + } + ((MP4RtpHintTrack*)pTrack)->WriteHint(duration, isSyncSample); +} + +uint64_t MP4File::ConvertFromMovieDuration( + MP4Duration duration, + uint32_t timeScale) +{ + return MP4ConvertTime((uint64_t)duration, + GetTimeScale(), timeScale); +} + +uint64_t MP4File::ConvertFromTrackTimestamp( + MP4TrackId trackId, + MP4Timestamp timeStamp, + uint32_t timeScale) +{ + return MP4ConvertTime(timeStamp, + GetTrackTimeScale(trackId), timeScale); +} + +MP4Timestamp MP4File::ConvertToTrackTimestamp( + MP4TrackId trackId, + uint64_t timeStamp, + uint32_t timeScale) +{ + return (MP4Timestamp)MP4ConvertTime(timeStamp, + timeScale, GetTrackTimeScale(trackId)); +} + +uint64_t MP4File::ConvertFromTrackDuration( + MP4TrackId trackId, + MP4Duration duration, + uint32_t timeScale) +{ + return MP4ConvertTime((uint64_t)duration, + GetTrackTimeScale(trackId), timeScale); +} + +MP4Duration MP4File::ConvertToTrackDuration( + MP4TrackId trackId, + uint64_t duration, + uint32_t timeScale) +{ + return (MP4Duration)MP4ConvertTime(duration, + timeScale, GetTrackTimeScale(trackId)); +} + +uint8_t MP4File::ConvertTrackTypeToStreamType(const char* trackType) +{ + uint8_t streamType; + + if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) { + streamType = MP4ObjectDescriptionStreamType; + } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) { + streamType = MP4SceneDescriptionStreamType; + } else if (!strcmp(trackType, MP4_CLOCK_TRACK_TYPE)) { + streamType = MP4ClockReferenceStreamType; + } else if (!strcmp(trackType, MP4_MPEG7_TRACK_TYPE)) { + streamType = MP4Mpeg7StreamType; + } else if (!strcmp(trackType, MP4_OCI_TRACK_TYPE)) { + streamType = MP4OCIStreamType; + } else if (!strcmp(trackType, MP4_IPMP_TRACK_TYPE)) { + streamType = MP4IPMPStreamType; + } else if (!strcmp(trackType, MP4_MPEGJ_TRACK_TYPE)) { + streamType = MP4MPEGJStreamType; + } else { + streamType = MP4UserPrivateStreamType; + } + + return streamType; +} + +// edit list + +char* MP4File::MakeTrackEditName( + MP4TrackId trackId, + MP4EditId editId, + const char* name) +{ + char* trakName = MakeTrackName(trackId, NULL); + + if (m_editName == NULL) { + m_editName = (char *)malloc(1024); + if (m_editName == NULL) return NULL; + } + snprintf(m_editName, 1024, + "%s.edts.elst.entries[%u].%s", + trakName, editId - 1, name); + return m_editName; +} + +MP4EditId MP4File::AddTrackEdit( + MP4TrackId trackId, + MP4EditId editId) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + return m_pTracks[FindTrackIndex(trackId)]->AddEdit(editId); +} + +void MP4File::DeleteTrackEdit( + MP4TrackId trackId, + MP4EditId editId) +{ + ProtectWriteOperation(__FILE__, __LINE__, __FUNCTION__); + m_pTracks[FindTrackIndex(trackId)]->DeleteEdit(editId); +} + +uint32_t MP4File::GetTrackNumberOfEdits( + MP4TrackId trackId) +{ + return GetTrackIntegerProperty(trackId, "edts.elst.entryCount"); +} + +MP4Duration MP4File::GetTrackEditTotalDuration( + MP4TrackId trackId, + MP4EditId editId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetEditTotalDuration(editId); +} + +MP4Timestamp MP4File::GetTrackEditStart( + MP4TrackId trackId, + MP4EditId editId) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetEditStart(editId); +} + +MP4Timestamp MP4File::GetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId) +{ + return GetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaTime")); +} + +void MP4File::SetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime) +{ + SetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaTime"), + startTime); +} + +MP4Duration MP4File::GetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId) +{ + return GetIntegerProperty( + MakeTrackEditName(trackId, editId, "segmentDuration")); +} + +void MP4File::SetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration) +{ + SetIntegerProperty( + MakeTrackEditName(trackId, editId, "segmentDuration"), + duration); +} + +bool MP4File::GetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId) +{ + return (GetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaRate")) == 0); +} + +void MP4File::SetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId, + bool dwell) +{ + SetIntegerProperty( + MakeTrackEditName(trackId, editId, "mediaRate"), + (dwell ? 0 : 1)); +} + +MP4SampleId MP4File::GetSampleIdFromEditTime( + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetSampleIdFromEditTime( + when, pStartTime, pDuration); +} + +MP4Duration MP4File::GetTrackDurationPerChunk( MP4TrackId trackId ) +{ + return m_pTracks[FindTrackIndex(trackId)]->GetDurationPerChunk(); +} + +void MP4File::SetTrackDurationPerChunk( MP4TrackId trackId, MP4Duration duration ) +{ + m_pTracks[FindTrackIndex(trackId)]->SetDurationPerChunk( duration ); +} + +void MP4File::CopySample( + MP4File* srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4File* dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration ) +{ + // Note: we leave it up to the caller to ensure that the + // source and destination tracks are compatible. + // i.e. copying audio samples into a video track + // is unlikely to do anything useful + + uint8_t* pBytes = NULL; + uint32_t numBytes = 0; + MP4Duration sampleDuration; + MP4Duration renderingOffset; + bool isSyncSample; + bool hasDependencyFlags; + uint32_t dependencyFlags; + + srcFile->ReadSample( + srcTrackId, + srcSampleId, + &pBytes, + &numBytes, + NULL, + &sampleDuration, + &renderingOffset, + &isSyncSample, + &hasDependencyFlags, + &dependencyFlags ); + + if( !dstFile ) + dstFile = srcFile; + + if( dstTrackId == MP4_INVALID_TRACK_ID ) + dstTrackId = srcTrackId; + + if( dstSampleDuration != MP4_INVALID_DURATION ) + sampleDuration = dstSampleDuration; + + if( hasDependencyFlags ) { + dstFile->WriteSampleDependency( + dstTrackId, + pBytes, + numBytes, + sampleDuration, + renderingOffset, + isSyncSample, + dependencyFlags ); + } + else { + dstFile->WriteSample( + dstTrackId, + pBytes, + numBytes, + sampleDuration, + renderingOffset, + isSyncSample ); + } + + free( pBytes ); +} + +void MP4File::EncAndCopySample( + MP4File* srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + encryptFunc_t encfcnp, + uint32_t encfcnparam1, + MP4File* dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration ) +{ + // Note: we leave it up to the caller to ensure that the + // source and destination tracks are compatible. + // i.e. copying audio samples into a video track + // is unlikely to do anything useful + + uint8_t* pBytes = NULL; + uint32_t numBytes = 0; + uint8_t* encSampleData = NULL; + uint32_t encSampleLength = 0; + MP4Duration sampleDuration; + MP4Duration renderingOffset; + bool isSyncSample; + bool hasDependencyFlags; + uint32_t dependencyFlags; + + ASSERT(srcFile); + srcFile->ReadSample( + srcTrackId, + srcSampleId, + &pBytes, + &numBytes, + NULL, + &sampleDuration, + &renderingOffset, + &isSyncSample, + &hasDependencyFlags, + &dependencyFlags ); + + if( !dstFile ) + dstFile = srcFile; + + ASSERT(dstFile); + + if( dstTrackId == MP4_INVALID_TRACK_ID ) + dstTrackId = srcTrackId; + + if( dstSampleDuration != MP4_INVALID_DURATION ) + sampleDuration = dstSampleDuration; + + //if( ismacrypEncryptSampleAddHeader( ismaCryptSId, numBytes, pBytes, &encSampleLength, &encSampleData ) != 0) + if( encfcnp( encfcnparam1, numBytes, pBytes, &encSampleLength, &encSampleData ) != 0 ) + log.errorf("%s(%s,%s) Can't encrypt the sample and add its header %u", + __FUNCTION__, srcFile->GetFilename().c_str(), dstFile->GetFilename().c_str(), srcSampleId ); + + if( hasDependencyFlags ) { + dstFile->WriteSampleDependency( + dstTrackId, + pBytes, + numBytes, + sampleDuration, + renderingOffset, + isSyncSample, + dependencyFlags ); + } + else { + dstFile->WriteSample( + dstTrackId, + encSampleData, + encSampleLength, + sampleDuration, + renderingOffset, + isSyncSample ); + } + + free( pBytes ); + + if( encSampleData != NULL ) + free( encSampleData ); +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file.h new file mode 100644 index 00000000..813f90f7 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file.h @@ -0,0 +1,991 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 - 2005. All Rights Reserved. +// +// 3GPP features implementation is based on 3GPP's TS26.234-v5.60, +// and was contributed by Ximpo Group Ltd. +// +// Portions created by Ximpo Group Ltd. are +// Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. +// +// Contributors: +// Dave Mackie, [email protected] +// Alix Marchandise-Franquet, [email protected] +// Ximpo Group Ltd., [email protected] +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_MP4FILE_H +#define MP4V2_IMPL_MP4FILE_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +class MP4Atom; +class MP4Property; +class MP4Float32Property; +class MP4StringProperty; +class MP4BytesProperty; +class MP4Descriptor; +class MP4DescriptorProperty; + +class MP4File +{ +public: + static void CopySample( + MP4File* srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + MP4File* dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration ); + + static void EncAndCopySample( + MP4File* srcFile, + MP4TrackId srcTrackId, + MP4SampleId srcSampleId, + encryptFunc_t encfcnp, + uint32_t encfcnparam1, + MP4File* dstFile, + MP4TrackId dstTrackId, + MP4Duration dstSampleDuration ); + +public: + MP4File(); + ~MP4File(); + + /////////////////////////////////////////////////////////////////////////// + // file ops + /////////////////////////////////////////////////////////////////////////// + + void Create( const char* fileName, + uint32_t flags, + int add_ftyp = 1, + int add_iods = 1, + char* majorBrand = NULL, + uint32_t minorVersion = 0, + char** supportedBrands = NULL, + uint32_t supportedBrandsCount = 0 ); + + const std::string &GetFilename() const; + void Read( const char* name, const MP4FileProvider* provider ); + bool Modify( const char* fileName ); + void Optimize( const char* srcFileName, const char* dstFileName = NULL ); + bool CopyClose( const string& copyFileName ); + void Dump( bool dumpImplicits = false ); + void Close(uint32_t flags = 0); + + bool Use64Bits(const char *atomName); + void Check64BitStatus(const char *atomName); + /* file properties */ + + uint64_t GetIntegerProperty(const char* name); + float GetFloatProperty(const char* name); + const char* GetStringProperty(const char* name); + void GetBytesProperty(const char* name, + uint8_t** ppValue, uint32_t* pValueSize); + + void SetIntegerProperty(const char* name, uint64_t value); + void SetFloatProperty(const char* name, float value); + void SetStringProperty(const char* name, const char* value); + void SetBytesProperty(const char* name, + const uint8_t* pValue, uint32_t valueSize); + + // file level convenience functions + + MP4Duration GetDuration(); + void SetDuration(MP4Duration value); + + uint32_t GetTimeScale(); + void SetTimeScale(uint32_t value); + + uint8_t GetODProfileLevel(); + void SetODProfileLevel(uint8_t value); + + uint8_t GetSceneProfileLevel(); + void SetSceneProfileLevel(uint8_t value); + + uint8_t GetVideoProfileLevel(); + void SetVideoProfileLevel(uint8_t value); + + uint8_t GetAudioProfileLevel(); + void SetAudioProfileLevel(uint8_t value); + + uint8_t GetGraphicsProfileLevel(); + void SetGraphicsProfileLevel(uint8_t value); + + const char* GetSessionSdp(); + void SetSessionSdp(const char* sdpString); + void AppendSessionSdp(const char* sdpString); + + /* track operations */ + + MP4TrackId AddTrack(const char* type, uint32_t timeScale = 1000); + void DeleteTrack(MP4TrackId trackId); + + uint32_t GetNumberOfTracks(const char* type = NULL, uint8_t subType = 0); + + MP4TrackId AllocTrackId(); + MP4TrackId FindTrackId(uint16_t trackIndex, + const char* type = NULL, uint8_t subType = 0); + uint16_t FindTrackIndex(MP4TrackId trackId); + uint16_t FindTrakAtomIndex(MP4TrackId trackId); + + /* track properties */ + MP4Atom *FindTrackAtom(MP4TrackId trackId, const char *name); + uint64_t GetTrackIntegerProperty( + MP4TrackId trackId, const char* name); + float GetTrackFloatProperty( + MP4TrackId trackId, const char* name); + const char* GetTrackStringProperty( + MP4TrackId trackId, const char* name); + void GetTrackBytesProperty( + MP4TrackId trackId, const char* name, + uint8_t** ppValue, uint32_t* pValueSize); + + void SetTrackIntegerProperty( + MP4TrackId trackId, const char* name, int64_t value); + void SetTrackFloatProperty( + MP4TrackId trackId, const char* name, float value); + void SetTrackStringProperty( + MP4TrackId trackId, const char* name, const char* value); + void SetTrackBytesProperty( + MP4TrackId trackId, const char* name, + const uint8_t* pValue, uint32_t valueSize); + + bool GetTrackLanguage( MP4TrackId, char* ); + bool SetTrackLanguage( MP4TrackId, const char* ); + bool GetTrackName( MP4TrackId trackId, char** name ); + bool SetTrackName( MP4TrackId trackId, const char* name); + + /* sample operations */ + + uint32_t GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId); + + uint32_t GetTrackMaxSampleSize(MP4TrackId trackId); + + MP4SampleId GetSampleIdFromTime(MP4TrackId trackId, + MP4Timestamp when, bool wantSyncSample = false); + + MP4Timestamp GetSampleTime( + MP4TrackId trackId, MP4SampleId sampleId); + + MP4Duration GetSampleDuration( + MP4TrackId trackId, MP4SampleId sampleId); + + MP4Duration GetSampleRenderingOffset( + MP4TrackId trackId, MP4SampleId sampleId); + + bool GetSampleSync( + MP4TrackId trackId, MP4SampleId sampleId); + + void ReadSample( + // input parameters + MP4TrackId trackId, + MP4SampleId sampleId, + // output parameters + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL, + MP4Duration* pRenderingOffset = NULL, + bool* pIsSyncSample = NULL, + bool* hasDependencyFlags = NULL, + uint32_t* dependencyFlags = NULL ); + + void WriteSample( + MP4TrackId trackId, + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration = 0, + MP4Duration renderingOffset = 0, + bool isSyncSample = true ); + + void WriteSampleDependency( + MP4TrackId trackId, + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample, + uint32_t dependencyFlags ); + + void SetSampleRenderingOffset( + MP4TrackId trackId, + MP4SampleId sampleId, + MP4Duration renderingOffset ); + + MP4Duration GetTrackDurationPerChunk( MP4TrackId ); + void SetTrackDurationPerChunk( MP4TrackId, MP4Duration ); + + /* track level convenience functions */ + + MP4TrackId AddSystemsTrack(const char* type, uint32_t timeScale = 1000 ); + + MP4TrackId AddODTrack(); + + MP4TrackId AddSceneTrack(); + + MP4TrackId AddAudioTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint8_t audioType); + + MP4TrackId AddULawAudioTrack( + uint32_t timeScale); + + MP4TrackId AddALawAudioTrack( + uint32_t timeScale); + + MP4TrackId AddAC3AudioTrack( + uint32_t samplingRate, + uint8_t fscod, + uint8_t bsid, + uint8_t bsmod, + uint8_t acmod, + uint8_t lfeon, + uint8_t bit_rate_code); + + MP4TrackId AddEncAudioTrack( // ismacryp + uint32_t timeScale, + MP4Duration sampleDuration, + uint8_t audioType, + uint32_t scheme_type, + uint16_t scheme_version, + uint8_t key_ind_len, + uint8_t iv_len, + bool selective_enc, + const char *kms_uri, + bool use_ismacryp); + + void SetAmrVendor( + MP4TrackId trackId, + uint32_t vendor); + + void SetAmrDecoderVersion( + MP4TrackId trackId, + uint8_t decoderVersion); + + void SetAmrModeSet( + MP4TrackId trackId, + uint16_t modeSet); + uint16_t GetAmrModeSet(MP4TrackId trackId); + + MP4TrackId AddAmrAudioTrack( + uint32_t timeScale, + uint16_t modeSet, + uint8_t modeChangePeriod, + uint8_t framesPerSample, + bool isAmrWB); + + MP4TrackId AddHrefTrack(uint32_t timeScale, + MP4Duration sampleDuration, + const char *base_url); + + MP4TrackId AddMP4VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t videoType); + + MP4TrackId AddEncVideoTrack( // ismacryp + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t videoType, + mp4v2_ismacrypParams *icPp, + const char *oFormat); + + void SetH263Vendor( + MP4TrackId trackId, + uint32_t vendor); + + void SetH263DecoderVersion( + MP4TrackId trackId, + uint8_t decoderVersion); + + void SetH263Bitrates( + MP4TrackId, + uint32_t avgBitrate, + uint32_t maxBitrate); + + MP4TrackId AddH263VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t h263Level, + uint8_t h263Profile, + uint32_t avgBitrate, + uint32_t maxBitrate); + + MP4TrackId AddH264VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + uint8_t AVCProfileIndication, + uint8_t profile_compat, + uint8_t AVCLevelIndication, + uint8_t sampleLenFieldSizeMinusOne); + + MP4TrackId AddEncH264VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + MP4Atom *srcAtom, + mp4v2_ismacrypParams *icPp); + + void AddH264SequenceParameterSet(MP4TrackId trackId, + const uint8_t *pSequence, + uint16_t sequenceLen); + void AddH264PictureParameterSet(MP4TrackId trackId, + const uint8_t *pPicture, + uint16_t pictureLen); + MP4TrackId AddHintTrack(MP4TrackId refTrackId); + + MP4TrackId AddTextTrack(MP4TrackId refTrackId); + + /** Add a QuickTime chapter track. + * + * This function adds a chapter (text) track. + * The optional parameter <b>timescale</b> may be supplied to give the new + * chapter a specific timescale. Otherwise the chapter track will have + * the same timescale as the reference track defined in parameter refTrackId. + * + * @param refTrackId ID of the track that will reference the chapter track. + * @param timescale the timescale of the chapter track or 0 to use the + * timescale of track specified by <b>refTrackId</b>. + * + * @return ID of the created chapter track. + */ + MP4TrackId AddChapterTextTrack( + MP4TrackId refTrackId, + uint32_t timescale = 0 ); + + MP4TrackId AddSubtitleTrack(uint32_t timescale, + uint16_t width, + uint16_t height); + + MP4TrackId AddSubpicTrack(uint32_t timescale, + uint16_t width, + uint16_t height); + + MP4TrackId AddPixelAspectRatio(MP4TrackId trackId, uint32_t hSpacing, uint32_t vSpacing); + MP4TrackId AddColr(MP4TrackId trackId, uint16_t pri, uint16_t tran, uint16_t mat); + + /** Add a QuickTime chapter. + * + * @param chapterTrackId ID of chapter track or #MP4_INVALID_TRACK_ID + * if unknown. + * @param chapterDuration duration (in the timescale of the chapter track). + * @param chapterTitle title text for the chapter or NULL to use default + * title format ("Chapter %03d", n) where n is the chapter number. + */ + void AddChapter( + MP4TrackId chapterTrackId, + MP4Duration chapterDuration, + const char* chapterTitle = 0 ); + + /** Add a Nero chapter. + * + * @param chapterStart the start time of the chapter in 100 nanosecond units + * @param chapterTitle title text for the chapter or NULL to use default + * title format ("Chapter %03d", n) where n is the chapter number. + */ + void AddNeroChapter( + MP4Timestamp chapterStart, + const char* chapterTitle = 0 ); + + /*! Returns the ID of the track referencing the chapter track chapterTrackId. + * This function searches for a track of type MP4_AUDIO_TRACK_TYPE that references + * the track chapterTrackId through the atom "tref.chap". + * + * @param chapterTrackId the ID of the chapter track + * @param trackName receives the name of the referencing track if not null + * @param trackNameSize the size of the memory pointed to by trackName + * @return the ID if the track referencing the chapter track or MP4_INVALID_TRACK_ID + */ + MP4TrackId FindChapterReferenceTrack(MP4TrackId chapterTrackId, + char *trackName = 0, + int trackNameSize = 0); + + /*! Find the QuickTime chapter track in the current file. + * This function searches for a track of type text. + * + * @param trackName receives the name of the chapter track if not null + * @param trackNameSize the size of the memory pointed to by trackName + * @return the ID of the chapter track or MP4_INVALID_TRACK_ID + */ + MP4TrackId FindChapterTrack(char *trackName = 0, int trackNameSize = 0); + + /** Delete chapters. + * + * @param chapterType the type of chapters to delete: + * @li #MP4ChapterTypeAny (delete all known chapter types) + * @li #MP4ChapterTypeQt + * @li #MP4ChapterTypeNero + * @param chapterTrackId ID of the chapter track if known, + * or #MP4_INVALID_TRACK_ID. + * Only applies when <b>chapterType</b>=#MP4ChapterTypeQt. + * + * @return the type of deleted chapters + */ + MP4ChapterType DeleteChapters( + MP4ChapterType chapterType = MP4ChapterTypeQt, + MP4TrackId chapterTrackId = 0 ); + + /** Get list of chapters. + * + * @param chapterList address receiving array of chapter items. + * If a non-NULL is received the caller is responsible for freeing the + * memory with MP4Free(). + * @param chapterCount address receiving count of items in array. + * @param chapterType the type of chapters to read: + * @li #MP4ChapterTypeAny (any chapters, searched in order of Qt, Nero) + * @li #MP4ChapterTypeQt + * @li #MP4ChapterTypeNero + * + * @result the first type of chapters found. + */ + + MP4ChapterType GetChapters( + MP4Chapter_t** chapterList, + uint32_t* chapterCount, + MP4ChapterType fromChapterType = MP4ChapterTypeQt ); + + /** Set list of chapters. + * + * This functions sets the complete chapter list. + * If any chapters of the same type already exist they will first + * be deleted. + * + * @param chapterList array of chapters items. + * @param chapterCount count of items in array. + * @param chapterType type of chapters to write: + * @li #MP4ChapterTypeAny (chapters of all types are written) + * @li #MP4ChapterTypeQt + * @li #MP4ChapterTypeNero + * + * @return the type of chapters written. + */ + MP4ChapterType SetChapters( + MP4Chapter_t* chapterList, + uint32_t chapterCount, + MP4ChapterType toChapterType = MP4ChapterTypeQt ); + + /** Convert chapters to another type. + * + * This function converts existing chapters + * from one type to another type. + * Conversion from Nero to QuickTime or QuickTime to Nero is supported. + * + * @param toChapterType the chapter type to convert to: + * @li #MP4ChapterTypeQt (convert from Nero to Qt) + * @li #MP4ChapterTypeNero (convert from Qt to Nero) + * + * @return the chapter type before conversion or #MP4ChapterTypeNone + * if the source chapters do not exist + * or invalid <b>toChapterType</b> was specified. + */ + MP4ChapterType ConvertChapters(MP4ChapterType toChapterType = MP4ChapterTypeQt); + + /** Change the general timescale. + * + * This function changes the general timescale to the new timescale + * <b>value</b> by recalculating all values that depend on the timescale + * in "moov.mvhd". + * + * If the timescale is already equal to value nothing is done. + * + * @param value the new timescale. + */ + void ChangeMovieTimeScale(uint32_t timescale); + + MP4SampleId GetTrackNumberOfSamples(MP4TrackId trackId); + + const char* GetTrackType(MP4TrackId trackId); + + const char *GetTrackMediaDataName(MP4TrackId trackId); + bool GetTrackMediaDataOriginalFormat(MP4TrackId trackId, + char *originalFormat, uint32_t buflen); + MP4Duration GetTrackDuration(MP4TrackId trackId); + + uint32_t GetTrackTimeScale(MP4TrackId trackId); + void SetTrackTimeScale(MP4TrackId trackId, uint32_t value); + + // replacement to GetTrackAudioType and GetTrackVideoType + uint8_t GetTrackEsdsObjectTypeId(MP4TrackId trackId); + + uint8_t GetTrackAudioMpeg4Type(MP4TrackId trackId); + + MP4Duration GetTrackFixedSampleDuration(MP4TrackId trackId); + + double GetTrackVideoFrameRate(MP4TrackId trackId); + + int GetTrackAudioChannels(MP4TrackId trackId); + void GetTrackESConfiguration(MP4TrackId trackId, + uint8_t** ppConfig, uint32_t* pConfigSize); + void SetTrackESConfiguration(MP4TrackId trackId, + const uint8_t* pConfig, uint32_t configSize); + + void GetTrackVideoMetadata(MP4TrackId trackId, + uint8_t** ppConfig, uint32_t* pConfigSize); + void GetTrackH264SeqPictHeaders(MP4TrackId trackId, + uint8_t ***pSeqHeader, + uint32_t **pSeqHeaderSize, + uint8_t ***pPictHeader, + uint32_t **pPictHeaderSize); + const char* GetHintTrackSdp(MP4TrackId hintTrackId); + void SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString); + void AppendHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString); + + void MakeFtypAtom( + char* majorBrand, + uint32_t minorVersion, + char** compatibleBrands, + uint32_t compatibleBrandsCount ); + + // 3GPP specific functions + void Make3GPCompliant(const char* fileName, + char* majorBrand, + uint32_t minorVersion, + char** supportedBrands, + uint32_t supportedBrandsCount, + bool deleteIodsAtom); + + // ISMA specific functions + + // true if media track encrypted according to ismacryp + bool IsIsmaCrypMediaTrack(MP4TrackId trackId); + + void MakeIsmaCompliant(bool addIsmaComplianceSdp = true); + + void CreateIsmaIodFromParams( + uint8_t videoProfile, + uint32_t videoBitrate, + uint8_t* videoConfig, + uint32_t videoConfigLength, + uint8_t audioProfile, + uint32_t audioBitrate, + uint8_t* audioConfig, + uint32_t audioConfigLength, + uint8_t** ppBytes, + uint64_t* pNumBytes); + + // time convenience functions + + uint64_t ConvertFromMovieDuration( + MP4Duration duration, + uint32_t timeScale); + + uint64_t ConvertFromTrackTimestamp( + MP4TrackId trackId, + MP4Timestamp timeStamp, + uint32_t timeScale); + + MP4Timestamp ConvertToTrackTimestamp( + MP4TrackId trackId, + uint64_t timeStamp, + uint32_t timeScale); + + uint64_t ConvertFromTrackDuration( + MP4TrackId trackId, + MP4Duration duration, + uint32_t timeScale); + + MP4Duration ConvertToTrackDuration( + MP4TrackId trackId, + uint64_t duration, + uint32_t timeScale); + + // specialized operations + + void GetHintTrackRtpPayload( + MP4TrackId hintTrackId, + char** ppPayloadName = NULL, + uint8_t* pPayloadNumber = NULL, + uint16_t* pMaxPayloadSize = NULL, + char **ppEncodingParams = NULL); + + void SetHintTrackRtpPayload( + MP4TrackId hintTrackId, + const char* payloadName, + uint8_t* pPayloadNumber, + uint16_t maxPayloadSize, + const char *encoding_params, + bool include_rtp_map, + bool include_mpeg4_esid); + + MP4TrackId GetHintTrackReferenceTrackId( + MP4TrackId hintTrackId); + + void ReadRtpHint( + MP4TrackId hintTrackId, + MP4SampleId hintSampleId, + uint16_t* pNumPackets = NULL); + + uint16_t GetRtpHintNumberOfPackets( + MP4TrackId hintTrackId); + + int8_t GetRtpPacketBFrame( + MP4TrackId hintTrackId, + uint16_t packetIndex); + + int32_t GetRtpPacketTransmitOffset( + MP4TrackId hintTrackId, + uint16_t packetIndex); + + void ReadRtpPacket( + MP4TrackId hintTrackId, + uint16_t packetIndex, + uint8_t** ppBytes, + uint32_t* pNumBytes, + uint32_t ssrc = 0, + bool includeHeader = true, + bool includePayload = true); + + MP4Timestamp GetRtpTimestampStart( + MP4TrackId hintTrackId); + + void SetRtpTimestampStart( + MP4TrackId hintTrackId, + MP4Timestamp rtpStart); + + void AddRtpHint( + MP4TrackId hintTrackId, + bool isBframe, + uint32_t timestampOffset); + + void AddRtpPacket( + MP4TrackId hintTrackId, + bool setMbit, + int32_t transmitOffset); + + void AddRtpImmediateData( + MP4TrackId hintTrackId, + const uint8_t* pBytes, + uint32_t numBytes); + + void AddRtpSampleData( + MP4TrackId hintTrackId, + MP4SampleId sampleId, + uint32_t dataOffset, + uint32_t dataLength); + + void AddRtpESConfigurationPacket( + MP4TrackId hintTrackId); + + void WriteRtpHint( + MP4TrackId hintTrackId, + MP4Duration duration, + bool isSyncSample); + + uint8_t AllocRtpPayloadNumber(); + + // edit list related + + char* MakeTrackEditName( + MP4TrackId trackId, + MP4EditId editId, + const char* name); + + MP4EditId AddTrackEdit( + MP4TrackId trackId, + MP4EditId editId = MP4_INVALID_EDIT_ID); + + void DeleteTrackEdit( + MP4TrackId trackId, + MP4EditId editId); + + uint32_t GetTrackNumberOfEdits( + MP4TrackId trackId); + + MP4Timestamp GetTrackEditStart( + MP4TrackId trackId, + MP4EditId editId); + + MP4Duration GetTrackEditTotalDuration( + MP4TrackId trackId, + MP4EditId editId); + + MP4Timestamp GetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId); + + void SetTrackEditMediaStart( + MP4TrackId trackId, + MP4EditId editId, + MP4Timestamp startTime); + + MP4Duration GetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId); + + void SetTrackEditDuration( + MP4TrackId trackId, + MP4EditId editId, + MP4Duration duration); + + bool GetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId); + + void SetTrackEditDwell( + MP4TrackId trackId, + MP4EditId editId, + bool dwell); + + MP4SampleId GetSampleIdFromEditTime( + MP4TrackId trackId, + MP4Timestamp when, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL); + + /* "protected" interface to be used only by friends in library */ + + uint64_t GetPosition( File* file = NULL ); + void SetPosition( uint64_t pos, File* file = NULL ); + uint64_t GetSize( File* file = NULL ); + + void ReadBytes( uint8_t* buf, uint32_t bufsiz, File* file = NULL ); + void PeekBytes( uint8_t* buf, uint32_t bufsiz, File* file = NULL ); + + uint64_t ReadUInt(uint8_t size); + uint8_t ReadUInt8(); + uint16_t ReadUInt16(); + uint32_t ReadUInt24(); + uint32_t ReadUInt32(); + uint64_t ReadUInt64(); + float ReadFixed16(); + float ReadFixed32(); + float ReadFloat(); + char* ReadString(); + char* ReadCountedString( + uint8_t charSize = 1, bool allowExpandedCount = false, uint8_t fixedLength = 0); + uint64_t ReadBits(uint8_t numBits); + void FlushReadBits(); + uint32_t ReadMpegLength(); + + + void WriteBytes( uint8_t* buf, uint32_t bufsiz, File* file = NULL ); + void WriteUInt8(uint8_t value); + void WriteUInt16(uint16_t value); + void WriteUInt24(uint32_t value); + void WriteUInt32(uint32_t value); + void WriteUInt64(uint64_t value); + void WriteFixed16(float value); + void WriteFixed32(float value); + void WriteFloat(float value); + void WriteString(char* string); + void WriteCountedString(char* string, + uint8_t charSize = 1, + bool allowExpandedCount = false, + uint32_t fixedLength = 0); + void WriteBits(uint64_t bits, uint8_t numBits); + void PadWriteBits(uint8_t pad = 0); + void FlushWriteBits(); + void WriteMpegLength(uint32_t value, bool compact = false); + + void EnableMemoryBuffer( + uint8_t* pBytes = NULL, uint64_t numBytes = 0); + void DisableMemoryBuffer( + uint8_t** ppBytes = NULL, uint64_t* pNumBytes = NULL); + + bool IsWriteMode(); + + MP4Track* GetTrack(MP4TrackId trackId); + + void UpdateDuration(MP4Duration duration); + + MP4Atom* FindAtom(const char* name); + + MP4Atom* AddChildAtom( + const char* parentName, + const char* childName); + + MP4Atom* AddChildAtom( + MP4Atom* pParentAtom, + const char* childName); + + MP4Atom* InsertChildAtom( + const char* parentName, + const char* childName, + uint32_t index); + + MP4Atom* InsertChildAtom( + MP4Atom* pParentAtom, + const char* childName, + uint32_t index); + + MP4Atom* AddDescendantAtoms( + const char* ancestorName, + const char* childName); + + MP4Atom* AddDescendantAtoms( + MP4Atom* pAncestorAtom, + const char* childName); + +protected: + void Init(); + void Open( const char* name, File::Mode mode, const MP4FileProvider* provider ); + void ReadFromFile(); + void GenerateTracks(); + void BeginWrite(); + void FinishWrite(uint32_t options); + void CacheProperties(); + void RewriteMdat( File& src, File& dst ); + bool ShallHaveIods(); + + void Rename(const char* existingFileName, const char* newFileName); + + void ProtectWriteOperation(const char* file, int line, const char *func); + + void FindIntegerProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + void FindFloatProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + void FindStringProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + void FindBytesProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + bool FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + + MP4TrackId AddVideoTrackDefault( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height, + const char *videoType); + MP4TrackId AddCntlTrackDefault( + uint32_t timeScale, + MP4Duration sampleDuration, + const char *videoType); + void AddTrackToIod(MP4TrackId trackId); + + void RemoveTrackFromIod(MP4TrackId trackId, bool shallHaveIods = true); + + void AddTrackToOd(MP4TrackId trackId); + + void RemoveTrackFromOd(MP4TrackId trackId); + + void GetTrackReferenceProperties(const char* trefName, + MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty); + + void AddTrackReference(const char* trefName, MP4TrackId refTrackId); + + uint32_t FindTrackReference(const char* trefName, MP4TrackId refTrackId); + + void RemoveTrackReference(const char* trefName, MP4TrackId refTrackId); + + void AddDataReference(MP4TrackId trackId, const char* url); + + char* MakeTrackName(MP4TrackId trackId, const char* name); + + uint8_t ConvertTrackTypeToStreamType(const char* trackType); + + void CreateIsmaIodFromFile( + MP4TrackId odTrackId, + MP4TrackId sceneTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + uint8_t** ppBytes, + uint64_t* pNumBytes); + + void CreateESD( + MP4DescriptorProperty* pEsProperty, + uint32_t esid, + uint8_t objectType, + uint8_t streamType, + uint32_t bufferSize, + uint32_t bitrate, + const uint8_t* pConfig, + uint32_t configLength, + char* url); + + void CreateIsmaODUpdateCommandFromFileForFile( + MP4TrackId odTrackId, + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + uint8_t** ppBytes, + uint64_t* pNumBytes); + + void CreateIsmaODUpdateCommandFromFileForStream( + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + uint8_t** ppBytes, + uint64_t* pNumBytes); + + void CreateIsmaODUpdateCommandForStream( + MP4DescriptorProperty* pAudioEsdProperty, + MP4DescriptorProperty* pVideoEsdProperty, + uint8_t** ppBytes, + uint64_t* pNumBytes); + + void CreateIsmaSceneCommand( + bool hasAudio, + bool hasVideo, + uint8_t** ppBytes, + uint64_t* pNumBytes); + +protected: + File* m_file; + uint64_t m_fileOriginalSize; + uint32_t m_createFlags; + + MP4Atom* m_pRootAtom; + MP4Integer32Array m_trakIds; + MP4TrackArray m_pTracks; + MP4TrackId m_odTrackId; + bool m_useIsma; + + // cached properties + MP4IntegerProperty* m_pModificationProperty; + MP4Integer32Property* m_pTimeScaleProperty; + MP4IntegerProperty* m_pDurationProperty; + + // read/write in memory + uint8_t* m_memoryBuffer; + uint64_t m_memoryBufferPosition; + uint64_t m_memoryBufferSize; + + // bit read/write buffering + uint8_t m_numReadBits; + uint8_t m_bufReadBits; + uint8_t m_numWriteBits; + uint8_t m_bufWriteBits; + + char m_trakName[1024]; + char *m_editName; + + private: + MP4File ( const MP4File &src ); + MP4File &operator= ( const MP4File &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4FILE_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file_io.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file_io.cpp new file mode 100644 index 00000000..5de29104 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4file_io.cpp @@ -0,0 +1,581 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +// MP4File low level IO support + +uint64_t MP4File::GetPosition( File* file ) +{ + if( m_memoryBuffer ) + return m_memoryBufferPosition; + + if( !file ) + file = m_file; + + ASSERT( file ); + return file->position; +} + +void MP4File::SetPosition( uint64_t pos, File* file ) +{ + if( m_memoryBuffer ) { + if( pos >= m_memoryBufferSize ) + throw new Exception( "position out of range", __FILE__, __LINE__, __FUNCTION__ ); + m_memoryBufferPosition = pos; + return; + } + + if( !file ) + file = m_file; + + ASSERT( file ); + if( file->seek( pos )) + throw new PlatformException( "seek failed", sys::getLastError(), __FILE__, __LINE__, __FUNCTION__ ); +} + +uint64_t MP4File::GetSize( File* file ) +{ + if( m_memoryBuffer ) + return m_memoryBufferSize; + + if( !file ) + file = m_file; + + ASSERT( file ); + return file->size; +} + +void MP4File::ReadBytes( uint8_t* buf, uint32_t bufsiz, File* file ) +{ + if( bufsiz == 0 ) + return; + + ASSERT( buf ); + WARNING( m_numReadBits > 0 ); + + if( m_memoryBuffer ) { + if( m_memoryBufferPosition + bufsiz > m_memoryBufferSize ) + throw new Exception( "not enough bytes, reached end-of-memory", __FILE__, __LINE__, __FUNCTION__ ); + memcpy( buf, &m_memoryBuffer[m_memoryBufferPosition], bufsiz ); + m_memoryBufferPosition += bufsiz; + return; + } + + if( !file ) + file = m_file; + + ASSERT( file ); + File::Size nin; + if( file->read( buf, bufsiz, nin )) + throw new PlatformException( "read failed", sys::getLastError(), __FILE__, __LINE__, __FUNCTION__ ); + if( nin != bufsiz ) + throw new Exception( "not enough bytes, reached end-of-file", __FILE__, __LINE__, __FUNCTION__ ); +} + +void MP4File::PeekBytes( uint8_t* buf, uint32_t bufsiz, File* file ) +{ + const uint64_t pos = GetPosition( file ); + ReadBytes( buf, bufsiz, file ); + SetPosition( pos, file ); +} + +void MP4File::EnableMemoryBuffer( uint8_t* pBytes, uint64_t numBytes ) +{ + ASSERT( !m_memoryBuffer ); + + if (pBytes) { + m_memoryBuffer = pBytes; + m_memoryBufferSize = numBytes; + } else { + if (numBytes) { + m_memoryBufferSize = numBytes; + } else { + m_memoryBufferSize = 4096; + } + m_memoryBuffer = (uint8_t*)MP4Malloc(m_memoryBufferSize); + } + m_memoryBufferPosition = 0; +} + +void MP4File::DisableMemoryBuffer( uint8_t** ppBytes, uint64_t* pNumBytes ) +{ + ASSERT(m_memoryBuffer != NULL); + + if (ppBytes) { + *ppBytes = m_memoryBuffer; + } + if (pNumBytes) { + *pNumBytes = m_memoryBufferPosition; + } + + m_memoryBuffer = NULL; + m_memoryBufferSize = 0; + m_memoryBufferPosition = 0; +} + +void MP4File::WriteBytes( uint8_t* buf, uint32_t bufsiz, File* file ) +{ + ASSERT( m_numWriteBits == 0 || m_numWriteBits >= 8 ); + + if( !buf || bufsiz == 0 ) + return; + + if( m_memoryBuffer ) { + if( m_memoryBufferPosition + bufsiz > m_memoryBufferSize ) { + m_memoryBufferSize = 2 * (m_memoryBufferSize + bufsiz); + m_memoryBuffer = (uint8_t*)MP4Realloc( m_memoryBuffer, m_memoryBufferSize ); + } + memcpy( &m_memoryBuffer[m_memoryBufferPosition], buf, bufsiz ); + m_memoryBufferPosition += bufsiz; + return; + } + + if( !file ) + file = m_file; + + ASSERT( file ); + File::Size nout; + if( file->write( buf, bufsiz, nout )) + throw new PlatformException( "write failed", sys::getLastError(), __FILE__, __LINE__, __FUNCTION__ ); + if( nout != bufsiz ) + throw new Exception( "not all bytes written", __FILE__, __LINE__, __FUNCTION__ ); +} + +uint64_t MP4File::ReadUInt(uint8_t size) +{ + switch (size) { + case 1: + return ReadUInt8(); + case 2: + return ReadUInt16(); + case 3: + return ReadUInt24(); + case 4: + return ReadUInt32(); + case 8: + return ReadUInt64(); + default: + ASSERT(false); + return 0; + } +} + +uint8_t MP4File::ReadUInt8() +{ + uint8_t data; + ReadBytes(&data, 1); + return data; +} + +void MP4File::WriteUInt8(uint8_t value) +{ + WriteBytes(&value, 1); +} + +uint16_t MP4File::ReadUInt16() +{ + uint8_t data[2]; + ReadBytes(&data[0], 2); + return ((data[0] << 8) | data[1]); +} + +void MP4File::WriteUInt16(uint16_t value) +{ + uint8_t data[2]; + data[0] = (value >> 8) & 0xFF; + data[1] = value & 0xFF; + WriteBytes(data, 2); +} + +uint32_t MP4File::ReadUInt24() +{ + uint8_t data[3]; + ReadBytes(&data[0], 3); + return ((data[0] << 16) | (data[1] << 8) | data[2]); +} + +void MP4File::WriteUInt24(uint32_t value) +{ + uint8_t data[3]; + data[0] = (value >> 16) & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[2] = value & 0xFF; + WriteBytes(data, 3); +} + +uint32_t MP4File::ReadUInt32() +{ + uint8_t data[4]; + ReadBytes(&data[0], 4); + return ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]); +} + +void MP4File::WriteUInt32(uint32_t value) +{ + uint8_t data[4]; + data[0] = (value >> 24) & 0xFF; + data[1] = (value >> 16) & 0xFF; + data[2] = (value >> 8) & 0xFF; + data[3] = value & 0xFF; + WriteBytes(data, 4); +} + +uint64_t MP4File::ReadUInt64() +{ + uint8_t data[8]; + uint64_t result = 0; + uint64_t temp; + + ReadBytes(&data[0], 8); + + for (int i = 0; i < 8; i++) { + temp = data[i]; + result |= temp << ((7 - i) * 8); + } + return result; +} + +void MP4File::WriteUInt64(uint64_t value) +{ + uint8_t data[8]; + + for (int i = 7; i >= 0; i--) { + data[i] = value & 0xFF; + value >>= 8; + } + WriteBytes(data, 8); +} + +float MP4File::ReadFixed16() +{ + uint8_t iPart = ReadUInt8(); + uint8_t fPart = ReadUInt8(); + + return iPart + (((float)fPart) / 0x100); +} + +void MP4File::WriteFixed16(float value) +{ + if (value >= 0x100) { + ostringstream msg; + msg << value << " out of range"; + throw new PlatformException(msg.str().c_str(), ERANGE, __FILE__, __LINE__, __FUNCTION__); + } + + uint8_t iPart = (uint8_t)value; + uint8_t fPart = (uint8_t)((value - iPart) * 0x100); + + WriteUInt8(iPart); + WriteUInt8(fPart); +} + +float MP4File::ReadFixed32() +{ + uint16_t iPart = ReadUInt16(); + uint16_t fPart = ReadUInt16(); + + return iPart + (((float)fPart) / 0x10000); +} + +void MP4File::WriteFixed32(float value) +{ + if (value >= 0x10000) { + ostringstream msg; + msg << value << " out of range"; + throw new PlatformException(msg.str().c_str(), ERANGE, __FILE__, __LINE__, __FUNCTION__); + } + + uint16_t iPart = (uint16_t)value; + uint16_t fPart = (uint16_t)((value - iPart) * 0x10000); + + WriteUInt16(iPart); + WriteUInt16(fPart); +} + +float MP4File::ReadFloat() +{ + union { + float f; + uint32_t i; + } u; + + u.i = ReadUInt32(); + return u.f; +} + +void MP4File::WriteFloat(float value) +{ + union { + float f; + uint32_t i; + } u; + + u.f = value; + WriteUInt32(u.i); +} + +char* MP4File::ReadString() +{ + uint32_t length = 0; + uint32_t alloced = 64; + char* data = (char*)MP4Malloc(alloced); + + do { + if (length == alloced) { + data = (char*)MP4Realloc(data, alloced * 2); + if (data == NULL) return NULL; + alloced *= 2; + } + ReadBytes((uint8_t*)&data[length], 1); + length++; + } while (data[length - 1] != 0); + + data = (char*)MP4Realloc(data, length); + return data; +} + +void MP4File::WriteString(char* string) +{ + if (string == NULL) { + uint8_t zero = 0; + WriteBytes(&zero, 1); + } else { + WriteBytes((uint8_t*)string, (uint32_t)strlen(string) + 1); + } +} + +char* MP4File::ReadCountedString(uint8_t charSize, bool allowExpandedCount, uint8_t fixedLength) +{ + uint32_t charLength; + if (allowExpandedCount) { + uint8_t b; + uint32_t ix = 0; + charLength = 0; + do { + b = ReadUInt8(); + charLength += b; + ix++; + if (ix > 25) + throw new PlatformException("Counted string too long 25 * 255",ERANGE, + __FILE__, __LINE__, __FUNCTION__); + } while (b == 255); + } else { + charLength = ReadUInt8(); + } + + if (fixedLength && (charLength > fixedLength)) { + /* + * The counted length of this string is greater than the + * maxiumum fixed length, so truncate the string to the + * maximum fixed length amount (take 1 byte away from the + * fixedlength since we've already sacrificed one byte for + * reading the counted length, and there has been a bug where + * a non counted string has been used in the place of a + * counted string). + */ + WARNING(charLength > fixedLength); + charLength = fixedLength - 1U; + } + + uint32_t byteLength = charLength * charSize; + char* data = (char*)MP4Malloc(byteLength + 1); + if (byteLength > 0) { + ReadBytes((uint8_t*)data, byteLength); + } + data[byteLength] = '\0'; + + // read padding + if (fixedLength) { + const uint8_t padsize = fixedLength - byteLength -1U; + if( padsize ) { + uint8_t* padbuf = (uint8_t*)malloc( padsize ); + ReadBytes( padbuf, padsize ); + free( padbuf ); + } + } + + return data; +} + +void MP4File::WriteCountedString(char* string, + uint8_t charSize, bool allowExpandedCount, + uint32_t fixedLength) +{ + uint32_t byteLength; + uint8_t zero[1]; + + if (string) { + byteLength = (uint32_t)strlen(string); + if (fixedLength && (byteLength >= fixedLength)) { + byteLength = fixedLength-1; + } + } + else { + byteLength = 0; + } + uint32_t charLength = byteLength / charSize; + + if (allowExpandedCount) { + while (charLength >= 0xFF) { + WriteUInt8(0xFF); + charLength -= 0xFF; + } + // Write the count + WriteUInt8(charLength); + } else { + if (charLength > 255) { + ostringstream msg; + msg << "Length is " << charLength; + throw new PlatformException(msg.str().c_str(), ERANGE, __FILE__, __LINE__, __FUNCTION__); + } + // Write the count + WriteUInt8(charLength); + } + + if (byteLength > 0) { + // Write the string (or the portion that we want to write) + WriteBytes((uint8_t*)string, byteLength); + } + + // Write any padding if this is a fixed length counted string + if (fixedLength) { + zero[0] = 0; + while (byteLength < fixedLength-1U) { + WriteBytes(zero, 1); + byteLength++; + } + } +} + +uint64_t MP4File::ReadBits(uint8_t numBits) +{ + ASSERT(numBits > 0); + ASSERT(numBits <= 64); + + uint64_t bits = 0; + + for (uint8_t i = numBits; i > 0; i--) { + if (m_numReadBits == 0) { + ReadBytes(&m_bufReadBits, 1); + m_numReadBits = 8; + } + bits = (bits << 1) | ((m_bufReadBits >> (--m_numReadBits)) & 1); + } + + return bits; +} + +void MP4File::FlushReadBits() +{ + // eat any remaining bits in the read buffer + m_numReadBits = 0; +} + +void MP4File::WriteBits(uint64_t bits, uint8_t numBits) +{ + ASSERT(numBits <= 64); + + for (uint8_t i = numBits; i > 0; i--) { + m_bufWriteBits |= + (((bits >> (i - 1)) & 1) << (8 - ++m_numWriteBits)); + + if (m_numWriteBits == 8) { + FlushWriteBits(); + } + } +} + +void MP4File::PadWriteBits(uint8_t pad) +{ + if (m_numWriteBits) { + WriteBits(pad ? 0xFF : 0x00, 8 - m_numWriteBits); + } +} + +void MP4File::FlushWriteBits() +{ + if (m_numWriteBits > 0) { + WriteBytes(&m_bufWriteBits, 1); + m_numWriteBits = 0; + m_bufWriteBits = 0; + } +} + +uint32_t MP4File::ReadMpegLength() +{ + uint32_t length = 0; + uint8_t numBytes = 0; + uint8_t b; + + do { + b = ReadUInt8(); + length = (length << 7) | (b & 0x7F); + numBytes++; + } while ((b & 0x80) && numBytes < 4); + + return length; +} + +void MP4File::WriteMpegLength(uint32_t value, bool compact) +{ + if (value > 0x0FFFFFFF) { + ostringstream msg; + msg << "out of range: " << value; + throw new PlatformException(msg.str().c_str(), ERANGE, __FILE__, __LINE__, __FUNCTION__ ); + } + + int8_t numBytes; + + if (compact) { + if (value <= 0x7F) { + numBytes = 1; + } else if (value <= 0x3FFF) { + numBytes = 2; + } else if (value <= 0x1FFFFF) { + numBytes = 3; + } else { + numBytes = 4; + } + } else { + numBytes = 4; + } + + int8_t i = numBytes; + do { + i--; + uint8_t b = (value >> (i * 7)) & 0x7F; + if (i > 0) { + b |= 0x80; + } + WriteUInt8(b); + } while (i > 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4info.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4info.cpp new file mode 100644 index 00000000..44bf45e5 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4info.cpp @@ -0,0 +1,625 @@ +/* + * 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-2002. All Rights Reserved. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Bill May [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +static char* PrintAudioInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + static const char* mpeg4AudioNames[] = { + "MPEG-4 AAC main", + "MPEG-4 AAC LC", + "MPEG-4 AAC SSR", + "MPEG-4 AAC LTP", + "MPEG-4 AAC HE", + "MPEG-4 AAC Scalable", + "MPEG-4 TwinVQ", + "MPEG-4 CELP", + "MPEG-4 HVXC", + NULL, NULL, + "MPEG-4 TTSI", + "MPEG-4 Main Synthetic", + "MPEG-4 Wavetable Syn", + "MPEG-4 General MIDI", + "MPEG-4 Algo Syn and Audio FX", + "MPEG-4 ER AAC LC", + NULL, + "MPEG-4 ER AAC LTP", + "MPEG-4 ER AAC Scalable", + "MPEG-4 ER TwinVQ", + "MPEG-4 ER BSAC", + "MPEG-4 ER ACC LD", + "MPEG-4 ER CELP", + "MPEG-4 ER HVXC", + "MPEG-4 ER HILN", + "MPEG-4 ER Parametric", + "MPEG-4 SSC", + "MPEG-4 PS", + "MPEG-4 MPEG Surround", + NULL, + "MPEG-4 Layer-1", + "MPEG-4 Layer-2", + "MPEG-4 Layer-3", + "MPEG-4 DST", + "MPEG-4 Audio Lossless", + "MPEG-4 SLS", + "MPEG-4 SLS non-core", + }; + + static const uint8_t mpegAudioTypes[] = { + MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, // 0x66 + MP4_MPEG2_AAC_LC_AUDIO_TYPE, // 0x67 + MP4_MPEG2_AAC_SSR_AUDIO_TYPE, // 0x68 + MP4_MPEG2_AUDIO_TYPE, // 0x69 + MP4_MPEG1_AUDIO_TYPE, // 0x6B + // private types + MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE, + MP4_VORBIS_AUDIO_TYPE, + MP4_ALAW_AUDIO_TYPE, + MP4_ULAW_AUDIO_TYPE, + MP4_G723_AUDIO_TYPE, + MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE, + }; + static const char* mpegAudioNames[] = { + "MPEG-2 AAC Main", + "MPEG-2 AAC LC", + "MPEG-2 AAC SSR", + "MPEG-2 Audio (13818-3)", + "MPEG-1 Audio (11172-3)", + // private types + "PCM16 (little endian)", + "Vorbis", + "G.711 aLaw", + "G.711 uLaw", + "G.723.1", + "PCM16 (big endian)", + }; + uint8_t numMpegAudioTypes = + sizeof(mpegAudioTypes) / sizeof(uint8_t); + + const char* typeName = "Unknown"; + bool foundType = false; + uint8_t type = 0; + const char *media_data_name; + + media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); + + if (media_data_name == NULL) { + typeName = "Unknown - no media data name"; + } else if (strcasecmp(media_data_name, "samr") == 0) { + typeName = "AMR"; + foundType = true; + } else if (strcasecmp(media_data_name, "sawb") == 0) { + typeName = "AMR-WB"; + foundType = true; + } else if (strcasecmp(media_data_name, "mp4a") == 0) { + + type = MP4GetTrackEsdsObjectTypeId(mp4File, trackId); + switch (type) { + case MP4_INVALID_AUDIO_TYPE: + typeName = "AAC from .mov"; + foundType = true; + break; + case MP4_MPEG4_AUDIO_TYPE: { + + type = MP4GetTrackAudioMpeg4Type(mp4File, trackId); + if (type == MP4_MPEG4_INVALID_AUDIO_TYPE || + type > NUM_ELEMENTS_IN_ARRAY(mpeg4AudioNames) || + mpeg4AudioNames[type - 1] == NULL) { + typeName = "MPEG-4 Unknown Profile"; + } else { + typeName = mpeg4AudioNames[type - 1]; + foundType = true; + } + break; + } + // fall through + default: + for (uint8_t i = 0; i < numMpegAudioTypes; i++) { + if (type == mpegAudioTypes[i]) { + typeName = mpegAudioNames[i]; + foundType = true; + break; + } + } + } + } else { + typeName = media_data_name; + foundType = true; + } + + uint32_t timeScale = + MP4GetTrackTimeScale(mp4File, trackId); + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + double(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + + uint32_t avgBitRate = + MP4GetTrackBitRate(mp4File, trackId); + + char *sInfo = (char*)MP4Malloc(256); + + // type duration avgBitrate samplingFrequency + if (foundType) + snprintf(sInfo, 256, + "%u\taudio\t%s%s, %.3f secs, %u kbps, %u Hz\n", + trackId, + MP4IsIsmaCrypMediaTrack(mp4File, trackId) ? "enca - " : "", + typeName, + msDuration / 1000.0, + (avgBitRate + 500) / 1000, + timeScale); + else + snprintf(sInfo, 256, + "%u\taudio\t%s%s(%u), %.3f secs, %u kbps, %u Hz\n", + trackId, + MP4IsIsmaCrypMediaTrack(mp4File, trackId) ? "enca - " : "", + typeName, + type, + msDuration / 1000.0, + (avgBitRate + 500) / 1000, + timeScale); + + return sInfo; +} +static const struct { + uint8_t profile; + const char *name; +} VisualProfileToName[] = { + { MPEG4_SP_L1, "MPEG-4 Simple @ L1"}, + { MPEG4_SP_L2, "MPEG-4 Simple @ L2" }, + { MPEG4_SP_L3, "MPEG-4 Simple @ L3" }, + { MPEG4_SP_L0, "MPEG-4 Simple @ L0" }, + { MPEG4_SSP_L1, "MPEG-4 Simple Scalable @ L1"}, + { MPEG4_SSP_L2, "MPEG-4 Simple Scalable @ L2" }, + { MPEG4_CP_L1, "MPEG-4 Core @ L1"}, + { MPEG4_CP_L2, "MPEG-4 Core @ L2"}, + { MPEG4_MP_L2, "MPEG-4 Main @ L2"}, + { MPEG4_MP_L3, "MPEG-4 Main @ L3"}, + { MPEG4_MP_L4, "MPEG-4 Main @ L4"}, + { MPEG4_NBP_L2, "MPEG-4 N-bit @ L2"}, + { MPEG4_STP_L1, "MPEG-4 Scalable Texture @ L1"}, + { MPEG4_SFAP_L1, "MPEG-4 Simple Face Anim @ L1"}, + { MPEG4_SFAP_L2, "MPEG-4 Simple Face Anim @ L2"}, + { MPEG4_SFBAP_L1, "MPEG-4 Simple FBA @ L1"}, + { MPEG4_SFBAP_L2, "MPEG-4 Simple FBA @ L2"}, + { MPEG4_BATP_L1, "MPEG-4 Basic Anim Text @ L1"}, + { MPEG4_BATP_L2, "MPEG-4 Basic Anim Text @ L2"}, + { MPEG4_HP_L1, "MPEG-4 Hybrid @ L1"}, + { MPEG4_HP_L2, "MPEG-4 Hybrid @ L2"}, + { MPEG4_ARTSP_L1, "MPEG-4 Adv RT Simple @ L1"}, + { MPEG4_ARTSP_L2, "MPEG-4 Adv RT Simple @ L2"}, + { MPEG4_ARTSP_L3, "MPEG-4 Adv RT Simple @ L3"}, + { MPEG4_ARTSP_L4, "MPEG-4 Adv RT Simple @ L4"}, + { MPEG4_CSP_L1, "MPEG-4 Core Scalable @ L1"}, + { MPEG4_CSP_L2, "MPEG-4 Core Scalable @ L2"}, + { MPEG4_CSP_L3, "MPEG-4 Core Scalable @ L3"}, + { MPEG4_ACEP_L1, "MPEG-4 Adv Coding Efficieny @ L1"}, + { MPEG4_ACEP_L2, "MPEG-4 Adv Coding Efficieny @ L2"}, + { MPEG4_ACEP_L3, "MPEG-4 Adv Coding Efficieny @ L3"}, + { MPEG4_ACEP_L4, "MPEG-4 Adv Coding Efficieny @ L4"}, + { MPEG4_ACP_L1, "MPEG-4 Adv Core Profile @ L1"}, + { MPEG4_ACP_L2, "MPEG-4 Adv Core Profile @ L2"}, + { MPEG4_AST_L1, "MPEG-4 Adv Scalable Texture @ L1"}, + { MPEG4_AST_L2, "MPEG-4 Adv Scalable Texture @ L2"}, + { MPEG4_AST_L3, "MPEG-4 Adv Scalable Texture @ L3"}, + { MPEG4_S_STUDIO_P_L1, "MPEG-4 Simple Studio @ L1"}, + { MPEG4_S_STUDIO_P_L2, "MPEG-4 Simple Studio @ L2"}, + { MPEG4_S_STUDIO_P_L3, "MPEG-4 Simple Studio @ L3"}, + { MPEG4_S_STUDIO_P_L4, "MPEG-4 Simple Studio @ L4"}, + { MPEG4_C_STUDIO_P_L1, "MPEG-4 Core Studio @ L1"}, + { MPEG4_C_STUDIO_P_L2, "MPEG-4 Core Studio @ L2"}, + { MPEG4_C_STUDIO_P_L3, "MPEG-4 Core Studio @ L3"}, + { MPEG4_C_STUDIO_P_L4, "MPEG-4 Core Studio @ L4"}, + { MPEG4_ASP_L0, "MPEG-4 Adv Simple@L0"}, + { MPEG4_ASP_L1, "MPEG-4 Adv Simple@L1"}, + { MPEG4_ASP_L2, "MPEG-4 Adv Simple@L2"}, + { MPEG4_ASP_L3, "MPEG-4 Adv Simple@L3"}, + { MPEG4_ASP_L4, "MPEG-4 Adv Simple@L4"}, + { MPEG4_ASP_L5, "MPEG-4 Adv Simple@L5"}, + { MPEG4_ASP_L3B, "MPEG-4 Adv Simple@L3b"}, + { MPEG4_FGSP_L0, "MPEG-4 FGS @ L0" }, + { MPEG4_FGSP_L1, "MPEG-4 FGS @ L1" }, + { MPEG4_FGSP_L2, "MPEG-4 FGS @ L2" }, + { MPEG4_FGSP_L3, "MPEG-4 FGS @ L3" }, + { MPEG4_FGSP_L4, "MPEG-4 FGS @ L4" }, + { MPEG4_FGSP_L5, "MPEG-4 FGS @ L5" } +}; + +static const char *Mpeg4VisualProfileName (uint8_t visual_profile) +{ + size_t size = sizeof(VisualProfileToName) / sizeof(*VisualProfileToName); + + for (size_t ix = 0; ix < size; ix++) { + if (visual_profile == VisualProfileToName[ix].profile) { + return (VisualProfileToName[ix].name); + } + } + return (NULL); +} +static char* PrintVideoInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + + static const uint8_t mpegVideoTypes[] = { + MP4_MPEG2_SIMPLE_VIDEO_TYPE, // 0x60 + MP4_MPEG2_MAIN_VIDEO_TYPE, // 0x61 + MP4_MPEG2_SNR_VIDEO_TYPE, // 0x62 + MP4_MPEG2_SPATIAL_VIDEO_TYPE, // 0x63 + MP4_MPEG2_HIGH_VIDEO_TYPE, // 0x64 + MP4_MPEG2_442_VIDEO_TYPE, // 0x65 + MP4_MPEG1_VIDEO_TYPE, // 0x6A + MP4_JPEG_VIDEO_TYPE, // 0x6C + MP4_YUV12_VIDEO_TYPE, + MP4_H263_VIDEO_TYPE, + MP4_H261_VIDEO_TYPE, + }; + static const char* mpegVideoNames[] = { + "MPEG-2 Simple", + "MPEG-2 Main", + "MPEG-2 SNR", + "MPEG-2 Spatial", + "MPEG-2 High", + "MPEG-2 4:2:2", + "MPEG-1", + "JPEG", + "YUV12", + "H.263", + "H.261", + }; + uint8_t numMpegVideoTypes = + sizeof(mpegVideoTypes) / sizeof(uint8_t); + bool foundTypeName = false; + const char* typeName = "Unknown"; + + const char *media_data_name; + char originalFormat[8]; + char oformatbuffer[32]; + originalFormat[0] = 0; + *oformatbuffer = 0; + uint8_t type = 0; + + media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); + // encv 264b + if (strcasecmp(media_data_name, "encv") == 0) { + if (MP4GetTrackMediaDataOriginalFormat(mp4File, + trackId, + originalFormat, + sizeof(originalFormat)) == false) + media_data_name = NULL; + + } + + char typebuffer[80]; + if (media_data_name == NULL) { + typeName = "Unknown - no media data name"; + foundTypeName = true; + } else if ((strcasecmp(media_data_name, "avc1") == 0) || + (strcasecmp(originalFormat, "264b") == 0)) { + // avc + uint8_t profile, level; + char profileb[20], levelb[20]; + if (MP4GetTrackH264ProfileLevel(mp4File, trackId, + &profile, &level)) { + if (profile == 66) { + strcpy(profileb, "Baseline"); + } else if (profile == 77) { + strcpy(profileb, "Main"); + } else if (profile == 88) { + strcpy(profileb, "Extended"); + } else if (profile == 100) { + strcpy(profileb, "High"); + } else if (profile == 110) { + strcpy(profileb, "High 10"); + } else if (profile == 122) { + strcpy(profileb, "High 4:2:2"); + } else if (profile == 144) { + strcpy(profileb, "High 4:4:4"); + } else { + snprintf(profileb, 20, "Unknown Profile %x", profile); + } + switch (level) { + case 10: + case 20: + case 30: + case 40: + case 50: + snprintf(levelb, 20, "%u", level / 10); + break; + case 11: + case 12: + case 13: + case 21: + case 22: + case 31: + case 32: + case 41: + case 42: + case 51: + snprintf(levelb, 20, "%u.%u", level / 10, level % 10); + break; + default: + snprintf(levelb, 20, "unknown level %x", level); + break; + } + if (originalFormat != NULL && originalFormat[0] != '\0') + snprintf(oformatbuffer, 32, "(%s) ", originalFormat); + snprintf(typebuffer, sizeof(typebuffer), "H264 %s%s@%s", + oformatbuffer, profileb, levelb); + typeName = typebuffer; + } else { + typeName = "H.264 - profile/level error"; + } + foundTypeName = true; + } else if (strcasecmp(media_data_name, "s263") == 0) { + // 3gp h.263 + typeName = "H.263"; + foundTypeName = true; + } else if ((strcasecmp(media_data_name, "mp4v") == 0) || + (strcasecmp(media_data_name, "encv") == 0)) { + // note encv might needs it's own field eventually. + type = MP4GetTrackEsdsObjectTypeId(mp4File, trackId); + if (type == MP4_MPEG4_VIDEO_TYPE) { + type = MP4GetVideoProfileLevel(mp4File, trackId); + typeName = Mpeg4VisualProfileName(type); + if (typeName == NULL) { + typeName = "MPEG-4 Unknown Profile"; + } else { + foundTypeName = true; + } + } else { + for (uint8_t i = 0; i < numMpegVideoTypes; i++) { + if (type == mpegVideoTypes[i]) { + typeName = mpegVideoNames[i]; + foundTypeName = true; + break; + } + } + } + } else { + typeName = media_data_name; + foundTypeName = true; // we don't have a type value to display + } + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + double(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + + uint32_t avgBitRate = + MP4GetTrackBitRate(mp4File, trackId); + + // Note not all mp4 implementations set width and height correctly + // The real answer can be buried inside the ES configuration info + uint16_t width = MP4GetTrackVideoWidth(mp4File, trackId); + + uint16_t height = MP4GetTrackVideoHeight(mp4File, trackId); + + double fps = MP4GetTrackVideoFrameRate(mp4File, trackId); + + char *sInfo = (char*)MP4Malloc(256); + + // type duration avgBitrate frameSize frameRate + if (foundTypeName) { + sprintf(sInfo, + "%u\tvideo\t%s%s, %.3f secs, %u kbps, %ux%u @ %f fps\n", + trackId, + MP4IsIsmaCrypMediaTrack(mp4File, trackId) ? "encv - " : "", + typeName, + msDuration / 1000.0, + (avgBitRate + 500) / 1000, + width, + height, + fps + ); + } else { + sprintf(sInfo, + "%u\tvideo\t%s(%u), %.3f secs, %u kbps, %ux%u @ %f fps\n", + trackId, + typeName, + type, + msDuration / 1000.0, + (avgBitRate + 500) / 1000, + width, + height, + fps + ); + } + + return sInfo; +} +static char* PrintCntlInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + const char *media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); + const char *typeName = "Unknown"; + + if (media_data_name == NULL) { + typeName = "Unknown - no media data name"; + } else if (strcasecmp(media_data_name, "href") == 0) { + typeName = "ISMA Href"; + } else { + typeName = media_data_name; + } + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + double(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + char *sInfo = (char *)MP4Malloc(256); + + snprintf(sInfo, 256, + "%u\tcontrol\t%s, %.3f secs\n", + trackId, + typeName, + msDuration / 1000.0); + return sInfo; +} + + +static char* PrintHintInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + MP4TrackId referenceTrackId = + MP4GetHintTrackReferenceTrackId(mp4File, trackId); + + char* payloadName = NULL; + if (!MP4GetHintTrackRtpPayload(mp4File, trackId, &payloadName)) + return NULL; + + char *sInfo = (char*)MP4Malloc(256); + + snprintf(sInfo, 256, + "%u\thint\tPayload %s for track %u\n", + trackId, + payloadName, + referenceTrackId); + + free(payloadName); + + return sInfo; +} + +static char* PrintTrackInfo( + MP4FileHandle mp4File, + MP4TrackId trackId) +{ + char* trackInfo = NULL; + + const char* trackType = + MP4GetTrackType(mp4File, trackId); + if (trackType == NULL) return NULL; + + if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) { + trackInfo = PrintAudioInfo(mp4File, trackId); + } else if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE)) { + trackInfo = PrintVideoInfo(mp4File, trackId); + } else if (!strcmp(trackType, MP4_HINT_TRACK_TYPE)) { + trackInfo = PrintHintInfo(mp4File, trackId); + } else if (strcmp(trackType, MP4_CNTL_TRACK_TYPE) == 0) { + trackInfo = PrintCntlInfo(mp4File, trackId); + } else { + trackInfo = (char*)MP4Malloc(256); + if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) { + snprintf(trackInfo, 256, + "%u\tod\tObject Descriptors\n", + trackId); + } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) { + snprintf(trackInfo, 256, + "%u\tscene\tBIFS\n", + trackId); + } else { + snprintf(trackInfo, 256, + "%u\t%s\n", + trackId, trackType); + } + } + + return trackInfo; +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +/////////////////////////////////////////////////////////////////////////////// + +using namespace mp4v2::impl; + +extern "C" +char* MP4Info( + MP4FileHandle mp4File, + MP4TrackId trackId ) +{ + char* info = NULL; + + if (MP4_IS_VALID_FILE_HANDLE(mp4File)) { + try { + if (trackId == MP4_INVALID_TRACK_ID) { + uint32_t buflen = 4 * 1024; + info = (char*)MP4Calloc(buflen); + + buflen -= snprintf(info, buflen, + "Track\tType\tInfo\n"); + + uint32_t numTracks = MP4GetNumberOfTracks(mp4File); + + for (uint32_t i = 0; i < numTracks; i++) { + trackId = MP4FindTrackId(mp4File, i); + char* trackInfo = PrintTrackInfo(mp4File, trackId); + strncat(info, trackInfo, buflen); + uint32_t newlen = (uint32_t)strlen(trackInfo); + if (newlen > buflen) buflen = 0; + else buflen -= newlen; + MP4Free(trackInfo); + } + } else { + info = PrintTrackInfo(mp4File, trackId); + } + } + catch (Exception* x) { + mp4v2::impl::log.errorf(*x); + delete x; + } + } + + return info; +} + +extern "C" +char* MP4FileInfo( + const char* fileName, + MP4TrackId trackId ) +{ + MP4FileHandle mp4File = MP4Read(fileName); + + if (!mp4File) { + return NULL; + } + + char* info = MP4Info(mp4File, trackId); + + MP4Close(mp4File); + + return info; // caller should free this +} diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4property.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4property.cpp new file mode 100644 index 00000000..9a5b1e32 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4property.cpp @@ -0,0 +1,1190 @@ +/* + * 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 [email protected] + * Kona Blend kona8lend@@gmail.com + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Property::MP4Property(MP4Atom& parentAtom, const char* name) + : m_parentAtom(parentAtom) +{ + m_name = name; + 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)) { + log.verbose1f("\"%s\": FindProperty: matched %s", + m_parentAtom.GetFile().GetFilename().c_str(), 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(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u] = %u (0x%02x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index], m_values[index]); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %u (0x%02x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index], m_values[index]); +} + +void MP4Integer16Property::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u] = %u (0x%04x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index], m_values[index]); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %u (0x%04x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index], m_values[index]); +} + +void MP4Integer24Property::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u] = %u (0x%06x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index], m_values[index]); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %u (0x%06x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index], m_values[index]); +} + +void MP4Integer32Property::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u] = %u (0x%08x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index], m_values[index]); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %u (0x%08x)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index], m_values[index]); +} + +void MP4Integer64Property::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u] = %" PRIu64 " (0x%016" PRIx64 ")", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index], m_values[index]); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %" PRIu64 " (0x%016" PRIx64 ")", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index], m_values[index]); +} + +// MP4BitfieldProperty + +void MP4BitfieldProperty::Read(MP4File& file, uint32_t index) +{ + if (m_implicit) { + return; + } + m_values[index] = file.ReadBits(m_numBits); +} + +void MP4BitfieldProperty::Write(MP4File& file, uint32_t index) +{ + if (m_implicit) { + return; + } + file.WriteBits(m_values[index], m_numBits); +} + +void MP4BitfieldProperty::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + uint8_t hexWidth = m_numBits / 4; + if (hexWidth == 0 || (m_numBits % 4)) { + hexWidth++; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, + "\"%s\": %s[%u] = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits>", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index], (int)hexWidth, m_values[index], m_numBits); + else + log.dump(indent, MP4_LOG_VERBOSE1, + "\"%s\": %s = %" PRIu64 " (0x%0*" PRIx64 ") <%u bits>", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index], (int)hexWidth, m_values[index], m_numBits); +} + +// MP4Float32Property + +void MP4Float32Property::Read(MP4File& file, uint32_t index) +{ + if (m_implicit) { + return; + } + if (m_useFixed16Format) { + m_values[index] = file.ReadFixed16(); + } else if (m_useFixed32Format) { + m_values[index] = file.ReadFixed32(); + } else { + m_values[index] = file.ReadFloat(); + } +} + +void MP4Float32Property::Write(MP4File& file, uint32_t index) +{ + if (m_implicit) { + return; + } + if (m_useFixed16Format) { + file.WriteFixed16(m_values[index]); + } else if (m_useFixed32Format) { + file.WriteFixed32(m_values[index]); + } else { + file.WriteFloat(m_values[index]); + } +} + +void MP4Float32Property::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + if (m_implicit && !dumpImplicits) { + return; + } + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u] = %f", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index, m_values[index]); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %f", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, m_values[index]); +} + +// MP4StringProperty + +MP4StringProperty::MP4StringProperty( + MP4Atom& parentAtom, + const char* name, + bool useCountedFormat, + bool useUnicode, + bool arrayMode ) + + : MP4Property( parentAtom, name ) + , m_arrayMode ( arrayMode ) + , m_useCountedFormat ( useCountedFormat ) + , m_useExpandedCount ( false ) + , m_useUnicode ( useUnicode ) + , m_fixedLength ( 0 ) +{ + 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) { + ostringstream msg; + msg << "property " << m_name << "is read-only"; + throw new PlatformException(msg.str().c_str(), EACCES, __FILE__, __LINE__, __FUNCTION__ ); + } + + 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) { + m_values[index] = MP4Stralloc(value); + } else { + m_values[index] = NULL; + } + } +} + +void MP4StringProperty::Read( MP4File& file, 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]; + + // Generally a default atom setting, e.g. see atom_avc1.cpp, "JVT/AVC Coding"; we'll leak this string if + // we don't free. Note that MP4Free checks for null. + MP4Free(value); + + if( m_useCountedFormat ) { + value = file.ReadCountedString( (m_useUnicode ? 2 : 1), m_useExpandedCount, m_fixedLength ); + } + else if( m_fixedLength ) { + value = (char*)MP4Calloc( m_fixedLength + 1 ); + file.ReadBytes( (uint8_t*)value, m_fixedLength ); + } + else { + value = file.ReadString(); + } + } +} + +void MP4StringProperty::Write( MP4File& file, 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 ) { + file.WriteCountedString( value, (m_useUnicode ? 2 : 1), m_useExpandedCount, m_fixedLength ); + } + else if( m_fixedLength ) { + file.WriteBytes( (uint8_t*)value, m_fixedLength ); + } + else { + file.WriteString( value ); + } + } +} + +void MP4StringProperty::Dump( 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'; + + if( m_useUnicode ) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s%s = %ls", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, indexd, (wchar_t*)m_values[index] ); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s%s = %s", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, indexd, m_values[index] ); + } + else if( log.verbosity >= MP4_LOG_VERBOSE2 ) + { + const uint32_t max = GetCount(); + + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s (size=%u)", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, max ); + + for( uint32_t i = 0; i < max; i++ ) { + char*& value = m_values[i]; + + if( m_useUnicode ) + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s[%u] = %ls", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, i, (wchar_t*)value ); + else + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s[%u] = %s", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, i, value ); + } + } + else { + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": <table entries suppressed>", + m_parentAtom.GetFile().GetFilename().c_str() ); + } +} + +// MP4BytesProperty + +MP4BytesProperty::MP4BytesProperty(MP4Atom& parentAtom, const char* name, uint32_t valueSize, + uint32_t defaultValueSize) + : MP4Property(parentAtom, 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); + + 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) { + ostringstream msg; + msg << "property " << m_name << "is read-only"; + throw new PlatformException(msg.str().c_str(), EACCES, __FILE__, __LINE__, __FUNCTION__ ); + } + if (m_fixedValueSize) { + if (valueSize > m_fixedValueSize) { + ostringstream msg; + msg << GetParentAtom().GetType() << "." << GetName() << " value size " << valueSize << " exceeds fixed value size " << m_fixedValueSize; + throw new Exception(msg.str().c_str(), __FILE__, __LINE__, __FUNCTION__ ); + } + 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 Exception("can't change size of fixed sized property", + __FILE__, __LINE__, __FUNCTION__ ); + } + 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& file, uint32_t index) +{ + if (m_implicit) { + return; + } + MP4Free(m_values[index]); + m_values[index] = (uint8_t*)MP4Malloc(m_valueSizes[index]); + file.ReadBytes(m_values[index], m_valueSizes[index]); +} + +void MP4BytesProperty::Write(MP4File& file, uint32_t index) +{ + if (m_implicit) { + return; + } + file.WriteBytes(m_values[index], m_valueSizes[index]); +} + +void MP4BytesProperty::Dump(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]; + + if( size == 0 ) { + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s = <%u bytes>", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, size ); + 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() << "|"; + + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s = <%u bytes>%s", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, size, oss.str().c_str() ); + return; + } + + // specialization for ilst item data always show all bytes except for covr + bool showall = false; + MP4Atom* const datac = m_parentAtom.GetParentAtom(); // data container + MP4Atom* const datacc = datac->GetParentAtom(); + if( datacc && + ATOMID( datacc->GetType() ) == ATOMID( "ilst" ) && + ATOMID( datac->GetType() ) != ATOMID( "covr" ) ) + { + showall = true; + } + + uint32_t adjsize; + bool supressed; + + if( showall || + size < 128 || log.verbosity >= MP4_LOG_VERBOSE2 ) + { + adjsize = size; + supressed = false; + } + else { + adjsize = 128; + supressed = true; + } + + ostringstream oss; + ostringstream text; + + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s = <%u bytes>", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, size ); + log.hexDump(indent, MP4_LOG_VERBOSE2, value, adjsize, "\"%s\": %s", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name); + + if( supressed ) { + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": <remaining bytes supressed>", + m_parentAtom.GetFile().GetFilename().c_str() ); + } +} + +// MP4TableProperty + +MP4TableProperty::MP4TableProperty(MP4Atom& parentAtom, const char* name, MP4IntegerProperty* pCountProperty) + : MP4Property(parentAtom, 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->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; + } + } + + log.verbose1f("\"%s\": FindProperty: matched %s", + m_parentAtom.GetFile().GetFilename().c_str(), 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& file, 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(file, i); + } +} + +void MP4TableProperty::ReadEntry(MP4File& file, uint32_t index) +{ + for (uint32_t j = 0; j < m_pProperties.Size(); j++) { + m_pProperties[j]->Read(file, index); + } +} + +void MP4TableProperty::Write(MP4File& file, 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) { + log.errorf("%s: \"%s\": %s %s \"%s\"table entries %u doesn't match count %u", + __FUNCTION__, m_parentAtom.GetFile().GetFilename().c_str(), + 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(file, i); + } +} + +void MP4TableProperty::WriteEntry(MP4File& file, uint32_t index) +{ + for (uint32_t j = 0; j < m_pProperties.Size(); j++) { + m_pProperties[j]->Write(file, index); + } +} + +void MP4TableProperty::Dump(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(indent + 1, dumpImplicits, i); + } + } +} + +// MP4DescriptorProperty + +MP4DescriptorProperty::MP4DescriptorProperty(MP4Atom& parentAtom, const char* name, + uint8_t tagsStart, uint8_t tagsEnd, bool mandatory, bool onlyOne) + : MP4Property(parentAtom, 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]; + } +} + +MP4Descriptor* MP4DescriptorProperty::AddDescriptor(uint8_t tag) +{ + // check that tag is in expected range + ASSERT(tag >= m_tagsStart && tag <= m_tagsEnd); + + MP4Descriptor* pDescriptor = CreateDescriptor(m_parentAtom, tag); + ASSERT(pDescriptor); + + m_pDescriptors.Add(pDescriptor); + + 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; + } + + log.verbose1f("\"%s\": matched %s", + m_parentAtom.GetFile().GetFilename().c_str(), + 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& file, uint32_t index) +{ + ASSERT(index == 0); + + if (m_implicit) { + return; + } + + uint64_t start = file.GetPosition(); + + while (true) { + // enforce size limitation + if (m_sizeLimit && file.GetPosition() >= start + m_sizeLimit) { + break; + } + + uint8_t tag; + try { + file.PeekBytes(&tag, 1); + } + catch (Exception* x) { + if (file.GetPosition() >= file.GetSize()) { + // EOF + delete x; + break; + } + throw x; + } + + // check if tag is in desired range + if (tag < m_tagsStart || tag > m_tagsEnd) { + break; + } + + MP4Descriptor* pDescriptor = + AddDescriptor(tag); + + pDescriptor->Read(file); + } + + // warnings + if (m_mandatory && m_pDescriptors.Size() == 0) { + log.warningf("%s: \"%s\": Mandatory descriptor 0x%02x missing", + __FUNCTION__, GetParentAtom().GetFile().GetFilename().c_str(), m_tagsStart); + } else if (m_onlyOne && m_pDescriptors.Size() > 1) { + log.warningf("%s: \"%s\": Descriptor 0x%02x has more than one instance", + __FUNCTION__, GetParentAtom().GetFile().GetFilename().c_str(), m_tagsStart); + } +} + +void MP4DescriptorProperty::Write(MP4File& file, uint32_t index) +{ + ASSERT(index == 0); + + if (m_implicit) { + return; + } + + for (uint32_t i = 0; i < m_pDescriptors.Size(); i++) { + m_pDescriptors[i]->Write(file); + } +} + +void MP4DescriptorProperty::Dump(uint8_t indent, + bool dumpImplicits, uint32_t index) +{ + ASSERT(index == 0); + + if (m_implicit && !dumpImplicits) { + return; + } + + if (m_name) { + if (index != 0) + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s[%u]", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name, index); + else + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s", + m_parentAtom.GetFile().GetFilename().c_str(), + m_name); + indent++; + } + + for (uint32_t i = 0; i < m_pDescriptors.Size(); i++) { + m_pDescriptors[i]->Dump(indent, dumpImplicits); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +MP4LanguageCodeProperty::MP4LanguageCodeProperty( MP4Atom& parentAtom, const char* name, bmff::LanguageCode value ) + : MP4Property( parentAtom, name ) +{ + SetValue( value ); +} + +MP4LanguageCodeProperty::MP4LanguageCodeProperty( MP4Atom& parentAtom, const char* name, const string& code ) + : MP4Property( parentAtom, name ) +{ + SetValue( bmff::enumLanguageCode.toType( code )); +} + +void +MP4LanguageCodeProperty::Dump( uint8_t indent, bool dumpImplicits, 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) ); + } + + log.dump(indent, MP4_LOG_VERBOSE2, "\"%s\": %s = %s (0x%04x)", + m_parentAtom.GetFile().GetFilename().c_str(), + 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( MP4Atom& parentAtom, const char* name, itmf::BasicType type ) + : MP4Property( parentAtom, name ) +{ + SetValue( type ); +} + +void +MP4BasicTypeProperty::Dump( uint8_t indent, bool dumpImplicits, uint32_t index ) +{ + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": %s = %s (0x%02x)", + m_parentAtom.GetFile().GetFilename().c_str(), 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 diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4property.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4property.h new file mode 100644 index 00000000..4c7ccad9 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4property.h @@ -0,0 +1,663 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_MP4PROPERTY_H +#define MP4V2_IMPL_MP4PROPERTY_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +// forward declarations +class MP4Atom; + +class MP4Descriptor; +MP4ARRAY_DECL(MP4Descriptor, MP4Descriptor*); + +enum MP4PropertyType { + Integer8Property, + Integer16Property, + Integer24Property, + Integer32Property, + Integer64Property, + Float32Property, + StringProperty, + BytesProperty, + TableProperty, + DescriptorProperty, + LanguageCodeProperty, + BasicTypeProperty, +}; + +class MP4Property { +public: + MP4Property(MP4Atom& parentAtom, const char *name = NULL); + + virtual ~MP4Property() { } + + MP4Atom& GetParentAtom() { + return m_parentAtom; + } + + const char *GetName() { + return m_name; + } + + virtual MP4PropertyType GetType() = 0; + + bool IsReadOnly() { + return m_readOnly; + } + void SetReadOnly(bool value = true) { + m_readOnly = value; + } + + bool IsImplicit() { + return m_implicit; + } + void SetImplicit(bool value = true) { + m_implicit = value; + } + + virtual uint32_t GetCount() = 0; + virtual void SetCount(uint32_t count) = 0; + + virtual void Generate() { /* default is a no-op */ }; + + virtual void Read(MP4File& file, uint32_t index = 0) = 0; + + virtual void Write(MP4File& file, uint32_t index = 0) = 0; + + virtual void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0) = 0; + + virtual bool FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + +protected: + MP4Atom& m_parentAtom; + const char* m_name; + bool m_readOnly; + bool m_implicit; + +private: + MP4Property(); + MP4Property ( const MP4Property &src ); + MP4Property &operator= ( const MP4Property &src ); +}; + +MP4ARRAY_DECL(MP4Property, MP4Property*); + +class MP4IntegerProperty : public MP4Property { +protected: + MP4IntegerProperty(MP4Atom& parentAtom, const char* name) + : MP4Property(parentAtom, name) { }; + +public: + uint64_t GetValue(uint32_t index = 0); + + void SetValue(uint64_t value, uint32_t index = 0); + + void InsertValue(uint64_t value, uint32_t index = 0); + + void DeleteValue(uint32_t index = 0); + + void IncrementValue(int32_t increment = 1, uint32_t index = 0); + +private: + MP4IntegerProperty(); + MP4IntegerProperty ( const MP4IntegerProperty &src ); + MP4IntegerProperty &operator= ( const MP4IntegerProperty &src ); +}; + +#define MP4INTEGER_PROPERTY_DECL2(isize, xsize) \ + class MP4Integer##xsize##Property : public MP4IntegerProperty { \ + public: \ + MP4Integer##xsize##Property(MP4Atom& parentAtom, const char* name) \ + : MP4IntegerProperty(parentAtom, name) { \ + SetCount(1); \ + m_values[0] = 0; \ + } \ + \ + MP4PropertyType GetType() { \ + return Integer##xsize##Property; \ + } \ + \ + uint32_t GetCount() { \ + return m_values.Size(); \ + } \ + void SetCount(uint32_t count) { \ + m_values.Resize(count); \ + } \ + \ + uint##isize##_t GetValue(uint32_t index = 0) { \ + return m_values[index]; \ + } \ + \ + void SetValue(uint##isize##_t value, uint32_t index = 0) { \ + if (m_readOnly) { \ + ostringstream msg; \ + msg << "property is read-only: " << m_name; \ + throw new PlatformException(msg.str().c_str(), EACCES, __FILE__, __LINE__, __FUNCTION__); \ + } \ + m_values[index] = value; \ + } \ + void AddValue(uint##isize##_t value) { \ + m_values.Add(value); \ + } \ + void InsertValue(uint##isize##_t value, uint32_t index) { \ + m_values.Insert(value, index); \ + } \ + void DeleteValue(uint32_t index) { \ + m_values.Delete(index); \ + } \ + void IncrementValue(int32_t increment = 1, uint32_t index = 0) { \ + m_values[index] += increment; \ + } \ + void Read(MP4File& file, uint32_t index = 0) { \ + if (m_implicit) { \ + return; \ + } \ + m_values[index] = file.ReadUInt##xsize(); \ + } \ + \ + void Write(MP4File& file, uint32_t index = 0) { \ + if (m_implicit) { \ + return; \ + } \ + file.WriteUInt##xsize(m_values[index]); \ + } \ + void Dump(uint8_t indent, \ + bool dumpImplicits, uint32_t index = 0); \ + \ + protected: \ + MP4Integer##isize##Array m_values; \ + private: \ + MP4Integer##xsize##Property(); \ + MP4Integer##xsize##Property ( const MP4Integer##xsize##Property &src ); \ + MP4Integer##xsize##Property &operator= ( const MP4Integer##xsize##Property &src ); \ + }; + +#define MP4INTEGER_PROPERTY_DECL(size) \ + MP4INTEGER_PROPERTY_DECL2(size, size) + +MP4INTEGER_PROPERTY_DECL(8); +MP4INTEGER_PROPERTY_DECL(16); +MP4INTEGER_PROPERTY_DECL2(32, 24); +MP4INTEGER_PROPERTY_DECL(32); +MP4INTEGER_PROPERTY_DECL(64); + +class MP4BitfieldProperty : public MP4Integer64Property { +public: + MP4BitfieldProperty(MP4Atom& parentAtom, const char* name, uint8_t numBits) + : MP4Integer64Property(parentAtom, name) { + ASSERT(numBits != 0); + ASSERT(numBits <= 64); + m_numBits = numBits; + } + + uint8_t GetNumBits() { + return m_numBits; + } + void SetNumBits(uint8_t numBits) { + m_numBits = numBits; + } + + void Read(MP4File& file, uint32_t index = 0); + void Write(MP4File& file, uint32_t index = 0); + void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0); + +protected: + uint8_t m_numBits; + +private: + MP4BitfieldProperty(); + MP4BitfieldProperty ( const MP4BitfieldProperty &src ); + MP4BitfieldProperty &operator= ( const MP4BitfieldProperty &src ); +}; + +class MP4Float32Property : public MP4Property { +public: + MP4Float32Property(MP4Atom& parentAtom, const char* name) + : MP4Property(parentAtom, name) { + m_useFixed16Format = false; + m_useFixed32Format = false; + SetCount(1); + m_values[0] = 0.0; + } + + MP4PropertyType GetType() { + return Float32Property; + } + + uint32_t GetCount() { + return m_values.Size(); + } + void SetCount(uint32_t count) { + m_values.Resize(count); + } + + float GetValue(uint32_t index = 0) { + return m_values[index]; + } + + void SetValue(float value, uint32_t index = 0) { + if (m_readOnly) { + ostringstream msg; + msg << "property is read-only: " << m_name; + throw new PlatformException(msg.str().c_str(), EACCES, __FILE__, __LINE__, __FUNCTION__); + } + m_values[index] = value; + } + + void AddValue(float value) { + m_values.Add(value); + } + + void InsertValue(float value, uint32_t index) { + m_values.Insert(value, index); + } + + bool IsFixed16Format() { + return m_useFixed16Format; + } + + void SetFixed16Format(bool useFixed16Format = true) { + m_useFixed16Format = useFixed16Format; + } + + bool IsFixed32Format() { + return m_useFixed32Format; + } + + void SetFixed32Format(bool useFixed32Format = true) { + m_useFixed32Format = useFixed32Format; + } + + void Read(MP4File& file, uint32_t index = 0); + void Write(MP4File& file, uint32_t index = 0); + void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0); + +protected: + bool m_useFixed16Format; + bool m_useFixed32Format; + MP4Float32Array m_values; + +private: + MP4Float32Property(); + MP4Float32Property ( const MP4Float32Property &src ); + MP4Float32Property &operator= ( const MP4Float32Property &src ); +}; + +class MP4StringProperty : public MP4Property { +public: + MP4StringProperty(MP4Atom& parentAtom, const char* name, + bool useCountedFormat = false, bool useUnicode = false, bool arrayMode = false); + + ~MP4StringProperty(); + + MP4PropertyType GetType() { + return StringProperty; + } + + uint32_t GetCount() { + return m_values.Size(); + } + + void SetCount(uint32_t count); + + const char* GetValue(uint32_t index = 0) { + return m_values[index]; + } + + void SetValue(const char* value, uint32_t index = 0); + + void AddValue(const char* value) { + uint32_t count = GetCount(); + SetCount(count + 1); + SetValue(value, count); + } + + bool IsCountedFormat() { + return m_useCountedFormat; + } + + void SetCountedFormat(bool useCountedFormat) { + m_useCountedFormat = useCountedFormat; + } + + bool IsExpandedCountedFormat() { + return m_useExpandedCount; + } + + void SetExpandedCountedFormat(bool useExpandedCount) { + m_useExpandedCount = useExpandedCount; + } + + bool IsUnicode() { + return m_useUnicode; + } + + void SetUnicode(bool useUnicode) { + m_useUnicode = useUnicode; + } + + uint32_t GetFixedLength() { + return m_fixedLength; + } + + void SetFixedLength(uint32_t fixedLength) { + m_fixedLength = fixedLength; + } + + void Read(MP4File& file, uint32_t index = 0); + void Write(MP4File& file, uint32_t index = 0); + void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0); + +protected: + bool m_arrayMode; // during read/write ignore index and read/write full array + bool m_useCountedFormat; + bool m_useExpandedCount; + bool m_useUnicode; + uint32_t m_fixedLength; + + MP4StringArray m_values; + +private: + MP4StringProperty(); + MP4StringProperty ( const MP4StringProperty &src ); + MP4StringProperty &operator= ( const MP4StringProperty &src ); +}; + +class MP4BytesProperty : public MP4Property { +public: + MP4BytesProperty(MP4Atom& parentAtom, const char* name, uint32_t valueSize = 0, + uint32_t defaultValueSize = 0); + + ~MP4BytesProperty(); + + MP4PropertyType GetType() { + return BytesProperty; + } + + uint32_t GetCount() { + return m_values.Size(); + } + + void SetCount(uint32_t count); + + void GetValue(uint8_t** ppValue, uint32_t* pValueSize, + uint32_t index = 0) { + // N.B. caller must free memory + *ppValue = (uint8_t*)MP4Malloc(m_valueSizes[index]); + memcpy(*ppValue, m_values[index], m_valueSizes[index]); + *pValueSize = m_valueSizes[index]; + } + + char* GetValueStringAlloc( uint32_t index = 0 ) { + char* buf = (char*)MP4Malloc( m_valueSizes[index] + 1 ); + memcpy( buf, m_values[index], m_valueSizes[index] ); + buf[m_valueSizes[index]] = '\0'; + return buf; + } + + bool CompareToString( const string& s, uint32_t index = 0 ) { + return string( (const char*)m_values[index], m_valueSizes[index] ) != s; + } + + void CopyValue(uint8_t* pValue, uint32_t index = 0) { + // N.B. caller takes responsbility for valid pointer + // and sufficient memory at the destination + memcpy(pValue, m_values[index], m_valueSizes[index]); + } + + void SetValue(const uint8_t* pValue, uint32_t valueSize, + uint32_t index = 0); + + void AddValue(const uint8_t* pValue, uint32_t valueSize) { + uint32_t count = GetCount(); + SetCount(count + 1); + SetValue(pValue, valueSize, count); + } + + uint32_t GetValueSize( uint32_t index = 0 ) { + return m_valueSizes[index]; + } + + void SetValueSize(uint32_t valueSize, uint32_t index = 0); + + uint32_t GetFixedSize() { + return m_fixedValueSize; + } + + void SetFixedSize(uint32_t fixedSize); + + void Read(MP4File& file, uint32_t index = 0); + void Write(MP4File& file, uint32_t index = 0); + void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0); + +protected: + uint32_t m_fixedValueSize; + uint32_t m_defaultValueSize; + MP4Integer32Array m_valueSizes; + MP4BytesArray m_values; + +private: + MP4BytesProperty(); + MP4BytesProperty ( const MP4BytesProperty &src ); + MP4BytesProperty &operator= ( const MP4BytesProperty &src ); +}; + +class MP4TableProperty : public MP4Property { +public: + MP4TableProperty(MP4Atom& parentAtom, const char* name, MP4IntegerProperty* pCountProperty); + + ~MP4TableProperty(); + + MP4PropertyType GetType() { + return TableProperty; + } + + void AddProperty(MP4Property* pProperty); + + MP4Property* GetProperty(uint32_t index) { + return m_pProperties[index]; + } + + virtual uint32_t GetCount() { + return m_pCountProperty->GetValue(); + } + virtual void SetCount(uint32_t count) { + m_pCountProperty->SetValue(count); + } + + void Read(MP4File& file, uint32_t index = 0); + void Write(MP4File& file, uint32_t index = 0); + void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0); + + bool FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + +protected: + virtual void ReadEntry(MP4File& file, uint32_t index); + virtual void WriteEntry(MP4File& file, uint32_t index); + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex); + +protected: + MP4IntegerProperty* m_pCountProperty; + MP4PropertyArray m_pProperties; + +private: + MP4TableProperty(); + MP4TableProperty ( const MP4TableProperty &src ); + MP4TableProperty &operator= ( const MP4TableProperty &src ); +}; + +class MP4DescriptorProperty : public MP4Property { +public: + MP4DescriptorProperty(MP4Atom& parentAtom, const char* name = NULL, + uint8_t tagsStart = 0, uint8_t tagsEnd = 0, + bool mandatory = false, bool onlyOne = false); + + ~MP4DescriptorProperty(); + + MP4PropertyType GetType() { + return DescriptorProperty; + } + + void SetParentAtom(MP4Atom* pParentAtom); + + void SetSizeLimit(uint64_t sizeLimit) { + m_sizeLimit = sizeLimit; + } + + uint32_t GetCount() { + return m_pDescriptors.Size(); + } + void SetCount(uint32_t count) { + m_pDescriptors.Resize(count); + } + + void SetTags(uint8_t tagsStart, uint8_t tagsEnd = 0) { + m_tagsStart = tagsStart; + m_tagsEnd = tagsEnd ? tagsEnd : tagsStart; + } + + MP4Descriptor* AddDescriptor(uint8_t tag); + + void AppendDescriptor(MP4Descriptor* pDescriptor) { + m_pDescriptors.Add(pDescriptor); + } + + void DeleteDescriptor(uint32_t index); + + void Generate(); + void Read(MP4File& file, uint32_t index = 0); + void Write(MP4File& file, uint32_t index = 0); + void Dump(uint8_t indent, + bool dumpImplicits, uint32_t index = 0); + + bool FindProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex = NULL); + +protected: + virtual MP4Descriptor* CreateDescriptor(MP4Atom& parentAtom, uint8_t tag); + + bool FindContainedProperty(const char* name, + MP4Property** ppProperty, uint32_t* pIndex); + +protected: + uint8_t m_tagsStart; + uint8_t m_tagsEnd; + uint64_t m_sizeLimit; + bool m_mandatory; + bool m_onlyOne; + MP4DescriptorArray m_pDescriptors; + +private: + MP4DescriptorProperty(); + MP4DescriptorProperty ( const MP4DescriptorProperty &src ); + MP4DescriptorProperty &operator= ( const MP4DescriptorProperty &src ); +}; + +class MP4QosQualifierProperty : public MP4DescriptorProperty { +public: + MP4QosQualifierProperty(MP4Atom& parentAtom, const char* name = NULL, + uint8_t tagsStart = 0, uint8_t tagsEnd = 0, + bool mandatory = false, bool onlyOne = false) : + MP4DescriptorProperty(parentAtom, name, tagsStart, tagsEnd, mandatory, onlyOne) { } + +protected: + MP4Descriptor* CreateDescriptor(MP4Atom& parentAtom, uint8_t tag); + +private: + MP4QosQualifierProperty(); + MP4QosQualifierProperty ( const MP4QosQualifierProperty &src ); + MP4QosQualifierProperty &operator= ( const MP4QosQualifierProperty &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +/// ISO-639-2/T language code. +/// Language codes are 3-alpha (always lowercase) codes which are then +/// offset using 0x60 and packed as 5-bit values into 16-bits, most +/// significant bit is zero-padding. + +class MP4LanguageCodeProperty : public MP4Property { +private: + bmff::LanguageCode _value; + +public: + explicit MP4LanguageCodeProperty( MP4Atom& parentAtom, const char* , bmff::LanguageCode = bmff::ILC_UND ); + MP4LanguageCodeProperty( MP4Atom& parentAtom, const char* , const string& ); + + MP4PropertyType GetType(); + uint32_t GetCount(); + void SetCount( uint32_t ); + void Read( MP4File&, uint32_t = 0 ); + void Write( MP4File&, uint32_t = 0 ); + void Dump( uint8_t, bool, uint32_t = 0 ); + + bmff::LanguageCode GetValue(); + void SetValue( bmff::LanguageCode ); + +private: + MP4LanguageCodeProperty(); + MP4LanguageCodeProperty ( const MP4LanguageCodeProperty &src ); + MP4LanguageCodeProperty &operator= ( const MP4LanguageCodeProperty &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class MP4BasicTypeProperty : public MP4Property { +private: + itmf::BasicType _value; + +public: + explicit MP4BasicTypeProperty( MP4Atom& parentAtom, const char* , itmf::BasicType = itmf::BT_UNDEFINED ); + + MP4PropertyType GetType(); + uint32_t GetCount(); + void SetCount( uint32_t ); + void Read( MP4File&, uint32_t = 0 ); + void Write( MP4File&, uint32_t = 0 ); + void Dump( uint8_t, bool, uint32_t = 0 ); + itmf::BasicType GetValue(); + void SetValue( itmf::BasicType ); + +private: + MP4BasicTypeProperty(); + MP4BasicTypeProperty ( const MP4BasicTypeProperty &src ); + MP4BasicTypeProperty &operator= ( const MP4BasicTypeProperty &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4PROPERTY_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4track.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4track.cpp new file mode 100644 index 00000000..cfa1a1f4 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4track.cpp @@ -0,0 +1,1910 @@ +/* + * 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 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Alix Marchandise-Franquet [email protected] + * Ximpo Group Ltd. [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +#define AMR_UNINITIALIZED -1 +#define AMR_TRUE 0 +#define AMR_FALSE 1 + +MP4Track::MP4Track(MP4File& file, MP4Atom& trakAtom) + : m_File(file) + , m_trakAtom(trakAtom) +{ + m_lastStsdIndex = 0; + m_lastSampleFile = NULL; + + m_cachedReadSampleId = MP4_INVALID_SAMPLE_ID; + m_pCachedReadSample = NULL; + m_cachedReadSampleSize = 0; + + m_writeSampleId = 1; + m_fixedSampleDuration = 0; + m_pChunkBuffer = NULL; + m_chunkBufferSize = 0; + m_sizeOfDataInChunkBuffer = 0; + m_chunkSamples = 0; + m_chunkDuration = 0; + + // m_bytesPerSample should be set to 1, except for the + // quicktime audio constant bit rate samples, which have non-1 values + m_bytesPerSample = 1; + m_samplesPerChunk = 0; + m_durationPerChunk = 0; + m_isAmr = AMR_UNINITIALIZED; + m_curMode = 0; + + m_cachedSttsSid = MP4_INVALID_SAMPLE_ID; + m_cachedCttsSid = MP4_INVALID_SAMPLE_ID; + + bool success = true; + + MP4Integer32Property* pTrackIdProperty; + success &= m_trakAtom.FindProperty( + "trak.tkhd.trackId", + (MP4Property**)&pTrackIdProperty); + if (success) { + m_trackId = pTrackIdProperty->GetValue(); + } + + success &= m_trakAtom.FindProperty( + "trak.mdia.mdhd.timeScale", + (MP4Property**)&m_pTimeScaleProperty); + if (success) { + // default chunking is 1 second of samples + m_durationPerChunk = m_pTimeScaleProperty->GetValue(); + } + + success &= m_trakAtom.FindProperty( + "trak.tkhd.duration", + (MP4Property**)&m_pTrackDurationProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.mdhd.duration", + (MP4Property**)&m_pMediaDurationProperty); + + success &= m_trakAtom.FindProperty( + "trak.tkhd.modificationTime", + (MP4Property**)&m_pTrackModificationProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.mdhd.modificationTime", + (MP4Property**)&m_pMediaModificationProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.hdlr.handlerType", + (MP4Property**)&m_pTypeProperty); + + // get handles on sample size information + + + m_pStszFixedSampleSizeProperty = NULL; + bool have_stsz = + m_trakAtom.FindProperty("trak.mdia.minf.stbl.stsz.sampleSize", + (MP4Property**)&m_pStszFixedSampleSizeProperty); + + if (have_stsz) { + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsz.sampleCount", + (MP4Property**)&m_pStszSampleCountProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsz.entries.entrySize", + (MP4Property**)&m_pStszSampleSizeProperty); + m_stsz_sample_bits = 32; + } else { + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stz2.sampleCount", + (MP4Property**)&m_pStszSampleCountProperty); + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stz2.entries.entrySize", + (MP4Property**)&m_pStszSampleSizeProperty); + MP4Integer8Property *stz2_field_size; + if (m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stz2.fieldSize", + (MP4Property **)&stz2_field_size)) { + m_stsz_sample_bits = stz2_field_size->GetValue(); + m_have_stz2_4bit_sample = false; + } else success = false; + } + + // get handles on information needed to map sample id's to file offsets + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsc.entryCount", + (MP4Property**)&m_pStscCountProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsc.entries.firstChunk", + (MP4Property**)&m_pStscFirstChunkProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsc.entries.samplesPerChunk", + (MP4Property**)&m_pStscSamplesPerChunkProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsc.entries.sampleDescriptionIndex", + (MP4Property**)&m_pStscSampleDescrIndexProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsc.entries.firstSample", + (MP4Property**)&m_pStscFirstSampleProperty); + + bool haveStco = m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stco.entryCount", + (MP4Property**)&m_pChunkCountProperty); + + if (haveStco) { + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stco.entries.chunkOffset", + (MP4Property**)&m_pChunkOffsetProperty); + } else { + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.co64.entryCount", + (MP4Property**)&m_pChunkCountProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.co64.entries.chunkOffset", + (MP4Property**)&m_pChunkOffsetProperty); + } + + // get handles on sample timing info + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stts.entryCount", + (MP4Property**)&m_pSttsCountProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stts.entries.sampleCount", + (MP4Property**)&m_pSttsSampleCountProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stts.entries.sampleDelta", + (MP4Property**)&m_pSttsSampleDeltaProperty); + + // get handles on rendering offset info if it exists + + m_pCttsCountProperty = NULL; + m_pCttsSampleCountProperty = NULL; + m_pCttsSampleOffsetProperty = NULL; + + bool haveCtts = m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.ctts.entryCount", + (MP4Property**)&m_pCttsCountProperty); + + if (haveCtts) { + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.ctts.entries.sampleCount", + (MP4Property**)&m_pCttsSampleCountProperty); + + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.ctts.entries.sampleOffset", + (MP4Property**)&m_pCttsSampleOffsetProperty); + } + + // get handles on sync sample info if it exists + + m_pStssCountProperty = NULL; + m_pStssSampleProperty = NULL; + + bool haveStss = m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stss.entryCount", + (MP4Property**)&m_pStssCountProperty); + + if (haveStss) { + success &= m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stss.entries.sampleNumber", + (MP4Property**)&m_pStssSampleProperty); + } + + // edit list + (void)InitEditListProperties(); + + // was everything found? + if (!success) { + throw new Exception("invalid track", __FILE__, __LINE__, __FUNCTION__ ); + } + CalculateBytesPerSample(); + + // update sdtp log from sdtp atom + MP4SdtpAtom* sdtp = (MP4SdtpAtom*)m_trakAtom.FindAtom( "trak.mdia.minf.stbl.sdtp" ); + if( sdtp ) { + uint8_t* buffer; + uint32_t bufsize; + sdtp->data.GetValue( &buffer, &bufsize ); + m_sdtpLog.assign( (char*)buffer, bufsize ); + free( buffer ); + } +} + +MP4Track::~MP4Track() +{ + MP4Free(m_pCachedReadSample); + m_pCachedReadSample = NULL; + MP4Free(m_pChunkBuffer); + m_pChunkBuffer = NULL; +} + +const char* MP4Track::GetType() +{ + return m_pTypeProperty->GetValue(); +} + +void MP4Track::SetType(const char* type) +{ + m_pTypeProperty->SetValue(MP4NormalizeTrackType(type)); +} + +void MP4Track::ReadSample( + MP4SampleId sampleId, + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime, + MP4Duration* pDuration, + MP4Duration* pRenderingOffset, + bool* pIsSyncSample, + bool* hasDependencyFlags, + uint32_t* dependencyFlags ) +{ + if( sampleId == MP4_INVALID_SAMPLE_ID ) + throw new Exception( "sample id can't be zero", __FILE__, __LINE__, __FUNCTION__ ); + + if( hasDependencyFlags ) + *hasDependencyFlags = !m_sdtpLog.empty(); + + if( dependencyFlags ) { + if( m_sdtpLog.empty() ) { + *dependencyFlags = 0; + } + else { + if( sampleId > m_sdtpLog.size() ) + throw new Exception( "sample id > sdtp logsize", __FILE__, __LINE__, __FUNCTION__ ); + *dependencyFlags = m_sdtpLog[sampleId-1]; // sampleId is 1-based + } + } + + // handle unusual case of wanting to read a sample + // that is still sitting in the write chunk buffer + if (m_pChunkBuffer && sampleId >= m_writeSampleId - m_chunkSamples) { + WriteChunkBuffer(); + } + + File* fin = GetSampleFile( sampleId ); + if( fin == (File*)-1 ) + throw new Exception( "sample is located in an inaccessible file", __FILE__, __LINE__, __FUNCTION__ ); + + uint64_t fileOffset = GetSampleFileOffset(sampleId); + + uint32_t sampleSize = GetSampleSize(sampleId); + if (*ppBytes != NULL && *pNumBytes < sampleSize) { + throw new Exception("sample buffer is too small", + __FILE__, __LINE__, __FUNCTION__ ); + } + *pNumBytes = sampleSize; + + log.verbose3f("\"%s\": ReadSample: track %u id %u offset 0x%" PRIx64 " size %u (0x%x)", + GetFile().GetFilename().c_str(), m_trackId, sampleId, fileOffset, *pNumBytes, *pNumBytes); + + bool bufferMalloc = false; + if (*ppBytes == NULL) { + *ppBytes = (uint8_t*)MP4Malloc(*pNumBytes); + bufferMalloc = true; + } + + uint64_t oldPos = m_File.GetPosition( fin ); // only used in mode == 'w' + try { + m_File.SetPosition( fileOffset, fin ); + m_File.ReadBytes( *ppBytes, *pNumBytes, fin ); + + if (pStartTime || pDuration) { + GetSampleTimes(sampleId, pStartTime, pDuration); + + log.verbose3f("\"%s\": ReadSample: start %" PRIu64 " duration %" PRId64, + GetFile().GetFilename().c_str(), (pStartTime ? *pStartTime : 0), + (pDuration ? *pDuration : 0)); + } + if (pRenderingOffset) { + *pRenderingOffset = GetSampleRenderingOffset(sampleId); + + log.verbose3f("\"%s\": ReadSample: renderingOffset %" PRId64, + GetFile().GetFilename().c_str(), *pRenderingOffset); + } + if (pIsSyncSample) { + *pIsSyncSample = IsSyncSample(sampleId); + + log.verbose3f("\"%s\": ReadSample: isSyncSample %u", + GetFile().GetFilename().c_str(), *pIsSyncSample); + } + } + + catch (Exception* x) { + if( bufferMalloc ) { + MP4Free( *ppBytes ); + *ppBytes = NULL; + } + + if( m_File.IsWriteMode() ) + m_File.SetPosition( oldPos, fin ); + + throw x; + } + + if( m_File.IsWriteMode() ) + m_File.SetPosition( oldPos, fin ); +} + +void MP4Track::ReadSampleFragment( + MP4SampleId sampleId, + uint32_t sampleOffset, + uint16_t sampleLength, + uint8_t* pDest) +{ + if (sampleId == MP4_INVALID_SAMPLE_ID) { + throw new Exception("invalid sample id", + __FILE__, __LINE__, __FUNCTION__ ); + } + + if (sampleId != m_cachedReadSampleId) { + MP4Free(m_pCachedReadSample); + m_pCachedReadSample = NULL; + m_cachedReadSampleSize = 0; + m_cachedReadSampleId = MP4_INVALID_SAMPLE_ID; + + ReadSample( + sampleId, + &m_pCachedReadSample, + &m_cachedReadSampleSize); + + m_cachedReadSampleId = sampleId; + } + + if (sampleOffset + sampleLength > m_cachedReadSampleSize) { + throw new Exception("offset and/or length are too large", + __FILE__, __LINE__, __FUNCTION__ ); + } + + memcpy(pDest, &m_pCachedReadSample[sampleOffset], sampleLength); +} + +void MP4Track::WriteSample( + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample ) +{ + uint8_t curMode = 0; + + log.verbose3f("\"%s\": WriteSample: track %u id %u size %u (0x%x) ", + GetFile().GetFilename().c_str(), + m_trackId, m_writeSampleId, numBytes, numBytes); + + if (pBytes == NULL && numBytes > 0) { + throw new Exception("no sample data", __FILE__, __LINE__, __FUNCTION__ ); + } + + if (m_isAmr == AMR_UNINITIALIZED ) { + // figure out if this is an AMR audio track + if (m_trakAtom.FindAtom("trak.mdia.minf.stbl.stsd.samr") || + m_trakAtom.FindAtom("trak.mdia.minf.stbl.stsd.sawb")) { + m_isAmr = AMR_TRUE; + m_curMode = (pBytes[0] >> 3) & 0x000F; + } else { + m_isAmr = AMR_FALSE; + } + } + + if (m_isAmr == AMR_TRUE) { + curMode = (pBytes[0] >> 3) &0x000F; // The mode is in the first byte + } + + if (duration == MP4_INVALID_DURATION) { + duration = GetFixedSampleDuration(); + } + + log.verbose3f("\"%s\": duration %" PRIu64, GetFile().GetFilename().c_str(), + duration); + + if ((m_isAmr == AMR_TRUE) && + (m_curMode != curMode)) { + WriteChunkBuffer(); + m_curMode = curMode; + } + + // append sample bytes to chunk buffer + if( m_sizeOfDataInChunkBuffer + numBytes > m_chunkBufferSize ) { + m_pChunkBuffer = (uint8_t*)MP4Realloc(m_pChunkBuffer, m_chunkBufferSize + numBytes); + if (m_pChunkBuffer == NULL) + return; + + m_chunkBufferSize += numBytes; + } + + memcpy(&m_pChunkBuffer[m_sizeOfDataInChunkBuffer], pBytes, numBytes); + m_sizeOfDataInChunkBuffer += numBytes; + m_chunkSamples++; + m_chunkDuration += duration; + + UpdateSampleSizes(m_writeSampleId, numBytes); + + UpdateSampleTimes(duration); + + UpdateRenderingOffsets(m_writeSampleId, renderingOffset); + + UpdateSyncSamples(m_writeSampleId, isSyncSample); + + if (IsChunkFull(m_writeSampleId)) { + WriteChunkBuffer(); + m_curMode = curMode; + } + + UpdateDurations(duration); + + UpdateModificationTimes(); + + m_writeSampleId++; +} + +void MP4Track::WriteSampleDependency( + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample, + uint32_t dependencyFlags ) +{ + m_sdtpLog.push_back( dependencyFlags ); // record dependency flags for processing at finish + WriteSample( pBytes, numBytes, duration, renderingOffset, isSyncSample ); +} + +void MP4Track::WriteChunkBuffer() +{ + if (m_sizeOfDataInChunkBuffer == 0) { + return; + } + + uint64_t chunkOffset = m_File.GetPosition(); + + // write chunk buffer + m_File.WriteBytes(m_pChunkBuffer, m_sizeOfDataInChunkBuffer); + + log.verbose3f("\"%s\": WriteChunk: track %u offset 0x%" PRIx64 " size %u (0x%x) numSamples %u", + GetFile().GetFilename().c_str(), + m_trackId, chunkOffset, m_sizeOfDataInChunkBuffer, + m_sizeOfDataInChunkBuffer, m_chunkSamples); + + UpdateSampleToChunk(m_writeSampleId, + m_pChunkCountProperty->GetValue() + 1, + m_chunkSamples); + + UpdateChunkOffsets(chunkOffset); + + // note: we do not free our chunk buffer; we reuse it, expanding as needed. + // It gets zapped when this class goes out of scope + m_sizeOfDataInChunkBuffer = 0; + m_chunkSamples = 0; + m_chunkDuration = 0; +} + +void MP4Track::FinishWrite(uint32_t options) +{ + FinishSdtp(); + + // write out any remaining samples in chunk buffer + WriteChunkBuffer(); + + if (m_pStszFixedSampleSizeProperty == NULL && + m_stsz_sample_bits == 4) { + if (m_have_stz2_4bit_sample) { + ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(m_stz2_4bit_sample_value); + m_pStszSampleSizeProperty->IncrementValue(); + } + } + + // record buffer size and bitrates + MP4BitfieldProperty* pBufferSizeProperty; + + if (m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + pBufferSizeProperty->SetValue(GetMaxSampleSize()); + } + + // don't overwrite bitrate if it was requested in the Close call + if( !(options & MP4_CLOSE_DO_NOT_COMPUTE_BITRATE)) { + MP4Integer32Property* pBitrateProperty; + + if (m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.maxBitrate", + (MP4Property**)&pBitrateProperty)) { + pBitrateProperty->SetValue(GetMaxBitrate()); + } + + if (m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate", + (MP4Property**)&pBitrateProperty)) { + pBitrateProperty->SetValue(GetAvgBitrate()); + } + } + + // cleaup trak.udta + MP4BytesProperty* nameProperty = NULL; + m_trakAtom.FindProperty("trak.udta.name.value", (MP4Property**) &nameProperty); + if( nameProperty != NULL && nameProperty->GetValueSize() == 0 ){ + // Zero length name value--delete name, and then udta if no child atoms + MP4Atom* name = m_trakAtom.FindChildAtom("udta.name"); + if( name ) { + MP4Atom* udta = name->GetParentAtom(); + udta->DeleteChildAtom( name ); + delete name; + + if( udta->GetNumberOfChildAtoms() == 0 ) { + udta->GetParentAtom()->DeleteChildAtom( udta ); + delete udta; + } + } + } +} + +// Process sdtp log and add sdtp atom. +// +// Testing (subjective) showed a marked improvement with QuickTime +// player on Mac OS X when scrubbing. Best results were obtained +// from encodings using low number of bframes. It's expected sdtp may help +// other QT-based players. +// +void MP4Track::FinishSdtp() +{ + // bail if log is empty -- indicates dependency information was not written + if( m_sdtpLog.empty() ) + return; + + MP4SdtpAtom* sdtp = (MP4SdtpAtom*)m_trakAtom.FindAtom( "trak.mdia.minf.stbl.sdtp" ); + if( !sdtp ) + sdtp = (MP4SdtpAtom*)AddAtom( "trak.mdia.minf.stbl", "sdtp" ); + sdtp->data.SetValue( (const uint8_t*)m_sdtpLog.data(), (uint32_t)m_sdtpLog.size() ); + + // add avc1 compatibility indicator if not present + MP4FtypAtom* ftyp = (MP4FtypAtom*)m_File.FindAtom( "ftyp" ); + if( ftyp ) { + bool found = false; + const uint32_t max = ftyp->compatibleBrands.GetCount(); + for( uint32_t i = 0; i < max; i++ ) { + if( !strcmp( ftyp->compatibleBrands.GetValue( i ), "avc1" )) { + found = true; + break; + } + } + + if( !found ) + ftyp->compatibleBrands.AddValue( "avc1" ); + } +} + +bool MP4Track::IsChunkFull(MP4SampleId sampleId) +{ + if (m_samplesPerChunk) { + return m_chunkSamples >= m_samplesPerChunk; + } + + ASSERT(m_durationPerChunk); + return m_chunkDuration >= m_durationPerChunk; +} + +uint32_t MP4Track::GetNumberOfSamples() +{ + return m_pStszSampleCountProperty->GetValue(); +} + +uint32_t MP4Track::GetSampleSize(MP4SampleId sampleId) +{ + if (m_pStszFixedSampleSizeProperty != NULL) { + uint32_t fixedSampleSize = + m_pStszFixedSampleSizeProperty->GetValue(); + + if (fixedSampleSize != 0) { + return fixedSampleSize * m_bytesPerSample; + } + } + // will have to check for 4 bit sample size here + if (m_stsz_sample_bits == 4) { + uint8_t value = m_pStszSampleSizeProperty->GetValue((sampleId - 1) / 2); + if ((sampleId - 1) / 2 == 0) { + value >>= 4; + } else value &= 0xf; + return m_bytesPerSample * value; + } + return m_bytesPerSample * + m_pStszSampleSizeProperty->GetValue(sampleId - 1); +} + +uint32_t MP4Track::GetMaxSampleSize() +{ + if (m_pStszFixedSampleSizeProperty != NULL) { + uint32_t fixedSampleSize = + m_pStszFixedSampleSizeProperty->GetValue(); + + if (fixedSampleSize != 0) { + return fixedSampleSize * m_bytesPerSample; + } + } + + uint32_t maxSampleSize = 0; + uint32_t numSamples = m_pStszSampleSizeProperty->GetCount(); + for (MP4SampleId sid = 1; sid <= numSamples; sid++) { + uint32_t sampleSize = + m_pStszSampleSizeProperty->GetValue(sid - 1); + if (sampleSize > maxSampleSize) { + maxSampleSize = sampleSize; + } + } + return maxSampleSize * m_bytesPerSample; +} + +uint64_t MP4Track::GetTotalOfSampleSizes() +{ + uint64_t retval; + if (m_pStszFixedSampleSizeProperty != NULL) { + uint32_t fixedSampleSize = + m_pStszFixedSampleSizeProperty->GetValue(); + + // if fixed sample size, just need to multiply by number of samples + if (fixedSampleSize != 0) { + retval = m_bytesPerSample; + retval *= fixedSampleSize; + retval *= GetNumberOfSamples(); + return retval; + } + } + + // else non-fixed sample size, sum them + uint64_t totalSampleSizes = 0; + uint32_t numSamples = m_pStszSampleSizeProperty->GetCount(); + for (MP4SampleId sid = 1; sid <= numSamples; sid++) { + uint32_t sampleSize = + m_pStszSampleSizeProperty->GetValue(sid - 1); + totalSampleSizes += sampleSize; + } + return totalSampleSizes * m_bytesPerSample; +} + +void MP4Track::SampleSizePropertyAddValue (uint32_t size) +{ + // this has to deal with different sample size values + switch (m_pStszSampleSizeProperty->GetType()) { + case Integer32Property: + ((MP4Integer32Property *)m_pStszSampleSizeProperty)->AddValue(size); + break; + case Integer16Property: + ((MP4Integer16Property *)m_pStszSampleSizeProperty)->AddValue(size); + break; + case Integer8Property: + if (m_stsz_sample_bits == 4) { + if (m_have_stz2_4bit_sample == false) { + m_have_stz2_4bit_sample = true; + m_stz2_4bit_sample_value = size << 4; + return; + } else { + m_have_stz2_4bit_sample = false; + size &= 0xf; + size |= m_stz2_4bit_sample_value; + } + } + ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(size); + break; + default: + break; + } + + + // m_pStszSampleSizeProperty->IncrementValue(); +} + +void MP4Track::UpdateSampleSizes(MP4SampleId sampleId, uint32_t numBytes) +{ + if (m_bytesPerSample > 1) { + if ((numBytes % m_bytesPerSample) != 0) { + // error + log.errorf("%s: \"%s\": numBytes %u not divisible by bytesPerSample %u sampleId %u", + __FUNCTION__, GetFile().GetFilename().c_str(), + numBytes, m_bytesPerSample, sampleId); + } + numBytes /= m_bytesPerSample; + } + // for first sample + // wmay - if we are adding, we want to make sure that + // we don't inadvertently set up the fixed size again. + // so, we check the number of samples + if (sampleId == 1 && GetNumberOfSamples() == 0) { + if (m_pStszFixedSampleSizeProperty == NULL || + numBytes == 0) { + // special case of first sample is zero bytes in length + // leave m_pStszFixedSampleSizeProperty at 0 + // start recording variable sample sizes + if (m_pStszFixedSampleSizeProperty != NULL) + m_pStszFixedSampleSizeProperty->SetValue(0); + SampleSizePropertyAddValue(0); + } else { + // presume sample size is fixed + m_pStszFixedSampleSizeProperty->SetValue(numBytes); + } + } else { // sampleId > 1 + + uint32_t fixedSampleSize = 0; + if (m_pStszFixedSampleSizeProperty != NULL) { + fixedSampleSize = m_pStszFixedSampleSizeProperty->GetValue(); + } + + // if we don't have a fixed size, or the current sample size + // doesn't match our sample size, we need to write the current + // sample size into the table + if (fixedSampleSize == 0 || numBytes != fixedSampleSize) { + if (fixedSampleSize != 0) { + // fixed size was set; we need to clear fixed sample size + m_pStszFixedSampleSizeProperty->SetValue(0); + + // and create sizes for all previous samples + // use GetNumberOfSamples due to needing the total number + // not just the appended part of the file + uint32_t samples = GetNumberOfSamples(); + for (MP4SampleId sid = 1; sid <= samples; sid++) { + SampleSizePropertyAddValue(fixedSampleSize); + } + } + // add size value for this sample + SampleSizePropertyAddValue(numBytes); + } + } + // either way, we increment the number of samples. + m_pStszSampleCountProperty->IncrementValue(); +} + +uint32_t MP4Track::GetAvgBitrate() +{ + if (GetDuration() == 0) { + return 0; + } + + double calc = double(GetTotalOfSampleSizes()); + // this is a bit better - we use the whole duration + calc *= 8.0; + calc *= GetTimeScale(); + calc /= double(GetDuration()); + // we might want to think about rounding to the next 100 or 1000 + return (uint32_t) ceil(calc); +} + +uint32_t MP4Track::GetMaxBitrate() +{ + uint32_t timeScale = GetTimeScale(); + MP4SampleId numSamples = GetNumberOfSamples(); + uint32_t maxBytesPerSec = 0; + uint32_t bytesThisSec = 0; + MP4Timestamp thisSecStart = 0; + MP4Timestamp lastSampleTime = 0; + uint32_t lastSampleSize = 0; + + MP4SampleId thisSecStartSid = 1; + for (MP4SampleId sid = 1; sid <= numSamples; sid++) { + uint32_t sampleSize; + MP4Timestamp sampleTime; + + sampleSize = GetSampleSize(sid); + GetSampleTimes(sid, &sampleTime, NULL); + + if (sampleTime < thisSecStart + timeScale) { + bytesThisSec += sampleSize; + lastSampleSize = sampleSize; + lastSampleTime = sampleTime; + } else { + // we've already written the last sample and sampleSize. + // this means that we've probably overflowed the last second + // calculate the time we've overflowed + MP4Duration overflow_dur = + (thisSecStart + timeScale) - lastSampleTime; + // calculate the duration of the last sample + MP4Duration lastSampleDur = sampleTime - lastSampleTime; + // now, calculate the number of bytes we overflowed. Round up. + if( lastSampleDur > 0 ) { + uint32_t overflow_bytes = 0; + overflow_bytes = ((lastSampleSize * overflow_dur) + (lastSampleDur - 1)) / lastSampleDur; + + if (bytesThisSec - overflow_bytes > maxBytesPerSec) { + maxBytesPerSec = bytesThisSec - overflow_bytes; + } + } + + // now adjust the values for this sample. Remove the bytes + // from the first sample in this time frame + lastSampleTime = sampleTime; + lastSampleSize = sampleSize; + bytesThisSec += sampleSize; + bytesThisSec -= GetSampleSize(thisSecStartSid); + thisSecStartSid++; + GetSampleTimes(thisSecStartSid, &thisSecStart, NULL); + } + } + + return maxBytesPerSec * 8; +} + +uint32_t MP4Track::GetSampleStscIndex(MP4SampleId sampleId) +{ + uint32_t stscIndex; + uint32_t numStscs = m_pStscCountProperty->GetValue(); + + if (numStscs == 0) { + throw new Exception("No data chunks exist", __FILE__, __LINE__, __FUNCTION__ ); + } + + for (stscIndex = 0; stscIndex < numStscs; stscIndex++) { + if (sampleId < m_pStscFirstSampleProperty->GetValue(stscIndex)) { + ASSERT(stscIndex != 0); + stscIndex -= 1; + break; + } + } + if (stscIndex == numStscs) { + ASSERT(stscIndex != 0); + stscIndex -= 1; + } + + return stscIndex; +} + +File* MP4Track::GetSampleFile( MP4SampleId sampleId ) +{ + uint32_t stscIndex = GetSampleStscIndex( sampleId ); + uint32_t stsdIndex = m_pStscSampleDescrIndexProperty->GetValue( stscIndex ); + + // check if the answer will be the same as last time + if( m_lastStsdIndex && stsdIndex == m_lastStsdIndex ) + return m_lastSampleFile; + + MP4Atom* pStsdAtom = m_trakAtom.FindAtom( "trak.mdia.minf.stbl.stsd" ); + ASSERT( pStsdAtom ); + + MP4Atom* pStsdEntryAtom = pStsdAtom->GetChildAtom( stsdIndex - 1 ); + ASSERT( pStsdEntryAtom ); + + MP4Integer16Property* pDrefIndexProperty = NULL; + if( !pStsdEntryAtom->FindProperty( "*.dataReferenceIndex", (MP4Property**)&pDrefIndexProperty ) || + pDrefIndexProperty == NULL ) + { + throw new Exception( "invalid stsd entry", __FILE__, __LINE__, __FUNCTION__ ); + } + + uint32_t drefIndex = pDrefIndexProperty->GetValue(); + + MP4Atom* pDrefAtom = m_trakAtom.FindAtom( "trak.mdia.minf.dinf.dref" ); + ASSERT(pDrefAtom); + + MP4Atom* pUrlAtom = pDrefAtom->GetChildAtom( drefIndex - 1 ); + ASSERT( pUrlAtom ); + + File* file; + + // make sure this is actually a url atom (somtimes it's "cios", like in iTunes videos) + if( strcmp(pUrlAtom->GetType(), "url ") || + pUrlAtom->GetFlags() & 1 ) { + file = NULL; // self-contained + } + else { + MP4StringProperty* pLocationProperty = NULL; + ASSERT( pUrlAtom->FindProperty( "*.location", (MP4Property**)&pLocationProperty) ); + ASSERT( pLocationProperty ); + + const char* url = pLocationProperty->GetValue(); + + log.verbose3f("\"%s\": dref url = %s", GetFile().GetFilename().c_str(), + url); + + file = (File*)-1; + + // attempt to open url if it's a file url + // currently this is the only thing we understand + if( !strncmp( url, "file:", 5 )) { + const char* fileName = url + 5; + + if( !strncmp(fileName, "//", 2 )) + fileName = strchr( fileName + 2, '/' ); + + if( fileName ) { + file = new File( fileName, File::MODE_READ ); + if( !file->open() ) { + delete file; + file = (File*)-1; + } + } + } + } + + if( m_lastSampleFile ) + m_lastSampleFile->close(); + + // cache the answer + m_lastStsdIndex = stsdIndex; + m_lastSampleFile = file; + + return file; +} + +uint64_t MP4Track::GetSampleFileOffset(MP4SampleId sampleId) +{ + uint32_t stscIndex = + GetSampleStscIndex(sampleId); + + // firstChunk is the chunk index of the first chunk with + // samplesPerChunk samples in the chunk. There may be multiples - + // ie: several chunks with the same number of samples per chunk. + uint32_t firstChunk = + m_pStscFirstChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSample = + m_pStscFirstSampleProperty->GetValue(stscIndex); + + uint32_t samplesPerChunk = + m_pStscSamplesPerChunkProperty->GetValue(stscIndex); + + // chunkId tells which is the absolute chunk number that this sample + // is stored in. + MP4ChunkId chunkId = firstChunk + + ((sampleId - firstSample) / samplesPerChunk); + + // chunkOffset is the file offset (absolute) for the start of the chunk + uint64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1); + + MP4SampleId firstSampleInChunk = + sampleId - ((sampleId - firstSample) % samplesPerChunk); + + // need cumulative samples sizes from firstSample to sampleId - 1 + uint32_t sampleOffset = 0; + for (MP4SampleId i = firstSampleInChunk; i < sampleId; i++) { + sampleOffset += GetSampleSize(i); + } + + return chunkOffset + sampleOffset; +} + +void MP4Track::UpdateSampleToChunk(MP4SampleId sampleId, + MP4ChunkId chunkId, uint32_t samplesPerChunk) +{ + uint32_t numStsc = m_pStscCountProperty->GetValue(); + + // if samplesPerChunk == samplesPerChunk of last entry + if (numStsc && samplesPerChunk == + m_pStscSamplesPerChunkProperty->GetValue(numStsc-1)) { + + // nothing to do + + } else { + // add stsc entry + m_pStscFirstChunkProperty->AddValue(chunkId); + m_pStscSamplesPerChunkProperty->AddValue(samplesPerChunk); + m_pStscSampleDescrIndexProperty->AddValue(1); + m_pStscFirstSampleProperty->AddValue(sampleId - samplesPerChunk + 1); + + m_pStscCountProperty->IncrementValue(); + } +} + +void MP4Track::UpdateChunkOffsets(uint64_t chunkOffset) +{ + if (m_pChunkOffsetProperty->GetType() == Integer32Property) { + ((MP4Integer32Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset); + } else { + ((MP4Integer64Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset); + } + m_pChunkCountProperty->IncrementValue(); +} + +MP4Duration MP4Track::GetFixedSampleDuration() +{ + uint32_t numStts = m_pSttsCountProperty->GetValue(); + + if (numStts == 0) { + return m_fixedSampleDuration; + } + if (numStts != 1) { + return MP4_INVALID_DURATION; // sample duration is not fixed + } + return m_pSttsSampleDeltaProperty->GetValue(0); +} + +void MP4Track::SetFixedSampleDuration(MP4Duration duration) +{ + uint32_t numStts = m_pSttsCountProperty->GetValue(); + + // setting this is only allowed before samples have been written + if (numStts != 0) { + return; + } + m_fixedSampleDuration = duration; + return; +} + +void MP4Track::GetSampleTimes(MP4SampleId sampleId, + MP4Timestamp* pStartTime, MP4Duration* pDuration) +{ + uint32_t numStts = m_pSttsCountProperty->GetValue(); + MP4SampleId sid; + MP4Duration elapsed; + + + if (m_cachedSttsSid != MP4_INVALID_SAMPLE_ID && sampleId >= m_cachedSttsSid) { + sid = m_cachedSttsSid; + elapsed = m_cachedSttsElapsed; + } else { + m_cachedSttsIndex = 0; + sid = 1; + elapsed = 0; + } + + for (uint32_t sttsIndex = m_cachedSttsIndex; sttsIndex < numStts; sttsIndex++) { + uint32_t sampleCount = + m_pSttsSampleCountProperty->GetValue(sttsIndex); + uint32_t sampleDelta = + m_pSttsSampleDeltaProperty->GetValue(sttsIndex); + + if (sampleId <= sid + sampleCount - 1) { + if (pStartTime) { + *pStartTime = (sampleId - sid); + *pStartTime *= sampleDelta; + *pStartTime += elapsed; + } + if (pDuration) { + *pDuration = sampleDelta; + } + + m_cachedSttsIndex = sttsIndex; + m_cachedSttsSid = sid; + m_cachedSttsElapsed = elapsed; + + return; + } + sid += sampleCount; + elapsed += sampleCount * sampleDelta; + } + + throw new Exception("sample id out of range", + __FILE__, __LINE__, __FUNCTION__ ); +} + +MP4SampleId MP4Track::GetSampleIdFromTime( + MP4Timestamp when, + bool wantSyncSample) +{ + uint32_t numStts = m_pSttsCountProperty->GetValue(); + MP4SampleId sid = 1; + MP4Duration elapsed = 0; + + for (uint32_t sttsIndex = 0; sttsIndex < numStts; sttsIndex++) { + uint32_t sampleCount = + m_pSttsSampleCountProperty->GetValue(sttsIndex); + uint32_t sampleDelta = + m_pSttsSampleDeltaProperty->GetValue(sttsIndex); + + if (sampleDelta == 0 && sttsIndex < numStts - 1) { + log.warningf("%s: \"%s\": Zero sample duration, stts entry %u", + __FUNCTION__, GetFile().GetFilename().c_str(), sttsIndex); + } + + MP4Duration d = when - elapsed; + + if (d <= sampleCount * sampleDelta) { + MP4SampleId sampleId = sid; + if (sampleDelta) { + sampleId += (d / sampleDelta); + } + + if (wantSyncSample) { + return GetNextSyncSample(sampleId); + } + return sampleId; + } + + sid += sampleCount; + elapsed += sampleCount * sampleDelta; + } + + throw new Exception("time out of range", + __FILE__, __LINE__, __FUNCTION__); + + return 0; // satisfy MS compiler +} + +void MP4Track::UpdateSampleTimes(MP4Duration duration) +{ + uint32_t numStts = m_pSttsCountProperty->GetValue(); + + // if duration == duration of last entry + if (numStts + && duration == m_pSttsSampleDeltaProperty->GetValue(numStts-1)) { + // increment last entry sampleCount + m_pSttsSampleCountProperty->IncrementValue(1, numStts-1); + + } else { + // add stts entry, sampleCount = 1, sampleDuration = duration + m_pSttsSampleCountProperty->AddValue(1); + m_pSttsSampleDeltaProperty->AddValue(duration); + m_pSttsCountProperty->IncrementValue();; + } +} + +uint32_t MP4Track::GetSampleCttsIndex(MP4SampleId sampleId, + MP4SampleId* pFirstSampleId) +{ + uint32_t numCtts = m_pCttsCountProperty->GetValue(); + MP4SampleId sid; + + if (m_cachedCttsSid != MP4_INVALID_SAMPLE_ID && sampleId >= m_cachedCttsSid) { + sid = m_cachedCttsSid; + } else { + m_cachedCttsIndex = 0; + sid = 1; + } + + for (uint32_t cttsIndex = m_cachedCttsIndex; cttsIndex < numCtts; cttsIndex++) { + uint32_t sampleCount = + m_pCttsSampleCountProperty->GetValue(cttsIndex); + + if (sampleId <= sid + sampleCount - 1) { + if (pFirstSampleId) { + *pFirstSampleId = sid; + } + + m_cachedCttsIndex = cttsIndex; + m_cachedCttsSid = sid; + + return cttsIndex; + } + sid += sampleCount; + } + + throw new Exception("sample id out of range", + __FILE__, __LINE__, __FUNCTION__ ); + return 0; // satisfy MS compiler +} + +MP4Duration MP4Track::GetSampleRenderingOffset(MP4SampleId sampleId) +{ + if (m_pCttsCountProperty == NULL) { + return 0; + } + if (m_pCttsCountProperty->GetValue() == 0) { + return 0; + } + + uint32_t cttsIndex = GetSampleCttsIndex(sampleId); + + return m_pCttsSampleOffsetProperty->GetValue(cttsIndex); +} + +void MP4Track::UpdateRenderingOffsets(MP4SampleId sampleId, + MP4Duration renderingOffset) +{ + // if ctts atom doesn't exist + if (m_pCttsCountProperty == NULL) { + + // no rendering offset, so nothing to do + if (renderingOffset == 0) { + return; + } + + // else create a ctts atom + MP4Atom* pCttsAtom = AddAtom("trak.mdia.minf.stbl", "ctts"); + + // and get handles on the properties + ASSERT(pCttsAtom->FindProperty( + "ctts.entryCount", + (MP4Property**)&m_pCttsCountProperty)); + + ASSERT(pCttsAtom->FindProperty( + "ctts.entries.sampleCount", + (MP4Property**)&m_pCttsSampleCountProperty)); + + ASSERT(pCttsAtom->FindProperty( + "ctts.entries.sampleOffset", + (MP4Property**)&m_pCttsSampleOffsetProperty)); + + // if this is not the first sample + if (sampleId > 1) { + // add a ctts entry for all previous samples + // with rendering offset equal to zero + m_pCttsSampleCountProperty->AddValue(sampleId - 1); + m_pCttsSampleOffsetProperty->AddValue(0); + m_pCttsCountProperty->IncrementValue();; + } + } + + // ctts atom exists (now) + + uint32_t numCtts = m_pCttsCountProperty->GetValue(); + + // if renderingOffset == renderingOffset of last entry + if (numCtts && renderingOffset + == m_pCttsSampleOffsetProperty->GetValue(numCtts-1)) { + + // increment last entry sampleCount + m_pCttsSampleCountProperty->IncrementValue(1, numCtts-1); + + } else { + // add ctts entry, sampleCount = 1, sampleOffset = renderingOffset + m_pCttsSampleCountProperty->AddValue(1); + m_pCttsSampleOffsetProperty->AddValue(renderingOffset); + m_pCttsCountProperty->IncrementValue(); + } +} + +void MP4Track::SetSampleRenderingOffset(MP4SampleId sampleId, + MP4Duration renderingOffset) +{ + // check if any ctts entries exist + if (m_pCttsCountProperty == NULL + || m_pCttsCountProperty->GetValue() == 0) { + // if not then Update routine can be used + // to create a ctts entry for samples before this one + // and a ctts entry for this sample + UpdateRenderingOffsets(sampleId, renderingOffset); + + // but we also need a ctts entry + // for all samples after this one + uint32_t afterSamples = GetNumberOfSamples() - sampleId; + + if (afterSamples) { + m_pCttsSampleCountProperty->AddValue(afterSamples); + m_pCttsSampleOffsetProperty->AddValue(0); + m_pCttsCountProperty->IncrementValue();; + } + + return; + } + + MP4SampleId firstSampleId; + uint32_t cttsIndex = GetSampleCttsIndex(sampleId, &firstSampleId); + + // do nothing in the degenerate case + if (renderingOffset == + m_pCttsSampleOffsetProperty->GetValue(cttsIndex)) { + return; + } + + uint32_t sampleCount = + m_pCttsSampleCountProperty->GetValue(cttsIndex); + + // if this sample has it's own ctts entry + if (sampleCount == 1) { + // then just set the value, + // note we don't attempt to collapse entries + m_pCttsSampleOffsetProperty->SetValue(renderingOffset, cttsIndex); + return; + } + + MP4SampleId lastSampleId = firstSampleId + sampleCount - 1; + + // else we share this entry with other samples + // we need to insert our own entry + if (sampleId == firstSampleId) { + // our sample is the first one + m_pCttsSampleCountProperty-> + InsertValue(1, cttsIndex); + m_pCttsSampleOffsetProperty-> + InsertValue(renderingOffset, cttsIndex); + + m_pCttsSampleCountProperty-> + SetValue(sampleCount - 1, cttsIndex + 1); + + m_pCttsCountProperty->IncrementValue(); + + } else if (sampleId == lastSampleId) { + // our sample is the last one + m_pCttsSampleCountProperty-> + InsertValue(1, cttsIndex + 1); + m_pCttsSampleOffsetProperty-> + InsertValue(renderingOffset, cttsIndex + 1); + + m_pCttsSampleCountProperty-> + SetValue(sampleCount - 1, cttsIndex); + + m_pCttsCountProperty->IncrementValue(); + + } else { + // our sample is in the middle, UGH! + + // insert our new entry + m_pCttsSampleCountProperty-> + InsertValue(1, cttsIndex + 1); + m_pCttsSampleOffsetProperty-> + InsertValue(renderingOffset, cttsIndex + 1); + + // adjust count of previous entry + m_pCttsSampleCountProperty-> + SetValue(sampleId - firstSampleId, cttsIndex); + + // insert new entry for those samples beyond our sample + m_pCttsSampleCountProperty-> + InsertValue(lastSampleId - sampleId, cttsIndex + 2); + uint32_t oldRenderingOffset = + m_pCttsSampleOffsetProperty->GetValue(cttsIndex); + m_pCttsSampleOffsetProperty-> + InsertValue(oldRenderingOffset, cttsIndex + 2); + + m_pCttsCountProperty->IncrementValue(2); + } +} + +bool MP4Track::IsSyncSample(MP4SampleId sampleId) +{ + if (m_pStssCountProperty == NULL) { + return true; + } + + uint32_t numStss = m_pStssCountProperty->GetValue(); + uint32_t stssLIndex = 0; + uint32_t stssRIndex = numStss - 1; + + while (stssRIndex >= stssLIndex) { + uint32_t stssIndex = (stssRIndex + stssLIndex) >> 1; + MP4SampleId syncSampleId = + m_pStssSampleProperty->GetValue(stssIndex); + + if (sampleId == syncSampleId) { + return true; + } + + if (sampleId > syncSampleId) { + stssLIndex = stssIndex + 1; + } else { + stssRIndex = stssIndex - 1; + } + } + + return false; +} + +// N.B. "next" is inclusive of this sample id +MP4SampleId MP4Track::GetNextSyncSample(MP4SampleId sampleId) +{ + if (m_pStssCountProperty == NULL) { + return sampleId; + } + + uint32_t numStss = m_pStssCountProperty->GetValue(); + + for (uint32_t stssIndex = 0; stssIndex < numStss; stssIndex++) { + MP4SampleId syncSampleId = + m_pStssSampleProperty->GetValue(stssIndex); + + if (sampleId > syncSampleId) { + continue; + } + return syncSampleId; + } + + // LATER check stsh for alternate sample + + return MP4_INVALID_SAMPLE_ID; +} + +void MP4Track::UpdateSyncSamples(MP4SampleId sampleId, bool isSyncSample) +{ + if (isSyncSample) { + // if stss atom exists, add entry + if (m_pStssCountProperty) { + m_pStssSampleProperty->AddValue(sampleId); + m_pStssCountProperty->IncrementValue(); + } // else nothing to do (yet) + + } else { // !isSyncSample + // if stss atom doesn't exist, create one + if (m_pStssCountProperty == NULL) { + + MP4Atom* pStssAtom = AddAtom("trak.mdia.minf.stbl", "stss"); + + ASSERT(pStssAtom->FindProperty( + "stss.entryCount", + (MP4Property**)&m_pStssCountProperty)); + + ASSERT(pStssAtom->FindProperty( + "stss.entries.sampleNumber", + (MP4Property**)&m_pStssSampleProperty)); + + // set values for all samples that came before this one + uint32_t samples = GetNumberOfSamples(); + for (MP4SampleId sid = 1; sid < samples; sid++) { + m_pStssSampleProperty->AddValue(sid); + m_pStssCountProperty->IncrementValue(); + } + } // else nothing to do + } +} + +MP4Atom* MP4Track::AddAtom(const char* parentName, const char* childName) +{ + MP4Atom* pParentAtom = m_trakAtom.FindAtom(parentName); + ASSERT(pParentAtom); + + MP4Atom* pChildAtom = MP4Atom::CreateAtom(m_File, pParentAtom, childName); + + pParentAtom->AddChildAtom(pChildAtom); + + pChildAtom->Generate(); + + return pChildAtom; +} + +uint64_t MP4Track::GetDuration() +{ + return m_pMediaDurationProperty->GetValue(); +} + +uint32_t MP4Track::GetTimeScale() +{ + return m_pTimeScaleProperty->GetValue(); +} + +void MP4Track::UpdateDurations(MP4Duration duration) +{ + // update media, track, and movie durations + m_pMediaDurationProperty->SetValue( + m_pMediaDurationProperty->GetValue() + duration); + + MP4Duration movieDuration = ToMovieDuration( + m_pMediaDurationProperty->GetValue()); + m_pTrackDurationProperty->SetValue(movieDuration); + + m_File.UpdateDuration(m_pTrackDurationProperty->GetValue()); +} + +MP4Duration MP4Track::ToMovieDuration(MP4Duration trackDuration) +{ + return (trackDuration * m_File.GetTimeScale()) + / m_pTimeScaleProperty->GetValue(); +} + +void MP4Track::UpdateModificationTimes() +{ + // update media and track modification times + MP4Timestamp now = MP4GetAbsTimestamp(); + m_pMediaModificationProperty->SetValue(now); + m_pTrackModificationProperty->SetValue(now); +} + +uint32_t MP4Track::GetNumberOfChunks() +{ + return m_pChunkOffsetProperty->GetCount(); +} + +uint32_t MP4Track::GetChunkStscIndex(MP4ChunkId chunkId) +{ + uint32_t stscIndex; + uint32_t numStscs = m_pStscCountProperty->GetValue(); + + ASSERT(chunkId); + ASSERT(numStscs > 0); + + for (stscIndex = 0; stscIndex < numStscs; stscIndex++) { + if (chunkId < m_pStscFirstChunkProperty->GetValue(stscIndex)) { + ASSERT(stscIndex != 0); + break; + } + } + return stscIndex - 1; +} + +MP4Timestamp MP4Track::GetChunkTime(MP4ChunkId chunkId) +{ + uint32_t stscIndex = GetChunkStscIndex(chunkId); + + MP4ChunkId firstChunkId = + m_pStscFirstChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSample = + m_pStscFirstSampleProperty->GetValue(stscIndex); + + uint32_t samplesPerChunk = + m_pStscSamplesPerChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSampleInChunk = + firstSample + ((chunkId - firstChunkId) * samplesPerChunk); + + MP4Timestamp chunkTime; + + GetSampleTimes(firstSampleInChunk, &chunkTime, NULL); + + return chunkTime; +} + +uint32_t MP4Track::GetChunkSize(MP4ChunkId chunkId) +{ + uint32_t stscIndex = GetChunkStscIndex(chunkId); + + MP4ChunkId firstChunkId = + m_pStscFirstChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSample = + m_pStscFirstSampleProperty->GetValue(stscIndex); + + uint32_t samplesPerChunk = + m_pStscSamplesPerChunkProperty->GetValue(stscIndex); + + MP4SampleId firstSampleInChunk = + firstSample + ((chunkId - firstChunkId) * samplesPerChunk); + + // need cumulative sizes of samples in chunk + uint32_t chunkSize = 0; + for (uint32_t i = 0; i < samplesPerChunk; i++) { + chunkSize += GetSampleSize(firstSampleInChunk + i); + } + + return chunkSize; +} + +void MP4Track::ReadChunk(MP4ChunkId chunkId, + uint8_t** ppChunk, uint32_t* pChunkSize) +{ + ASSERT(chunkId); + ASSERT(ppChunk); + ASSERT(pChunkSize); + + uint64_t chunkOffset = + m_pChunkOffsetProperty->GetValue(chunkId - 1); + + *pChunkSize = GetChunkSize(chunkId); + *ppChunk = (uint8_t*)MP4Malloc(*pChunkSize); + + log.verbose3f("\"%s\": ReadChunk: track %u id %u offset 0x%" PRIx64 " size %u (0x%x)", + GetFile().GetFilename().c_str(), + m_trackId, chunkId, chunkOffset, *pChunkSize, *pChunkSize); + + uint64_t oldPos = m_File.GetPosition(); // only used in mode == 'w' + try { + m_File.SetPosition( chunkOffset ); + m_File.ReadBytes( *ppChunk, *pChunkSize ); + } + catch( Exception* x ) { + MP4Free( *ppChunk ); + *ppChunk = NULL; + + if( m_File.IsWriteMode() ) + m_File.SetPosition( oldPos ); + + throw x; + } + + if( m_File.IsWriteMode() ) + m_File.SetPosition( oldPos ); +} + +void MP4Track::RewriteChunk(MP4ChunkId chunkId, + uint8_t* pChunk, uint32_t chunkSize) +{ + uint64_t chunkOffset = m_File.GetPosition(); + + m_File.WriteBytes(pChunk, chunkSize); + + m_pChunkOffsetProperty->SetValue(chunkOffset, chunkId - 1); + + log.verbose3f("\"%s\": RewriteChunk: track %u id %u offset 0x%" PRIx64 " size %u (0x%x)", + GetFile().GetFilename().c_str(), + m_trackId, chunkId, chunkOffset, chunkSize, chunkSize); +} + +// map track type name aliases to official names + + +bool MP4Track::InitEditListProperties() +{ + m_pElstCountProperty = NULL; + m_pElstMediaTimeProperty = NULL; + m_pElstDurationProperty = NULL; + m_pElstRateProperty = NULL; + m_pElstReservedProperty = NULL; + + MP4Atom* pElstAtom = + m_trakAtom.FindAtom("trak.edts.elst"); + + if (!pElstAtom) { + return false; + } + + (void)pElstAtom->FindProperty( + "elst.entryCount", + (MP4Property**)&m_pElstCountProperty); + (void)pElstAtom->FindProperty( + "elst.entries.mediaTime", + (MP4Property**)&m_pElstMediaTimeProperty); + (void)pElstAtom->FindProperty( + "elst.entries.segmentDuration", + (MP4Property**)&m_pElstDurationProperty); + (void)pElstAtom->FindProperty( + "elst.entries.mediaRate", + (MP4Property**)&m_pElstRateProperty); + + (void)pElstAtom->FindProperty( + "elst.entries.reserved", + (MP4Property**)&m_pElstReservedProperty); + + return m_pElstCountProperty + && m_pElstMediaTimeProperty + && m_pElstDurationProperty + && m_pElstRateProperty + && m_pElstReservedProperty; +} + +MP4EditId MP4Track::AddEdit(MP4EditId editId) +{ + if (!m_pElstCountProperty) { + (void)m_File.AddDescendantAtoms(&m_trakAtom, "edts.elst"); + if (InitEditListProperties() == false) return MP4_INVALID_EDIT_ID; + } + + if (editId == MP4_INVALID_EDIT_ID) { + editId = m_pElstCountProperty->GetValue() + 1; + } + + m_pElstMediaTimeProperty->InsertValue(0, editId - 1); + m_pElstDurationProperty->InsertValue(0, editId - 1); + m_pElstRateProperty->InsertValue(1, editId - 1); + m_pElstReservedProperty->InsertValue(0, editId - 1); + + m_pElstCountProperty->IncrementValue(); + + return editId; +} + +void MP4Track::DeleteEdit(MP4EditId editId) +{ + if (editId == MP4_INVALID_EDIT_ID) { + throw new Exception("edit id can't be zero", + __FILE__, __LINE__, __FUNCTION__ ); + } + + if (!m_pElstCountProperty + || m_pElstCountProperty->GetValue() == 0) { + throw new Exception("no edits exist", + __FILE__, __LINE__, __FUNCTION__ ); + } + + m_pElstMediaTimeProperty->DeleteValue(editId - 1); + m_pElstDurationProperty->DeleteValue(editId - 1); + m_pElstRateProperty->DeleteValue(editId - 1); + m_pElstReservedProperty->DeleteValue(editId - 1); + + m_pElstCountProperty->IncrementValue(-1); + + // clean up if last edit is deleted + if (m_pElstCountProperty->GetValue() == 0) { + m_pElstCountProperty = NULL; + m_pElstMediaTimeProperty = NULL; + m_pElstDurationProperty = NULL; + m_pElstRateProperty = NULL; + m_pElstReservedProperty = NULL; + + m_trakAtom.DeleteChildAtom( + m_trakAtom.FindAtom("trak.edts")); + } +} + +MP4Timestamp MP4Track::GetEditStart( + MP4EditId editId) +{ + if (editId == MP4_INVALID_EDIT_ID) { + return MP4_INVALID_TIMESTAMP; + } else if (editId == 1) { + return 0; + } + return (MP4Timestamp)GetEditTotalDuration(editId - 1); +} + +MP4Duration MP4Track::GetEditTotalDuration( + MP4EditId editId) +{ + uint32_t numEdits = 0; + + if (m_pElstCountProperty) { + numEdits = m_pElstCountProperty->GetValue(); + } + + if (editId == MP4_INVALID_EDIT_ID) { + editId = numEdits; + } + + if (numEdits == 0 || editId > numEdits) { + return MP4_INVALID_DURATION; + } + + MP4Duration totalDuration = 0; + + for (MP4EditId eid = 1; eid <= editId; eid++) { + totalDuration += + m_pElstDurationProperty->GetValue(eid - 1); + } + + return totalDuration; +} + +MP4SampleId MP4Track::GetSampleIdFromEditTime( + MP4Timestamp editWhen, + MP4Timestamp* pStartTime, + MP4Duration* pDuration) +{ + MP4SampleId sampleId = MP4_INVALID_SAMPLE_ID; + uint32_t numEdits = 0; + + if (m_pElstCountProperty) { + numEdits = m_pElstCountProperty->GetValue(); + } + + if (numEdits) { + MP4Duration editElapsedDuration = 0; + + for (MP4EditId editId = 1; editId <= numEdits; editId++) { + // remember edit segment's start time (in edit timeline) + MP4Timestamp editStartTime = + (MP4Timestamp)editElapsedDuration; + + // accumulate edit segment's duration + editElapsedDuration += + m_pElstDurationProperty->GetValue(editId - 1); + + // calculate difference between the specified edit time + // and the end of this edit segment + if (editElapsedDuration - editWhen <= 0) { + // the specified time has not yet been reached + continue; + } + + // 'editWhen' is within this edit segment + + // calculate the specified edit time + // relative to just this edit segment + MP4Duration editOffset = + editWhen - editStartTime; + + // calculate the media (track) time that corresponds + // to the specified edit time based on the edit list + MP4Timestamp mediaWhen = + m_pElstMediaTimeProperty->GetValue(editId - 1) + + editOffset; + + // lookup the sample id for the media time + sampleId = GetSampleIdFromTime(mediaWhen, false); + + // lookup the sample's media start time and duration + MP4Timestamp sampleStartTime; + MP4Duration sampleDuration; + + GetSampleTimes(sampleId, &sampleStartTime, &sampleDuration); + + // calculate the difference if any between when the sample + // would naturally start and when it starts in the edit timeline + MP4Duration sampleStartOffset = + mediaWhen - sampleStartTime; + + // calculate the start time for the sample in the edit time line + MP4Timestamp editSampleStartTime = + editWhen - min(editOffset, sampleStartOffset); + + MP4Duration editSampleDuration = 0; + + // calculate how long this sample lasts in the edit list timeline + if (m_pElstRateProperty->GetValue(editId - 1) == 0) { + // edit segment is a "dwell" + // so sample duration is that of the edit segment + editSampleDuration = + m_pElstDurationProperty->GetValue(editId - 1); + + } else { + // begin with the natural sample duration + editSampleDuration = sampleDuration; + + // now shorten that if the edit segment starts + // after the sample would naturally start + if (editOffset < sampleStartOffset) { + editSampleDuration -= sampleStartOffset - editOffset; + } + + // now shorten that if the edit segment ends + // before the sample would naturally end + if (editElapsedDuration + < editSampleStartTime + sampleDuration) { + editSampleDuration -= (editSampleStartTime + sampleDuration) + - editElapsedDuration; + } + } + + if (pStartTime) { + *pStartTime = editSampleStartTime; + } + + if (pDuration) { + *pDuration = editSampleDuration; + } + + log.verbose2f("\"%s\": GetSampleIdFromEditTime: when %" PRIu64 " " + "sampleId %u start %" PRIu64 " duration %" PRId64, + GetFile().GetFilename().c_str(), + editWhen, sampleId, + editSampleStartTime, editSampleDuration); + + return sampleId; + } + + throw new Exception("time out of range", + __FILE__, __LINE__, __FUNCTION__ ); + + } else { // no edit list + sampleId = GetSampleIdFromTime(editWhen, false); + + if (pStartTime || pDuration) { + GetSampleTimes(sampleId, pStartTime, pDuration); + } + } + + return sampleId; +} + +void MP4Track::CalculateBytesPerSample () +{ + MP4Atom *pMedia = m_trakAtom.FindAtom("trak.mdia.minf.stbl.stsd"); + MP4Atom *pMediaData; + const char *media_data_name; + if (pMedia == NULL) return; + + if (pMedia->GetNumberOfChildAtoms() != 1) return; + + pMediaData = pMedia->GetChildAtom(0); + media_data_name = pMediaData->GetType(); + if ((ATOMID(media_data_name) == ATOMID("twos")) || + (ATOMID(media_data_name) == ATOMID("sowt"))) { + MP4IntegerProperty *chan, *sampleSize; + chan = (MP4IntegerProperty *)pMediaData->GetProperty(4); + sampleSize = (MP4IntegerProperty *)pMediaData->GetProperty(5); + m_bytesPerSample = chan->GetValue() * (sampleSize->GetValue() / 8); + } +} + +MP4Duration MP4Track::GetDurationPerChunk() +{ + return m_durationPerChunk; +} + +void MP4Track::SetDurationPerChunk( MP4Duration duration ) +{ + m_durationPerChunk = duration; +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4track.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4track.h new file mode 100644 index 00000000..2a649f20 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4track.h @@ -0,0 +1,294 @@ +/* + * 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 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Ximpo Group Ltd. [email protected] + */ + +#ifndef MP4V2_IMPL_MP4TRACK_H +#define MP4V2_IMPL_MP4TRACK_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +typedef uint32_t MP4ChunkId; + +// forward declarations +class MP4File; +class MP4Atom; +class MP4Property; +class MP4IntegerProperty; +class MP4Integer8Property; +class MP4Integer16Property; +class MP4Integer32Property; +class MP4Integer64Property; +class MP4StringProperty; + +class MP4Track +{ +public: + MP4Track(MP4File& file, MP4Atom& trakAtom); + + virtual ~MP4Track(); + + MP4TrackId GetId() { + return m_trackId; + } + + const char* GetType(); + + void SetType(const char* type); + + MP4File& GetFile() { + return m_File; + } + + MP4Atom& GetTrakAtom() { + return m_trakAtom; + } + + void ReadSample( + // input parameters + MP4SampleId sampleId, + // output parameters + uint8_t** ppBytes, + uint32_t* pNumBytes, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL, + MP4Duration* pRenderingOffset = NULL, + bool* pIsSyncSample = NULL, + bool* hasDependencyFlags = NULL, + uint32_t* dependencyFlags = NULL ); + + void WriteSample( + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration = 0, + MP4Duration renderingOffset = 0, + bool isSyncSample = true); + + void WriteSampleDependency( + const uint8_t* pBytes, + uint32_t numBytes, + MP4Duration duration, + MP4Duration renderingOffset, + bool isSyncSample, + uint32_t dependencyFlags ); + + virtual void FinishWrite(uint32_t options = 0); + + uint64_t GetDuration(); // in track timeScale units + uint32_t GetTimeScale(); + uint32_t GetNumberOfSamples(); + uint32_t GetSampleSize(MP4SampleId sampleId); + uint32_t GetMaxSampleSize(); + uint64_t GetTotalOfSampleSizes(); + uint32_t GetAvgBitrate(); // in bps + uint32_t GetMaxBitrate(); // in bps + + MP4Duration GetFixedSampleDuration(); + void SetFixedSampleDuration(MP4Duration duration); + + void GetSampleTimes(MP4SampleId sampleId, + MP4Timestamp* pStartTime, MP4Duration* pDuration); + + bool IsSyncSample(MP4SampleId sampleId); + + MP4SampleId GetSampleIdFromTime( + MP4Timestamp when, + bool wantSyncSample = false); + + MP4Duration GetSampleRenderingOffset(MP4SampleId sampleId); + void SetSampleRenderingOffset(MP4SampleId sampleId, + MP4Duration renderingOffset); + + MP4EditId AddEdit( + MP4EditId editId = MP4_INVALID_EDIT_ID); + + void DeleteEdit( + MP4EditId editId); + + MP4Timestamp GetEditStart( + MP4EditId editId); + + MP4Timestamp GetEditTotalDuration( + MP4EditId editId); + + MP4SampleId GetSampleIdFromEditTime( + MP4Timestamp editWhen, + MP4Timestamp* pStartTime = NULL, + MP4Duration* pDuration = NULL); + + // special operation for use during hint track packet assembly + void ReadSampleFragment( + MP4SampleId sampleId, + uint32_t sampleOffset, + uint16_t sampleLength, + uint8_t* pDest); + + // special operations for use during optimization + + uint32_t GetNumberOfChunks(); + + MP4Timestamp GetChunkTime(MP4ChunkId chunkId); + + void ReadChunk(MP4ChunkId chunkId, + uint8_t** ppChunk, uint32_t* pChunkSize); + + void RewriteChunk(MP4ChunkId chunkId, + uint8_t* pChunk, uint32_t chunkSize); + + MP4Duration GetDurationPerChunk(); + void SetDurationPerChunk( MP4Duration ); + +protected: + bool InitEditListProperties(); + + File* GetSampleFile( MP4SampleId sampleId ); + uint64_t GetSampleFileOffset(MP4SampleId sampleId); + uint32_t GetSampleStscIndex(MP4SampleId sampleId); + uint32_t GetChunkStscIndex(MP4ChunkId chunkId); + uint32_t GetChunkSize(MP4ChunkId chunkId); + uint32_t GetSampleCttsIndex(MP4SampleId sampleId, + MP4SampleId* pFirstSampleId = NULL); + MP4SampleId GetNextSyncSample(MP4SampleId sampleId); + + void UpdateSampleSizes(MP4SampleId sampleId, + uint32_t numBytes); + bool IsChunkFull(MP4SampleId sampleId); + void UpdateSampleToChunk(MP4SampleId sampleId, + MP4ChunkId chunkId, uint32_t samplesPerChunk); + void UpdateChunkOffsets(uint64_t chunkOffset); + void UpdateSampleTimes(MP4Duration duration); + void UpdateRenderingOffsets(MP4SampleId sampleId, + MP4Duration renderingOffset); + void UpdateSyncSamples(MP4SampleId sampleId, + bool isSyncSample); + + MP4Atom* AddAtom(const char* parentName, const char* childName); + + void UpdateDurations(MP4Duration duration); + MP4Duration ToMovieDuration(MP4Duration trackDuration); + + void UpdateModificationTimes(); + + void WriteChunkBuffer(); + + void CalculateBytesPerSample(); + + void FinishSdtp(); + +protected: + MP4File& m_File; + MP4Atom& m_trakAtom; // moov.trak[] + MP4TrackId m_trackId; // moov.trak[].tkhd.trackId + MP4StringProperty* m_pTypeProperty; // moov.trak[].mdia.hdlr.handlerType + + uint32_t m_lastStsdIndex; + File* m_lastSampleFile; + + // for efficient construction of hint track packets + MP4SampleId m_cachedReadSampleId; + uint8_t* m_pCachedReadSample; + uint32_t m_cachedReadSampleSize; + + // for writing + MP4SampleId m_writeSampleId; + MP4Duration m_fixedSampleDuration; + uint8_t* m_pChunkBuffer; + uint32_t m_chunkBufferSize; // Actual size of our chunk buffer. + uint32_t m_sizeOfDataInChunkBuffer; // Size of the data in the chunk buffer. + uint32_t m_chunkSamples; + MP4Duration m_chunkDuration; + + // controls for chunking + uint32_t m_samplesPerChunk; + MP4Duration m_durationPerChunk; + + uint32_t m_bytesPerSample; + + // controls for AMR chunking + int m_isAmr; + uint8_t m_curMode; + + MP4Integer32Property* m_pTimeScaleProperty; + MP4IntegerProperty* m_pTrackDurationProperty; // 32 or 64 bits + MP4IntegerProperty* m_pMediaDurationProperty; // 32 or 64 bits + MP4IntegerProperty* m_pTrackModificationProperty; // 32 or 64 bits + MP4IntegerProperty* m_pMediaModificationProperty; // 32 or 64 bits + + MP4Integer32Property* m_pStszFixedSampleSizeProperty; + MP4Integer32Property* m_pStszSampleCountProperty; + + void SampleSizePropertyAddValue(uint32_t bytes); + uint8_t m_stsz_sample_bits; + bool m_have_stz2_4bit_sample; + uint8_t m_stz2_4bit_sample_value; + MP4IntegerProperty* m_pStszSampleSizeProperty; + + MP4Integer32Property* m_pStscCountProperty; + MP4Integer32Property* m_pStscFirstChunkProperty; + MP4Integer32Property* m_pStscSamplesPerChunkProperty; + MP4Integer32Property* m_pStscSampleDescrIndexProperty; + MP4Integer32Property* m_pStscFirstSampleProperty; + + MP4Integer32Property* m_pChunkCountProperty; + MP4IntegerProperty* m_pChunkOffsetProperty; // 32 or 64 bits + + MP4Integer32Property* m_pSttsCountProperty; + MP4Integer32Property* m_pSttsSampleCountProperty; + MP4Integer32Property* m_pSttsSampleDeltaProperty; + + // for improve sequental timestamp index access + uint32_t m_cachedSttsIndex; + MP4SampleId m_cachedSttsSid; + MP4Timestamp m_cachedSttsElapsed; + + uint32_t m_cachedCttsIndex; + MP4SampleId m_cachedCttsSid; + + MP4Integer32Property* m_pCttsCountProperty; + MP4Integer32Property* m_pCttsSampleCountProperty; + MP4Integer32Property* m_pCttsSampleOffsetProperty; + + MP4Integer32Property* m_pStssCountProperty; + MP4Integer32Property* m_pStssSampleProperty; + + MP4Integer32Property* m_pElstCountProperty; + MP4IntegerProperty* m_pElstMediaTimeProperty; // 32 or 64 bits + MP4IntegerProperty* m_pElstDurationProperty; // 32 or 64 bits + MP4Integer16Property* m_pElstRateProperty; + MP4Integer16Property* m_pElstReservedProperty; + + string m_sdtpLog; // records frame types for H264 samples +}; + +MP4ARRAY_DECL(MP4Track, MP4Track*); + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4TRACK_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4util.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4util.cpp new file mode 100644 index 00000000..47bd74ea --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4util.cpp @@ -0,0 +1,352 @@ +/* + * 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-2005. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie [email protected] + * Bill May [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +bool MP4NameFirstMatches(const char* s1, const char* s2) +{ + if (s1 == NULL || *s1 == '\0' || s2 == NULL || *s2 == '\0') { + return false; + } + + if (*s2 == '*') { + return true; + } + + while (*s1 != '\0') { + if (*s2 == '\0' || strchr("[.", *s2)) { + break; + } + if (tolower(*s1) != tolower(*s2)) { + return false; + } + s1++; + s2++; + } + return true; +} + +bool MP4NameFirstIndex(const char* s, uint32_t* pIndex) +{ + if (s == NULL) { + return false; + } + + while (*s != '\0' && *s != '.') { + if (*s == '[') { + s++; + ASSERT(pIndex); + if (sscanf(s, "%u", pIndex) != 1) { + return false; + } + return true; + } + s++; + } + return false; +} + +char* MP4NameFirst(const char *s) +{ + if (s == NULL) { + return NULL; + } + + const char* end = s; + + while (*end != '\0' && *end != '.') { + end++; + } + + char* first = (char*)MP4Calloc((end - s) + 1); + + if (first) { + strncpy(first, s, end - s); + } + + return first; +} + +const char* MP4NameAfterFirst(const char *s) +{ + if (s == NULL) { + return NULL; + } + + while (*s != '\0') { + if (*s == '.') { + s++; + if (*s == '\0') { + return NULL; + } + return s; + } + s++; + } + return NULL; +} + +char* MP4ToBase16(const uint8_t* pData, uint32_t dataSize) +{ + if (dataSize) { + ASSERT(pData); + } + uint32_t size = 2 * dataSize + 1; + char* s = (char*)MP4Calloc(size); + + uint32_t i, j; + for (i = 0, j = 0; i < dataSize; i++) { + size -= snprintf(&s[j], size, "%02x", pData[i]); + j += 2; + } + + return s; /* N.B. caller is responsible for free'ing s */ +} + +char* MP4ToBase64(const uint8_t* pData, uint32_t dataSize) +{ + if (pData == NULL || dataSize == 0) return NULL; + + static const char encoding[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' + }; + + char* s = (char*)MP4Calloc((((dataSize + 2) * 4) / 3) + 1); + + const uint8_t* src = pData; + if (pData == NULL) return NULL; + char* dest = s; + uint32_t numGroups = dataSize / 3; + + for (uint32_t i = 0; i < numGroups; i++) { + *dest++ = encoding[src[0] >> 2]; + *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)]; + *dest++ = encoding[((src[1] & 0x0F) << 2) | (src[2] >> 6)]; + *dest++ = encoding[src[2] & 0x3F]; + src += 3; + } + + if (dataSize % 3 == 1) { + *dest++ = encoding[src[0] >> 2]; + *dest++ = encoding[((src[0] & 0x03) << 4)]; + *dest++ = '='; + *dest++ = '='; + } else if (dataSize % 3 == 2) { + *dest++ = encoding[src[0] >> 2]; + *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)]; + *dest++ = encoding[((src[1] & 0x0F) << 2)]; + *dest++ = '='; + } + *dest = '\0'; + return s; /* N.B. caller is responsible for free'ing s */ +} + +static bool convertBase64 (const char data, uint8_t *value) +{ + static const uint8_t decodingarr64[128] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + uint8_t index = (uint8_t)data; + if ((index & 0x80) != 0) return false; + + if (decodingarr64[index] == 0xff) return false; + *value = decodingarr64[index]; + return true; +} + +uint8_t *Base64ToBinary (const char *pData, uint32_t decodeSize, uint32_t *pDataSize) +{ + uint8_t *ret; + uint32_t size, ix, groups; + if (pData == NULL || decodeSize == 0 || pDataSize == NULL) + return NULL; + + if ((decodeSize % 4) != 0) { + // must be multiples of 4 characters + return NULL; + } + size = (decodeSize * 3) / 4; + groups = decodeSize / 4; + ret = (uint8_t *)MP4Calloc(size); + if (ret == NULL) return NULL; + for (ix = 0; ix < groups; ix++) { + uint8_t value[4]; + for (uint8_t jx = 0; jx < 4; jx++) { + if (pData[jx] == '=') { + if (ix != (groups - 1)) { + free(ret); + return NULL; + } + size--; + value[jx] = 0; + } else if (convertBase64(pData[jx], &value[jx]) == false) { + free(ret); + return NULL; + } + } + ret[(ix * 3)] = value[0] << 2 | ((value[1] >> 4) & 0x3); + ret[(ix * 3) + 1] = (value[1] << 4) | (value[2] >> 2 & 0xf); + ret[(ix * 3) + 2] = ((value[2] & 0x3) << 6) | value[3]; + pData += 4; + } + *pDataSize = size; + return ret; +} + +// log2 of value, rounded up +static uint8_t ilog2(uint64_t value) +{ + uint64_t powerOf2 = 1; + for (uint8_t i = 0; i < 64; i++) { + if (value <= powerOf2) { + return i; + } + powerOf2 <<= 1; + } + return 64; +} + +uint64_t MP4ConvertTime(uint64_t t, + uint32_t oldTimeScale, uint32_t newTimeScale) +{ + // avoid float point exception + if (oldTimeScale == 0) { + throw new Exception("division by zero", __FILE__, __LINE__, __FUNCTION__ ); + } + + if (oldTimeScale == newTimeScale) return t; + + // check if we can safely use integer operations + if (ilog2(t) + ilog2(newTimeScale) <= 64) { + return (t * newTimeScale) / oldTimeScale; + } + + // final resort is to use floating point + double d = (double)newTimeScale; + d *= double(t); + d /= (double)oldTimeScale; + d += 0.5; // round up. + + return (uint64_t)d; +} + +const char* MP4NormalizeTrackType (const char* type) +{ + if (!strcasecmp(type, "vide") + || !strcasecmp(type, "video") + || !strcasecmp(type, "mp4v") + || !strcasecmp(type, "avc1") + || !strcasecmp(type, "s263") // 3GPP H.263 + || !strcasecmp(type, "encv")) { + return MP4_VIDEO_TRACK_TYPE; + } + + if (!strcasecmp(type, "soun") + || !strcasecmp(type, "sound") + || !strcasecmp(type, "audio") + || !strcasecmp(type, "enca") + || !strcasecmp(type, "samr") // 3GPP AMR + || !strcasecmp(type, "sawb") // 3GPP AMR/WB + || !strcasecmp(type, "mp4a")) { + return MP4_AUDIO_TRACK_TYPE; + } + + if (!strcasecmp(type, "sdsm") + || !strcasecmp(type, "scene") + || !strcasecmp(type, "bifs")) { + return MP4_SCENE_TRACK_TYPE; + } + + if (!strcasecmp(type, "odsm") + || !strcasecmp(type, "od")) { + return MP4_OD_TRACK_TYPE; + } + if (strcasecmp(type, "cntl") == 0) { + return MP4_CNTL_TRACK_TYPE; + } + + log.verbose1f("Attempt to normalize %s did not match",type); + + return type; +} + +MP4Timestamp MP4GetAbsTimestamp() { + /* MP4 epoch is midnight, January 1, 1904 + * offset from midnight, January 1, 1970 is 2082844800 seconds + * 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60 + */ + return time::getLocalTimeSeconds() + 2082844800; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint32_t STRTOINT32( const char* s ) +{ +#if defined( MP4V2_INTSTRING_ALIGNMENT ) + // it seems ARM integer instructions require 4-byte alignment so we + // manually copy string-data into the integer before performing ops + uint32_t tmp; + memcpy( &tmp, s, sizeof(tmp) ); + return MP4V2_NTOHL( tmp ); +#else + return MP4V2_NTOHL(*(uint32_t *)s); +#endif +} + +void INT32TOSTR( uint32_t i, char* s ) +{ +#if defined( MP4V2_INTSTRING_ALIGNMENT ) + // it seems ARM integer instructions require 4-byte alignment so we + // manually copy string-data into the integer before performing ops + uint32_t tmp = MP4V2_HTONL( i ); + memcpy( s, &tmp, sizeof(tmp) ); +#else + *(uint32_t *)s = MP4V2_HTONL(i); +#endif + s[4] = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4util.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4util.h new file mode 100644 index 00000000..1fbbd81e --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/mp4util.h @@ -0,0 +1,113 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_MP4UTIL_H +#define MP4V2_IMPL_MP4UTIL_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +#include <assert.h> + +#define LIBMPV42_STRINGIFY(x) #x + +#ifndef ASSERT +# define ASSERT(expr) \ + if (!(expr)) { \ + throw new Exception("assert failure: "LIBMPV42_STRINGIFY((expr)), __FILE__, __LINE__, __FUNCTION__ ); \ + } +#endif + +#define WARNING(expr) \ + if (expr) { \ + log.errorf("Warning (%s) in %s at line %u", \ + LIBMPV42_STRINGIFY(expr), __FILE__, __LINE__); \ + } + +/////////////////////////////////////////////////////////////////////////////// + +#define CHECK_AND_FREE(a) if ((a) != NULL) { free((void *)(a)); (a) = NULL;} + +#define NUM_ELEMENTS_IN_ARRAY(name) ((sizeof((name))) / (sizeof(*(name)))) + +/////////////////////////////////////////////////////////////////////////////// + +inline void* MP4Malloc(size_t size) { + if (size == 0) return NULL; + void* p = malloc(size); + if (p == NULL && size > 0) { + throw new PlatformException("malloc failed",errno,__FILE__,__LINE__,__FUNCTION__); + } + return p; +} + +inline void* MP4Calloc(size_t size) { + if (size == 0) return NULL; + return memset(MP4Malloc(size), 0, size); +} + +inline char* MP4Stralloc(const char* s1) { + char* s2 = (char*)MP4Malloc(strlen(s1) + 1); + strcpy(s2, s1); + return s2; +} + +inline void* MP4Realloc(void* p, uint32_t newSize) { + // workaround library bug + if (p == NULL && newSize == 0) { + return NULL; + } + + void* temp = realloc(p, newSize); + if (temp == NULL && newSize > 0) { + throw new PlatformException("malloc failed",errno,__FILE__,__LINE__,__FUNCTION__); + } + return temp; +} + +uint32_t STRTOINT32( const char* ); +void INT32TOSTR( uint32_t, char* ); + +MP4Timestamp MP4GetAbsTimestamp(); + +uint64_t MP4ConvertTime(uint64_t t, + uint32_t oldTimeScale, uint32_t newTimeScale); + +bool MP4NameFirstMatches(const char* s1, const char* s2); + +bool MP4NameFirstIndex(const char* s, uint32_t* pIndex); + +char* MP4NameFirst(const char *s); + +const char* MP4NameAfterFirst(const char *s); + +char* MP4ToBase16(const uint8_t* pData, uint32_t dataSize); + +char* MP4ToBase64(const uint8_t* pData, uint32_t dataSize); + +const char* MP4NormalizeTrackType(const char* type); + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_MP4UTIL_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/ocidescriptors.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/ocidescriptors.cpp new file mode 100644 index 00000000..0f78850d --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/ocidescriptors.cpp @@ -0,0 +1,320 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4ContentClassDescriptor::MP4ContentClassDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "classificationEntity")); + AddProperty( /* 1 */ + new MP4Integer16Property(parentAtom, "classificationTable")); + AddProperty( /* 2 */ + new MP4BytesProperty(parentAtom, "contentClassificationData")); +} + +void MP4ContentClassDescriptor::Read(MP4File& file) +{ + ReadHeader(file); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 6); + + ReadProperties(file); +} + +MP4KeywordDescriptor::MP4KeywordDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "languageCode", 3)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "isUTF8String", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "reserved", 7)); + MP4Integer8Property* pCount = + new MP4Integer8Property(parentAtom, "keywordCount"); + AddProperty(pCount); /* 3 */ + + MP4TableProperty* pTable = new MP4TableProperty(parentAtom, "keywords", pCount); + AddProperty(pTable); /* 4 */ + + pTable->AddProperty( /* 4, 0 */ + new MP4StringProperty(pTable->GetParentAtom(), "string", Counted)); + + SetReadMutate(2); +} + +void MP4KeywordDescriptor::Mutate() +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + MP4Property* pProperty = + ((MP4TableProperty*)m_pProperties[4])->GetProperty(0); + ASSERT(pProperty); + ((MP4StringProperty*)pProperty)->SetUnicode(!utf8Flag); +} + +MP4RatingDescriptor::MP4RatingDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "ratingEntity")); + AddProperty( /* 1 */ + new MP4Integer16Property(parentAtom, "ratingCriteria")); + AddProperty( /* 2 */ + new MP4BytesProperty(parentAtom, "ratingInfo")); +} + +void MP4RatingDescriptor::Read(MP4File& file) +{ + ReadHeader(file); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 6); + + ReadProperties(file); +} + +MP4LanguageDescriptor::MP4LanguageDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "languageCode", 3)); +} + +MP4ShortTextDescriptor::MP4ShortTextDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "languageCode", 3)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "isUTF8String", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "reserved", 7)); + AddProperty( /* 3 */ + new MP4StringProperty(parentAtom, "eventName", Counted)); + AddProperty( /* 4 */ + new MP4StringProperty(parentAtom, "eventText", Counted)); + + SetReadMutate(2); +} + +void MP4ShortTextDescriptor::Mutate() +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + ((MP4StringProperty*)m_pProperties[3])->SetUnicode(!utf8Flag); + ((MP4StringProperty*)m_pProperties[4])->SetUnicode(!utf8Flag); +} + +MP4ExpandedTextDescriptor::MP4ExpandedTextDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "languageCode", 3)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "isUTF8String", 1)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(parentAtom, "reserved", 7)); + MP4Integer8Property* pCount = + new MP4Integer8Property(parentAtom, "itemCount"); + AddProperty(pCount); /* 3 */ + + MP4TableProperty* pTable = new MP4TableProperty(parentAtom, "items", pCount); + AddProperty(pTable); /* 4 */ + + pTable->AddProperty( /* Table 0 */ + new MP4StringProperty(pTable->GetParentAtom(), "itemDescription", Counted)); + pTable->AddProperty( /* Table 1 */ + new MP4StringProperty(pTable->GetParentAtom(), "itemText", Counted)); + + AddProperty( /* 5 */ + new MP4StringProperty(parentAtom, "nonItemText")); + ((MP4StringProperty*)m_pProperties[5])->SetExpandedCountedFormat(true); + + SetReadMutate(2); +} + +void MP4ExpandedTextDescriptor::Mutate() +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(); + + MP4Property* pProperty = + ((MP4TableProperty*)m_pProperties[4])->GetProperty(0); + ASSERT(pProperty); + ((MP4StringProperty*)pProperty)->SetUnicode(!utf8Flag); + + pProperty = ((MP4TableProperty*)m_pProperties[4])->GetProperty(1); + ASSERT(pProperty); + ((MP4StringProperty*)pProperty)->SetUnicode(!utf8Flag); + + ((MP4StringProperty*)m_pProperties[5])->SetUnicode(!utf8Flag); +} + +class MP4CreatorTableProperty : public MP4TableProperty { +public: + MP4CreatorTableProperty(MP4Atom& parentAtom, const char* name, MP4Integer8Property* pCountProperty) : + MP4TableProperty(parentAtom, name, pCountProperty) { + }; +protected: + void ReadEntry(MP4File& file, uint32_t index); + void WriteEntry(MP4File& file, uint32_t index); +private: + MP4CreatorTableProperty(); + MP4CreatorTableProperty ( const MP4CreatorTableProperty &src ); + MP4CreatorTableProperty &operator= ( const MP4CreatorTableProperty &src ); +}; + +MP4CreatorDescriptor::MP4CreatorDescriptor(MP4Atom& parentAtom, uint8_t tag) + : MP4Descriptor(parentAtom, tag) +{ + MP4Integer8Property* pCount = + new MP4Integer8Property(parentAtom, "creatorCount"); + AddProperty(pCount); /* 0 */ + + MP4TableProperty* pTable = new MP4CreatorTableProperty(parentAtom, "creators", pCount); + AddProperty(pTable); /* 1 */ + + pTable->AddProperty( /* Table 0 */ + new MP4BytesProperty(pTable->GetParentAtom(), "languageCode", 3, 3)); + pTable->AddProperty( /* Table 1 */ + new MP4BitfieldProperty(pTable->GetParentAtom(), "isUTF8String", 1)); + pTable->AddProperty( /* Table 2 */ + new MP4BitfieldProperty(pTable->GetParentAtom(), "reserved", 7)); + pTable->AddProperty( /* Table 3 */ + new MP4StringProperty(pTable->GetParentAtom(), "name", Counted)); +} + +void MP4CreatorTableProperty::ReadEntry(MP4File& file, uint32_t index) +{ + m_pProperties[0]->Read(file, index); + m_pProperties[1]->Read(file, index); + + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(index); + ((MP4StringProperty*)m_pProperties[3])->SetUnicode(!utf8Flag); + + m_pProperties[2]->Read(file, index); + m_pProperties[3]->Read(file, index); +} + +void MP4CreatorTableProperty::WriteEntry(MP4File& file, uint32_t index) +{ + bool utf8Flag = ((MP4BitfieldProperty*)m_pProperties[1])->GetValue(index); + ((MP4StringProperty*)m_pProperties[3])->SetUnicode(!utf8Flag); + + MP4TableProperty::WriteEntry(file, index); +} + +MP4CreationDescriptor::MP4CreationDescriptor(MP4Atom& parentAtom, uint8_t tag) + : MP4Descriptor(parentAtom, tag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty(parentAtom, "contentCreationDate", 40)); +} + +MP4SmpteCameraDescriptor::MP4SmpteCameraDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + MP4Integer8Property* pCount = + new MP4Integer8Property(parentAtom, "parameterCount"); + AddProperty(pCount); + + MP4TableProperty* pTable = new MP4TableProperty(parentAtom, "parameters", pCount); + AddProperty(pTable); + + pTable->AddProperty( + new MP4Integer8Property(parentAtom, "id")); + pTable->AddProperty( + new MP4Integer32Property(parentAtom, "value")); +} + +MP4UnknownOCIDescriptor::MP4UnknownOCIDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "data")); +} + +void MP4UnknownOCIDescriptor::Read(MP4File& file) +{ + ReadHeader(file); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[0])->SetValueSize(m_size); + + ReadProperties(file); +} + +MP4Descriptor* CreateOCIDescriptor(MP4Atom& parentAtom, uint8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + + switch (tag) { + case MP4ContentClassDescrTag: + pDescriptor = new MP4ContentClassDescriptor(parentAtom); + break; + case MP4KeywordDescrTag: + pDescriptor = new MP4KeywordDescriptor(parentAtom); + break; + case MP4RatingDescrTag: + pDescriptor = new MP4RatingDescriptor(parentAtom); + break; + case MP4LanguageDescrTag: + pDescriptor = new MP4LanguageDescriptor(parentAtom); + break; + case MP4ShortTextDescrTag: + pDescriptor = new MP4ShortTextDescriptor(parentAtom); + break; + case MP4ExpandedTextDescrTag: + pDescriptor = new MP4ExpandedTextDescriptor(parentAtom); + break; + case MP4ContentCreatorDescrTag: + case MP4OCICreatorDescrTag: + pDescriptor = new MP4CreatorDescriptor(parentAtom, tag); + break; + case MP4ContentCreationDescrTag: + case MP4OCICreationDescrTag: + pDescriptor = new MP4CreationDescriptor(parentAtom, tag); + break; + case MP4SmpteCameraDescrTag: + pDescriptor = new MP4SmpteCameraDescriptor(parentAtom); + break; + } + + if (pDescriptor == NULL) { + if (tag >= MP4OCIDescrTagsStart && tag <= MP4OCIDescrTagsEnd) { + pDescriptor = new MP4UnknownOCIDescriptor(parentAtom); + pDescriptor->SetTag(tag); + } + } + + return pDescriptor; +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/ocidescriptors.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/ocidescriptors.h new file mode 100644 index 00000000..c3018501 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/ocidescriptors.h @@ -0,0 +1,151 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_OCIDESCRIPTORS_H +#define MP4V2_IMPL_OCIDESCRIPTORS_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +const uint8_t MP4OCIDescrTagsStart = 0x40; +const uint8_t MP4ContentClassDescrTag = 0x40; +const uint8_t MP4KeywordDescrTag = 0x41; +const uint8_t MP4RatingDescrTag = 0x42; +const uint8_t MP4LanguageDescrTag = 0x43; +const uint8_t MP4ShortTextDescrTag = 0x44; +const uint8_t MP4ExpandedTextDescrTag = 0x45; +const uint8_t MP4ContentCreatorDescrTag = 0x46; +const uint8_t MP4ContentCreationDescrTag = 0x47; +const uint8_t MP4OCICreatorDescrTag = 0x48; +const uint8_t MP4OCICreationDescrTag = 0x49; +const uint8_t MP4SmpteCameraDescrTag = 0x4A; +const uint8_t MP4OCIDescrTagsEnd = 0x5F; + +class MP4ContentClassDescriptor : public MP4Descriptor { +public: + MP4ContentClassDescriptor(MP4Atom& parentAtom); + void Read(MP4File& file); +private: + MP4ContentClassDescriptor(); + MP4ContentClassDescriptor ( const MP4ContentClassDescriptor &src ); + MP4ContentClassDescriptor &operator= ( const MP4ContentClassDescriptor &src ); +}; + +class MP4KeywordDescriptor : public MP4Descriptor { +public: + MP4KeywordDescriptor(MP4Atom& parentAtom); +protected: + void Mutate(); +private: + MP4KeywordDescriptor(); + MP4KeywordDescriptor ( const MP4KeywordDescriptor &src ); + MP4KeywordDescriptor &operator= ( const MP4KeywordDescriptor &src ); +}; + +class MP4RatingDescriptor : public MP4Descriptor { +public: + MP4RatingDescriptor(MP4Atom& parentAtom); + void Read(MP4File& file); +private: + MP4RatingDescriptor(); + MP4RatingDescriptor ( const MP4RatingDescriptor &src ); + MP4RatingDescriptor &operator= ( const MP4RatingDescriptor &src ); +}; + +class MP4LanguageDescriptor : public MP4Descriptor { +public: + MP4LanguageDescriptor(MP4Atom& parentAtom); +private: + MP4LanguageDescriptor(); + MP4LanguageDescriptor ( const MP4LanguageDescriptor &src ); + MP4LanguageDescriptor &operator= ( const MP4LanguageDescriptor &src ); +}; + +class MP4ShortTextDescriptor : public MP4Descriptor { +public: + MP4ShortTextDescriptor(MP4Atom& parentAtom); +protected: + void Mutate(); +private: + MP4ShortTextDescriptor(); + MP4ShortTextDescriptor ( const MP4ShortTextDescriptor &src ); + MP4ShortTextDescriptor &operator= ( const MP4ShortTextDescriptor &src ); +}; + +class MP4ExpandedTextDescriptor : public MP4Descriptor { +public: + MP4ExpandedTextDescriptor(MP4Atom& parentAtom); +protected: + void Mutate(); +private: + MP4ExpandedTextDescriptor(); + MP4ExpandedTextDescriptor ( const MP4ExpandedTextDescriptor &src ); + MP4ExpandedTextDescriptor &operator= ( const MP4ExpandedTextDescriptor &src ); +}; + +class MP4CreatorDescriptor : public MP4Descriptor { +public: + MP4CreatorDescriptor(MP4Atom& parentAtom, uint8_t tag); +private: + MP4CreatorDescriptor(); + MP4CreatorDescriptor ( const MP4CreatorDescriptor &src ); + MP4CreatorDescriptor &operator= ( const MP4CreatorDescriptor &src ); +}; + +class MP4CreationDescriptor : public MP4Descriptor { +public: + MP4CreationDescriptor(MP4Atom& parentAtom, uint8_t tag); +private: + MP4CreationDescriptor(); + MP4CreationDescriptor ( const MP4CreationDescriptor &src ); + MP4CreationDescriptor &operator= ( const MP4CreationDescriptor &src ); +}; + +class MP4SmpteCameraDescriptor : public MP4Descriptor { +public: + MP4SmpteCameraDescriptor(MP4Atom& parentAtom); +private: + MP4SmpteCameraDescriptor(); + MP4SmpteCameraDescriptor ( const MP4SmpteCameraDescriptor &src ); + MP4SmpteCameraDescriptor &operator= ( const MP4SmpteCameraDescriptor &src ); +}; + +class MP4UnknownOCIDescriptor : public MP4Descriptor { +public: + MP4UnknownOCIDescriptor(MP4Atom& parentAtom); + void Read(MP4File& file); +private: + MP4UnknownOCIDescriptor(); + MP4UnknownOCIDescriptor ( const MP4UnknownOCIDescriptor &src ); + MP4UnknownOCIDescriptor &operator= ( const MP4UnknownOCIDescriptor &src ); +}; + + +extern MP4Descriptor *CreateOCIDescriptor(MP4Atom& parentAtom, uint8_t tag); + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_OCIDESCRIPTORS_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/odcommands.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/odcommands.cpp new file mode 100644 index 00000000..7cf4f748 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/odcommands.cpp @@ -0,0 +1,113 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4ODUpdateDescriptor::MP4ODUpdateDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4ODUpdateODCommandTag) +{ + // just a container for ObjectDescriptors + AddProperty( /* 0 */ + new MP4DescriptorProperty(parentAtom, NULL, + MP4FileODescrTag, 0, Required, Many)); +} + +MP4ODRemoveDescriptor::MP4ODRemoveDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4ODRemoveODCommandTag) +{ + MP4Integer32Property* pCount = + new MP4Integer32Property(parentAtom, "entryCount"); + pCount->SetImplicit(); + AddProperty(pCount); /* 0 */ + + MP4TableProperty* pTable = + new MP4TableProperty(parentAtom, "entries", pCount); + AddProperty(pTable); /* 1 */ + + pTable->AddProperty( /* 1, 0 */ + new MP4BitfieldProperty(pTable->GetParentAtom(), "objectDescriptorId", 10)); +} + +void MP4ODRemoveDescriptor::Read(MP4File& file) +{ + // table entry count computed from descriptor size + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(false); + ((MP4Integer32Property*)m_pProperties[0])->SetValue((m_size * 8) / 10); + ((MP4Integer32Property*)m_pProperties[0])->SetReadOnly(true); + + MP4Descriptor::Read(file); +} + +MP4ESUpdateDescriptor::MP4ESUpdateDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4ESUpdateODCommandTag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty(parentAtom, "objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "pad", 6)); + AddProperty( /* 2 */ + new MP4DescriptorProperty(parentAtom, "esIdRefs", + MP4ESIDRefDescrTag, 0, Required, Many)); +} + +// LATER might be able to combine with ESUpdateDescriptor +MP4ESRemoveDescriptor::MP4ESRemoveDescriptor(MP4Atom& parentAtom) + : MP4Descriptor(parentAtom, MP4ESRemoveODCommandTag) +{ + AddProperty( /* 0 */ + new MP4BitfieldProperty(parentAtom, "objectDescriptorId", 10)); + AddProperty( /* 1 */ + new MP4BitfieldProperty(parentAtom, "pad", 6)); + AddProperty( /* 2 */ + new MP4DescriptorProperty(parentAtom, "esIdRefs", + MP4ESIDRefDescrTag, 0, Required, Many)); +} + +MP4Descriptor* CreateODCommand(MP4Atom& parentAtom, uint8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + + switch (tag) { + case MP4ODUpdateODCommandTag: + pDescriptor = new MP4ODUpdateDescriptor(parentAtom); + break; + case MP4ODRemoveODCommandTag: + pDescriptor = new MP4ODRemoveDescriptor(parentAtom); + break; + case MP4ESUpdateODCommandTag: + pDescriptor = new MP4ESUpdateDescriptor(parentAtom); + break; + case MP4ESRemoveODCommandTag: + pDescriptor = new MP4ESRemoveDescriptor(parentAtom); + break; + } + return pDescriptor; +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/odcommands.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/odcommands.h new file mode 100644 index 00000000..08f11974 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/odcommands.h @@ -0,0 +1,83 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_ODCOMMANDS_H +#define MP4V2_IMPL_ODCOMMANDS_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +// OD stream command descriptors +const uint8_t MP4ODUpdateODCommandTag = 0x01; +const uint8_t MP4ODRemoveODCommandTag = 0x02; +const uint8_t MP4ESUpdateODCommandTag = 0x03; +const uint8_t MP4ESRemoveODCommandTag = 0x04; +const uint8_t MP4IPMPUpdateODCommandTag = 0x05; +const uint8_t MP4IPMPRemoveODCommandTag = 0x06; +const uint8_t MP4ESRemoveRefODCommandTag = 0x07; + +class MP4ODUpdateDescriptor : public MP4Descriptor { +public: + MP4ODUpdateDescriptor(MP4Atom& parentAtom); +private: + MP4ODUpdateDescriptor(); + MP4ODUpdateDescriptor ( const MP4ODUpdateDescriptor &src ); + MP4ODUpdateDescriptor &operator= ( const MP4ODUpdateDescriptor &src ); +}; + +class MP4ODRemoveDescriptor : public MP4Descriptor { +public: + MP4ODRemoveDescriptor(MP4Atom& parentAtom); + void Read(MP4File& file); +private: + MP4ODRemoveDescriptor(); + MP4ODRemoveDescriptor ( const MP4ODRemoveDescriptor &src ); + MP4ODRemoveDescriptor &operator= ( const MP4ODRemoveDescriptor &src ); +}; + +class MP4ESUpdateDescriptor : public MP4Descriptor { +public: + MP4ESUpdateDescriptor(MP4Atom& parentAtom); +private: + MP4ESUpdateDescriptor(); + MP4ESUpdateDescriptor ( const MP4ESUpdateDescriptor &src ); + MP4ESUpdateDescriptor &operator= ( const MP4ESUpdateDescriptor &src ); +}; + +class MP4ESRemoveDescriptor : public MP4Descriptor { +public: + MP4ESRemoveDescriptor(MP4Atom& parentAtom); +private: + MP4ESRemoveDescriptor(); + MP4ESRemoveDescriptor ( const MP4ESRemoveDescriptor &src ); + MP4ESRemoveDescriptor &operator= ( const MP4ESRemoveDescriptor &src ); +}; + +MP4Descriptor* CreateODCommand(MP4Atom& parentAtom, uint8_t tag); + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_ODCOMMANDS_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qosqualifiers.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qosqualifiers.cpp new file mode 100644 index 00000000..02d54c1e --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qosqualifiers.cpp @@ -0,0 +1,174 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +#if 1 +MP4QosDescriptorBase::MP4QosDescriptorBase (MP4Atom& parentAtom, uint8_t tag) + : MP4Descriptor(parentAtom, tag) +{ + switch (tag) { + case MP4QosDescrTag: + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "predefined")); + AddProperty( /* 1 */ + new MP4QosQualifierProperty(parentAtom, "qualifiers", + MP4QosTagsStart, + MP4QosTagsEnd, Optional, Many)); + break; + case MP4MaxDelayQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxDelay")); + break; + case MP4PrefMaxDelayQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "prefMaxDelay")); + break; + case MP4LossProbQosTag: + AddProperty( /* 0 */ + new MP4Float32Property(parentAtom, "lossProb")); + break; + case MP4MaxGapLossQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxGapLoss")); + break; + case MP4MaxAUSizeQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxAUSize")); + break; + case MP4AvgAUSizeQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "avgAUSize")); + break; + case MP4MaxAURateQosTag: + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxAURate")); + break; + } +} + +#else +MP4QosDescriptor::MP4QosDescriptor(MP4Atom &parentAtom) + : MP4Descriptor(parentAtom, MP4QosDescrTag) +{ + AddProperty( /* 0 */ + new MP4Integer8Property(parentAtom, "predefined")); + AddProperty( /* 1 */ + new MP4QosQualifierProperty(parentAtom, "qualifiers", + MP4QosTagsStart, MP4QosTagsEnd, Optional, Many)); +} + +MP4MaxDelayQosQualifier::MP4MaxDelayQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4MaxDelayQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxDelay")); +} + +MP4PrefMaxDelayQosQualifier::MP4PrefMaxDelayQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4PrefMaxDelayQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "prefMaxDelay")); +} + +MP4LossProbQosQualifier::MP4LossProbQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4LossProbQosTag) +{ + AddProperty( /* 0 */ + new MP4Float32Property(parentAtom, "lossProb")); +} + +MP4MaxGapLossQosQualifier::MP4MaxGapLossQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4MaxGapLossQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxGapLoss")); +} + +MP4MaxAUSizeQosQualifier::MP4MaxAUSizeQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4MaxAUSizeQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxAUSize")); +} + +MP4AvgAUSizeQosQualifier::MP4AvgAUSizeQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4AvgAUSizeQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "avgAUSize")); +} + +MP4MaxAURateQosQualifier::MP4MaxAURateQosQualifier(MP4Atom &parentAtom) + : MP4QosQualifier(parentAtom, MP4MaxAURateQosTag) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(parentAtom, "maxAURate")); +} +#endif +MP4UnknownQosQualifier::MP4UnknownQosQualifier(MP4Atom &parentAtom) + : MP4Descriptor(parentAtom) +{ + AddProperty( /* 0 */ + new MP4BytesProperty(parentAtom, "data")); +} + +void MP4UnknownQosQualifier::Read(MP4File& file) +{ + ReadHeader(file); + + /* byte properties need to know how long they are before reading */ + ((MP4BytesProperty*)m_pProperties[0])->SetValueSize(m_size); + + ReadProperties(file); +} + +MP4Descriptor* MP4QosQualifierProperty::CreateDescriptor(MP4Atom &parentAtom, uint8_t tag) +{ + MP4Descriptor* pDescriptor = NULL; + switch (tag) { + case MP4MaxDelayQosTag: + case MP4PrefMaxDelayQosTag: + case MP4LossProbQosTag: + case MP4MaxGapLossQosTag: + case MP4MaxAUSizeQosTag: + case MP4AvgAUSizeQosTag: + case MP4MaxAURateQosTag: + pDescriptor = new MP4QosDescriptorBase(parentAtom, tag); + break; + default: + pDescriptor = new MP4UnknownQosQualifier(parentAtom); + pDescriptor->SetTag(tag); + } + + return pDescriptor; +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qosqualifiers.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qosqualifiers.h new file mode 100644 index 00000000..5bd4bd0e --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qosqualifiers.h @@ -0,0 +1,65 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_QOSQUALIFIERS_H +#define MP4V2_IMPL_QOSQUALIFIERS_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +const uint8_t MP4QosDescrTag = 0x0C; +const uint8_t MP4QosTagsStart = 0x01; +const uint8_t MP4MaxDelayQosTag = 0x01; +const uint8_t MP4PrefMaxDelayQosTag = 0x02; +const uint8_t MP4LossProbQosTag = 0x03; +const uint8_t MP4MaxGapLossQosTag = 0x04; +const uint8_t MP4MaxAUSizeQosTag = 0x41; +const uint8_t MP4AvgAUSizeQosTag = 0x42; +const uint8_t MP4MaxAURateQosTag = 0x43; +const uint8_t MP4QosTagsEnd = 0xFF; + +class MP4QosDescriptorBase : public MP4Descriptor { +public: + MP4QosDescriptorBase(MP4Atom &parentAtom, uint8_t tag); +private: + MP4QosDescriptorBase(); + MP4QosDescriptorBase ( const MP4QosDescriptorBase &src ); + MP4QosDescriptorBase &operator= ( const MP4QosDescriptorBase &src ); +}; + +class MP4UnknownQosQualifier : public MP4Descriptor { +public: + MP4UnknownQosQualifier(MP4Atom &parentAtom); + void Read(MP4File& file); +private: + MP4UnknownQosQualifier(); + MP4UnknownQosQualifier ( const MP4UnknownQosQualifier &src ); + MP4UnknownQosQualifier &operator= ( const MP4UnknownQosQualifier &src ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_QOSQUALIFIERS_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/ColorParameterBox.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/ColorParameterBox.cpp new file mode 100644 index 00000000..7581c63b --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/ColorParameterBox.cpp @@ -0,0 +1,345 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { namespace qtff { + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + const string BOX_CODE = "colr"; + + bool findColorParameterBox( MP4FileHandle file, MP4Atom& coding, MP4Atom*& colr ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::add( MP4FileHandle file, uint16_t trackIndex, const Item& item ) +{ + MP4Atom* coding; + + if( !MP4_IS_VALID_FILE_HANDLE( file )) + throw new Exception( "invalid file handle", __FILE__, __LINE__, __FUNCTION__ ); + + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* colr; + if( !findColorParameterBox( file, *coding, colr )) + throw new Exception( "colr-box already exists", __FILE__, __LINE__, __FUNCTION__ ); + + colr = MP4Atom::CreateAtom( *((MP4File *)file), coding, BOX_CODE.c_str() ); + coding->AddChildAtom( colr ); + colr->Generate(); + + MP4StringProperty* type; + MP4Integer16Property* primariesIndex; + MP4Integer16Property* transferFunctionIndex; + MP4Integer16Property* matrixIndex; + + if( colr->FindProperty( "colr.colorParameterType", (MP4Property**)&type )) + type->SetValue( "nclc" ); + + if( colr->FindProperty( "colr.primariesIndex", (MP4Property**)&primariesIndex )) + primariesIndex->SetValue( item.primariesIndex ); + + if( colr->FindProperty( "colr.transferFunctionIndex", (MP4Property**)&transferFunctionIndex )) + transferFunctionIndex->SetValue( item.transferFunctionIndex ); + + if( colr->FindProperty( "colr.matrixIndex", (MP4Property**)&matrixIndex )) + matrixIndex->SetValue( item.matrixIndex ); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::add( MP4FileHandle file, MP4TrackId trackId, const Item& item ) +{ + MP4File& mp4 = *((MP4File*)file); + return add( file, mp4.FindTrackIndex( trackId ), item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::get( MP4FileHandle file, uint16_t trackIndex, Item& item ) +{ + item.reset(); + + MP4Atom* coding; + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* colr; + if( findColorParameterBox( file, *coding, colr )) + throw new Exception( "colr-box not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Integer16Property* primariesIndex; + MP4Integer16Property* transferFunctionIndex; + MP4Integer16Property* matrixIndex; + + if( colr->FindProperty( "colr.primariesIndex", (MP4Property**)&primariesIndex )) + item.primariesIndex = primariesIndex->GetValue(); + + if( colr->FindProperty( "colr.transferFunctionIndex", (MP4Property**)&transferFunctionIndex )) + item.transferFunctionIndex = transferFunctionIndex->GetValue(); + + if( colr->FindProperty( "colr.matrixIndex", (MP4Property**)&matrixIndex )) + item.matrixIndex = matrixIndex->GetValue(); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::get( MP4FileHandle file, MP4TrackId trackId, Item& item ) +{ + MP4File& mp4 = *((MP4File*)file); + return get( file, mp4.FindTrackIndex( trackId ), item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::list( MP4FileHandle file, ItemList& itemList ) +{ + itemList.clear(); + MP4File& mp4 = *((MP4File*)file); + + const uint16_t trackc = mp4.GetNumberOfTracks(); + for( uint16_t i = 0; i < trackc; i++) { + MP4TrackId id = mp4.FindTrackId( i ); + if( id == MP4_INVALID_TRACK_ID ) + continue; + + const char* type = mp4.GetTrackType( id ); + if( !type ) + continue; + + itemList.resize( itemList.size() + 1 ); + IndexedItem& xitem = itemList[itemList.size()-1]; + + xitem.trackIndex = i; + xitem.trackId = id; + + bool success = false; + try { + success = !get( file, i, xitem.item ); + } + catch( Exception* x ) { + delete x; + } + + if( !success ) { + itemList.resize( itemList.size() - 1 ); + continue; + } + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::remove( MP4FileHandle file, uint16_t trackIndex ) +{ + MP4Atom* coding; + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* colr; + if( findColorParameterBox( file, *coding, colr )) + throw new Exception( "colr-box not found", __FILE__, __LINE__, __FUNCTION__ ); + + coding->DeleteChildAtom( colr ); + delete colr; + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::remove( MP4FileHandle file, MP4TrackId trackId ) +{ + MP4File& mp4 = *((MP4File*)file); + return remove( file, mp4.FindTrackIndex( trackId )); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::set( MP4FileHandle file, uint16_t trackIndex, const Item& item ) +{ + MP4Atom* coding; + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* colr; + if( findColorParameterBox( file, *coding, colr )) + throw new Exception( "colr-box not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Integer16Property* primariesIndex; + MP4Integer16Property* transferFunctionIndex; + MP4Integer16Property* matrixIndex; + + if( colr->FindProperty( "colr.primariesIndex", (MP4Property**)&primariesIndex )) + primariesIndex->SetValue( item.primariesIndex ); + + if( colr->FindProperty( "colr.transferFunctionIndex", (MP4Property**)&transferFunctionIndex )) + transferFunctionIndex->SetValue( item.transferFunctionIndex ); + + if( colr->FindProperty( "colr.matrixIndex", (MP4Property**)&matrixIndex )) + matrixIndex->SetValue( item.matrixIndex ); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +ColorParameterBox::set( MP4FileHandle file, MP4TrackId trackId, const Item& item ) +{ + MP4File& mp4 = *((MP4File*)file); + return set( file, mp4.FindTrackIndex( trackId ), item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +ColorParameterBox::IndexedItem::IndexedItem() + : trackIndex ( numeric_limits<uint16_t>::max() ) + , trackId ( MP4_INVALID_TRACK_ID ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +ColorParameterBox::Item::Item() + : primariesIndex ( 6 ) + , transferFunctionIndex ( 1 ) + , matrixIndex ( 6 ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +void +ColorParameterBox::Item::convertFromCSV( const string& text ) +{ + istringstream iss( text ); + char delim; + + iss >> primariesIndex; + iss >> delim; + iss >> transferFunctionIndex; + iss >> delim; + iss >> matrixIndex; + + // input was good if we end up with only eofbit set + if( iss.rdstate() != ios::eofbit ) { + reset(); + ostringstream xss; + xss << "invalid ColorParameterBox format" + << " (expecting: INDEX1,INDEX2,INDEX3)" + << " got: " << text; + throw new Exception( xss.str(), __FILE__, __LINE__, __FUNCTION__ ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +string +ColorParameterBox::Item::convertToCSV() const +{ + string buffer; + return convertToCSV( buffer ); +} + +/////////////////////////////////////////////////////////////////////////////// + +string& +ColorParameterBox::Item::convertToCSV( string& buffer ) const +{ + ostringstream oss; + oss << primariesIndex << ',' << transferFunctionIndex << ',' << matrixIndex; + buffer = oss.str(); + return buffer; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +ColorParameterBox::Item::reset() +{ + primariesIndex = 6; + transferFunctionIndex = 1; + matrixIndex = 6; +} + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + +/////////////////////////////////////////////////////////////////////////////// + +bool +findColorParameterBox( MP4FileHandle file, MP4Atom& coding, MP4Atom*& colr ) +{ + colr = NULL; + + MP4Atom* found = NULL; + const uint32_t atomc = coding.GetNumberOfChildAtoms(); + for( uint32_t i = 0; i < atomc; i++ ) { + MP4Atom* atom = coding.GetChildAtom( i ); + if( BOX_CODE != atom->GetType() ) + continue; + found = atom; + } + if( !found ) + return true; + + MP4StringProperty* type; + if( !found->FindProperty( "colr.colorParameterType", (MP4Property**)&type )) + return true; + + const string type_nclc = "nclc"; + if( type_nclc != type->GetValue() ) + return true; + + colr = found; + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +} // anonymous + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::qtff diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/ColorParameterBox.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/ColorParameterBox.h new file mode 100644 index 00000000..9a27fcd4 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/ColorParameterBox.h @@ -0,0 +1,207 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_QTFF_COLORPARAMETERBOX_H +#define MP4V2_IMPL_QTFF_COLORPARAMETERBOX_H + +namespace mp4v2 { namespace impl { namespace qtff { + +/////////////////////////////////////////////////////////////////////////////// + +/// Functional class for colr-box (Color Parameter Box) support. +/// +/// A colr-box is expected to be contained in a video track which is one of +/// the following coding types: +/// @li avc1 +/// @li mp4v +/// +/// This implementation assumes a maximum count of <b>1</b> for +/// VideoSampleEntry of the supported codings. +/// +/// This implementation supports parameter-type 'nclc' only. +/// +class MP4V2_EXPORT ColorParameterBox +{ +public: + /// Data object for colr-box item. + /// This object correlates to one colr-box (Color Parameter Box). + /// + class MP4V2_EXPORT Item + { + public: + Item(); + + /// reset to state of newly constructed object. + void reset(); + + // convert from string CSV format. + void convertFromCSV( const string& csv ); + + // convert to string CSV format. + string convertToCSV() const; + + // convert to string CSV format with buffer. + string& convertToCSV( string& buffer ) const; + + public: + /// a 16-bit unsigned integer index. + /// Specifies an index into a table specifying the CIE 1931 xy + /// chromaticity coordinates of the white point and the red, green, and + /// blue primaries. The table of primaries specifies the white point and + /// the red, green, and blue primary color points for a video system. + uint16_t primariesIndex; + + /// a 16-bit unsigned integer index. + /// Specifies an an index into a table specifying the nonlinear transfer + /// function coefficients used to translate between RGB color space values + /// and Y′CbCr values. The table of transfer function coefficients + /// specifies the nonlinear function coefficients used to translate + /// between the stored Y′CbCr values and a video capture or display + /// system. + uint16_t transferFunctionIndex; + + /// a 16-bit unsigned integer index. + /// Specifies an index into a table specifying the transformation matrix + /// coefficients used to translate between RGB color space values and + /// Y′CbCr values. The table of matrixes specifies the matrix used during + /// the translation. + uint16_t matrixIndex; + }; + + class MP4V2_EXPORT IndexedItem { + public: + IndexedItem(); + + uint16_t trackIndex; + uint16_t trackId; + Item item; + }; + + typedef vector<IndexedItem> ItemList; + + static bool list( MP4FileHandle file, ItemList& itemList ); + + /// Add colr-box by track-index. + /// + /// This function adds a colr-box to <b>trackId</b> of <b>file</b>. + /// The track must be a video-track and match one of the supporting + /// codings. + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// @param item colr-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool add( MP4FileHandle file, uint16_t trackIndex, const Item& item ); + + /// Add colr-box by track-id. + /// + /// This function adds a colr-box to <b>trackId</b> of <b>file</b>. + /// The track must be a video-track and match one of the supporting + /// codings. + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// @param item colr-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool add( MP4FileHandle file, MP4TrackId trackId, const Item& item ); + + /// Store colr-box (Color Parameter Box) properties by track-index. + /// + /// This function sets the properties of a <b>colr-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// @param item colr-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool set( MP4FileHandle file, uint16_t trackIndex, const Item& item ); + + /// Store colr-box (Color Parameter Box) properties by track-id. + /// + /// This function sets the properties of a <b>colr-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// @param item colr-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool set( MP4FileHandle file, MP4TrackId trackId, const Item& item ); + + /// Fetch colr-box (Color Parameter Box) properties by track-index. + /// + /// This function gets the properties of a <b>colr-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// @param item colr-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool get( MP4FileHandle file, uint16_t trackIndex, Item& item ); + + /// Fetch colr-box (Color Parameter Box) properties by track-id. + /// + /// This function gets the properties of a <b>colr-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// @param item colr-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool get( MP4FileHandle file, MP4TrackId trackId, Item& item ); + + /// Remove colr-box (Color Parameter Box) by track-index. + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool remove( MP4FileHandle file, uint16_t trackIndex ); + + /// Remove colr-box (Color Parameter Box) by track-id. + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool remove( MP4FileHandle file, MP4TrackId trackId ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::qtff + +#endif // MP4V2_IMPL_QTTF_COLORPARAMETERBOX_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/PictureAspectRatioBox.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/PictureAspectRatioBox.cpp new file mode 100644 index 00000000..4fe5916d --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/PictureAspectRatioBox.cpp @@ -0,0 +1,313 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { namespace qtff { + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + const string BOX_CODE = "pasp"; + + bool findPictureAspectRatioBox( MP4FileHandle file, MP4Atom& coding, MP4Atom*& pasp ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::add( MP4FileHandle file, uint16_t trackIndex, const Item& item ) +{ + MP4Atom* coding; + + if( !MP4_IS_VALID_FILE_HANDLE( file )) + throw new Exception( "invalid file handle", __FILE__, __LINE__, __FUNCTION__ ); + + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* pasp; + if( !findPictureAspectRatioBox( file, *coding, pasp )) + throw new Exception( "pasp-box already exists", __FILE__, __LINE__, __FUNCTION__ ); + + pasp = MP4Atom::CreateAtom( *((MP4File *)file), coding, BOX_CODE.c_str() ); + coding->AddChildAtom( pasp ); + pasp->Generate(); + + MP4Integer16Property* hSpacing; + MP4Integer16Property* vSpacing; + + if( pasp->FindProperty( "pasp.hSpacing", (MP4Property**)&hSpacing )) + hSpacing->SetValue( item.hSpacing ); + + if( pasp->FindProperty( "pasp.vSpacing", (MP4Property**)&vSpacing )) + vSpacing->SetValue( item.vSpacing ); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::add( MP4FileHandle file, MP4TrackId trackId, const Item& item ) +{ + MP4File& mp4 = *((MP4File*)file); + return add( file, mp4.FindTrackIndex( trackId ), item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::get( MP4FileHandle file, uint16_t trackIndex, Item& item ) +{ + item.reset(); + + MP4Atom* coding; + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* pasp; + if( findPictureAspectRatioBox( file, *coding, pasp )) + throw new Exception( "pasp-box not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Integer16Property* hSpacing; + MP4Integer16Property* vSpacing; + + if( pasp->FindProperty( "pasp.hSpacing", (MP4Property**)&hSpacing )) + item.hSpacing = hSpacing->GetValue(); + + if( pasp->FindProperty( "pasp.vSpacing", (MP4Property**)&vSpacing )) + item.vSpacing = vSpacing->GetValue(); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::get( MP4FileHandle file, MP4TrackId trackId, Item& item ) +{ + MP4File& mp4 = *((MP4File*)file); + return get( file, mp4.FindTrackIndex( trackId ), item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::list( MP4FileHandle file, ItemList& itemList ) +{ + itemList.clear(); + MP4File& mp4 = *((MP4File*)file); + + const uint16_t trackc = mp4.GetNumberOfTracks(); + for( uint16_t i = 0; i < trackc; i++) { + MP4TrackId id = mp4.FindTrackId( i ); + if( id == MP4_INVALID_TRACK_ID ) + continue; + + const char* type = mp4.GetTrackType( id ); + if( !type ) + continue; + + itemList.resize( itemList.size() + 1 ); + IndexedItem& xitem = itemList[itemList.size()-1]; + + xitem.trackIndex = i; + xitem.trackId = id; + + bool success = false; + try { + success = !get( file, i, xitem.item ); + } + catch( Exception* x ) { + delete x; + } + + if( !success ) { + itemList.resize( itemList.size() - 1 ); + continue; + } + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::remove( MP4FileHandle file, uint16_t trackIndex ) +{ + MP4Atom* coding; + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* pasp; + if( findPictureAspectRatioBox( file, *coding, pasp )) + throw new Exception( "pasp-box not found", __FILE__, __LINE__, __FUNCTION__ ); + + coding->DeleteChildAtom( pasp ); + delete pasp; + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::remove( MP4FileHandle file, MP4TrackId trackId ) +{ + MP4File& mp4 = *((MP4File*)file); + return remove( file, mp4.FindTrackIndex( trackId )); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::set( MP4FileHandle file, uint16_t trackIndex, const Item& item ) +{ + MP4Atom* coding; + if( findCoding( file, trackIndex, coding )) + throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Atom* pasp; + if( findPictureAspectRatioBox( file, *coding, pasp )) + throw new Exception( "pasp-box not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4Integer16Property* hSpacing; + MP4Integer16Property* vSpacing; + + if( pasp->FindProperty( "pasp.hSpacing", (MP4Property**)&hSpacing )) + hSpacing->SetValue( item.hSpacing ); + + if( pasp->FindProperty( "pasp.vSpacing", (MP4Property**)&vSpacing )) + vSpacing->SetValue( item.vSpacing ); + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +PictureAspectRatioBox::set( MP4FileHandle file, MP4TrackId trackId, const Item& item ) +{ + MP4File& mp4 = *((MP4File*)file); + return set( file, mp4.FindTrackIndex( trackId ), item ); +} + +/////////////////////////////////////////////////////////////////////////////// + +PictureAspectRatioBox::IndexedItem::IndexedItem() + : trackIndex ( numeric_limits<uint16_t>::max() ) + , trackId ( MP4_INVALID_TRACK_ID ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +PictureAspectRatioBox::Item::Item() + : hSpacing ( 1 ) + , vSpacing ( 1 ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +void +PictureAspectRatioBox::Item::reset() +{ + hSpacing = 1; + vSpacing = 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +void +PictureAspectRatioBox::Item::convertFromCSV( const string& text ) +{ + istringstream iss( text ); + char delim; + + iss >> hSpacing; + iss >> delim; + iss >> vSpacing; + + // input was good if we end up with only eofbit set + if( iss.rdstate() != ios::eofbit ) { + reset(); + ostringstream xss; + xss << "invalid PcitureAspectRatioBox format" + << " (expecting: hSpacing,vSpacing)" + << " got: " << text; + throw new Exception( xss.str(), __FILE__, __LINE__, __FUNCTION__ ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +string +PictureAspectRatioBox::Item::convertToCSV() const +{ + string buffer; + return convertToCSV( buffer ); +} + +/////////////////////////////////////////////////////////////////////////////// + +string& +PictureAspectRatioBox::Item::convertToCSV( string& buffer ) const +{ + ostringstream oss; + oss << hSpacing << ',' << vSpacing; + buffer = oss.str(); + return buffer; +} + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + +/////////////////////////////////////////////////////////////////////////////// + +bool +findPictureAspectRatioBox( MP4FileHandle file, MP4Atom& coding, MP4Atom*& pasp ) +{ + pasp = NULL; + + MP4Atom* found = NULL; + const uint32_t atomc = coding.GetNumberOfChildAtoms(); + for( uint32_t i = 0; i < atomc; i++ ) { + MP4Atom* atom = coding.GetChildAtom( i ); + if( BOX_CODE != atom->GetType() ) + continue; + found = atom; + } + if( !found ) + return true; + + pasp = found; + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +}}}} // namespace mp4v2::impl::qtff::anonymous diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/PictureAspectRatioBox.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/PictureAspectRatioBox.h new file mode 100644 index 00000000..75e4c8fa --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/PictureAspectRatioBox.h @@ -0,0 +1,188 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_QTFF_PICTUREAPSECTRATIOBOX_H +#define MP4V2_IMPL_QTFF_PICTUREAPSECTRATIOBOX_H + +namespace mp4v2 { namespace impl { namespace qtff { + using namespace std; + +/////////////////////////////////////////////////////////////////////////////// + +/// Functional class for pasp-box (Picture Aspect Ratio Box) support. +/// +/// A pasp-box is expected to be contained in a video track which is one of +/// the following coding types: +/// @li avc1 +/// @li mp4v +/// +/// This implementation assumes a maximum count of <b>1</b> for +/// VideoSampleEntry of the supported codings. +/// +class MP4V2_EXPORT PictureAspectRatioBox +{ +public: + /// Data object for pasp-box item. + /// This object correlates to one pasp-box (Picture Aspect Ratio Box). + class MP4V2_EXPORT Item + { + public: + Item (); + + /// reset to state of newly constructed object. + void reset(); + + // convert from string CSV format. + void convertFromCSV( const string& csv ); + + // convert to string CSV format. + string convertToCSV() const; + + // convert to string CSV format with buffer. + string& convertToCSV( string& buffer ) const; + + public: + /// an unsigned 32-bit integer specifying the vertical spacing of pixels. + uint32_t hSpacing; + + /// an unsigned 32-bit integer specifying the horizontal spacing of pixels. + uint32_t vSpacing; + }; + + class MP4V2_EXPORT IndexedItem { + public: + IndexedItem(); + + uint16_t trackIndex; + uint16_t trackId; + Item item; + }; + + typedef vector<IndexedItem> ItemList; + + static bool list( MP4FileHandle file, ItemList& itemList ); + + /// Add pasp-box by track-index. + /// + /// This function adds a pasp-box to <b>trackId</b> of <b>file</b>. + /// The track must be a video-track and match one of the supporting + /// codings. + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// @param item pasp-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool add( MP4FileHandle file, uint16_t trackIndex, const Item& item ); + + /// Add pasp-box by track-id. + /// + /// This function adds a pasp-box to <b>trackId</b> of <b>file</b>. + /// The track must be a video-track and match one of the supporting + /// codings. + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// @param item pasp-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool add( MP4FileHandle file, MP4TrackId trackId, const Item& item ); + + /// Store pasp-box (Color Parameter Box) properties by track-index. + /// + /// This function sets the properties of a <b>pasp-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// @param item pasp-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool set( MP4FileHandle file, uint16_t trackIndex, const Item& item ); + + /// Store pasp-box (Color Parameter Box) properties by track-id. + /// + /// This function sets the properties of a <b>pasp-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// @param item pasp-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool set( MP4FileHandle file, MP4TrackId trackId, const Item& item ); + + /// Fetch pasp-box (Color Parameter Box) properties by track-index. + /// + /// This function gets the properties of a <b>pasp-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// @param item pasp-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool get( MP4FileHandle file, uint16_t trackIndex, Item& item ); + + /// Fetch pasp-box (Color Parameter Box) properties by track-id. + /// + /// This function gets the properties of a <b>pasp-box</b> + /// (Color Parameter Box). + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// @param item pasp-box properties to set. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool get( MP4FileHandle file, MP4TrackId trackId, Item& item ); + + /// Remove pasp-box (Color Parameter Box) by track-index. + /// + /// @param file on which to operate. + /// @param trackIndex on which to operate. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool remove( MP4FileHandle file, uint16_t trackIndex ); + + /// Remove pasp-box (Color Parameter Box) by track-id. + /// + /// @param file on which to operate. + /// @param trackId on which to operate. + /// + /// @return <b>true</b> on failure, <b>false</b> on success. + /// + static bool remove( MP4FileHandle file, MP4TrackId trackId ); +}; + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::qtff + +#endif // MP4V2_IMPL_QTTF_PICTUREAPSECTRATIOBOX_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/coding.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/coding.cpp new file mode 100644 index 00000000..29eaf779 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/coding.cpp @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "impl.h" + +namespace mp4v2 { namespace impl { namespace qtff { + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + class StaticData + { + public: + StaticData() + { + supportedCodings.insert( "avc1" ); + supportedCodings.insert( "mp4v" ); + } + + set<string> supportedCodings; + }; + + const StaticData STATIC_DATA; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool +findCoding( MP4FileHandle file, uint16_t trackIndex, MP4Atom*& coding ) +{ + coding = NULL; + MP4File& mp4 = *((MP4File*)file); + + if( trackIndex == numeric_limits<uint16_t>::max() ) { + ostringstream xss; + xss << "invalid track-index: " << trackIndex; + throw new Exception( xss.str(), __FILE__, __LINE__, __FUNCTION__ ); + } + + ostringstream oss; + oss << "moov.trak[" << trackIndex << "].mdia.hdlr"; + MP4Atom* hdlr = mp4.FindAtom( oss.str().c_str() ); + if( !hdlr ) + throw new Exception( "media handler not found", __FILE__, __LINE__, __FUNCTION__ ); + + MP4StringProperty* handlerType; + if( !hdlr->FindProperty( "hdlr.handlerType", (MP4Property**)&handlerType )) + throw new Exception( "media handler type-property not found", __FILE__, __LINE__, __FUNCTION__ ); + + const string video = "vide"; + if( video != handlerType->GetValue() ) + throw new Exception( "video-track required", __FILE__, __LINE__, __FUNCTION__ ); + + oss.str( "" ); + oss.clear(); + oss << "moov.trak[" << trackIndex << "].mdia.minf.stbl.stsd"; + MP4Atom* stsd = mp4.FindAtom( oss.str().c_str() ); + if( !stsd ) + throw new Exception( "media handler type-property not found", __FILE__, __LINE__, __FUNCTION__ ); + + // find first atom which is a supported coding + const uint32_t atomc = stsd->GetNumberOfChildAtoms(); + for( uint32_t i = 0; i < atomc; i++ ) { + MP4Atom* atom = stsd->GetChildAtom( i ); + if( STATIC_DATA.supportedCodings.find( atom->GetType() ) == STATIC_DATA.supportedCodings.end() ) + continue; + coding = atom; + } + + return coding == NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::qtff diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/coding.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/coding.h new file mode 100644 index 00000000..819c5cc9 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/coding.h @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_QTFF_CODING_H +#define MP4V2_IMPL_QTFF_CODING_H + +namespace mp4v2 { namespace impl { namespace qtff { + +/////////////////////////////////////////////////////////////////////////////// + +bool findCoding( MP4FileHandle file, uint16_t trackIndex, MP4Atom*& coding ); + +/////////////////////////////////////////////////////////////////////////////// + +}}} // namespace mp4v2::impl::qtff + +#endif // MP4V2_IMPL_QTTF_CODING_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/impl.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/impl.h new file mode 100644 index 00000000..27c7edbd --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/impl.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_QTFF_IMPL_H +#define MP4V2_IMPL_QTFF_IMPL_H + +/////////////////////////////////////////////////////////////////////////////// + +#include "src/impl.h" +#include "qtff.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_QTFF_IMPL_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/qtff.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/qtff.h new file mode 100644 index 00000000..64038219 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/qtff/qtff.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 MP4v2. +// +// The Initial Developer of the Original Code is Kona Blend. +// Portions created by Kona Blend are Copyright (C) 2008. +// All Rights Reserved. +// +// Contributors: +// Kona Blend, kona8lend@@gmail.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MP4V2_IMPL_QTFF_QTFF_H +#define MP4V2_IMPL_QTFF_QTFF_H + +/// @namespace mp4v2::impl::qtff (private) QuickTime File Format. +/// <b>WARNING: THIS IS A PRIVATE NAMESPACE. NOT FOR PUBLIC CONSUMPTION.</b> +/// +/// This namespace implements some features that are specified by the +/// QuickTime File Format Specification, revision 2007-09-04. +/// +namespace mp4v2 { namespace impl { namespace qtff { + ; +}}} + +/////////////////////////////////////////////////////////////////////////////// + +#include "ColorParameterBox.h" +#include "PictureAspectRatioBox.h" +#include "coding.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_QTTF_QTFF_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/rtphint.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/rtphint.cpp new file mode 100644 index 00000000..e07309d6 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/rtphint.cpp @@ -0,0 +1,1358 @@ +/* + * 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 [email protected] + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +/* rtp hint track operations */ + +MP4RtpHintTrack::MP4RtpHintTrack(MP4File& file, MP4Atom& trakAtom) + : MP4Track(file, trakAtom) +{ + m_pRefTrack = NULL; + + m_pRtpMapProperty = NULL; + m_pPayloadNumberProperty = NULL; + m_pMaxPacketSizeProperty = NULL; + m_pSnroProperty = NULL; + m_pTsroProperty = NULL; + + m_pReadHint = NULL; + m_pReadHintSample = NULL; + m_readHintSampleSize = 0; + + m_pWriteHint = NULL; + m_writeHintId = MP4_INVALID_SAMPLE_ID; + m_writePacketId = 0; + + m_pTrpy = NULL; + m_pNump = NULL; + m_pTpyl = NULL; + m_pMaxr = NULL; + m_pDmed = NULL; + m_pDimm = NULL; + m_pPmax = NULL; + m_pDmax = NULL; + + m_pMaxPdu = NULL; + m_pAvgPdu = NULL; + m_pMaxBitRate = NULL; + m_pAvgBitRate = NULL; + + m_thisSec = 0; + m_bytesThisSec = 0; + m_bytesThisHint = 0; + m_bytesThisPacket = 0; +} + +MP4RtpHintTrack::~MP4RtpHintTrack() +{ + delete m_pReadHint; m_pReadHint = NULL; + MP4Free( m_pReadHintSample ); m_pReadHintSample = NULL; + delete m_pWriteHint; m_pWriteHint = NULL; +} + +void MP4RtpHintTrack::InitRefTrack() +{ + if (m_pRefTrack == NULL) { + MP4Integer32Property* pRefTrackIdProperty = NULL; + (void)m_trakAtom.FindProperty( + "trak.tref.hint.entries[0].trackId", + (MP4Property**)&pRefTrackIdProperty); + ASSERT(pRefTrackIdProperty); + + m_pRefTrack = m_File.GetTrack(pRefTrackIdProperty->GetValue()); + } +} + +void MP4RtpHintTrack::InitRtpStart() +{ + number::srandom( time::getLocalTimeMilliseconds() ); + + (void)m_trakAtom.FindProperty( + "trak.udta.hnti.rtp .snro.offset", + (MP4Property**)&m_pSnroProperty); + + if (m_pSnroProperty) { + m_rtpSequenceStart = m_pSnroProperty->GetValue(); + } else { + m_rtpSequenceStart = number::random32(); + } + + (void)m_trakAtom.FindProperty( + "trak.udta.hnti.rtp .tsro.offset", + (MP4Property**)&m_pTsroProperty); + + if (m_pTsroProperty) { + m_rtpTimestampStart = m_pTsroProperty->GetValue(); + } else { + m_rtpTimestampStart = number::random32(); + } +} + +void MP4RtpHintTrack::ReadHint( + MP4SampleId hintSampleId, + uint16_t* pNumPackets) +{ + if (m_pRefTrack == NULL) { + InitRefTrack(); + InitRtpStart(); + } + + // dispose of any old hint + delete m_pReadHint; m_pReadHint = NULL; + MP4Free( m_pReadHintSample ); m_pReadHintSample = NULL; + m_readHintSampleSize = 0; + + // read the desired hint sample into memory + ReadSample( + hintSampleId, + &m_pReadHintSample, + &m_readHintSampleSize, + &m_readHintTimestamp); + + m_File.EnableMemoryBuffer(m_pReadHintSample, m_readHintSampleSize); + + m_pReadHint = new MP4RtpHint(*this); + m_pReadHint->Read(m_File); + + m_File.DisableMemoryBuffer(); + + if (pNumPackets) { + *pNumPackets = GetHintNumberOfPackets(); + } +} + +uint16_t MP4RtpHintTrack::GetHintNumberOfPackets() +{ + if (m_pReadHint == NULL) { + throw new Exception("no hint has been read", + __FILE__, __LINE__, __FUNCTION__); + } + return m_pReadHint->GetNumberOfPackets(); +} + +bool MP4RtpHintTrack::GetPacketBFrame(uint16_t packetIndex) +{ + if (m_pReadHint == NULL) { + throw new Exception("no hint has been read", + __FILE__, __LINE__, __FUNCTION__); + } + MP4RtpPacket* pPacket = + m_pReadHint->GetPacket(packetIndex); + + return pPacket->IsBFrame(); +} + +uint16_t MP4RtpHintTrack::GetPacketTransmitOffset(uint16_t packetIndex) +{ + if (m_pReadHint == NULL) { + throw new Exception("no hint has been read", + __FILE__, __LINE__, __FUNCTION__); + } + + MP4RtpPacket* pPacket = + m_pReadHint->GetPacket(packetIndex); + + return pPacket->GetTransmitOffset(); +} + +void MP4RtpHintTrack::ReadPacket( + uint16_t packetIndex, + uint8_t** ppBytes, + uint32_t* pNumBytes, + uint32_t ssrc, + bool addHeader, + bool addPayload) +{ + if (m_pReadHint == NULL) { + throw new Exception("no hint has been read", + __FILE__, __LINE__, __FUNCTION__); + } + if (!addHeader && !addPayload) { + throw new Exception("no data requested", + __FILE__, __LINE__, __FUNCTION__); + } + + MP4RtpPacket* pPacket = + m_pReadHint->GetPacket(packetIndex); + + *pNumBytes = 0; + if (addHeader) { + *pNumBytes += 12; + } + if (addPayload) { + *pNumBytes += pPacket->GetDataSize(); + } + + // if needed, allocate the packet memory + bool buffer_malloc = false; + + if (*ppBytes == NULL) { + *ppBytes = (uint8_t*)MP4Malloc(*pNumBytes); + buffer_malloc = true; + } + + try { + uint8_t* pDest = *ppBytes; + + if (addHeader) { + *pDest++ = + 0x80 | (pPacket->GetPBit() << 5) | (pPacket->GetXBit() << 4); + + *pDest++ = + (pPacket->GetMBit() << 7) | pPacket->GetPayload(); + + *((uint16_t*)pDest) = + MP4V2_HTONS(m_rtpSequenceStart + pPacket->GetSequenceNumber()); + pDest += 2; + + *((uint32_t*)pDest) = + MP4V2_HTONL(m_rtpTimestampStart + (uint32_t)m_readHintTimestamp); + pDest += 4; + + *((uint32_t*)pDest) = + MP4V2_HTONL(ssrc); + pDest += 4; + } + + if (addPayload) { + pPacket->GetData(pDest); + } + } + catch (Exception* x) { + if (buffer_malloc) { + MP4Free(*ppBytes); + *ppBytes = NULL; + } + throw x; + } + + log.hexDump(0, MP4_LOG_VERBOSE1, *ppBytes, *pNumBytes, + "\"%s\": %u ", GetFile().GetFilename().c_str(), + packetIndex); +} + +MP4Timestamp MP4RtpHintTrack::GetRtpTimestampStart() +{ + if (m_pRefTrack == NULL) { + InitRefTrack(); + InitRtpStart(); + } + + return m_rtpTimestampStart; +} + +void MP4RtpHintTrack::SetRtpTimestampStart(MP4Timestamp start) +{ + if (!m_pTsroProperty) { + MP4Atom* pTsroAtom = + m_File.AddDescendantAtoms(&m_trakAtom, "udta.hnti.rtp .tsro"); + + ASSERT(pTsroAtom); + + (void)pTsroAtom->FindProperty("offset", + (MP4Property**)&m_pTsroProperty); + + ASSERT(m_pTsroProperty); + } + + m_pTsroProperty->SetValue(start); + m_rtpTimestampStart = start; +} + +void MP4RtpHintTrack::InitPayload() +{ + if (m_pRtpMapProperty == NULL) { + (void)m_trakAtom.FindProperty( + "trak.udta.hinf.payt.rtpMap", + (MP4Property**)&m_pRtpMapProperty); + } + + if (m_pPayloadNumberProperty == NULL) { + (void)m_trakAtom.FindProperty( + "trak.udta.hinf.payt.payloadNumber", + (MP4Property**)&m_pPayloadNumberProperty); + } + + if (m_pMaxPacketSizeProperty == NULL) { + (void)m_trakAtom.FindProperty( + "trak.mdia.minf.stbl.stsd.rtp .maxPacketSize", + (MP4Property**)&m_pMaxPacketSizeProperty); + } +} + +void MP4RtpHintTrack::GetPayload( + char** ppPayloadName, + uint8_t* pPayloadNumber, + uint16_t* pMaxPayloadSize, + char **ppEncodingParams) +{ + const char* pRtpMap; + const char* pSlash; + uint32_t length; + InitPayload(); + + if (ppPayloadName || ppEncodingParams) { + if (ppPayloadName) + *ppPayloadName = NULL; + if (ppEncodingParams) + *ppEncodingParams = NULL; + if (m_pRtpMapProperty) { + pRtpMap = m_pRtpMapProperty->GetValue(); + pSlash = strchr(pRtpMap, '/'); + + if (pSlash) { + length = pSlash - pRtpMap; + } else { + length = (uint32_t)strlen(pRtpMap); + } + + if (ppPayloadName) { + *ppPayloadName = (char*)MP4Calloc(length + 1); + strncpy(*ppPayloadName, pRtpMap, length); + } + if (pSlash && ppEncodingParams) { + pSlash++; + pSlash = strchr(pSlash, '/'); + if (pSlash != NULL) { + pSlash++; + if (pSlash != '\0') { + length = (uint32_t)strlen(pRtpMap) - (pSlash - pRtpMap); + *ppEncodingParams = (char *)MP4Calloc(length + 1); + strncpy(*ppEncodingParams, pSlash, length); + } + } + } + } + } + + if (pPayloadNumber) { + if (m_pPayloadNumberProperty) { + *pPayloadNumber = m_pPayloadNumberProperty->GetValue(); + } else { + *pPayloadNumber = 0; + } + } + + if (pMaxPayloadSize) { + if (m_pMaxPacketSizeProperty) { + *pMaxPayloadSize = m_pMaxPacketSizeProperty->GetValue(); + } else { + *pMaxPayloadSize = 0; + } + } +} + +void MP4RtpHintTrack::SetPayload( + const char* payloadName, + uint8_t payloadNumber, + uint16_t maxPayloadSize, + const char *encoding_parms, + bool include_rtp_map, + bool include_mpeg4_esid) +{ + InitRefTrack(); + InitPayload(); + + ASSERT(m_pRtpMapProperty); + ASSERT(m_pPayloadNumberProperty); + ASSERT(m_pMaxPacketSizeProperty); + + size_t len = strlen(payloadName) + 16; + if (encoding_parms != NULL) { + size_t temp = strlen(encoding_parms); + if (temp == 0) { + encoding_parms = NULL; + } else { + len += temp; + } + } + + char* rtpMapBuf = (char*)MP4Malloc(len); + snprintf(rtpMapBuf, len, "%s/%u%c%s", + payloadName, + GetTimeScale(), + encoding_parms != NULL ? '/' : '\0', + encoding_parms == NULL ? "" : encoding_parms); + m_pRtpMapProperty->SetValue(rtpMapBuf); + + m_pPayloadNumberProperty->SetValue(payloadNumber); + + if (maxPayloadSize == 0) { + maxPayloadSize = 1460; + } + m_pMaxPacketSizeProperty->SetValue(maxPayloadSize); + + // set sdp media type + const char* sdpMediaType; + if (!strcmp(m_pRefTrack->GetType(), MP4_AUDIO_TRACK_TYPE)) { + sdpMediaType = "audio"; + } else if (!strcmp(m_pRefTrack->GetType(), MP4_VIDEO_TRACK_TYPE)) { + sdpMediaType = "video"; + } else if (!strcmp(m_pRefTrack->GetType(), MP4_CNTL_TRACK_TYPE)) { + sdpMediaType = "control"; + } else { + sdpMediaType = "application"; + } + + uint32_t maxlen = + (uint32_t)strlen(sdpMediaType) + (uint32_t)strlen(rtpMapBuf) + 256; + char* sdpBuf = (char*)MP4Malloc(maxlen); + uint32_t buflen; + buflen = snprintf(sdpBuf, maxlen, + "m=%s 0 RTP/AVP %u\015\012" + "a=control:trackID=%u\015\012", + sdpMediaType, payloadNumber, + m_trackId); + if (include_rtp_map) { + buflen += snprintf(sdpBuf + buflen, maxlen - buflen, + "a=rtpmap:%u %s\015\012", + payloadNumber, rtpMapBuf); + } + if (include_mpeg4_esid) { + snprintf(sdpBuf + buflen, maxlen - buflen, + "a=mpeg4-esid:%u\015\012", + m_pRefTrack->GetId()); + } + + MP4StringProperty* pSdpProperty = NULL; + (void)m_trakAtom.FindProperty("trak.udta.hnti.sdp .sdpText", + (MP4Property**)&pSdpProperty); + ASSERT(pSdpProperty); + pSdpProperty->SetValue(sdpBuf); + + // cleanup + MP4Free(rtpMapBuf); + MP4Free(sdpBuf); +} + +void MP4RtpHintTrack::AddHint(bool isBFrame, uint32_t timestampOffset) +{ + // on first hint, need to lookup the reference track + if (m_writeHintId == MP4_INVALID_SAMPLE_ID) { + InitRefTrack(); + InitStats(); + } + + if (m_pWriteHint) { + throw new Exception("unwritten hint is still pending", __FILE__, __LINE__, __FUNCTION__); + } + + m_pWriteHint = new MP4RtpHint(*this); + m_pWriteHint->SetBFrame(isBFrame); + m_pWriteHint->SetTimestampOffset(timestampOffset); + + m_bytesThisHint = 0; + m_writeHintId++; +} + +void MP4RtpHintTrack::AddPacket(bool setMbit, int32_t transmitOffset) +{ + if (m_pWriteHint == NULL) { + throw new Exception("no hint pending", __FILE__, __LINE__, __FUNCTION__); + } + + MP4RtpPacket* pPacket = m_pWriteHint->AddPacket(); + + ASSERT(m_pPayloadNumberProperty); + + pPacket->Set( + m_pPayloadNumberProperty->GetValue(), + m_writePacketId++, + setMbit); + pPacket->SetTransmitOffset(transmitOffset); + + m_bytesThisHint += 12; + if (m_bytesThisPacket > m_pPmax->GetValue()) { + m_pPmax->SetValue(m_bytesThisPacket); + } + m_bytesThisPacket = 12; + m_pNump->IncrementValue(); + m_pTrpy->IncrementValue(12); // RTP packet header size +} + +void MP4RtpHintTrack::AddImmediateData( + const uint8_t* pBytes, + uint32_t numBytes) +{ + if (m_pWriteHint == NULL) { + throw new Exception("no hint pending", __FILE__, __LINE__, __FUNCTION__ ); + } + + MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); + if (pPacket == NULL) { + throw new Exception("no packet pending", __FILE__, __LINE__, __FUNCTION__); + } + + if (pBytes == NULL || numBytes == 0) { + throw new Exception("no data", + __FILE__, __LINE__, __FUNCTION__ ); + } + if (numBytes > 14) { + throw new Exception("data size is larger than 14 bytes", + __FILE__, __LINE__, __FUNCTION__ ); + } + + MP4RtpImmediateData* pData = new MP4RtpImmediateData(*pPacket); + pData->Set(pBytes, numBytes); + + pPacket->AddData(pData); + + m_bytesThisHint += numBytes; + m_bytesThisPacket += numBytes; + m_pDimm->IncrementValue(numBytes); + m_pTpyl->IncrementValue(numBytes); + m_pTrpy->IncrementValue(numBytes); +} + +void MP4RtpHintTrack::AddSampleData( + MP4SampleId sampleId, + uint32_t dataOffset, + uint32_t dataLength) +{ + if (m_pWriteHint == NULL) { + throw new Exception("no hint pending", __FILE__, __LINE__, __FUNCTION__ ); + } + + MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); + if (pPacket == NULL) { + throw new Exception("no packet pending", __FILE__, __LINE__, __FUNCTION__ ); + } + + MP4RtpSampleData* pData = new MP4RtpSampleData(*pPacket); + + pData->SetReferenceSample(sampleId, dataOffset, dataLength); + + pPacket->AddData(pData); + + m_bytesThisHint += dataLength; + m_bytesThisPacket += dataLength; + m_pDmed->IncrementValue(dataLength); + m_pTpyl->IncrementValue(dataLength); + m_pTrpy->IncrementValue(dataLength); +} + +void MP4RtpHintTrack::AddESConfigurationPacket() +{ + if (m_pWriteHint == NULL) { + throw new Exception("no hint pending", __FILE__, __LINE__, __FUNCTION__ ); + } + + uint8_t* pConfig = NULL; + uint32_t configSize = 0; + + m_File.GetTrackESConfiguration(m_pRefTrack->GetId(), + &pConfig, &configSize); + + if (pConfig == NULL) { + return; + } + + ASSERT(m_pMaxPacketSizeProperty); + + if (configSize > m_pMaxPacketSizeProperty->GetValue()) { + throw new Exception("ES configuration is too large for RTP payload", __FILE__, __LINE__, __FUNCTION__ ); + } + + AddPacket(false); + + MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); + ASSERT(pPacket); + + // This is ugly! + // To get the ES configuration data somewhere known + // we create a sample data reference that points to + // this hint track (not the media track) + // and this sample of the hint track + // the offset into this sample is filled in during the write process + MP4RtpSampleData* pData = new MP4RtpSampleData(*pPacket); + + pData->SetEmbeddedImmediate(m_writeSampleId, pConfig, configSize); + + pPacket->AddData(pData); + + m_bytesThisHint += configSize; + m_bytesThisPacket += configSize; + m_pTpyl->IncrementValue(configSize); + m_pTrpy->IncrementValue(configSize); +} + +void MP4RtpHintTrack::WriteHint(MP4Duration duration, bool isSyncSample) +{ + if (m_pWriteHint == NULL) { + throw new Exception("no hint pending", __FILE__, __LINE__, __FUNCTION__ ); + } + + uint8_t* pBytes; + uint64_t numBytes; + + m_File.EnableMemoryBuffer(); + + m_pWriteHint->Write(m_File); + + m_File.DisableMemoryBuffer(&pBytes, &numBytes); + + WriteSample(pBytes, numBytes, duration, 0, isSyncSample); + + MP4Free(pBytes); + + // update statistics + if (m_bytesThisPacket > m_pPmax->GetValue()) { + m_pPmax->SetValue(m_bytesThisPacket); + } + + if (duration > m_pDmax->GetValue()) { + m_pDmax->SetValue(duration); + } + + MP4Timestamp startTime; + + GetSampleTimes(m_writeHintId, &startTime, NULL); + + if (startTime < m_thisSec + GetTimeScale()) { + m_bytesThisSec += m_bytesThisHint; + } else { + if (m_bytesThisSec > m_pMaxr->GetValue()) { + m_pMaxr->SetValue(m_bytesThisSec); + } + m_thisSec = startTime - (startTime % GetTimeScale()); + m_bytesThisSec = m_bytesThisHint; + } + + // cleanup + delete m_pWriteHint; + m_pWriteHint = NULL; +} + +void MP4RtpHintTrack::FinishWrite(uint32_t option) +{ + if (m_writeHintId != MP4_INVALID_SAMPLE_ID) { + m_pMaxPdu->SetValue(m_pPmax->GetValue()); + if (m_pNump->GetValue()) { + m_pAvgPdu->SetValue(m_pTrpy->GetValue() / m_pNump->GetValue()); + } + + m_pMaxBitRate->SetValue(m_pMaxr->GetValue() * 8); + if (GetDuration()) { + m_pAvgBitRate->SetValue( + m_pTrpy->GetValue() * 8 * GetTimeScale() / GetDuration()); + } + } + + MP4Track::FinishWrite(); +} + +void MP4RtpHintTrack::InitStats() +{ + MP4Atom* pHinfAtom = m_trakAtom.FindAtom("trak.udta.hinf"); + + ASSERT(pHinfAtom); + + (void)pHinfAtom->FindProperty("hinf.trpy.bytes", (MP4Property**)&m_pTrpy); + (void)pHinfAtom->FindProperty("hinf.nump.packets", (MP4Property**)&m_pNump); + (void)pHinfAtom->FindProperty("hinf.tpyl.bytes", (MP4Property**)&m_pTpyl); + (void)pHinfAtom->FindProperty("hinf.maxr.bytes", (MP4Property**)&m_pMaxr); + (void)pHinfAtom->FindProperty("hinf.dmed.bytes", (MP4Property**)&m_pDmed); + (void)pHinfAtom->FindProperty("hinf.dimm.bytes", (MP4Property**)&m_pDimm); + (void)pHinfAtom->FindProperty("hinf.pmax.bytes", (MP4Property**)&m_pPmax); + (void)pHinfAtom->FindProperty("hinf.dmax.milliSecs", (MP4Property**)&m_pDmax); + + MP4Atom* pHmhdAtom = m_trakAtom.FindAtom("trak.mdia.minf.hmhd"); + + ASSERT(pHmhdAtom); + + (void)pHmhdAtom->FindProperty("hmhd.maxPduSize", (MP4Property**)&m_pMaxPdu); + (void)pHmhdAtom->FindProperty("hmhd.avgPduSize", (MP4Property**)&m_pAvgPdu); + (void)pHmhdAtom->FindProperty("hmhd.maxBitRate", (MP4Property**)&m_pMaxBitRate); + (void)pHmhdAtom->FindProperty("hmhd.avgBitRate", (MP4Property**)&m_pAvgBitRate); + + MP4Integer32Property* pMaxrPeriod = NULL; + (void)pHinfAtom->FindProperty("hinf.maxr.granularity", + (MP4Property**)&pMaxrPeriod); + if (pMaxrPeriod) { + pMaxrPeriod->SetValue(1000); // 1 second + } +} + + +MP4RtpHint::MP4RtpHint(MP4RtpHintTrack& track) + : m_track(track) +{ + AddProperty( /* 0 */ + new MP4Integer16Property(this->GetTrack().GetTrakAtom(), "packetCount")); + AddProperty( /* 1 */ + new MP4Integer16Property(this->GetTrack().GetTrakAtom(), "reserved")); +} + +MP4RtpHint::~MP4RtpHint() +{ + for (uint32_t i = 0; i < m_rtpPackets.Size(); i++) { + delete m_rtpPackets[i]; + } +} + +MP4RtpPacket* MP4RtpHint::AddPacket() +{ + MP4RtpPacket* pPacket = new MP4RtpPacket(*this); + m_rtpPackets.Add(pPacket); + + // packetCount property + ((MP4Integer16Property*)m_pProperties[0])->IncrementValue(); + + pPacket->SetBFrame(m_isBFrame); + pPacket->SetTimestampOffset(m_timestampOffset); + + return pPacket; +} + +void MP4RtpHint::Read(MP4File& file) +{ + // call base class Read for required properties + MP4Container::Read(file); + + uint16_t numPackets = + ((MP4Integer16Property*)m_pProperties[0])->GetValue(); + + for (uint16_t i = 0; i < numPackets; i++) { + MP4RtpPacket* pPacket = new MP4RtpPacket(*this); + + m_rtpPackets.Add(pPacket); + + pPacket->Read(file); + } + + if (log.verbosity >= MP4_LOG_VERBOSE1) { + log.verbose1f("\"%s\": ReadHint:", GetTrack().GetFile().GetFilename().c_str()); + Dump(10, false); + } +} + +void MP4RtpHint::Write(MP4File& file) +{ + uint64_t hintStartPos = file.GetPosition(); + + MP4Container::Write(file); + + uint64_t packetStartPos = file.GetPosition(); + + uint32_t i; + + // first write out packet (and data) entries + for (i = 0; i < m_rtpPackets.Size(); i++) { + m_rtpPackets[i]->Write(file); + } + + // now let packets write their extra data into the hint sample + for (i = 0; i < m_rtpPackets.Size(); i++) { + m_rtpPackets[i]->WriteEmbeddedData(file, hintStartPos); + } + + uint64_t endPos = file.GetPosition(); + + file.SetPosition(packetStartPos); + + // finally rewrite the packet and data entries + // which now contain the correct offsets for the embedded data + for (i = 0; i < m_rtpPackets.Size(); i++) { + m_rtpPackets[i]->Write(file); + } + + file.SetPosition(endPos); + + if (log.verbosity >= MP4_LOG_VERBOSE1) { + log.verbose1f("\"%s\": WriteRtpHint:", GetTrack().GetFile().GetFilename().c_str()); + Dump(14, false); + } +} + +void MP4RtpHint::Dump(uint8_t indent, bool dumpImplicits) +{ + MP4Container::Dump(indent, dumpImplicits); + + for (uint32_t i = 0; i < m_rtpPackets.Size(); i++) { + log.dump(indent, MP4_LOG_VERBOSE1,"\"%s\": RtpPacket: %u", + GetTrack().GetFile().GetFilename().c_str(), i); + m_rtpPackets[i]->Dump(indent + 1, dumpImplicits); + } +} + +MP4RtpPacket::MP4RtpPacket(MP4RtpHint& hint) + : m_hint(hint) +{ + AddProperty( /* 0 */ + new MP4Integer32Property(this->GetHint().GetTrack().GetTrakAtom(), "relativeXmitTime")); + AddProperty( /* 1 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "reserved1", 2)); + AddProperty( /* 2 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "Pbit", 1)); + AddProperty( /* 3 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "Xbit", 1)); + AddProperty( /* 4 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "reserved2", 4)); + AddProperty( /* 5 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "Mbit", 1)); + AddProperty( /* 6 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "payloadType", 7)); + AddProperty( /* 7 */ + new MP4Integer16Property(this->GetHint().GetTrack().GetTrakAtom(), "sequenceNumber")); + AddProperty( /* 8 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "reserved3", 13)); + AddProperty( /* 9 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "extraFlag", 1)); + AddProperty( /* 10 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "bFrameFlag", 1)); + AddProperty( /* 11 */ + new MP4BitfieldProperty(this->GetHint().GetTrack().GetTrakAtom(), "repeatFlag", 1)); + AddProperty( /* 12 */ + new MP4Integer16Property(this->GetHint().GetTrack().GetTrakAtom(), "entryCount")); +} + +MP4RtpPacket::~MP4RtpPacket() +{ + for (uint32_t i = 0; i < m_rtpData.Size(); i++) { + delete m_rtpData[i]; + } +} + +void MP4RtpPacket::AddExtraProperties() +{ + AddProperty( /* 13 */ + new MP4Integer32Property(this->GetHint().GetTrack().GetTrakAtom(), "extraInformationLength")); + + // This is a bit of a hack, since the tlv entries are really defined + // as atoms but there is only one type defined now, rtpo, and getting + // our atom code hooked up here would be a major pain with little gain + + AddProperty( /* 14 */ + new MP4Integer32Property(this->GetHint().GetTrack().GetTrakAtom(), "tlvLength")); + AddProperty( /* 15 */ + new MP4StringProperty(this->GetHint().GetTrack().GetTrakAtom(), "tlvType")); + AddProperty( /* 16 */ + new MP4Integer32Property(this->GetHint().GetTrack().GetTrakAtom(), "timestampOffset")); + + ((MP4Integer32Property*)m_pProperties[13])->SetValue(16); + ((MP4Integer32Property*)m_pProperties[14])->SetValue(12); + ((MP4StringProperty*)m_pProperties[15])->SetFixedLength(4); + ((MP4StringProperty*)m_pProperties[15])->SetValue("rtpo"); +} + +void MP4RtpPacket::Read(MP4File& file) +{ + // call base class Read for required properties + MP4Container::Read(file); + + // read extra info if present + // we only support the rtpo field! + if (((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 1) { + ReadExtra(file); + } + + uint16_t numDataEntries = + ((MP4Integer16Property*)m_pProperties[12])->GetValue(); + + // read data entries + for (uint16_t i = 0; i < numDataEntries; i++) { + uint8_t dataType; + file.PeekBytes(&dataType, 1); + + MP4RtpData* pData; + + switch (dataType) { + case 0: + pData = new MP4RtpNullData(*this); + break; + case 1: + pData = new MP4RtpImmediateData(*this); + break; + case 2: + pData = new MP4RtpSampleData(*this); + break; + case 3: + pData = new MP4RtpSampleDescriptionData(*this); + break; + default: + throw new Exception("unknown packet data entry type", __FILE__, __LINE__, __FUNCTION__ ); + } + + m_rtpData.Add(pData); + + // read data entry's properties + pData->Read(file); + } +} + +void MP4RtpPacket::ReadExtra(MP4File& file) +{ + AddExtraProperties(); + + int32_t extraLength = (int32_t)file.ReadUInt32(); + + if (extraLength < 4) { + throw new Exception("bad packet extra info length", __FILE__, __LINE__, __FUNCTION__ ); + } + extraLength -= 4; + + while (extraLength > 0) { + uint32_t entryLength = file.ReadUInt32(); + uint32_t entryTag = file.ReadUInt32(); + + if (entryLength < 8) { + throw new Exception("bad packet extra info entry length", __FILE__, __LINE__, __FUNCTION__ ); + } + + if (entryTag == STRTOINT32("rtpo") && entryLength == 12) { + // read the rtp timestamp offset + m_pProperties[16]->Read(file); + } else { + // ignore it, LATER carry it along + file.SetPosition(file.GetPosition() + entryLength - 8); + } + + extraLength -= entryLength; + } + + if (extraLength < 0) { + throw new Exception("invalid packet extra info length", __FILE__, __LINE__, __FUNCTION__ ); + } +} + +void MP4RtpPacket::Set(uint8_t payloadNumber, + uint32_t packetId, bool setMbit) +{ + ((MP4BitfieldProperty*)m_pProperties[5])->SetValue(setMbit); + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(payloadNumber); + ((MP4Integer16Property*)m_pProperties[7])->SetValue(packetId); +} + +int32_t MP4RtpPacket::GetTransmitOffset() +{ + return ((MP4Integer32Property*)m_pProperties[0])->GetValue(); +} + +void MP4RtpPacket::SetTransmitOffset(int32_t transmitOffset) +{ + ((MP4Integer32Property*)m_pProperties[0])->SetValue(transmitOffset); +} + +bool MP4RtpPacket::GetPBit() +{ + return ((MP4BitfieldProperty*)m_pProperties[2])->GetValue(); +} + +bool MP4RtpPacket::GetXBit() +{ + return ((MP4BitfieldProperty*)m_pProperties[3])->GetValue(); +} + +bool MP4RtpPacket::GetMBit() +{ + return ((MP4BitfieldProperty*)m_pProperties[5])->GetValue(); +} + +uint8_t MP4RtpPacket::GetPayload() +{ + return ((MP4BitfieldProperty*)m_pProperties[6])->GetValue(); +} + +uint16_t MP4RtpPacket::GetSequenceNumber() +{ + return ((MP4Integer16Property*)m_pProperties[7])->GetValue(); +} + +bool MP4RtpPacket::IsBFrame() +{ + return ((MP4BitfieldProperty*)m_pProperties[10])->GetValue(); +} + +void MP4RtpPacket::SetBFrame(bool isBFrame) +{ + ((MP4BitfieldProperty*)m_pProperties[10])->SetValue(isBFrame); +} + +void MP4RtpPacket::SetTimestampOffset(uint32_t timestampOffset) +{ + if (timestampOffset == 0) { + return; + } + + ASSERT(((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 0); + + // set X bit + ((MP4BitfieldProperty*)m_pProperties[9])->SetValue(1); + + AddExtraProperties(); + + ((MP4Integer32Property*)m_pProperties[16])->SetValue(timestampOffset); +} + +void MP4RtpPacket::AddData(MP4RtpData* pData) +{ + m_rtpData.Add(pData); + + // increment entry count property + ((MP4Integer16Property*)m_pProperties[12])->IncrementValue(); +} + +uint32_t MP4RtpPacket::GetDataSize() +{ + uint32_t totalDataSize = 0; + + for (uint32_t i = 0; i < m_rtpData.Size(); i++) { + totalDataSize += m_rtpData[i]->GetDataSize(); + } + + return totalDataSize; +} + +void MP4RtpPacket::GetData(uint8_t* pDest) +{ + for (uint32_t i = 0; i < m_rtpData.Size(); i++) { + m_rtpData[i]->GetData(pDest); + pDest += m_rtpData[i]->GetDataSize(); + } +} + +void MP4RtpPacket::Write(MP4File& file) +{ + MP4Container::Write(file); + + for (uint32_t i = 0; i < m_rtpData.Size(); i++) { + m_rtpData[i]->Write(file); + } +} + +void MP4RtpPacket::WriteEmbeddedData(MP4File& file, uint64_t startPos) +{ + for (uint32_t i = 0; i < m_rtpData.Size(); i++) { + m_rtpData[i]->WriteEmbeddedData(file, startPos); + } +} + +void MP4RtpPacket::Dump(uint8_t indent, bool dumpImplicits) +{ + MP4Container::Dump(indent, dumpImplicits); + + for (uint32_t i = 0; i < m_rtpData.Size(); i++) { + log.dump(indent, MP4_LOG_VERBOSE1, "\"%s\": RtpData: %u", + GetHint().GetTrack().GetFile().GetFilename().c_str(), i); + m_rtpData[i]->Dump(indent + 1, dumpImplicits); + } +} + +MP4RtpData::MP4RtpData(MP4RtpPacket& packet) + : m_packet(packet) +{ + AddProperty( /* 0 */ + new MP4Integer8Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "type")); +} + +MP4Track* MP4RtpData::FindTrackFromRefIndex(uint8_t refIndex) +{ + MP4Track* pTrack; + + if (refIndex == (uint8_t)-1) { + // ourselves + pTrack = &GetPacket().GetHint().GetTrack(); + } else if (refIndex == 0) { + // our reference track + pTrack = GetPacket().GetHint().GetTrack().GetRefTrack(); + } else { + // some other track + MP4RtpHintTrack* pHintTrack = + &GetPacket().GetHint().GetTrack(); + + MP4Atom& trakAtom = pHintTrack->GetTrakAtom(); + + MP4Integer32Property* pTrackIdProperty = NULL; + (void)trakAtom.FindProperty( + "trak.tref.hint.entries", + (MP4Property**)&pTrackIdProperty); + ASSERT(pTrackIdProperty); + + uint32_t refTrackId = + pTrackIdProperty->GetValue(refIndex - 1); + + pTrack = pHintTrack->GetFile().GetTrack(refTrackId); + } + + return pTrack; +} + +MP4RtpNullData::MP4RtpNullData(MP4RtpPacket& packet) + : MP4RtpData(packet) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(0); + + AddProperty( /* 1 */ + new MP4BytesProperty(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "pad", 15)); + + ((MP4BytesProperty*)m_pProperties[1])->SetFixedSize(15); +} + +MP4RtpImmediateData::MP4RtpImmediateData(MP4RtpPacket& packet) + : MP4RtpData(packet) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(1); + + AddProperty( /* 1 */ + new MP4Integer8Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "count")); + AddProperty( /* 2 */ + new MP4BytesProperty(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "data", 14)); + + ((MP4BytesProperty*)m_pProperties[2])->SetFixedSize(14); +} + +void MP4RtpImmediateData::Set(const uint8_t* pBytes, uint8_t numBytes) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue(numBytes); + ((MP4BytesProperty*)m_pProperties[2])->SetValue(pBytes, numBytes); +} + +uint16_t MP4RtpImmediateData::GetDataSize() +{ + return ((MP4Integer8Property*)m_pProperties[1])->GetValue(); +} + +void MP4RtpImmediateData::GetData(uint8_t* pDest) +{ + uint8_t* pValue; + uint32_t valueSize; + ((MP4BytesProperty*)m_pProperties[2])->GetValue(&pValue, &valueSize); + + memcpy(pDest, pValue, GetDataSize()); + MP4Free(pValue); +} + +MP4RtpSampleData::MP4RtpSampleData(MP4RtpPacket& packet) + : MP4RtpData(packet) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(2); + + AddProperty( /* 1 */ + new MP4Integer8Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "trackRefIndex")); + AddProperty( /* 2 */ + new MP4Integer16Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "length")); + AddProperty( /* 3 */ + new MP4Integer32Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "sampleNumber")); + AddProperty( /* 4 */ + new MP4Integer32Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "sampleOffset")); + AddProperty( /* 5 */ + new MP4Integer16Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "bytesPerBlock")); + AddProperty( /* 6 */ + new MP4Integer16Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "samplesPerBlock")); + + ((MP4Integer16Property*)m_pProperties[5])->SetValue(1); + ((MP4Integer16Property*)m_pProperties[6])->SetValue(1); + + m_pRefData = NULL; + m_pRefTrack = NULL; + m_refSampleId = MP4_INVALID_SAMPLE_ID; + m_refSampleOffset = 0; +} + +void MP4RtpSampleData::SetEmbeddedImmediate(MP4SampleId sampleId, + uint8_t* pData, uint16_t dataLength) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue((uint8_t)-1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(dataLength); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleId); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(0); + CHECK_AND_FREE(m_pRefData); + m_pRefData = pData; +} + +void MP4RtpSampleData::SetReferenceSample( + MP4SampleId refSampleId, uint32_t refSampleOffset, + uint16_t sampleLength) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue(0); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(sampleLength); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(refSampleId); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(refSampleOffset); +} + +void MP4RtpSampleData::SetEmbeddedSample( + MP4SampleId sampleId, MP4Track* pRefTrack, + MP4SampleId refSampleId, uint32_t refSampleOffset, + uint16_t sampleLength) +{ + ((MP4Integer8Property*)m_pProperties[1])->SetValue((uint8_t)-1); + ((MP4Integer16Property*)m_pProperties[2])->SetValue(sampleLength); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleId); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(0); + m_pRefTrack = pRefTrack; + m_refSampleId = refSampleId; + m_refSampleOffset = refSampleOffset; +} + +uint16_t MP4RtpSampleData::GetDataSize() +{ + return ((MP4Integer16Property*)m_pProperties[2])->GetValue(); +} + +void MP4RtpSampleData::GetData(uint8_t* pDest) +{ + uint8_t trackRefIndex = + ((MP4Integer8Property*)m_pProperties[1])->GetValue(); + + MP4Track* pSampleTrack = + FindTrackFromRefIndex(trackRefIndex); + + pSampleTrack->ReadSampleFragment( + ((MP4Integer32Property*)m_pProperties[3])->GetValue(), // sampleId + ((MP4Integer32Property*)m_pProperties[4])->GetValue(), // sampleOffset + ((MP4Integer16Property*)m_pProperties[2])->GetValue(), // sampleLength + pDest); +} + +void MP4RtpSampleData::WriteEmbeddedData(MP4File& file, uint64_t startPos) +{ + // if not using embedded data, nothing to do + if (((MP4Integer8Property*)m_pProperties[1])->GetValue() != (uint8_t)-1) { + return; + } + + // figure out the offset within this hint sample for this embedded data + uint64_t offset = file.GetPosition() - startPos; + ASSERT(offset <= 0xFFFFFFFF); + ((MP4Integer32Property*)m_pProperties[4])->SetValue((uint32_t)offset); + + uint16_t length = ((MP4Integer16Property*)m_pProperties[2])->GetValue(); + + if (m_pRefData) { + file.WriteBytes(m_pRefData, length); + return; + } + + if (m_refSampleId != MP4_INVALID_SAMPLE_ID) { + uint8_t* pSample = NULL; + uint32_t sampleSize = 0; + + ASSERT(m_pRefTrack); + m_pRefTrack->ReadSample(m_refSampleId, &pSample, &sampleSize); + + ASSERT(m_refSampleOffset + length <= sampleSize); + + file.WriteBytes(&pSample[m_refSampleOffset], length); + + MP4Free(pSample); + return; + } +} + +MP4RtpSampleDescriptionData::MP4RtpSampleDescriptionData(MP4RtpPacket& packet) + : MP4RtpData(packet) +{ + ((MP4Integer8Property*)m_pProperties[0])->SetValue(3); + + AddProperty( /* 1 */ + new MP4Integer8Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "trackRefIndex")); + AddProperty( /* 2 */ + new MP4Integer16Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "length")); + AddProperty( /* 3 */ + new MP4Integer32Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "sampleDescriptionIndex")); + AddProperty( /* 4 */ + new MP4Integer32Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "sampleDescriptionOffset")); + AddProperty( /* 5 */ + new MP4Integer32Property(this->GetPacket().GetHint().GetTrack().GetTrakAtom(), "reserved")); +} + +void MP4RtpSampleDescriptionData::Set(uint32_t sampleDescrIndex, + uint32_t offset, uint16_t length) +{ + ((MP4Integer16Property*)m_pProperties[2])->SetValue(length); + ((MP4Integer32Property*)m_pProperties[3])->SetValue(sampleDescrIndex); + ((MP4Integer32Property*)m_pProperties[4])->SetValue(offset); +} + +uint16_t MP4RtpSampleDescriptionData::GetDataSize() +{ + return ((MP4Integer16Property*)m_pProperties[2])->GetValue(); +} + +void MP4RtpSampleDescriptionData::GetData(uint8_t* pDest) +{ + // we start with the index into our track references + uint8_t trackRefIndex = + ((MP4Integer8Property*)m_pProperties[1])->GetValue(); + + // from which we can find the track structure + MP4Track* pSampleTrack = + FindTrackFromRefIndex(trackRefIndex); + + // next find the desired atom in the track's sample description table + uint32_t sampleDescrIndex = + ((MP4Integer32Property*)m_pProperties[3])->GetValue(); + + MP4Atom& trakAtom = + pSampleTrack->GetTrakAtom(); + + char sdName[64]; + snprintf(sdName, 64, "trak.mdia.minf.stbl.stsd.*[%u]", sampleDescrIndex); + + MP4Atom* pSdAtom = + trakAtom.FindAtom(sdName); + + // bad reference + if (pSdAtom == NULL) { + throw new Exception("invalid sample description index", __FILE__, __LINE__, __FUNCTION__ ); + } + + // check validity of the upcoming copy + uint16_t length = + ((MP4Integer16Property*)m_pProperties[2])->GetValue(); + uint32_t offset = + ((MP4Integer32Property*)m_pProperties[4])->GetValue(); + + if (offset + length > pSdAtom->GetSize()) { + throw new Exception("offset and/or length are too large", + __FILE__, __LINE__, __FUNCTION__); + } + + // now we use the raw file to get the desired bytes + + MP4File& file = GetPacket().GetHint().GetTrack().GetFile(); + + uint64_t orgPos = file.GetPosition(); + + // It's not entirely clear from the spec whether the offset is from + // the start of the sample descirption atom, or the start of the atom's + // data. I believe it is the former, but the commented out code will + // realize the latter interpretation if I turn out to be wrong. + uint64_t dataPos = pSdAtom->GetStart(); + //uint64_t dataPos = pSdAtom->GetEnd() - pSdAtom->GetSize(); + + file.SetPosition(dataPos + offset); + + file.ReadBytes(pDest, length); + + file.SetPosition(orgPos); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/rtphint.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/rtphint.h new file mode 100644 index 00000000..a2a4fa8a --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/rtphint.h @@ -0,0 +1,362 @@ +/* + * 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 [email protected] + */ + +#ifndef MP4V2_IMPL_RTPHINT_H +#define MP4V2_IMPL_RTPHINT_H + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +// forward declarations +class MP4RtpHintTrack; +class MP4RtpHint; +class MP4RtpPacket; + +class MP4RtpData : public MP4Container { +public: + MP4RtpData(MP4RtpPacket& packet); + + MP4RtpPacket& GetPacket() { + return m_packet; + } + + virtual uint16_t GetDataSize() = 0; + virtual void GetData(uint8_t* pDest) = 0; + + MP4Track* FindTrackFromRefIndex(uint8_t refIndex); + + virtual void WriteEmbeddedData(MP4File& file, uint64_t startPos) { + // default is no-op + } + +protected: + MP4RtpPacket& m_packet; +}; + +MP4ARRAY_DECL(MP4RtpData, MP4RtpData*) + +class MP4RtpNullData : public MP4RtpData { +public: + MP4RtpNullData(MP4RtpPacket& packet); + + uint16_t GetDataSize() { + return 0; + } + + void GetData(uint8_t* pDest) { + // no-op + } +}; + +class MP4RtpImmediateData : public MP4RtpData { +public: + MP4RtpImmediateData(MP4RtpPacket& packet); + + void Set(const uint8_t* pBytes, uint8_t numBytes); + + uint16_t GetDataSize(); + + void GetData(uint8_t* pDest); +}; + +class MP4RtpSampleData : public MP4RtpData { +public: + MP4RtpSampleData(MP4RtpPacket& packet); + + ~MP4RtpSampleData(void) { + CHECK_AND_FREE(m_pRefData); + }; + + void SetEmbeddedImmediate( + MP4SampleId sampleId, + uint8_t* pData, uint16_t dataLength); + + void SetReferenceSample( + MP4SampleId refSampleId, uint32_t refSampleOffset, + uint16_t sampleLength); + + void SetEmbeddedSample( + MP4SampleId sampleId, MP4Track* pRefTrack, + MP4SampleId refSampleId, uint32_t refSampleOffset, + uint16_t sampleLength); + + uint16_t GetDataSize(); + + void GetData(uint8_t* pDest); + + void WriteEmbeddedData(MP4File& file, uint64_t startPos); + +protected: + uint8_t* m_pRefData; + + MP4Track* m_pRefTrack; + MP4SampleId m_refSampleId; + uint32_t m_refSampleOffset; +}; + +class MP4RtpSampleDescriptionData : public MP4RtpData { +public: + MP4RtpSampleDescriptionData(MP4RtpPacket& packet); + + void Set(uint32_t sampleDescrIndex, + uint32_t offset, uint16_t length); + + uint16_t GetDataSize(); + + void GetData(uint8_t* pDest); +}; + +class MP4RtpPacket : public MP4Container { +public: + MP4RtpPacket(MP4RtpHint& hint); + + ~MP4RtpPacket(); + + void AddExtraProperties(); + + MP4RtpHint& GetHint() { + return m_hint; + } + + void Set(uint8_t payloadNumber, uint32_t packetId, bool setMbit); + + int32_t GetTransmitOffset(); + + bool GetPBit(); + + bool GetXBit(); + + bool GetMBit(); + + uint8_t GetPayload(); + + uint16_t GetSequenceNumber(); + + void SetTransmitOffset(int32_t transmitOffset); + + bool IsBFrame(); + + void SetBFrame(bool isBFrame); + + void SetTimestampOffset(uint32_t timestampOffset); + + void AddData(MP4RtpData* pData); + + uint32_t GetDataSize(); + + void GetData(uint8_t* pDest); + + void Read(MP4File& file); + + void ReadExtra(MP4File& file); + + void Write(MP4File& file); + + void WriteEmbeddedData(MP4File& file, uint64_t startPos); + + void Dump(uint8_t indent, bool dumpImplicits); + +protected: + MP4RtpHint& m_hint; + MP4RtpDataArray m_rtpData; +}; + +MP4ARRAY_DECL(MP4RtpPacket, MP4RtpPacket*) + +class MP4RtpHint : public MP4Container { +public: + MP4RtpHint(MP4RtpHintTrack& track); + + ~MP4RtpHint(); + + MP4RtpHintTrack& GetTrack() { + return m_track; + } + + uint16_t GetNumberOfPackets() { + return m_rtpPackets.Size(); + } + + bool IsBFrame() { + return m_isBFrame; + } + void SetBFrame(bool isBFrame) { + m_isBFrame = isBFrame; + } + + uint32_t GetTimestampOffset() { + return m_timestampOffset; + } + void SetTimestampOffset(uint32_t timestampOffset) { + m_timestampOffset = timestampOffset; + } + + MP4RtpPacket* AddPacket(); + + MP4RtpPacket* GetPacket(uint16_t index) { + return m_rtpPackets[index]; + } + + MP4RtpPacket* GetCurrentPacket() { + if (m_rtpPackets.Size() == 0) { + return NULL; + } + return m_rtpPackets[m_rtpPackets.Size() - 1]; + } + + void Read(MP4File& file); + + void Write(MP4File& file); + + void Dump(uint8_t indent, bool dumpImplicits); + +protected: + MP4RtpHintTrack& m_track; + MP4RtpPacketArray m_rtpPackets; + + // values when adding packets to a hint (write mode) + bool m_isBFrame; + uint32_t m_timestampOffset; +}; + +class MP4RtpHintTrack : public MP4Track { +public: + MP4RtpHintTrack(MP4File& file, MP4Atom& trakAtom); + + ~MP4RtpHintTrack(); + + void InitRefTrack(); + + void InitPayload(); + + void InitRtpStart(); + + void InitStats(); + + MP4Track* GetRefTrack() { + InitRefTrack(); + return m_pRefTrack; + } + + void GetPayload( + char** ppPayloadName = NULL, + uint8_t* pPayloadNumber = NULL, + uint16_t* pMaxPayloadSize = NULL, + char **ppEncodingParams = NULL); + + void SetPayload( + const char* payloadName, + uint8_t payloadNumber, + uint16_t maxPayloadSize, + const char *encoding_parms, + bool add_rtpmap, + bool add_mpeg4_esid); + + void ReadHint( + MP4SampleId hintSampleId, + uint16_t* pNumPackets = NULL); + + uint16_t GetHintNumberOfPackets(); + + bool GetPacketBFrame(uint16_t packetIndex); + + uint16_t GetPacketTransmitOffset(uint16_t packetIndex); + + void ReadPacket( + uint16_t packetIndex, + uint8_t** ppBytes, + uint32_t* pNumBytes, + uint32_t ssrc, + bool includeHeader = true, + bool includePayload = true); + + MP4Timestamp GetRtpTimestampStart(); + + void SetRtpTimestampStart(MP4Timestamp start); + + void AddHint(bool isBFrame, uint32_t timestampOffset); + + void AddPacket(bool setMbit, int32_t transmitOffset = 0); + + void AddImmediateData(const uint8_t* pBytes, uint32_t numBytes); + + void AddSampleData(MP4SampleId sampleId, + uint32_t dataOffset, uint32_t dataLength); + + void AddESConfigurationPacket(); + + void WriteHint(MP4Duration duration, bool isSyncSample); + + void FinishWrite(uint32_t options = 0); + +protected: + MP4Track* m_pRefTrack; + + MP4StringProperty* m_pRtpMapProperty; + MP4Integer32Property* m_pPayloadNumberProperty; + MP4Integer32Property* m_pMaxPacketSizeProperty; + MP4Integer32Property* m_pSnroProperty; + MP4Integer32Property* m_pTsroProperty; + uint32_t m_rtpSequenceStart; + uint32_t m_rtpTimestampStart; + + // reading + MP4RtpHint* m_pReadHint; + uint8_t* m_pReadHintSample; + uint32_t m_readHintSampleSize; + MP4Timestamp m_readHintTimestamp; + + // writing + MP4RtpHint* m_pWriteHint; + MP4SampleId m_writeHintId; + uint32_t m_writePacketId; + + // statistics + // in trak.udta.hinf + MP4Integer64Property* m_pTrpy; + MP4Integer64Property* m_pNump; + MP4Integer64Property* m_pTpyl; + MP4Integer32Property* m_pMaxr; + MP4Integer64Property* m_pDmed; + MP4Integer64Property* m_pDimm; + MP4Integer32Property* m_pPmax; + MP4Integer32Property* m_pDmax; + + // in trak.mdia.minf.hmhd + MP4Integer16Property* m_pMaxPdu; + MP4Integer16Property* m_pAvgPdu; + MP4Integer32Property* m_pMaxBitRate; + MP4Integer32Property* m_pAvgBitRate; + + MP4Timestamp m_thisSec; + uint32_t m_bytesThisSec; + uint32_t m_bytesThisHint; + uint32_t m_bytesThisPacket; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_RTPHINT_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/src.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/src.h new file mode 100644 index 00000000..472d8a0e --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/src.h @@ -0,0 +1,52 @@ +#ifndef MP4V2_IMPL_SRC_H +#define MP4V2_IMPL_SRC_H + +/////////////////////////////////////////////////////////////////////////////// + +#include "libplatform/platform.h" +#include <mp4v2/mp4v2.h> + +/////////////////////////////////////////////////////////////////////////////// + +namespace mp4v2 { namespace impl { + using namespace mp4v2::platform; + using io::File; + using io::FileSystem; +}} // namspace mp4v2::impl + +/////////////////////////////////////////////////////////////////////////////// + +#include "text.h" +#include "enum.h" +#include "exception.h" + +#include "bmff/typebmff.h" +#include "itmf/type.h" + +#include "util.h" +#include "log.h" +#include "mp4util.h" +#include "mp4array.h" +#include "mp4track.h" +#include "mp4file.h" +#include "mp4property.h" +#include "mp4container.h" + +#include "mp4atom.h" +#include "atoms.h" + +#include "bmff/bmff.h" +#include "itmf/itmf.h" +#include "qtff/qtff.h" + +#include "mp4descriptor.h" +#include "descriptors.h" +#include "ocidescriptors.h" + +#include "qosqualifiers.h" +#include "odcommands.h" +#include "rtphint.h" + +/////////////////////////////////////////////////////////////////////////////// + +#endif // MP4V2_IMPL_SRC_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/text.cpp b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/text.cpp new file mode 100644 index 00000000..5790f967 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/text.cpp @@ -0,0 +1,41 @@ +#include "src/impl.h" + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +bool +LessIgnoreCase::operator()( const string& xstr, const string& ystr ) const +{ + const string::size_type xlen = xstr.length(); + const string::size_type ylen = ystr.length(); + + if( xlen < ylen ) { + for( string::size_type i = 0; i < xlen; i++ ) { + const char x = std::toupper( xstr[i] ); + const char y = std::toupper( ystr[i] ); + + if( x < y ) + return true; + else if ( x > y ) + return false; + } + return true; + } + else { + for( string::size_type i = 0; i < ylen; i++ ) { + const char x = std::toupper( xstr[i] ); + const char y = std::toupper( ystr[i] ); + + if( x < y ) + return true; + else if ( x > y ) + return false; + } + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/text.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/text.h new file mode 100644 index 00000000..4afd336b --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/text.h @@ -0,0 +1,17 @@ +#ifndef MP4V2_IMPL_TEXT_H +#define MP4V2_IMPL_TEXT_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +struct MP4V2_EXPORT LessIgnoreCase : less<string> +{ + bool operator()( const string&, const string& ) const; +}; + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_TEXT_H diff --git a/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/util.h b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/util.h new file mode 100644 index 00000000..aa3aba67 --- /dev/null +++ b/debian/mp4v2/mp4v2-2.0.0~dfsg0/src/util.h @@ -0,0 +1,82 @@ +#ifndef MP4V2_IMPL_UTIL_H +#define MP4V2_IMPL_UTIL_H + +namespace mp4v2 { namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +inline int8_t max( int8_t a, int8_t b ) { + return ( a > b ) ? a : b; +} + +inline int16_t max( int16_t a, int16_t b ) { + return ( a > b ) ? a : b; +} + +inline int32_t max( int32_t a, int32_t b ) { + return ( a > b ) ? a : b; +} + +inline int64_t max( int64_t a, int64_t b ) { + return ( a > b ) ? a : b; +} + +/////////////////////////////////////////////////////////////////////////////// + +inline uint8_t max( uint8_t a, uint8_t b ) { + return ( a > b ) ? a : b; +} + +inline uint16_t max( uint16_t a, uint16_t b ) { + return ( a > b ) ? a : b; +} + +inline uint32_t max( uint32_t a, uint32_t b ) { + return ( a > b ) ? a : b; +} + +inline uint64_t max( uint64_t a, uint64_t b ) { + return ( a > b ) ? a : b; +} + +/////////////////////////////////////////////////////////////////////////////// + +inline int8_t min( int8_t a, int8_t b ) { + return ( a < b ) ? a : b; +} + +inline int16_t min( int16_t a, int16_t b ) { + return ( a < b ) ? a : b; +} + +inline int32_t min( int32_t a, int32_t b ) { + return ( a < b ) ? a : b; +} + +inline int64_t min( int64_t a, int64_t b ) { + return ( a < b ) ? a : b; +} + +/////////////////////////////////////////////////////////////////////////////// + +inline uint8_t min( uint8_t a, uint8_t b ) { + return ( a < b ) ? a : b; +} + +inline uint16_t min( uint16_t a, uint16_t b ) { + return ( a < b ) ? a : b; +} + +inline uint32_t min( uint32_t a, uint32_t b ) { + return ( a < b ) ? a : b; +} + +inline uint64_t min( uint64_t a, uint64_t b ) { + return ( a < b ) ? a : b; +} + +/////////////////////////////////////////////////////////////////////////////// + +}} // namespace mp4v2::impl + +#endif // MP4V2_IMPL_UTIL_H |