shithub: aacdec

Download patch

ref: 0ab055fe640979fa9161ae5ddea6160e2340fd16
parent: 0b2ef5faeb07dbc043cc925da4177b69b2146c84
author: menno <menno>
date: Sun Jun 29 17:41:00 EDT 2003

iTunes tagging support

--- /dev/null
+++ b/common/mp4v2/atom_enca.cpp
@@ -1,0 +1,61 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is MPEG4IP.
+ * 
+ * The Initial Developer of the Original Code is Cisco Systems Inc.
+ * Portions created by Cisco Systems Inc. are
+ * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
+ * 
+ * Contributor(s): 
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
+ */
+
+#include "mp4common.h"
+
+MP4EncaAtom::MP4EncaAtom() 
+	: MP4Atom("enca") 
+{
+	AddReserved("reserved1", 6); /* 0 */
+
+	AddProperty( /* 1 */
+		new MP4Integer16Property("dataReferenceIndex"));
+
+	AddReserved("reserved2", 16); /* 2 */
+
+	AddProperty( /* 3 */
+		new MP4Integer16Property("timeScale"));
+
+	AddReserved("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 u_int8_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);
+}
--- /dev/null
+++ b/common/mp4v2/atom_encv.cpp
@@ -1,0 +1,80 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is MPEG4IP.
+ * 
+ * The Initial Developer of the Original Code is Cisco Systems Inc.
+ * Portions created by Cisco Systems Inc. are
+ * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
+ * 
+ * Contributor(s): 
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
+ */
+
+#include "mp4common.h"
+
+MP4EncvAtom::MP4EncvAtom() 
+	: MP4Atom("encv")
+{
+	AddReserved("reserved1", 6); /* 0 */
+
+	AddProperty( /* 1 */
+		new MP4Integer16Property("dataReferenceIndex"));
+
+	AddReserved("reserved2", 16); /* 2 */
+
+	AddProperty( /* 3 */
+		new MP4Integer16Property("width"));
+	AddProperty( /* 4 */
+		new MP4Integer16Property("height"));
+
+	AddReserved("reserved3", 14); /* 5 */
+
+	MP4StringProperty* pProp = 
+		new MP4StringProperty("compressorName");
+	pProp->SetFixedLength(32);
+	pProp->SetValue("");
+	AddProperty(pProp); /* 6 */
+	AddReserved("reserved4", 4); /* 7 */
+
+	ExpectChildAtom("esds", Required, OnlyOne);
+	ExpectChildAtom("sinf", Required, OnlyOne);
+}	
+
+void MP4EncvAtom::Generate()
+{
+	MP4Atom::Generate();
+
+	((MP4Integer16Property*)m_pProperties[1])->SetValue(1);
+
+	// property reserved3 has non-zero fixed values
+	static u_int8_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 u_int8_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);
+}
+
--- /dev/null
+++ b/common/mp4v2/atom_frma.cpp
@@ -1,0 +1,32 @@
+/*
+ * 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): 
+ *		Alix Marchandise-Franquet alix@cisco.com
+ *
+ * Add the OriginalFormatBox for ISMACrypt 
+ * contains the original format of the data (i.e. decrypted format)
+ */
+
+#include "mp4common.h"
+
+MP4FrmaAtom::MP4FrmaAtom() 
+	: MP4Atom("frma") 
+{
+        AddProperty( /* 0 */
+                new MP4Integer32Property("data-format"));			
+}
--- a/common/mp4v2/atom_ftyp.cpp
+++ b/common/mp4v2/atom_ftyp.cpp
@@ -49,12 +49,14 @@
 {
 	MP4Atom::Generate();
 
-	((MP4StringProperty*)m_pProperties[0])->SetValue("isom");
+	((MP4StringProperty*)m_pProperties[0])->SetValue("mp42");
 
 	MP4StringProperty* pBrandProperty = (MP4StringProperty*)
 		((MP4TableProperty*)m_pProperties[3])->GetProperty(0);
 	ASSERT(pBrandProperty);
-	pBrandProperty->AddValue("mp41");
+	pBrandProperty->AddValue("mp42");
+	pBrandProperty->AddValue("isom");
+	((MP4Integer32Property*)m_pProperties[2])->IncrementValue();
 	((MP4Integer32Property*)m_pProperties[2])->IncrementValue();
 }
 
--- /dev/null
+++ b/common/mp4v2/atom_iKMS.cpp
@@ -1,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 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): 
+ *		Alix Marchandise-Franquet alix@cisco.com
+ *
+ * ISMAKMSBox for ISMACrypt
+ * Do we care about the string length? Do we need to handle the null-term
+ * issue like in the hdlr atom?
+ */
+
+#include "mp4common.h"
+
+MP4IKMSAtom::MP4IKMSAtom() 
+	: MP4Atom("iKMS") 
+{
+	AddVersionAndFlags(); /* 0, 1 */
+	MP4StringProperty* pProp = new MP4StringProperty("kms_URI");
+	AddProperty(pProp); /* 2 */
+}
--- /dev/null
+++ b/common/mp4v2/atom_iSFM.cpp
@@ -1,0 +1,38 @@
+/*
+ * 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): 
+ *		Alix Marchandise-Franquet alix@cisco.com
+ *
+ * ISMASampleFormatBox for ISMACrypt		
+ */
+
+#include "mp4common.h"
+
+MP4ISFMAtom::MP4ISFMAtom() 
+	: MP4Atom("iSFM") 
+{
+	AddVersionAndFlags(); /* 0, 1 */
+	AddProperty( /* 2 */
+		new MP4BitfieldProperty("selective-encryption", 1));
+	AddProperty( /* 3 */
+		new MP4BitfieldProperty("reserved", 7));
+	AddProperty( /* 4 */
+		new MP4Integer8Property("key-indicator-length"));	
+	AddProperty( /* 5 */
+		new MP4Integer8Property("IV-length"));	
+}
--- /dev/null
+++ b/common/mp4v2/atom_meta.cpp
@@ -1,0 +1,183 @@
+/*
+ * 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 "mp4common.h"
+
+MP4MetaAtom::MP4MetaAtom()
+    : MP4Atom("meta")
+{
+	AddVersionAndFlags(); /* 0, 1 */
+
+    ExpectChildAtom("hdlr", Required, OnlyOne);
+    ExpectChildAtom("ilst", Required, OnlyOne);
+}
+
+MP4MeanAtom::MP4MeanAtom()
+    : MP4Atom("mean")
+{
+	AddVersionAndFlags(); /* 0, 1 */
+
+    AddProperty(
+        new MP4BytesProperty("metadata")); /* 2 */
+}
+
+void MP4MeanAtom::Read() 
+{
+	// calculate size of the metadata from the atom size
+	((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 4);
+
+	MP4Atom::Read();
+}
+
+MP4NameAtom::MP4NameAtom()
+    : MP4Atom("name")
+{
+	AddVersionAndFlags(); /* 0, 1 */
+
+    AddProperty(
+        new MP4BytesProperty("metadata")); /* 2 */
+}
+
+void MP4NameAtom::Read() 
+{
+	// calculate size of the metadata from the atom size
+	((MP4BytesProperty*)m_pProperties[2])->SetValueSize(m_size - 4);
+
+	MP4Atom::Read();
+}
+
+MP4DataAtom::MP4DataAtom()
+    : MP4Atom("data")
+{
+	AddVersionAndFlags(); /* 0, 1 */
+    AddReserved("reserved2", 4); /* 2 */
+
+    AddProperty(
+        new MP4BytesProperty("metadata")); /* 3 */
+}
+
+void MP4DataAtom::Read() 
+{
+	// calculate size of the metadata from the atom size
+	((MP4BytesProperty*)m_pProperties[3])->SetValueSize(m_size - 8);
+
+	MP4Atom::Read();
+}
+
+MP4IlstAtom::MP4IlstAtom()
+    : MP4Atom("ilst")
+{
+    ExpectChildAtom("�nam", Optional, OnlyOne); /* name */
+    ExpectChildAtom("�ART", Optional, OnlyOne); /* artist */
+    ExpectChildAtom("�wrt", Optional, OnlyOne); /* writer */
+    ExpectChildAtom("�alb", Optional, OnlyOne); /* album */
+    ExpectChildAtom("�day", Optional, OnlyOne); /* date */
+    ExpectChildAtom("�too", Optional, OnlyOne); /* tool */
+    ExpectChildAtom("�cmt", Optional, OnlyOne); /* comment */
+    ExpectChildAtom("trkn", Optional, OnlyOne); /* tracknumber */
+    ExpectChildAtom("disk", Optional, OnlyOne); /* disknumber */
+    ExpectChildAtom("gnre", Optional, OnlyOne); /* genre */
+    ExpectChildAtom("cpil", Optional, OnlyOne); /* compilation */
+    ExpectChildAtom("tmpo", Optional, OnlyOne); /* BPM */
+    ExpectChildAtom("----", Optional, Many); /* ---- free form */
+}
+
+MP4DashAtom::MP4DashAtom()
+    : MP4Atom("----")
+{
+    ExpectChildAtom("mean", Required, OnlyOne);
+    ExpectChildAtom("name", Required, OnlyOne);
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4NamAtom::MP4NamAtom()
+    : MP4Atom("�nam")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4ArtAtom::MP4ArtAtom()
+    : MP4Atom("�ART")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4WrtAtom::MP4WrtAtom()
+    : MP4Atom("�wrt")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4AlbAtom::MP4AlbAtom()
+    : MP4Atom("�alb")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4CmtAtom::MP4CmtAtom()
+    : MP4Atom("�cmt")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4TrknAtom::MP4TrknAtom()
+    : MP4Atom("trkn")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4DiskAtom::MP4DiskAtom()
+    : MP4Atom("disk")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4DayAtom::MP4DayAtom()
+    : MP4Atom("�day")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4TooAtom::MP4TooAtom()
+    : MP4Atom("�too")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4GnreAtom::MP4GnreAtom()
+    : MP4Atom("gnre")
+{
+    ExpectChildAtom("data", Optional, OnlyOne);
+}
+
+MP4CpilAtom::MP4CpilAtom()
+    : MP4Atom("cpil")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
+
+MP4TmpoAtom::MP4TmpoAtom()
+    : MP4Atom("tmpo")
+{
+    ExpectChildAtom("data", Required, OnlyOne);
+}
--- /dev/null
+++ b/common/mp4v2/atom_schi.cpp
@@ -1,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 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): 
+ *		Alix Marchandise-Franquet  alix@cisco.com
+ *
+ * SchemeInformationBox for ISMACrypt
+ */
+
+#include "mp4common.h"
+
+MP4SchiAtom::MP4SchiAtom() 
+	: MP4Atom("schi") 
+{
+	AddVersionAndFlags();
+	// not sure if this is child atoms or table of boxes
+	// get clarification on spec 9.1.2.5
+	ExpectChildAtom("iKMS", Required, OnlyOne);
+	ExpectChildAtom("iSFM", Required, OnlyOne);
+}
--- /dev/null
+++ b/common/mp4v2/atom_schm.cpp
@@ -1,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.
+ * 
+ * Contributor(s): 
+ *              Alix Marchandise-Franquet alix@cisco.com
+ *
+ * Add the SchemeTypeBox for ISMACrypt
+ */
+
+#include "mp4common.h"
+
+MP4SchmAtom::MP4SchmAtom() 
+	: MP4Atom("schm") 
+{
+	AddVersionAndFlags(); /* 0, 1 */
+	AddProperty( /* 2 */
+                new MP4Integer32Property("scheme_type"));
+	AddProperty( /* 3 */
+	        new MP4Integer32Property("scheme_version"));
+	// browser URI if flags set, TODO
+}
--- /dev/null
+++ b/common/mp4v2/atom_sinf.cpp
@@ -1,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 MPEG4IP.
+ * 
+ * The Initial Developer of the Original Code is Cisco Systems Inc.
+ * Portions created by Cisco Systems Inc. are
+ * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
+ * 
+ * Contributor(s): 
+ *              Dave Mackie                dmackie@cisco.com
+ *		Alix Marchandise-Franquet  alix@cisco.com
+ *
+ * Add the ProtectionInfoBox for ISMACrypt
+ */
+
+#include "mp4common.h"
+
+MP4SinfAtom::MP4SinfAtom() 
+	: MP4Atom("sinf") 
+{
+	AddVersionAndFlags();
+	ExpectChildAtom("frma", Required, OnlyOne);
+	ExpectChildAtom("schm", Required, OnlyOne);
+	ExpectChildAtom("schi", Required, OnlyOne);
+}
--- a/common/mp4v2/atom_stsd.cpp
+++ b/common/mp4v2/atom_stsd.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
  */
 
 #include "mp4common.h"
@@ -32,8 +33,10 @@
 	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);
 }
 
--- a/common/mp4v2/atom_tag4.cpp
+++ /dev/null
@@ -1,41 +1,0 @@
-/*
- * 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     menno@audiocoding.com
- */
-
-#include "mp4common.h"
-
-MP4Tag4Atom::MP4Tag4Atom()
-    : MP4Atom("TAG4")
-{
-    AddVersionAndFlags();
-
-    MP4Integer32Property* pCount =
-        new MP4Integer32Property("entryCount");
-    AddProperty(pCount);
-
-    MP4TableProperty* pTable = new
-        MP4TableProperty("entries", pCount);
-    AddProperty(pTable);
-
-    pTable->AddProperty(
-        new MP4StringProperty("name"));
-    pTable->AddProperty(
-        new MP4StringProperty("value"));
-}
--- a/common/mp4v2/atom_udta.cpp
+++ b/common/mp4v2/atom_udta.cpp
@@ -26,6 +26,7 @@
 {
 	ExpectChildAtom("cprt", Optional, Many);
 	ExpectChildAtom("hnti", Optional, OnlyOne);
+	ExpectChildAtom("meta", Optional, OnlyOne);
 }
 
 void MP4UdtaAtom::Read() 
--- a/common/mp4v2/atoms.h
+++ b/common/mp4v2/atoms.h
@@ -443,9 +443,141 @@
 	void Write();
 };
 
-class MP4Tag4Atom : public MP4Atom {
+// ismacrypt
+class MP4EncaAtom : public MP4Atom {
 public:
-	MP4Tag4Atom();
+        MP4EncaAtom();
+        void Generate();
+};
+
+class MP4EncvAtom : public MP4Atom {
+public:
+        MP4EncvAtom();
+        void Generate();
+};
+
+class MP4FrmaAtom : public MP4Atom {
+public:
+        MP4FrmaAtom();
+};
+
+class MP4IKMSAtom : public MP4Atom {
+public:
+        MP4IKMSAtom();
+};
+
+class MP4ISFMAtom : public MP4Atom {
+public:
+        MP4ISFMAtom();
+};
+
+class MP4SchiAtom : public MP4Atom {
+public:
+        MP4SchiAtom();
+};
+
+class MP4SchmAtom : public MP4Atom {
+public:
+        MP4SchmAtom();
+};
+
+class MP4SinfAtom : public MP4Atom {
+public:
+        MP4SinfAtom();
+};
+
+/* iTunes META data atoms */
+class MP4MetaAtom : public MP4Atom {
+public:
+	MP4MetaAtom();
+};
+
+class MP4NameAtom : public MP4Atom {
+public:
+    MP4NameAtom();
+    void Read();
+};
+
+class MP4MeanAtom : public MP4Atom {
+public:
+    MP4MeanAtom();
+    void Read();
+};
+
+class MP4DataAtom : public MP4Atom {
+public:
+    MP4DataAtom();
+    void Read();
+};
+
+class MP4IlstAtom : public MP4Atom {
+public:
+	MP4IlstAtom();
+};
+
+class MP4DashAtom : public MP4Atom {
+public:
+    MP4DashAtom();
+};
+
+class MP4NamAtom : public MP4Atom {
+public:
+	MP4NamAtom();
+};
+
+class MP4ArtAtom : public MP4Atom {
+public:
+	MP4ArtAtom();
+};
+
+class MP4WrtAtom : public MP4Atom {
+public:
+	MP4WrtAtom();
+};
+
+class MP4AlbAtom : public MP4Atom {
+public:
+	MP4AlbAtom();
+};
+
+class MP4TrknAtom : public MP4Atom {
+public:
+	MP4TrknAtom();
+};
+
+class MP4DayAtom : public MP4Atom {
+public:
+	MP4DayAtom();
+};
+
+class MP4TooAtom : public MP4Atom {
+public:
+	MP4TooAtom();
+};
+
+class MP4GnreAtom : public MP4Atom {
+public:
+	MP4GnreAtom();
+};
+
+class MP4CpilAtom : public MP4Atom {
+public:
+	MP4CpilAtom();
+};
+
+class MP4TmpoAtom : public MP4Atom {
+public:
+	MP4TmpoAtom();
+};
+
+class MP4CmtAtom : public MP4Atom {
+public:
+	MP4CmtAtom();
+};
+
+class MP4DiskAtom : public MP4Atom {
+public:
+	MP4DiskAtom();
 };
 
 #endif /* __MP4_ATOMS_INCLUDED__ */
--- a/common/mp4v2/descriptors.cpp
+++ b/common/mp4v2/descriptors.cpp
@@ -367,6 +367,13 @@
 			// 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 = 
--- a/common/mp4v2/descriptors.h
+++ b/common/mp4v2/descriptors.h
@@ -92,7 +92,7 @@
 	MP4SLConfigDescriptor();
 	void Generate();
 	void Read(MP4File* pFile);
-protected:
+ protected:
 	void Mutate();
 };
 
--- a/common/mp4v2/isma.cpp
+++ b/common/mp4v2/isma.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie		  dmackie@cisco.com
+ *              Alix Marchandise-Franquet alix@cisco.com
  */
 
 #include "mp4common.h"
@@ -201,6 +202,8 @@
 	pEsProperty->SetTags(MP4ESDescrTag);
 
 	MP4IntegerProperty* pSetProperty;
+	MP4IntegerProperty* pSceneESID;
+	MP4IntegerProperty* pOdESID;
 
 	// OD
 	MP4Descriptor* pOdEsd =
@@ -208,9 +211,11 @@
 	pOdEsd->Generate();
 
 	pOdEsd->FindProperty("ESID", 
-		(MP4Property**)&pSetProperty);
-	pSetProperty->SetValue(m_odTrackId);
+		(MP4Property**)&pOdESID);
 
+	// we set the OD ESID to a non-zero unique value
+	pOdESID->SetValue(m_odTrackId);
+
 	pOdEsd->FindProperty("URLFlag", 
 		(MP4Property**)&pSetProperty);
 	pSetProperty->SetValue(1);
@@ -280,8 +285,9 @@
 	pSceneEsd->Generate();
 
 	pSceneEsd->FindProperty("ESID", 
-		(MP4Property**)&pSetProperty);
-	pSetProperty->SetValue(sceneTrackId);
+		(MP4Property**)&pSceneESID);
+	// we set the Scene ESID to a non-zero unique value
+	pSceneESID->SetValue(sceneTrackId);
 
 	pSceneEsd->FindProperty("URLFlag", 
 		(MP4Property**)&pSetProperty);
@@ -346,6 +352,8 @@
 	// 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;
 
@@ -477,7 +485,7 @@
     delete pVideoEsdProperty;
 
 	VERBOSE_ISMA(GetVerbosity(),
-		printf("OD data =\n"); MP4HexDump(pBytes, numBytes));
+		printf("OD data = %llu bytes\n", numBytes); MP4HexDump(pBytes, numBytes));
 
 	char* odCmdBase64 = MP4ToBase64(pBytes, numBytes);
 
@@ -672,32 +680,37 @@
 	u_int64_t* pNumBytes)
 {
 	MP4DescriptorProperty* pAudioEsd = NULL;
-	MP4Integer8Property* pAudioSLConfig = NULL;
+	MP4Integer8Property* pAudioSLConfigPredef = NULL;
 	MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL;
 	int oldAudioUnitEndFlagValue = 0;
 	MP4DescriptorProperty* pVideoEsd = NULL;
-	MP4Integer8Property* pVideoSLConfig = 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.mp4a.esds"));
+				"mdia.minf.stbl.stsd.*.esds"));
 		ASSERT(pEsdsAtom);
 
 		pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
+		// ESID is 0 for file, stream needs to be non-ze
+		pAudioEsd->FindProperty("ESID", 
+					(MP4Property**)&pAudioEsdId);
 
+		ASSERT(pAudioEsdId);
+		pAudioEsdId->SetValue(audioTrackId);
+
 		// SL config needs to change from 2 (file) to 1 (null)
 		pAudioEsd->FindProperty("slConfigDescr.predefined", 
-			(MP4Property**)&pAudioSLConfig);
-		ASSERT(pAudioSLConfig);
-#if 0
-		// changed 12/05/02 wmay
-		pAudioSLConfig->SetValue(1);
-#else
-		pAudioSLConfig->SetValue(0);
-#endif
+			(MP4Property**)&pAudioSLConfigPredef);
+		ASSERT(pAudioSLConfigPredef);
+		pAudioSLConfigPredef->SetValue(0);
+
 		pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag",
 					(MP4Property **)&pAudioAccessUnitEndFlag);
 		oldAudioUnitEndFlagValue = 
@@ -706,23 +719,25 @@
 	}
 
 	if (videoTrackId != MP4_INVALID_TRACK_ID) {
+	  // changed mp4v to * to handle encv case
 		MP4Atom* pEsdsAtom = 
 			FindAtom(MakeTrackName(videoTrackId, 
-				"mdia.minf.stbl.stsd.mp4v.esds"));
+				"mdia.minf.stbl.stsd.*.esds"));
 		ASSERT(pEsdsAtom);
 
 		pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
+		pVideoEsd->FindProperty("ESID", 
+					(MP4Property**)&pVideoEsdId);
 
+		ASSERT(pVideoEsdId);
+		pVideoEsdId->SetValue(videoTrackId);
+
 		// SL config needs to change from 2 (file) to 1 (null)
 		pVideoEsd->FindProperty("slConfigDescr.predefined", 
-			(MP4Property**)&pVideoSLConfig);
-		ASSERT(pVideoSLConfig);
-#if 0
-		pVideoSLConfig->SetValue(1);
-		// changed 12/05/02 wmay
-#else
-		pVideoSLConfig->SetValue(0);
-#endif
+			(MP4Property**)&pVideoSLConfigPredef);
+		ASSERT(pVideoSLConfigPredef);
+		pVideoSLConfigPredef->SetValue(0);
+
 		pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag",
 					(MP4Property **)&pVideoAccessUnitEndFlag);
 		oldVideoUnitEndFlagValue = 
@@ -732,16 +747,24 @@
 
 	CreateIsmaODUpdateCommandForStream(
 		pAudioEsd, pVideoEsd, ppBytes, pNumBytes);
-			
+	VERBOSE_ISMA(GetVerbosity(),
+		printf("After CreateImsaODUpdateCommandForStream len %llu =\n", *pNumBytes); MP4HexDump(*ppBytes, *pNumBytes));
 	// return SL config values to 2 (file)
-	if (pAudioSLConfig) {
-		pAudioSLConfig->SetValue(2);
+	// return ESID values to 0
+	if (pAudioSLConfigPredef) {
+		pAudioSLConfigPredef->SetValue(2);
 	}
+	if (pAudioEsdId) {
+	  pAudioEsdId->SetValue(0);
+	}
 	if (pAudioAccessUnitEndFlag) {
 	  pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue );
 	}
-	if (pVideoSLConfig) {
-		pVideoSLConfig->SetValue(2);
+	if (pVideoEsdId) {
+	  pVideoEsdId->SetValue(0);
+	}
+	if (pVideoSLConfigPredef) {
+		pVideoSLConfigPredef->SetValue(2);
 	}
 	if (pVideoAccessUnitEndFlag) {
 	  pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue );
--- a/common/mp4v2/libmp4v2_cb.dsp
+++ b/common/mp4v2/libmp4v2_cb.dsp
@@ -41,6 +41,7 @@
 # PROP Intermediate_Dir "CB_Release"
 # PROP Target_Dir ""
 MTL=midl.exe
+F90=df.exe
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
 # ADD CPP /nologo /MD /W3 /GX /O2 /I ".\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_FILE_CALLBACKS" /YX /FD /c
 # ADD BASE RSC /l 0x413 /d "NDEBUG"
@@ -65,6 +66,7 @@
 # PROP Intermediate_Dir "CB_Debug"
 # PROP Target_Dir ""
 MTL=midl.exe
+F90=df.exe
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
 # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_FILE_CALLBACKS" /YX /FD /GZ /c
 # ADD BASE RSC /l 0x413 /d "_DEBUG"
@@ -131,6 +133,14 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_enca.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_encv.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_esds.cpp
 # End Source File
 # Begin Source File
@@ -139,6 +149,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_frma.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_ftyp.cpp
 # End Source File
 # Begin Source File
@@ -159,10 +173,18 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_iKMS.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_iods.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_iSFM.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_maxr.cpp
 # End Source File
 # Begin Source File
@@ -179,6 +201,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_meta.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_mfhd.cpp
 # End Source File
 # Begin Source File
@@ -239,10 +265,22 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_schi.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_schm.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_sdp.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_sinf.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_smhd.cpp
 # End Source File
 # Begin Source File
@@ -287,10 +325,6 @@
 # End Source File
 # Begin Source File
 
-SOURCE=.\atom_tag4.cpp
-# End Source File
-# Begin Source File
-
 SOURCE=.\atom_tfhd.cpp
 # End Source File
 # Begin Source File
@@ -396,6 +430,10 @@
 # Begin Source File
 
 SOURCE=.\mp4info.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4meta.cpp
 # End Source File
 # Begin Source File
 
--- a/common/mp4v2/libmp4v2_st60.dsp
+++ b/common/mp4v2/libmp4v2_st60.dsp
@@ -131,6 +131,14 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_enca.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_encv.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_esds.cpp
 # End Source File
 # Begin Source File
@@ -139,6 +147,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_frma.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_ftyp.cpp
 # End Source File
 # Begin Source File
@@ -159,10 +171,18 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_iKMS.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_iods.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_iSFM.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_maxr.cpp
 # End Source File
 # Begin Source File
@@ -179,6 +199,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_meta.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_mfhd.cpp
 # End Source File
 # Begin Source File
@@ -239,10 +263,22 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_schi.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_schm.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_sdp.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\atom_sinf.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\atom_smhd.cpp
 # End Source File
 # Begin Source File
@@ -287,10 +323,6 @@
 # End Source File
 # Begin Source File
 
-SOURCE=.\atom_tag4.cpp
-# End Source File
-# Begin Source File
-
 SOURCE=.\atom_tfhd.cpp
 # End Source File
 # Begin Source File
@@ -392,6 +424,10 @@
 # Begin Source File
 
 SOURCE=.\mp4file_io.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4meta.cpp
 # End Source File
 # Begin Source File
 
--- a/common/mp4v2/mp4.cpp
+++ b/common/mp4v2/mp4.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
  */
 
 /* 
@@ -638,6 +639,24 @@
 	return MP4_INVALID_TRACK_ID;
 }
 
+extern "C" MP4TrackId MP4AddEncAudioTrack(MP4FileHandle hFile, 
+					  u_int32_t timeScale, 
+					  MP4Duration sampleDuration, 
+					  u_int8_t audioType)
+{
+  if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+    try {
+      return ((MP4File*)hFile)->
+	AddEncAudioTrack(timeScale, sampleDuration, audioType);
+    }
+    catch (MP4Error* e) {
+      PRINT_ERROR(e);
+      delete e;
+    }
+  }
+  return MP4_INVALID_TRACK_ID;
+}
+
 extern "C" MP4TrackId MP4AddVideoTrack(
 	MP4FileHandle hFile, 
 	u_int32_t timeScale, 
@@ -659,6 +678,26 @@
 	return MP4_INVALID_TRACK_ID;
 }
 
+extern "C" MP4TrackId MP4AddEncVideoTrack(MP4FileHandle hFile, 
+					  u_int32_t timeScale, 
+					  MP4Duration sampleDuration,
+					  u_int16_t width, 
+					  u_int16_t height, 
+					  u_int8_t videoType)
+{
+  if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+    try {
+      return ((MP4File*)hFile)->AddEncVideoTrack(timeScale, sampleDuration, 
+						 width, height, videoType);
+    }
+    catch (MP4Error* e) {
+      PRINT_ERROR(e);
+      delete e;
+    }
+  }
+  return MP4_INVALID_TRACK_ID;
+}
+
 extern "C" MP4TrackId MP4AddHintTrack(
 	MP4FileHandle hFile, MP4TrackId refTrackId)
 {
@@ -693,6 +732,8 @@
 	}
 
 	if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) {
+                MP4SetVideoProfileLevel(dstFile, 
+                                        MP4GetVideoProfileLevel(srcFile));
 		dstTrackId = MP4AddVideoTrack(
 			dstFile,
 			MP4GetTrackTimeScale(srcFile, srcTrackId),
@@ -699,14 +740,16 @@
 			MP4GetTrackFixedSampleDuration(srcFile, srcTrackId),
 			MP4GetTrackVideoWidth(srcFile, srcTrackId),
 			MP4GetTrackVideoHeight(srcFile, srcTrackId),
-			MP4GetTrackVideoType(srcFile, srcTrackId));
+			MP4GetTrackEsdsObjectTypeId(srcFile, srcTrackId));
 
 	} else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) {
+                MP4SetAudioProfileLevel(dstFile, 
+                                        MP4GetAudioProfileLevel(srcFile));
 		dstTrackId = MP4AddAudioTrack(
 			dstFile,
 			MP4GetTrackTimeScale(srcFile, srcTrackId),
 			MP4GetTrackFixedSampleDuration(srcFile, srcTrackId),
-			MP4GetTrackAudioType(srcFile, srcTrackId));
+			MP4GetTrackEsdsObjectTypeId(srcFile, srcTrackId));
 
 	} else if (MP4_IS_OD_TRACK_TYPE(trackType)) {
 		dstTrackId = MP4AddODTrack(dstFile);
@@ -735,6 +778,8 @@
 		dstTrackId,
 		MP4GetTrackTimeScale(srcFile, srcTrackId));
 
+	if (MP4_IS_AUDIO_TRACK_TYPE(trackType) 
+	    || MP4_IS_VIDEO_TRACK_TYPE(trackType)) {
 	// copy track ES configuration
 	u_int8_t* pConfig = NULL;
 	u_int32_t configSize = 0;
@@ -752,6 +797,7 @@
 		configSize);
 
 		free(pConfig);
+	}
 
 	if (MP4_IS_HINT_TRACK_TYPE(trackType)) {
 		// probably not exactly what is wanted
@@ -787,91 +833,259 @@
 	return dstTrackId;
 }
 
-extern "C" MP4TrackId MP4CopyTrack(
-	MP4FileHandle srcFile, 
-	MP4TrackId srcTrackId,
-	MP4FileHandle dstFile, 
-	bool applyEdits)
+// Given a track, make an encrypted clone of it in the dest. file
+extern "C" MP4TrackId MP4EncAndCloneTrack(MP4FileHandle srcFile, 
+					  MP4TrackId srcTrackId,
+					  MP4FileHandle dstFile)
 {
-	bool copySamples = true;	// LATER allow false => reference samples
+  MP4TrackId dstTrackId = MP4_INVALID_TRACK_ID;
 
-	MP4TrackId dstTrackId =
-		MP4CloneTrack(srcFile, srcTrackId, dstFile);
+  if (dstFile == NULL) {
+    dstFile = srcFile;
+  }
 
-	if (dstTrackId == MP4_INVALID_TRACK_ID) {
-		return dstTrackId;
-	}
+  const char* trackType = 
+    MP4GetTrackType(srcFile, srcTrackId);
 
-	bool viaEdits =
-		applyEdits && MP4GetTrackNumberOfEdits(srcFile, srcTrackId);
+  if (!trackType) {
+    return dstTrackId;
+  }
 
-	MP4SampleId sampleId = 0;
-	MP4SampleId numSamples = 
-		MP4GetTrackNumberOfSamples(srcFile, srcTrackId);
+  if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) {
+    MP4SetVideoProfileLevel(dstFile, MP4GetVideoProfileLevel(srcFile));
+    dstTrackId = MP4AddEncVideoTrack(dstFile,
+				     MP4GetTrackTimeScale(srcFile, srcTrackId),
+				     MP4GetTrackFixedSampleDuration(srcFile, 
+								    srcTrackId),
+				     MP4GetTrackVideoWidth(srcFile, srcTrackId),
+				     MP4GetTrackVideoHeight(srcFile, srcTrackId),
+				     MP4GetTrackEsdsObjectTypeId(srcFile, 
+								 srcTrackId));
 
-	MP4Timestamp when = 0;
-	MP4Duration editsDuration = 
-		MP4GetTrackEditTotalDuration(srcFile, srcTrackId);
+  } else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) {
+    MP4SetAudioProfileLevel(dstFile, MP4GetAudioProfileLevel(srcFile));
+    dstTrackId = MP4AddEncAudioTrack(dstFile,
+				     MP4GetTrackTimeScale(srcFile, srcTrackId),
+				     MP4GetTrackFixedSampleDuration(srcFile, 
+								    srcTrackId),
+				     MP4GetTrackEsdsObjectTypeId(srcFile, 
+								 srcTrackId));
 
-	while (true) {
-		MP4Duration sampleDuration = MP4_INVALID_DURATION;
+  } else if (MP4_IS_OD_TRACK_TYPE(trackType)) {
+    dstTrackId = MP4AddODTrack(dstFile);
 
-		if (viaEdits) {
-			sampleId = MP4GetSampleIdFromEditTime(
-				srcFile,
-				srcTrackId,
-				when,
-				NULL,
-				&sampleDuration);
+  } else if (MP4_IS_SCENE_TRACK_TYPE(trackType)) {
+    dstTrackId = MP4AddSceneTrack(dstFile);
+    
+  } else if (MP4_IS_HINT_TRACK_TYPE(trackType)) {
+    dstTrackId = MP4AddHintTrack(dstFile,
+				 MP4GetHintTrackReferenceTrackId(srcFile, 
+								 srcTrackId));
 
-			// in theory, this shouldn't happen
-			if (sampleId == MP4_INVALID_SAMPLE_ID) {
-				MP4DeleteTrack(dstFile, dstTrackId);
-				return MP4_INVALID_TRACK_ID;
-			}
+  } else if (MP4_IS_SYSTEMS_TRACK_TYPE(trackType)) {
+    dstTrackId = MP4AddSystemsTrack(dstFile, trackType);
+    
+  } else {
+    dstTrackId = MP4AddTrack(dstFile, trackType);
+  }
 
-			when += sampleDuration;
+  if (dstTrackId == MP4_INVALID_TRACK_ID) {
+    return dstTrackId;
+  }
 
-			if (when >= editsDuration) {
-				break;
-			}
-		} else {
-			sampleId++;
-			if (sampleId > numSamples) {
-				break;
-			}
-		}
+  MP4SetTrackTimeScale(dstFile, 
+		       dstTrackId,
+		       MP4GetTrackTimeScale(srcFile, srcTrackId));
 
-		bool rc = false;
+  if (MP4_IS_AUDIO_TRACK_TYPE(trackType) 
+   || MP4_IS_VIDEO_TRACK_TYPE(trackType)) {
+    // copy track ES configuration
+    u_int8_t* pConfig = NULL;
+    u_int32_t configSize = 0;
+    if (MP4GetTrackESConfiguration(srcFile, srcTrackId,
+				   &pConfig, &configSize)) {
+    
+      if (pConfig != NULL) {
+	MP4SetTrackESConfiguration(dstFile, dstTrackId,
+				   pConfig, configSize);
+      }
+    }
+    if (pConfig != NULL)
+      free(pConfig);
+    }
 
-		if (copySamples) {
-			rc = MP4CopySample(
-				srcFile,
-				srcTrackId,
-				sampleId,
-				dstFile,
-				dstTrackId,
-				sampleDuration);
+  return dstTrackId;
+}
 
-		} else {
-			rc = MP4ReferenceSample(
-				srcFile,
-				srcTrackId,
-				sampleId,
-				dstFile,
-				dstTrackId,
-				sampleDuration);
-		}
+extern "C" MP4TrackId MP4CopyTrack(MP4FileHandle srcFile, 
+				   MP4TrackId srcTrackId,
+				   MP4FileHandle dstFile, 
+				   bool applyEdits)
+{
+  bool copySamples = true;	// LATER allow false => reference samples
 
-		if (!rc) {
-			MP4DeleteTrack(dstFile, dstTrackId);
-			return MP4_INVALID_TRACK_ID;
-		}
-	}
+  MP4TrackId dstTrackId =
+    MP4CloneTrack(srcFile, srcTrackId, dstFile);
 
-	return dstTrackId;
+  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
+extern "C" MP4TrackId MP4EncAndCopyTrack(MP4FileHandle srcFile, 
+				      MP4TrackId srcTrackId,
+				      MP4FileHandle dstFile, 
+				      bool applyEdits)
+{
+  bool copySamples = true;	// LATER allow false => reference samples
+
+  MP4TrackId dstTrackId =
+    MP4EncAndCloneTrack(srcFile, srcTrackId, dstFile);
+
+  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) {
+      // will need to encrypt the sample here
+      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;
+}
+
 extern "C" bool MP4DeleteTrack(
 	MP4FileHandle hFile, 
 	MP4TrackId trackId)
@@ -1002,12 +1216,16 @@
 	return false;
 }
 
+
+// This function should not be used anymore  
+// use MP4GetTrackEsdsObjectTypeId instead 
 extern "C" u_int8_t MP4GetTrackAudioType(
-	MP4FileHandle hFile, MP4TrackId trackId)
+     MP4FileHandle hFile, MP4TrackId trackId)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->GetTrackAudioType(trackId);
+		  
+		  return ((MP4File*)hFile)->GetTrackAudioType(trackId);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -1033,6 +1251,8 @@
 }
 
 
+// This function should not be used anymore  
+// use MP4GetTrackEsdsObjectTypeId instead 
 extern "C" u_int8_t MP4GetTrackVideoType(
 	MP4FileHandle hFile, MP4TrackId trackId)
 {
@@ -1048,6 +1268,24 @@
 	return MP4_INVALID_VIDEO_TYPE;
 }
 
+// Replacement to MP4GetTrackVideoType and MP4GetTrackAudioType
+// Basically does the same thing but with a more self-explanatory name
+extern "C" u_int8_t MP4GetTrackEsdsObjectTypeId(
+     MP4FileHandle hFile, MP4TrackId trackId)
+{
+  if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+    try {
+      
+      return ((MP4File*)hFile)->GetTrackEsdsObjectTypeId(trackId);
+    }
+    catch (MP4Error* e) {
+      PRINT_ERROR(e);
+      delete e;
+    }
+  }
+  return MP4_INVALID_AUDIO_TYPE;
+}
+
 extern "C" MP4Duration MP4GetTrackFixedSampleDuration(
 	MP4FileHandle hFile, MP4TrackId trackId)
 {
@@ -1079,7 +1317,7 @@
 	return 0;
 }
 
-extern "C" void MP4GetTrackESConfiguration(
+extern "C" bool MP4GetTrackESConfiguration(
 	MP4FileHandle hFile, MP4TrackId trackId, 
 	u_int8_t** ppConfig, u_int32_t* pConfigSize)
 {
@@ -1087,7 +1325,7 @@
 		try {
 			((MP4File*)hFile)->GetTrackESConfiguration(
 				trackId, ppConfig, pConfigSize);
-			return;
+			return true;
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -1096,7 +1334,7 @@
 	}
 	*ppConfig = NULL;
 	*pConfigSize = 0;
-	return;
+	return false;
 }
 
 extern "C" bool MP4SetTrackESConfiguration(
@@ -1137,8 +1375,8 @@
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId,
-				"mdia.minf.stbl.stsd.mp4v.width");
+		       return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId,
+				"mdia.minf.stbl.stsd.*.width");
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -1154,7 +1392,7 @@
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
 			return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId,
-				"mdia.minf.stbl.stsd.mp4v.height");
+				"mdia.minf.stbl.stsd.*.height");
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -1400,7 +1638,7 @@
 extern "C" bool MP4WriteSample(
 	MP4FileHandle hFile,
 	MP4TrackId trackId,
-	u_int8_t* pBytes, 
+	const u_int8_t* pBytes, 
 	u_int32_t numBytes,
 	MP4Duration duration,
 	MP4Duration renderingOffset, 
@@ -1765,12 +2003,15 @@
 	const char* pPayloadName,
 	u_int8_t* pPayloadNumber,
 	u_int16_t maxPayloadSize,
-	const char *encode_params)
+	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);
+				hintTrackId, pPayloadName, pPayloadNumber, maxPayloadSize, encode_params,
+				include_rtp_map, include_mpeg4_esid);
 			return true;
 		}
 		catch (MP4Error* e) {
@@ -2517,13 +2758,16 @@
 	return NULL;
 }
 
-/* tagging functions */
 
-extern "C" bool MP4TagDelete(MP4FileHandle hFile, MP4TrackId trackId)
+/* iTunes meta data handling */
+extern "C" bool MP4GetMetadataByIndex(MP4FileHandle hFile, u_int32_t index,
+                                       const char** ppName,
+                                       u_int8_t** ppValue, u_int32_t* pValueSize)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->TagDelete(trackId);
+			return ((MP4File*)hFile)->GetMetadataByIndex(
+                index, ppName, ppValue, pValueSize);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -2530,14 +2774,14 @@
 			delete e;
 		}
 	}
+    return false;
 }
 
-extern "C" bool MP4TagAddEntry(MP4FileHandle hFile, MP4TrackId trackId,
-                               const char *name, const char *value)
+extern "C" bool MP4MetadataDelete(MP4FileHandle hFile)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->TagAddEntry(trackId, name, value);
+			return ((MP4File*)hFile)->MetadataDelete();
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -2544,16 +2788,15 @@
 			delete e;
 		}
 	}
+    return false;
 }
 
-#if 0
-extern "C" void MP4TagDeleteEntry(MP4FileHandle hFile, MP4TrackId trackId,
-                                  u_int32_t index)
+extern "C" bool MP4SetMetadataName(MP4FileHandle hFile,
+                                  const char* value)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			((MP4File*)hFile)->TagDeleteEntry(trackId, index);
-            return;
+			return ((MP4File*)hFile)->SetMetadataName(value);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -2560,32 +2803,30 @@
 			delete e;
 		}
 	}
+    return false;
 }
-#endif
 
-extern "C" u_int32_t MP4TagGetNumEntries(MP4FileHandle hFile, MP4TrackId trackId)
+extern "C" bool MP4GetMetadataName(MP4FileHandle hFile,
+                                   char** value)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->TagGetNumEntries(trackId);
+			return ((MP4File*)hFile)->GetMetadataName(value);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
 			delete e;
-            return 0;
 		}
 	}
+    return false;
 }
 
-extern "C" void MP4TagGetEntry(MP4FileHandle hFile, MP4TrackId trackId,
-                               u_int32_t index, const char **name,
-                               const char **value)
+extern "C" bool MP4SetMetadataWriter(MP4FileHandle hFile,
+                                     const char* value)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			((MP4File*)hFile)->TagGetEntry(trackId, index,
-                name, value);
-            return;
+			return ((MP4File*)hFile)->SetMetadataWriter(value);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -2592,14 +2833,15 @@
 			delete e;
 		}
 	}
+    return false;
 }
 
-extern "C" bool MP4TagGetEntryByName(MP4FileHandle hFile, MP4TrackId trackId,
-                                     char *name, const char **value)
+extern "C" bool MP4GetMetadataWriter(MP4FileHandle hFile,
+                                   char** value)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->TagGetEntryByName(trackId, name, value);
+			return ((MP4File*)hFile)->GetMetadataWriter(value);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -2606,4 +2848,359 @@
 			delete e;
 		}
 	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataAlbum(MP4FileHandle hFile,
+                                    const char* value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataAlbum(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataAlbum(MP4FileHandle hFile,
+                                    char** value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataAlbum(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataArtist(MP4FileHandle hFile,
+                                     const char* value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataArtist(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataArtist(MP4FileHandle hFile,
+                                     char** value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataArtist(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataTool(MP4FileHandle hFile,
+                                   const char* value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataTool(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataTool(MP4FileHandle hFile,
+                                   char** value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataTool(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataComment(MP4FileHandle hFile,
+                                      const char* value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataComment(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataComment(MP4FileHandle hFile,
+                                      char** value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataComment(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataYear(MP4FileHandle hFile,
+                                   const char* value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataYear(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataYear(MP4FileHandle hFile,
+                                   char** value)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataYear(value);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataTrack(MP4FileHandle hFile,
+                                    u_int16_t track, u_int16_t totalTracks)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataTrack(track, totalTracks);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataTrack(MP4FileHandle hFile,
+                                    u_int16_t* track, u_int16_t* totalTracks)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataTrack(track, totalTracks);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataDisk(MP4FileHandle hFile,
+                                   u_int16_t disk, u_int16_t totalDisks)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataDisk(disk, totalDisks);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataDisk(MP4FileHandle hFile,
+                                   u_int16_t* disk, u_int16_t* totalDisks)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataDisk(disk, totalDisks);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataGenre(MP4FileHandle hFile, u_int16_t genre)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataGenre(genre);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataGenre(MP4FileHandle hFile, u_int16_t* genre)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataGenre(genre);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataTempo(MP4FileHandle hFile, u_int16_t tempo)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataTempo(tempo);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataTempo(MP4FileHandle hFile, u_int16_t* tempo)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataTempo(tempo);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataCompilation(MP4FileHandle hFile, u_int8_t cpl)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataCompilation(cpl);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataCompilation(MP4FileHandle hFile, u_int8_t* cpl)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataCompilation(cpl);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataCoverArt(MP4FileHandle hFile,
+                                       u_int8_t *coverArt, u_int32_t size)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataCoverArt(coverArt, size);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataCoverArt(MP4FileHandle hFile,
+                                       u_int8_t **coverArt, u_int32_t* size)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataCoverArt(coverArt, size);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4SetMetadataFreeForm(MP4FileHandle hFile, char *name,
+                                       u_int8_t* pValue, u_int32_t valueSize)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->SetMetadataFreeForm(name, pValue, valueSize);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
+}
+
+extern "C" bool MP4GetMetadataFreeForm(MP4FileHandle hFile, char *name,
+                                       u_int8_t** pValue, u_int32_t* valueSize)
+{
+	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+		try {
+			return ((MP4File*)hFile)->GetMetadataFreeForm(name, pValue, valueSize);
+		}
+		catch (MP4Error* e) {
+			PRINT_ERROR(e);
+			delete e;
+		}
+	}
+    return false;
 }
--- a/common/mp4v2/mp4.h
+++ b/common/mp4v2/mp4.h
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
  */
 
 #ifndef __MP4_INCLUDED__
@@ -167,7 +168,8 @@
 #define MP4_IS_MPEG4_AAC_AUDIO_TYPE(mpeg4Type) \
 	(((mpeg4Type) >= MP4_MPEG4_AAC_MAIN_AUDIO_TYPE \
 		&& (mpeg4Type) <= MP4_MPEG4_AAC_LTP_AUDIO_TYPE) \
-	  || (mpeg4Type) == MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE)
+	  || (mpeg4Type) == MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE \
+          || (mpeg4Type) == 17)
 
 #define MP4_IS_AAC_AUDIO_TYPE(type) \
 	(MP4_IS_MPEG2_AAC_AUDIO_TYPE(type) \
@@ -206,15 +208,6 @@
 
 /* MP4 API declarations */
 
-typedef u_int32_t (*MP4OpenCallback)(const char *pName, const char *mode, void *userData);
-typedef void (*MP4CloseCallback)(void *userData);
-typedef u_int32_t (*MP4ReadCallback)(void *pBuffer, unsigned int nBytesToRead, void *userData);
-typedef u_int32_t (*MP4WriteCallback)(void *pBuffer, unsigned int nBytesToWrite, void *userData);
-typedef int32_t (*MP4SetposCallback)(u_int32_t pos, void *userData);
-typedef int64_t (*MP4GetposCallback)(void *userData);
-typedef int64_t (*MP4FilesizeCallback)(void *userData);
-
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -236,23 +229,6 @@
 	const char* fileName, 
 	u_int32_t verbosity DEFAULT(0));
 
-MP4FileHandle MP4ReadCb(u_int32_t verbosity,
-                        MP4OpenCallback MP4fopen,
-                        MP4CloseCallback MP4fclose,
-                        MP4ReadCallback MP4fread,
-                        MP4WriteCallback MP4fwrite,
-                        MP4SetposCallback MP4fsetpos,
-                        MP4GetposCallback MP4fgetpos,
-                        MP4FilesizeCallback MP4filesize,
-                        void *userData);
-
-MP4FileHandle MP4ModifyCb(int32_t verbosity,
-    bool useExtensibleFormat,
-    MP4OpenCallback MP4fopen, MP4CloseCallback MP4fclose,
-    MP4ReadCallback MP4fread, MP4WriteCallback MP4fwrite,
-    MP4SetposCallback MP4fsetpos, MP4GetposCallback MP4fgetpos,
-    MP4FilesizeCallback MP4filesize, void *userData);
-
 bool MP4Close(
 	MP4FileHandle hFile);
 
@@ -367,6 +343,12 @@
 	MP4Duration sampleDuration,
 	u_int8_t audioType DEFAULT(MP4_MPEG4_AUDIO_TYPE));
 
+MP4TrackId MP4AddEncAudioTrack(
+	MP4FileHandle hFile, 
+	u_int32_t timeScale, 
+	MP4Duration sampleDuration,
+	u_int8_t audioType DEFAULT(MP4_MPEG4_AUDIO_TYPE));
+
 MP4TrackId MP4AddVideoTrack(
 	MP4FileHandle hFile, 
 	u_int32_t timeScale, 
@@ -375,6 +357,14 @@
 	u_int16_t height,
 	u_int8_t videoType DEFAULT(MP4_MPEG4_VIDEO_TYPE));
 
+MP4TrackId MP4AddEncVideoTrack(
+	MP4FileHandle hFile, 
+	u_int32_t timeScale, 
+	MP4Duration sampleDuration,
+	u_int16_t width, 
+	u_int16_t height,
+	u_int8_t videoType DEFAULT(MP4_MPEG4_VIDEO_TYPE));
+
 MP4TrackId MP4AddHintTrack(
 	MP4FileHandle hFile, 
 	MP4TrackId refTrackId);
@@ -384,6 +374,11 @@
 	MP4TrackId srcTrackId,
 	MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE));
 
+MP4TrackId MP4EncAndCloneTrack(
+	MP4FileHandle srcFile, 
+	MP4TrackId srcTrackId,
+	MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE));
+
 MP4TrackId MP4CopyTrack(
 	MP4FileHandle srcFile, 
 	MP4TrackId srcTrackId,
@@ -390,6 +385,12 @@
 	MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), 
 	bool applyEdits DEFAULT(false));
 
+MP4TrackId MP4EncAndCopyTrack(
+	MP4FileHandle srcFile, 
+	MP4TrackId srcTrackId,
+	MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE), 
+	bool applyEdits DEFAULT(false));
+
 bool MP4DeleteTrack(
 	MP4FileHandle hFile, 
 	MP4TrackId trackId);
@@ -430,6 +431,7 @@
 	MP4TrackId trackId, 
 	u_int32_t value);
 
+// Should not be used, replace with MP4GetTrackEsdsObjectTypeId
 u_int8_t MP4GetTrackAudioType(
 	MP4FileHandle hFile, 
 	MP4TrackId trackId);
@@ -438,10 +440,15 @@
 	MP4FileHandle hFile, 
 	MP4TrackId trackId);
 
+// Should not be used, replace with MP4GetTrackEsdsObjectTypeId
 u_int8_t MP4GetTrackVideoType(
 	MP4FileHandle hFile, 
 	MP4TrackId trackId);
 
+u_int8_t MP4GetTrackEsdsObjectTypeId(
+	MP4FileHandle hFile, 
+	MP4TrackId trackId);
+
 /* returns MP4_INVALID_DURATION if track samples do not have a fixed duration */
 MP4Duration MP4GetTrackFixedSampleDuration(
 	MP4FileHandle hFile, 
@@ -451,7 +458,7 @@
 	MP4FileHandle hFile, 
 	MP4TrackId trackId);
 
-void MP4GetTrackESConfiguration(
+bool MP4GetTrackESConfiguration(
 	MP4FileHandle hFile, 
 	MP4TrackId trackId, 
 	u_int8_t** ppConfig, 
@@ -562,7 +569,7 @@
 bool MP4WriteSample(
 	MP4FileHandle hFile,
 	MP4TrackId trackId,
-	u_int8_t* pBytes, 
+	const u_int8_t* pBytes, 
 	u_int32_t numBytes,
 	MP4Duration duration DEFAULT(MP4_INVALID_DURATION),
 	MP4Duration renderingOffset DEFAULT(0), 
@@ -644,7 +651,9 @@
 	const char* pPayloadName,
 	u_int8_t* pPayloadNumber,
 	u_int16_t maxPayloadSize DEFAULT(0),
-	const char *encode_params DEFAULT(NULL));
+	const char *encode_params DEFAULT(NULL),
+	bool include_rtp_map DEFAULT(true),
+	bool include_mpeg4_esid DEFAULT(true));
 
 const char* MP4GetSessionSdp(
 	MP4FileHandle hFile);
@@ -907,18 +916,73 @@
 	const u_int8_t* pData, 
 	u_int32_t dataSize);
 
-bool MP4TagDelete(MP4FileHandle hFile, MP4TrackId trackId);
-bool MP4TagAddEntry(MP4FileHandle hFile, MP4TrackId trackId,
-                    const char *name, const char *value);
-#if 0
-void MP4TagDeleteEntry(MP4FileHandle hFile, MP4TrackId trackId,
-                       u_int32_t index);
-#endif
-u_int32_t MP4TagGetNumEntries(MP4FileHandle hFile, MP4TrackId trackId);
-void MP4TagGetEntry(MP4FileHandle hFile, MP4TrackId trackId,
-                    u_int32_t index, const char **name, const char **value);
-bool MP4TagGetEntryByName(MP4FileHandle hFile, MP4TrackId trackId,
-                          char *name, const char **value);
+/* iTunes metadata handling */
+bool MP4MetadataDelete(MP4FileHandle hFile);
+bool MP4GetMetadataByIndex(MP4FileHandle hFile, u_int32_t index,
+                           const char** ppName,
+                           u_int8_t** ppValue, u_int32_t* pValueSize);
+bool MP4SetMetadataName(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataName(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataArtist(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataArtist(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataWriter(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataWriter(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataComment(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataComment(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataTool(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataTool(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataYear(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataYear(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataAlbum(MP4FileHandle hFile, const char* value);
+bool MP4GetMetadataAlbum(MP4FileHandle hFile, char** value);
+bool MP4SetMetadataTrack(MP4FileHandle hFile,
+                         u_int16_t track, u_int16_t totalTracks);
+bool MP4GetMetadataTrack(MP4FileHandle hFile,
+                         u_int16_t* track, u_int16_t* totalTracks);
+bool MP4SetMetadataDisk(MP4FileHandle hFile,
+                        u_int16_t disk, u_int16_t totalDisks);
+bool MP4GetMetadataDisk(MP4FileHandle hFile,
+                        u_int16_t* disk, u_int16_t* totalDisks);
+bool MP4SetMetadataGenre(MP4FileHandle hFile, u_int16_t genre);
+bool MP4GetMetadataGenre(MP4FileHandle hFile, u_int16_t* genre);
+bool MP4SetMetadataTempo(MP4FileHandle hFile, u_int16_t tempo);
+bool MP4GetMetadataTempo(MP4FileHandle hFile, u_int16_t* tempo);
+bool MP4SetMetadataCompilation(MP4FileHandle hFile, u_int8_t cpl);
+bool MP4GetMetadataCompilation(MP4FileHandle hFile, u_int8_t* cpl);
+bool MP4SetMetadataCoverArt(MP4FileHandle hFile,
+                            u_int8_t *coverArt, u_int32_t size);
+bool MP4GetMetadataCoverArt(MP4FileHandle hFile,
+                            u_int8_t **coverArt, u_int32_t* size);
+bool MP4SetMetadataFreeForm(MP4FileHandle hFile, char *name,
+                            u_int8_t* pValue, u_int32_t valueSize);
+bool MP4GetMetadataFreeForm(MP4FileHandle hFile, char *name,
+                            u_int8_t** pValue, u_int32_t* valueSize);
+
+//#ifdef USE_FILE_CALLBACKS
+typedef u_int32_t (*MP4OpenCallback)(const char *pName, const char *mode, void *userData);
+typedef void (*MP4CloseCallback)(void *userData);
+typedef u_int32_t (*MP4ReadCallback)(void *pBuffer, unsigned int nBytesToRead, void *userData);
+typedef u_int32_t (*MP4WriteCallback)(void *pBuffer, unsigned int nBytesToWrite, void *userData);
+typedef int32_t (*MP4SetposCallback)(u_int32_t pos, void *userData);
+typedef int64_t (*MP4GetposCallback)(void *userData);
+typedef int64_t (*MP4FilesizeCallback)(void *userData);
+
+MP4FileHandle MP4ReadCb(u_int32_t verbosity,
+                        MP4OpenCallback MP4fopen,
+                        MP4CloseCallback MP4fclose,
+                        MP4ReadCallback MP4fread,
+                        MP4WriteCallback MP4fwrite,
+                        MP4SetposCallback MP4fsetpos,
+                        MP4GetposCallback MP4fgetpos,
+                        MP4FilesizeCallback MP4filesize,
+                        void *userData);
+MP4FileHandle MP4ModifyCb(int32_t verbosity,
+                          bool useExtensibleFormat,
+                          MP4OpenCallback MP4fopen, MP4CloseCallback MP4fclose,
+                          MP4ReadCallback MP4fread, MP4WriteCallback MP4fwrite,
+                          MP4SetposCallback MP4fsetpos, MP4GetposCallback MP4fgetpos,
+                          MP4FilesizeCallback MP4filesize, void *userData);
+//#endif
 
 #ifdef __cplusplus
 }
--- a/common/mp4v2/mp4atom.cpp
+++ b/common/mp4v2/mp4atom.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
  */
 
 #include "mp4common.h"
@@ -59,184 +60,269 @@
 
 MP4Atom* MP4Atom::CreateAtom(const char* type)
 {
-	MP4Atom* pAtom = NULL;
+  MP4Atom* pAtom = NULL;
 
-	if (type == NULL) {
-		pAtom = new MP4RootAtom();
-	} else if (type[0] == 'c') {
-		if (ATOMID(type) == ATOMID("ctts")) {
-			pAtom = new MP4CttsAtom();
-		} else if (ATOMID(type) == ATOMID("co64")) {
-			pAtom = new MP4Co64Atom();
-		} else if (ATOMID(type) == ATOMID("cprt")) {
-			pAtom = new MP4CprtAtom();
-		}
-	} else if (type[0] == 'd') {
-		if (ATOMID(type) == ATOMID("dinf")) {
-			pAtom = new MP4DinfAtom();
-		} else if (ATOMID(type) == ATOMID("dref")) {
-			pAtom = new MP4DrefAtom();
-		} else if (ATOMID(type) == ATOMID("dpnd")) {
-			pAtom = new MP4TrefTypeAtom(type);
-		} else if (ATOMID(type) == ATOMID("dmed")) {
-			pAtom = new MP4DmedAtom();
-		} else if (ATOMID(type) == ATOMID("dimm")) {
-			pAtom = new MP4DimmAtom();
-		} else if (ATOMID(type) == ATOMID("drep")) {
-			pAtom = new MP4DrepAtom();
-		} else if (ATOMID(type) == ATOMID("dmax")) {
-			pAtom = new MP4DmaxAtom();
-		}
-	} else if (type[0] == 'e') {
-		if (ATOMID(type) == ATOMID("esds")) {
-			pAtom = new MP4EsdsAtom();
-		} else if (ATOMID(type) == ATOMID("edts")) {
-			pAtom = new MP4EdtsAtom();
-		} else if (ATOMID(type) == ATOMID("elst")) {
-			pAtom = new MP4ElstAtom();
-		}
-	} else if (type[0] == 'h') {
-		if (ATOMID(type) == ATOMID("hdlr")) {
-			pAtom = new MP4HdlrAtom();
-		} else if (ATOMID(type) == ATOMID("hmhd")) {
-			pAtom = new MP4HmhdAtom();
-		} else if (ATOMID(type) == ATOMID("hint")) {
-			pAtom = new MP4TrefTypeAtom(type);
-		} else if (ATOMID(type) == ATOMID("hnti")) {
-			pAtom = new MP4HntiAtom();
-		} else if (ATOMID(type) == ATOMID("hinf")) {
-			pAtom = new MP4HinfAtom();
-		}
-	} else if (type[0] == 'm') {
-		if (ATOMID(type) == ATOMID("mdia")) {
-			pAtom = new MP4MdiaAtom();
-		} else if (ATOMID(type) == ATOMID("minf")) {
-			pAtom = new MP4MinfAtom();
-		} else if (ATOMID(type) == ATOMID("mdhd")) {
-			pAtom = new MP4MdhdAtom();
-		} else if (ATOMID(type) == ATOMID("mdat")) {
-			pAtom = new MP4MdatAtom();
-		} else if (ATOMID(type) == ATOMID("moov")) {
-			pAtom = new MP4MoovAtom();
-		} else if (ATOMID(type) == ATOMID("mvhd")) {
-			pAtom = new MP4MvhdAtom();
-		} else if (ATOMID(type) == ATOMID("mpod")) {
-			pAtom = new MP4TrefTypeAtom(type);
-		} else if (ATOMID(type) == ATOMID("mp4a")) {
-			pAtom = new MP4Mp4aAtom();
-		} else if (ATOMID(type) == ATOMID("mp4s")) {
-			pAtom = new MP4Mp4sAtom();
-		} else if (ATOMID(type) == ATOMID("mp4v")) {
-			pAtom = new MP4Mp4vAtom();
-		} else if (ATOMID(type) == ATOMID("moof")) {
-			pAtom = new MP4MoofAtom();
-		} else if (ATOMID(type) == ATOMID("mfhd")) {
-			pAtom = new MP4MfhdAtom();
-		} else if (ATOMID(type) == ATOMID("mvex")) {
-			pAtom = new MP4MvexAtom();
-		} else if (ATOMID(type) == ATOMID("maxr")) {
-			pAtom = new MP4MaxrAtom();
-		}
-	} else if (type[0] == 's') {
-		if (ATOMID(type) == ATOMID("stbl")) {
-			pAtom = new MP4StblAtom();
-		} else if (ATOMID(type) == ATOMID("stsd")) {
-			pAtom = new MP4StsdAtom();
-		} else if (ATOMID(type) == ATOMID("stts")) {
-			pAtom = new MP4SttsAtom();
-		} else if (ATOMID(type) == ATOMID("stsz")) {
-			pAtom = new MP4StszAtom();
-		} else if (ATOMID(type) == ATOMID("stsc")) {
-			pAtom = new MP4StscAtom();
-		} else if (ATOMID(type) == ATOMID("stco")) {
-			pAtom = new MP4StcoAtom();
-		} else if (ATOMID(type) == ATOMID("stss")) {
-			pAtom = new MP4StssAtom();
-		} else if (ATOMID(type) == ATOMID("stsh")) {
-			pAtom = new MP4StshAtom();
-		} else if (ATOMID(type) == ATOMID("stdp")) {
-			pAtom = new MP4StdpAtom();
-		} else if (ATOMID(type) == ATOMID("smhd")) {
-			pAtom = new MP4SmhdAtom();
-		} else if (ATOMID(type) == ATOMID("sdp ")) {
-			pAtom = new MP4SdpAtom();
-		} else if (ATOMID(type) == ATOMID("snro")) {
-			pAtom = new MP4SnroAtom();
-		} else if (ATOMID(type) == ATOMID("sync")) {
-			pAtom = new MP4TrefTypeAtom(type);
-		} else if (ATOMID(type) == ATOMID("skip")) {
-			pAtom = new MP4FreeAtom();
-			pAtom->SetType("skip");
-		}
-	} else if (type[0] == 't') {
-		if (ATOMID(type) == ATOMID("trak")) {
-			pAtom = new MP4TrakAtom();
-		} else if (ATOMID(type) == ATOMID("tkhd")) {
-			pAtom = new MP4TkhdAtom();
-		} else if (ATOMID(type) == ATOMID("tref")) {
-			pAtom = new MP4TrefAtom();
-		} else if (ATOMID(type) == ATOMID("traf")) {
-			pAtom = new MP4TrafAtom();
-		} else if (ATOMID(type) == ATOMID("tfhd")) {
-			pAtom = new MP4TfhdAtom();
-		} else if (ATOMID(type) == ATOMID("trex")) {
-			pAtom = new MP4TrexAtom();
-		} else if (ATOMID(type) == ATOMID("trun")) {
-			pAtom = new MP4TrunAtom();
-		} else if (ATOMID(type) == ATOMID("tmin")) {
-			pAtom = new MP4TminAtom();
-		} else if (ATOMID(type) == ATOMID("tmax")) {
-			pAtom = new MP4TmaxAtom();
-		} else if (ATOMID(type) == ATOMID("trpy")) {
-			pAtom = new MP4TrpyAtom();
-		} else if (ATOMID(type) == ATOMID("tpyl")) {
-			pAtom = new MP4TpylAtom();
-		} else if (ATOMID(type) == ATOMID("tims")) {
-			pAtom = new MP4TimsAtom();
-		} else if (ATOMID(type) == ATOMID("tsro")) {
-			pAtom = new MP4TsroAtom();
-		}
-	} else if (type[0] == 'u') {
-		if (ATOMID(type) == ATOMID("udta")) {
-			pAtom = new MP4UdtaAtom();
-		} else if (ATOMID(type) == ATOMID("url ")) {
-			pAtom = new MP4UrlAtom();
-		} else if (ATOMID(type) == ATOMID("urn ")) {
-			pAtom = new MP4UrnAtom();
-		}
-	} else {
-		if (ATOMID(type) == ATOMID("free")) {
-			pAtom = new MP4FreeAtom();
-		} else if (ATOMID(type) == ATOMID("ftyp")) {
-			pAtom = new MP4FtypAtom();
-		} else if (ATOMID(type) == ATOMID("iods")) {
-			pAtom = new MP4IodsAtom();
-		} else if (ATOMID(type) == ATOMID("ipir")) {
-			pAtom = new MP4TrefTypeAtom(type);
-		} else if (ATOMID(type) == ATOMID("nmhd")) {
-			pAtom = new MP4NmhdAtom();
-		} else if (ATOMID(type) == ATOMID("nump")) {
-			pAtom = new MP4NumpAtom();
-		} else if (ATOMID(type) == ATOMID("pmax")) {
-			pAtom = new MP4PmaxAtom();
-		} else if (ATOMID(type) == ATOMID("payt")) {
-			pAtom = new MP4PaytAtom();
-		} else if (ATOMID(type) == ATOMID("rtp ")) {
-			pAtom = new MP4RtpAtom();
-		} else if (ATOMID(type) == ATOMID("vmhd")) {
-			pAtom = new MP4VmhdAtom();
-		} else if (ATOMID(type) == ATOMID("TAG4")) {
-			pAtom = new MP4Tag4Atom();
-		}
-	}
+  if (type == NULL) {
+    pAtom = new MP4RootAtom();
+  } else {
+    switch(type[0]) {
+    case 'c':
+      if (ATOMID(type) == ATOMID("ctts")) {
+	pAtom = new MP4CttsAtom();
+      } else if (ATOMID(type) == ATOMID("co64")) {
+	pAtom = new MP4Co64Atom();
+      } else if (ATOMID(type) == ATOMID("cprt")) {
+	pAtom = new MP4CprtAtom();
+      } else if (ATOMID(type) == ATOMID("cpil")) { /* Apple iTunes */
+	pAtom = new MP4CpilAtom();
+      }
+      break;
+    case 'd':
+      if (ATOMID(type) == ATOMID("dinf")) {
+	pAtom = new MP4DinfAtom();
+      } else if (ATOMID(type) == ATOMID("dref")) {
+	pAtom = new MP4DrefAtom();
+      } else if (ATOMID(type) == ATOMID("dpnd")) {
+	pAtom = new MP4TrefTypeAtom(type);
+      } else if (ATOMID(type) == ATOMID("dmed")) {
+	pAtom = new MP4DmedAtom();
+      } else if (ATOMID(type) == ATOMID("dimm")) {
+	pAtom = new MP4DimmAtom();
+      } else if (ATOMID(type) == ATOMID("drep")) {
+	pAtom = new MP4DrepAtom();
+      } else if (ATOMID(type) == ATOMID("dmax")) {
+	pAtom = new MP4DmaxAtom();
+      } else if (ATOMID(type) == ATOMID("data")) { /* Apple iTunes */
+	pAtom = new MP4DataAtom();
+      } else if (ATOMID(type) == ATOMID("disk")) { /* Apple iTunes */
+	pAtom = new MP4DiskAtom();
+      }
+      break;
+    case 'e':
+      if (ATOMID(type) == ATOMID("esds")) {
+	pAtom = new MP4EsdsAtom();
+      } else if (ATOMID(type) == ATOMID("edts")) {
+	pAtom = new MP4EdtsAtom();
+      } else if (ATOMID(type) == ATOMID("elst")) {
+	pAtom = new MP4ElstAtom();
+      } else if (ATOMID(type) == ATOMID("enca")) {
+	pAtom = new MP4EncaAtom();
+      } else if (ATOMID(type) == ATOMID("encv")) {
+	pAtom = new MP4EncvAtom();
+      }
+      break;
+    case 'f':
+      if (ATOMID(type) == ATOMID("free")) {
+	pAtom = new MP4FreeAtom();
+      } else if (ATOMID(type) == ATOMID("frma")) {
+	pAtom = new MP4FrmaAtom();
+      } else if (ATOMID(type) == ATOMID("ftyp")) {
+	pAtom = new MP4FtypAtom();
+      }
+      break;
+    case 'g':
+      if (ATOMID(type) == ATOMID("gnre")) { /* Apple iTunes */
+	pAtom = new MP4GnreAtom();
+      }
+      break;
+    case 'h':
+      if (ATOMID(type) == ATOMID("hdlr")) {
+	pAtom = new MP4HdlrAtom();
+      } else if (ATOMID(type) == ATOMID("hmhd")) {
+	pAtom = new MP4HmhdAtom();
+      } else if (ATOMID(type) == ATOMID("hint")) {
+	pAtom = new MP4TrefTypeAtom(type);
+      } else if (ATOMID(type) == ATOMID("hnti")) {
+	pAtom = new MP4HntiAtom();
+      } else if (ATOMID(type) == ATOMID("hinf")) {
+	pAtom = new MP4HinfAtom();
+      }
+      break;
+    case 'i':
+      if (ATOMID(type) == ATOMID("iKMS")) {
+	pAtom = new MP4IKMSAtom();
+      } else if (ATOMID(type) == ATOMID("iSFM")) {
+	pAtom = new MP4ISFMAtom();
+      } else if (ATOMID(type) == ATOMID("iods")) {
+	pAtom = new MP4IodsAtom();
+      } else if (ATOMID(type) == ATOMID("ipir")) {
+	pAtom = new MP4TrefTypeAtom(type);
+      } else if (ATOMID(type) == ATOMID("ilst")) { /* Apple iTunes */
+	pAtom = new MP4IlstAtom();
+      }
+      break;
+    case 'm':
+      if (ATOMID(type) == ATOMID("mdia")) {
+	pAtom = new MP4MdiaAtom();
+      } else if (ATOMID(type) == ATOMID("minf")) {
+	pAtom = new MP4MinfAtom();
+      } else if (ATOMID(type) == ATOMID("mdhd")) {
+	pAtom = new MP4MdhdAtom();
+      } else if (ATOMID(type) == ATOMID("mdat")) {
+	pAtom = new MP4MdatAtom();
+      } else if (ATOMID(type) == ATOMID("moov")) {
+	pAtom = new MP4MoovAtom();
+      } else if (ATOMID(type) == ATOMID("mvhd")) {
+	pAtom = new MP4MvhdAtom();
+      } else if (ATOMID(type) == ATOMID("mpod")) {
+	pAtom = new MP4TrefTypeAtom(type);
+      } else if (ATOMID(type) == ATOMID("mp4a")) {
+	pAtom = new MP4Mp4aAtom();
+      } else if (ATOMID(type) == ATOMID("mp4s")) {
+	pAtom = new MP4Mp4sAtom();
+      } else if (ATOMID(type) == ATOMID("mp4v")) {
+	pAtom = new MP4Mp4vAtom();
+      } else if (ATOMID(type) == ATOMID("moof")) {
+	pAtom = new MP4MoofAtom();
+      } else if (ATOMID(type) == ATOMID("mfhd")) {
+	pAtom = new MP4MfhdAtom();
+      } else if (ATOMID(type) == ATOMID("mvex")) {
+	pAtom = new MP4MvexAtom();
+      } else if (ATOMID(type) == ATOMID("maxr")) {
+	pAtom = new MP4MaxrAtom();
+      } else if (ATOMID(type) == ATOMID("meta")) { /* Apple iTunes */
+	pAtom = new MP4MetaAtom();
+      } else if (ATOMID(type) == ATOMID("mean")) { /* Apple iTunes */
+	pAtom = new MP4MeanAtom();
+      }
+      break;
+    case 'n':
+      if (ATOMID(type) == ATOMID("nmhd")) {
+	pAtom = new MP4NmhdAtom();
+      } else if (ATOMID(type) == ATOMID("nump")) {
+	pAtom = new MP4NumpAtom();
+      } else if (ATOMID(type) == ATOMID("name")) {
+	pAtom = new MP4NameAtom();
+      }
+      break;
+    case 'p':
+      if (ATOMID(type) == ATOMID("pmax")) {
+	pAtom = new MP4PmaxAtom();
+      } else if (ATOMID(type) == ATOMID("payt")) {
+	pAtom = new MP4PaytAtom();
+      }
+      break;
+    case 'r':
+      if (ATOMID(type) == ATOMID("rtp ")) {
+	pAtom = new MP4RtpAtom();
+      }
+      break;
+    case 's':
+      if (ATOMID(type) == ATOMID("schi")) {
+	pAtom = new MP4SchiAtom();
+      } else if (ATOMID(type) == ATOMID("schm")) {
+	pAtom = new MP4SchmAtom();
+      } else if (ATOMID(type) == ATOMID("sinf")) {
+	pAtom = new MP4SinfAtom();
+      } else if (ATOMID(type) == ATOMID("stbl")) {
+	pAtom = new MP4StblAtom();
+      } else if (ATOMID(type) == ATOMID("stsd")) {
+	pAtom = new MP4StsdAtom();
+      } else if (ATOMID(type) == ATOMID("stts")) {
+	pAtom = new MP4SttsAtom();
+      } else if (ATOMID(type) == ATOMID("stsz")) {
+	pAtom = new MP4StszAtom();
+      } else if (ATOMID(type) == ATOMID("stsc")) {
+	pAtom = new MP4StscAtom();
+      } else if (ATOMID(type) == ATOMID("stco")) {
+	pAtom = new MP4StcoAtom();
+      } else if (ATOMID(type) == ATOMID("stss")) {
+	pAtom = new MP4StssAtom();
+      } else if (ATOMID(type) == ATOMID("stsh")) {
+	pAtom = new MP4StshAtom();
+      } else if (ATOMID(type) == ATOMID("stdp")) {
+	pAtom = new MP4StdpAtom();
+      } else if (ATOMID(type) == ATOMID("smhd")) {
+	pAtom = new MP4SmhdAtom();
+      } else if (ATOMID(type) == ATOMID("sdp ")) {
+	pAtom = new MP4SdpAtom();
+      } else if (ATOMID(type) == ATOMID("snro")) {
+	pAtom = new MP4SnroAtom();
+      } else if (ATOMID(type) == ATOMID("sync")) {
+	pAtom = new MP4TrefTypeAtom(type);
+      } else if (ATOMID(type) == ATOMID("skip")) {
+	pAtom = new MP4FreeAtom();
+	pAtom->SetType("skip");
+      }
+      break;
+    case 't':
+      if (ATOMID(type) == ATOMID("trak")) {
+	pAtom = new MP4TrakAtom();
+      } else if (ATOMID(type) == ATOMID("tkhd")) {
+	pAtom = new MP4TkhdAtom();
+      } else if (ATOMID(type) == ATOMID("tref")) {
+	pAtom = new MP4TrefAtom();
+      } else if (ATOMID(type) == ATOMID("traf")) {
+	pAtom = new MP4TrafAtom();
+      } else if (ATOMID(type) == ATOMID("tfhd")) {
+	pAtom = new MP4TfhdAtom();
+      } else if (ATOMID(type) == ATOMID("trex")) {
+	pAtom = new MP4TrexAtom();
+      } else if (ATOMID(type) == ATOMID("trun")) {
+	pAtom = new MP4TrunAtom();
+      } else if (ATOMID(type) == ATOMID("tmin")) {
+	pAtom = new MP4TminAtom();
+      } else if (ATOMID(type) == ATOMID("tmax")) {
+	pAtom = new MP4TmaxAtom();
+      } else if (ATOMID(type) == ATOMID("trpy")) {
+	pAtom = new MP4TrpyAtom();
+      } else if (ATOMID(type) == ATOMID("tpyl")) {
+	pAtom = new MP4TpylAtom();
+      } else if (ATOMID(type) == ATOMID("tims")) {
+	pAtom = new MP4TimsAtom();
+      } else if (ATOMID(type) == ATOMID("tsro")) {
+	pAtom = new MP4TsroAtom();
+      } else if (ATOMID(type) == ATOMID("trkn")) { /* Apple iTunes */
+	pAtom = new MP4TrknAtom();
+      } else if (ATOMID(type) == ATOMID("tmpo")) { /* Apple iTunes */
+	pAtom = new MP4TmpoAtom();
+      }
+      break;
+    case 'u':
+      if (ATOMID(type) == ATOMID("udta")) {
+	pAtom = new MP4UdtaAtom();
+      } else if (ATOMID(type) == ATOMID("url ")) {
+	pAtom = new MP4UrlAtom();
+      } else if (ATOMID(type) == ATOMID("urn ")) {
+	pAtom = new MP4UrnAtom();
+      }
+      break;
+    case 'v':
+      if (ATOMID(type) == ATOMID("vmhd")) {
+	pAtom = new MP4VmhdAtom();
+      }
+      break;
+    case '�':
+      if (ATOMID(type) == ATOMID("�nam")) {
+	pAtom = new MP4NamAtom();
+      } else if (ATOMID(type) == ATOMID("�ART")) { /* Apple iTunes */
+	pAtom = new MP4ArtAtom();
+      } else if (ATOMID(type) == ATOMID("�wrt")) { /* Apple iTunes */
+	pAtom = new MP4WrtAtom();
+      } else if (ATOMID(type) == ATOMID("�alb")) { /* Apple iTunes */
+	pAtom = new MP4AlbAtom();
+      } else if (ATOMID(type) == ATOMID("�day")) { /* Apple iTunes */
+	pAtom = new MP4DayAtom();
+      } else if (ATOMID(type) == ATOMID("�too")) { /* Apple iTunes */
+	pAtom = new MP4TooAtom();
+      } else if (ATOMID(type) == ATOMID("�cmt")) { /* Apple iTunes */
+	pAtom = new MP4CmtAtom();
+      }
+      break;
+    case '-':
+      if (ATOMID(type) == ATOMID("----")) { /* Apple iTunes */
+	pAtom = new MP4DashAtom();
+      }
+    }
+  }
 
-	if (pAtom == NULL) {
-		pAtom = new MP4Atom(type);
-		pAtom->SetUnknownType(true);
-	}
+  if (pAtom == NULL) {
+    pAtom = new MP4Atom(type);
+    pAtom->SetUnknownType(true);
+  }
 
-	ASSERT(pAtom);
-	return pAtom;
+  ASSERT(pAtom);
+  return pAtom;
 }
 
 // generate a skeletal self
@@ -613,6 +699,7 @@
 void MP4Atom::BeginWrite(bool use64)
 {
 	m_start = m_pFile->GetPosition();
+	//use64 = m_pFile->Use64Bits();
 	if (use64) {
 		m_pFile->WriteUInt32(1);
 	} else {
@@ -631,6 +718,7 @@
 {
 	m_end = m_pFile->GetPosition();
 	m_size = (m_end - m_start);
+	//use64 = m_pFile->Use64Bits();
 	if (use64) {
 		m_pFile->SetPosition(m_start + 8);
 		m_pFile->WriteUInt64(m_size);
--- a/common/mp4v2/mp4file.cpp
+++ b/common/mp4v2/mp4file.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie		  dmackie@cisco.com
+ *              Alix Marchandise-Franquet alix@cisco.com
  */
 
 #include "mp4common.h"
@@ -547,8 +548,8 @@
 	}
 
 #ifndef USE_FILE_CALLBACKS
-    fclose(m_pFile);
-    m_pFile = NULL;
+	fclose(m_pFile);
+	m_pFile = NULL;
 #else
 	m_MP4fclose(this);
 #endif
@@ -1089,7 +1090,15 @@
 	pStsdCountProperty->IncrementValue();
 
 	SetTrackIntegerProperty(trackId, 
-		"mdia.minf.stbl.stsd.mp4s.esds.ESID", trackId);
+				"mdia.minf.stbl.stsd.mp4s.esds.ESID", 
+#if 0
+				// note - for a file, these values need to 
+				// be 0 - wmay - 04/16/2003
+				trackId
+#else
+				0
+#endif
+				);
 
 	SetTrackIntegerProperty(trackId, 
 		"mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", 
@@ -1157,7 +1166,15 @@
 		"mdia.minf.stbl.stsd.mp4a.timeScale", timeScale);
 
 	SetTrackIntegerProperty(trackId, 
-		"mdia.minf.stbl.stsd.mp4a.esds.ESID", trackId);
+				"mdia.minf.stbl.stsd.mp4a.esds.ESID", 
+#if 0
+				// note - for a file, these values need to 
+				// be 0 - wmay - 04/16/2003
+				trackId
+#else
+				0
+#endif
+				);
 
 	SetTrackIntegerProperty(trackId, 
 		"mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId", 
@@ -1173,6 +1190,56 @@
 	return trackId;
 }
 
+MP4TrackId MP4File::AddEncAudioTrack(u_int32_t timeScale, 
+				     MP4Duration sampleDuration, 
+				     u_int8_t audioType)
+{
+  MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
+
+  AddTrackToOd(trackId);
+
+  SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);
+
+  InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);
+
+  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();
+
+  SetTrackIntegerProperty(trackId, 
+			  "mdia.minf.stbl.stsd.enca.timeScale", timeScale);
+
+  SetTrackIntegerProperty(trackId, 
+			  "mdia.minf.stbl.stsd.enca.esds.ESID", 
+#if 0
+			  // note - for a file, these values need to 
+			  // be 0 - wmay - 04/16/2003
+			  trackId
+#else
+			  0
+#endif
+			  );
+
+  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::AddVideoTrack(
 	u_int32_t timeScale, 
 	MP4Duration sampleDuration, 
@@ -1205,7 +1272,15 @@
 		"mdia.minf.stbl.stsd.mp4v.height", height);
 
 	SetTrackIntegerProperty(trackId, 
-		"mdia.minf.stbl.stsd.mp4v.esds.ESID", trackId);
+				"mdia.minf.stbl.stsd.mp4v.esds.ESID", 
+#if 0
+				// note - for a file, these values need to 
+				// be 0 - wmay - 04/16/2003
+				trackId
+#else
+				0
+#endif
+				);
 
 	SetTrackIntegerProperty(trackId, 
 		"mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId", 
@@ -1224,6 +1299,64 @@
 	return trackId;
 }
 
+MP4TrackId MP4File::AddEncVideoTrack(u_int32_t timeScale, 
+				     MP4Duration sampleDuration, 
+				     u_int16_t width, 
+				     u_int16_t height, 
+				     u_int8_t videoType)
+{
+  MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale);
+
+  AddTrackToOd(trackId);
+
+  SetTrackFloatProperty(trackId, "tkhd.width", width);
+  SetTrackFloatProperty(trackId, "tkhd.height", height);
+
+  InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0);
+
+  AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "encv");
+
+  // 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 encv atom
+  MP4Integer32Property* pStsdCountProperty;
+  FindIntegerProperty(
+		      MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
+		      (MP4Property**)&pStsdCountProperty);
+  pStsdCountProperty->IncrementValue();
+
+  SetTrackIntegerProperty(trackId, 
+			  "mdia.minf.stbl.stsd.encv.width", width);
+  SetTrackIntegerProperty(trackId, 
+			  "mdia.minf.stbl.stsd.encv.height", height);
+
+  SetTrackIntegerProperty(trackId, 
+			  "mdia.minf.stbl.stsd.encv.esds.ESID", 
+#if 0
+			  // note - for a file, these values need to 
+			  // be 0 - wmay - 04/16/2003
+			  trackId
+#else
+			  0
+#endif
+			  );
+
+  SetTrackIntegerProperty(trackId, 
+		  "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.objectTypeId", 
+			  videoType);
+
+  SetTrackIntegerProperty(trackId, 
+		"mdia.minf.stbl.stsd.encv.esds.decConfigDescr.streamType", 
+			  MP4VisualStreamType);
+
+  SetTrackIntegerProperty(trackId, 
+			  "mdia.minf.stbl.stsz.sampleSize", sampleDuration);
+
+  m_pTracks[FindTrackIndex(trackId)]->
+    SetFixedSampleDuration(sampleDuration);
+
+  return trackId;
+}
+
 MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId)
 {
 	// validate reference track id
@@ -1303,11 +1436,11 @@
 		if (!strcmp(normType, m_pTracks[i]->GetType())) {
 			if (subType) {
 				if (normType == MP4_AUDIO_TRACK_TYPE) {
-					if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
+					if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
 						continue;
 					}
 				} else if (normType == MP4_VIDEO_TRACK_TYPE) {
-					if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
+					if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
 						continue;
 					}
 				} 
@@ -1356,43 +1489,43 @@
 	return MP4_INVALID_TRACK_ID;		// to keep MSVC happy
 }
 
-MP4TrackId MP4File::FindTrackId(
-	u_int16_t trackIndex, const char* type, u_int8_t subType)
+MP4TrackId MP4File::FindTrackId(u_int16_t trackIndex, 
+				const char* type, u_int8_t subType)
 {
-	if (type == NULL) {
-		return m_pTracks[trackIndex]->GetId();
-	} 
+  if (type == NULL) {
+    return m_pTracks[trackIndex]->GetId();
+  } 
 
-	u_int32_t typeSeen = 0;
-	const char* normType = MP4Track::NormalizeTrackType(type);
+  u_int32_t typeSeen = 0;
+  const char* normType = MP4Track::NormalizeTrackType(type);
 
-	for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
-		if (!strcmp(normType, m_pTracks[i]->GetType())) {
-			if (subType) {
-				if (normType == MP4_AUDIO_TRACK_TYPE) {
-					if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
-						continue;
-					}
-				} else if (normType == MP4_VIDEO_TRACK_TYPE) {
-					if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
-						continue;
-					}
-				} 
-				// else unknown subtype, ignore it
-			}
+  for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
+    if (!strcmp(normType, m_pTracks[i]->GetType())) {
+      if (subType) {
+	if (normType == MP4_AUDIO_TRACK_TYPE) {
+	  if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
+	    continue;
+	  }
+	} else if (normType == MP4_VIDEO_TRACK_TYPE) {
+	  if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
+	    continue;
+	  }
+	} 
+	// else unknown subtype, ignore it
+      }
 
-			if (trackIndex == typeSeen) {
-				return m_pTracks[i]->GetId();
-			}
+      if (trackIndex == typeSeen) {
+	return m_pTracks[i]->GetId();
+      }
 
-			typeSeen++;
-		}
-	}
+      typeSeen++;
+    }
+  }
 
-	throw new MP4Error("Track index doesn't exist - track %d type %s", 
-			   "FindTrackId", 
-			   trackIndex, type); 
-	return MP4_INVALID_TRACK_ID; // satisfy MS compiler
+  throw new MP4Error("Track index doesn't exist - track %d type %s", 
+		     "FindTrackId", 
+		     trackIndex, type); 
+  return MP4_INVALID_TRACK_ID; // satisfy MS compiler
 }
 
 u_int16_t MP4File::FindTrackIndex(MP4TrackId trackId)
@@ -1480,7 +1613,7 @@
 }
 
 void MP4File::WriteSample(MP4TrackId trackId,
-		u_int8_t* pBytes, u_int32_t numBytes,
+		const u_int8_t* pBytes, u_int32_t numBytes,
 		MP4Duration duration, MP4Duration renderingOffset, bool isSyncSample)
 {
 	ProtectWriteOperation("MP4WriteSample");
@@ -1701,16 +1834,24 @@
 	return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration");
 }
 
+// now GetTrackEsdsObjectTypeId 
 u_int8_t MP4File::GetTrackAudioType(MP4TrackId trackId)
 {
+        return GetTrackIntegerProperty(trackId,
+                "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId");
+}
+
+u_int8_t MP4File::GetTrackEsdsObjectTypeId(MP4TrackId trackId)
+{
+	// changed mp4a to * to handle enca case
 	return GetTrackIntegerProperty(trackId, 
-		"mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId");
+		"mdia.minf.stbl.stsd.*.esds.decConfigDescr.objectTypeId");
 }
 
 u_int8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId)
 {
 	// verify that track is an MPEG-4 audio track 
-	if (GetTrackAudioType(trackId) != MP4_MPEG4_AUDIO_TYPE) {
+	if (GetTrackEsdsObjectTypeId(trackId) != MP4_MPEG4_AUDIO_TYPE) {
 		return MP4_MPEG4_INVALID_AUDIO_TYPE;
 	}
 
@@ -1733,6 +1874,7 @@
 	return mpeg4Type;
 }
 
+// replaced with GetTrackEsdsObjectTypeId
 u_int8_t MP4File::GetTrackVideoType(MP4TrackId trackId)
 {
 	return GetTrackIntegerProperty(trackId, 
@@ -1748,11 +1890,7 @@
 {
 	MP4SampleId numSamples =
 		GetTrackNumberOfSamples(trackId);
-#ifdef _WIN32
-	int64_t
-#else
 	u_int64_t 
-#endif
 		msDuration =
 		ConvertFromTrackDuration(trackId, 
 			GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE);
@@ -1761,7 +1899,7 @@
 		return 0.0;
 	}
 
-	return ((double)numSamples / (double)msDuration) * MP4_MSECS_TIME_SCALE;
+	return ((double)numSamples / UINT64_TO_DOUBLE(msDuration)) * MP4_MSECS_TIME_SCALE;
 }
 
 void MP4File::GetTrackESConfiguration(MP4TrackId trackId, 
@@ -1869,7 +2007,9 @@
 
 void MP4File::SetHintTrackRtpPayload(MP4TrackId hintTrackId,
 	const char* payloadName, u_int8_t* pPayloadNumber, u_int16_t maxPayloadSize,
-				     const char *encoding_params)
+				     const char *encoding_params,
+				     bool include_rtp_map,
+				     bool include_mpeg4_esid)
 {
 	MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
 
@@ -1889,7 +2029,8 @@
 	}
 
 	((MP4RtpHintTrack*)pTrack)->SetPayload(
-		payloadName, payloadNumber, maxPayloadSize, encoding_params);
+		payloadName, payloadNumber, maxPayloadSize, encoding_params,
+		include_rtp_map, include_mpeg4_esid);
 }
 
 u_int8_t MP4File::AllocRtpPayloadNumber()
@@ -2140,7 +2281,7 @@
 	MP4Timestamp timeStamp,
 	u_int32_t timeScale)
 {
-	return MP4ConvertTime((u_int64_t)timeStamp, 
+	return MP4ConvertTime(timeStamp, 
 		GetTrackTimeScale(trackId), timeScale);
 }
 
@@ -2312,187 +2453,3 @@
 		when, pStartTime, pDuration);
 }
 
-
-/* Code for handling mp4 tagging */
-
-void MP4File::TagCreate(MP4TrackId trackId)
-{
-    if (trackId == NULL)
-        AddDescendantAtoms("moov", "udta.TAG4");
-    else
-        AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.TAG4");
-}
-
-bool MP4File::TagDelete(MP4TrackId trackId)
-{
-    MP4Atom *pUdtaAtom = NULL;
-    MP4Atom *pTagAtom = NULL;
-
-    if (trackId == NULL)
-    {
-        pUdtaAtom = m_pRootAtom->FindAtom("moov.udta");
-        pTagAtom = m_pRootAtom->FindAtom("moov.udta.TAG4");
-    } else {
-        pUdtaAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId, "udta"));
-        pTagAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId, "udta.TAG4"));
-    }
-    /* there is no tag */
-    if (!pUdtaAtom || !pTagAtom)
-        return false;
-
-    pUdtaAtom->DeleteChildAtom(pTagAtom);
-
-    delete pTagAtom;
-
-    return true;
-}
-
-bool MP4File::TagAddEntry(MP4TrackId trackId,
-                          const char *name, const char *value)
-{
-    MP4StringProperty *pNameProperty = NULL;
-    MP4StringProperty *pValueProperty = NULL;
-    MP4Integer32Property *pCountProperty = NULL;
-    MP4Atom *pTagAtom = NULL;
-
-    if (trackId == NULL)
-        pTagAtom = m_pRootAtom->FindAtom("moov.udta.TAG4");
-    else
-        pTagAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId, "udta.TAG4"));
-    if (!pTagAtom)
-    {
-        TagCreate(trackId);
-        if (trackId == NULL)
-            pTagAtom = m_pRootAtom->FindAtom("moov.udta.TAG4");
-        else
-            pTagAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId, "udta.TAG4"));
-    }
-
-    pTagAtom->FindProperty("TAG4.entryCount",
-        (MP4Property**)&pCountProperty);
-    ASSERT(pCountProperty);
-
-    pTagAtom->FindProperty("TAG4.entries.name",
-        (MP4Property**)&pNameProperty);
-    ASSERT(pNameProperty);
-
-    {
-        char name2[128];
-        if (strlen(name) > 126)
-        {
-            memcpy(name2, name, 127);
-            name2[127] = '\0';
-            pNameProperty->AddValue((char*)name2);
-        } else {
-    pNameProperty->AddValue((char*)name);
-        }
-    }
-
-    pTagAtom->FindProperty("TAG4.entries.value",
-        (MP4Property**)&pValueProperty);
-    ASSERT(pValueProperty);
-
-    {
-        char value2[128];
-        if (strlen(value) > 126)
-        {
-            memcpy(value2, value, 127);
-            value2[127] = '\0';
-            pValueProperty->AddValue((char*)value2);
-        } else {
-    pValueProperty->AddValue((char*)value);
-        }
-    }
-
-    pCountProperty->IncrementValue();
-
-    return true;
-}
-
-#if 0 // not working
-void MP4File::TagDeleteEntry(MP4TrackId trackId, u_int32_t index)
-{
-    MP4TableProperty *pEntryProperty = NULL;
-    MP4Integer32Property *pCountProperty = NULL;
-    MP4Atom *pTagAtom = NULL;
-
-    if (trackId == NULL)
-        pTagAtom = m_pRootAtom->FindAtom("moov.udta.TAG4");
-    else
-        pTagAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId, "udta.TAG4"));
-
-    pTagAtom->FindProperty("TAG4.entryCount",
-        (MP4Property**)&pCountProperty);
-    ASSERT(pCountProperty);
-
-    pTagAtom->FindProperty("TAG4.entries",
-        (MP4Property**)&pEntryProperty);
-    ASSERT(pEntryProperty);
-
-    pEntryProperty->DeleteEntry(index);
-
-    pCountProperty->IncrementValue(-1);
-}
-#endif
-
-u_int32_t MP4File::TagGetNumEntries(MP4TrackId trackId)
-{
-    MP4Integer32Property *pCountProperty = NULL;
-    MP4Atom *pTagAtom = NULL;
-
-    if (trackId == NULL)
-        pTagAtom = m_pRootAtom->FindAtom("moov.udta.TAG4");
-    else
-        pTagAtom = m_pRootAtom->FindAtom(MakeTrackName(trackId, "udta.TAG4"));
-
-    if (pTagAtom)
-    {
-        pTagAtom->FindProperty("TAG4.entryCount",
-            (MP4Property**)&pCountProperty);
-        if (pCountProperty)
-        {
-            return pCountProperty->GetValue();
-        }
-    }
-
-    return 0;
-}
-
-void MP4File::TagGetEntry(MP4TrackId trackId, u_int32_t index,
-                          const char **name, const char **value)
-{
-    char s[256];
-
-    if (trackId == NULL)
-    {
-        sprintf(s, "moov.udta.TAG4.entries[%u].name", index);		
-        *name = GetStringProperty(s);
-        sprintf(s, "moov.udta.TAG4.entries[%u].value", index);
-        *value = GetStringProperty(s);
-    } else {
-        sprintf(s, "udta.TAG4.entries[%u].name", index);		
-        *name = GetTrackStringProperty(trackId, s);
-        sprintf(s, "udta.TAG4.entries[%u].value", index);
-        *value = GetTrackStringProperty(trackId, s);
-    }
-}
-
-bool MP4File::TagGetEntryByName(MP4TrackId trackId, char *name,
-                                const char **value)
-{
-    int numEntries = TagGetNumEntries(trackId);
-
-    for (int i = 0; i < numEntries; i++)
-    {
-        const char *n = NULL, *v = NULL;
-        TagGetEntry(trackId, i, &n, &v);
-
-        if (!strcmp(n, name))
-        {
-            *value = v;
-            return true;
-        }
-    }
-
-    return false;
-}
--- a/common/mp4v2/mp4file.h
+++ b/common/mp4v2/mp4file.h
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
  */
 
 #ifndef __MP4_FILE_INCLUDED__
@@ -31,6 +32,7 @@
 class MP4Descriptor;
 class MP4DescriptorProperty;
 
+
 #ifdef USE_FILE_CALLBACKS
 typedef u_int32_t (*MP4OpenCallback)(const char *pName, const char *mode, void *userData);
 typedef void (*MP4CloseCallback)(void *userData);
@@ -180,7 +182,7 @@
 
 	void WriteSample(
 		MP4TrackId trackId,
-		u_int8_t* pBytes, 
+		const u_int8_t* pBytes, 
 		u_int32_t numBytes,
 		MP4Duration duration = 0,
 		MP4Duration renderingOffset = 0, 
@@ -204,6 +206,11 @@
 		MP4Duration sampleDuration,
 		u_int8_t audioType);
 
+	MP4TrackId AddEncAudioTrack( // ismacrypt
+		u_int32_t timeScale, 
+		MP4Duration sampleDuration,
+		u_int8_t audioType);
+
 	MP4TrackId AddVideoTrack(
 		u_int32_t timeScale, 
 		MP4Duration sampleDuration,
@@ -210,6 +217,13 @@
 		u_int16_t width, 
 		u_int16_t height, 
 		u_int8_t videoType);
+	
+	MP4TrackId AddEncVideoTrack( // ismacrypt
+		u_int32_t timeScale, 
+		MP4Duration sampleDuration,
+		u_int16_t width, 
+		u_int16_t height, 
+		u_int8_t videoType);
 
 	MP4TrackId AddHintTrack(MP4TrackId refTrackId);
 
@@ -222,6 +236,9 @@
 	u_int32_t GetTrackTimeScale(MP4TrackId trackId);
 	void SetTrackTimeScale(MP4TrackId trackId, u_int32_t value);
 
+	// replacement to GetTrackAudioType and GetTrackVideoType	
+	u_int8_t GetTrackEsdsObjectTypeId(MP4TrackId trackId);
+
 	u_int8_t GetTrackAudioType(MP4TrackId trackId);
 	u_int8_t GetTrackAudioMpeg4Type(MP4TrackId trackId);
 	u_int8_t GetTrackVideoType(MP4TrackId trackId);
@@ -295,7 +312,9 @@
 		const char* payloadName,
 		u_int8_t* pPayloadNumber,
 		u_int16_t maxPayloadSize,
-		const char *encoding_params);
+		const char *encoding_params,
+		bool include_rtp_map,
+		bool include_mpeg4_esid);
 
 	MP4TrackId GetHintTrackReferenceTrackId(
 		MP4TrackId hintTrackId);
@@ -422,16 +441,45 @@
 		MP4Timestamp* pStartTime = NULL,
 		MP4Duration* pDuration = NULL);
 
-    /* tagging */
-    void TagCreate(MP4TrackId trackId);
-    bool TagDelete(MP4TrackId trackId);
-    bool TagAddEntry(MP4TrackId trackId,
-        const char *name, const char *value);
-    u_int32_t TagGetNumEntries(MP4TrackId trackId);
-    void TagGetEntry(MP4TrackId trackId, u_int32_t index,
-        const char **name, const char **value);
-    bool TagGetEntryByName(MP4TrackId trackId, char *name,
-        const char **value);
+    /* iTunes metadata handling */
+    bool CreateMetadataAtom(const char* name);
+    bool MetadataDelete();
+
+    /* set metadata */
+    bool SetMetadataName(const char* value);
+    bool SetMetadataWriter(const char* value);
+    bool SetMetadataAlbum(const char* value);
+    bool SetMetadataArtist(const char* value);
+    bool SetMetadataTool(const char* value);
+    bool SetMetadataComment(const char* value);
+    bool SetMetadataYear(const char* value);
+    bool SetMetadataTrack(u_int16_t track, u_int16_t totalTracks);
+    bool SetMetadataDisk(u_int16_t disk, u_int16_t totalDisks);
+    bool SetMetadataGenre(u_int16_t genreIndex);
+    bool SetMetadataTempo(u_int16_t tempo);
+    bool SetMetadataCompilation(u_int8_t compilation);
+    bool SetMetadataCoverArt(u_int8_t *coverArt, u_int32_t size);
+    bool SetMetadataFreeForm(char *name, u_int8_t* pValue, u_int32_t valueSize);
+
+    /* get metadata */
+    bool GetMetadataByIndex(u_int32_t index,
+        const char** ppName,
+        u_int8_t** ppValue, u_int32_t* pValueSize);
+    bool GetMetadataName(char** value);
+    bool GetMetadataWriter(char** value);
+    bool GetMetadataAlbum(char** value);
+    bool GetMetadataArtist(char** value);
+    bool GetMetadataTool(char** value);
+    bool GetMetadataComment(char** value);
+    bool GetMetadataYear(char** value);
+    bool GetMetadataTrack(u_int16_t* track, u_int16_t* totalTracks);
+    bool GetMetadataDisk(u_int16_t* disk, u_int16_t* totalDisks);
+    bool GetMetadataGenre(u_int16_t* genreIndex);
+    bool GetMetadataTempo(u_int16_t* tempo);
+    bool GetMetadataCompilation(u_int8_t* compilation);
+    bool GetMetadataCoverArt(u_int8_t **coverArt, u_int32_t* size);
+    bool GetMetadataFreeForm(char *name, u_int8_t** pValue, u_int32_t* valueSize);
+
 
 	/* end of MP4 API */
 
--- a/common/mp4v2/mp4file_io.cpp
+++ b/common/mp4v2/mp4file_io.cpp
@@ -34,14 +34,13 @@
 u_int64_t MP4File::GetPosition(FILE* pFile)
 {
 	if (m_memoryBuffer == NULL) {
-        int64_t pos;
 #ifndef USE_FILE_CALLBACKS
+		fpos_t fpos;
 		if (pFile == NULL) {
 			ASSERT(m_pFile);
 			pFile = m_pFile;
 		}
 
-		fpos_t fpos;
 		if (fgetpos(pFile, &fpos) < 0) {
 			throw new MP4Error(errno, "MP4GetPosition");
 		}
@@ -48,6 +47,7 @@
 		return FPOS_TO_UINT64(fpos);
 #else
 
+        u_int64_t pos;
 		if ((pos = m_MP4fgetpos(m_userData)) < 0) {
 			throw new MP4Error(errno, "MP4GetPosition");
 		}
@@ -199,6 +199,7 @@
 			ASSERT(m_pFile);
 			pFile = m_pFile;
 		}
+
 		u_int32_t rc = fwrite(pBytes, 1, numBytes, pFile);
 #else
 		u_int32_t rc = m_MP4fwrite(pBytes, numBytes, m_userData);
@@ -474,7 +475,7 @@
 		WriteUInt8(charLength);
 	} else {
 		if (charLength > 255) {
-			throw new MP4Error(ERANGE, "MP4WriteCountedString");
+			throw new MP4Error(ERANGE, "Length is %d", "MP4WriteCountedString", charLength);
 		}
 		WriteUInt8(charLength);
 	}
--- a/common/mp4v2/mp4info.cpp
+++ b/common/mp4v2/mp4info.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001-2002.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie		  dmackie@cisco.com
+ *		Alix Marchandise-Franquet alix@cisco.com
  */
 
 #include "mp4common.h"
@@ -63,7 +64,7 @@
 		"MPEG-2 (MP3)",
 		"MPEG-1 (MP3)",
 		"PCM16 (little endian)",
-		"OGG VORBIS",
+		"Vorbis",
 		"G.711 aLaw",
 		"G.711 uLaw",
 		"G.723.1",
@@ -73,7 +74,7 @@
 		sizeof(mpegAudioTypes) / sizeof(u_int8_t);
 
 	u_int8_t type =
-		MP4GetTrackAudioType(mp4File, trackId);
+		MP4GetTrackEsdsObjectTypeId(mp4File, trackId);
 	const char* typeName = "Unknown";
 
 	if (type == MP4_MPEG4_AUDIO_TYPE) {
@@ -99,11 +100,8 @@
 		MP4GetTrackDuration(mp4File, trackId);
 
 	double msDuration =
-#ifdef _WIN32
-		(int64_t)
-#endif
-		MP4ConvertFromTrackDuration(mp4File, trackId, 
-			trackDuration, MP4_MSECS_TIME_SCALE);
+		UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, 
+			trackDuration, MP4_MSECS_TIME_SCALE));
 
 	u_int32_t avgBitRate =
 		MP4GetTrackBitRate(mp4File, trackId);
@@ -178,7 +176,7 @@
 		sizeof(mpegVideoTypes) / sizeof(u_int8_t);
 
 	u_int8_t type =
-		MP4GetTrackVideoType(mp4File, trackId);
+		MP4GetTrackEsdsObjectTypeId(mp4File, trackId);
 	const char* typeName = "Unknown";
 
 	if (type == MP4_MPEG4_VIDEO_TYPE) {
@@ -201,11 +199,8 @@
 		MP4GetTrackDuration(mp4File, trackId);
 
 	double msDuration =
-#ifdef _WIN32
-		(int64_t)
-#endif
-		MP4ConvertFromTrackDuration(mp4File, trackId, 
-			trackDuration, MP4_MSECS_TIME_SCALE);
+		UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, 
+			trackDuration, MP4_MSECS_TIME_SCALE));
 
 	u_int32_t avgBitRate =
 		MP4GetTrackBitRate(mp4File, trackId);
@@ -267,8 +262,6 @@
 	const char* trackType = 
 		MP4GetTrackType(mp4File, trackId);
 
-    if (trackType) {
-
 	if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) {
 		trackInfo = PrintAudioInfo(mp4File, trackId);
 	} else if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE)) {
@@ -291,8 +284,6 @@
 					trackId, trackType);
 		}
 	}
-
-    }
 
 	return trackInfo;
 }
--- /dev/null
+++ b/common/mp4v2/mp4meta.cpp
@@ -1,0 +1,876 @@
+/*
+ * 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 Metadata handling
+ */
+
+/**
+
+ The iTunes tagging seems to support any tag field name
+ but there are some predefined fields, also known from the QuickTime format
+
+ predefined fields (the ones I know of until now):
+ - �nam : Name of the song/movie (string)
+ - �ART : Name of the artist/performer (string)
+ - �wrt : Name of the writer (string)
+ - �alb : Name of the album (string)
+ - �day : Year (4 bytes, e.g. "2003") (string)
+ - �too : Tool(s) used to create the file (string)
+ - �cmt : Comment (string)
+ - trkn : Tracknumber (8 byte string)
+           16 bit: empty
+           16 bit: tracknumber
+           16 bit: total tracks on album
+           16 bit: empty
+ - disk : Disknumber (8 byte string)
+           16 bit: empty
+           16 bit: disknumber
+           16 bit: total number of disks
+           16 bit: empty
+ - gnre : Genre (16 bit genre)
+ - cpil : Part of a compilation (1 byte, 1 or 0)
+ - tmpo : Tempo in BPM (16 bit)
+ - covr : Cover art (xx bytes binary data)
+ - ---- : Free form metadata, can have any name and any data
+
+**/
+
+#include "mp4common.h"
+
+bool MP4File::GetMetadataByIndex(u_int32_t index,
+                                 const char** ppName,
+                                 u_int8_t** ppValue, u_int32_t* pValueSize)
+{
+    char s[256];
+
+    sprintf(s, "moov.udta.meta.ilst.*[%u].data.metadata", index);
+    GetBytesProperty(s, ppValue, pValueSize);
+
+    sprintf(s, "moov.udta.meta.ilst.*[%u]", index);
+    MP4Atom* pParent = m_pRootAtom->FindAtom(s);
+    *ppName = pParent->GetType();
+
+    /* check for free form tagfield */
+    if (memcmp(*ppName, "----", 4) == 0)
+    {
+        u_int8_t* pV;
+        u_int32_t VSize = 0;
+        char *pN;
+
+        sprintf(s, "moov.udta.meta.ilst.*[%u].name.metadata", index);
+        GetBytesProperty(s, &pV, &VSize);
+
+        pN = (char*)malloc((VSize+1)*sizeof(char));
+        memset(pN, 0, (VSize+1)*sizeof(char));
+        memcpy(pN, pV, VSize*sizeof(char));
+
+        *ppName = pN;
+    }
+
+    return true;
+}
+
+bool MP4File::CreateMetadataAtom(const char* name)
+{
+    char s[256];
+    char t[256];
+
+    sprintf(t, "udta.meta.ilst.%s.data", name);
+    sprintf(s, "moov.udta.meta.ilst.%s.data", name);
+    AddDescendantAtoms("moov", t);
+    MP4Atom *pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+        return false;
+
+    /* some fields need special flags set */
+    if (name[0] == '�')
+    {
+        pMetaAtom->SetFlags(0x1);
+    } else if ((memcmp(name, "cpil", 4) == 0) || (memcmp(name, "tmpo", 4) == 0)) {
+        pMetaAtom->SetFlags(0xF);
+    }
+
+    MP4Atom *pHdlrAtom = m_pRootAtom->FindAtom("moov.udta.meta.hdlr");
+    MP4StringProperty *pStringProperty = NULL;
+    MP4BytesProperty *pBytesProperty = NULL;
+    ASSERT(pHdlrAtom);
+
+    pHdlrAtom->FindProperty(
+        "hdlr.handlerType", (MP4Property**)&pStringProperty);
+    ASSERT(pStringProperty);
+    pStringProperty->SetValue("mdir");
+
+    u_int8_t val[12];
+    memset(val, 0, 12*sizeof(u_int8_t));
+    val[0] = 0x61;
+    val[1] = 0x70;
+    val[2] = 0x70;
+    val[3] = 0x6c;
+    pHdlrAtom->FindProperty(
+        "hdlr.reserved2", (MP4Property**)&pBytesProperty);
+    ASSERT(pBytesProperty);
+    pBytesProperty->SetReadOnly(false);
+    pBytesProperty->SetValue(val, 12);
+    pBytesProperty->SetReadOnly(true);
+
+    return true;
+}
+
+bool MP4File::SetMetadataName(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�nam.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�nam"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
+
+    return true;
+}
+
+bool MP4File::GetMetadataName(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�nam.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataWriter(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�wrt.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�wrt"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
+
+    return true;
+}
+
+bool MP4File::GetMetadataWriter(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�wrt.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataAlbum(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�alb.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�alb"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
+
+    return true;
+}
+
+bool MP4File::GetMetadataAlbum(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�alb.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataArtist(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�ART.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�ART"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
+
+    return true;
+}
+
+bool MP4File::GetMetadataArtist(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�ART.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataTool(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�too.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�too"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
+
+    return true;
+}
+
+bool MP4File::GetMetadataTool(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�too.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataComment(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�cmt.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�cmt"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
+
+    return true;
+}
+
+bool MP4File::GetMetadataComment(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�cmt.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataYear(const char* value)
+{
+    const char *s = "moov.udta.meta.ilst.�day.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("�day"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    if (strlen(value) < 4)
+        return false;
+
+    pMetadataProperty->SetValue((u_int8_t*)value, 4);
+
+    return true;
+}
+
+bool MP4File::GetMetadataYear(char** value)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.�day.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    if (valSize > 0)
+    {
+        *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
+        memset(*value, 0, (valSize+1)*sizeof(unsigned char));
+        memcpy(*value, val, valSize*sizeof(unsigned char));
+        return true;
+    } else {
+        *value = NULL;
+        return false;
+    }
+}
+
+bool MP4File::SetMetadataTrack(u_int16_t track, u_int16_t totalTracks)
+{
+    unsigned char t[9];
+    const char *s = "moov.udta.meta.ilst.trkn.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("trkn"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    memset(t, 0, 9*sizeof(unsigned char));
+    t[2] = (unsigned char)(track>>8)&0xFF;
+    t[3] = (unsigned char)(track)&0xFF;
+    t[4] = (unsigned char)(totalTracks>>8)&0xFF;
+    t[5] = (unsigned char)(totalTracks)&0xFF;
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)t, 8);
+
+    return true;
+}
+
+bool MP4File::GetMetadataTrack(u_int16_t* track, u_int16_t* totalTracks)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.trkn.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    *track = 0;
+    *totalTracks = 0;
+
+    if (valSize != 8)
+        return false;
+
+    *track = (u_int16_t)(val[3]);
+    *track += (u_int16_t)(val[2]<<8);
+    *totalTracks = (u_int16_t)(val[5]);
+    *totalTracks += (u_int16_t)(val[4]<<8);
+
+    return true;
+}
+
+bool MP4File::SetMetadataDisk(u_int16_t disk, u_int16_t totalDisks)
+{
+    unsigned char t[9];
+    const char *s = "moov.udta.meta.ilst.disk.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("disk"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    memset(t, 0, 9*sizeof(unsigned char));
+    t[2] = (unsigned char)(disk>>8)&0xFF;
+    t[3] = (unsigned char)(disk)&0xFF;
+    t[4] = (unsigned char)(totalDisks>>8)&0xFF;
+    t[5] = (unsigned char)(totalDisks)&0xFF;
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)t, 8);
+
+    return true;
+}
+
+bool MP4File::GetMetadataDisk(u_int16_t* disk, u_int16_t* totalDisks)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.disk.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    *disk = 0;
+    *totalDisks = 0;
+
+    if (valSize != 8)
+        return false;
+
+    *disk = (u_int16_t)(val[3]);
+    *disk += (u_int16_t)(val[2]<<8);
+    *totalDisks = (u_int16_t)(val[5]);
+    *totalDisks += (u_int16_t)(val[4]<<8);
+
+    return true;
+}
+
+bool MP4File::SetMetadataGenre(u_int16_t genreIndex)
+{
+    unsigned char t[3];
+    const char *s = "moov.udta.meta.ilst.gnre.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("gnre"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    memset(t, 0, 3*sizeof(unsigned char));
+    t[0] = (unsigned char)(genreIndex>>8)&0xFF;
+    t[1] = (unsigned char)(genreIndex)&0xFF;
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)t, 2);
+
+    return true;
+}
+
+bool MP4File::GetMetadataGenre(u_int16_t* genreIndex)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.gnre.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    *genreIndex = 0;
+
+    if (valSize != 2)
+        return false;
+
+    *genreIndex = (u_int16_t)(val[1]);
+    *genreIndex += (u_int16_t)(val[0]<<8);
+
+    return true;
+}
+
+bool MP4File::SetMetadataTempo(u_int16_t tempo)
+{
+    unsigned char t[3];
+    const char *s = "moov.udta.meta.ilst.tmpo.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("tmpo"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    memset(t, 0, 3*sizeof(unsigned char));
+    t[0] = (unsigned char)(tempo>>8)&0xFF;
+    t[1] = (unsigned char)(tempo)&0xFF;
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue((u_int8_t*)t, 2);
+
+    return true;
+}
+
+bool MP4File::GetMetadataTempo(u_int16_t* tempo)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.tmpo.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    *tempo = 0;
+
+    if (valSize != 2)
+        return false;
+
+    *tempo = (u_int16_t)(val[1]);
+    *tempo += (u_int16_t)(val[0]<<8);
+
+    return true;
+}
+
+bool MP4File::SetMetadataCompilation(u_int8_t compilation)
+{
+    const char *s = "moov.udta.meta.ilst.cpil.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("cpil"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    compilation &= 0x1;
+    pMetadataProperty->SetValue((u_int8_t*)&compilation, 1);
+
+    return true;
+}
+
+bool MP4File::GetMetadataCompilation(u_int8_t* compilation)
+{
+    unsigned char *val = NULL;
+    u_int32_t valSize = 0;
+    const char *s = "moov.udta.meta.ilst.cpil.data.metadata";
+    GetBytesProperty(s, (u_int8_t**)&val, &valSize);
+
+    *compilation = 0;
+
+    if (valSize != 1)
+        return false;
+
+    *compilation = (u_int16_t)(val[0]);
+
+    return true;
+}
+
+bool MP4File::SetMetadataCoverArt(u_int8_t *coverArt, u_int32_t size)
+{
+    const char *s = "moov.udta.meta.ilst.covr.data";
+    MP4BytesProperty *pMetadataProperty = NULL;
+    MP4Atom *pMetaAtom = NULL;
+    
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+    {
+        if (!CreateMetadataAtom("covr"))
+            return false;
+
+        pMetaAtom = m_pRootAtom->FindAtom(s);
+    }
+
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+
+    pMetadataProperty->SetValue(coverArt, size);
+
+    return true;
+}
+
+bool MP4File::GetMetadataCoverArt(u_int8_t **coverArt, u_int32_t *size)
+{
+    const char *s = "moov.udta.meta.ilst.covr.data.metadata";
+    GetBytesProperty(s, coverArt, size);
+
+    if (size == 0)
+        return false;
+
+    return true;
+}
+
+bool MP4File::SetMetadataFreeForm(char *name, u_int8_t* pValue, u_int32_t valueSize)
+{
+    MP4Atom *pMetaAtom = NULL;
+    MP4BytesProperty *pMetadataProperty = NULL;
+    char s[256];
+    int i = 0;
+    bool nameExists = false;
+
+    while (1)
+    {
+        MP4BytesProperty *pMetadataProperty;
+
+        sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
+
+        MP4Atom *pTagAtom = m_pRootAtom->FindAtom(s);
+
+        if (!pTagAtom)
+            break;
+
+        pTagAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
+        if (pMetadataProperty)
+        {
+            u_int8_t* pV;
+            u_int32_t VSize = 0;
+
+            pMetadataProperty->GetValue(&pV, &VSize);
+
+            if (VSize != 0)
+            {
+                if (memcmp(pV, name, VSize) == 0)
+                {
+                    sprintf(s, "moov.udta.meta.ilst.----[%u].data.metadata", i);
+                    SetBytesProperty(s, pValue, valueSize);
+
+                    return true;
+                }
+            }
+        }
+
+        i++;
+    }
+
+    /* doesn't exist yet, create it */
+    char t[256];
+
+    sprintf(t, "udta.meta.ilst.----[%u]", i);
+    sprintf(s, "moov.udta.meta.ilst.----[%u].data", i);
+    AddDescendantAtoms("moov", t);
+
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    if (!pMetaAtom)
+        return false;
+
+    pMetaAtom->SetFlags(0x1);
+
+    MP4Atom *pHdlrAtom = m_pRootAtom->FindAtom("moov.udta.meta.hdlr");
+    MP4StringProperty *pStringProperty = NULL;
+    MP4BytesProperty *pBytesProperty = NULL;
+    ASSERT(pHdlrAtom);
+
+    pHdlrAtom->FindProperty(
+        "hdlr.handlerType", (MP4Property**)&pStringProperty);
+    ASSERT(pStringProperty);
+    pStringProperty->SetValue("mdir");
+
+    u_int8_t val[12];
+    memset(val, 0, 12*sizeof(u_int8_t));
+    val[0] = 0x61;
+    val[1] = 0x70;
+    val[2] = 0x70;
+    val[3] = 0x6c;
+    pHdlrAtom->FindProperty(
+        "hdlr.reserved2", (MP4Property**)&pBytesProperty);
+    ASSERT(pBytesProperty);
+    pBytesProperty->SetReadOnly(false);
+    pBytesProperty->SetValue(val, 12);
+    pBytesProperty->SetReadOnly(true);
+
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+    pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+    pMetadataProperty->SetValue(pValue, valueSize);
+
+    sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+    pMetaAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+    pMetadataProperty->SetValue((u_int8_t*)name, strlen(name));
+
+    sprintf(s, "moov.udta.meta.ilst.----[%u].mean", i);
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+    pMetaAtom->FindProperty("mean.metadata", (MP4Property**)&pMetadataProperty);
+    ASSERT(pMetadataProperty);
+    pMetadataProperty->SetValue((u_int8_t*)"com.apple.iTunes", 16); /* ?? */
+
+    return true;
+}
+
+bool MP4File::GetMetadataFreeForm(char *name, u_int8_t** ppValue, u_int32_t *pValueSize)
+{
+    char s[256];
+    int i = 0;
+
+    while (1)
+    {
+        MP4BytesProperty *pMetadataProperty;
+
+        sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
+
+        MP4Atom *pTagAtom = m_pRootAtom->FindAtom(s);
+
+        if (!pTagAtom)
+            return false;
+
+        pTagAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
+        if (pMetadataProperty)
+        {
+            u_int8_t* pV;
+            u_int32_t VSize = 0;
+
+            pMetadataProperty->GetValue(&pV, &VSize);
+
+            if (VSize != 0)
+            {
+                if (memcmp(pV, name, VSize) == 0)
+                {
+                    sprintf(s, "moov.udta.meta.ilst.----[%u].data.metadata", i);
+                    GetBytesProperty(s, ppValue, pValueSize);
+
+                    return true;
+                }
+            }
+        }
+
+        i++;
+    }
+}
+
+bool MP4File::MetadataDelete()
+{
+    MP4Atom *pMetaAtom = NULL;
+    char s[256];
+
+    sprintf(s, "moov.udta.meta");
+    pMetaAtom = m_pRootAtom->FindAtom(s);
+
+    /* if it exists, delete it */
+    if (pMetaAtom)
+    {
+        MP4Atom *pParent = pMetaAtom->GetParentAtom();
+
+        pParent->DeleteChildAtom(pMetaAtom);
+
+        delete pMetaAtom;
+
+        return true;
+    }
+
+    return false;
+}
--- a/common/mp4v2/mp4property.cpp
+++ b/common/mp4v2/mp4property.cpp
@@ -584,37 +584,6 @@
 	return false;
 }
 
-void MP4TableProperty::DeleteEntry(u_int32_t index)
-{
-    u_int32_t numProperties = m_pProperties.Size();
-
-	for (u_int32_t i = 0; i < numProperties; i++) {
-        switch (m_pProperties[i]->GetType()) {
-        case Integer8Property:
-            ((MP4Integer8Property*)m_pProperties[i])->DeleteValue(index);
-            break;
-        case Integer16Property:
-            ((MP4Integer16Property*)m_pProperties[i])->DeleteValue(index);
-            break;
-        case Integer24Property:
-            ((MP4Integer24Property*)m_pProperties[i])->DeleteValue(index);
-            break;
-        case Integer32Property:
-            ((MP4Integer32Property*)m_pProperties[i])->DeleteValue(index);
-            break;
-        case Integer64Property:
-            ((MP4Integer64Property*)m_pProperties[i])->DeleteValue(index);
-            break;
-        case StringProperty:
-            ((MP4StringProperty*)m_pProperties[i])->DeleteValue(index);
-            break;
-        default:
-            ASSERT(FALSE);
-            break;
-        }
-    }
-}
-
 void MP4TableProperty::Read(MP4File* pFile, u_int32_t index)
 {
 	ASSERT(index == 0);
--- a/common/mp4v2/mp4property.h
+++ b/common/mp4v2/mp4property.h
@@ -307,10 +307,6 @@
 		SetValue(value, count);
 	}
 
-    void DeleteValue(u_int32_t index) {
-        m_values.Delete(index);
-    }
-
 	bool IsCountedFormat() {
 		return m_useCountedFormat;
 	}
@@ -464,8 +460,6 @@
 
 	bool FindProperty(const char* name,
 		MP4Property** ppProperty, u_int32_t* pIndex = NULL);
-
-    void DeleteEntry(u_int32_t index);
 
 protected:
 	virtual void ReadEntry(MP4File* pFile, u_int32_t index);
--- a/common/mp4v2/mp4track.cpp
+++ b/common/mp4v2/mp4track.cpp
@@ -16,7 +16,8 @@
  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  * 
  * Contributor(s): 
- *		Dave Mackie		dmackie@cisco.com
+ *		Dave Mackie			dmackie@cisco.com
+ *		Alix Marchandise-Franquet	alix@cisco.com
  */
 
 #include "mp4common.h"
@@ -335,7 +336,7 @@
 }
 
 void MP4Track::WriteSample(
-	u_int8_t* pBytes, 
+	const u_int8_t* pBytes, 
 	u_int32_t numBytes,
 	MP4Duration duration, 
 	MP4Duration renderingOffset, 
@@ -823,7 +824,9 @@
 
 		if (sampleId <= sid + sampleCount - 1) {
 			if (pStartTime) {
-				*pStartTime = elapsed + ((sampleId - sid) * sampleDelta);
+			  *pStartTime = (sampleId - sid);
+			  *pStartTime *= sampleDelta;
+			  *pStartTime += elapsed;
 			}
 			if (pDuration) {
 				*pDuration = sampleDelta;
@@ -1350,7 +1353,8 @@
 {
 	if (!strcasecmp(type, "vide")
 	  || !strcasecmp(type, "video")
-	  || !strcasecmp(type, "mp4v")) {
+	  || !strcasecmp(type, "mp4v")
+	  || !strcasecmp(type, "encv")) {
 		return MP4_VIDEO_TRACK_TYPE;
 	}
 
@@ -1357,6 +1361,7 @@
 	if (!strcasecmp(type, "soun")
 	  || !strcasecmp(type, "sound")
 	  || !strcasecmp(type, "audio")
+	  || !strcasecmp(type, "enca")  // ismacrypt 
 	  || !strcasecmp(type, "mp4a")) {
 		return MP4_AUDIO_TRACK_TYPE;
 	}
--- a/common/mp4v2/mp4track.h
+++ b/common/mp4v2/mp4track.h
@@ -68,7 +68,7 @@
 		bool* pIsSyncSample = NULL);
 
 	void WriteSample(
-		u_int8_t* pBytes, 
+		const u_int8_t* pBytes, 
 		u_int32_t numBytes,
 		MP4Duration duration = 0,
 		MP4Duration renderingOffset = 0, 
--- a/common/mp4v2/mp4util.cpp
+++ b/common/mp4v2/mp4util.cpp
@@ -231,11 +231,7 @@
 
 	// final resort is to use floating point
 	double d = ((double)newTimeScale / (double)oldTimeScale) + 0.5;
-#ifdef _WINDOWS
-	d *= (double)(int64_t)t;
-#else
-	d *= (double)t;
-#endif
+	d *= UINT64_TO_DOUBLE(t);
 
 	return (u_int64_t)d;
 }
--- a/common/mp4v2/mp4util.h
+++ b/common/mp4v2/mp4util.h
@@ -210,7 +210,11 @@
 inline MP4Timestamp MP4GetAbsTimestamp() {
 	struct timeval tv;
 	gettimeofday(&tv, NULL);
-	return tv.tv_sec + 209606400;	// MP4 start date is 1/1/1904
+	MP4Timestamp ret;
+	ret = tv.tv_sec;
+	ret += 2082844800;
+	return ret;	// MP4 start date is 1/1/1904
+	// 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
 }
 
 u_int64_t MP4ConvertTime(u_int64_t t, 
--- a/common/mp4v2/rtphint.cpp
+++ b/common/mp4v2/rtphint.cpp
@@ -370,7 +370,9 @@
 	const char* payloadName,
 	u_int8_t payloadNumber,
 	u_int16_t maxPayloadSize, 
-	const char *encoding_parms)
+	const char *encoding_parms,
+	bool include_rtp_map,
+	bool include_mpeg4_esid)
 {
 	InitRefTrack();
 	InitPayload();
@@ -416,15 +418,22 @@
 
 	char* sdpBuf = (char*)MP4Malloc(
 		strlen(sdpMediaType) + strlen(rtpMapBuf) + 256);
-	sprintf(sdpBuf, 
-		"m=%s 0 RTP/AVP %u\015\012"
-		"a=rtpmap:%u %s\015\012"
-		"a=control:trackID=%u\015\012" 
-		"a=mpeg4-esid:%u\015\012",
-		sdpMediaType, payloadNumber,
-		payloadNumber, rtpMapBuf,
-		m_trackId,
-		m_pRefTrack->GetId());
+	uint32_t buflen;
+	buflen = sprintf(sdpBuf, 
+			 "m=%s 0 RTP/AVP %u\015\012"
+			 "a=control:trackID=%u\015\012",
+			 sdpMediaType, payloadNumber,
+			 m_trackId);
+	if (include_rtp_map) {
+	  buflen += sprintf(sdpBuf + buflen, 
+			    "a=rtpmap:%u %s\015\012",
+			    payloadNumber, rtpMapBuf);
+	}
+	if (include_mpeg4_esid) {
+	  sprintf(sdpBuf + buflen, 
+		  "a=mpeg4-esid:%u\015\012",
+		  m_pRefTrack->GetId());
+	}
 
 	MP4StringProperty* pSdpProperty = NULL;
 	m_pTrakAtom->FindProperty("trak.udta.hnti.sdp .sdpText",
--- a/common/mp4v2/rtphint.h
+++ b/common/mp4v2/rtphint.h
@@ -259,7 +259,9 @@
 		const char* payloadName,
 		u_int8_t payloadNumber,
 		u_int16_t maxPayloadSize,
-		const char *encoding_parms);
+		const char *encoding_parms,
+		bool add_rtpmap,
+		bool add_mpeg4_esid);
 
 	void ReadHint(
 		MP4SampleId hintSampleId,
--- a/common/mp4v2/systems.h
+++ b/common/mp4v2/systems.h
@@ -27,6 +27,7 @@
 #define HAVE_IN_PORT_T
 #define HAVE_SOCKLEN_T
 #include <win32_ver.h>
+#define NEED_SDL_VIDEO_IN_MAIN_THREAD
 #else
 #undef PACKAGE
 #undef VERSION
@@ -35,10 +36,13 @@
 
 
 
+
 #ifdef WIN32
 
 #define _WIN32_WINNT 0x0400
+#define _WINSOCKAPI_
 #include <windows.h>
+#include <winsock2.h>
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -58,7 +62,7 @@
 typedef __int16 int16_t;
 typedef __int8  int8_t;
 typedef unsigned short in_port_t;
-typedef unsigned int socklen_t;
+typedef int socklen_t;
 typedef int ssize_t;
 #define snprintf _snprintf
 #define strncasecmp _strnicmp
@@ -96,6 +100,7 @@
 #define LLD "%I64d"
 #define LLU "%I64u"
 #define LLX "%I64x"
+#define LLX16 "%016I64x"
 #define M_LLU 1000i64
 #define C_LLU 100i64
 #define I_LLU 1i64
@@ -122,8 +127,26 @@
 #define FOPEN_READ_BINARY "rb"
 #define FOPEN_WRITE_BINARY "wb"
 
+#define UINT64_TO_DOUBLE(a) ((double)((int64_t)(a)))
 #else /* UNIX */
+/*****************************************************************************
+ *   UNIX LIKE DEFINES BELOW THIS POINT
+ *****************************************************************************/
+#ifdef sun
+#include <sys/feature_tests.h>
+#endif
 
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#else
+#if _FILE_OFFSET_BITS < 64
+#error File offset bits is already set to non-64 value
+#endif
+#endif
+
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE
+#endif
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -150,7 +173,16 @@
 #include <ctype.h>
 #include <netdb.h>
 #include <sys/stat.h>
+#ifdef TIME_WITH_SYS_TIME
 #include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
 #include <sys/param.h>
 
 #define OPEN_RDWR O_RDWR
@@ -163,6 +195,7 @@
 #define LLD "%lld"
 #define LLU "%llu"
 #define LLX "%llx"
+#define LLX16 "%016llx"
 #define M_LLU 1000LLU
 #define C_LLU 100LLU
 #define I_LLU 1LLU
@@ -176,8 +209,12 @@
 
 #define FOPEN_READ_BINARY "r"
 #define FOPEN_WRITE_BINARY "w"
+#define UINT64_TO_DOUBLE(a) ((double)(a))
 #endif /* define unix */
 
+/*****************************************************************************
+ *             Generic type includes used in the whole package               *
+ *****************************************************************************/
 #include <stdarg.h>
 typedef void (*error_msg_func_t)(int loglevel,
 				 const char *lib,
@@ -228,7 +265,10 @@
 
 #define MALLOC_STRUCTURE(a) ((a *)malloc(sizeof(a)))
 
-#define CHECK_AND_FREE(a) if ((a) != NULL) { free((a)); (a) = NULL;}
+#define CHECK_AND_FREE(a) if ((a) != NULL) { free((void *)(a)); (a) = NULL;}
+
+#define NUM_ELEMENTS_IN_ARRAY(name) ((sizeof((name))) / (sizeof(*(name))))
+
 #ifndef HAVE_GLIB_H
 typedef char gchar;
 typedef unsigned char guchar;
@@ -264,7 +304,6 @@
 #ifndef FALSE
 #define FALSE 0
 #endif
-
 
 #endif /* __SYSTEMS_H__ */
 
--- a/common/mp4v2/win32_ver.h
+++ b/common/mp4v2/win32_ver.h
@@ -1,2 +1,2 @@
 #define PACKAGE "mpeg4ip"
-#define VERSION "0.9.7.2"
+#define VERSION "0.9.8.6"
--- a/plugins/foo_mp4/foo_mp4.cpp
+++ b/plugins/foo_mp4/foo_mp4.cpp
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: foo_mp4.cpp,v 1.34 2003/06/25 19:18:35 menno Exp $
+** $Id: foo_mp4.cpp,v 1.35 2003/06/29 21:41:00 menno Exp $
 **/
 
 #include <mp4.h>
@@ -44,7 +44,7 @@
 #endif
 
 DECLARE_COMPONENT_VERSION ("MPEG-4 AAC decoder",
-                           "$Revision: 1.34 $",
+                           "$Revision: 1.35 $",
                            "Based on FAAD2 v" FAAD2_VERSION "\nCopyright (C) 2002-2003 http://www.audiocoding.com" );
 
 class input_mp4 : public input
@@ -209,6 +209,7 @@
 
     virtual int set_info(reader *r,const file_info * info)
     {
+#if 0
         m_reader = r;
 
         hFile = MP4ModifyCb(0, 0, open_cb, close_cb, read_cb, write_cb,
@@ -257,6 +258,82 @@
 
         /* end */
         return 1;
+#else
+        m_reader = r;
+
+        hFile = MP4ModifyCb(0, 0, open_cb, close_cb, read_cb, write_cb,
+            setpos_cb, getpos_cb, filesize_cb, (void*)m_reader);
+        if (hFile == MP4_INVALID_FILE_HANDLE) return 0;
+
+        MP4MetadataDelete(hFile);
+
+        /* replay gain writing */
+        const char *p = NULL;
+
+        p = info->info_get("REPLAYGAIN_TRACK_PEAK");
+        if (p)
+            MP4SetMetadataFreeForm(hFile, "REPLAYGAIN_TRACK_PEAK", (unsigned __int8*)p, strlen(p));
+        p = info->info_get("REPLAYGAIN_TRACK_GAIN");
+        if (p)
+            MP4SetMetadataFreeForm(hFile, "REPLAYGAIN_TRACK_GAIN", (unsigned __int8*)p, strlen(p));
+        p = info->info_get("REPLAYGAIN_ALBUM_PEAK");
+        if (p)
+            MP4SetMetadataFreeForm(hFile, "REPLAYGAIN_ALBUM_PEAK", (unsigned __int8*)p, strlen(p));
+        p = info->info_get("REPLAYGAIN_ALBUM_GAIN");
+        if (p)
+            MP4SetMetadataFreeForm(hFile, "REPLAYGAIN_ALBUM_GAIN", (unsigned __int8*)p, strlen(p));
+
+        int numItems = info->meta_get_count();
+        if (numItems > 0)
+        {
+            for (int i = 0; i < numItems; i++)
+            {
+                char *pName = (char*)info->meta_enum_name(i);
+                const char *val = info->meta_enum_value(i);
+
+                if (strcmp(pName, "TITLE") == 0)
+                {
+                    MP4SetMetadataName(hFile, val);
+                } else if (strcmp(pName, "ARTIST") == 0) {
+                    MP4SetMetadataArtist(hFile, val);
+                } else if (strcmp(pName, "WRITER") == 0) {
+                    MP4SetMetadataWriter(hFile, val);
+                } else if (strcmp(pName, "ALBUM") == 0) {
+                    MP4SetMetadataAlbum(hFile, val);
+                } else if (strcmp(pName, "YEAR") == 0) {
+                    MP4SetMetadataYear(hFile, val);
+                } else if (strcmp(pName, "TOOL") == 0) {
+                    MP4SetMetadataTool(hFile, val);
+                } else if (strcmp(pName, "COMMENT") == 0) {
+                    MP4SetMetadataComment(hFile, val);
+                } else if (strcmp(pName, "GENRE") == 0) {
+                    unsigned __int16 genre = 0;
+                    MP4SetMetadataGenre(hFile, genre);
+                } else if (strcmp(pName, "TRACKNUMBER") == 0) {
+                    unsigned __int16 trkn = 0, tot = 0;
+                    sscanf(val, "%d", &trkn);
+                    MP4SetMetadataTrack(hFile, trkn, tot);
+                } else if (strcmp(pName, "DISKNUMBER") == 0) {
+                    unsigned __int16 disk = 0, tot = 0;
+                    sscanf(val, "%d", &disk);
+                    MP4SetMetadataDisk(hFile, disk, tot);
+                } else if (strcmp(pName, "COMPILATION") == 0) {
+                    unsigned __int8 cpil = 0;
+                    sscanf(val, "%d", &cpil);
+                    MP4SetMetadataCompilation(hFile, cpil);
+                } else if (strcmp(pName, "TEMPO") == 0) {
+                    unsigned __int16 tempo = 0;
+                    sscanf(val, "%d", &tempo);
+                    MP4SetMetadataTempo(hFile, tempo);
+                } else {
+                    MP4SetMetadataFreeForm(hFile, pName, (unsigned __int8*)val, strlen(val));
+                }
+            }
+        }
+
+        /* end */
+        return 1;
+#endif
     }
 
     virtual int seek(double seconds)
@@ -288,32 +365,96 @@
 
     int ReadMP4Tag(file_info *info)
     {
-        int numItems = MP4TagGetNumEntries(hFile, track);
+        unsigned __int32 valueSize = 0;
+        unsigned __int8* pValue;
+        char* pName;
+        int i = 0;
 
-        for (int i = 0; i < numItems; i++)
-        {
-            float f = 0.0;
-            const char *n = NULL, *v = NULL;
+        do {
+            valueSize = 0;
 
-            MP4TagGetEntry(hFile, track, i, &n, &v);
+            MP4GetMetadataByIndex(hFile, i, (const char**)&pName, &pValue, &valueSize);
 
-            if (!strcmp(n, "REPLAYGAIN_TRACK_PEAK"))
+            if (valueSize > 0)
             {
-                sscanf(v, "%f", &f);
-                info->info_set_replaygain_track_peak((double)f);
-            } else if (!strcmp(n, "REPLAYGAIN_TRACK_GAIN")) {
-                sscanf(v, "%f", &f);
-                info->info_set_replaygain_track_gain((double)f);
-            } else if (!strcmp(n, "REPLAYGAIN_ALBUM_PEAK")) {
-                sscanf(v, "%f", &f);
-                info->info_set_replaygain_album_peak((double)f);
-            } else if (!strcmp(n, "REPLAYGAIN_ALBUM_GAIN")) {
-                sscanf(v, "%f", &f);
-                info->info_set_replaygain_album_gain((double)f);
-            } else {
-                info->meta_add(n, v);
+                char* val = (char*)malloc((valueSize+1)*sizeof(char));
+                memset(val, 0, (valueSize+1)*sizeof(char));
+                memcpy(val, pValue, valueSize*sizeof(char));
+
+                if (pName[0] == '�')
+                {
+                    if (memcmp(pName, "�nam", 4) == 0)
+                    {
+                        info->meta_add("TITLE", val);
+                    } else if (memcmp(pName, "�ART", 4) == 0) {
+                        info->meta_add("ARTIST", val);
+                    } else if (memcmp(pName, "�wrt", 4) == 0) {
+                        info->meta_add("WRITER", val);
+                    } else if (memcmp(pName, "�alb", 4) == 0) {
+                        info->meta_add("ALBUM", val);
+                    } else if (memcmp(pName, "�day", 4) == 0) {
+                        info->meta_add("YEAR", val);
+                    } else if (memcmp(pName, "�too", 4) == 0) {
+                        info->meta_add("TOOL", val);
+                    } else if (memcmp(pName, "�cmt", 4) == 0) {
+                        info->meta_add("COMMENT", val);
+                    } else {
+                        info->meta_add(pName, val);
+                    }
+                } else if (memcmp(pName, "gnre", 4) == 0) {
+                    unsigned __int16 genre = 0;
+                    char t[200];
+                    MP4GetMetadataGenre(hFile, &genre);
+                    wsprintf(t, "%d", genre);
+                    info->meta_add("GENRE", t);
+                } else if (memcmp(pName, "trkn", 4) == 0) {
+                    unsigned __int16 trkn = 0, tot = 0;
+                    char t[200];
+                    MP4GetMetadataTrack(hFile, &trkn, &tot);
+                    wsprintf(t, "%d", trkn);
+                    info->meta_add("TRACKNUMBER", t);
+                } else if (memcmp(pName, "disk", 4) == 0) {
+                    unsigned __int16 disk = 0, tot = 0;
+                    char t[200];
+                    MP4GetMetadataDisk(hFile, &disk, &tot);
+                    wsprintf(t, "%d", disk);
+                    info->meta_add("DISKNUMBER", t);
+                } else if (memcmp(pName, "cpil", 4) == 0) {
+                    unsigned __int8 cpil = 0;
+                    char t[200];
+                    MP4GetMetadataCompilation(hFile, &cpil);
+                    wsprintf(t, "%d", cpil);
+                    info->meta_add("COMPILATION", t);
+                } else if (memcmp(pName, "tmpo", 4) == 0) {
+                    unsigned __int16 tempo = 0;
+                    char t[200];
+                    MP4GetMetadataTempo(hFile, &tempo);
+                    wsprintf(t, "%d BPM", tempo);
+                    info->meta_add("TEMPO", t);
+                } else {
+                    float f = 0;
+                    if (!strcmp(pName, "REPLAYGAIN_TRACK_PEAK"))
+                    {
+                        sscanf(val, "%f", &f);
+                        info->info_set_replaygain_track_peak((double)f);
+                    } else if (!strcmp(pName, "REPLAYGAIN_TRACK_GAIN")) {
+                        sscanf(val, "%f", &f);
+                        info->info_set_replaygain_track_gain((double)f);
+                    } else if (!strcmp(pName, "REPLAYGAIN_ALBUM_PEAK")) {
+                        sscanf(val, "%f", &f);
+                        info->info_set_replaygain_album_peak((double)f);
+                    } else if (!strcmp(pName, "REPLAYGAIN_ALBUM_GAIN")) {
+                        sscanf(val, "%f", &f);
+                        info->info_set_replaygain_album_gain((double)f);
+                    } else {
+                        info->meta_add(pName, val);
+                    }
+                }
             }
-        }
+
+            i++;
+
+        } while (valueSize > 0);
 
         return 1;
     }