[Helix-client-dev] CR (Resend): Extended support for iTunes meta-info in datatype projects

Petar Basic <[email protected]> Tue, 20 Oct 2009 20:14:42 +0200
Newsgroups gmane.comp.multimedia.helix.devel
Message-ID <[email protected]>
Modified by: pbasic at real.com
Date: 2009/10/19
Project: GMP MetaEditor (meta3gp.exe)

Synopsis:
Extended support for iTunes meta-info in datatype projects

Overview:
GMP MetaEditor tool must support both 3GPP and iTunes meta-info
flavors in MP4-based files.  iTunes metadata boxes were only partially
supported in MP4 file-writer and so far unsupported in MP4
file-format.  This CR adds support for standard iTunes tags minus the
Cover Art ('covr') tag which will be addressed separately.

The following iTunes tags are now supported:
Album Name (@alb)
Artist(@ART)
User Comment(@cmt)
Copyright (cprt)
Release Date (@day)
Encoded By (@enc)
Pre-defined Genre (gnre)
User Genre (@gen)
Song Name (@nam)
Track Sub-Title (@st3)
Encoding Tool (@too)
Composer (@wrt)
Album Artist (aART)
Disc Compilation (cpil)
Disc Number (disk)
Grouping (@grp)
Lyrics (@lyr)
Content Rating (rtng)
Beats Per Minute (tmpo)
Track Number (@trkn)

File-writer takes into account common expectations of other software
packages and outputs atoms accordingly.  For this reason, the length
of values in string atoms except @lyr is currently limited to 255
characters.  UTF8 and UTF16BE output is fully supported except for
@lyr which must be in UTF8 format.  Only year portion of @day atom is
read/written as the full date seems unimportant to most other software
(e.g. iTunes9 also allows input of the year part only).

Details:
1.) Fixed a bug in EncStrUtils::ConvertUTF8ToUTF16.

2.) Updated project dependencies in helix.bif.

3.) Added iTunes meta-flavor definition to ihxmetaeditor.h.

4.) Updated meta-info key defines in metainfokeys.h.  The keys have
been split in several non-overlapping sets.  Currently defined are
Generic set, iTunes specific set, 3GPP specific set.  Key sets can be
combined where needed.  Some aliases in specific sets have been
defined which reference keys in the generic set.

5.) Moved MetaInfo3GP utilities from meta3gp project into
common/util/metautil.cpp module.  Renamed utility class to MetaInfo.
This class simplifies processing of meta-info properties in
file-headers, stream-headers, etc.  It can also be used as a simpler
temporary C++-style container for meta-info values; export/import
to/from Helix IHXValues container is supported.

6.) Updated code in dtdriver/common/decoder, dtdriver/common/engine,
datatype/tools/metaeditor to use MetaInfo class utilities.  All
available meta-info is now always transferred between headers in
FFDriver components.

7.) Metaeditor's source handler now transfers all available meta-info
properties between headers and leaves meta-info set/flavor filtering
to IHXMetaDataProcessor.

8.) Updated and refactored command line processing in meta3gp
executable project according to GMP MetaEditor specs.  Both flavors of
meta-data (3GPP, iTunes) can be injected into the same media-file by
specifying the -metastyle switch multiple times.

9.) Merged MP4 atom handling improvements from 310Atlas:
 A.) MP4 fileformat's atomizer had to be extended to handle
non-standard size (versioned) container atoms.  Until now it was
assumed that each container has 8 byte header - e.g. 'meta' atom uses
12 bytes.
 B.) MP4 fileformat has been extended with 'meta' and 'ID32'
definitions. ID32 Tags found at track level are handled by TrackInfo
manager and are inserted into the stream header of the corresponding
stream.
 C.) Removed dead code (TypedChildIterator) in MP4 fileformat.
 D.) MP4 filewriter has been extended with 'meta' and 'ID32'
definitions.  Stream mixer outputs the ID3v2 tag to the following atom
path: /file/moov/meta/ID32.
 E.) MP4 filewriter writes out the ID32 meta data as part of the moov
or trak meta box depending on the location (file or stream header) of
the ID32 blob.

10.) MP4 filewriter has been updated to respect MetaDataFlavor
configuration option and can therefore update both flavors of
meta-data into the same media-file.  Added/extended iTunes atom
definitions and atom tree builder methods.

11.) MP4 fileformat has been updated to read iTunes meta tags.
Added/extended iTunes atom definitions and atom tree builder methods.
CreateQTAtom method now takes additional parameter specifying the
current tree root - this was needed because there is some overlap
among flavor atom names (3GPP gnre/iTunes gnre, 3GPP cprt/iTunes cprt,
3GPP rtng/iTunes rntg).  The tree builder needs current root type to
decide the context of creation and to create an atom of the correct
class (iTunes or 3GPP).  Since both flavors of metadata can now be
encountered inside a single media-file, some extraction method
prioritization has been implemented based on MajorBrand value.  By
default, 3GPP info will overwrite iTunes info.  In case of M4A brand,
iTunes info will overwrite 3GPP info.  The reader is not subject to
artificial 255 characters limitation in iTunes strings; it also
tolerates various deviations from the iTMF spec where it is safe and
possible to do so.

Testing:
Verified that meta-info injected by GMP MetaEditor can be read with
other software (iTunes 9, AtomicParsley 0.9, CT metadata extractor
1.3).  Verified that meta-info injected by other software can be read
with GMP MetaEditor.

Files Modified:
common/include/ihxmetaeditor.h
common/util/encstr.cpp
datatype/include/metainfokeys.h
datatype/common/util/metautil.cpp
datatype/common/util/pub/metautil.h
datatype/common/util/Umakefil
datatype/tools/dtdriver/common/Umakefil
datatype/tools/dtdriver/decoder/audio/Umakefil
datatype/tools/dtdriver/decoder/audio/adecoder.cpp
datatype/tools/dtdriver/decoder/video/Umakefil
datatype/tools/dtdriver/decoder/video/vdecoder.cpp
datatype/tools/dtdriver/decoder/video/vdepacker.cpp
datatype/tools/dtdriver/engine/pub/ffdriver.h
datatype/tools/dtdriver/engine/ffdriver.cpp
datatype/tools/dtdriver/engine/Umakefil
datatype/tools/dtdriver/apps/meta3gp/main.cpp
datatype/tools/dtdriver/apps/meta3gp/Umakefil_meta3gp
datatype/tools/metaeditor/srchandler.cpp
datatype/tools/metaeditor/srchandler.h
datatype/tools/metaeditor/Umakefil
datatype/mp4/fileformat/atomizer.cpp
datatype/mp4/fileformat/pub/atomizer.h
datatype/mp4/fileformat/qtatoms.cpp
datatype/mp4/fileformat/pub/qtatoms.h
datatype/mp4/fileformat/qtatmmgs.cpp
datatype/mp4/fileformat/pub/qtatmmgs.h
datatype/mp4/fileformat/qtffplin.cpp
datatype/mp4/fileformat/pub/qtffplin.h
datatype/mp4/fileformat/pub/qtbatom.h
datatype/mp4/fileformat/dllumakefil
datatype/mp4/fileformat/libumakefil
datatype/mp4/filewriter/3gpmeta.h
datatype/mp4/filewriter/3gpmeta.cpp
datatype/mp4/filewriter/mp4sm.h
datatype/mp4/filewriter/mp4sm.cpp
datatype/mp4/filewriter/m4amdatoms.h
datatype/mp4/filewriter/mp4atoms.h

Files Removed:
datatype/tools/metaeditor/metautil3gp.cpp
datatype/tools/metaeditor/pub/metautil3gp.h
datatype/tools/metaeditor/Umakefile_3gp_lib
datatype/tools/metaeditor/Umakefile_dll

Platforms and Profiles Affected:
All

Image Size and Heap Use impact:
Small increase

Platforms and Profiles Build Verified:
system id: win32-i386-vc7
profile: helix-client-all-defines

Platforms and Profiles Functionality Verified:
x86 Windows XP SP2

Branch:
HEAD

Copyright assignment:
I am a RealNetworks employee or contractor.

_______________________________________________
Helix-client-dev mailing list
[email protected]
http://lists.helixcommunity.org/mailman/listinfo/helix-client-dev
common_include.diff (text/x-patch, 2.5 KB)
Index: ihxmetaeditor.h
===================================================================
RCS file: /cvsroot/common/include/ihxmetaeditor.h,v
retrieving revision 1.1
diff -d -H -b -B -w -U30 -r1.1 ihxmetaeditor.h
--- ihxmetaeditor.h	5 Nov 2007 21:32:45 -0000	1.1
+++ ihxmetaeditor.h	19 Oct 2009 17:39:52 -0000
@@ -58,62 +58,63 @@
 #include "hxcomptr.h"
 #include "hxsrcin.h"
 
 
 /****************************************************************************
  *
  *  Additional options (datatype-driver-chain):
  *
  *  METADATAFLAVOR_OPTION_NAME - ULONG32, value must be one of METADATA_FLAVOR
  *      constants. Notifies components about the flavor of meta-data they are
  *      about to process.
  *
  *  BLASTMETADATA_OPTION_NAME - ULONG32, if !=0, the meta-data incoming
  *      from the source will be erased before any new meta-data is added.
  *      Otherwise, new and existing meta-data will be merged.
  *  
  */
 #define METADATAFLAVOR_OPTION_NAME  "MetaDataFlavor"
 #define BLASTMETADATA_OPTION_NAME   "BlastMetaData"
 
 
 /****************************************************************************
  *
  *  Meta-data flavors:
  *  Used by meta-data source-handler and meta-data processors to
  *  extract/inject correct set of properties from/to file-header.
  *
  */
 typedef enum 
 {
-    METADATA_FLAVOR_UNKNOWN = 0,
-    METADATA_FLAVOR_3GP
+    METADATA_FLAVOR_3GPP    = 0x00000010,
+    METADATA_FLAVOR_ITUNES  = 0x00000100,
+    METADATA_FLAVOR_ALL = METADATA_FLAVOR_3GPP | METADATA_FLAVOR_ITUNES
 } METADATA_FLAVOR;
 
 
 /****************************************************************************
  *
  *  Interface:
  *	IHXMetaDataProcessor
  *
  *  Purpose:
  *      Used by IHXMetaDataSourceHandler to process meta-data. Clients
  *      can implement this interface if there is a need for special processing.
  *      Meta-data editor provides default processor implementation.
  *
  *  IID_IHXMetaDataProcessor
  *      {241640A0-E73C-46a3-AA62-6C130BE884D6}

  *

  */
 DEFINE_GUID(IID_IHXMetaDataProcessor,

             0x241640a0, 0xe73c, 0x46a3, 0xaa, 0x62, 0x6c, 0x13, 0x0b, 0xe8, 0x84, 0xd6);

 
 #undef  INTERFACE
 #define INTERFACE   IHXMetaDataProcessor
 
 DECLARE_INTERFACE_(IHXMetaDataProcessor, IUnknown)
 {
     /****************************************************************************
      *  Method:
      *       IHXMetaDataProcessor::InitMetaDataProcessor()
      *  Purpose:
      *       Called to initialize MetaDataProcessor. May be called multiple times
common_util.diff (text/x-patch, 2.2 KB)
Index: encstr.cpp
===================================================================
RCS file: /cvsroot/common/util/encstr.cpp,v
retrieving revision 1.5
diff -d -H -b -B -w -U30 -r1.5 encstr.cpp
--- encstr.cpp	29 Feb 2008 13:40:22 -0000	1.5
+++ encstr.cpp	19 Oct 2009 17:39:59 -0000
@@ -579,61 +579,62 @@
                     break;
             }
             memcpy(pszCopy + 2, psz, len);
         }
     }
     return pszCopy;
 }
 
 char* EncStrUtils::ConvertUTF8ToUTF16(const char* psz, HXBOOL bBigEndian, HXBOOL bPrependBOM, UINT32 allocFlags)
 {
     if(!psz)
     {
         return 0;
     }
     UINT32 numConsumed = 0;
     UINT32 numOutputed = 0;
     if(::ConvertUTF8StringToUTF16String((const UINT8*)psz, MAX_UINT32, numConsumed,
                                 0, 0, numOutputed, bBigEndian) < 0)
     {
         return 0; //conversion error
     }
     if(numOutputed)
     {
         if(bPrependBOM)
         {
             numOutputed += 1;
         }
         char* pszOut = EncStrUtils::Allocate(numOutputed * 2, allocFlags);
         if(pszOut && ::ConvertUTF8StringToUTF16String((const UINT8*)psz, MAX_UINT32, numConsumed,
                             (UINT16*)(bPrependBOM ? pszOut + 2 : pszOut),
-                            numOutputed - 1, numOutputed, bBigEndian) < 0)
+                            (bPrependBOM ? numOutputed - 1 : numOutputed),
+                            numOutputed, bBigEndian) < 0)
         {
             EncStrUtils::Deallocate(pszOut, allocFlags);
             return 0; //conversion error
         }
         if(bPrependBOM)
         {
             EncStrUtils::WriteUTF16BOM(pszOut, bBigEndian);
         }
         return pszOut;
     }
     return 0;
 }
 
 char* EncStrUtils::ConvertUTF16ToUTF8(const char* psz, HX_TEXT_ENCODING_TYPE enc, UINT32 allocFlags)
 {
     if(!psz)
     {
         return 0;
     }
     // check encoding
     HXBOOL bBigEndian = TRUE;
     switch(enc)
     {
         case HX_TEXT_ENCODING_TYPE_UTF16:
         case HX_TEXT_ENCODING_TYPE_UTF16BE:
             break;
         case HX_TEXT_ENCODING_TYPE_UTF16LE:
             bBigEndian = FALSE;
             break;
datatype_common_util.diff (text/x-patch, 67.3 KB)
Index: Umakefil
===================================================================
RCS file: /cvsroot/datatype/common/util/Umakefil,v
retrieving revision 1.14
diff -d -H -b -B -w -U30 -r1.14 Umakefil
--- Umakefil	14 Nov 2008 21:46:28 -0000	1.14
+++ Umakefil	19 Oct 2009 17:41:07 -0000
@@ -30,51 +30,52 @@
 # use your version of this file under the terms of any one of the
 # RPSL, the RCSL or the GPL.
 # 
 # This file is part of the Helix DNA Technology. RealNetworks is the
 # developer of the Original Code and owns the copyrights in the
 # portions it created.
 # 
 # This file, and the files included with this file, is distributed
 # and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 # KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 # ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 # ENJOYMENT OR NON-INFRINGEMENT.
 # 
 # Technology Compatibility Kit Test Suite(s) Location:
 #    http://www.helixcommunity.org/content/tck
 # 
 # Contributor(s):
 # 
 # ***** END LICENSE BLOCK *****
 # 
 
 UmakefileVersion(2,1)
 
 project.AddModuleIncludes(  "common/include",
 			    "common/system/pub",
 			    "common/dbgtool/pub",
 			    "common/util/pub",
 			    "common/container/pub",
 			    "common/runtime/pub",
-			    "common/log/logutil/pub")
+			    "common/log/logutil/pub",
+                "datatype/include")
 
 project.AddSources("bitstream.cpp",
                    "bitpack.cpp",
                    "riff.cpp",
                    "deintl.cpp",                   
                    "invtelec.cpp",                   
                    "resize.cpp",                   
                    "pyldparse.cpp",
                    "pxtransp.cpp",
                    "metautil.cpp",
                    "sspayld.cpp",
                    "getreqhdr.cpp",
                    "adjtime.cpp")
 
 if "HELIX_FEATURE_STATS" in project.defines:
 	project.AddSources('rendstats.cpp')
 
 LibraryTarget('dtutillib')
 
 DependTarget()
Index: metautil.cpp
===================================================================
RCS file: /cvsroot/datatype/common/util/metautil.cpp,v
retrieving revision 1.7
diff -d -H -b -B -w -U30 -r1.7 metautil.cpp
--- metautil.cpp	6 Jul 2007 22:00:23 -0000	1.7
+++ metautil.cpp	19 Oct 2009 17:41:09 -0000
@@ -26,60 +26,65 @@
  * or RCSL, indicate your decision by deleting the provisions above
  * and replace them with the notice and other provisions required by
  * the GPL. If you do not delete the provisions above, a recipient may
  * use your version of this file under the terms of any one of the
  * RPSL, the RCSL or the GPL.
  * 
  * This file is part of the Helix DNA Technology. RealNetworks is the
  * developer of the Original Code and owns the copyrights in the
  * portions it created.
  * 
  * This file, and the files included with this file, is distributed
  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  * ENJOYMENT OR NON-INFRINGEMENT.
  * 
  * Technology Compatibility Kit Test Suite(s) Location:
  *    http://www.helixcommunity.org/content/tck
  * 
  * Contributor(s):
  * 
  * ***** END LICENSE BLOCK ***** */
 
 #include "hlxclib/string.h"
 #include "hxtypes.h"
 #include "hxcom.h"
 #include "ihxpckts.h"
 #include "hxfiles.h"
 #include "hxccf.h"
+#include "iso639.h"
+#include "proptools.h"
+
+#include "metautil.h"
+
 
 HX_RESULT CheckMetaInfoRequest(IHXRequest*            pRequest,
                                IHXCommonClassFactory* pFactory,
                                REF(HXBOOL)              rbAcceptMetaInfoPresent,
                                REF(HXBOOL)              rbAllMetaInfoRequested,
                                REF(IHXValues*)        rpRequestedMetaInfo)
 {
     HX_RESULT retVal = HXR_FAIL;
 
     if (pRequest && pFactory)
     {
         IHXValues* pReqHdrs = NULL;
         retVal = pRequest->GetRequestHeaders(pReqHdrs);
         if (SUCCEEDED(retVal) && pReqHdrs)
         {
             IHXBuffer* pBuffer = NULL;
             pReqHdrs->GetPropertyCString("AcceptMetaInfo", pBuffer);
             if (pBuffer)
             {
                 // "AcceptMetaInfo" is present
                 rbAcceptMetaInfoPresent = TRUE;
                 // Get the string to examine
                 const char* pszStr = (const char*) pBuffer->GetBuffer();
                 // Check if it's "*"
                 if (!strcmp(pszStr, "*"))
                 {
                     // All meta info is requested
                     rbAllMetaInfoRequested = TRUE;
                     rpRequestedMetaInfo    = NULL;
                 }
@@ -119,30 +124,1348 @@
                     }
                     else
                     {
                         // AcceptMetaInfo was present, but there
                         // weren't any valid strings in it, so we fail
                         retVal = HXR_FAIL;
                     }
                     // Release the values
                     HX_RELEASE(pInfo);
                 }
             }
             else
             {
                 // "AcceptMetaInfo" is not present in
                 // the request headers
                 rbAcceptMetaInfoPresent = FALSE;
             }
             HX_RELEASE(pBuffer);
         }
         else
         {
             // No request headers
             rbAcceptMetaInfoPresent = FALSE;
         }
         HX_RELEASE(pReqHdrs);
     }
 
     return retVal;
 }
 
+const char* const g_ID3_genres[] = {
+    "Blues", //0
+    "Classic Rock",
+    "Country",
+    "Dance",
+    "Disco",
+    "Funk", //5
+    "Grunge",
+    "Hip-Hop",
+    "Jazz",
+    "Metal",
+    "New Age", //10
+    "Oldies",
+    "Other",
+    "Pop",
+    "R&B",
+    "Rap", //15
+    "Reggae",
+    "Rock",
+    "Techno",
+    "Industrial",
+    "Alternative", //20
+    "Ska",
+    "Death Metal",
+    "Pranks",
+    "Soundtrack",
+    "Euro-Techno", //25
+    "Ambient",
+    "Trip-Hop",
+    "Vocal",
+    "Jazz+Funk",
+    "Fusion", //30
+    "Trance",
+    "Classical",
+    "Instrumental",
+    "Acid",
+    "House", //35
+    "Game",
+    "Sound Clip",
+    "Gospel",
+    "Noise",
+    "AlternRock", //40
+    "Bass",
+    "Soul",
+    "Punk",
+    "Space",
+    "Meditative", //45
+    "Instrumental Pop",
+    "Instrumental Rock",
+    "Ethnic",
+    "Gothic",
+    "Darkwave", //50
+    "Techno-Industrial",
+    "Electronic",
+    "Pop-Folk",
+    "Eurodance",
+    "Dream", //55
+    "Southern Rock",
+    "Comedy",
+    "Cult",
+    "Gangsta",
+    "Top 40", //60
+    "Christian Rap",
+    "Pop/Funk",
+    "Jungle",
+    "Native American",
+    "Cabaret", //65
+    "New Wave",
+    "Psychadelic",
+    "Rave",
+    "Showtunes",
+    "Trailer", //70
+    "Lo-Fi",
+    "Tribal",
+    "Acid Punk",
+    "Acid Jazz",
+    "Polka", //75
+    "Retro",
+    "Musical",
+    "Rock & Roll",
+    "Hard Rock",
+
+    // Winamp extensions
+    "Folk", //80
+    "Folk-Rock",
+    "National Folk",
+    "Swing",
+    "Fast Fusion",
+    "Bebob", //85
+    "Latin",
+    "Revival",
+    "Celtic",
+    "Bluegrass",
+    "Avantgarde", //90
+    "Gothic Rock",
+    "Progressive Rock",
+    "Psychedelic Rock",
+    "Symphonic Rock",
+    "Slow Rock", //95
+    "Big Band",
+    "Chorus",
+    "Easy Listening",
+    "Acoustic",
+    "Humour", //100
+    "Speech",
+    "Chanson",
+    "Opera",
+    "Chamber Music",
+    "Sonata", //105
+    "Symphony",
+    "Booty Bass",
+    "Primus",
+    "Porn Groove",
+    "Satire", //110
+    "Slow Jam",
+    "Club",
+    "Tango",
+    "Samba",
+    "Folklore", //115
+    "Ballad",
+    "Power Ballad",
+    "Rhythmic Soul",
+    "Freestyle",
+    "Duet", //120
+    "Punk Rock",
+    "Drum Solo",
+    "Acapella",
+    "Euro-House",
+    "Dance Hall" //125
+};
+
+const UINT32 g_ID3_genre_count = sizeof(g_ID3_genres) / sizeof(const char*);
+
+HXBOOL ID3Tools::GenreOrdinalFromName(const char* szGenreName, UINT8& outOrdinal, HXBOOL bCaseSensitiveSearch)
+{
+    int(*pfnStrCmp)(const char*, const char*) = bCaseSensitiveSearch ? strcmp : strcmpi;
+
+    for(UINT8 iOrd = 0; iOrd < g_ID3_genre_count; iOrd++)
+    {
+        if(!pfnStrCmp(g_ID3_genres[iOrd], szGenreName))
+        {
+            outOrdinal = iOrd;
+            return TRUE;
+        }
+    }
+
+    // not found
+    return FALSE;
+}
+
+const char* ID3Tools::GenreNameFromOrdinal(UINT8 uGenreOrdinal)
+{
+    return (uGenreOrdinal < g_ID3_genre_count) ? g_ID3_genres[uGenreOrdinal] : 0;
+}
+
+ULONG32 ID3Tools::ParseGenreNameList(CHXPtrArray& genreOrdinals, const char* szGenreNames,
+                              HXBOOL bCaseSensitiveSearch, char separator, HXBOOL bTrimWhitespace)
+{
+    if(!szGenreNames)
+    {
+        return 0;
+    }
+
+    ULONG32 genreCount = 0;
+    CHXString sVal = szGenreNames;
+
+    while(!sVal.IsEmpty())
+    {
+        INT32 pos = sVal.Find(',');
+
+        CHXString sEntry = (pos < 0) ? sVal : ((pos == 0) ? CHXString() : sVal.Left(pos));
+        if(bTrimWhitespace)
+        {
+            sEntry.TrimLeft();
+            sEntry.TrimRight();
+        }
+
+        if(!sEntry.IsEmpty())
+        {
+            UINT8 uGenreOrdinal = 0;
+            if(GenreOrdinalFromName((const char*)sEntry, uGenreOrdinal, bCaseSensitiveSearch))
+            {
+                genreCount++;
+                genreOrdinals.Add((void*)ULONG32(uGenreOrdinal));
+            }
+        }
+
+        // next entry
+        sVal = (pos >= 0) ? sVal.Right(sVal.GetLength() - pos - 1) : CHXString();
+    }
+
+    return genreCount;
+}
+
+void ID3Tools::MakeGenreNameList(CHXString& outGenreNames, const CHXPtrArray& genreOrdinals, const char* szSeparator)
+{
+    if(!szSeparator || !szSeparator[0])
+    {
+        szSeparator = ",";
+    }
+
+    for(int i = 0; i < genreOrdinals.GetSize(); i++)
+    {
+        UINT8 uGenreOrdinal = (UINT8)(ULONG32)genreOrdinals.GetAt(i);
+
+        const char* szID3GenreName = GenreNameFromOrdinal(uGenreOrdinal);
+        if(szID3GenreName && szID3GenreName[0])
+        {
+            if(!outGenreNames.IsEmpty())
+            {
+                outGenreNames += szSeparator;
+            }
+            outGenreNames += szID3GenreName;
+        }
+    }
+}
+
+HX_RESULT MetaInfo::RemoveKeywordProperties(IHXValues* pValues)
+{
+    HX_RESULT retVal = HXR_OK;
+
+    ULONG32 ulKeywordCount = 0;
+    if(PropTools::CopyPropertyULONG32(ulKeywordCount, pValues, _3GPP_META_INFO_KEYWORD_COUNT_KEY))
+    {
+        PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_KEYWORD_COUNT_KEY);
+
+        for(ULONG32 i = 0; i < ulKeywordCount; i++)
+        {
+            char key[128];
+            sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
+            PropTools::RemovePropertyBuffer(retVal, pValues, key);
+        }
+    }
+    return retVal;
+}
+
+HX_RESULT MetaInfo::CopyKeywordProperties(IHXValues* dst, IHXValues* src, HXBOOL bBlast)
+{
+    HX_RESULT retVal = HXR_OK;
+
+    ULONG32 ulKeywordCount = 0;
+    if(PropTools::CopyPropertyULONG32(ulKeywordCount, src, _3GPP_META_INFO_KEYWORD_COUNT_KEY))
+    {
+        retVal = RemoveKeywordProperties(dst);
+
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_KEYWORD_COUNT_KEY, TRUE);
+        for(ULONG32 i = 0; i < ulKeywordCount; i++)
+        {
+            if(SUCCEEDED(retVal))
+            {
+                char key[128];
+                sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
+                PropTools::CopyPropertyBuffer(retVal, dst, src, key, TRUE);
+            }
+        }
+    }
+    else if(bBlast)
+    {
+        retVal = RemoveKeywordProperties(dst);
+    }
+    return retVal;
+}
+
+HX_RESULT MetaInfo::RemoveAllProperties(IHXValues* pValues, ULONG32 metaInfoSetFlags)
+{
+    HX_RESULT retVal = HXR_OK;
+
+    // Generic
+    if(metaInfoSetFlags & METAINFO_SET_GENERIC)
+    {
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_TITLE_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_COMPOSER_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_COPYRIGHT_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_COMMENT_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_ARTIST_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_GENRE_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _GENERIC_META_INFO_ALBUM_KEY);
+
+        PropTools::RemovePropertyULONG32(retVal, pValues, _GENERIC_META_INFO_TRACK_NUMBER_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _GENERIC_META_INFO_RECORDING_YEAR_KEY);
+    }
+
+    // iTunes
+    if(metaInfoSetFlags & METAINFO_SET_ITUNES_SPECIFIC)
+    {
+        PropTools::RemovePropertyBuffer(retVal, pValues, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _ITUNES_META_INFO_GENERATOR_TOOL_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _ITUNES_META_INFO_ENCODED_BY_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _ITUNES_META_INFO_GROUPING_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _ITUNES_META_INFO_ALBUM_ARTIST_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _ITUNES_META_INFO_LYRICS_KEY);
+
+        PropTools::RemovePropertyULONG32(retVal, pValues, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _ITUNES_META_INFO_PART_OF_COMPILATION_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _ITUNES_META_INFO_TRACK_COUNT_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _ITUNES_META_INFO_DISC_NUMBER_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _ITUNES_META_INFO_DISC_COUNT_KEY);
+    }
+
+    // 3GPP
+    if(metaInfoSetFlags & METAINFO_SET_3GPP_SPECIFIC)
+    {
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_RATING_ENTITY_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_RATING_CRITERIA_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_RATING_INFO_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_NAME_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_LATITUDE_KEY);
+        PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY);
+
+        PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY);
+        PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_LOCATION_ROLE_KEY);
+
+        // keywords
+        if(SUCCEEDED(retVal))
+        {
+            retVal = RemoveKeywordProperties(pValues);
+        }
+    }
+
+    return retVal;
+}
+
+HX_RESULT MetaInfo::CopyAllProperties(IHXValues* dst, IHXValues* src, ULONG32 metaInfoSetFlags, HXBOOL bBlast)
+{
+    HX_RESULT retVal = HXR_OK;
+
+    // Generic
+    if(metaInfoSetFlags & METAINFO_SET_GENERIC)
+    {
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_TITLE_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_COMPOSER_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_COPYRIGHT_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_COMMENT_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_ARTIST_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_GENRE_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _GENERIC_META_INFO_ALBUM_KEY, bBlast);
+
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _GENERIC_META_INFO_TRACK_NUMBER_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _GENERIC_META_INFO_RECORDING_YEAR_KEY, bBlast);
+    }
+
+    // iTunes
+    if(metaInfoSetFlags & METAINFO_SET_ITUNES_SPECIFIC)
+    {
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _ITUNES_META_INFO_GENERATOR_TOOL_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _ITUNES_META_INFO_ENCODED_BY_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _ITUNES_META_INFO_GROUPING_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _ITUNES_META_INFO_ALBUM_ARTIST_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _ITUNES_META_INFO_LYRICS_KEY, bBlast);
+
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _ITUNES_META_INFO_PART_OF_COMPILATION_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _ITUNES_META_INFO_TRACK_COUNT_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _ITUNES_META_INFO_DISC_NUMBER_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _ITUNES_META_INFO_DISC_COUNT_KEY, bBlast);
+    }
+
+    // 3GPP
+    if(metaInfoSetFlags & METAINFO_SET_3GPP_SPECIFIC)
+    {
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_RATING_ENTITY_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_RATING_CRITERIA_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_RATING_INFO_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_NAME_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_LATITUDE_KEY, bBlast);
+        PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY, bBlast);
+
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, bBlast);
+        PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_LOCATION_ROLE_KEY, bBlast);
+
+        // keywords
+        if(SUCCEEDED(retVal))
+        {
+            retVal = CopyKeywordProperties(dst, src, bBlast);
+        }
+    }
+
+    return retVal;
+}
+
+ULONG32 MetaInfo::GetSetsFromFlavors(ULONG32 metaFlavorFlags)
+{
+    ULONG32 metaInfoSets = 0;
+
+    if(metaFlavorFlags & METADATA_FLAVOR_3GPP)
+    {
+        metaInfoSets |= METAINFO_SET_3GPP_ALL;
+    }
+
+    if(metaFlavorFlags & METADATA_FLAVOR_ITUNES)
+    {
+        metaInfoSets |= METAINFO_SET_ITUNES_ALL;
+    }
+
+    return metaInfoSets;
+}
+
+CHXString MetaInfo::GetFlavorName(METADATA_FLAVOR flavor)
+{
+    switch(flavor)
+    {
+        case METADATA_FLAVOR_3GPP:
+            return "3GPP";
+
+        case METADATA_FLAVOR_ITUNES:
+            return "iTunes";
+    }
+    return "UNKNOWN";
+}
+
+CHXString MetaInfo::GetFlavorNames(ULONG32 metaFlavorFlags)
+{
+    const METADATA_FLAVOR allFlavors[] = { METADATA_FLAVOR_3GPP, METADATA_FLAVOR_ITUNES };
+
+    CHXString s;
+    for(int i = 0; i < (sizeof(allFlavors) / sizeof(METADATA_FLAVOR)); i++)
+    {
+        if(metaFlavorFlags & allFlavors[i])
+        {
+            if(!s.IsEmpty())
+            {
+                s += ", ";
+            }
+            s += GetFlavorName(allFlavors[i]);
+        }
+    }
+
+    return s;
+}
+
+ULONG32 MetaInfo::GetSetsWhichSupportItem(eStringMetaItem itemName)
+{
+    switch(itemName)
+    {
+        case StringMetaItem_Title:
+        case StringMetaItem_Artist:
+        case StringMetaItem_Album:
+        case StringMetaItem_Genre:
+        case StringMetaItem_Composer:
+        case StringMetaItem_Comment:
+        case StringMetaItem_Copyright:
+            return METAINFO_SET_GENERIC;
+
+        case StringMetaItem_TrackSubtitle:
+        case StringMetaItem_GeneratorTool:
+        case StringMetaItem_EncodedBy:
+        case StringMetaItem_Grouping:
+        case StringMetaItem_AlbumArtist:
+        case StringMetaItem_Lyrics:
+            return METAINFO_SET_ITUNES_SPECIFIC;
+
+        case StringMetaItem_GlobalLanguageEncoding:
+        case StringMetaItem_RatingEntity:
+        case StringMetaItem_RatingCriteria:
+        case StringMetaItem_RatingInfo:
+        case StringMetaItem_ClassificationEntity:
+        case StringMetaItem_ClassificationInfo:
+        case StringMetaItem_LocationName:
+        case StringMetaItem_LocationAstronomicalBody:
+        case StringMetaItem_LocationAdditionalNotes:
+        case StringMetaItem_LocationLongitude:
+        case StringMetaItem_LocationLatitude:
+        case StringMetaItem_LocationAltitude:
+        case StringMetaItem_Keywords:
+            return METAINFO_SET_3GPP_SPECIFIC;
+    }
+    return 0;
+}
+
+ULONG32 MetaInfo::GetFlavorsWhichSupportItem(eStringMetaItem itemName)
+{
+    switch(itemName)
+    {
+        case StringMetaItem_Title:
+        case StringMetaItem_Artist:
+        case StringMetaItem_Album:
+        case StringMetaItem_Genre:
+        case StringMetaItem_Composer:
+        case StringMetaItem_Comment:
+        case StringMetaItem_Copyright:
+            return (METADATA_FLAVOR_3GPP | METADATA_FLAVOR_ITUNES);
+
+        case StringMetaItem_TrackSubtitle:
+        case StringMetaItem_GeneratorTool:
+        case StringMetaItem_EncodedBy:
+        case StringMetaItem_Grouping:
+        case StringMetaItem_AlbumArtist:
+        case StringMetaItem_Lyrics:
+            return METADATA_FLAVOR_ITUNES;
+
+        case StringMetaItem_GlobalLanguageEncoding:
+        case StringMetaItem_RatingEntity:
+        case StringMetaItem_RatingCriteria:
+        case StringMetaItem_RatingInfo:
+        case StringMetaItem_ClassificationEntity:
+        case StringMetaItem_ClassificationInfo:
+        case StringMetaItem_LocationName:
+        case StringMetaItem_LocationAstronomicalBody:
+        case StringMetaItem_LocationAdditionalNotes:
+        case StringMetaItem_LocationLongitude:
+        case StringMetaItem_LocationLatitude:
+        case StringMetaItem_LocationAltitude:
+        case StringMetaItem_Keywords:
+            return METADATA_FLAVOR_3GPP;
+    }
+    return 0;
+}
+
+HXBOOL MetaInfo::IsItemValueValidForFlavors(eStringMetaItem itemName, const EncodedString& val, ULONG32 metaFlavorFlags)
+{
+    switch(itemName)
+    {
+        case StringMetaItem_Title:
+        case StringMetaItem_Artist:
+        case StringMetaItem_Album:
+        case StringMetaItem_Genre:
+        case StringMetaItem_Composer:
+        case StringMetaItem_Comment:
+        case StringMetaItem_Copyright:
+        case StringMetaItem_TrackSubtitle:
+        case StringMetaItem_GeneratorTool:
+        case StringMetaItem_EncodedBy:
+        case StringMetaItem_Grouping:
+        case StringMetaItem_AlbumArtist:
+            // iTunes have 255 character limit for all string properties except Lyrics
+            return (metaFlavorFlags & METADATA_FLAVOR_ITUNES) ? (val.GetCodeUnitLength(FALSE, FALSE) <= 255) : TRUE;
+
+        case StringMetaItem_Keywords:
+            // 3GPP has 255 characters limit for Keywords
+            return (val.GetCodeUnitLength(FALSE, FALSE) <= 255);
+    }
+    return TRUE;
+}
+
+ULONG32 MetaInfo::GetSetsWhichSupportItem(eUlongMetaItem itemName)
+{
+    switch(itemName)
+    {
+        case UlongMetaItem_TrackNumber:
+        case UlongMetaItem_RecordingYear:
+            return METAINFO_SET_GENERIC;
+
+        case UlongMetaItem_BeatsPerMinute:
+        case UlongMetaItem_PartOfCompilation:
+        case UlongMetaItem_ExplicitContent:
+        case UlongMetaItem_TrackCount:
+        case UlongMetaItem_DiscNumber:
+        case UlongMetaItem_DiscCount:
+            return METAINFO_SET_ITUNES_SPECIFIC;
+
+        case UlongMetaItem_ClassificationTable:
+        case UlongMetaItem_LocationRole:
+            return METAINFO_SET_3GPP_SPECIFIC;
+    }
+    return 0;
+}
+
+ULONG32 MetaInfo::GetFlavorsWhichSupportItem(eUlongMetaItem itemName)
+{
+    switch(itemName)
+    {
+        case UlongMetaItem_TrackNumber:
+        case UlongMetaItem_RecordingYear:
+            return (METADATA_FLAVOR_3GPP | METADATA_FLAVOR_ITUNES);
+
+        case UlongMetaItem_BeatsPerMinute:
+        case UlongMetaItem_PartOfCompilation:
+        case UlongMetaItem_ExplicitContent:
+        case UlongMetaItem_TrackCount:
+        case UlongMetaItem_DiscNumber:
+        case UlongMetaItem_DiscCount:
+            return METADATA_FLAVOR_ITUNES;
+
+        case UlongMetaItem_ClassificationTable:
+        case UlongMetaItem_LocationRole:
+            return METADATA_FLAVOR_3GPP;
+    }
+    return 0;
+}
+
+HXBOOL MetaInfo::IsItemValueValidForFlavors(eUlongMetaItem itemName, ULONG32 val, ULONG32 metaFlavorFlags)
+{
+    switch(itemName)
+    {
+        case UlongMetaItem_TrackNumber:
+        {
+            HXBOOL bInRange = TRUE;
+            if(metaFlavorFlags & METADATA_FLAVOR_ITUNES)
+            {
+                bInRange = bInRange && IsInRange16(val);
+            }
+            if(metaFlavorFlags & METADATA_FLAVOR_3GPP)
+            {
+                bInRange = bInRange && IsInRange8(val);
+            }
+            return metaFlavorFlags ? bInRange : FALSE;
+        }
+
+        case UlongMetaItem_RecordingYear:
+        {
+            HXBOOL bInRange = TRUE;
+            if(metaFlavorFlags & METADATA_FLAVOR_ITUNES)
+            {
+                bInRange = bInRange && IsInRange(val, 0, 9999);
+            }
+            if(metaFlavorFlags & METADATA_FLAVOR_3GPP)
+            {
+                bInRange = bInRange && IsInRange16(val);
+            }
+            return metaFlavorFlags ? bInRange : FALSE;
+        }
+
+        case UlongMetaItem_PartOfCompilation:
+        case UlongMetaItem_ExplicitContent:
+        {
+            if(metaFlavorFlags & METADATA_FLAVOR_ITUNES)
+            {
+                return IsInRangeBoolean(val);
+            }
+            return FALSE;
+        }
+
+        case UlongMetaItem_TrackCount:
+        case UlongMetaItem_DiscNumber:
+        case UlongMetaItem_DiscCount:
+        {
+            if(metaFlavorFlags & METADATA_FLAVOR_ITUNES)
+            {
+                return IsInRange16(val);
+            }
+            return FALSE;
+        }
+
+        case UlongMetaItem_ClassificationTable:
+        {
+            if(metaFlavorFlags & METADATA_FLAVOR_3GPP)
+            {
+                return IsInRange16(val);
+            }
+            return FALSE;
+        }
+
+        case UlongMetaItem_LocationRole:
+        {
+            if(metaFlavorFlags & METADATA_FLAVOR_3GPP)
+            {
+                return IsInRange8(val);
+            }
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+MetaInfo::MetaInfo()
+{
+    Clear();
+}
+
+MetaInfo::~MetaInfo()
+{
+    ClearKeywords();
+}
+
+MetaInfo::MetaInfo(const MetaInfo& rhs)
+{
+    *this = rhs;
+}
+
+MetaInfo& MetaInfo::operator=(const MetaInfo& rhs)
+{
+    Clear();
+    UpdateItems(rhs);
+    return *this;
+}
+
+void MetaInfo::Dump(ULONG32 metaInfoSetFlags)
+{
+    // Generic
+    if(metaInfoSetFlags & METAINFO_SET_GENERIC)
+    {
+        Dump(_GENERIC_META_INFO_TITLE_KEY, m_stringItems[StringMetaItem_Title]);
+        Dump(_GENERIC_META_INFO_COMPOSER_KEY, m_stringItems[StringMetaItem_Composer]);
+        Dump(_GENERIC_META_INFO_COPYRIGHT_KEY, m_stringItems[StringMetaItem_Copyright]);
+        Dump(_GENERIC_META_INFO_COMMENT_KEY, m_stringItems[StringMetaItem_Comment]);
+        Dump(_GENERIC_META_INFO_ARTIST_KEY, m_stringItems[StringMetaItem_Artist]);
+        Dump(_GENERIC_META_INFO_GENRE_KEY, m_stringItems[StringMetaItem_Genre]);
+        Dump(_GENERIC_META_INFO_ALBUM_KEY, m_stringItems[StringMetaItem_Album]);
+
+        Dump(_GENERIC_META_INFO_TRACK_NUMBER_KEY, m_ulongItems[UlongMetaItem_TrackNumber],
+                                                m_ulongItemValidFlags[UlongMetaItem_TrackNumber]);
+        Dump(_GENERIC_META_INFO_RECORDING_YEAR_KEY, m_ulongItems[UlongMetaItem_RecordingYear],
+                                                m_ulongItemValidFlags[UlongMetaItem_RecordingYear]);
+    }
+
+    // iTunes
+    if(metaInfoSetFlags & METAINFO_SET_ITUNES_SPECIFIC)
+    {
+        Dump(_ITUNES_META_INFO_TRACK_SUBTITLE_KEY, m_stringItems[StringMetaItem_TrackSubtitle]);
+        Dump(_ITUNES_META_INFO_GENERATOR_TOOL_KEY, m_stringItems[StringMetaItem_GeneratorTool]);
+        Dump(_ITUNES_META_INFO_ENCODED_BY_KEY, m_stringItems[StringMetaItem_EncodedBy]);
+        Dump(_ITUNES_META_INFO_GROUPING_KEY, m_stringItems[StringMetaItem_Grouping]);
+        Dump(_ITUNES_META_INFO_ALBUM_ARTIST_KEY, m_stringItems[StringMetaItem_AlbumArtist]);
+        Dump(_ITUNES_META_INFO_LYRICS_KEY, m_stringItems[StringMetaItem_Lyrics]);
+        Dump(_ITUNES_META_INFO_BEATS_PER_MINUTE_KEY, m_ulongItems[UlongMetaItem_BeatsPerMinute],
+                                            m_ulongItemValidFlags[UlongMetaItem_BeatsPerMinute]);
+        Dump(_ITUNES_META_INFO_PART_OF_COMPILATION_KEY, m_ulongItems[UlongMetaItem_PartOfCompilation],
+                                            m_ulongItemValidFlags[UlongMetaItem_PartOfCompilation]);
+        Dump(_ITUNES_META_INFO_EXPLICIT_CONTENT_KEY, m_ulongItems[UlongMetaItem_ExplicitContent],
+                                            m_ulongItemValidFlags[UlongMetaItem_ExplicitContent]);
+        Dump(_ITUNES_META_INFO_TRACK_COUNT_KEY, m_ulongItems[UlongMetaItem_TrackCount],
+                                            m_ulongItemValidFlags[UlongMetaItem_TrackCount]);
+        Dump(_ITUNES_META_INFO_DISC_NUMBER_KEY, m_ulongItems[UlongMetaItem_DiscNumber],
+                                            m_ulongItemValidFlags[UlongMetaItem_DiscNumber]);
+        Dump(_ITUNES_META_INFO_DISC_COUNT_KEY, m_ulongItems[UlongMetaItem_DiscCount],
+                                            m_ulongItemValidFlags[UlongMetaItem_DiscCount]);
+    }
+
+    // 3GPP
+    if(metaInfoSetFlags & METAINFO_SET_3GPP_SPECIFIC)
+    {
+        Dump(_3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, m_stringItems[StringMetaItem_GlobalLanguageEncoding]);
+        Dump(_3GPP_META_INFO_RATING_ENTITY_KEY, m_stringItems[StringMetaItem_RatingEntity]);
+        Dump(_3GPP_META_INFO_RATING_CRITERIA_KEY, m_stringItems[StringMetaItem_RatingCriteria]);
+        Dump(_3GPP_META_INFO_RATING_INFO_KEY, m_stringItems[StringMetaItem_RatingInfo]);
+        Dump(_3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, m_stringItems[StringMetaItem_ClassificationEntity]);
+        Dump(_3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, m_ulongItems[UlongMetaItem_ClassificationTable],
+                                                m_ulongItemValidFlags[UlongMetaItem_ClassificationTable]);
+        Dump(_3GPP_META_INFO_CLASSIFICATION_INFO_KEY, m_stringItems[StringMetaItem_ClassificationInfo]);
+        Dump(_3GPP_META_INFO_LOCATION_NAME_KEY, m_stringItems[StringMetaItem_LocationName]);
+        Dump(_3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, m_stringItems[StringMetaItem_LocationAstronomicalBody]);
+        Dump(_3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, m_stringItems[StringMetaItem_LocationAdditionalNotes]);
+        Dump(_3GPP_META_INFO_LOCATION_ROLE_KEY, m_ulongItems[UlongMetaItem_LocationRole],
+                                        m_ulongItemValidFlags[UlongMetaItem_LocationRole]);
+        Dump(_3GPP_META_INFO_LOCATION_LONGITUDE_KEY, m_stringItems[StringMetaItem_LocationLongitude]);
+        Dump(_3GPP_META_INFO_LOCATION_LATITUDE_KEY, m_stringItems[StringMetaItem_LocationLatitude]);
+        Dump(_3GPP_META_INFO_LOCATION_ALTITUDE_KEY, m_stringItems[StringMetaItem_LocationAltitude]);
+
+        for(ULONG32 i = 0; i < GetKeywordCount(); i++)
+        {
+            printf(_3GPP_META_INFO_KEYWORD_KEY": ", int(i));
+            EncodedString kwd;
+            GetKeyword(i, kwd);
+            kwd.Dump();
+            printf("\n");
+        }
+    }
+}
+
+void MetaInfo::Clear()
+{
+    for(int iStrItem = StringMetaItem_StringItemBegin; iStrItem < StringMetaItem_StringItemEnd; iStrItem++)
+    {
+        m_stringItems[iStrItem].Clear();
+    }
+
+    ClearKeywords();
+
+    for(int iUlongItem = UlongMetaItem_UlongItemBegin; iUlongItem < UlongMetaItem_UlongItemEnd; iUlongItem++)
+    {
+        m_ulongItems[iUlongItem] = 0;
+        m_ulongItemValidFlags[iUlongItem] = FALSE;
+    }
+}
+
+void MetaInfo::ClearItems(ULONG32 metaInfoSetFlags)
+{
+    for(int iStrItem = StringMetaItem_StringItemBegin; iStrItem < StringMetaItem_StringItemEnd; iStrItem++)
+    {
+        if(IsItemSupportedByAnySet((eStringMetaItem)iStrItem, metaInfoSetFlags))
+        {
+            m_stringItems[iStrItem].Clear();
+        }
+    }
+
+    if(IsItemSupportedByAnySet(StringMetaItem_Keywords, metaInfoSetFlags))
+    {
+        ClearKeywords();
+    }
+
+    for(int iUlongItem = UlongMetaItem_UlongItemBegin; iUlongItem < UlongMetaItem_UlongItemEnd; iUlongItem++)
+    {
+        if(IsItemSupportedByAnySet((eUlongMetaItem)iUlongItem, metaInfoSetFlags))
+        {
+            m_ulongItems[iUlongItem] = 0;
+            m_ulongItemValidFlags[iUlongItem] = FALSE;
+        }
+    }
+}
+
+void MetaInfo::UpdateItems(const MetaInfo& src, ULONG32 metaInfoSetFlags)
+{
+    for(int iStrItem = StringMetaItem_StringItemBegin; iStrItem < StringMetaItem_StringItemEnd; iStrItem++)
+    {
+        if(IsItemSupportedByAnySet((eStringMetaItem)iStrItem, metaInfoSetFlags))
+        {
+            Update(m_stringItems[iStrItem], src.m_stringItems[iStrItem]);
+        }
+    }
+
+    if(IsItemSupportedByAnySet(StringMetaItem_Keywords, metaInfoSetFlags))
+    {
+        for(ULONG32 i = 0; i < src.GetKeywordCount(); i++)
+        {
+            EncodedString sTmp;
+            src.GetKeyword(i, sTmp);
+            AddKeyword(sTmp);
+        }
+    }
+
+    for(int iUlongItem = UlongMetaItem_UlongItemBegin; iUlongItem < UlongMetaItem_UlongItemEnd; iUlongItem++)
+    {
+        if(IsItemSupportedByAnySet((eUlongMetaItem)iUlongItem, metaInfoSetFlags))
+        {
+            Update(m_ulongItems[iUlongItem], m_ulongItemValidFlags[iUlongItem],
+                   src.m_ulongItems[iUlongItem], src.m_ulongItemValidFlags[iUlongItem]);
+        }
+    }
+}
+
+void MetaInfo::CopyToValues(IHXValues* pValues, HXBOOL bBlast, ULONG32 metaInfoSetFlags) const
+{
+    if(!pValues)
+    {
+        return;
+    }
+
+    // Generic
+    if(metaInfoSetFlags & METAINFO_SET_GENERIC)
+    {
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_TITLE_KEY, StringMetaItem_Title);
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_COMPOSER_KEY, StringMetaItem_Composer);
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_COPYRIGHT_KEY, StringMetaItem_Copyright);
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_COMMENT_KEY, StringMetaItem_Comment);
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_ARTIST_KEY, StringMetaItem_Artist);
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_GENRE_KEY, StringMetaItem_Genre);
+        CopyString(pValues, bBlast, _GENERIC_META_INFO_ALBUM_KEY, StringMetaItem_Album);
+
+        CopyULONG32(pValues, bBlast, _GENERIC_META_INFO_TRACK_NUMBER_KEY, UlongMetaItem_TrackNumber);
+        CopyULONG32(pValues, bBlast, _GENERIC_META_INFO_RECORDING_YEAR_KEY, UlongMetaItem_RecordingYear);
+    }
+
+    // iTunes
+    if(metaInfoSetFlags & METAINFO_SET_ITUNES_SPECIFIC)
+    {
+        CopyString(pValues, bBlast, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY, StringMetaItem_TrackSubtitle);
+        CopyString(pValues, bBlast, _ITUNES_META_INFO_GENERATOR_TOOL_KEY, StringMetaItem_GeneratorTool);
+        CopyString(pValues, bBlast, _ITUNES_META_INFO_ENCODED_BY_KEY, StringMetaItem_EncodedBy);
+        CopyString(pValues, bBlast, _ITUNES_META_INFO_GROUPING_KEY, StringMetaItem_Grouping);
+        CopyString(pValues, bBlast, _ITUNES_META_INFO_ALBUM_ARTIST_KEY, StringMetaItem_AlbumArtist);
+        CopyString(pValues, bBlast, _ITUNES_META_INFO_LYRICS_KEY, StringMetaItem_Lyrics);
+
+        CopyULONG32(pValues, bBlast, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY, UlongMetaItem_BeatsPerMinute);
+        CopyULONG32(pValues, bBlast, _ITUNES_META_INFO_PART_OF_COMPILATION_KEY, UlongMetaItem_PartOfCompilation);
+        CopyULONG32(pValues, bBlast, _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY, UlongMetaItem_ExplicitContent);
+        CopyULONG32(pValues, bBlast, _ITUNES_META_INFO_TRACK_COUNT_KEY, UlongMetaItem_TrackCount);
+        CopyULONG32(pValues, bBlast, _ITUNES_META_INFO_DISC_NUMBER_KEY, UlongMetaItem_DiscNumber);
+        CopyULONG32(pValues, bBlast, _ITUNES_META_INFO_DISC_COUNT_KEY, UlongMetaItem_DiscCount);
+    }
+
+    // 3GPP
+    if(metaInfoSetFlags & METAINFO_SET_3GPP_SPECIFIC)
+    {
+        CopyString(pValues, bBlast, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, StringMetaItem_GlobalLanguageEncoding);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_RATING_ENTITY_KEY, StringMetaItem_RatingEntity);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_RATING_CRITERIA_KEY, StringMetaItem_RatingCriteria);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_RATING_INFO_KEY, StringMetaItem_RatingInfo);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, StringMetaItem_ClassificationEntity);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY, StringMetaItem_ClassificationInfo);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_LOCATION_NAME_KEY, StringMetaItem_LocationName);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, StringMetaItem_LocationAstronomicalBody);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, StringMetaItem_LocationAdditionalNotes);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY, StringMetaItem_LocationLongitude);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_LOCATION_LATITUDE_KEY, StringMetaItem_LocationLatitude);
+        CopyString(pValues, bBlast, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY, StringMetaItem_LocationAltitude);
+
+        CopyULONG32(pValues, bBlast, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, UlongMetaItem_ClassificationTable);
+        CopyULONG32(pValues, bBlast, _3GPP_META_INFO_LOCATION_ROLE_KEY, UlongMetaItem_LocationRole);
+
+        // keyword section
+        if(bBlast)
+        {
+            RemoveKeywordProperties(pValues);
+        }
+
+        EncodedString sTmp;
+        ULONG32 ulKeywordCount = GetKeywordCount();
+        if(ulKeywordCount)
+        {
+            PropTools::CopyPropertyULONG32(pValues, TRUE, ULONG32(ulKeywordCount),
+                                                _3GPP_META_INFO_KEYWORD_COUNT_KEY, TRUE);
+            for(ULONG32 i = 0; i < ulKeywordCount; i++)
+            {
+                char key[128];
+                sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
+                GetKeyword(i, sTmp);
+                PropTools::CopyPropertyBuffer(pValues, sTmp, key, TRUE);
+            }
+        }
+    }
+}
+
+void MetaInfo::CopyFromValues(IHXValues* pValues, HXBOOL bBlast, ULONG32 metaInfoSetFlags)
+{
+    if(!pValues)
+    {
+        return;
+    }
+
+    // Generic
+    if(metaInfoSetFlags & METAINFO_SET_GENERIC)
+    {
+        CopyString(StringMetaItem_Title, bBlast, pValues, _GENERIC_META_INFO_TITLE_KEY);
+        CopyString(StringMetaItem_Composer, bBlast, pValues, _GENERIC_META_INFO_COMPOSER_KEY);
+        CopyString(StringMetaItem_Copyright, bBlast, pValues, _GENERIC_META_INFO_COPYRIGHT_KEY);
+        CopyString(StringMetaItem_Comment, bBlast, pValues, _GENERIC_META_INFO_COMMENT_KEY);
+        CopyString(StringMetaItem_Artist, bBlast, pValues, _GENERIC_META_INFO_ARTIST_KEY);
+        CopyString(StringMetaItem_Genre, bBlast, pValues, _GENERIC_META_INFO_GENRE_KEY);
+        CopyString(StringMetaItem_Album, bBlast, pValues, _GENERIC_META_INFO_ALBUM_KEY);
+
+        CopyULONG32(UlongMetaItem_TrackNumber, bBlast, pValues, _GENERIC_META_INFO_TRACK_NUMBER_KEY);
+        CopyULONG32(UlongMetaItem_RecordingYear, bBlast, pValues, _GENERIC_META_INFO_RECORDING_YEAR_KEY);
+    }
+
+    // iTunes
+    if(metaInfoSetFlags & METAINFO_SET_ITUNES_SPECIFIC)
+    {
+        CopyString(StringMetaItem_TrackSubtitle, bBlast, pValues, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY);
+        CopyString(StringMetaItem_GeneratorTool, bBlast, pValues, _ITUNES_META_INFO_GENERATOR_TOOL_KEY);
+        CopyString(StringMetaItem_GeneratorTool, bBlast, pValues, _ITUNES_META_INFO_ENCODED_BY_KEY);
+        CopyString(StringMetaItem_Grouping, bBlast, pValues, _ITUNES_META_INFO_GROUPING_KEY);
+        CopyString(StringMetaItem_AlbumArtist, bBlast, pValues, _ITUNES_META_INFO_ALBUM_ARTIST_KEY);
+        CopyString(StringMetaItem_Lyrics, bBlast, pValues, _ITUNES_META_INFO_LYRICS_KEY);
+
+        CopyULONG32(UlongMetaItem_BeatsPerMinute, bBlast, pValues, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY);
+        CopyULONG32(UlongMetaItem_PartOfCompilation, bBlast, pValues, _ITUNES_META_INFO_PART_OF_COMPILATION_KEY);
+        CopyULONG32(UlongMetaItem_ExplicitContent, bBlast, pValues, _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY);
+        CopyULONG32(UlongMetaItem_TrackCount, bBlast, pValues, _ITUNES_META_INFO_TRACK_COUNT_KEY);
+        CopyULONG32(UlongMetaItem_DiscNumber, bBlast, pValues, _ITUNES_META_INFO_DISC_NUMBER_KEY);
+        CopyULONG32(UlongMetaItem_DiscCount, bBlast, pValues, _ITUNES_META_INFO_DISC_COUNT_KEY);
+    }
+
+    // 3GPP
+    if(metaInfoSetFlags & METAINFO_SET_3GPP_SPECIFIC)
+    {
+        CopyString(StringMetaItem_GlobalLanguageEncoding, bBlast, pValues, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY);
+        CopyString(StringMetaItem_RatingEntity, bBlast, pValues, _3GPP_META_INFO_RATING_ENTITY_KEY);
+        CopyString(StringMetaItem_RatingCriteria, bBlast, pValues, _3GPP_META_INFO_RATING_CRITERIA_KEY);
+        CopyString(StringMetaItem_RatingInfo, bBlast, pValues, _3GPP_META_INFO_RATING_INFO_KEY);
+        CopyString(StringMetaItem_ClassificationEntity, bBlast, pValues, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY);
+        CopyString(StringMetaItem_ClassificationInfo, bBlast, pValues, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY);
+        CopyString(StringMetaItem_LocationName, bBlast, pValues, _3GPP_META_INFO_LOCATION_NAME_KEY);
+        CopyString(StringMetaItem_LocationAstronomicalBody, bBlast, pValues, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY);
+        CopyString(StringMetaItem_LocationAdditionalNotes, bBlast, pValues, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY);
+        CopyString(StringMetaItem_LocationLongitude, bBlast, pValues, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY);
+        CopyString(StringMetaItem_LocationLatitude, bBlast, pValues, _3GPP_META_INFO_LOCATION_LATITUDE_KEY);
+        CopyString(StringMetaItem_LocationAltitude, bBlast, pValues, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY);
+
+        CopyULONG32(UlongMetaItem_ClassificationTable, bBlast, pValues, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY);
+        CopyULONG32(UlongMetaItem_LocationRole, bBlast, pValues, _3GPP_META_INFO_LOCATION_ROLE_KEY);
+
+        // keyword section
+        if(bBlast)
+        {
+            ClearKeywords();
+        }
+
+        EncodedString sTmp;
+        ULONG32 ulKeywordCount = 0;
+        if(PropTools::CopyPropertyULONG32(ulKeywordCount, pValues, _3GPP_META_INFO_KEYWORD_COUNT_KEY))
+        {
+            for(ULONG32 i = 0; i < ulKeywordCount; i++)
+            {
+                char key[128];
+                sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
+                if(PropTools::CopyPropertyBuffer(sTmp, pValues, key))
+                {
+                    AddKeyword(sTmp);
+                }
+            }
+        }
+
+        RemoveKeywordDuplicates();
+    }
+}
+
+HX_RESULT MetaInfo::GetStringItem(eStringMetaItem itemName, EncodedString& out) const
+{
+    out = m_stringItems[itemName];
+    return out.IsEmpty() ? HXR_FAILED : HXR_OK;
+}
+
+HX_RESULT MetaInfo::SetStringItem(eStringMetaItem itemName, const EncodedString& val, ULONG32 metaFlavorFlags)
+{
+    switch(itemName)
+    {
+        case StringMetaItem_Title:
+        case StringMetaItem_Artist:
+        case StringMetaItem_Album:
+        case StringMetaItem_Genre:
+        case StringMetaItem_Composer:
+        case StringMetaItem_Comment:
+        case StringMetaItem_Copyright:
+        case StringMetaItem_TrackSubtitle:
+        case StringMetaItem_GeneratorTool:
+        case StringMetaItem_EncodedBy:
+        case StringMetaItem_Grouping:
+        case StringMetaItem_AlbumArtist:
+            // iTunes have 255 character limit for all string properties except Lyrics
+            if((metaFlavorFlags & METADATA_FLAVOR_ITUNES) && (val.GetCodeUnitLength(FALSE, FALSE) > 255))
+            {
+                return HXR_INVALID_PARAMETER;
+            }
+            break;
+
+        case StringMetaItem_GlobalLanguageEncoding:
+            return SetGlobalLanguageEncoding(val);
+
+        case StringMetaItem_RatingEntity:
+        case StringMetaItem_RatingCriteria:
+        case StringMetaItem_ClassificationEntity:
+            return SetStringAsciiMaxLen(m_stringItems[itemName], val, 4);
+
+        case StringMetaItem_LocationLongitude:
+        case StringMetaItem_LocationLatitude:
+        case StringMetaItem_LocationAltitude:
+            return SetStringFixedPointNum(m_stringItems[itemName], val);
+    }
+
+    // default assignment
+    m_stringItems[itemName] = val;
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::GetUlongItem(eUlongMetaItem itemName, ULONG32& out) const
+{
+    out = m_ulongItems[itemName];
+    return m_ulongItemValidFlags[itemName] ? HXR_OK : HXR_FAILED;
+}
+
+HX_RESULT MetaInfo::SetUlongItem(eUlongMetaItem itemName, ULONG32 val, HXBOOL bValid, ULONG32 metaFlavorFlags)
+{
+    switch(itemName)
+    {
+        case UlongMetaItem_TrackNumber:
+        {
+            ULONG32 maxVal = 0x0000FFFF; //iTunes
+            if(metaFlavorFlags & METADATA_FLAVOR_3GPP)
+            {
+                maxVal = 0x000000FF;
+            }
+            return SetUlong(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid, 0, maxVal);
+        }
+
+        case UlongMetaItem_RecordingYear:
+        {
+            ULONG32 maxVal = 0x0000FFFF; //3GPP
+            if(metaFlavorFlags & METADATA_FLAVOR_ITUNES)
+            {
+                maxVal = 9999;
+            }
+            return SetUlong(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid, 0, maxVal);
+        }
+
+        case UlongMetaItem_PartOfCompilation:
+        case UlongMetaItem_ExplicitContent:
+            return SetUlongBoolean(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid);
+
+        case UlongMetaItem_TrackCount:
+        case UlongMetaItem_DiscNumber:
+        case UlongMetaItem_DiscCount:
+            return SetUlong16(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid);
+
+        case UlongMetaItem_ClassificationTable:
+            return SetUlong16(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid);
+
+        case UlongMetaItem_LocationRole:
+            return SetUlong8(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid);
+    }
+
+    // default assignment
+    SetUlong(m_ulongItems[itemName], m_ulongItemValidFlags[itemName], val, bValid);
+    return HXR_OK;
+}
+
+ULONG32 MetaInfo::GetKeywordCount() const
+{
+    return (ULONG32)m_aKeywords.GetSize();
+}
+
+HX_RESULT MetaInfo::GetKeyword(ULONG32 index, EncodedString& out) const
+{
+    INT32 idx = INT32(index);
+    if(idx < m_aKeywords.GetSize())
+    {
+        out = *((EncodedString*)m_aKeywords[idx]);
+        return HXR_OK;
+    }
+    return HXR_FAILED;
+}
+
+HX_RESULT MetaInfo::ClearKeywords()
+{
+    ClearPropertyStringArray(m_aKeywords);
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::AddKeyword(const EncodedString& val)
+{
+    if(val.GetByteLength() > 255)
+    {
+        return HXR_INVALID_PARAMETER;
+    }
+    
+    for(INT32 i = 0; i < m_aKeywords.GetSize(); i++)
+    {
+        if(*((EncodedString*)m_aKeywords[i]) == val)
+        {
+            return HXR_OK;
+        }
+    }
+    m_aKeywords.Add(new EncodedString(val));
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::RemoveKeyword(const EncodedString& val)
+{
+    for(INT32 i = 0; i < m_aKeywords.GetSize(); i++)
+    {
+        EncodedString* s = (EncodedString*)m_aKeywords[i];
+        if(*s == val)
+        {
+            delete s;
+            // Remaining keywords are shifted to fill the hole,
+            // search index must stay the same for new iteration.
+            m_aKeywords.RemoveAt(i--, 1);
+        }
+    }
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::RemoveKeywordDuplicates()
+{
+    CHXPtrArray aTmpKeywords;
+    for(INT32 i = 0; i < m_aKeywords.GetSize(); i++)
+    {
+        aTmpKeywords.Add(new EncodedString(*((EncodedString*)m_aKeywords[i])));
+    }
+
+    ClearPropertyStringArray(m_aKeywords);
+
+    for(INT32 i = 0; i < aTmpKeywords.GetSize(); i++)
+    {
+        AddKeyword(*((EncodedString*)aTmpKeywords[i]));
+    }
+
+    ClearPropertyStringArray(aTmpKeywords);
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::SetGlobalLanguageEncoding(const EncodedString& val)
+{
+    if(!val.IsAsciiOnly() || (val.GetCodeUnitLength(FALSE, FALSE) != 3))
+    {
+        return HXR_INVALID_PARAMETER;
+    }
+
+    EncodedString valConv;
+    val.ConvertToUTF8(valConv);
+    if(!val.GetData())
+    {
+        return HXR_FAILED;
+    }
+
+    CHXISO639LangCodeRegistry lcreg;
+    if(!lcreg.IsValidLangCode(valConv.GetData()))
+    {
+        return HXR_INVALID_PARAMETER;
+    }
+
+    m_stringItems[StringMetaItem_GlobalLanguageEncoding] = valConv;
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::SetStringAsciiMaxLen(EncodedString& dst, const EncodedString& val, ULONG32 maxLen)
+{
+    if(!val.IsAsciiOnly() || (val.GetCodeUnitLength(FALSE, FALSE) > maxLen))
+    {
+        return HXR_INVALID_PARAMETER;
+    }
+
+    dst = val;
+    return HXR_OK;
+}
+
+HX_RESULT MetaInfo::SetStringFixedPointNum(EncodedString& dst, const EncodedString& val)
+{
+    EncodedString normVal = val;
+    if(!PropTools::IsFixedPointNumber(normVal, TRUE))
+    {
+        return HXR_INVALID_PARAMETER;
+    }
+
+    dst = normVal;
+    return HXR_OK;
+}
+
+void MetaInfo::Update(EncodedString& dst, const EncodedString& src)
+{
+    if(!src.IsEmpty())
+    {
+        dst = src;
+    }
+}
+
+void MetaInfo::Dump(const char* propName, const EncodedString& val)
+{
+    if(!val.IsEmpty())
+    {
+        printf("%s: ", propName);
+        val.Dump();
+        printf("\n");
+    }
+}
+
+void MetaInfo::CopyString(eStringMetaItem dstItemName, HXBOOL bBlast, IHXValues* pSrcValues, const char* srcEnginePropName)
+{
+    EncodedString sTmp;
+    if(PropTools::CopyPropertyBuffer(sTmp, pSrcValues, srcEnginePropName))
+    {
+        m_stringItems[dstItemName] = sTmp;
+    }
+    else if(bBlast)
+    {
+        m_stringItems[dstItemName].Clear();
+    }
+}
+
+void MetaInfo::CopyString(IHXValues* pDstValues, HXBOOL bBlast, const char* dstEnginePropName, eStringMetaItem srcItemName) const
+{
+    PropTools::CopyPropertyBuffer(pDstValues, m_stringItems[srcItemName], dstEnginePropName, bBlast);
+}
+
+HX_RESULT MetaInfo::SetUlong(ULONG32& dstVal, HXBOOL& dstValid, ULONG32 srcVal, HXBOOL srcValid,
+                            ULONG32 minVal, ULONG32 maxVal)
+{
+    if(IsInRange(srcVal, minVal, maxVal))
+    {
+        dstVal = srcVal;
+        dstValid = srcValid;
+        return HXR_OK;
+    }
+    return HXR_INVALID_PARAMETER;
+}
+
+void MetaInfo::Update(ULONG32& dst, HXBOOL& dstValid, ULONG32 src, HXBOOL srcValid)
+{
+    if(srcValid)
+    {
+        dstValid = srcValid;
+        dst = src;
+    }
+}
+
+void MetaInfo::Dump(const char* propName, ULONG32 val, HXBOOL bValid)
+{
+    if(bValid)
+    {
+        printf("%s: dec=%u, hex=0x%08x\n", propName, val, val);
+    }
+}
+
+void MetaInfo::CopyULONG32(eUlongMetaItem dstItemName, HXBOOL bBlast, IHXValues* pSrcValues, const char* srcEnginePropName)
+{
+    ULONG32 uTmp = 0;
+    if(PropTools::CopyPropertyULONG32(uTmp, pSrcValues, srcEnginePropName))
+    {
+        m_ulongItems[dstItemName] = uTmp;
+        m_ulongItemValidFlags[dstItemName] = TRUE;
+    }
+    else if(bBlast)
+    {
+        m_ulongItems[dstItemName] = 0;
+        m_ulongItemValidFlags[dstItemName] = FALSE;
+    }
+}
+
+void MetaInfo::CopyULONG32(IHXValues* pDstValues, HXBOOL bBlast, const char* dstEnginePropName, eUlongMetaItem srcItemName) const
+{
+    PropTools::CopyPropertyULONG32(pDstValues, m_ulongItemValidFlags[srcItemName],
+                                    m_ulongItems[srcItemName], dstEnginePropName, bBlast);
+}
+
+void MetaInfo::ClearPropertyStringArray(CHXPtrArray& aStrings)
+{
+    for(INT32 i = 0; i < aStrings.GetSize(); i++)
+    {
+        delete (EncodedString*)aStrings[i];
+    }
+
+    aStrings.RemoveAll();
+}
+
Index: pub/metautil.h
===================================================================
RCS file: /cvsroot/datatype/common/util/pub/metautil.h,v
retrieving revision 1.4
diff -d -H -b -B -w -U30 -r1.4 metautil.h
--- pub/metautil.h	6 Jul 2007 22:00:24 -0000	1.4
+++ pub/metautil.h	19 Oct 2009 17:41:09 -0000
@@ -64,38 +64,276 @@
  * to the IHXFileFormatObject::GetFileHeader() call.
  *
  * In the function below, an IHXRequest is passed
  * in. If HX_RESULT returns HXR_OK, then the other
  * variables passed in by referenced can then be
  * examined in this order:
  *
  * If "AcceptMetaInfo" is present in the request headers,
  *   then rbAcceptMetaInfoPresent will be TRUE. Otherwise,
  *   it will be FALSE and rbAllMetaInfoRequested and
  *   rpRequestedMetaInfo will not be altered.
  *
  * If rbAcceptMetaInfoPresent is TRUE and
  *   AcceptMetaInfo = "*", then rbAllMetaInfoRequested
  *   will be TRUE and rpRequestedMetaInfo will be NULL.
  *
  * If rbAcceptMetaInfoPresent is TRUE and
  *   AcceptMetaInfo is a delimited string of property
  *   names, then rbAllMetaInfoRequested will be FALSE
  *   and rpRequestedMetaInfo will be non-NULL and will
  *   contain this list of property names as ULONG32
  *   properties. These property names can then be retrieved
  *   by using the IHXValues::GetFirstPropertyULONG32()
  *   and IHXValues::GetNextPropertyULONG32() calls.
  *   Note that this does not imply that the properties
  *   are necessarily ULONG32 properties - it's just
  *   more convenient to make them ULONG32 properties
  *   than CString or Buffer properties.
  */
 
+#include "hxtypes.h"
+#include "ihxmetaeditor.h"
+#include "metainfokeys.h"
+#include "carray.h"
+#include "encstr.h"
+
+
 HX_RESULT CheckMetaInfoRequest(IHXRequest*            pRequest,
                                IHXCommonClassFactory* pFactory,
                                REF(HXBOOL)              rbAcceptMetaInfoPresent,
                                REF(HXBOOL)              rbAllMetaInfoRequested,
                                REF(IHXValues*)        rpRequestedMetaInfo);
 
+//
+// ID3 utilities
+//
+class ID3Tools
+{
+public:
+    static HXBOOL GenreOrdinalFromName(const char* szGenreName, UINT8& outOrdinal,
+                                        HXBOOL bCaseSensitiveSearch = TRUE);
+
+    static const char* GenreNameFromOrdinal(UINT8 uGenreOrdinal);
+
+    // returns number of entries
+    static ULONG32 ParseGenreNameList(CHXPtrArray& outGenreOrdinals, const char* szGenreNames,
+                              HXBOOL bCaseSensitiveSearch = TRUE, char separator = ',',
+                              HXBOOL bTrimWhitespace = TRUE);
+
+    static void MakeGenreNameList(CHXString& outGenreNames, const CHXPtrArray& genreOrdinals,
+                            const char* szSeparator = ",");
+};
+
+//
+// Known metadata tools
+//
+class MetaInfo
+{
+public:
+    static HX_RESULT RemoveKeywordProperties(IHXValues* pValues);
+    static HX_RESULT CopyKeywordProperties(IHXValues* dst, IHXValues* src, HXBOOL bBlast);
+
+    static HX_RESULT RemoveAllProperties(IHXValues* pValues, ULONG32 metaInfoSetFlags);
+    static HX_RESULT CopyAllProperties(IHXValues* dst, IHXValues* src, ULONG32 metaInfoSetFlags, HXBOOL bBlast);
+
+    static ULONG32 GetSetsFromFlavors(ULONG32 metaFlavorFlags);
+    static CHXString GetFlavorName(METADATA_FLAVOR flavor);
+    static CHXString GetFlavorNames(ULONG32 metaFlavorFlags);
+
+    enum eStringMetaItem
+    {
+        StringMetaItem_StringItemBegin = 0,
+
+        StringMetaItem_Title = StringMetaItem_StringItemBegin,
+        StringMetaItem_Artist,
+        StringMetaItem_Album,
+        StringMetaItem_Genre,
+        StringMetaItem_Composer,
+        StringMetaItem_Comment,
+        StringMetaItem_Copyright,
+
+        StringMetaItem_TrackSubtitle, //iTunes
+        StringMetaItem_GeneratorTool, //iTunes
+        StringMetaItem_EncodedBy, //iTunes
+        StringMetaItem_Grouping, //iTunes
+        StringMetaItem_AlbumArtist, //iTunes
+        StringMetaItem_Lyrics, //iTunes
+
+        StringMetaItem_GlobalLanguageEncoding, //3GPP, exactly 3 ASCII characters, must be valid ISO639.2/T language code
+        StringMetaItem_RatingEntity, //3GPP, max 4 ASCII characters
+        StringMetaItem_RatingCriteria, //3GPP, max 4 ASCII characters
+        StringMetaItem_RatingInfo, //3GPP
+        StringMetaItem_ClassificationEntity, //3GPP, max 4 ASCII characters
+        StringMetaItem_ClassificationInfo, //3GPP
+        StringMetaItem_LocationName, //3GPP
+        StringMetaItem_LocationAstronomicalBody, //3GPP
+        StringMetaItem_LocationAdditionalNotes, //3GPP
+        StringMetaItem_LocationLongitude, //3GPP, fixed point number format
+        StringMetaItem_LocationLatitude, //3GPP, fixed point number format
+        StringMetaItem_LocationAltitude, //3GPP, fixed point number format
+
+        StringMetaItem_StringItemEnd, //special
+        StringMetaItem_StringItemCount = StringMetaItem_StringItemEnd - StringMetaItem_StringItemBegin, //special
+
+        StringMetaItem_Keywords //special, uncounted
+    };
+
+    static ULONG32 GetSetsWhichSupportItem(eStringMetaItem itemName);
+    static HXBOOL IsItemSupportedByAnySet(eStringMetaItem itemName, ULONG32 metaInfoSetFlags)
+    {
+        return (GetSetsWhichSupportItem(itemName) & metaInfoSetFlags) != 0;
+    }
+    static HXBOOL IsItemSupportedByAllSets(eStringMetaItem itemName, ULONG32 metaInfoSetFlags)
+    {
+        return (GetSetsWhichSupportItem(itemName) & metaInfoSetFlags) != metaInfoSetFlags;
+    }
+
+    static ULONG32 GetFlavorsWhichSupportItem(eStringMetaItem itemName);
+    static HXBOOL IsItemSupportedByAnyFlavor(eStringMetaItem itemName, ULONG32 metaFlavorFlags)
+    {
+        return (GetFlavorsWhichSupportItem(itemName) & metaFlavorFlags) != 0;
+    }
+    static HXBOOL IsItemSupportedByAllFlavors(eStringMetaItem itemName, ULONG32 metaFlavorFlags)
+    {
+        return (GetFlavorsWhichSupportItem(itemName) & metaFlavorFlags) == metaFlavorFlags;
+    }
+    static HXBOOL IsItemValueValidForFlavors(eStringMetaItem itemName, const EncodedString& val, ULONG32 metaFlavorFlags);
+
+    enum eUlongMetaItem
+    {
+        UlongMetaItem_UlongItemBegin = 0,
+        UlongMetaItem_TrackNumber = UlongMetaItem_UlongItemBegin, //3GPP UINT8, iTunes INT16
+        UlongMetaItem_RecordingYear, //3GPP UINT16, iTunes YYYY format [0-9999]
+
+        UlongMetaItem_BeatsPerMinute, //iTunes
+        UlongMetaItem_PartOfCompilation, //iTunes
+        UlongMetaItem_ExplicitContent, //iTunes
+        UlongMetaItem_TrackCount, //iTunes INT16
+        UlongMetaItem_DiscNumber, //iTunes INT16
+        UlongMetaItem_DiscCount, //iTunes INT16
+
+        UlongMetaItem_ClassificationTable, //3GPP UINT16
+        UlongMetaItem_LocationRole, //3GPP UINT8
+
+        UlongMetaItem_UlongItemEnd, //special
+        UlongMetaItem_UlongItemCount = UlongMetaItem_UlongItemEnd - UlongMetaItem_UlongItemBegin, //special
+    };
+
+    static ULONG32 GetSetsWhichSupportItem(eUlongMetaItem itemName);
+    static HXBOOL IsItemSupportedByAnySet(eUlongMetaItem itemName, ULONG32 metaInfoSetFlags)
+    {
+        return (GetSetsWhichSupportItem(itemName) & metaInfoSetFlags) != 0;
+    }
+    static HXBOOL IsItemSupportedByAllSets(eUlongMetaItem itemName, ULONG32 metaInfoSetFlags)
+    {
+        return (GetSetsWhichSupportItem(itemName) & metaInfoSetFlags) != metaInfoSetFlags;
+    }
+
+    static ULONG32 GetFlavorsWhichSupportItem(eUlongMetaItem itemName);
+    static HXBOOL IsItemSupportedByAnyFlavor(eUlongMetaItem itemName, ULONG32 metaFlavorFlags)
+    {
+        return (GetFlavorsWhichSupportItem(itemName) & metaFlavorFlags) != 0;
+    }
+    static HXBOOL IsItemSupportedByAllFlavors(eUlongMetaItem itemName, ULONG32 metaFlavorFlags)
+    {
+        return (GetFlavorsWhichSupportItem(itemName) & metaFlavorFlags) != metaFlavorFlags;
+    }
+    static HXBOOL IsItemValueValidForFlavors(eUlongMetaItem itemName, ULONG32 val, ULONG32 metaFlavorFlags);
+
+public:
+    MetaInfo();
+    ~MetaInfo();
+
+    MetaInfo(const MetaInfo& rhs);
+    MetaInfo& operator=(const MetaInfo& rhs);
+
+    void Dump(ULONG32 metaInfoSetFlags = METAINFO_SET_ALL);
+
+    void Clear();
+    void ClearItems(ULONG32 metaInfoSetFlags = METAINFO_SET_ALL);
+    void UpdateItems(const MetaInfo& src, ULONG32 metaInfoSetFlags = METAINFO_SET_ALL);
+
+    void CopyToValues(IHXValues* pValues, HXBOOL bBlast, ULONG32 metaInfoSetFlags = METAINFO_SET_ALL) const;
+    void CopyFromValues(IHXValues* pValues, HXBOOL bBlast, ULONG32 metaInfoSetFlags = METAINFO_SET_ALL);
+
+    // Getters always update <out>.
+    // String getters return success if <out> is empty.
+    // UINT getters return success if the value copied to <out> is considered valid.
+    HX_RESULT GetStringItem(eStringMetaItem itemName, EncodedString& out) const;
+    HX_RESULT SetStringItem(eStringMetaItem itemName, const EncodedString& val, ULONG32 metaFlavorFlags = METADATA_FLAVOR_ALL);
+
+    HX_RESULT GetUlongItem(eUlongMetaItem itemName, ULONG32& out) const;
+    HX_RESULT SetUlongItem(eUlongMetaItem itemName, ULONG32 val, HXBOOL bValid, ULONG32 metaFlavorFlags = METADATA_FLAVOR_ALL);
+
+    // 3GPP keywords
+    ULONG32 GetKeywordCount() const;
+
+    // Returns FALSE if <index> is out of range.
+    HX_RESULT GetKeyword(ULONG32 index, EncodedString& out) const;
+    HX_RESULT ClearKeywords();
+
+    // Returns FALSE if the byte-length of <val> is greater than 255 (maximum allowed by 3GPP).
+    // Also, maximum number of keywords that can be written to 3GPP file is 255 (this method
+    // does not check this to allow easier addition/removal, so this should be checked after
+    // changes by calling GetKeywordCount and taking appropriate actions).
+    HX_RESULT AddKeyword(const EncodedString& val);
+    HX_RESULT RemoveKeyword(const EncodedString& val);
+    HX_RESULT RemoveKeywordDuplicates();
+
+private:
+    HX_RESULT SetGlobalLanguageEncoding(const EncodedString& val);
+    static HX_RESULT SetStringAsciiMaxLen(EncodedString& dst, const EncodedString& val, ULONG32 maxLen);
+    static HX_RESULT SetStringFixedPointNum(EncodedString& dst, const EncodedString& val);
+    static void Update(EncodedString& dst, const EncodedString& src);
+    static void Dump(const char* propName, const EncodedString& val);
+    void CopyString(eStringMetaItem dstItemName, HXBOOL bBlast, IHXValues* pSrcValues, const char* srcEnginePropName);
+    void CopyString(IHXValues* pDstValues, HXBOOL bBlast, const char* dstEnginePropName, eStringMetaItem srcItemName) const;
+
+    static HXBOOL IsInRange(ULONG32 val, ULONG32 min, ULONG32 max)
+    {
+        return (val >= min) && (val <= max);
+    }
+    static HXBOOL IsInRange16(ULONG32 val)
+    {
+        return IsInRange(val, 0, 0x0000FFFF);
+    }
+    static HXBOOL IsInRange8(ULONG32 val)
+    {
+        return IsInRange(val, 0, 0x000000FF);
+    }
+    static HXBOOL IsInRangeBoolean(ULONG32 val)
+    {
+        return IsInRange(val, 0, 1);
+    }
+    static HX_RESULT SetUlong(ULONG32& dstVal, HXBOOL& dstValid, ULONG32 srcVal, HXBOOL srcValid,
+                            ULONG32 minVal = 0, ULONG32 maxVal = 0xFFFFFFFF);
+
+    static HX_RESULT SetUlong16(ULONG32& dstVal, HXBOOL& dstValid, ULONG32 srcVal, HXBOOL srcValid)
+    {
+        return SetUlong(dstVal, dstValid, srcVal, srcValid, 0, 0x0000FFFF);
+    }
+    static HX_RESULT SetUlong8(ULONG32& dstVal, HXBOOL& dstValid, ULONG32 srcVal, HXBOOL srcValid)
+    {
+        return SetUlong(dstVal, dstValid, srcVal, srcValid, 0, 0x000000FF);
+    }
+    static HX_RESULT SetUlongBoolean(ULONG32& dstVal, HXBOOL& dstValid, ULONG32 srcVal, HXBOOL srcValid)
+    {
+        return SetUlong(dstVal, dstValid, srcVal, srcValid, 0, 1);
+    }
+    static void Update(ULONG32& dst, HXBOOL& dstValid, ULONG32 src, HXBOOL srcValid);
+    static void Dump(const char* propName, ULONG32 val, HXBOOL bValid);
+    void CopyULONG32(eUlongMetaItem dstItemName, HXBOOL bBlast, IHXValues* pSrcValues, const char* srcEnginePropName);
+    void CopyULONG32(IHXValues* pDstValues, HXBOOL bBlast, const char* dstEnginePropName, eUlongMetaItem srcItemName) const;
+
+    static void ClearPropertyStringArray(CHXPtrArray& aStrings);
+
+private:
+    EncodedString m_stringItems[StringMetaItem_StringItemCount];
+
+    HXBOOL m_ulongItemValidFlags[UlongMetaItem_UlongItemCount];
+    ULONG32 m_ulongItems[UlongMetaItem_UlongItemCount];
+
+    CHXPtrArray m_aKeywords;
+};
 
 #endif /* #ifndef METAUTIL_H */
datatype_include.diff (text/x-patch, 8 KB)
Index: metainfokeys.h
===================================================================
RCS file: /cvsroot/datatype/include/metainfokeys.h,v
retrieving revision 1.3
diff -d -H -b -B -w -U30 -r1.3 metainfokeys.h
--- metainfokeys.h	5 Nov 2007 21:36:26 -0000	1.3
+++ metainfokeys.h	19 Oct 2009 17:40:53 -0000
@@ -9,63 +9,110 @@
  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  * the file under the RealNetworks Community Source License Version 1.0 
  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  * in which case the RCSL will apply. You may also obtain the license terms 
  * directly from RealNetworks.  You may not use this file except in 
  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  * RCSL for the rights, obligations and limitations governing use of the 
  * contents of the file.  
  *  
  * This file is part of the Helix DNA Technology. RealNetworks is the 
  * developer of the Original Code and owns the copyrights in the portions 
  * it created. 
  *  
  * This file, and the files included with this file, is distributed and made 
  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  * 
  * Technology Compatibility Kit Test Suite(s) Location: 
  *    http://www.helixcommunity.org/content/tck 
  * 
  * Contributor(s): 
  *  
  * ***** END LICENSE BLOCK ***** */ 
 
 #ifndef _METAINFOKEYS_H_
 #define _METAINFOKEYS_H_ 
 
-#if (defined HELIX_FEATURE_3GPP_METAINFO || defined HELIX_FEATURE_SERVER)
+
+typedef enum 
+{
+    METAINFO_SET_GENERIC          = 0x00000001,
+    METAINFO_SET_3GPP_SPECIFIC    = 0x00000010,
+    METAINFO_SET_3GPP_ALL         = METAINFO_SET_GENERIC | METAINFO_SET_3GPP_SPECIFIC,
+    METAINFO_SET_ITUNES_SPECIFIC  = 0x00000100,
+    METAINFO_SET_ITUNES_ALL       = METAINFO_SET_GENERIC | METAINFO_SET_ITUNES_SPECIFIC,
+    METAINFO_SET_ALL              = METAINFO_SET_GENERIC | METAINFO_SET_3GPP_SPECIFIC | METAINFO_SET_ITUNES_SPECIFIC
+} METAINFO_SET;
+
+// Generic set
+#define _GENERIC_META_INFO_TITLE_KEY                    "Title"
+#define _GENERIC_META_INFO_COMPOSER_KEY                 "Author"
+#define _GENERIC_META_INFO_COPYRIGHT_KEY                "Copyright"
+#define _GENERIC_META_INFO_COMMENT_KEY                  "Abstract"
+#define _GENERIC_META_INFO_ARTIST_KEY                   "Performer"
+#define _GENERIC_META_INFO_GENRE_KEY                    "Genre"
+#define _GENERIC_META_INFO_ALBUM_KEY                    "AlbumTitle"
+#define _GENERIC_META_INFO_TRACK_NUMBER_KEY             "TrackNumber"
+#define _GENERIC_META_INFO_RECORDING_YEAR_KEY           "RecordingYear"
+
+// iTunes aliases for Generic set, for use in file-format/file-writer
+#define _ITUNES_META_INFO_TITLE_KEY                     _GENERIC_META_INFO_TITLE_KEY
+#define _ITUNES_META_INFO_COMPOSER_KEY                  _GENERIC_META_INFO_COMPOSER_KEY
+#define _ITUNES_META_INFO_COPYRIGHT_KEY                 _GENERIC_META_INFO_COPYRIGHT_KEY
+#define _ITUNES_META_INFO_COMMENT_KEY                   _GENERIC_META_INFO_COMMENT_KEY
+#define _ITUNES_META_INFO_ARTIST_KEY                    _GENERIC_META_INFO_ARTIST_KEY
+#define _ITUNES_META_INFO_GENRE_KEY                     _GENERIC_META_INFO_GENRE_KEY
+#define _ITUNES_META_INFO_ALBUM_KEY                     _GENERIC_META_INFO_ALBUM_KEY
+#define _ITUNES_META_INFO_TRACK_NUMBER_KEY              _GENERIC_META_INFO_TRACK_NUMBER_KEY
+#define _ITUNES_META_INFO_RELEASE_DATE_KEY              _GENERIC_META_INFO_RECORDING_YEAR_KEY
+
+// iTunes specific set
+#define _ITUNES_META_INFO_TRACK_SUBTITLE_KEY            "TrackSubtitle"
+#define _ITUNES_META_INFO_GENERATOR_TOOL_KEY            "GeneratorTool"
+#define _ITUNES_META_INFO_ENCODED_BY_KEY                "EncodedBy"
+#define _ITUNES_META_INFO_GROUPING_KEY                  "Grouping"
+#define _ITUNES_META_INFO_ALBUM_ARTIST_KEY              "AlbumArtist"
+#define _ITUNES_META_INFO_LYRICS_KEY                    "Lyrics"
+#define _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY          "BeatsPerMinute"
+#define _ITUNES_META_INFO_PART_OF_COMPILATION_KEY       "PartOfCompilation"
+#define _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY          "ExplicitContent"
+#define _ITUNES_META_INFO_TRACK_COUNT_KEY               "TrackCount"
+#define _ITUNES_META_INFO_DISC_NUMBER_KEY               "DiscNumber"
+#define _ITUNES_META_INFO_DISC_COUNT_KEY                "DiscCount"
+
+// 3GPP aliases for Generic set, for use in file-format/file-writer
+#define _3GPP_META_INFO_TITLE_KEY                       _GENERIC_META_INFO_TITLE_KEY
+#define _3GPP_META_INFO_AUTHOR_KEY                      _GENERIC_META_INFO_COMPOSER_KEY
+#define _3GPP_META_INFO_COPYRIGHT_KEY                   _GENERIC_META_INFO_COPYRIGHT_KEY
+#define _3GPP_META_INFO_DESCRIPTION_KEY                 _GENERIC_META_INFO_COMMENT_KEY
+#define _3GPP_META_INFO_PERFORMER_KEY                   _GENERIC_META_INFO_ARTIST_KEY
+#define _3GPP_META_INFO_GENRE_KEY                       _GENERIC_META_INFO_GENRE_KEY
+#define _3GPP_META_INFO_ALBUM_TITLE_KEY                 _GENERIC_META_INFO_ALBUM_KEY
+#define _3GPP_META_INFO_TRACK_NUMBER_KEY                _GENERIC_META_INFO_TRACK_NUMBER_KEY
+#define _3GPP_META_INFO_RECORDING_YEAR_KEY              _GENERIC_META_INFO_RECORDING_YEAR_KEY
+
+// 3GPP specific set
 #define _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY    "GlobalLanguageEncoding"
-#define _3GPP_META_INFO_TITLE_KEY                       "Title"
-#define _3GPP_META_INFO_AUTHOR_KEY                      "Author"
-#define _3GPP_META_INFO_COPYRIGHT_KEY                   "Copyright"
-#ifdef HELIX_FEATURE_3GPP_METAINFO
-#define _3GPP_META_INFO_DESCRIPTION_KEY                 "Abstract"
-#define _3GPP_META_INFO_PERFORMER_KEY                   "Performer"
-#define _3GPP_META_INFO_GENRE_KEY                       "Genre"
-#define _3GPP_META_INFO_RATING_KEY                      "Rating" //obsolete define, use RATING_CRITERIA instead
 #define _3GPP_META_INFO_RATING_ENTITY_KEY               "RatingEntity"
-#define _3GPP_META_INFO_RATING_CRITERIA_KEY             "Rating"
+#define _3GPP_META_INFO_RATING_CRITERIA_KEY             "RatingCriteria"
 #define _3GPP_META_INFO_RATING_INFO_KEY                 "RatingInfo"
 #define _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY       "ClassificationEntity"
-#define _3GPP_META_INFO_CLASSIFICATION_INFO_KEY         "ClassificationInfo"
 #define _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY        "ClassificationTable"
-#define _3GPP_META_INFO_KEYWORD_COUNT_KEY               "KeywordCount"
-#define _3GPP_META_INFO_KEYWORD_KEY                     "Keyword%d"
+#define _3GPP_META_INFO_CLASSIFICATION_INFO_KEY         "ClassificationInfo"
 #define _3GPP_META_INFO_LOCATION_NAME_KEY               "LocationName"
 #define _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY  "LocationAstronomicalBody"
 #define _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY   "LocationAdditionalNotes"
 #define _3GPP_META_INFO_LOCATION_ROLE_KEY               "LocationRole"
 #define _3GPP_META_INFO_LOCATION_LONGITUDE_KEY          "LocationLongitude"
 #define _3GPP_META_INFO_LOCATION_LATITUDE_KEY           "LocationLatitude"
 #define _3GPP_META_INFO_LOCATION_ALTITUDE_KEY           "LocationAltitude"
-#define _3GPP_META_INFO_ALBUM_TITLE_KEY                 "AlbumTitle"
-#define _3GPP_META_INFO_TRACK_NUMBER_KEY                "AlbumTrackNumber"
-#define _3GPP_META_INFO_RECORDING_YEAR_KEY              "RecordingYear"
-#endif // HELIX_FEATURE_3GPP_METAINFO
-#endif // HELIX_FEATURE_3GPP_METAINFO || HELIX_FEATURE_SERVER
+#define _3GPP_META_INFO_KEYWORD_COUNT_KEY               "KeywordCount"
+#define _3GPP_META_INFO_KEYWORD_KEY                     "Keyword%d"
+#define _3GPP_META_INFO_ID32_BLOB_KEY                   "ID32BLOB"
+
 
 #endif // _METAINFOKEYS_H_
datatype_mp4_fileformat.diff (text/x-patch, 142.4 KB) - not displayed
datatype_mp4_filewriter.diff (text/x-patch, 97.9 KB)
Index: 3gpmeta.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/3gpmeta.cpp,v
retrieving revision 1.2
diff -d -H -b -B -w -U30 -r1.2 3gpmeta.cpp
--- 3gpmeta.cpp	20 Apr 2009 17:24:05 -0000	1.2
+++ 3gpmeta.cpp	19 Oct 2009 17:45:14 -0000
@@ -489,30 +489,71 @@
     return retVal;
 }
 
 C3GPAtom_yrrc::C3GPAtom_yrrc()
     : CMP4VersionedAtom(MP4_BUILD_ATOMID('y','r','r','c'))
 {
     m_year = 0;
 }
 
 void C3GPAtom_yrrc::SetRecordingYear(UINT16 year)
 {
     m_year = year;
 }
 
 STDMETHODIMP_(UINT32) C3GPAtom_yrrc::GetCurrentSize(THIS_ HXBOOL bIncludeChildren)
 {
     return CMP4VersionedAtom::GetCurrentSize( bIncludeChildren ) +
             sizeof(UINT16);
 }
 
 STDMETHODIMP C3GPAtom_yrrc::WriteToBuffer(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren)
 {
     HX_RESULT retVal = HXR_OK;
     if( pBuffer )
     {
         CMP4VersionedAtom::WriteAtomAndVersionInfo( pBuffer );
         CMP4Atom::WriteToBufferAndInc( pBuffer, m_year );
     }
     return retVal;
 }
+
+C3GPAtom_ID32::C3GPAtom_ID32()
+    : C3GPAtom_LangBase(MP4_BUILD_ATOMID('I','D','3','2'))
+    , m_pBlob(0)
+    , m_uBlobSize(0)
+{
+}
+
+C3GPAtom_ID32::~C3GPAtom_ID32()
+{
+    HX_VECTOR_DELETE(m_pBlob);
+}
+
+void C3GPAtom_ID32::SetBlob(UCHAR* pData, UINT32 size)
+{
+    HX_VECTOR_DELETE(m_pBlob);
+    m_uBlobSize = size;
+    m_pBlob = new UCHAR[size];
+    memcpy(m_pBlob, pData, size);
+}
+
+STDMETHODIMP_(UINT32) C3GPAtom_ID32::GetCurrentSize(THIS_ HXBOOL bIncludeChildren)
+{
+    return C3GPAtom_LangBase::GetCurrentSize( bIncludeChildren ) +
+                m_uBlobSize;
+}
+
+STDMETHODIMP C3GPAtom_ID32::WriteToBuffer(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren)
+{
+    HX_RESULT retVal = HXR_OK;
+    if(pBuffer)
+    {
+        CMP4VersionedAtom::WriteAtomAndVersionInfo( pBuffer );
+        C3GPAtom_LangBase::WriteLanguageToBuffer( pBuffer );
+        if(m_uBlobSize)
+        {
+            CMP4Atom::WriteToBufferAndInc( pBuffer, (UCHAR*)m_pBlob, m_uBlobSize );
+        }
+    }
+    return retVal;
+}
Index: 3gpmeta.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/3gpmeta.h,v
retrieving revision 1.4
diff -d -H -b -B -w -U30 -r1.4 3gpmeta.h
--- 3gpmeta.h	20 Apr 2009 17:24:05 -0000	1.4
+++ 3gpmeta.h	19 Oct 2009 17:45:15 -0000
@@ -12,63 +12,66 @@
  * in which case the RCSL will apply. You may also obtain the license terms
  * directly from RealNetworks.  You may not use this file except in
  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
  * applicable to this file, the RCSL.  Please see the applicable RPSL or
  * RCSL for the rights, obligations and limitations governing use of the
  * contents of the file.
  *
  * This file is part of the Helix DNA Technology. RealNetworks is the
  * developer of the Original Code and owns the copyrights in the portions
  * it created.
  *
  * This file, and the files included with this file, is distributed and made
  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  *
  * Technology Compatibility Kit Test Suite(s) Location:
  *    http://www.helixcommunity.org/content/tck
  *
  * Contributor(s):
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _3GPMETA_H_
 #define _3GPMETA_H_
 
 #include "mp4atoms.h"
 #include "proptools.h"
 
+//*****************************************************************************
 // 3GP asset meta data
-// top level 3GP asset meta data is a user-data box
-// most 3GP meta info sub-boxes has the same format of full_box + language + string
+// Container box for 3GP asset metadata is 'udta' box.
+// Exception is ID3v2 box which must reside in 'meta' box.
+// 'meta' box itself can reside at file, 'moov' or 'trak' level.
+// Most 3GP metadata boxes have the same format: full_box + language + string
 //
 class C3GPAtom_LangBase : public CMP4VersionedAtom
 {
 public:
     static void ConfigureStringOutput(HXBOOL bUseUTF16);
     static HXBOOL IsStringOutputUTF16(HXBOOL bUseUTF16);
 
 public:
     C3GPAtom_LangBase(UINT32 ulAtomID);
 
     void InitLanguage();
     void SetLanguage(const UCHAR* lang);
     void SetLanguage(const char* lang)
     {
         SetLanguage(reinterpret_cast<const UCHAR*>(lang));
     }
     UINT32 GetLanguageSize()
     {
         return sizeof(UINT16);
     }
     void WriteLanguageToBuffer(UCHAR*& pBuffer);
 
     STDMETHOD_(UINT32, GetCurrentSize)(THIS_ HXBOOL bIncludeChildren = FALSE);
     STDMETHOD(WriteToBuffer)(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE);
 
 protected:
     // utilities which simplify definitions of string atom parts
     static char* EncodeStringForOutput(const char* psz, HX_TEXT_ENCODING_TYPE et);
     void InitStringPartImp(char*& pszPart);
     void DeleteStringPartImp(char*& pszPart);
@@ -261,31 +264,48 @@
     void SetString_AlbumTitle(const char* psz, HX_TEXT_ENCODING_TYPE et)
     {
         SetStringPartImp(m_pszAlbumTitle, psz, et);
     }
     void SetTrackNumber(HXBOOL includeTrackNum, UINT8 trackNum);
 
     STDMETHOD_(UINT32, GetCurrentSize)(THIS_ HXBOOL bIncludeChildren = FALSE);
     STDMETHOD(WriteToBuffer)(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE);
 
 private:
     char* m_pszAlbumTitle;
     HXBOOL m_include_tracknum;
     UINT8 m_tracknum;
 };
 
 // Recording Year
 class C3GPAtom_yrrc : public CMP4VersionedAtom
 {
 public:
     C3GPAtom_yrrc();
 
     void SetRecordingYear(UINT16 year);
 
     STDMETHOD_(UINT32, GetCurrentSize)(THIS_ HXBOOL bIncludeChildren = FALSE);
     STDMETHOD(WriteToBuffer)(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE);
 
 private:
     UINT16 m_year;
 };
 
+// ID32
+class C3GPAtom_ID32 : public C3GPAtom_LangBase
+{
+public:
+    C3GPAtom_ID32();
+    virtual ~C3GPAtom_ID32();
+
+    void SetBlob(UCHAR* pData, UINT32 size);
+
+    STDMETHOD_(UINT32, GetCurrentSize)(THIS_ HXBOOL bIncludeChildren = FALSE);
+    STDMETHOD(WriteToBuffer)(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE);
+
+private:
+    UCHAR* m_pBlob;
+    UINT32 m_uBlobSize;
+};
+
 #endif  /* _3GPMETA_H_ */
Index: m4amdatoms.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/m4amdatoms.h,v
retrieving revision 1.6
diff -d -H -b -B -w -U30 -r1.6 m4amdatoms.h
--- m4amdatoms.h	20 Apr 2009 17:24:05 -0000	1.6
+++ m4amdatoms.h	19 Oct 2009 17:45:15 -0000
@@ -16,377 +16,546 @@
  * RCSL for the rights, obligations and limitations governing use of the
  * contents of the file.
  *
  * This file is part of the Helix DNA Technology. RealNetworks is the
  * developer of the Original Code and owns the copyrights in the portions
  * it created.
  *
  * This file, and the files included with this file, is distributed and made
  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  *
  * Technology Compatibility Kit Test Suite(s) Location:
  *    http://www.helixcommunity.org/content/tck
  *
  * Contributor(s):
  *
  * ***** END LICENSE BLOCK ***** */
 // m4amdatoms.h: atoms specific to m4a metadata
 
 #ifndef _M4AMDATOMS_H_
 #define _M4AMDATOMS_H_
 
 #include "mp4atoms.h"
 
 //iTunes stype meta info
 
 // meta; this is the top level atom inside the udta, and all
 //       metadata atoms live inside it
-class CM4AAtom_meta : public CMP4VersionedAtom
+class CiTunesAtom_meta : public CMP4VersionedAtom
 {
 public:
-    CM4AAtom_meta() : CMP4VersionedAtom(MP4_BUILD_ATOMID('m','e','t','a'))
+    CiTunesAtom_meta() : CMP4VersionedAtom(MP4_BUILD_ATOMID('m','e','t','a'))
 	{}
     STDMETHOD( WriteToBuffer )    (THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE )
 	{
 	    HX_RESULT retVal = HXR_OK;
 	    
 	    if( pBuffer )
 	    {
 		CMP4VersionedAtom::WriteAtomAndVersionInfo( pBuffer );
 
 		if( bIncludeChildren )
 		{
 		    retVal = ChildrenWriteToBuffer( pBuffer );
 		}
 	    }
 	    return retVal;
 	}
 };
 
-class CM4AAtom_ilst : public CMP4ContainerAtom
-{
-public:
-    CM4AAtom_ilst() : CMP4ContainerAtom(MP4_BUILD_ATOMID('i','l','s','t'))
-	{}
-};
-
-class CM4AAtom_hdlr : public CMP4VersionedAtom
+class CiTunesAtom_hdlr : public CMP4VersionedAtom
 {
 public:
-    CM4AAtom_hdlr() : CMP4VersionedAtom(MP4_BUILD_ATOMID('h','d','l','r'))
+    CiTunesAtom_hdlr() : CMP4VersionedAtom(MP4_BUILD_ATOMID('h','d','l','r'))
 	{
 	    m_uiHdlrType = 0;
 	    m_uiHdlrSubType = MP4_BUILD_ATOMID('m','d','i','r');
 	    m_uiHdlrManufacturer = MP4_BUILD_ATOMID('a','p','p','l');
 	    m_uiComponentFlags = 0;
 	    m_uiComponentFlagsMask = 0;
 	    m_pszName = NULL;
 	    m_uiNameLength = 2;
 	}
-    ~CM4AAtom_hdlr()
+    ~CiTunesAtom_hdlr()
 	{
 	    HX_VECTOR_DELETE( m_pszName );
 	}
     STDMETHOD_( UINT32, GetCurrentSize )            ( THIS_ HXBOOL bIncludeChildren = FALSE )
 	{
 	    UINT32 len = CMP4VersionedAtom::GetCurrentSize( bIncludeChildren )
 			 + 4 + 4 + 4 + 4 + 4;
 	    len += m_uiNameLength;
 	    return len;
 	}
     STDMETHOD( WriteToBuffer )                 (THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE)
 	{
 	    HX_RESULT retVal = HXR_OK;
 
 	    if( pBuffer )
 	    {
 		CMP4VersionedAtom::WriteAtomAndVersionInfo( pBuffer );
 		
 		CMP4Atom::WriteToBufferAndInc( pBuffer, m_uiHdlrType );
 		CMP4Atom::WriteToBufferAndInc( pBuffer, m_uiHdlrSubType );
 		CMP4Atom::WriteToBufferAndInc( pBuffer, m_uiHdlrManufacturer );
 		CMP4Atom::WriteToBufferAndInc( pBuffer, m_uiComponentFlags );
 		CMP4Atom::WriteToBufferAndInc( pBuffer, m_uiComponentFlagsMask );
 
 		if( m_pszName )
 		{
 		    CMP4Atom::WriteToBufferAndInc( pBuffer, m_pszName, m_uiNameLength );
 		} else
 		{
 		    CMP4Atom::WriteToBufferAndInc( pBuffer, (UCHAR*)"\0Z", 2 );
 		}
 		
 
 		if( bIncludeChildren )
 		{
 		    retVal = ChildrenWriteToBuffer( pBuffer );
 		}
 	    }
 	    return retVal;
 	}
     
 private:
     UINT32 m_uiHdlrType;
     UINT32 m_uiHdlrSubType;
     UINT32 m_uiHdlrManufacturer;
     UINT32 m_uiComponentFlags;
     UINT32 m_uiComponentFlagsMask;
     UCHAR* m_pszName;
     UINT32 m_uiNameLength;
 };
 
-class CM4AAtom_data : public CMP4VersionedAtom
+class CiTunesAtom_ilst : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_data() : CMP4VersionedAtom(MP4_BUILD_ATOMID('d','a','t','a'))
+    CiTunesAtom_ilst() : CMP4ContainerAtom(MP4_BUILD_ATOMID('i','l','s','t'))
+	{}
+};
+
+class CiTunesAtom_data : public CMP4Atom
 	{
-	    m_reserved = 0;
-	    m_ucBinStrBuf = NULL;
-	    m_uiIntBuf = NULL;
-	    m_uiDataLength = 0;
+public:
+    CiTunesAtom_data() : CMP4Atom(MP4_BUILD_ATOMID('d','a','t','a'))
+	{
+	    m_typeIndicatorReserved = 0;
+            m_typeIndicatorTypeSetIdentifier = 0;
+            SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Implicit);
+	    m_localeIndicator = 0;
+            m_uiByteBufLength = 0;
+	    m_ucByteBuf = NULL;
 	}
-    ~CM4AAtom_data()
+    ~CiTunesAtom_data()
 	{
-	    HX_VECTOR_DELETE( m_ucBinStrBuf );
-	    HX_VECTOR_DELETE( m_uiIntBuf );
+            ClearData();
 	}
     STDMETHOD_(UINT32, GetCurrentSize )     (THIS_ HXBOOL bIncludeChildren = FALSE)
 	{
-	    UINT32 len = CMP4VersionedAtom::GetCurrentSize(bIncludeChildren)
-			 + 4 + m_uiDataLength;
-	    return len;
+            // BaseAtomSize + TypeIndicatorReserved + TypeIndicatorTypeSetIdentifier + TypeIndicatorTypeCode + LocaleIndicator
+	    UINT32 len = 8 + 2 + 1 + 1 + 4;
+
+            if( m_uiByteBufLength )
+            {
+                len += m_uiByteBufLength;
+            }
+
+            return len + (bIncludeChildren ? GetSizeOfChildren() : 0);
 	}
     STDMETHOD( WriteToBuffer )      (THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren = FALSE)
 	{
 	    HX_RESULT retVal = HXR_OK;
 
 	    if( pBuffer )
 	    {
-		CMP4VersionedAtom::WriteAtomAndVersionInfo( pBuffer );
+                CMP4Atom::WriteToBufferAndInc( pBuffer, GetCurrentSize() );
+                CMP4Atom::WriteToBufferAndInc( pBuffer, m_ulAtomID );
 
-		CMP4Atom::WriteToBufferAndInc( pBuffer, m_reserved );
+		CMP4Atom::WriteToBufferAndInc( pBuffer, m_typeIndicatorReserved );
+		CMP4Atom::WriteToBufferAndInc( pBuffer, m_typeIndicatorTypeSetIdentifier );
+		CMP4Atom::WriteToBufferAndInc( pBuffer, m_typeIndicatorTypeCode );
+		CMP4Atom::WriteToBufferAndInc( pBuffer, m_localeIndicator );
 
-		if( m_uiFlags == _DataFlags::INT )
-		{
-		    CMP4Atom::WriteToBufferAndInc( pBuffer, m_uiIntBuf, m_uiDataLength );
-		}
-		else
+                if( m_uiByteBufLength )
 		{
-		    CMP4Atom::WriteToBufferAndInc( pBuffer, m_ucBinStrBuf, m_uiDataLength );
+                    CMP4Atom::WriteToBufferAndInc( pBuffer, m_ucByteBuf, m_uiByteBufLength );
 		}
 
 		if( bIncludeChildren )
 		{
 		    retVal = ChildrenWriteToBuffer( pBuffer );
 		}
 	    }
 	    return retVal;
 	}
 
     /*
      * Local routines
      */
-    STDMETHOD( SetString )          (THIS_ const UCHAR* pszString)
+    STDMETHOD( SetBytes ) (THIS_ const UCHAR* pBytes, UINT32 len )
 	{
-	    HX_RESULT retVal = HXR_INVALID_PARAMETER;
+	    HX_RESULT retVal = AllocBuffer(len);
 	    
-	    if( pszString )
+	    if( SUCCEEDED(retVal) && pBytes )
 	    {
-		UINT32 len = strlen((const char*)pszString);
-		m_ucBinStrBuf = new UCHAR[ len ];
-		retVal = HXR_OUTOFMEMORY;
-		
-		if( m_ucBinStrBuf )
+                memcpy(m_ucByteBuf, pBytes, len);
+	    }
+	    return retVal;
+	}
+    STDMETHOD( SetUTF8String ) (THIS_ const char* pStr, UINT32 byteLengthWithoutTerm )
 		{
-		    memcpy( m_ucBinStrBuf, pszString, len );
-		    m_uiDataLength = len;
-		    CMP4VersionedAtom::m_uiFlags = _DataFlags::STRING;
+            HX_RESULT retVal = SetBytes((const UCHAR*)pStr, byteLengthWithoutTerm);
+            if( SUCCEEDED(retVal) )
+            {
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_UTF8);
+            }
+            return retVal;
+        }
+    STDMETHOD( SetUTF16BEString ) (THIS_ const char* pStr, UINT32 byteLengthWithoutTerm )
+	{
+            HX_RESULT retVal = SetBytes((const UCHAR*)pStr, byteLengthWithoutTerm);
+            if( SUCCEEDED(retVal) )
+            {
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_UTF16BE);
+            }
+            return retVal;
+        }
+    STDMETHOD( SetUInteger32 ) (THIS_ ULONG32 value )
+	{
+            // 4 bytes
+            HX_RESULT retVal = AllocBuffer(4);
+            if( SUCCEEDED(retVal) )
+            {
+                // write integer in BE order
+                UCHAR* pBuffer = m_ucByteBuf;
+                WriteToBufferAndInc(pBuffer, value);
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Integer);
+            }
+            return retVal;
+        }
+    STDMETHOD( SetUInteger16 ) (THIS_ ULONG32 value )
+	{
+            // 2 bytes
+            HX_RESULT retVal = AllocBuffer(2);
+            if( SUCCEEDED(retVal) )
+            {
+                // write integer in BE order
+                UCHAR* pBuffer = m_ucByteBuf;
+                WriteToBufferAndInc(pBuffer, static_cast<UINT16>(value & 0x000000FF));
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Integer);
+            }
+            return retVal;
+        }
+    STDMETHOD( SetUInteger8 ) (THIS_ ULONG32 value )
+	{
+            // 1 byte
+            HX_RESULT retVal = AllocBuffer(1);
+            if( SUCCEEDED(retVal) )
+            {
+                m_ucByteBuf[0] = static_cast<UCHAR>(value & 0x000000FF);
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Integer);
+            }
+            return retVal;
+        }
+    STDMETHOD( SetSpecial_TrackNumberCount ) (THIS_ ULONG32 trackNumber, ULONG32 trackCount )
+	{
+            // 2 bytes reserved + 2 bytes track number + 2 bytes track count
+            // + 1 byte playlist-name length (must be set to 0) + 1 byte playlist-name terminator
+            // The last byte should not exist by iTMF spec since playlist-name length field mustbe 0,
+            // but most tools expect it, iTunes 9 included. Since the encoding of playlist-name is not specified,
+            // we can think of the last byte as of C-string 0-terminator.
+            const UINT32 dataLength = 8;
+            HX_RESULT retVal = AllocBuffer(dataLength);
+            if( SUCCEEDED(retVal) )
+            {
+                memset(m_ucByteBuf, 0, dataLength);
 		    
-		    retVal = HXR_OK;
+                UCHAR* pTmp = m_ucByteBuf + 2;
+                WriteToBufferAndInc(pTmp, static_cast<UINT16>(trackNumber & 0x0000FFFF));
+                WriteToBufferAndInc(pTmp, static_cast<UINT16>(trackCount & 0x0000FFFF));
+
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Implicit);
 		}
+            return retVal;
+        }
+    STDMETHOD( SetSpecial_DiscNumberCount ) (THIS_ ULONG32 discNumber, ULONG32 discCount )
+	{
+            // 2 bytes reserved + 2 bytes disc number + 2 bytes disc count
+            const UINT32 dataLength = 6;
+            HX_RESULT retVal = AllocBuffer(dataLength);
+            if( SUCCEEDED(retVal) )
+            {
+                memset(m_ucByteBuf, 0, dataLength);
+
+                UCHAR* pTmp = m_ucByteBuf + 2;
+                WriteToBufferAndInc(pTmp, static_cast<UINT16>(discNumber & 0x0000FFFF));
+                WriteToBufferAndInc(pTmp, static_cast<UINT16>(discCount & 0x0000FFFF));
+
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Implicit);
 	    }
 	    return retVal;
 	}
-    STDMETHOD( SetBinary )          (THIS_ const UCHAR* pBinary, UINT32 len )
+    STDMETHOD( SetSpecial_PredefinedGenreEntries ) (THIS_ CHXPtrArray& genreEntries )
 	{
-	    HX_RESULT retVal = HXR_INVALID_PARAMETER;
+            if(!genreEntries.GetSize())
+            {
+                return HXR_FAILED;
+            }
 	    
-	    if( pBinary )
+            // 2*count bytes
+            const UINT32 dataLength = genreEntries.GetSize() * 2;
+            HX_RESULT retVal = AllocBuffer(dataLength);
+            if( SUCCEEDED(retVal) )
 	    {
-		m_ucBinStrBuf = new UCHAR[ len ];
-		retVal = HXR_OUTOFMEMORY;
+                UCHAR* pTmp = m_ucByteBuf;
 		
-		if( m_ucBinStrBuf )
+                for(ULONG32 i = 0; i < genreEntries.GetSize(); i++)
 		{
-		    memcpy( m_ucBinStrBuf, pBinary, len );
-		    CMP4VersionedAtom::m_uiFlags = _DataFlags::BINARY;
-		    retVal = HXR_OK;
+                    UINT16 entry = (UINT16)(ULONG32)genreEntries.GetAt(i);
+                    WriteToBufferAndInc(pTmp, entry);
 		}
+
+                // The TypeIndicatorTypeCode_Genres makes most tools (including iTunes9)
+                // ignore this atom, so use implicit.
+                SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Implicit);
+                //SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Genres);
 	    }
 	    return retVal;
 	}
-    STDMETHOD( SetInt )             (THIS_ const UINT32* pInt, UINT32 len )
+
+protected:
+    void ClearData()
 	{
-	    HX_RESULT retVal = HXR_INVALID_PARAMETER;
+        m_uiByteBufLength = 0;
+        HX_VECTOR_DELETE( m_ucByteBuf );
 	    
-	    if( pInt )
+        SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Implicit);
+    }
+
+    HX_RESULT AllocBuffer(ULONG32 len)
+    {
+        ClearData();
+
+        HX_RESULT retVal = HXR_INVALID_PARAMETER;
+        if(len)
 	    {
-		m_uiIntBuf = new UINT32[ len ];
 		retVal = HXR_OUTOFMEMORY;
+            m_ucByteBuf = new UCHAR[len];
 		
-		if( m_uiIntBuf )
+            if(m_ucByteBuf)
 		{
-		    memcpy( m_uiIntBuf, pInt, len << 2 );
-		    CMP4VersionedAtom::m_uiFlags = _DataFlags::INT;
+                m_uiByteBufLength = len;
+		memset(m_ucByteBuf, 0, len);
 		    retVal = HXR_OK;
 		}
 	    }
 	    return retVal;
 	}
-    STDMETHOD( SetByte )            (THIS_ const UCHAR* pByte, UINT32 len )
+
+    enum TypeIndicatorTypeCode
 	{
-	    HX_RESULT retVal = SetBinary( pByte, len );
-	    if( SUCCEEDED( retVal ) )
+        TypeIndicatorTypeCode_Implicit = 0, //no type needs to be indicated because only one type is allowed
+        TypeIndicatorTypeCode_UTF8 = 1, //without count or null terminator
+        TypeIndicatorTypeCode_UTF16BE = 2, //without count or null terminator
+        TypeIndicatorTypeCode_Genres = 18, //special enumeration
+        TypeIndicatorTypeCode_Integer = 21 //signed big-endian integer in 1,2,3,4,8 bytes
+    };
+
+    void SetTypeIndicatorTypeCode(TypeIndicatorTypeCode tc)
 	    {
-		CMP4VersionedAtom::m_uiFlags = _DataFlags::BYTE;
-	    }
-	    return retVal;
+        m_typeIndicatorTypeCode = (UCHAR)tc;
 	}
 
-protected:
-    // XXX Probably not the best naming ever. The distinctions here
-    //     aren't very clear
-    enum _DataFlags
-    {
-	INT=0x00,
-	STRING=0x01,
-	BINARY=0x0D,
-	BYTE=0x15,
-    };
 private:
-    UINT32 m_reserved;
-    UCHAR* m_ucBinStrBuf;  // used for STRING, BINARY, BYTE
-    UINT32* m_uiIntBuf;    // used for INT
-    UINT32 m_uiDataLength;
+    UINT16 m_typeIndicatorReserved; //reserved to be 0
+    UCHAR m_typeIndicatorTypeSetIdentifier; //only one type set defined: 0
+    UCHAR m_typeIndicatorTypeCode;
+    UINT32 m_localeIndicator; //reserved to be 0
+    UINT32 m_uiByteBufLength;
+    UCHAR* m_ucByteBuf;
 };
 
 // track name
 // string
-class CM4AAtom_nam : public CMP4ContainerAtom
+class CiTunesAtom_A9nam : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_nam() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'n','a','m'))
+    CiTunesAtom_A9nam() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'n','a','m'))
 	{}
 };
 
-// track artist
+// track subtitle
 // string
-class CM4AAtom_art : public CMP4ContainerAtom
+class CiTunesAtom_A9st3 : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_art() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'A','R','T'))
+    CiTunesAtom_A9st3() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'s','t','3'))
 	{}
 };
 
-// album name
+// track artist
 // string
-class CM4AAtom_alb : public CMP4ContainerAtom
+class CiTunesAtom_A9ART : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_alb() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'a','l','b'))
+    CiTunesAtom_A9ART() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'A','R','T'))
 	{}
 };
 
-// genre name
+// album name
 // string
-class CM4AAtom_gen : public CMP4ContainerAtom
+class CiTunesAtom_A9alb : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_gen() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'g','e','n'))
+    CiTunesAtom_A9alb() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'a','l','b'))
 	{}
 };
 
-// track number
-// int array, 1-2 items
-class CM4AAtom_trkn: public CMP4ContainerAtom
+// user genre
+// string
+class CiTunesAtom_A9gen : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_trkn() : CMP4ContainerAtom(MP4_BUILD_ATOMID('t','r','k','n'))
+    CiTunesAtom_A9gen() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'g','e','n'))
 	{}
 };
 
-// disk number
-// int array, 1-2 items
-class CM4AAtom_disk : public CMP4ContainerAtom
+// copyright
+// string
+class CiTunesAtom_cprt : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_disk() : CMP4ContainerAtom(MP4_BUILD_ATOMID('d','i','s','k'))
+    CiTunesAtom_cprt() : CMP4ContainerAtom(MP4_BUILD_ATOMID('c','p','r','t'))
 	{}
 };
 
-// day (year)
+// year
 // string
-class CM4AAtom_day : public CMP4ContainerAtom
+class CiTunesAtom_A9day : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_day() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'d','a','y'))
+    CiTunesAtom_A9day() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'d','a','y'))
 	{}
 };
 
 // comment
 // string
-class CM4AAtom_cmt : public CMP4ContainerAtom
+class CiTunesAtom_A9cmt : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_cmt() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'c','m','t'))
+    CiTunesAtom_A9cmt() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'c','m','t'))
 	{}
 };
 
 // composer
 // string
-class CM4AAtom_wrt : public CMP4ContainerAtom
+class CiTunesAtom_A9wrt : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_wrt() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'w','r','t'))
+    CiTunesAtom_A9wrt() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'w','r','t'))
 	{}
 };
 
-// cover art
-// binary
-class CM4AAtom_covr : public CMP4ContainerAtom
+// tool
+// string
+class CiTunesAtom_A9too : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_covr() : CMP4ContainerAtom(MP4_BUILD_ATOMID('c','o','v','r'))
+    CiTunesAtom_A9too() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'t','o','o'))
 	{}
 };
 
-// tempo
-// byte (2)
-class CM4AAtom_tmpo : public CMP4ContainerAtom
+// encoded by
+// string
+class CiTunesAtom_A9enc : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_tmpo() : CMP4ContainerAtom(MP4_BUILD_ATOMID('t','m','p','o'))
+    CiTunesAtom_A9enc() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'e','n','c'))
 	{}
 };
 
-// compilation
-// byte (1)
-class CM4AAtom_cmpl : public CMP4ContainerAtom
+// grouping
+// string
+class CiTunesAtom_grup : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_cmpl() : CMP4ContainerAtom(MP4_BUILD_ATOMID('c','m','p','l'))
+    CiTunesAtom_grup() : CMP4ContainerAtom(MP4_BUILD_ATOMID('g','r','u','p'))
 	{}
 };
 
-// tools
+// album artist
 // string
-class CM4AAtom_too : public CMP4ContainerAtom
+class CiTunesAtom_aART : public CMP4ContainerAtom
 {
 public:
-    CM4AAtom_too() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xa9,'t','o','o'))
+    CiTunesAtom_aART() : CMP4ContainerAtom(MP4_BUILD_ATOMID('a','A','R','T'))
+	{}
+};
+
+// lyrics
+// string
+class CiTunesAtom_A9lyr : public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_A9lyr() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'l','y','r'))
+	{}
+};
+
+// track number
+// special format
+class CiTunesAtom_trkn: public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_trkn() : CMP4ContainerAtom(MP4_BUILD_ATOMID('t','r','k','n'))
+	{}
+};
+
+// disc number
+// special format
+class CiTunesAtom_disk : public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_disk() : CMP4ContainerAtom(MP4_BUILD_ATOMID('d','i','s','k'))
+	{}
+};
+
+// predefined genre
+// uint16 array
+class CiTunesAtom_gnre : public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_gnre() : CMP4ContainerAtom(MP4_BUILD_ATOMID('g','n','r','e'))
+	{}
+};
+
+// beats per minute
+// signed int32
+class CiTunesAtom_tmpo : public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_tmpo() : CMP4ContainerAtom(MP4_BUILD_ATOMID('t','m','p','o'))
+	{}
+};
+
+// compilation
+// signed int8
+class CiTunesAtom_cpil : public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_cpil() : CMP4ContainerAtom(MP4_BUILD_ATOMID('c','p','i','l'))
+	{}
+};
+
+// content rating
+// signed int8
+class CiTunesAtom_rtng : public CMP4ContainerAtom
+{
+public:
+    CiTunesAtom_rtng() : CMP4ContainerAtom(MP4_BUILD_ATOMID('r','t','n','g'))
 	{}
 };
 
 #endif  /* _M4AMDATOMS_H_ */
Index: mp4atoms.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4atoms.h,v
retrieving revision 1.14
diff -d -H -b -B -w -U30 -r1.14 mp4atoms.h
--- mp4atoms.h	23 May 2009 09:35:06 -0000	1.14
+++ mp4atoms.h	19 Oct 2009 17:45:19 -0000
@@ -429,60 +429,81 @@
 class CMP4VersionedAtom : public CMP4Atom
 {
 public:
     CMP4VersionedAtom(UINT32 uiAtomID)
         : CMP4Atom(uiAtomID)
         , m_ucVersion(0)
         , m_uiFlags(0)
     {
     };
 
     STDMETHOD_(UINT32, GetCurrentSize )     (THIS_ HXBOOL bIncludeChildren = FALSE)
         {
             return 8 + 1 + 3 + (bIncludeChildren ? GetSizeOfChildren() : 0);
         }
 protected:
     // The derived object should set up the buffer first, then call us
     void WriteAtomAndVersionInfo( UCHAR*& p )
         {
             UINT32 verflags = (((UINT32)m_ucVersion) << 24) | (m_uiFlags & 0x00ffffff);
             // XXX the below GetCurrentSize() call should hit the most derived obj...
             CMP4Atom::WriteToBufferAndInc( p, GetCurrentSize(TRUE) );
             CMP4Atom::WriteToBufferAndInc( p, m_ulAtomID );
             CMP4Atom::WriteToBufferAndInc( p, verflags );
         }
     
     UCHAR  m_ucVersion;
     UINT32 m_uiFlags;    // actually 24 bit
 };
 
 
+class CMP4VersionedContainerAtom : public CMP4VersionedAtom
+{
+public:
+    CMP4VersionedContainerAtom(UINT32 uiAtomID) : CMP4VersionedAtom(uiAtomID)
+        {}
+    STDMETHOD( WriteToBuffer )(THIS_ UCHAR*& pBuffer, HXBOOL bIncludeChildren=FALSE)
+        {
+            HX_RESULT retVal = HXR_OK;
+            if( pBuffer )
+            {
+                CMP4VersionedAtom::WriteAtomAndVersionInfo( pBuffer );
+                if( bIncludeChildren )
+                {
+                    retVal = ChildrenWriteToBuffer( pBuffer );
+                }
+            }
+            return retVal;
+        }
+};
+
+
 // Conceptually, there has to be a 'root' atom which represents
 // the file itself; this atom is never written, and isn't really
 // a container, but within it are all the top-level atoms,
 // represented as children
 
 // atom:      file
 // container: n/a
 // purpose:   provides a top level atom, specific to our implementation
 class CMP4Atom_file : public CMP4Atom
 {
 public:
     CMP4Atom_file() : CMP4Atom(MP4_BUILD_ATOMID('f','i','l','e'))
         {}
     STDMETHOD_(UINT32, GetCurrentSize )     (THIS_ HXBOOL bIncludeChildren = FALSE)
         {
             return bIncludeChildren ? GetSizeOfChildren() : 0;
         }
     STDMETHOD( WriteToBuffer )      (THIS_ UCHAR*& pBuffer,
                                      HXBOOL bIncludeChildren=FALSE)
         {
             HX_RESULT retVal = HXR_NOTIMPL;
             if( bIncludeChildren )
             {
                 retVal = ChildrenWriteToBuffer( pBuffer );
             }
             return retVal;
         }
 };
 
 // atom:      ftyp
@@ -2554,62 +2575,70 @@
 //            way to retain the streeam data. instead, we have a length
 //            field which indicates the total number of bytes we actually
 //            wrote, and when queried for our size we give only our actual
 //            atom size (non inclusive of the bytes we wrote)
 class CMP4Atom_mdat : public CMP4ContainerAtom
 {
 public:
     CMP4Atom_mdat() : CMP4ContainerAtom(MP4_BUILD_ATOMID('m','d','a','t'))
         {
             m_uiBytesWritten = 0;
         }
     STDMETHOD( WriteToBuffer )      (THIS_ UCHAR*& pBuffer,
                                      HXBOOL bIncludeChildren= FALSE)
         {
             HX_RESULT retVal = HXR_OK;
             if( pBuffer )
             {
                 CMP4Atom::WriteToBufferAndInc( pBuffer, GetCurrentSize() + m_uiBytesWritten );
                 CMP4Atom::WriteToBufferAndInc( pBuffer, m_ulAtomID );
             }
             // XXX we should never have children, so ignore bIncludeChildren
             
             return retVal;
         }
     
     MP4_ATOM_PROPERTY(BytesWritten, UINT32, m_uiBytesWritten);
 private:
     UINT32 m_uiBytesWritten;
 };
 
-
-
+// atom:      meta
+// container: file, moov, trak
+// purpose:   container for general (descriptive, annotative) meta-data
+// note:      must contain hdlr atom as first child
+class CMP4Atom_meta : public CMP4VersionedContainerAtom
+{
+public:
+    CMP4Atom_meta() : CMP4VersionedContainerAtom(MP4_BUILD_ATOMID('m','e','t','a'))
+        {}
+};
 
 
 ////////////////////////////////////////////////////
 //
 // BEGIN:      AMR NB, WB, WB+ MPEG4 (3GPP) Atoms Section
 //
 ////////////////////////////////////////////////////
 
 
 
 // 3GPP AMRSpecificBox, part of the AMRSampleEntry box.  The same AMRSpecificBox
 // is used for both the sample entry box for AMR-NB and AMR-WB.
 class CMP4Atom_dAMR : public CMP4Atom
 {
   public:
     CMP4Atom_dAMR() :
         CMP4Atom(MP4_BUILD_ATOMID('d','a','m','r')),
         m_ulDecoderInfoSize(0),
         m_pDecoderInfo(NULL)
         {
         }
 
         ~CMP4Atom_dAMR()
         {
             HX_VECTOR_DELETE(m_pDecoderInfo);
         }
 
         STDMETHOD_(UINT32, GetCurrentSize ) (THIS_ HXBOOL bIncludeChildren = FALSE)
         {
             return 8 + m_ulDecoderInfoSize;
Index: mp4sm.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.cpp,v
retrieving revision 1.19
diff -d -H -b -B -w -U30 -r1.19 mp4sm.cpp
--- mp4sm.cpp	16 Oct 2009 16:46:17 -0000	1.19
+++ mp4sm.cpp	19 Oct 2009 17:45:25 -0000
@@ -19,60 +19,61 @@
  * This file is part of the Helix DNA Technology. RealNetworks is the
  * developer of the Original Code and owns the copyrights in the portions
  * it created.
  *
  * This file, and the files included with this file, is distributed and made
  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  *
  * Technology Compatibility Kit Test Suite(s) Location:
  *    http://www.helixcommunity.org/content/tck
  *
  * Contributor(s):
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "hxassert.h"
 #include "hxbuffer.h"
 #include "chxpckts.h"
 #include "pckunpck.h"
 #include "mp4arch.h"
 #include "mp4sm.h"
 #include "mp4atoms.h"
 #include "asmrulep.h"
 
 #include "m4amdatoms.h"
 #include "pspmeta.h"
 #include "3gpmeta.h"
 #include "metainfokeys.h"
+#include "metautil.h"
 #include "iso639.h"
 #include "proptools.h"
 #include "private_clsids.h"
 
 // Added for branching off to type specific atoms build
 #include "mp4atomgateway.h"
 
 #include "cspkt.h"
 
 #define MP4_RESERVE_BLOCK_SIZE    (1024)
 
 #define MP4_DEFAULT_METADATA_RESERVE_SIZE (2 * 1024)
 
 #define SAMPLERATE_AS_MEDIA_TIMESCALE 1
 
 const UCHAR CPSPAtom_USMT::sm_userType[16] = {'U', 'S', 'M', 'T', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 
 // class to handle managing the stbl, will eventually
 //  be pulled out into mp4fwlib
 class CStblManager
 {
 public:
     CStblManager(CMP4StreamMixer *pSm, CMP4Atom_stbl* pStbl, IHXValues* pStreamHdr, IUnknown* pContext)
         {
 	    m_pStreamMixer = pSm;
 	    pSm->AddRef();
             m_bFirstPacket = TRUE;
             m_uiLastTimeStamp   = 0;
             m_uiSampleCounter   = 0;
@@ -626,180 +627,197 @@
 }
 
 CMP4StreamMixer::HintInfo::HintInfo(CHXHintContext &hctx)
     : hinting(hctx), trak(NULL), tkhd(NULL), mdhd(NULL), sdp(NULL), stblmgr(NULL), trackid(NULL)
 {
 }
 
 CMP4StreamMixer::HintInfo::~HintInfo()
 {
 }
 
 CMP4StreamMixer::CMP4StreamMixer(IUnknown* pContext, CMP4Archiver* pArchiver)
     : m_lRefCount(0)
     , m_ulLastTimestamp(0)
     , m_ulActualDuration(0)
     , m_ulReportedDuration(0)
     , m_uiByteCount(0)
     , m_uiReservedBlockCount(0)
     , m_ulFirstTimestamp(0)
     , m_eIsRtp(UNCHECKED)
     , m_bMoovAtEnd(FALSE)
     , m_bForceMoovFirst(FALSE)
     , m_pMvhd(NULL)
     , m_pFileHeader(NULL)
     , m_pStreamInfo(NULL)
     , m_ulStreamCount(0)
     , m_ulStreamGroupCount(0)
     , m_ulStreamHeaderReceived(0)
     , m_ulStreamDoneReceived(0)
     , m_eMetaFlavor(META_ITUNES)
+    , m_bRequestedOutputMetaFlavor3GPP(FALSE)
+    , m_bRequestedOutputMetaFlavorITUNES(FALSE)
     , m_bUTF16Output(FALSE)
     , m_e3gpMode(M3GPP_NONE)
     , m_bTSInterleave(FALSE)
     , m_bGenerateHintTracks(FALSE)
     , m_uiBaseWriteOffset(0)
     , m_uiCurrentOffset(0)
     , m_uiGlobalFlush(0)
 {
     m_pContext = pContext;
     HX_ADDREF(m_pContext);
 
     HX_ASSERT( pArchiver );
     m_pArchiver = pArchiver;
     m_pArchiver->AddRef();
 
     m_pRootAtom = new CMP4Atom_file();
     HX_ASSERT( m_pRootAtom );
     m_pRootAtom->AddRef();
 }
 
 
 CMP4StreamMixer::~CMP4StreamMixer()
 {
     HX_RELEASE( m_pArchiver );
     HX_RELEASE( m_pRootAtom );
     HX_RELEASE( m_pFileHeader );
     HX_VECTOR_DELETE(m_pStreamInfo);
     HX_RELEASE( m_pContext );
 }
 
 STDMETHODIMP CMP4StreamMixer::QueryInterface( THIS_ REFIID riid, void** ppvObj )
 {
     // dont support, for now
     return HXR_NOINTERFACE;
 }
 
 STDMETHODIMP_(ULONG32) CMP4StreamMixer::AddRef()
 {
     return InterlockedIncrement( &m_lRefCount );
 }
 STDMETHODIMP_(ULONG32) CMP4StreamMixer::Release()
 {
     if( InterlockedDecrement( &m_lRefCount ) > 0 )
     {
         return m_lRefCount;
     }
     delete this;
     return 0;
 }
 
 STDMETHODIMP CMP4StreamMixer::SetProperties( THIS_ IHXValues* pProperties )
 {
-    // UTF16 output option
     ULONG32 ulVal = 0;
+
+    // Meta-data flavor options
+    PropTools::CopyPropertyULONG32(ulVal, pProperties, "MetaDataFlavor");
+
+    const ULONG32 METADATA_FLAVOR_3GPP = 0x00000001; //from ihxmetaeditor.h
+    m_bRequestedOutputMetaFlavor3GPP = (ulVal & METADATA_FLAVOR_3GPP) != 0;
+
+    const ULONG32 METADATA_FLAVOR_ITUNES = 0x00000010; //from ihxmetaeditor.h
+    m_bRequestedOutputMetaFlavorITUNES = (ulVal & METADATA_FLAVOR_ITUNES) != 0;
+
+    // UTF16 output option
     PropTools::CopyPropertyULONG32(ulVal, pProperties, "UTF16Output");
     m_bUTF16Output = ulVal ? TRUE : FALSE;
 
+    // Compatibility option
     PropTools::CopyPropertyBuffer(m_spCompatibility, pProperties, "Compatibility");
 
+    // 3GPP Mode option
     IHXBuffer *buf;
 
     if (SUCCEEDED(pProperties->GetPropertyCString("3GPPMode", buf)))
     {
 	UINT32 n = buf->GetSize();
 	const char *p3gpmode = (const char *)buf->GetBuffer();
 
 	if (n >= 4 && strncasecmp(p3gpmode, "none", 4) == 0)
 	{
 	    m_e3gpMode = M3GPP_NONE;
 	}
 	else if (n >= 7 && strncasecmp(p3gpmode, "general", 7) == 0)
 	{
 	    m_e3gpMode = M3GPP_GENERAL;
 	}
 	else if (n >= 5 && strncasecmp(p3gpmode, "basic", 5) == 0)
 	{
 	    m_e3gpMode = M3GPP_BASIC;
 	}
 	else if (n >= 9 && strncasecmp(p3gpmode, "streaming", 9) == 0)
 	{
 	    m_e3gpMode = M3GPP_STREAMING;
 	}
 	else if (n >= 6 && strncasecmp(p3gpmode, "progdl", 6) == 0)
 	{
 	    m_e3gpMode = M3GPP_PROGDL;
 	}
 	else if (n >= 8 && strncasecmp(p3gpmode, "streamdl", 8) == 0)
 	{
 	    m_e3gpMode = M3GPP_STREAMDL;
 	}
 	else if (n >= 4 && strncasecmp(p3gpmode, "rel5", 4) == 0)
 	{
 	    m_e3gpMode = M3GPP_REL5;
 	}
 	HX_RELEASE(buf);
 	switch (m_e3gpMode)
 	{
 	case M3GPP_PROGDL:
 	case M3GPP_STREAMDL:
 	    m_bTSInterleave = TRUE;
 	    break;
 	default:
 	    break;
 	}
     }
 
     // The default setting for hinting depends on the profile we are using
     switch (m_e3gpMode)
     {
     case M3GPP_STREAMING:
     case M3GPP_STREAMDL:
 	ulVal = 1;
 	break;
     default:
 	ulVal = 0;
 	break;
     }
+
+    // GenerateHintTracks option
     pProperties->GetPropertyULONG32("GenerateHintTracks", ulVal);
     m_bGenerateHintTracks = ulVal ? TRUE : FALSE;
 
+    // ForceMoovFirst option
     ulVal = 0;
     pProperties->GetPropertyULONG32("ForceMoovFirst", ulVal);
     if (ulVal != 0)
     {
 	m_bForceMoovFirst = TRUE;
     }
 
     return HXR_OK;
 }
 
 STDMETHODIMP CMP4StreamMixer::SetFileHeader( THIS_ IHXValues* pFileHeader )
 {
     HX_RESULT retVal = HXR_OK;
 
     pFileHeader->AddRef();
     m_pFileHeader = pFileHeader;
 
     //get stream count; this may be bigger than the actual number of tracks in
     //the output file, depending on how many NUL handlers are there
     m_pFileHeader->GetPropertyULONG32("StreamCount", m_ulStreamCount);
     m_pFileHeader->GetPropertyULONG32("StreamGroupCount", m_ulStreamGroupCount);
 
     if (m_ulStreamCount)
     {
         m_pStreamInfo = new StreamInfo[m_ulStreamCount];
     }
 
     HX_ASSERT(m_pStreamInfo);
 
     m_ulStreamHeaderReceived = 0;
@@ -1367,124 +1385,124 @@
     CMP4Atom_free* pFree = NULL;
     CMP4Atom_moov* pMoov = NULL;
     CMP4Atom_mdat* pMdat = NULL;
     
     pFtyp = new CMP4Atom_ftyp;
     if( pFtyp )
     {
         m_pRootAtom->AddChild( pFtyp );
         retVal = HXR_OK;
 
         //try to guess file branding info by file extension
 
         //default, MP4
         pFtyp->SetMajorBrand("M4V ");
         pFtyp->SetMinorVersion(0);
         pFtyp->SetCompatibleBrands("M4V M4A mp42isom");
 
         //default meta data flavor
         m_eMetaFlavor = META_ITUNES;
 
         CHXString fileExt;
         if ( SUCCEEDED(m_pArchiver->GetFileExtension(fileExt)) )
         {
             if (stricmp(fileExt, ".3gp") == 0)
             {
                 //3GP
                 pFtyp->SetMajorBrand("3gp7");
                 pFtyp->SetMinorVersion(0x200);
                 pFtyp->SetCompatibleBrands("3gp73gp6isom");
 
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
             }
             else
             if (stricmp(fileExt, ".3g2") == 0)
             {
                 //3G2
                 pFtyp->SetMajorBrand("3g2a");
                 pFtyp->SetCompatibleBrands("3g2a");
                 pFtyp->SetMinorVersion(0);
 
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
             }
             else
             if (    stricmp(fileExt, ".m4a") == 0
                 ||  stricmp(fileExt, ".m4p") == 0 )
             {
                 //M4A, M4P
                 pFtyp->SetMajorBrand("M4A ");
                 pFtyp->SetMinorVersion(0);
                 pFtyp->SetCompatibleBrands("M4A mp42isom");
 
                 m_eMetaFlavor = META_ITUNES;
             }
         }
 	// When in proper 3GPP-mode, only include rel6/rel5 definitions.
 	// Note that we don't even check that everything is conformant,
 	// just adjust those things we can affect.
 	switch (m_e3gpMode)
 	{
 	    case M3GPP_GENERAL:
 	        pFtyp->SetMajorBrand("3gg6");
 	        pFtyp->SetMinorVersion(0);
 	        pFtyp->SetCompatibleBrands("3gg63gp6isom");
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
 	        break;
 	    case M3GPP_BASIC:
 	        pFtyp->SetMajorBrand("3gp6");
 	        pFtyp->SetMinorVersion(0);
 	        pFtyp->SetCompatibleBrands("3gp63gp5isom");
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
 	        break;
 	    case M3GPP_STREAMING:
 	        pFtyp->SetMajorBrand("3gs6");
 	        pFtyp->SetMinorVersion(0);
 	        pFtyp->SetCompatibleBrands("3gs63gg63gp5isom");
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
 	        break;
 	    case M3GPP_PROGDL:
 	        pFtyp->SetMajorBrand("3gr6");
 	        pFtyp->SetMinorVersion(0);
 	        pFtyp->SetCompatibleBrands("3gr63gp63gg63gp5isom");
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
 	        break;
 	    case M3GPP_STREAMDL:
 	        pFtyp->SetMajorBrand("3gs6");
 	        pFtyp->SetMinorVersion(0);
 	        pFtyp->SetCompatibleBrands("3gs63gr63gg63gp5isom");
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
 		break;
 	    case M3GPP_REL5:
 		pFtyp->SetMajorBrand("3gp5");
 	        pFtyp->SetMinorVersion(0);
 	        pFtyp->SetCompatibleBrands("3gp53gp4isom");
-                m_eMetaFlavor = META_3GP;
+                m_eMetaFlavor = META_3GPP;
 		break;
 	}
     }
     
     if( SUCCEEDED( retVal ) )
     {
         retVal = HXR_OUTOFMEMORY;
         pMoov = new CMP4Atom_moov;
 
         if( pMoov )
         {
             retVal = HXR_OK;
         }
     }
     
     if( SUCCEEDED( retVal ) )
     {
         retVal = HXR_OUTOFMEMORY;
         pMdat = new CMP4Atom_mdat();
         
         if( pMdat )
         {
             retVal = HXR_OK;
         }
     }
 
 
     if( SUCCEEDED( retVal ) )
     {
         if( m_bMoovAtEnd )
@@ -1581,69 +1599,69 @@
                             if (ulTrackType == MP4_BUILD_ATOMID('v','i','d','e'))
                             {
                                 bHasVideo = TRUE;
                             }
                         }
                     }
                 }
             }
 	    for (UINT32 i = 0; i < m_ulStreamCount && SUCCEEDED(retVal); ++i)
 	    {
 		HintInfo *hi = m_pStreamInfo[i].m_pHintInfo;
 		
 		if (hi != NULL && hi->trak != NULL)
 		    pMoov->AddChild(hi->trak);
 	    }
         }
 
         // Do we need to generate a udta box that is a child
         // of the moov box?
         if (SUCCEEDED(retVal) && NeedToAddUdtaChildToMoovBox())
         {
             // Set the return value
             retVal = HXR_OUTOFMEMORY;
             // Create the udta box
             CMP4Atom_udta* pUdta = new CMP4Atom_udta();
             if (pUdta)
             {
                 // Clear the return value
                 retVal = HXR_OK;
                 // Check the meta-data format we are supposed to generate
-                if (m_eMetaFlavor == META_ITUNES)
+                if (m_bRequestedOutputMetaFlavorITUNES || (m_eMetaFlavor == META_ITUNES))
                 {
-                    // Build iPod meta-data
-                    BuildIPODMetaData(pUdta);
+                    // Build iTunes meta-data
+                    BuildiTunesMetaData(pUdta);
                 }
-                else if (m_eMetaFlavor == META_3GP)
+                if (m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP))
                 {
                     // Build 3GP meta-data
-                    Build3GPMetaData(pUdta);
+                    Build3GPMetaData(pUdta, pMoov);
                 }
                 // Are we generating a hinted file?
                 if (m_bGenerateHintTracks)
                 {
                     // Add the hnti box as a child of the udta box
                     AddMovieHintInformation(pUdta);
                 }
                 // Add this udta box as a child of the moov box
                 pMoov->AddChild(pUdta);
             }
         }
 
         // uuid/USMT atom for PSP style meta info
         if( SUCCEEDED( retVal ) && m_eMetaFlavor == META_PSP )
         {
             retVal = HXR_OUTOFMEMORY;
             CPSPAtom_USMT* pUsmt = new CPSPAtom_USMT();
             if( pUsmt )
             {
                 retVal = HXR_OK;
 
                 // Call out to build the metadata tree
                 BuildPSPMetaData( pUsmt );
 
                 pMoov->AddChild( pUsmt );
             }
         }
     
     }
 
@@ -1720,118 +1738,133 @@
 		    {
 			ulEstimatedSize += size + 40 +
 			    HINTTRACK_SDP_FRAG_MAX_SIZE;
 		    }
                 }
             }
 
             m_uiReservedBlockCount = 1 + (ulEstimatedSize / MP4_RESERVE_BLOCK_SIZE);
 
             ulStblWriteOffset = 8 + (m_uiReservedBlockCount * MP4_RESERVE_BLOCK_SIZE);
         }
 
 	m_uiBaseWriteOffset = ulStblWriteOffset;
 	m_uiCurrentOffset = 0;
     }
     
     return retVal;
 }
 
 HX_RESULT CMP4StreamMixer::BuildTrack( UINT16 usStreamNum, CMP4Atom* pTrak )
 {
     HX_RESULT retVal = HXR_OK;
 
     UINT32 ulTrackType = MP4_BUILD_ATOMID('n','u','l','l');
     m_pStreamInfo[usStreamNum].m_pStreamHeader->GetPropertyULONG32("TrackType", ulTrackType);
 
     // Set up pTrak children
     // trak
     //   tkhd
     //   mdia
+    //   meta
 
     if (SUCCEEDED(retVal))
     {
         // tkhd
         retVal = HXR_OUTOFMEMORY;
         m_pStreamInfo[usStreamNum].m_pTkhd = new CMP4Atom_tkhd();
 
         if (m_pStreamInfo[usStreamNum].m_pTkhd)
         {
             retVal = HXR_OK;
             // Assign the track ID we previously chose in ChooseTrackIDs()
             m_pStreamInfo[usStreamNum].m_pTkhd->SetTrackID(m_pStreamInfo[usStreamNum].m_ulTrackID);
 
             // Set the alternate group
             UINT32 ulAlternateGroup = 0;
             if (m_ulStreamGroupCount &&
                 m_pStreamInfo[usStreamNum].m_ulStreamGroupNumber != HX_INVALID_STREAM_GROUP_NUMBER &&
                 m_pStreamInfo[usStreamNum].m_ulStreamGroupNumber < m_ulStreamGroupCount)
             {
                 ulAlternateGroup = m_pStreamInfo[usStreamNum].m_ulStreamGroupNumber + 1;
             }
             m_pStreamInfo[usStreamNum].m_pTkhd->SetAlternateGroup((UINT16) ulAlternateGroup);
 
             if (ulTrackType == MP4_BUILD_ATOMID('v','i','d','e'))
             {
                 UINT32 ulWidth = 0 , ulHeight = 0;
                 m_pStreamInfo[usStreamNum].m_pStreamHeader->GetPropertyULONG32("Width", ulWidth);
                 m_pStreamInfo[usStreamNum].m_pStreamHeader->GetPropertyULONG32("Height", ulHeight);
 
                 m_pStreamInfo[usStreamNum].m_pTkhd->SetWidth((UINT16) ulWidth);
                 m_pStreamInfo[usStreamNum].m_pTkhd->SetHeight((UINT16) ulHeight);
             }
             pTrak->AddChild( m_pStreamInfo[usStreamNum].m_pTkhd );
         }
 
         retVal = BuildMdia(usStreamNum, pTrak, NULL);
         if (SUCCEEDED(retVal))
         {
             // Do we need to add a udta box child to this trak box?
             if (NeedToAddUdtaChildToTrakBox((CMP4Atom_trak*) pTrak, (UINT32) usStreamNum))
             {
                 // Set the return value
                 retVal = HXR_OUTOFMEMORY;
                 // Create a udta box
                 CMP4Atom_udta* pUdtaBox = new CMP4Atom_udta();
                 if (pUdtaBox)
                 {
                     // Clear the return value
                     retVal = HXR_OK;
                     // Add this child to the trak box
                     pTrak->AddChild(pUdtaBox);
                     // Handle switch groups here. This will check to see if 
                     // there is a "SwitchGroupID" property in the stream header,
                     // and if so, add a tsel child box to the udta box.
                     SetSwitchGroup(pUdtaBox, (UINT32) usStreamNum);
                 }
             }
         }
+
+        // build meta atom at stream level (3GPP flavor only)
+        if( SUCCEEDED( retVal ) &&
+            (m_eMetaFlavor == META_3GPP || m_bRequestedOutputMetaFlavor3GPP))
+        {
+            // ID32, setup box hierarchy: trak/meta/[hdlr, ID32]
+            CMP4Atom_meta* pMeta = NULL;
+            retVal = Build3GPMetaDataID32(m_pStreamInfo[usStreamNum].m_pStreamHeader, &pMeta);
+
+            if( SUCCEEDED( retVal ) && pMeta )
+            {
+                retVal = pTrak->AddChild( pMeta );
+            }
+        }
     }
 
     if (SUCCEEDED(retVal) && m_bGenerateHintTracks)
     {
         HintInfo *hi = new HintInfo(m_HintContext);
 
         if (hi == NULL)
         {
             return HXR_OUTOFMEMORY;
         }
         retVal = hi->hinting.SetStreamHeader(m_pStreamInfo[usStreamNum].m_pStreamHeader);
         if (SUCCEEDED(retVal))
         {
             m_pStreamInfo[usStreamNum].m_pHintInfo = hi;
 
             // Assign the trackID we chose in ChooseTrackIDs()
             hi->trackid = m_pStreamInfo[usStreamNum].m_ulHintTrackID;
             // Set the hint track ID into the stream header
             m_pStreamInfo[usStreamNum].m_pStreamHeader->SetPropertyULONG32("TrackID", hi->trackid);
 
             hi->trak = new CMP4Atom_trak;
             if (hi->trak == NULL)
             {
                 return HXR_OUTOFMEMORY;
             }
             hi->tkhd = new CMP4Atom_tkhd;
             if (hi->tkhd == NULL)
             {
                 return HXR_OUTOFMEMORY;
             }
@@ -1972,63 +2005,65 @@
     {
         // The first question is: does the trak box already HAVE a udta box child? If
         // so then we don't need to add another one.
         CMP4Atom_udta* pUdtaBox = (CMP4Atom_udta*) pTrakBox->FindChild(MP4_BUILD_ATOMID('u','d','t','a'));
         if (!pUdtaBox)
         {
             // The trak box does not already have a udta child. The next question is: is this
             // stream involved in a switch group? If so, then we will need a udta box child
             // of the trak box in order to put our tsel (track selection) box in.
             if (IsStreamInSwitchGroup(ulStreamNumber))
             {
                 // For now, these are the only criteria. So if we made it here, we need
                 // to add a udta child to this trak box.
                 // XXXMEH - if we are hinting, we always add a udta box to the trak
                 // box for the hint track. However, if we are doing hinting of
                 // single-rate streams, then it's unclear if the trak box for the
                 // media tracks need udta children or not. For now, I'll assume that
                 // we only need udta children for media trak boxes if that track
                 // is in a switch group.
                 bRet = TRUE;
             }
         }
     }
 
     return bRet;
 }
 
 HXBOOL CMP4StreamMixer::NeedToAddUdtaChildToMoovBox()
 {
     // We need to generate a udta box as a child of the moov box if
-    // we are either generating iTunes or 3GP meta-data OR we 
+    // we are either generating iTunes or 3GPP meta-data OR we 
     // are generating hint tracks.
-    return (m_eMetaFlavor == META_ITUNES || m_eMetaFlavor == META_3GP || m_bGenerateHintTracks);
+    return (m_bRequestedOutputMetaFlavorITUNES || m_eMetaFlavor == META_ITUNES
+            || m_bRequestedOutputMetaFlavor3GPP || m_eMetaFlavor == META_3GPP
+            || m_bGenerateHintTracks);
 }
 
 HX_RESULT
 CMP4StreamMixer::AddMovieHintInformation(CMP4Atom_udta* pUdta)
 {
     HX_RESULT retVal = HXR_INVALID_PARAMETER;
 
     if (pUdta)
     {
         // Clear the return value
         retVal = HXR_OK;
         // Does this udta box already have a hnti child box?
         CMP4Atom_hnti* pHnti = (CMP4Atom_hnti*) pUdta->FindChild(MP4_BUILD_ATOMID('h','n','t','i'));
         if (!pHnti)
         {
             // Set the return value
             retVal = HXR_OUTOFMEMORY;
             // This udta box does NOT already have a hnti child box, so create one
             pHnti = new CMP4Atom_hnti();
             if (pHnti)
             {
                 // Create a CMP4Atom_RTPMovieHintInformation child box
                 CMP4Atom_RTPMovieHintInformation* pRTP = new CMP4Atom_RTPMovieHintInformation();
                 if (pRTP)
                 {
                     // Generate the movie-level SDP
                     CHXString strMovieLevelSDP;
                     retVal = GenerateMovieLevelSDP(&strMovieLevelSDP);
                     if (SUCCEEDED(retVal))
                     {
@@ -3387,262 +3422,571 @@
 	{
 	    retVal = HXR_OK;
 
 	    pStbl->AddChild( pStco );
 	}
     }
         
     if( SUCCEEDED( retVal ) )
     {
 	if (pHinfo == NULL)
 	{
             retVal = HXR_OUTOFMEMORY;
             
             // pass off the stbl atom to the stbl manager
             m_pStreamInfo[usStreamNum].m_pStblManager = new CStblManager(this, pStbl, m_pStreamInfo[usStreamNum].m_pStreamHeader, m_pContext);
 
             if( m_pStreamInfo[usStreamNum].m_pStblManager )
             {
                 retVal = HXR_OK;
             }
         }
 	else
 	{
 	    pHinfo->stblmgr = new CStblManager(this, pStbl, m_pStreamInfo[usStreamNum].m_pStreamHeader, m_pContext);
 	    retVal = pHinfo->stblmgr == NULL ? HXR_OUTOFMEMORY : HXR_OK;
 	}
     }
     return retVal;
 }
 
-HX_RESULT CMP4StreamMixer::BuildIPODMetaData( CMP4Atom* pUdta )
+// iTunes Utilities
+class iTunesMetadataTransferPort
+{
+public:
+    iTunesMetadataTransferPort()
+        : m_ulLengthLimit(0)
+        , m_bUTF16Output(FALSE)
+    {
+    }
+
+    virtual ~iTunesMetadataTransferPort() {;}
+    virtual HXBOOL ExtractData(IHXValues& values, const char* szPropName) = 0;
+    virtual HX_RESULT InjectData(CiTunesAtom_data& dataAtom) = 0;
+
+    void SetUTF16Output(HXBOOL bUTF16 = FALSE)
+    {
+        m_bUTF16Output = bUTF16;
+    }
+
+    // LengthLimit=0 means no limit
+    void SetLengthLimit(ULONG32 ulLengthLimit = 0)
+    {
+        m_ulLengthLimit = ulLengthLimit;
+    }
+
+    ULONG32 CalcInjectedStringByteLength(const EncodedString& es)
+    {
+        ULONG32 codeUnitLen = es.GetCodeUnitLength(FALSE, FALSE);
+        if((m_ulLengthLimit > 0) && (codeUnitLen > m_ulLengthLimit))
+        {
+            // only cover encoding we're exporting to atoms
+            switch(es.GetEncoding())
+            {
+                case HX_TEXT_ENCODING_TYPE_UTF16BE:
+                    return m_ulLengthLimit * 2;
+
+                case HX_TEXT_ENCODING_TYPE_UTF8:
+                    return m_ulLengthLimit;
+            }
+        }
+        return es.GetByteLength(FALSE);
+    }
+
+protected:
+    ULONG32 m_ulLengthLimit;
+    HXBOOL m_bUTF16Output;
+};
+
+class iTunesStringTransferPort : public iTunesMetadataTransferPort
+{
+public:
+    virtual HXBOOL ExtractData(IHXValues& values, const char* szPropName)
+    {
+        return szPropName ? PropTools::CopyPropertyBuffer(m_strValue, &values, szPropName) : FALSE;
+    }
+    virtual HX_RESULT InjectData(CiTunesAtom_data& dataAtom)
+    {
+        if(m_bUTF16Output)
+        {
+            // big-endian, no BOM, no terminator
+            EncodedString strValueOut;
+            if(m_strValue.ConvertToUTF16(strValueOut, TRUE, FALSE))
+            {
+                return dataAtom.SetUTF16BEString(strValueOut.GetData(), CalcInjectedStringByteLength(strValueOut));
+            }
+            return HXR_FAILED;
+        }
+
+        // UTF8
+        EncodedString strValueOut;
+        if(m_strValue.ConvertToUTF8(strValueOut))
+        {
+            // no terminator
+            return dataAtom.SetUTF8String(strValueOut.GetData(), CalcInjectedStringByteLength(strValueOut));
+        }
+        return HXR_FAILED;
+    }
+
+private:
+    EncodedString m_strValue;
+};
+
+class iTunesULongTransferPort : public iTunesMetadataTransferPort
+{
+public:
+    iTunesULongTransferPort() : m_ulValue(0)
+    {;}
+
+    virtual HXBOOL ExtractData(IHXValues& values, const char* szPropName)
+    {
+        return szPropName ? PropTools::CopyPropertyULONG32(m_ulValue, &values, szPropName) : FALSE;
+    }
+
+protected:
+    ULONG32 m_ulValue;
+};
+
+class iTunesUInteger32TransferPort : public iTunesULongTransferPort
+{
+public:
+    virtual HX_RESULT InjectData(CiTunesAtom_data& dataAtom)
+    {
+        return dataAtom.SetUInteger32(m_ulValue);
+    }
+};
+
+class iTunesUInteger16TransferPort : public iTunesULongTransferPort
+{
+public:
+    virtual HX_RESULT InjectData(CiTunesAtom_data& dataAtom)
+    {
+        return dataAtom.SetUInteger16(m_ulValue);
+    }
+};
+
+class iTunesUInteger8TransferPort : public iTunesULongTransferPort
+{
+public:
+    virtual HX_RESULT InjectData(CiTunesAtom_data& dataAtom)
+    {
+        return dataAtom.SetUInteger8(m_ulValue);
+    }
+};
+
+class iTunesRecordingYearTransferPort : public iTunesULongTransferPort
+{
+public:
+    virtual HX_RESULT InjectData(CiTunesAtom_data& dataAtom)
+    {
+        // Release date is in YYYY-MM-DD format, trailing fields can be omitted so we will write out YYYY.
+        ULONG32 uRecYear = (m_ulValue <= 9999) ? m_ulValue : 0;
+
+        char szOutputBuffer[8];
+        sprintf(szOutputBuffer, "%04d", uRecYear);
+
+        EncodedString strRecYearUTF8(szOutputBuffer, HX_TEXT_ENCODING_TYPE_UTF8);
+
+        // always output UTF8, no terminator
+        return dataAtom.SetUTF8String(strRecYearUTF8.GetData(), strRecYearUTF8.GetByteLength(FALSE));
+    }
+};
+
+void CMP4StreamMixer::MetaiTunes_AddItemAtom(HX_RESULT& retVal, CiTunesAtom_ilst* pIlst,
+                                    const char* pPropName, iTunesMetadataTransferPort& transfer)
+{
+    if( FAILED(retVal) )
+    {
+        return;
+    }
+
+    if( !pPropName || !pIlst )
+    {
+        retVal = HXR_INVALID_PARAMETER;
+        return;
+    }
+
+    if( !m_pFileHeader )
+    {
+        retVal = HXR_FAILED;
+        return;
+    }
+
+    if( transfer.ExtractData(*m_pFileHeader, pPropName) )
+    {
+        CMP4ContainerAtom* pItem = 0;
+        retVal = MetaiTunes_CreateItemAtomFromPropertyName(pPropName, &pItem);
+
+        if( SUCCEEDED(retVal) && pItem )
+        {
+            retVal = HXR_OUTOFMEMORY;
+
+            CiTunesAtom_data* pData = new CiTunesAtom_data();
+            if( pData )
+            {
+                retVal = transfer.InjectData(*pData);
+
+                if( SUCCEEDED( retVal ) )
+                {
+                    pItem->AddChild( pData );
+                    pIlst->AddChild( pItem );
+                }
+            }
+
+            if( FAILED( retVal ) )
+            {
+                delete pData;
+                delete pItem;
+            }
+        }
+    }
+}
+
+HX_RESULT CMP4StreamMixer::MetaiTunes_CreateItemAtomFromPropertyName(const char* pPropName, CMP4ContainerAtom** ppItemAtom)
+{
+    if( !ppItemAtom || *ppItemAtom )
+    {
+        return HXR_INVALID_PARAMETER;
+    }
+
+    HX_RESULT retVal = HXR_OK;
+
+    if (!strcmp(pPropName, _ITUNES_META_INFO_TITLE_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9nam();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_ARTIST_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9ART();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_COPYRIGHT_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_cprt();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_COMPOSER_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9wrt();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_COMMENT_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9cmt();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_ALBUM_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9alb();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_GENRE_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9gen();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9st3();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_GENERATOR_TOOL_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9too();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_ENCODED_BY_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9enc();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_GROUPING_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_grup();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_ALBUM_ARTIST_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_aART();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_LYRICS_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9lyr();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_RELEASE_DATE_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_A9day();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_tmpo();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_PART_OF_COMPILATION_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_cpil();
+    }
+    else if (!strcmp(pPropName, _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY))
+    {
+        *ppItemAtom = new CiTunesAtom_rtng();
+    }
+    else
+    {
+        // unknown property name
+        retVal = HXR_INVALID_PARAMETER;
+    }
+
+    if ( SUCCEEDED(retVal) && !(*ppItemAtom) )
+    {
+        retVal = HXR_OUTOFMEMORY;
+    }
+
+    return retVal;
+}
+
+HX_RESULT CMP4StreamMixer::BuildiTunesMetaData( CMP4Atom* pUdta )
 {
     HX_RESULT retVal = HXR_OUTOFMEMORY;
 
     // The metadata tree looks like this
     // udta
     //   meta
     //     hdlr
     //     ilst
     //     free
-    CM4AAtom_meta* pMeta = new CM4AAtom_meta();
+    CiTunesAtom_meta* pMeta = new CiTunesAtom_meta();
 
     if( pMeta )
     {
         retVal = HXR_OK;
 
         pUdta->AddChild( pMeta );
     }
 
     CMP4Atom_free* pFree = NULL;
-    CM4AAtom_ilst* pIlst = NULL;
+    CiTunesAtom_ilst* pIlst = NULL;
     if( SUCCEEDED( retVal ) )
     {
         retVal = HXR_OUTOFMEMORY;
 
         // hdlr
-        CM4AAtom_hdlr* pHdlr = new CM4AAtom_hdlr();
+        CiTunesAtom_hdlr* pHdlr = new CiTunesAtom_hdlr();
         if( pHdlr )
         {
             retVal = HXR_OK;
             
             pMeta->AddChild( pHdlr );
         }
         
         // ilst
         if( SUCCEEDED( retVal ) )
         {
             retVal = HXR_OUTOFMEMORY;
-            pIlst = new CM4AAtom_ilst();
+            pIlst = new CiTunesAtom_ilst();
 
             if( pIlst )
             {
                 retVal = HXR_OK;
                 
                 pMeta->AddChild( pIlst );
             }
         }
 
         // free. only create this if we are putting moov in the middle
         if( !m_bMoovAtEnd && !m_bForceMoovFirst)
         {
         if( SUCCEEDED( retVal ) )
         {
             retVal = HXR_OUTOFMEMORY;
             
             pFree = new CMP4Atom_free();
 
             if( pFree )
             {
                 retVal = HXR_OK;
                 
                 // reserve space for metadata
                 pFree->SetFreeSize(MP4_DEFAULT_METADATA_RESERVE_SIZE);
                 pMeta->AddChild( pFree );
             }
         }
     }
     }
 
     // Now build out the ilst
     if( SUCCEEDED( retVal ) )
     {
-        CM4AAtom_data* pData = NULL;
-        IHXBuffer* pBuf = NULL;
+        // string properties
+        // Although not mentioned by iTMF spec, iTunes have 255 character limit on string properties.
+        const ULONG32 ulStringLengthLimit = 255;
 
-        if( SUCCEEDED( m_pFileHeader->GetPropertyBuffer( "Author", pBuf ) ) && pBuf )
-        {
-            retVal = HXR_OUTOFMEMORY;
+        iTunesStringTransferPort stringTranferPort;
+        stringTranferPort.SetLengthLimit(ulStringLengthLimit);
+        stringTranferPort.SetUTF16Output(m_bUTF16Output);
             
-            CM4AAtom_art* pArtist = new CM4AAtom_art();
-            if( pArtist )
-            {
-                retVal = HXR_OUTOFMEMORY;
-                pData = new CM4AAtom_data();
-                if( pData )
-                {
-                    retVal = pData->SetString( pBuf->GetBuffer() );
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_TITLE_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_COMPOSER_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_COPYRIGHT_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_COMMENT_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_ARTIST_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_GENRE_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_ALBUM_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_GENERATOR_TOOL_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_ENCODED_BY_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_GROUPING_KEY, stringTranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_ALBUM_ARTIST_KEY, stringTranferPort);
+
+        // Lyrics atom (which is not described by iTMF spec) does not have 255 character limit.
+        // However it must be in UTF8 format.
+        stringTranferPort.SetLengthLimit(0);
+        stringTranferPort.SetUTF16Output(FALSE);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_LYRICS_KEY, stringTranferPort);
+
+        // predefined genre
                     if( SUCCEEDED( retVal ) )
                     {
-                        pArtist->AddChild( pData );
-                        pIlst->AddChild( pArtist );
-                        pData = NULL;
-                    }
-                }
-            }
-            HX_RELEASE( pBuf );
-        }
-        if( SUCCEEDED( m_pFileHeader->GetPropertyBuffer( "Title", pBuf ) ) && pBuf )
+            // try converting user defined genres to the list of ID3 predefined genres
+            EncodedString strGenres;
+            if(PropTools::CopyPropertyBuffer(strGenres, m_pFileHeader, _ITUNES_META_INFO_GENRE_KEY))
         {
-            retVal = HXR_OUTOFMEMORY;
-
-            CM4AAtom_nam* pName = new CM4AAtom_nam();
-            if( pName )
+                // need UTF8 to compare with ID3 names
+                EncodedString strGenresUTF8;
+                if(strGenres.ConvertToUTF8(strGenresUTF8))
             {
-                retVal = HXR_OUTOFMEMORY;
-                pData = new CM4AAtom_data();
-                if( pData )
+                    // iTunes user defined genre can be a comma separated list
+                    CHXPtrArray genreEntries;
+                    if(ID3Tools::ParseGenreNameList(genreEntries, strGenresUTF8.GetData(), FALSE, ',', TRUE))
                 {
-                    retVal = pData->SetString( pBuf->GetBuffer() );
-                    if( SUCCEEDED( retVal ) )
+                        // iTunes stores genre ordinals with ID3 value +1
+                        for(ULONG32 i = 0; i < genreEntries.GetSize(); i++)
                     {
-                        pName->AddChild( pData );
-                        pIlst->AddChild( pName );
-                        pData = NULL;
-                    }
-                }
-            }
-            HX_RELEASE( pBuf );
+                            UINT8 uGenreOrdinal = (UINT8)(ULONG32)genreEntries.GetAt(i) + 1;
+                            genreEntries.SetAt(i, (void*)(ULONG32)uGenreOrdinal);
         }
 
-        if( SUCCEEDED( m_pFileHeader->GetPropertyCString( "Generated By", pBuf ) ) && pBuf )
-        {
             retVal = HXR_OUTOFMEMORY;
 
-            CM4AAtom_too* pTools = new CM4AAtom_too();
-            if( pTools )
-            {
-                retVal = HXR_OUTOFMEMORY;
-                pData = new CM4AAtom_data();
-                if( pData )
-                {
-                    retVal = pData->SetString( pBuf->GetBuffer() );
-                    if( SUCCEEDED( retVal ) )
+                        CiTunesAtom_gnre* pItem = new CiTunesAtom_gnre();
+                        CiTunesAtom_data* pData = new CiTunesAtom_data();
+
+                        if(pItem && pData)
                     {
-                        pTools->AddChild( pData );
-                        pIlst->AddChild( pTools );
-                        pData = NULL;
+                            retVal = pData->SetSpecial_PredefinedGenreEntries(genreEntries);
+                        }
+
+                        MetaiTunes_LinkAtoms(retVal, pIlst, pItem, pData);
                     }
                 }
             }
-            HX_RELEASE( pBuf );
         }
         
-        if( SUCCEEDED( m_pFileHeader->GetPropertyBuffer( "Genre", pBuf ) ) && pBuf )
+        // recording year (type conversion), always outputed as UTF8
+        iTunesRecordingYearTransferPort recYearTranferPort;
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_RELEASE_DATE_KEY, recYearTranferPort);
+
+        // BPM should be 32 bits according to iTMF spec, but most implementations expect 16 bits
+        iTunesUInteger16TransferPort uint16TranferPort;
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY, uint16TranferPort);
+
+        // uint8 properties
+        iTunesUInteger8TransferPort uint8TranferPort;
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_PART_OF_COMPILATION_KEY, uint8TranferPort);
+        MetaiTunes_AddItemAtom(retVal, pIlst, _ITUNES_META_INFO_EXPLICIT_CONTENT_KEY, uint8TranferPort);
+
+        // track number/count
+        if(SUCCEEDED(retVal))
         {
-            retVal = HXR_OUTOFMEMORY;
+            ULONG32 ulTrackNumber = 0;
+            HXBOOL bHaveTN = PropTools::CopyPropertyULONG32(ulTrackNumber, m_pFileHeader, _ITUNES_META_INFO_TRACK_NUMBER_KEY);
 
-            CM4AAtom_gen* pGenre = new CM4AAtom_gen();
-            if( pGenre )
+            ULONG32 ulTrackCount = 0;
+            HXBOOL bHaveTC = PropTools::CopyPropertyULONG32(ulTrackCount, m_pFileHeader, _ITUNES_META_INFO_TRACK_COUNT_KEY);
+
+            if(bHaveTN || bHaveTC)
             {
                 retVal = HXR_OUTOFMEMORY;
-                pData = new CM4AAtom_data();
-                if( pData )
-                {
-                    retVal = pData->SetString( pBuf->GetBuffer() );
-                    if( SUCCEEDED( retVal ) )
+
+                CiTunesAtom_trkn* pItem = new CiTunesAtom_trkn();
+                CiTunesAtom_data* pData = new CiTunesAtom_data();
+
+                if(pItem && pData)
                     {
-                        pGenre->AddChild( pData );
-                        pIlst->AddChild( pGenre );
-                        pData = NULL;
-                    }
+                    retVal = pData->SetSpecial_TrackNumberCount(ulTrackNumber, ulTrackCount);
                 }
+
+                MetaiTunes_LinkAtoms(retVal, pIlst, pItem, pData);
             }
-            HX_RELEASE( pBuf );
         }
-        if( SUCCEEDED( m_pFileHeader->GetPropertyBuffer( "Album", pBuf ) ) && pBuf )
+
+        // disc number/count
+        if(SUCCEEDED(retVal))
         {
-            retVal = HXR_OUTOFMEMORY;
+            ULONG32 ulDiscNumber = 0;
+            HXBOOL bHaveDN = PropTools::CopyPropertyULONG32(ulDiscNumber, m_pFileHeader, _ITUNES_META_INFO_DISC_NUMBER_KEY);
 
-            CM4AAtom_alb* pAlbum = new CM4AAtom_alb();
-            if( pAlbum )
+            ULONG32 ulDiscCount = 0;
+            HXBOOL bHaveDC = PropTools::CopyPropertyULONG32(ulDiscCount, m_pFileHeader, _ITUNES_META_INFO_DISC_COUNT_KEY);
+
+            if(bHaveDN || bHaveDC)
             {
                 retVal = HXR_OUTOFMEMORY;
-                pData = new CM4AAtom_data();
-                if( pData )
-                {
-                    retVal = pData->SetString( pBuf->GetBuffer() );
-                    if( SUCCEEDED( retVal ) )
+
+                CiTunesAtom_disk* pItem = new CiTunesAtom_disk();
+                CiTunesAtom_data* pData = new CiTunesAtom_data();
+
+                if(pItem && pData)
                     {
-                        pAlbum->AddChild( pData );
-                        pIlst->AddChild( pAlbum );
-                        pData = NULL;
-                    }
+                    retVal = pData->SetSpecial_DiscNumberCount(ulDiscNumber, ulDiscCount);
                 }
+
+                MetaiTunes_LinkAtoms(retVal, pIlst, pItem, pData);
             }
-            HX_RELEASE( pBuf );
         }
-
     }
 
     // Resize our free atom (if present) given our new metadata
     if( SUCCEEDED( retVal ) && pFree )
     {
         UINT32 size = pUdta->GetCurrentSize( TRUE );
         size -= MP4_DEFAULT_METADATA_RESERVE_SIZE;
         
         pFree->SetFreeSize( MP4_DEFAULT_METADATA_RESERVE_SIZE - size );
     }
     
     return retVal;
 }
 
+void CMP4StreamMixer::MetaiTunes_LinkAtoms(HX_RESULT& retVal, CiTunesAtom_ilst* pIlst, CMP4ContainerAtom* pItem, CiTunesAtom_data* pData)
+{
+    if(SUCCEEDED(retVal) && pIlst && pItem && pData)
+    {
+        pItem->AddChild(pData);
+        pIlst->AddChild(pItem);
+    }
+
+    if(FAILED(retVal) || !pItem || !pData)
+    {
+        delete pItem;
+        delete pData;
+    }
+}
+
 HX_RESULT CMP4StreamMixer::BuildPSPMetaData( CMP4Atom* pUsmt )
 {
     HX_RESULT retVal = HXR_OUTOFMEMORY;
 
     CPSPAtom_MTDT* pMtdt = new CPSPAtom_MTDT();
 
     if( pMtdt )
     {
         retVal = HXR_OK;
 
         pUsmt->AddChild( pMtdt );
     }
 
     if( SUCCEEDED( retVal ) )
     {
         IHXBuffer* pBuf = NULL;
 
         if( SUCCEEDED( m_pFileHeader->GetPropertyBuffer( "Author", pBuf ) ) && pBuf )
         {
             pMtdt->SetAuthor( (const char*)pBuf->GetBuffer() );
             HX_RELEASE( pBuf );
         }
 
         if( SUCCEEDED( m_pFileHeader->GetPropertyBuffer( "Title", pBuf ) ) && pBuf )
         {
             pMtdt->SetTitle( (const char*)pBuf->GetBuffer() );
             HX_RELEASE( pBuf );
         }
     }
 
@@ -3777,61 +4121,61 @@
 
 HXBOOL CMP4StreamMixer::Meta3GP_ExtractFixedPoint(const EncodedString& s, INT32& outWhole, UINT32& outFrac, UINT32& outFixed)
 {
     if(s.IsEmpty() || !s.IsAsciiOnly())
     {
         return FALSE;
     }
 
     EncodedString val;
     s.ConvertToUTF8(val);
 
     if(!val.GetData())
     {
         return FALSE;
     }
     // ignore trailing junk; if there's any, it won't be written to the file anyway
     if(sscanf(val.GetData(), "%ld.%lu", &outWhole, &outFrac) == 2)
     {
         outFixed = (outWhole << 16) | (outFrac << 0);
         return TRUE;
     }
     if(sscanf(val.GetData(), "%ld", &outWhole) == 1)
     {
         outFrac = 0;
         outFixed = (outWhole << 16);
         return TRUE;
     }
     return FALSE;
 }
 
-HX_RESULT CMP4StreamMixer::Build3GPMetaData(  CMP4Atom* pUdta  )
+HX_RESULT CMP4StreamMixer::Build3GPMetaData(  CMP4Atom* pUdta, CMP4Atom* pMoov  )
 {
     HX_RESULT retVal = HXR_OK;
 
     // configure UTF16 output
     C3GPAtom_LangBase::ConfigureStringOutput(m_bUTF16Output);
 
     // Title
     Meta3GP_AddAtom_StringBase(retVal, pUdta, new C3GPAtom_titl(), _3GPP_META_INFO_TITLE_KEY);
 
     // Description
     Meta3GP_AddAtom_StringBase(retVal, pUdta, new C3GPAtom_dscp(), _3GPP_META_INFO_DESCRIPTION_KEY);
 
     // Copyright
     Meta3GP_AddAtom_StringBase(retVal, pUdta, new C3GPAtom_cprt(), _3GPP_META_INFO_COPYRIGHT_KEY);
 
     // Performer
     Meta3GP_AddAtom_StringBase(retVal, pUdta, new C3GPAtom_perf(), _3GPP_META_INFO_PERFORMER_KEY);
 
     // Author
     Meta3GP_AddAtom_StringBase(retVal, pUdta, new C3GPAtom_auth(), _3GPP_META_INFO_AUTHOR_KEY);
 
     // Genre
     Meta3GP_AddAtom_StringBase(retVal, pUdta, new C3GPAtom_gnre(), _3GPP_META_INFO_GENRE_KEY);
 
     // Rating
     C3GPAtom_rtng* pRtng = new C3GPAtom_rtng();
     if( Meta3GP_NewAtomGuard(retVal, pRtng) )
     {
         retVal = HXR_OK;
 
@@ -3846,139 +4190,139 @@
         UINT32 uCriteria = 0;
         EncodedString sCriteria;
         HXBOOL resCrit = PropTools::CopyPropertyBuffer(sCriteria, m_pFileHeader, _3GPP_META_INFO_RATING_CRITERIA_KEY);
         if(resCrit)
         {
             Meta3GP_ExtractUINT32(sCriteria, uCriteria);
         }
 
         EncodedString sInfo;
         HXBOOL resInfo = PropTools::CopyPropertyBuffer(sInfo, m_pFileHeader, _3GPP_META_INFO_RATING_INFO_KEY);
 
         if(resEnt || resCrit || resInfo)
         {
             if(resEnt)
             {
                 pRtng->SetRatingEntity(uEntity);
             }
             if(resCrit)
             {
                 pRtng->SetRatingCriteria(uCriteria);
             }
             if(resInfo)
             {
                 pRtng->SetString_RatingInfo(sInfo.GetData(), sInfo.GetEncoding());
             }
             Meta3GP_SetLanguageEncoding(pRtng);
             pUdta->AddChild(pRtng);
         }
         else
         {
-            delete pRtng;
+            HX_DELETE(pRtng);
         }
     }
 
     // Classification
     C3GPAtom_clsf* pClsf = new C3GPAtom_clsf();
     if( Meta3GP_NewAtomGuard(retVal, pClsf) )
     {
         retVal = HXR_OK;
 
         UINT32 uEntity = 0;
         EncodedString sEntity;
         HXBOOL resEnt = PropTools::CopyPropertyBuffer(sEntity, m_pFileHeader, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY);
         if(resEnt)
         {
             Meta3GP_ExtractUINT32(sEntity, uEntity);
         }
 
         ULONG32 uTable = 0;
         HXBOOL resTable = PropTools::CopyPropertyULONG32(uTable, m_pFileHeader, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY);
 
         EncodedString sInfo;
         HXBOOL resInfo = PropTools::CopyPropertyBuffer(sInfo, m_pFileHeader, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY);
 
         if(resEnt || resTable || resInfo)
         {
             if(resEnt)
             {
                 pClsf->SetClassificationEntity(uEntity);
             }
             if(resTable)
             {
                 pClsf->SetClassificationTable(UINT16(uTable));
             }
             if(resInfo)
             {
                 pClsf->SetString_ClassificationInfo(sInfo.GetData(), sInfo.GetEncoding());
             }
             Meta3GP_SetLanguageEncoding(pClsf);
             pUdta->AddChild(pClsf);
         }
         else
         {
-            delete pClsf;
+            HX_DELETE(pClsf);
         }
     }
 
     // Keywords
     C3GPAtom_kywd* pKywd = new C3GPAtom_kywd();
     if( Meta3GP_NewAtomGuard(retVal, pKywd) )
     {
         retVal = HXR_OK;
         HXBOOL bEmpty = TRUE;
 
         ULONG32 uCount = 0;
         HXBOOL resCount = PropTools::CopyPropertyULONG32(uCount, m_pFileHeader, _3GPP_META_INFO_KEYWORD_COUNT_KEY);
         if(resCount && (uCount > 0))
         {
             for(ULONG32 i = 0; i < uCount; i++)
             {
                 char key[64];
                 snprintf(key, 64, _3GPP_META_INFO_KEYWORD_KEY, i);
 
                 EncodedString sKeyword;
                 if(PropTools::CopyPropertyBuffer(sKeyword, m_pFileHeader, key))
                 {
                     pKywd->AddKeyword(sKeyword.GetData(), sKeyword.GetEncoding());
                 }
             }
             if(pKywd->GetKeywordCount() > 0)
             {
                 bEmpty = FALSE;
                 Meta3GP_SetLanguageEncoding(pKywd);
                 pUdta->AddChild(pKywd);
             }
         }
         if(bEmpty)
         {
-            delete pKywd;
+            HX_DELETE(pKywd);
         }
     }
 
     // Location
     C3GPAtom_loci* pLoci = new C3GPAtom_loci();
     if( Meta3GP_NewAtomGuard(retVal, pLoci) )
     {
         retVal = HXR_OK;
 
         EncodedString sName;
         HXBOOL resName = PropTools::CopyPropertyBuffer(sName, m_pFileHeader, _3GPP_META_INFO_LOCATION_NAME_KEY);
 
         EncodedString sAstro;
         HXBOOL resAstro = PropTools::CopyPropertyBuffer(sAstro, m_pFileHeader, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY);
 
         EncodedString sAddNotes;
         HXBOOL resAddNotes = PropTools::CopyPropertyBuffer(sAddNotes, m_pFileHeader, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY);
 
         ULONG32 uRole = 0;
         HXBOOL resRole = PropTools::CopyPropertyULONG32(uRole, m_pFileHeader, _3GPP_META_INFO_LOCATION_ROLE_KEY);
 
         INT32 coordWhole = 0;
         UINT32 coordFrac = 0;
 
         EncodedString sLong;
         UINT32 uLong = 0;
         HXBOOL resLong = PropTools::CopyPropertyBuffer(sLong, m_pFileHeader, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY) &&
                             Meta3GP_ExtractFixedPoint(sLong, coordWhole, coordFrac, uLong);
 
         EncodedString sLat;
@@ -3999,113 +4343,178 @@
             }
             if(resAstro)
             {
                 pLoci->SetString_AstronomicalBody(sAstro.GetData(), sAstro.GetEncoding());
             }
             if(resAddNotes)
             {
                 pLoci->SetString_AdditionalNotes(sAddNotes.GetData(), sAddNotes.GetEncoding());
             }
             if(resRole)
             {
                 pLoci->SetRole(UINT8(uRole));
             }
             if(resLong)
             {
                 pLoci->SetLongitude(uLong);
             }
             if(resLat)
             {
                 pLoci->SetLatitude(uLat);
             }
             if(resAlt)
             {
                 pLoci->SetAltitude(uAlt);
             }
             Meta3GP_SetLanguageEncoding(pLoci);
             pUdta->AddChild(pLoci);
         }
         else
         {
-            delete pLoci;
+            HX_DELETE(pLoci);
         }
     }
 
     // Album
     C3GPAtom_albm* pAlbm = new C3GPAtom_albm();
     if( Meta3GP_NewAtomGuard(retVal, pAlbm) )
     {
         retVal = HXR_OK;
 
         EncodedString sTitle;
         HXBOOL resTitle = PropTools::CopyPropertyBuffer(sTitle, m_pFileHeader, _3GPP_META_INFO_ALBUM_TITLE_KEY);
 
         ULONG32 uTrackNum = 0;
         HXBOOL resTrackNum = PropTools::CopyPropertyULONG32(uTrackNum, m_pFileHeader, _3GPP_META_INFO_TRACK_NUMBER_KEY);
 
         if(resTitle || resTrackNum)
         {
             if(resTitle)
             {
                 pAlbm->SetString_AlbumTitle(sTitle.GetData(), sTitle.GetEncoding());
             }
             if(resTrackNum)
             {
                 pAlbm->SetTrackNumber(TRUE, UINT8(uTrackNum));
             }
             Meta3GP_SetLanguageEncoding(pAlbm);
             pUdta->AddChild(pAlbm);
         }
         else
         {
-            delete pAlbm;
+            HX_DELETE(pAlbm);
         }
     }
 
     // Recording Year
     C3GPAtom_yrrc* pYrrc = new C3GPAtom_yrrc();
     if( Meta3GP_NewAtomGuard(retVal, pYrrc) )
     {
         retVal = HXR_OK;
 
         ULONG32 uRecYear = 0;
         if(PropTools::CopyPropertyULONG32(uRecYear, m_pFileHeader, _3GPP_META_INFO_RECORDING_YEAR_KEY))
         {
             pYrrc->SetRecordingYear(UINT16(uRecYear));
             pUdta->AddChild(pYrrc);
         }
         else
         {
-            delete pYrrc;
+            HX_DELETE(pYrrc);
+        }
+    }
+
+    // ID32, setup box hierarchy: file/moov/meta/[hdlr, ID32]
+    CMP4Atom_meta* pMeta = NULL;
+    if(SUCCEEDED(retVal))
+    {
+        retVal = Build3GPMetaDataID32(m_pFileHeader, &pMeta);
+        if(SUCCEEDED(retVal) && pMeta)
+        {
+            retVal = pMoov->AddChild(pMeta);
+        }
+    }
+
+    return retVal;
+}
+
+HX_RESULT CMP4StreamMixer::Build3GPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta )
+{
+    if(!ppMeta)
+    {
+        return HXR_POINTER;
+    }
+    if(!pHeader)
+    {
+        return HXR_INVALID_PARAMETER;
         }
+
+    *ppMeta = NULL;
+
+    IHXBuffer* pBlobID32 = NULL;
+    HX_RESULT retVal = HXR_OK;
+
+    if(SUCCEEDED(pHeader->GetPropertyBuffer(_3GPP_META_INFO_ID32_BLOB_KEY, pBlobID32)))
+    {
+        retVal = HXR_OUTOFMEMORY;
+
+        // setup box hierarchy: meta/[hdlr, ID32]
+        CMP4Atom_meta* pMeta = new CMP4Atom_meta();
+        CMP4Atom_hdlr* pHdlr = new CMP4Atom_hdlr();
+        C3GPAtom_ID32* pID32 = new C3GPAtom_ID32();
+
+        if(pMeta && pHdlr && pID32)
+        {
+            // 'hdlr' must be the first child of 'meta'
+            pHdlr->SetHandlerType("ID32");
+            pMeta->AddChild(pHdlr);
+
+            Meta3GP_SetLanguageEncoding(pID32);
+            pID32->SetBlob((UCHAR*)pBlobID32->GetBuffer(), pBlobID32->GetSize());
+            pMeta->AddChild(pID32);
+
+            retVal = HXR_OK;
     }
 
+        if(SUCCEEDED(retVal))
+        {
+            *ppMeta = pMeta;
+        }
+        else
+        {
+            HX_DELETE(pMeta);
+            HX_DELETE(pHdlr);
+            HX_DELETE(pID32);
+        }
+    }
+    HX_RELEASE(pBlobID32);
+
     return retVal;
 }
 
 HX_RESULT CMP4StreamMixer::StartBuildStsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum )
 {
     return BuildStsdEntry(pStsd, usStreamNum);
 }
 
 // Build out the stsd entry for a specific stream; we only have one stream in this case, but
 // extending this to handle multiple streams should be easy
 HX_RESULT CMP4StreamMixer::BuildStsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum )
 {
     // stream handler should have set SampleFormat already
     UINT32 ulSampleFormat  = 0;
     m_pStreamInfo[usStreamNum].m_pStreamHeader->GetPropertyULONG32("SampleFormat", ulSampleFormat);
 
     switch (ulSampleFormat)
     {
         case MP4_BUILD_ATOMID('m', 'p', '4', 'a'):
                 return BuildMP4AStsdEntry(pStsd, usStreamNum);
                 break;
         case MP4_BUILD_ATOMID('m', 'p', '4', 'v'):
                 return BuildMP4VStsdEntry(pStsd, usStreamNum);
                 break;
         case MP4_BUILD_ATOMID('a', 'v', 'c', '1'):
                 return BuildAVC1StsdEntry(pStsd, usStreamNum);
                 break;
         case MP4_BUILD_ATOMID('h', '2', '6', '3'):
                 return BuildH263StsdEntry(pStsd, usStreamNum);
                 break;
Index: mp4sm.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.h,v
retrieving revision 1.12
diff -d -H -b -B -w -U30 -r1.12 mp4sm.h
--- mp4sm.h	10 Jun 2009 16:06:40 -0000	1.12
+++ mp4sm.h	19 Oct 2009 17:45:25 -0000
@@ -25,66 +25,72 @@
  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  *
  * Technology Compatibility Kit Test Suite(s) Location:
  *    http://www.helixcommunity.org/content/tck
  *
  * Contributor(s):
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _MP4LAYOUT_H_
 #define _MP4LAYOUT_H_
 
 #include "hxslist.h"
 #include "pckunpck.h"
 #include "mp4fwplg.h"
 #include "proptools.h"
 
 #include "chxhintgen.h"
 
 // fdecl
 class CMP4Atom;
 class CMP4Atom_mvhd;
 class CMP4Atom_trak;
 class CMP4Atom_tkhd;
 class CMP4Atom_mdhd;
 class CMP4Atom_stsd;
 class CMP4Atom_sdp;
 class CMP4Atom_udta;
+class CMP4Atom_meta;
 class CMP4Archiver;
 
 class CMP4VersionedAtom;
+class CMP4ContainerAtom;
+class CiTunesAtom_ilst;
+class CiTunesAtom_data;
 class C3GPAtom_LangBase;
 class C3GPAtom_StringBase;
 
+class iTunesMetadataTransferPort;
+
 class CStblManager;
 class CHXString;
 
 #define HX_INVALID_STREAM_GROUP_NUMBER 0xFFFFFFFF
 #define HX_INVALID_SWITCH_GROUP_ID     0
 #define HX_INVALID_TRACK_ID            0
 #define HX_TRACK_ID_BASE               200
 #define HX_HINT_TRACK_ID_BASE          65536
 
 class CMP4StreamMixer : public IMP4StreamMixer
 {
 private:
     class HintInfo;
 public:
     CMP4StreamMixer( IUnknown* pContext, CMP4Archiver* pArchiver );
     ~CMP4StreamMixer();
     
     /*
      * IUnknown
      */
     STDMETHOD(QueryInterface)   ( THIS_ REFIID riid, void** ppvObj );
     STDMETHOD_(ULONG32,AddRef)  ( THIS );
     STDMETHOD_(ULONG32,Release) ( THIS );
 
     /*
      * IMP4StreamMixer routines
      */
     STDMETHOD(SetProperties)         (THIS_ IHXValues* pProperties                      );
     STDMETHOD(SetFileHeader)         (THIS_ IHXValues* pFileHeader                      );
     STDMETHOD(SetStreamHeader)       (THIS_ IHXValues* pStreamHeader                    );
@@ -179,172 +185,179 @@
         ~StreamInfo();
 
         IHXValues*     m_pStreamHeader;
         CStblManager*  m_pStblManager;
         HXBOOL         m_bHaveSeenFirstPacket;
         HXBOOL         m_bIsAudio;
         HXBOOL         m_bIsVideo;
         UINT32         m_ulFirstTimestamp;
         UINT32         m_ulLastTimestamp;
         UINT32         m_ulLastTimestampDelta;
         UINT32         m_ulFirstRTPTimestamp;
         UINT32         m_ulStreamGroupNumber;
         UINT32         m_ulSwitchGroupID;
         UINT32         m_ulAvgBitRate;
         UINT32         m_ulASMAverageBandwidth;
         UINT32         m_ulTrackID;
         UINT32         m_ulHintTrackID;
         UINT32         m_ulBaseRule;
         UINT32         m_ulNumASMRules;
         HXASMRuleInfo* m_pASMRuleInfo;
         CHXSimpleList* m_pPacketList;
         CMP4Atom_tkhd* m_pTkhd;
         CMP4Atom_mdhd* m_pMdhd;
         HintInfo*      m_pHintInfo;
     };
 
     // Build the entire atom tree
     HX_RESULT BuildMP4Atoms();
     
     // Build the metadata subtree
-    HX_RESULT BuildIPODMetaData( CMP4Atom* pUdta );
+    HX_RESULT BuildiTunesMetaData( CMP4Atom* pUdta );
     HX_RESULT BuildPSPMetaData( CMP4Atom* pUsmt );
-    HX_RESULT Build3GPMetaData( CMP4Atom* pUdta );
+    HX_RESULT Build3GPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov );
+    HX_RESULT Build3GPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta );
 
     // Build the trak subtree
     HX_RESULT BuildTrack( UINT16 usStreamNum, CMP4Atom* pTrak );
     HXBOOL    IsStreamInSwitchGroup(UINT32 ulStreamNumber, UINT32* pulSwitchGroupID = NULL);
     void      SetSwitchGroup(CMP4Atom_udta* pUdtaAtom, UINT32 ulStreamNumber);
     HXBOOL    NeedToAddUdtaChildToTrakBox(CMP4Atom_trak* pTrakBox, UINT32 ulStreamNumber);
     HXBOOL    NeedToAddUdtaChildToMoovBox();
     HX_RESULT AddMovieHintInformation(CMP4Atom_udta* pUdta);
     HX_RESULT GenerateMovieLevelSDP(CHXString* pSDPStr);
     HX_RESULT GenerateAltGroupSDP(CHXString* pAltGroupSDPStr);
     HX_RESULT FindStreamNumInAlternateGroupWithAvgBandwidth(UINT32 ulStreamGroupNumber, UINT32 ulStreamBandwidth, UINT32* pulStreamNum);
     HX_RESULT GetTrackIDForAssociatedHintTrack(UINT32 ulStreamNumber, UINT32* pulHintTrackID);
     HX_RESULT ParseASMRulePropertyUINT32(IHXValues* pProps, const char* pszName, UINT32 ulFlag, UINT32* pulAllFlags, UINT32* pulValue);
     HX_RESULT ParseASMRulePropertyPresence(IHXValues* pProps, const char* pszName, UINT32 ulFlag, UINT32* pulAllFlags, HXBOOL* pbValue);
     HX_RESULT ParseASMRuleProperties(IHXValues* pProps, HXASMRuleInfo* pInfo);
     HX_RESULT ParseStreamASMRuleBook(StreamInfo* pInfo);
     HX_RESULT FindStreamInSwitchGroup(UINT32 ulSwitchGroupID, UINT32 ulASMRule, UINT32* pulStreamNumber);
     HX_RESULT ChangePacketStreamNumber(IHXPacket* pPacket, UINT32 ulNewStreamNumber, REF(IHXPacket*) rpPacket);
     void      CheckForRTPPackets(IHXPacket* pPacket);
     void      ChooseTrackIDs();
     HX_RESULT DetermineStreamType(IHXValues* pStreamHeader, HXBOOL* pbIsAudio, HXBOOL* pbIsVideo);
     HX_RESULT GetStreamBandwidth(UINT32 ulStreamNum, UINT32* pulBandwidth);
     void      AddHintingStatisticsBoxes(CMP4Atom_udta* pUdta);
 
     // Method used to sort stream headers by "AvgBitRate" property
     static int StreamHeaderAvgBitRateSort(void* pHdr1, void* pHdr2);
 
     // Build the mdia subtree
     HX_RESULT BuildMdia(UINT16 usStreamNum, CMP4Atom *pTrak, HintInfo *pHinfo);
 
     // Build out an stsd entry for a specific stream
     HX_RESULT BuildStsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum );
     
     HX_RESULT BuildMP4AStsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum );
     HX_RESULT BuildMP4VStsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum );
     HX_RESULT BuildAVC1StsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum );
     HX_RESULT BuildH263StsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum );
     HX_RESULT BuildAMRStsdEntry( CMP4Atom_stsd* pStsd, UINT16 usStreamNum );
 
     // 3GP Utilities
     void Meta3GP_SetLanguageEncoding(C3GPAtom_LangBase* pAtom, const char* propertySpec = 0);
     HXBOOL Meta3GP_NewAtomGuard(HX_RESULT& retVal, CMP4VersionedAtom* pAtom);
     void Meta3GP_AddAtom_StringBase(HX_RESULT& retVal, CMP4Atom* pUdta, C3GPAtom_StringBase* pAtom, const char* pPropName);
     void Meta3GP_ExtractUINT32(const EncodedString& s, UINT32& out);
     void Meta3GP_ExtractUINT16(const EncodedString& s, UINT16& out);
     HXBOOL Meta3GP_ExtractFixedPoint(const EncodedString& s, INT32& outWhole, UINT32& outFrac, UINT32& outFixed);
 
+    void MetaiTunes_LinkAtoms(HX_RESULT& retVal, CiTunesAtom_ilst* pIlst, CMP4ContainerAtom* pItem, CiTunesAtom_data* pData);
+    void MetaiTunes_AddItemAtom(HX_RESULT& retVal, CiTunesAtom_ilst* pIlst, const char* pPropName, iTunesMetadataTransferPort& transfer);
+    HX_RESULT MetaiTunes_CreateItemAtomFromPropertyName(const char* pPropName, CMP4ContainerAtom** ppItemAtom);
+
     // Fix up the duration if it differs from the reported one
     HX_RESULT UpdateDuration( UINT32 ulDuration );
     
     // Update track duration
     HX_RESULT UpdateTrackDuration( UINT16 usStreamNo, UINT32 ulDuration );
     HX_RESULT FinalizeSDP(UINT32 ulStreamNum);
 
     HX_RESULT FlushPackets( UINT16 uiStreamNo );
     HX_RESULT FlushHintPackets( UINT16 uiStreamNo );
 
     // Routine to dump out atom contents
     HX_RESULT DumpAtoms();
     
     LONG32   m_lRefCount;
 
     CMP4Atom* m_pRootAtom;
 
     // We retain copies of these so we can adjust the duration
     // after all packets are received without having to do
     // multiple atom searches
     CMP4Atom_mvhd* m_pMvhd;
     CMP4Atom_mdhd* m_pMdhd;
 
     UINT32     m_ulReportedDuration;
     UINT32     m_ulActualDuration;
     UINT32     m_ulLastTimestamp;
     UINT32     m_ulFirstTimestamp;
 
     HXBOOL     m_bMoovAtEnd;
     HXBOOL     m_bForceMoovFirst;
 
     IUnknown*  m_pContext;
     IHXValues* m_pFileHeader;
     UINT32     m_ulStreamCount;
     UINT32     m_ulStreamGroupCount;
     UINT32     m_ulStreamHeaderReceived;
     UINT32     m_ulStreamDoneReceived;
 
     CHXHintContext m_HintContext;
 
     StreamInfo* m_pStreamInfo;
     
     CMP4Archiver* m_pArchiver;
 
     enum RTPPacketStream
     {
 	UNCHECKED = 0,
 	IS_RTP    = 1,
 	NOT_RTP   = 2,
     };
 
     RTPPacketStream m_eIsRtp;
     
     UINT32 m_uiByteCount;
     UINT32 m_uiReservedBlockCount;
 
     enum MetaFlavor
     {
         META_ITUNES,
-        META_3GP,
+        META_3GPP,
         META_PSP
     };
 
     MetaFlavor m_eMetaFlavor;
+    HXBOOL     m_bRequestedOutputMetaFlavor3GPP;
+    HXBOOL     m_bRequestedOutputMetaFlavorITUNES;
 
     HXBOOL        m_bUTF16Output;
     EncodedString m_spCompatibility;
 
 protected:
     enum ThreeGPPMode
     {
 	M3GPP_NONE,
 	M3GPP_GENERAL,
 	M3GPP_BASIC,
 	M3GPP_STREAMING,
 	M3GPP_PROGDL,
 	M3GPP_STREAMDL,
 	M3GPP_REL5
     };
     ThreeGPPMode m_e3gpMode;
     HXBOOL m_bTSInterleave;
     HXBOOL m_bGenerateHintTracks;
 
     friend class CStblManager;
 
     UINT32 m_uiBaseWriteOffset;
     UINT32 m_uiCurrentOffset;
     UINT32 m_uiGlobalFlush;
 };
 
 
 #endif // _MP4SM_H_
datatype_tools_dtdriver_apps_meta3gp.diff (text/x-patch, 83.6 KB)
Index: Umakefil_meta3gp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/Umakefil_meta3gp,v
retrieving revision 1.2
diff -d -H -b -B -w -U30 -r1.2 Umakefil_meta3gp
--- Umakefil_meta3gp	6 Nov 2007 11:39:02 -0000	1.2
+++ Umakefil_meta3gp	19 Oct 2009 17:42:05 -0000
@@ -1,33 +1,33 @@
 
 UmakefileVersion(2,0)
 
 project.AddModuleIncludes("common/include",
                           "common/log/logobserverfile/pub",
                           "datatype/include",
+                          "datatype/common/util/pub",
                           "datatype/common/filewriter/pub",
                           "datatype/tools/dtdriver/engine/pub",
                           "datatype/tools/minicntx/pub",
                           "datatype/tools/metaeditor/pub",
                           "producersdk/include")
 
 project.AddModuleLibraries( "client/common/container[contclntlib]",
 			    "client/common/system[sysclntlib]",
 			    "client/common/util[utlclntlib]",
                             "common/runtime[runtlib]",
 			    "common/dbgtool[debuglib]", 
 			    "common/util[utillib]", 
 			    "common/container[contlib]",
 			    "common/system[syslib]",
 			    "common/fileio[fileiolib]",
-			    "common/log/logutil[logutillib]")
-
-project.AddModuleLibraries("datatype/tools/metaeditor[metautil3gplib]")
+			    "common/log/logutil[logutillib]",
+                "datatype/common/util[dtutillib]")
 
 project.AddDefines( 'HELIX_FEATURE_ALLOW_DEPRECATED_SMARTPOINTERS' )
 
 project.AddSources( "main.cpp",
                     "dlliids.cpp")
 
 ProgramTarget('meta3gp')
 
 DependTarget()
Index: main.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/main.cpp,v
retrieving revision 1.1
diff -d -H -b -B -w -U30 -r1.1 main.cpp
--- main.cpp	5 Nov 2007 22:46:15 -0000	1.1
+++ main.cpp	19 Oct 2009 17:42:07 -0000
@@ -31,87 +31,78 @@
  * 
  * Contributor(s): 
  *  
  * ***** END LICENSE BLOCK ***** */ 
 
 
 /****************************************************************************
  *  Includes
  */
 #include <stdlib.h>
 #include <stdarg.h>
 
 #include "hlxclib/time.h"
 #include "hlxclib/stdio.h"
 #include "hlxclib/wchar.h"
 #include "hxtypes.h"
 #include "hlxosstr.h"
 #include "ffdriver.h"
 #include "cstrmsrt.h"
 #include "hxmemprb.h"
 #include "hxtick.h"
 #include "chxpckts.h"
 #include "pckunpck.h"
 #include "dllpath.h"
 #include "filespecutils.h"
 #include "metainfokeys.h"
 #include "uniconv.h"
 #include "proptools.h"
 #include "dllacces.h"
 #include "ihxmetaeditor.h"
-#include "metautil3gp.h"
+#include "metautil.h"
 
 
 /****************************************************************************
- *  3GP meta-data command line editor.
+ *  Meta-data command line editor.
  *  Build-time configuration options.
  */
 
-// uncomment to use synchronous mode
-#define USE_SYNCHRONOUS_MODE 1
-
-// uncomment to test meta-editor's default processor
-//#define TEST_DEFAULT_META_EDITOR_PROCESSOR 1
-
 // uncomment to force usage of legacy strings on Windows
 // (only relevant for command-line argument transfer)
 //#define FORCE_LEGACY_CHAR 1
 
 
 /****************************************************************************
- *  Operational mode
+ *  Component operational modes
  */
-#ifdef USE_SYNCHRONOUS_MODE
-const BOOL g_bSynchronousMode = TRUE;
-#else
-const BOOL g_bSynchronousMode = FALSE;
-#endif
+HXBOOL g_bUseDefaultMetaEditorProcessor = FALSE;
+HXBOOL g_bUseDTDriverSynchronousMode = FALSE;
 
 
 /****************************************************************************
  *  System character type macros
  */
 #ifdef USE_WIDE_CHAR
 #undef USE_WIDE_CHAR
 #endif
 
 #if defined(_WINDOWS) && !defined(FORCE_LEGACY_CHAR)
 #define USE_WIDE_CHAR 1
 #endif
 
 
 #ifdef _T
 #undef _T
 #endif
 #ifdef TCHAR
 #undef TCHAR
 #endif
 #ifdef TMAIN
 #undef TMAIN
 #endif
 
 
 #ifdef USE_WIDE_CHAR
 
 #define _T(Val) L##Val
 #define TCHAR wchar_t
 #define TMAIN wmain
@@ -119,440 +110,500 @@
 #define TStringLength ::StringLengthW
 #define TStringEqual ::StringEqualW
 #define TStringAppend ::StringAppendW
 #define TConvertToCCPString(Val) EncStrUtils::Duplicate((const char*)CCPFromWCharT(Val), \
                                             HX_TEXT_ENCODING_TYPE_UNKNOWN, EncStrUtils::ALLOC_FLAG_NEW)
 #define ENCODED_STRING_VAR(VarName, Val) EncodedString VarName((const char*)::UTF8FromWCharT(Val), HX_TEXT_ENCODING_TYPE_UTF8)
 #define ENCODED_STRING_CTOR(Val) EncodedString((const char*)::UTF8FromWCharT(Val), HX_TEXT_ENCODING_TYPE_UTF8)
 
 #else //USE_WIDE_CHAR
 
 #define _T(Val) Val
 #define TCHAR char
 #define TMAIN main
 #define TPrintf printf
 #define TStringLength ::StringLengthA
 #define TStringEqual ::StringEqualA
 #define TStringAppend ::StringAppendA
 #define TConvertToCCPString(Val) EncStrUtils::Duplicate(Val, \
                                             HX_TEXT_ENCODING_TYPE_UNKNOWN, EncStrUtils::ALLOC_FLAG_NEW)
 #define ENCODED_STRING_VAR(VarName, Val) EncodedString VarName((const char*)::UTF8FromCCP(Val), HX_TEXT_ENCODING_TYPE_UTF8)
 #define ENCODED_STRING_CTOR(Val) EncodedString((const char*)::UTF8FromCCP(Val), HX_TEXT_ENCODING_TYPE_UTF8)
 
 #endif //USE_WIDE_CHAR
 
 
 /****************************************************************************
  *  Build-time messages
  */
 #ifdef _WINDOWS
 
-#ifdef USE_SYNCHRONOUS_MODE
-#   pragma message("Using synchronous mode")
-#else
-#   pragma message("Using asynchronous mode")
-#endif
-
-#ifdef TEST_DEFAULT_META_EDITOR_PROCESSOR
-#   pragma message("Using default meta-data processor")
-#else
-#   pragma message("Using custom meta-data processor")
-#endif
-
 #ifdef USE_WIDE_CHAR
 #   pragma message("Using wide-string command-line arguments")
 #else
 #   pragma message("Using legacy-string command-line arguments")
 #endif
 
 #endif //_WINDOWS
 
 
 /****************************************************************************
  *  DLLAccessPath Variable
  */
 ENABLE_DLLACCESS_PATHS(g_Meta3GPAccessPath);
 
 
 /****************************************************************************
  *  Defines
  */
-#define PROGRAM_NAME_STRING         _T("RealNetworks 3GP meta-data editor")
-#define PROGRAM_COPYRIGHT_STRING    _T("Copyright (c) RealNetworks 2007")
-#define PROGRAM_VERSION_STRING      _T("1.0.11")
+#define PROGRAM_NAME_STRING         _T("RealNetworks meta-data editor")
+#define PROGRAM_COPYRIGHT_STRING    _T("Copyright (c) RealNetworks 2009")
+#define PROGRAM_VERSION_STRING      _T("2.0.0")
 
-#define OPTION_STRING_HELP          _T("h")
+// input/output control
+#define PARAM_STRING_SYNCMODE       _T("dev-syncmode")
+#define PARAM_STRING_DEFMETAPROC    _T("dev-defmetaproc")
+#define PARAM_STRING_INPUTFILE      _T("if")
+#define PARAM_STRING_OUTPUTFILE     _T("of")
+#define PARAM_STRING_XMLINPUTFILE   _T("xmlin")
+#define PARAM_STRING_XMLOUTPUTFILE  _T("xmlout")
+#define PARAM_STRING_CLEARMETADATA  _T("metaclear")
+#define PARAM_STRING_METASTYLE      _T("metastyle")
+#define PARAM_STRING_UTF16OUTPUT    _T("utf16")
+#define PARAM_STRING_OVERWRITEFILE  _T("overwrite")
+#define PARAM_STRING_PRINTMETADATA  _T("print")
+#define PARAM_STRING_HELP           _T("help")
 
-#define OPTION_STRING_INPUTFILE      _T("i")
-#define OPTION_STRING_OUTPUTFILE     _T("o")
-#define OPTION_STRING_OVERWRITEFILE  _T("w")
-#define OPTION_STRING_CLEARMETADATA  _T("c")
-#define OPTION_STRING_PRINTMETADATA  _T("p")
-#define OPTION_STRING_UTF16OUTPUT    _T("utf16")
+// common metadata
+#define PARAM_STRING_TITLE         _T("title")
+#define PARAM_STRING_ARTIST        _T("artist")
+#define PARAM_STRING_ALBUM         _T("album")
+#define PARAM_STRING_GENRE         _T("genre")
+#define PARAM_STRING_COMPOSER      _T("composer")
+#define PARAM_STRING_COMMENT       _T("comment")
+#define PARAM_STRING_COVERART      _T("cover")
+#define PARAM_STRING_TRACKNUMBER   _T("track")
+#define PARAM_STRING_YEAR          _T("year")
 
-#define OPTION_STRING_LANGUAGE_CODE  _T("lang")
+// iTunes specific metadata
+#define PARAM_STRING_SOFTWARE     _T("software")
+#define PARAM_STRING_ENCODEDBY    _T("encodedby")
+#define PARAM_STRING_GROUPING     _T("grouping")
+#define PARAM_STRING_ALBUMARTIST  _T("albumartist")
+#define PARAM_STRING_LYRICS       _T("lyrics")
+#define PARAM_STRING_SUBTITLE     _T("subtitle")
+#define PARAM_STRING_BPM          _T("bpm")
+#define PARAM_STRING_PARTOFCOMP   _T("partofcompilation")
+#define PARAM_STRING_EXPLICIT     _T("explicitcontent")
+#define PARAM_STRING_TRACKSTOTAL  _T("trackstotal")
+#define PARAM_STRING_DISKNUMBER   _T("disk")
+#define PARAM_STRING_DISKSTOTAL   _T("diskstotal")
 
-#define OPTION_STRING_TITLE         _T("title")
-#define OPTION_STRING_DESCRIPTION   _T("description")
-#define OPTION_STRING_COPYRIGHT     _T("copyright")
-#define OPTION_STRING_PERFORMER     _T("performer")
-#define OPTION_STRING_AUTHOR        _T("author")
-#define OPTION_STRING_GENRE         _T("genre")
-#define OPTION_STRING_ALBUM         _T("album")
-#define OPTION_STRING_TRACK         _T("track")
-#define OPTION_STRING_YEAR          _T("year")
+// 3GPP specific metadata
+#define PARAM_STRING_LANGUAGE_CODE  _T("lang")
+#define PARAM_STRING_COPYRIGHT      _T("copyright")
 
-#define OPTION_STRING_RATING_ENTITY     _T("rtgent")
-#define OPTION_STRING_RATING_CRITERIA   _T("rtgcrit")
-#define OPTION_STRING_RATING_INFO       _T("rtginfo")
+#define PARAM_STRING_RATING_ENTITY     _T("rtngent")
+#define PARAM_STRING_RATING_CRITERIA   _T("rtngcrit")
+#define PARAM_STRING_RATING_INFO       _T("rtnginfo")
 
-#define OPTION_STRING_CLASSIFICATION_ENTITY  _T("clsent")
-#define OPTION_STRING_CLASSIFICATION_TABLE   _T("clstbl")
-#define OPTION_STRING_CLASSIFICATION_INFO    _T("clsinfo")
+#define PARAM_STRING_CLASSIFICATION_ENTITY  _T("clsent")
+#define PARAM_STRING_CLASSIFICATION_TABLE   _T("clstbl")
+#define PARAM_STRING_CLASSIFICATION_INFO    _T("clsinfo")
 
-#define OPTION_STRING_KEYWORD_ADD          _T("kwadd")
-#define OPTION_STRING_KEYWORD_REMOVE       _T("kwrem")
-#define OPTION_STRING_KEYWORD_CLEAR        _T("kwclr")
+#define PARAM_STRING_KEYWORD_ADD          _T("kwdadd")
+#define PARAM_STRING_KEYWORD_REMOVE       _T("kwdrem")
+#define PARAM_STRING_KEYWORD_CLEAR        _T("kwdclr")
 
-#define OPTION_STRING_LOCATION_NAME               _T("locname")
-#define OPTION_STRING_LOCATION_ASTRONOMICAL_BODY  _T("locastro")
-#define OPTION_STRING_LOCATION_ADDITIONAL_NOTES   _T("locnotes")
-#define OPTION_STRING_LOCATION_ROLE               _T("locrole")
-#define OPTION_STRING_LOCATION_LONGITUDE          _T("loclong")
-#define OPTION_STRING_LOCATION_LATITUDE           _T("loclat")
-#define OPTION_STRING_LOCATION_ALTITUDE           _T("localt")
+#define PARAM_STRING_LOCATION_NAME               _T("locname")
+#define PARAM_STRING_LOCATION_ASTRONOMICAL_BODY  _T("locastro")
+#define PARAM_STRING_LOCATION_ADDITIONAL_NOTES   _T("locnotes")
+#define PARAM_STRING_LOCATION_ROLE               _T("locrole")
+#define PARAM_STRING_LOCATION_LONGITUDE          _T("loclong")
+#define PARAM_STRING_LOCATION_LATITUDE           _T("loclat")
+#define PARAM_STRING_LOCATION_ALTITUDE           _T("localt")
 
 
 /****************************************************************************
 *  Help display utilities
 */
-class CommandDesc
+class ParameterDesc
 {
 public:
-    CommandDesc(const TCHAR* cmd_, const TCHAR* cmd_suffix_, const TCHAR* desc_)
+    ParameterDesc(const TCHAR* cmd_ = 0, const TCHAR* cmd_suffix_ = 0, const TCHAR* desc_ = 0)
     {
         cmd = cmd_;
         cmd_suffix = cmd_suffix_;
         desc = desc_;
     }
-    UINT32 GetLeftColumnWidth()
+    ULONG32 GetLeftColumnWidth()
     {
-        UINT32 len = 0;
+        ULONG32 len = 0;
         if(cmd)
         {
-            len += 3 + TStringLength(cmd); //3 for prefix
+            len += 2 + TStringLength(cmd); //leading whitespace and parameter prefix
             if(cmd_suffix)
             {
-                len += 1 + TStringLength(cmd_suffix); //1 for whitespace separator
+                len += 1 + TStringLength(cmd_suffix); //whitespace separator
             }
         }
         return len;
     }
-    TCHAR* BuildLine(UINT32 leftColumnWidth)
+    TCHAR* BuildLine(ULONG32 leftColumnWidth)
     {
         TCHAR* out = TStringAppend(0, _T(""));
         if(cmd)
         {
-            out = TStringAppend(out, _T("  -"));
+            out = TStringAppend(out, _T(" -")); //leading whitespace and parameter prefix
             out = TStringAppend(out, cmd);
             if(cmd_suffix)
             {
-                out = TStringAppend(out, _T(" "));
+                out = TStringAppend(out, _T(" ")); //whitespace separator
                 out = TStringAppend(out, cmd_suffix);
             }
             if(desc)
             {
                 INT32 diff = leftColumnWidth - TStringLength(out);
                 for(int d = 0; d < diff; d++)
                 {
                     out = TStringAppend(out, _T(" "));
                 }
                 out = TStringAppend(out, desc);
             }
         }
         return out;
     }
 
 private:
     const TCHAR* cmd;
     const TCHAR* cmd_suffix;
     const TCHAR* desc;
 };
 
-class CommandDescPrinter
+class ParameterDescPrinter
 {
 public:
-    void Add(CommandDesc* cd)
+    void Add(ParameterDesc* cd)
     {
         descs.Add(cd);
     }
     int CalcLeftColumnWidth()
     {
         int leftColumnWidth = 0;
         for(int i = 0; i < descs.GetSize(); i++)
         {
-            CommandDesc* cd = (CommandDesc*)descs.GetAt(i);
+            ParameterDesc* cd = (ParameterDesc*)descs.GetAt(i);
             int width = cd->GetLeftColumnWidth();
             if(width > leftColumnWidth)
             {
                 leftColumnWidth = width;
             }
         }
         return leftColumnWidth;
     }
     void PrintColumns(int columnSpacing = 1)
     {
         int leftColumnWidth = CalcLeftColumnWidth() + columnSpacing;
         for(int i = 0; i < descs.GetSize(); i++)
         {
-            CommandDesc* cd = (CommandDesc*)descs.GetAt(i);
+            ParameterDesc* cd = (ParameterDesc*)descs.GetAt(i);
             TCHAR* line = cd->BuildLine(leftColumnWidth);
             if(line)
             {
                 TPrintf(_T("%s\n"), line);
             }
             delete [] line;
         }
     }
 
 private:
     CHXPtrArray descs;
 };
 
 void DisplayUsage(const TCHAR* argv0)
 {
     const TCHAR* pszDbg = _T("");
-    const TCHAR* pszSyncMode = _T("");
 #if defined(DEBUG) || defined(_DEBUG)
     pszDbg = _T(".debug");
-    if(g_bSynchronousMode)
-    {
-        pszSyncMode = _T(".sync");
-    }
-    else
-    {
-        pszSyncMode = _T(".async");
-    }
 #endif
-    TPrintf(_T("\n--- %s ---\n    %s\n    Version %s%s%s\n\n"), PROGRAM_NAME_STRING, PROGRAM_COPYRIGHT_STRING, PROGRAM_VERSION_STRING, pszDbg, pszSyncMode);
-    TPrintf(_T("usage: %s [ -command [value]... ]...\n"), argv0);
-    TPrintf(_T("with commands:\n"));
-
-    CommandDescPrinter cdp;
-
-    cdp.Add(new CommandDesc(OPTION_STRING_INPUTFILE, _T("<string>"), _T("input file")));
-    cdp.Add(new CommandDesc(OPTION_STRING_OUTPUTFILE, _T("<string>"), _T("3GP output file")));
-    cdp.Add(new CommandDesc(OPTION_STRING_OVERWRITEFILE, 0, _T("overwrite output file if it exists")));
-
-    cdp.Add(new CommandDesc(OPTION_STRING_CLEARMETADATA, 0, _T("clear all meta-data")));
-    cdp.Add(new CommandDesc(OPTION_STRING_PRINTMETADATA, 0, _T("print extracted/updated meta-data")));
-
-    cdp.Add(new CommandDesc(OPTION_STRING_UTF16OUTPUT, 0, _T("store meta-data strings in UTF16 format")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LANGUAGE_CODE, _T("<3-character string>"), _T("ISO639.2/T language code of meta-data text")));
-
-    cdp.Add(new CommandDesc(OPTION_STRING_TITLE, _T("<string>"), _T("update meta-data: title")));
-    cdp.Add(new CommandDesc(OPTION_STRING_DESCRIPTION, _T("<string>"), _T("update meta-data: description")));
-    cdp.Add(new CommandDesc(OPTION_STRING_COPYRIGHT, _T("<string>"), _T("update meta-data: copyright")));
-    cdp.Add(new CommandDesc(OPTION_STRING_PERFORMER, _T("<string>"), _T("update meta-data: performer")));
-    cdp.Add(new CommandDesc(OPTION_STRING_AUTHOR, _T("<string>"), _T("update meta-data: author")));
-    cdp.Add(new CommandDesc(OPTION_STRING_GENRE, _T("<string>"), _T("update meta-data: genre")));
-    cdp.Add(new CommandDesc(OPTION_STRING_ALBUM, _T("<string>"), _T("update meta-data: album title")));
-    cdp.Add(new CommandDesc(OPTION_STRING_TRACK, _T("<integer 0..255>"), _T("update meta-data: track number")));
-    cdp.Add(new CommandDesc(OPTION_STRING_YEAR, _T("<integer 0..65536>"), _T("update meta-data: recording year")));
-
-    cdp.Add(new CommandDesc(OPTION_STRING_RATING_ENTITY, _T("<4-character string>"), _T("update meta-data: rating entity")));
-    cdp.Add(new CommandDesc(OPTION_STRING_RATING_CRITERIA, _T("<4-character string>"), _T("update meta-data: rating criteria")));
-    cdp.Add(new CommandDesc(OPTION_STRING_RATING_INFO, _T("<string>"), _T("update meta-data: rating info")));
-
-    cdp.Add(new CommandDesc(OPTION_STRING_CLASSIFICATION_ENTITY, _T("<4-character string>"), _T("update meta-data: classification entity")));
-    cdp.Add(new CommandDesc(OPTION_STRING_CLASSIFICATION_TABLE, _T("<integer 0..65535>"), _T("update meta-data: classification table")));
-    cdp.Add(new CommandDesc(OPTION_STRING_CLASSIFICATION_INFO, _T("<string>"), _T("update meta-data: classification info")));
 
-    cdp.Add(new CommandDesc(OPTION_STRING_KEYWORD_ADD, _T("<string>"), _T("update meta-data: add keyword")));
-    cdp.Add(new CommandDesc(OPTION_STRING_KEYWORD_REMOVE, _T("<string>"), _T("update meta-data: remove keyword")));
-    cdp.Add(new CommandDesc(OPTION_STRING_KEYWORD_CLEAR, 0, _T("update meta-data: clear all keywords")));
+    TPrintf(_T("\n--- %s ---\n    %s\n    Version %s%s\n\n"), PROGRAM_NAME_STRING, PROGRAM_COPYRIGHT_STRING, PROGRAM_VERSION_STRING, pszDbg);
+    TPrintf(_T("usage: %s [ -parameter [value]... ]...\n"), argv0);
+    TPrintf(_T("with parameters:\n"));
 
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_NAME, _T("<string>"), _T("update meta-data: location name")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_ASTRONOMICAL_BODY, _T("<string>"), _T("update meta-data: location astronomical body")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_ADDITIONAL_NOTES, _T("<string>"), _T("update meta-data: location notes")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_ROLE, _T("<integer 0..255>"), _T("update meta-data: location role")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_LONGITUDE, _T("<decimal number>"), _T("update meta-data: location longitude")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_LATITUDE, _T("<decimal number>"), _T("update meta-data: location latitude")));
-    cdp.Add(new CommandDesc(OPTION_STRING_LOCATION_ALTITUDE, _T("<decimal number>"), _T("update meta-data: location altitude")));
+    ParameterDescPrinter pdp;
 
-    cdp.Add(new CommandDesc(OPTION_STRING_HELP, 0, _T("display help text")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_INPUTFILE, _T("<string>"), _T("input file")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_OUTPUTFILE, _T("<string>"), _T("output file")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_OVERWRITEFILE, 0, _T("overwrite output file if it exists")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_CLEARMETADATA, 0, _T("clear all extracted metadata before injection")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_METASTYLE, _T("<3GPP | iTunes>"), _T("flavor of injected metadata, default=all")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_UTF16OUTPUT, 0, _T("inject metadata strings in UTF16 format")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_PRINTMETADATA, 0, _T("print updated metadata")));
+    pdp.Add(new ParameterDesc());
+    pdp.Add(new ParameterDesc(PARAM_STRING_TITLE, _T("<string>"), _T("update title")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_ARTIST, _T("<string>"), _T("update 3GPP performer, iTunes artist")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_ALBUM, _T("<string>"), _T("update album")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_GENRE, _T("<string>"), _T("update genre")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_COMPOSER, _T("<string>"), _T("update 3GPP author, iTunes composer")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_COMMENT, _T("<string>"), _T("update 3GPP description, iTunes comment")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_COPYRIGHT, _T("<string>"), _T("update copyright")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_TRACKNUMBER, _T("<integer 0..255>"), _T("update track number")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_YEAR, _T("<integer 0..65536>"), _T("update 3GPP recording year, iTunes release date")));
+    pdp.Add(new ParameterDesc());
+    pdp.Add(new ParameterDesc(PARAM_STRING_SOFTWARE, _T("<string>"), _T("update iTunes generator tool")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_ENCODEDBY, _T("<string>"), _T("update iTunes encoded by")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_GROUPING, _T("<string>"), _T("update iTunes grouping")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_ALBUMARTIST, _T("<string>"), _T("update iTunes album artist")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LYRICS, _T("<string>"), _T("update iTunes lyrics")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_SUBTITLE, _T("<string>"), _T("update iTunes track subtitle")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_BPM, _T("<integer>"), _T("update iTunes beats per minute")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_PARTOFCOMP, _T("<0 | 1>"), _T("update iTunes part of compilation")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_EXPLICIT, _T("<0 | 1>"), _T("update iTunes content rating")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_TRACKSTOTAL, _T("<integer>"), _T("update iTunes track count")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_DISKNUMBER, _T("<integer>"), _T("update iTunes disc number")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_DISKSTOTAL, _T("<integer>"), _T("update iTunes disc count")));
+    pdp.Add(new ParameterDesc());
+    pdp.Add(new ParameterDesc(PARAM_STRING_RATING_ENTITY, _T("<4 character code>"), _T("update 3GPP rating entity")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_RATING_CRITERIA, _T("<4 character code>"), _T("update 3GPP rating criteria")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_RATING_INFO, _T("<string>"), _T("update 3GPP rating info")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_CLASSIFICATION_ENTITY, _T("<4 character code>"), _T("update 3GPP classification entity")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_CLASSIFICATION_TABLE, _T("<integer 0..65535>"), _T("update 3GPP classification table")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_CLASSIFICATION_INFO, _T("<string>"), _T("update 3GPP classification info")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_KEYWORD_ADD, _T("<string>"), _T("update 3GPP add keyword")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_KEYWORD_REMOVE, _T("<string>"), _T("update 3GPP remove keyword")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_KEYWORD_CLEAR, 0, _T("update 3GPP clear all keywords")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_NAME, _T("<string>"), _T("update 3GPP location name")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_ASTRONOMICAL_BODY, _T("<string>"), _T("update 3GPP location astronomical body")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_ADDITIONAL_NOTES, _T("<string>"), _T("update 3GPP location notes")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_ROLE, _T("<integer 0..255>"), _T("update 3GPP location role")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_LONGITUDE, _T("<decimal number>"), _T("update 3GPP location longitude")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_LATITUDE, _T("<decimal number>"), _T("update 3GPP location latitude")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LOCATION_ALTITUDE, _T("<decimal number>"), _T("update 3GPP location altitude")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_LANGUAGE_CODE, _T("<3 character code>"), _T("ISO639.2/T language code of 3GPP metadata text")));
+    pdp.Add(new ParameterDesc());
+    pdp.Add(new ParameterDesc(PARAM_STRING_SYNCMODE, 0, _T("dtdriver sync mode (developer option)")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_DEFMETAPROC, 0, _T("default meta processor (developer option)")));
+    pdp.Add(new ParameterDesc(PARAM_STRING_HELP, 0, _T("display help text")));
 
-    cdp.PrintColumns(3);
+    pdp.PrintColumns(2);
 }
 
 
 /****************************************************************************
-*  Option extractors
+*  Param extractors
 */
-const TCHAR* NextArg(HX_RESULT& retVal, int& argIndex, int argc, TCHAR* argv[], const TCHAR* optionName = 0)
+const TCHAR* NextArg(HX_RESULT& retVal, int& argIndex, int argc, TCHAR* argv[], const TCHAR* paramName)
 {
     if(FAILED(retVal))
     {
         return 0;
     }
+
     argIndex++;
     if(argIndex < argc)
     {
         retVal = HXR_OK;
         return argv[argIndex];
     }
-    if(optionName)
+
+    if(paramName)
     {
-        TPrintf(_T("Missing value for option: -%s\n"), optionName);
+        TPrintf(_T("Missing value for param: -%s\n"), paramName);
     }
+
     retVal = HXR_PARSE_ERROR;
     return 0;
 }
 
-BOOL ExtractStringOption(HX_RESULT& retVal, int& argIndex, int argc, TCHAR* argv[],
-                         MetaInfo3GP& metainfo, MetaInfo3GP::FnStringSetter setter,
-                         const TCHAR* optionName, const TCHAR** ppOutArg = 0)
+void ReportUnsupportedMetaStyleParam(const TCHAR* paramName)
+{
+    TPrintf(_T("Parameter -%s not supported in combination with specified metastyle(s)\n"), paramName);
+}
+
+void ReportInvalidValueForParameter(const TCHAR* paramName, const TCHAR* paramValue)
+{
+    TPrintf(_T("Invalid value for parameter -%s: %s\n"), paramName, paramValue);
+}
+
+HXBOOL ExtractStringParam(HX_RESULT& retVal, bool bSkipArgOnly, int& argIndex, int argc, TCHAR* argv[],
+                        MetaInfo& metainfo, MetaInfo::eStringMetaItem itemName, ULONG32 metaFlavorFlags,
+                        const TCHAR* paramName, const TCHAR** ppOutArg = 0)
 {
     if(FAILED(retVal))
     {
         return FALSE;
     }
-    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, optionName);
+
+    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, paramName);
+    if(bSkipArgOnly)
+    {
+        return SUCCEEDED(retVal) ? TRUE : FALSE;
+    }
+
     if(SUCCEEDED(retVal) && pVal)
     {
         if(ppOutArg)
         {
             *ppOutArg = pVal;
         }
+
+        if(MetaInfo::IsItemSupportedByAnyFlavor(itemName, metaFlavorFlags))
+        {
         ENCODED_STRING_VAR(sVal, pVal);
-        if((metainfo.*setter)(sVal))
+
+            if(MetaInfo::IsItemValueValidForFlavors(itemName, sVal, metaFlavorFlags))
+            {
+                retVal = metainfo.SetStringItem(itemName, sVal);
+                if(SUCCEEDED(retVal))
         {
             return TRUE;
         }
-        TPrintf(_T("Invalid value for option -%s: %s\n"), optionName, pVal);
+            }
+
+            ReportInvalidValueForParameter(paramName, pVal);
         retVal = HXR_PARSE_ERROR;
     }
+        else
+        {
+            ReportUnsupportedMetaStyleParam(paramName);
+            retVal = HXR_PARSE_ERROR;
+        }
+    }
     return FALSE;
 }
 
-BOOL ExtractKeywordStringOption(HX_RESULT& retVal, int& argIndex, int argc, TCHAR* argv[],
-                                CHXPtrArray& aKeywords,
-                                const TCHAR* optionName, const TCHAR** ppOutArg = 0)
+HXBOOL ExtractULONG32Param(HX_RESULT& retVal, bool bSkipArgOnly, int& argIndex, int argc, TCHAR* argv[],
+                         MetaInfo& metainfo, MetaInfo::eUlongMetaItem itemName, ULONG32 metaFlavorFlags,
+                         const TCHAR* paramName, const TCHAR** ppOutArg = 0)
 {
     if(FAILED(retVal))
     {
         return FALSE;
     }
-    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, optionName);
+
+    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, paramName);
+    if(bSkipArgOnly)
+    {
+        return SUCCEEDED(retVal) ? TRUE : FALSE;
+    }
+
     if(SUCCEEDED(retVal) && pVal)
     {
         if(ppOutArg)
         {
             *ppOutArg = pVal;
         }
-        EncodedString* s = new ENCODED_STRING_CTOR(pVal);
-        if(s->GetByteLength(TRUE) > 255)
+
+        if(MetaInfo::IsItemSupportedByAnyFlavor(itemName, metaFlavorFlags))
         {
-            TPrintf(_T("Invalid value for option -%s: %s\n"), optionName, pVal);
-            delete s;
-            retVal = HXR_PARSE_ERROR;
-        }
-        else
+            ENCODED_STRING_VAR(sVal, pVal);
+
+            UINT32 uVal = 0;
+            if(PropTools::ExtractUInt32(uVal, sVal))
+            {
+                if(MetaInfo::IsItemValueValidForFlavors(itemName, uVal, metaFlavorFlags))
+                {
+                    retVal = metainfo.SetUlongItem(itemName, uVal, TRUE);
+                    if(SUCCEEDED(retVal))
         {
-            aKeywords.Add(s);
             return TRUE;
         }
     }
-    return FALSE;
 }
 
-void ClearPropertyStringArray(CHXPtrArray& a)
-{
-    for(INT32 i = 0; i < a.GetSize(); i++)
+            ReportInvalidValueForParameter(paramName, pVal);
+            retVal = HXR_PARSE_ERROR;
+        }
+        else
     {
-        delete (EncodedString*)a[i];
+            ReportUnsupportedMetaStyleParam(paramName);
+            retVal = HXR_PARSE_ERROR;
     }
-    a.RemoveAll();
+    }
+    return FALSE;
 }
 
-BOOL ExtractUINT16Option(HX_RESULT& retVal, int& argIndex, int argc, TCHAR* argv[],
-                         MetaInfo3GP& metainfo, MetaInfo3GP::FnUINT16Setter setter,
-                         const TCHAR* optionName, const TCHAR** ppOutArg = 0)
+HXBOOL ExtractKeywordStringParam(HX_RESULT& retVal, bool bSkipArgOnly, int& argIndex, int argc, TCHAR* argv[],
+                                CHXPtrArray& aKeywords, ULONG32 metaFlavorFlags,
+                                const TCHAR* paramName, const TCHAR** ppOutArg = 0)
 {
     if(FAILED(retVal))
     {
         return FALSE;
     }
-    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, optionName);
+
+    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, paramName);
+    if(bSkipArgOnly)
+    {
+        return SUCCEEDED(retVal) ? TRUE : FALSE;
+    }
+
     if(SUCCEEDED(retVal) && pVal)
     {
         if(ppOutArg)
         {
             *ppOutArg = pVal;
         }
-        ENCODED_STRING_VAR(sVal, pVal);
-        UINT16 uVal = 0;
-        if(PropTools::ExtractUInt16(uVal, sVal))
+
+        if(MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::StringMetaItem_Keywords, metaFlavorFlags))
         {
-            if((metainfo.*setter)(uVal, TRUE)) return TRUE;
+            EncodedString* pEncStr = new ENCODED_STRING_CTOR(pVal);
+
+            if(pEncStr && MetaInfo::IsItemValueValidForFlavors(MetaInfo::StringMetaItem_Keywords, *pEncStr, metaFlavorFlags))
+            {
+                aKeywords.Add(pEncStr);
+                return TRUE;
         }
-        TPrintf(_T("Invalid value for option -%s: %s\n"), optionName, pVal);
+            else
+            {
+                ReportInvalidValueForParameter(paramName, pVal);
         retVal = HXR_PARSE_ERROR;
+                delete pEncStr;
     }
-    return FALSE;
 }
-
-BOOL ExtractUINT8Option(HX_RESULT& retVal, int& argIndex, int argc, TCHAR* argv[],
-                        MetaInfo3GP& metainfo, MetaInfo3GP::FnUINT8Setter setter,
-                        const TCHAR* optionName, const TCHAR** ppOutArg = 0)
-{
-    if(FAILED(retVal))
+        else
     {
+            ReportUnsupportedMetaStyleParam(paramName);
+            retVal = HXR_PARSE_ERROR;
+        }
+    }
         return FALSE;
     }
-    const TCHAR* pVal = NextArg(retVal, argIndex, argc, argv, optionName);
-    if(SUCCEEDED(retVal) && pVal)
-    {
-        if(ppOutArg)
+
+void ClearPropertyStringArray(CHXPtrArray& a)
         {
-            *ppOutArg = pVal;
-        }
-        ENCODED_STRING_VAR(sVal, pVal);
-        UINT8 uVal = 0;
-        if(PropTools::ExtractUInt8(uVal, sVal))
+    for(INT32 i = 0; i < a.GetSize(); i++)
         {
-            if((metainfo.*setter)(uVal, TRUE)) return TRUE;
-        }
-        TPrintf(_T("Invalid value for option -%s: %s\n"), optionName, pVal);
-        retVal = HXR_PARSE_ERROR;
+        delete (EncodedString*)a[i];
     }
-    return FALSE;
+    a.RemoveAll();
 }
 
 
 /****************************************************************************
 *  Asynchronous mode helpers
 */
 void SignalAsyncDriveEnd()
 {
 #ifdef _WINDOWS
     ::PostMessage(0, (WM_USER + 202), 0, 0);
 #else
     printf("ERROR: SignalAsyncDriveEnd not implemented.\n");
 #endif
 }
 
 void WaitAsyncDriveEnd()
 {
 #ifdef _WINDOWS
     MSG msg;
     while(GetMessage(&msg, 0, 0, 0))
     {
         if(msg.message == (WM_USER + 202))
         {
             break;
         }
         DispatchMessage(&msg);
     }
 #else
     printf("ERROR: WaitAsyncDriveEnd not implemented.\n");
 #endif
@@ -580,241 +631,273 @@
             AddRef();
             *ppvObj = (IUnknown*)(IHXMetaDataEditorResponse*)this;
             return HXR_OK;
         }
         if(IsEqualIID(riid, IID_IHXMetaDataEditorResponse))
         {
             AddRef();
             *ppvObj = (IHXMetaDataEditorResponse*)this;
             return HXR_OK;
         }
         *ppvObj = 0;
         return HXR_NOINTERFACE;
     }
     STDMETHOD_(ULONG32, AddRef)()
     {
         return InterlockedIncrement(&m_lRefCount);
     }
     STDMETHOD_(ULONG32, Release)()
     { 
         if(InterlockedDecrement(&m_lRefCount) > 0)
         {
             return m_lRefCount;
         }
         delete this;
         return 0;
     }
     STDMETHOD(InitMetaDataEditorResponse)(IUnknown* pContext, IHXValues* pOptions)
     {
         return HXR_OK;
     }
-    STDMETHOD(OnProgress)(UINT32 progress)
+    STDMETHOD(OnProgress)(ULONG32 progress)
     {
         return HXR_OK;
     }
-    STDMETHOD(OnTerminate)(HX_RESULT result, BOOL bWritingFile)
+    STDMETHOD(OnTerminate)(HX_RESULT result, HXBOOL bWritingFile)
     {
         m_TerminationStatus = result;
-        if(!g_bSynchronousMode)
+        if(!g_bUseDTDriverSynchronousMode)
         {
             SignalAsyncDriveEnd();
         }
         return HXR_OK;
     }
     HX_RESULT GetTerminationStatus()
     {
         return m_TerminationStatus;
     }
 
 private:
     LONG32 m_lRefCount;
     HX_RESULT m_TerminationStatus;
 };
 
 
 /****************************************************************************
+*  MetaProcessorVars
+*/
+struct MetaProcessorVars
+{
+    MetaProcessorVars()
+        : ClearMetaData(FALSE)
+        , ClearKeywords(FALSE)
+        , InjectedMetaFlavors(0)
+    {
+    }
+
+    ~MetaProcessorVars()
+    {
+        ClearPropertyStringArray(AddedKeywords);
+        ClearPropertyStringArray(RemovedKeywords);
+    }
+
+    HX_RESULT CopyAddedKeywordsToInjected()
+    {
+        for(INT32 i = 0; i < AddedKeywords.GetSize(); i++)
+        {
+            if(!InjectedMetaInfo.AddKeyword(*((EncodedString*)AddedKeywords[i])))
+            {
+                return HXR_FAILED;
+            }
+        }
+        return HXR_OK;
+    }
+
+    // meta-data input params
+    HXBOOL ClearMetaData;
+    HXBOOL ClearKeywords;
+    ULONG32 InjectedMetaFlavors;
+    MetaInfo InjectedMetaInfo;
+    CHXPtrArray AddedKeywords;
+    CHXPtrArray RemovedKeywords;
+
+    // meta-data output storage
+    MetaInfo ExtractedMetaInfo;
+    MetaInfo OutboundMetaInfo;
+};
+
+
+/****************************************************************************
 *  Meta-data processor
 */
 class CProcessor : public IHXMetaDataProcessor
 {
 public:
-    CProcessor()
+    CProcessor(MetaProcessorVars& vars)
         : m_lRefCount(0)
-        , m_bClearMetaData(FALSE)
-        , m_bClearKeywords(FALSE)
+        , m_vars(vars)
     {
     }
-    virtual ~CProcessor()
-    {
-        ClearPropertyStringArray(m_aAddedKeywords);
-        ClearPropertyStringArray(m_aRemovedKeywords);
-    }
     STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj)
     {
         if(IsEqualIID(riid, IID_IUnknown))
         {
             AddRef();
             *ppvObj = (IUnknown*)(IHXMetaDataProcessor*)this;
             return HXR_OK;
         }
         if(IsEqualIID(riid, IID_IHXMetaDataProcessor))
         {
             AddRef();
             *ppvObj = (IHXMetaDataProcessor*)this;
             return HXR_OK;
         }
         *ppvObj = 0;
         return HXR_NOINTERFACE;
     }
     STDMETHOD_(ULONG32, AddRef)()
     {
         return InterlockedIncrement(&m_lRefCount);
     }
     STDMETHOD_(ULONG32, Release)()
     { 
         if(InterlockedDecrement(&m_lRefCount) > 0)
         {
             return m_lRefCount;
         }
         delete this;
         return 0;
     }
     STDMETHOD(InitMetaDataProcessor)(IUnknown* pContext, IHXValues* pOptions)
     {
         return HXR_OK;
     }
     STDMETHOD(OnInboundMetaData)(IHXValues* pExtracted, IHXValues* pInjectSink)
     {
         // keep extracted
-        m_miExtracted.Clear();
-        m_miExtracted.CopyFromValues(pExtracted);
+        m_vars.ExtractedMetaInfo.Clear();
+        m_vars.ExtractedMetaInfo.CopyFromValues(pExtracted, FALSE, METAINFO_SET_ALL);
 
-        // modify meta-data
-        MetaInfo3GP mi;
-        if(!m_bClearMetaData)
+        // find out which sets of metadata should be passed through
+        MetaInfo mi;
+        ULONG32 injectedMetaInfoSets = MetaInfo::GetSetsFromFlavors(m_vars.InjectedMetaFlavors);
+
+        // check if the extracted metadata should be blocked or passed through
+        if(!m_vars.ClearMetaData)
         {
-            mi.Update(m_miExtracted);
+            mi.UpdateItems(m_vars.ExtractedMetaInfo, injectedMetaInfoSets);
         }
-        if(m_bClearKeywords)
+
+        // clear existing keywords if specified
+        if(m_vars.ClearKeywords)
         {
             mi.ClearKeywords();
         }
-        mi.Update(m_miInjected);
     
-        for(INT32 iAdd = 0; iAdd < m_aAddedKeywords.GetSize(); iAdd++)
+        // inject new items / update extracted items
+        mi.UpdateItems(m_vars.InjectedMetaInfo, injectedMetaInfoSets);
+
+        // inject specified keywords
+        for(INT32 iAdd = 0; iAdd < m_vars.AddedKeywords.GetSize(); iAdd++)
         {
-            mi.AddKeyword(*((EncodedString*)m_aAddedKeywords[iAdd]));
+            mi.AddKeyword(*((EncodedString*)m_vars.AddedKeywords[iAdd]));
         }
-        for(INT32 iRem = 0; iRem < m_aRemovedKeywords.GetSize(); iRem++)
+
+        // remove specified keywords
+        for(INT32 iRem = 0; iRem < m_vars.RemovedKeywords.GetSize(); iRem++)
         {
-            mi.RemoveKeyword(*((EncodedString*)m_aRemovedKeywords[iRem]));
+            mi.RemoveKeyword(*((EncodedString*)m_vars.RemovedKeywords[iRem]));
         }
 
-        // transfer to inject sink
-        mi.CopyToValues(pInjectSink);
+        // transfer final item set to the inject sink
+        mi.CopyToValues(pInjectSink, FALSE, METAINFO_SET_ALL);
 
         return HXR_OK;
     }
     STDMETHOD(OnOutboundMetaData)(IHXValues* pValues)
     {
         // keep outbound
-        m_miOutbound.Clear();
-        m_miOutbound.CopyFromValues(pValues);
-        return HXR_OK;
-    }
-
-    HX_RESULT CopyAddedKeywordsToInjected()
-    {
-        for(INT32 i = 0; i < m_aAddedKeywords.GetSize(); i++)
-        {
-            if(!m_miInjected.AddKeyword(*((EncodedString*)m_aAddedKeywords[i])))
-            {
-                return HXR_FAILED;
-            }
-        }
+        m_vars.OutboundMetaInfo.Clear();
+        m_vars.OutboundMetaInfo.CopyFromValues(pValues, FALSE, METAINFO_SET_ALL);
         return HXR_OK;
     }
 
-public:
-    // meta-data input params
-    MetaInfo3GP m_miInjected;
-    BOOL m_bClearMetaData;
-    BOOL m_bClearKeywords;
-    CHXPtrArray m_aAddedKeywords;
-    CHXPtrArray m_aRemovedKeywords;
-
-    // meta-data output params
-    MetaInfo3GP m_miExtracted;
-    MetaInfo3GP m_miOutbound;
-
 private:
     LONG32 m_lRefCount;
+    MetaProcessorVars& m_vars;
 };
 
 
 /****************************************************************************
 *  Main entry point
 */
 int TMAIN(int argc, TCHAR* argv[])
 {
     // separate shell command from output
     TPrintf(_T("\n"));
 
     // initialize variables
+    HXBOOL testDefaultMetaEditorProcessor = FALSE;
+    HXBOOL useDTDriverSynchronousMode = FALSE;
+
     CHXFileSpecifier exeFileSpec;
-    UINT32 startTime = 0;
+    ULONG32 startTime = 0;
     
     DLLAccess* pDLLAccess = 0;
     FPHXMEDIAPLATFORMOPEN fpHXMediaPlatformOpen = 0;
     FPHXCREATEMEDIAPLATFORM fpHXCreateMediaPlatform = 0;
     FPHXMEDIAPLATFORMCLOSE fpHXMediaPlatformClose = 0;
 
     IHXMediaPlatform* pMediaPlatform = 0;
     IHXCommonClassFactory* pCommonClassFactory = 0;
     IHXMetaDataEditor* pEditor = 0;
     CResponse* pResponse = 0;
     CProcessor* pProcessor = 0;
     IHXValues* pOptions = 0;
 
     char pDllPath[_MAX_PATH] = {0};
     char pDllFile[_MAX_PATH] = {0};
     const char* pszHelixLibs = 0;
 
     const TCHAR* ptInputFileName = 0;
     char* pInputFileName = 0;
     const TCHAR* ptOutputFileName = 0;
     char* pOutputFileName = 0;
+    const TCHAR* ptMetaStyleName = 0;
+    char* pMetaStyleName = 0;
 
-    BOOL bOverwriteFile = FALSE;
-    BOOL bDisplayHelp = FALSE;
-    BOOL bPrintMetaData = FALSE;
-    BOOL bUTF16Output = FALSE;
+    HXBOOL bDisplayHelp = FALSE;
+    HXBOOL bOverwriteFile = FALSE;
+    HXBOOL bPrintMetaData = FALSE;
+    HXBOOL bUTF16Output = FALSE;
+
+    MetaProcessorVars metaProcessorVars;
 
     // initialize Helix DNA client media-platform
     HX_RESULT retVal = HXR_OK;
 
     // load Helix media-platform library
     pDLLAccess = new DLLAccess();
     if(!pDLLAccess)
     {
         retVal = HXR_OUTOFMEMORY;
         goto cleanup;
     }
 
     // extract plugin directory
 #ifdef _WINDOWS
     exeFileSpec = CHXFileSpecUtils::GetCurrentApplication();
     strncpy(pDllPath, (const char*)exeFileSpec.GetParentDirectory().GetPathName(), _MAX_PATH);
     snprintf(pDllFile, _MAX_PATH, "%s\\%s", pDllPath, "hxmedpltfm.dll");
 
 #else
     pszHelixLibs = getenv("HELIX_LIBS");
     if(pszHelixLibs)
     {
         strncpy(pDllPath, pszHelixLibs, _MAX_PATH);
         snprintf(pDllFile, _MAX_PATH, "%s/%s", pDllPath, "hxmedpltfm.so");
     }
     else
     {
         printf("Missing HELIX_LIBS environment variable\n");
         goto cleanup;
     }
@@ -811,477 +894,739 @@
     if(pszHelixLibs)
     {
         strncpy(pDllPath, pszHelixLibs, _MAX_PATH);
         snprintf(pDllFile, _MAX_PATH, "%s/%s", pDllPath, "hxmedpltfm.so");
     }
     else
     {
         printf("Missing HELIX_LIBS environment variable\n");
         goto cleanup;
     }
 #endif
 
     pDllPath[_MAX_PATH - 1] = '\0';
     pDllFile[_MAX_PATH - 1] = '\0';
     
     if(pDLLAccess->open(pDllFile) != DLLAccess::DLL_OK)
     {
         printf("Failed to access Helix DNA client media-platform library file: %s\n", pDllFile);
         goto cleanup;
     }
 
     // initialize Helix media-platform
     fpHXMediaPlatformOpen = (FPHXMEDIAPLATFORMOPEN) pDLLAccess->getSymbol("HXMediaPlatformOpen");
     fpHXCreateMediaPlatform = (FPHXCREATEMEDIAPLATFORM) pDLLAccess->getSymbol("HXCreateMediaPlatform");
     fpHXMediaPlatformClose = (FPHXMEDIAPLATFORMCLOSE) pDLLAccess->getSymbol("HXMediaPlatformClose");
 
     if(!fpHXMediaPlatformOpen || !fpHXCreateMediaPlatform || !fpHXMediaPlatformClose)
     {
         retVal = HXR_FAILED;
     }
+
     if(SUCCEEDED(retVal))
     {
         retVal = fpHXMediaPlatformOpen();
     }
+
     if(SUCCEEDED(retVal))
     {
         retVal = fpHXCreateMediaPlatform((IHXMediaPlatform**)&pMediaPlatform);
     }
+
     if(SUCCEEDED(retVal))
     {
         retVal = pMediaPlatform->AddPluginPath("Meta3GP", pDllPath);
     }
+
     if(SUCCEEDED(retVal))
     {
         retVal = pMediaPlatform->Init(0);
     }
+
     if(SUCCEEDED(retVal))
     {
        retVal = pMediaPlatform->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCommonClassFactory);
     }
+
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix DNA client media-platform.\n");
         goto cleanup;
     }
 
     // initialize meta-data editor response object
     pResponse = new CResponse();
     HX_ADDREF(pResponse);
     if(!pResponse)
     {
         retVal = HXR_OUTOFMEMORY;
     }
+
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix meta-data editor response object.\n");
         goto cleanup;
     }
 
     // initialize meta-data processor object
-    pProcessor = new CProcessor();
+    pProcessor = new CProcessor(metaProcessorVars);
     HX_ADDREF(pProcessor);
     if(!pProcessor)
     {
         retVal = HXR_OUTOFMEMORY;
     }
+
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix meta-data processor object.\n");
         goto cleanup;
     }
 
     // initialize meta-data editor plugin
     retVal = CreateInstanceCCF_QI(CLSID_IHXMetaDataEditor, IID_IHXMetaDataEditor,
                                         (void**)&pEditor, pCommonClassFactory);
     if(SUCCEEDED(retVal))
     {
         retVal = pEditor->InitMetaDataEditor(pCommonClassFactory);
     }
+
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix meta-data editor plugin.\n");
         goto cleanup;
     }
 
-    // process commands
+    // The first phase seeks for independent arguments, the second phase seeks for dependent arguments.
+    enum eCommandLineProcessorPhase
+    {
+        CommandLineProcessorPhase_IndependentArgs = 0,
+        CommandLineProcessorPhase_DependentArgs,
+        CommandLineProcessorPhase_Done
+    };
+    eCommandLineProcessorPhase clProcessorPhase = CommandLineProcessorPhase_IndependentArgs;
+
+    while(SUCCEEDED(retVal) && (clProcessorPhase != CommandLineProcessorPhase_Done))
+    {
     for(int argIndex = 1; (argIndex < argc) && SUCCEEDED(retVal); argIndex++)
     {
-        // accept option format only
+            // accept parameter format only
         if(*argv[argIndex] != _T('-'))
         {
-            TPrintf(_T("Found non option command-line argument: %s\n"), argv[argIndex]);
+                TPrintf(_T("Found non-parameter command-line argument: %s\n"), argv[argIndex]);
             retVal = HXR_PARSE_ERROR;
             continue;
         }
-        TCHAR* pOption = argv[argIndex] + 1;
+            TCHAR* pParam = argv[argIndex] + 1;
 
-        if(TStringEqual(pOption, OPTION_STRING_INPUTFILE))
+            if(TStringEqual(pParam, PARAM_STRING_HELP))
         {
-            ptInputFileName = NextArg(retVal, argIndex, argc, argv);
+                bDisplayHelp = TRUE;
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_SYNCMODE))
+            {
+                g_bUseDTDriverSynchronousMode = TRUE;
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_DEFMETAPROC))
+            {
+                g_bUseDefaultMetaEditorProcessor = TRUE;
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_INPUTFILE))
+            {
+                if(clProcessorPhase == CommandLineProcessorPhase_IndependentArgs)
+                {
+                    ptInputFileName = NextArg(retVal, argIndex, argc, argv, PARAM_STRING_INPUTFILE);
             pInputFileName = TConvertToCCPString(ptInputFileName);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_OUTPUTFILE))
+                else
         {
-            ptOutputFileName = NextArg(retVal, argIndex, argc, argv);
+                    // already processed, just the argument
+                    argIndex++;
+                }
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_OUTPUTFILE))
+            {
+                if(clProcessorPhase == CommandLineProcessorPhase_IndependentArgs)
+                {
+                    ptOutputFileName = NextArg(retVal, argIndex, argc, argv, PARAM_STRING_OUTPUTFILE);
             pOutputFileName = TConvertToCCPString(ptOutputFileName);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_OVERWRITEFILE))
+                else
+                {
+                    // already processed, just the argument
+                    argIndex++;
+                }
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_OVERWRITEFILE))
         {
             bOverwriteFile = TRUE;
         }
-        else if(TStringEqual(pOption, OPTION_STRING_CLEARMETADATA))
+            else if(TStringEqual(pParam, PARAM_STRING_CLEARMETADATA))
         {
-            pProcessor->m_bClearMetaData = TRUE;
+                metaProcessorVars.ClearMetaData = TRUE;
         }
-        else if(TStringEqual(pOption, OPTION_STRING_PRINTMETADATA))
+            else if(TStringEqual(pParam, PARAM_STRING_PRINTMETADATA))
         {
             bPrintMetaData = TRUE;
         }
-        else if(TStringEqual(pOption, OPTION_STRING_UTF16OUTPUT))
+            else if(TStringEqual(pParam, PARAM_STRING_METASTYLE))
+            {
+                if(clProcessorPhase == CommandLineProcessorPhase_IndependentArgs)
+                {
+                    ptMetaStyleName = NextArg(retVal, argIndex, argc, argv, PARAM_STRING_METASTYLE);
+                    pMetaStyleName = TConvertToCCPString(ptMetaStyleName);
+
+                    if(SUCCEEDED(retVal))
+                    {
+                        if(!strcmpi(pMetaStyleName, "3gpp"))
+                        {
+                            metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_3GPP;
+                        }
+                        else if(!strcmpi(pMetaStyleName, "itunes"))
+                        {
+                            metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
+                        }
+                        else
+                        {
+                            retVal = HXR_PARSE_ERROR;
+                            ReportInvalidValueForParameter(PARAM_STRING_METASTYLE, ptMetaStyleName);
+                        }
+                    }
+                }
+                else
+                {
+                    // already processed, just the argument
+                    argIndex++;
+                }
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_UTF16OUTPUT))
         {
             bUTF16Output = TRUE;
         }
-        else if(TStringEqual(pOption, OPTION_STRING_HELP))
+            else if(TStringEqual(pParam, PARAM_STRING_TITLE))
         {
-            bDisplayHelp = TRUE;
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Title,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_TITLE);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LANGUAGE_CODE))
+            else if(TStringEqual(pParam, PARAM_STRING_ARTIST))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetGlobalLanguageEncoding, OPTION_STRING_LANGUAGE_CODE);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Artist,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_ARTIST);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_TITLE))
+            else if(TStringEqual(pParam, PARAM_STRING_ALBUM))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetTitle, OPTION_STRING_TITLE);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Album,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_ALBUM);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_AUTHOR))
+            else if(TStringEqual(pParam, PARAM_STRING_GENRE))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetAuthor, OPTION_STRING_AUTHOR);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Genre,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_GENRE);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_COPYRIGHT))
+            else if(TStringEqual(pParam, PARAM_STRING_COMPOSER))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetCopyright, OPTION_STRING_COPYRIGHT);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Composer,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_COMPOSER);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_DESCRIPTION))
+            else if(TStringEqual(pParam, PARAM_STRING_COMMENT))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetDescription, OPTION_STRING_DESCRIPTION);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Comment,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_COMMENT);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_PERFORMER))
+            else if(TStringEqual(pParam, PARAM_STRING_COPYRIGHT))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetPerformer, OPTION_STRING_PERFORMER);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Copyright,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_COPYRIGHT);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_GENRE))
+            else if(TStringEqual(pParam, PARAM_STRING_TRACKNUMBER))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetGenre, OPTION_STRING_GENRE);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_TrackNumber,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_TRACKNUMBER);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_RATING_ENTITY))
+            else if(TStringEqual(pParam, PARAM_STRING_YEAR))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetRatingEntity, OPTION_STRING_RATING_ENTITY);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_RecordingYear,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_YEAR);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_RATING_CRITERIA))
+            else if(TStringEqual(pParam, PARAM_STRING_SOFTWARE))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetRatingCriteria, OPTION_STRING_RATING_CRITERIA);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_GeneratorTool,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_SOFTWARE);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_RATING_INFO))
+            else if(TStringEqual(pParam, PARAM_STRING_ENCODEDBY))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetRatingInfo, OPTION_STRING_RATING_INFO);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_EncodedBy,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_ENCODEDBY);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_CLASSIFICATION_ENTITY))
+            else if(TStringEqual(pParam, PARAM_STRING_GROUPING))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetClassificationEntity, OPTION_STRING_CLASSIFICATION_ENTITY);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Grouping,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_GROUPING);
         }
-
-        else if(TStringEqual(pOption, OPTION_STRING_CLASSIFICATION_TABLE))
+            else if(TStringEqual(pParam, PARAM_STRING_ALBUMARTIST))
         {
-            ExtractUINT16Option(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetClassificationTable, OPTION_STRING_CLASSIFICATION_TABLE);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_AlbumArtist,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_ALBUMARTIST);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_CLASSIFICATION_INFO))
+            else if(TStringEqual(pParam, PARAM_STRING_LYRICS))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetClassificationInfo, OPTION_STRING_CLASSIFICATION_INFO);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_Lyrics,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LYRICS);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_KEYWORD_ADD))
+            else if(TStringEqual(pParam, PARAM_STRING_SUBTITLE))
         {
-            ExtractKeywordStringOption(retVal, argIndex, argc, argv,
-                pProcessor->m_aAddedKeywords, OPTION_STRING_KEYWORD_ADD);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_TrackSubtitle,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_SUBTITLE);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_KEYWORD_REMOVE))
+            else if(TStringEqual(pParam, PARAM_STRING_BPM))
         {
-            ExtractKeywordStringOption(retVal, argIndex, argc, argv,
-                pProcessor->m_aRemovedKeywords, OPTION_STRING_KEYWORD_REMOVE);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_BeatsPerMinute,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_BPM);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_KEYWORD_CLEAR))
+            else if(TStringEqual(pParam, PARAM_STRING_PARTOFCOMP))
         {
-            pProcessor->m_bClearKeywords = TRUE;
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_PartOfCompilation,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_PARTOFCOMP);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_NAME))
+            else if(TStringEqual(pParam, PARAM_STRING_EXPLICIT))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationName, OPTION_STRING_LOCATION_NAME);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_ExplicitContent,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_EXPLICIT);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_ASTRONOMICAL_BODY))
+            else if(TStringEqual(pParam, PARAM_STRING_TRACKSTOTAL))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationAstronomicalBody, OPTION_STRING_LOCATION_ASTRONOMICAL_BODY);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_TrackCount,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_TRACKSTOTAL);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_ADDITIONAL_NOTES))
+            else if(TStringEqual(pParam, PARAM_STRING_DISKNUMBER))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationAdditionalNotes, OPTION_STRING_LOCATION_ADDITIONAL_NOTES);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_DiscNumber,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_DISKNUMBER);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_ROLE))
+            else if(TStringEqual(pParam, PARAM_STRING_DISKSTOTAL))
         {
-            ExtractUINT8Option(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationRole, OPTION_STRING_LOCATION_ROLE);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_DiscCount,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_DISKSTOTAL);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_LONGITUDE))
+            else if(TStringEqual(pParam, PARAM_STRING_LANGUAGE_CODE))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationLongitude, OPTION_STRING_LOCATION_LONGITUDE);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_GlobalLanguageEncoding,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LANGUAGE_CODE);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_LATITUDE))
+            else if(TStringEqual(pParam, PARAM_STRING_RATING_ENTITY))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationLatitude, OPTION_STRING_LOCATION_LATITUDE);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_RatingEntity,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_RATING_ENTITY);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_LOCATION_ALTITUDE))
+            else if(TStringEqual(pParam, PARAM_STRING_RATING_CRITERIA))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetLocationAltitude, OPTION_STRING_LOCATION_ALTITUDE);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_RatingCriteria,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_RATING_CRITERIA);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_ALBUM))
+            else if(TStringEqual(pParam, PARAM_STRING_RATING_INFO))
         {
-            ExtractStringOption(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetAlbumTitle, OPTION_STRING_ALBUM);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_RatingInfo,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_RATING_INFO);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_TRACK))
+            else if(TStringEqual(pParam, PARAM_STRING_CLASSIFICATION_ENTITY))
         {
-            ExtractUINT8Option(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetAlbumTrackNumber, OPTION_STRING_TRACK);
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_ClassificationEntity,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_CLASSIFICATION_ENTITY);
         }
-        else if(TStringEqual(pOption, OPTION_STRING_YEAR))
+            else if(TStringEqual(pParam, PARAM_STRING_CLASSIFICATION_TABLE))
         {
-            ExtractUINT16Option(retVal, argIndex, argc, argv, pProcessor->m_miInjected,
-                &MetaInfo3GP::SetRecordingYear, OPTION_STRING_YEAR);
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_ClassificationTable,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_CLASSIFICATION_TABLE);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_CLASSIFICATION_INFO))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_ClassificationInfo,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_CLASSIFICATION_INFO);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_NAME))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_LocationName,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_NAME);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_ASTRONOMICAL_BODY))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_LocationAstronomicalBody,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_ASTRONOMICAL_BODY);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_ADDITIONAL_NOTES))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_LocationAdditionalNotes,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_ADDITIONAL_NOTES);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_ROLE))
+            {
+                ExtractULONG32Param(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::UlongMetaItem_LocationRole,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_ROLE);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_LONGITUDE))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_LocationLongitude,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_LONGITUDE);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_LATITUDE))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_LocationLatitude,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_LATITUDE);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_LOCATION_ALTITUDE))
+            {
+                ExtractStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_LocationAltitude,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_LOCATION_ALTITUDE);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_KEYWORD_ADD))
+            {
+                ExtractKeywordStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.AddedKeywords,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_KEYWORD_ADD);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_KEYWORD_REMOVE))
+            {
+                ExtractKeywordStringParam(retVal, (clProcessorPhase != CommandLineProcessorPhase_DependentArgs),
+                    argIndex, argc, argv, metaProcessorVars.RemovedKeywords,
+                    metaProcessorVars.InjectedMetaFlavors, PARAM_STRING_KEYWORD_REMOVE);
+            }
+            else if(TStringEqual(pParam, PARAM_STRING_KEYWORD_CLEAR))
+            {
+                metaProcessorVars.ClearKeywords = TRUE;
+
+                if((clProcessorPhase == CommandLineProcessorPhase_DependentArgs) &&
+                    !MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::StringMetaItem_Keywords, metaProcessorVars.InjectedMetaFlavors))
+                {
+                    ReportUnsupportedMetaStyleParam(PARAM_STRING_KEYWORD_CLEAR);
+                    retVal = HXR_PARSE_ERROR;
+                }
         }
         else
         {
-            TPrintf(_T("Unrecognized command: -%s\n"), pOption);
+                TPrintf(_T("Unrecognized parameter: -%s\n"), pParam);
             retVal = HXR_PARSE_ERROR;
         }
     }
 
-    // check for semantic errors
-    if(SUCCEEDED(retVal) && !bDisplayHelp)
+        // update metastylese
+        if(clProcessorPhase == CommandLineProcessorPhase_IndependentArgs)
     {
-        if(!pInputFileName)
+            // unless metastyles are explicitly specified, assume defaults according to file extension
+            if((metaProcessorVars.InjectedMetaFlavors == 0) && pOutputFileName)
         {
-            TPrintf(_T("Input file not specified.\n"));
-            retVal = HXR_PARSE_ERROR;
+                CHXString sFileExt = "";
+                CHXString sFileName = pOutputFileName;
+                INT32 dotPos = sFileName.ReverseFind('.');
+
+                if(dotPos >= 0)
+                {
+                    ULONG32 extLen = sFileName.GetLength() - dotPos - 1;
+                    if(extLen > 0)
+                    {
+                        sFileExt = sFileName.Right(extLen);
         }
     }
-    if(retVal == HXR_PARSE_ERROR)
+
+                if(!sFileExt.CompareNoCase("3gp"))
     {
-        bDisplayHelp = TRUE;
+                    metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_3GPP;
+                }
+                else if(!sFileExt.CompareNoCase("m4a"))
+                {
+                    metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
+                }
+            }
+        }
+
+        // next phase
+        clProcessorPhase = (eCommandLineProcessorPhase)(int(clProcessorPhase) + 1);
     }
 
     // display usage
+    if(argc == 1)
+    {
+        // auto help display if started without parameters
+        bDisplayHelp = TRUE;
+    }
+
     if(bDisplayHelp)
     {
         DisplayUsage(argv[0]);
         goto cleanup;
     }
 
+    // check for semantic errors
+    if(SUCCEEDED(retVal) && !bDisplayHelp)
+    {
+        if(!pInputFileName)
+        {
+            TPrintf(_T("Input file not specified.\n"));
+            retVal = HXR_PARSE_ERROR;
+        }
+    }
+
+    // cleanup on command-line errors
+    if(FAILED(retVal))
+    {
+        goto cleanup;
+    }
+
     // input file must exist
     if(SUCCEEDED(retVal) && !CHXFileSpecUtils::FileExists(CHXFileSpecifier(pInputFileName)))
     {
         TPrintf(_T("Input file '%s' not found.\n"), ptInputFileName);
         retVal = HXR_FAIL;
     }
+
     if(SUCCEEDED(retVal) && pOutputFileName)
     {
         // writing to input file is not allowed
         if(SUCCEEDED(retVal) && !strcmp(pInputFileName, pOutputFileName))
         {
             TPrintf(_T("File '%s' cannot be used for both input and output.\n"), ptOutputFileName);
             retVal = HXR_FAIL;
         }
         // output file must not exist or overwrite must be specified
         if(SUCCEEDED(retVal) && CHXFileSpecUtils::FileExists(CHXFileSpecifier(pOutputFileName)) && !bOverwriteFile)
         {
-            TPrintf(_T("Output file '%s' already exists. Use -%s command to force overwrite.\n"),
-            ptOutputFileName, OPTION_STRING_OVERWRITEFILE);
+            TPrintf(_T("Output file '%s' already exists. Use -%s parameter to force overwrite.\n"),
+            ptOutputFileName, PARAM_STRING_OVERWRITEFILE);
             retVal = HXR_FAIL;
         }
     }
+
     if(FAILED(retVal))
     {
         goto cleanup;
     }
 
     // initialize options
     retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues,
                                     (void**)&pOptions, pCommonClassFactory);
     if(SUCCEEDED(retVal))
     {
-        retVal = pOptions->SetPropertyULONG32(SYNCHRONOUS_OPTION_NAME, g_bSynchronousMode ? 1 : 0);
+        retVal = pOptions->SetPropertyULONG32(SYNCHRONOUS_OPTION_NAME, g_bUseDTDriverSynchronousMode ? 1 : 0);
     }
+
     if(SUCCEEDED(retVal))
     {
         retVal = pOptions->SetPropertyULONG32(BLASTFILE_OPTION_NAME, bOverwriteFile ? 1 : 0);
     }
+
     if(SUCCEEDED(retVal))
     {
         retVal = pOptions->SetPropertyULONG32(UTF16OUTPUT_OPTION_NAME, bUTF16Output ? 1 : 0);
     }
+
     if(SUCCEEDED(retVal))
     {
-        // Notify meta-editor that it's dealing with 3GP meta-data.
-        retVal = pOptions->SetPropertyULONG32(METADATAFLAVOR_OPTION_NAME, ULONG32(METADATA_FLAVOR_3GP));
+        // Notify meta-editor about the flavor of meta-data it should process.
+        retVal = pOptions->SetPropertyULONG32(METADATAFLAVOR_OPTION_NAME, metaProcessorVars.InjectedMetaFlavors);
     }
+
     if(SUCCEEDED(retVal))
     {
-#ifdef TEST_DEFAULT_META_EDITOR_PROCESSOR
-        retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME,
-                                        pProcessor->m_bClearMetaData ? 1 : 0);
-#else
+        if(g_bUseDefaultMetaEditorProcessor)
+        {
+            retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME, metaProcessorVars.ClearMetaData ? 1 : 0);
+        }
+        else
+        {
         // Notify meta-editor that we do not want it to perform any default internal meta-data merging.
         // Custom processor in this application performs special merging of extracted and injected meta-data.
         retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME, 1);
-#endif
     }
+    }
+
     if(FAILED(retVal))
     {
         printf("Failed to initialize options.\n");
         goto cleanup;
     }
 
+    // display operation info
+    {
+        CHXString sStyles = MetaInfo::GetFlavorNames(metaProcessorVars.InjectedMetaFlavors);
+        if(pOutputFileName)
+        {
+            printf("Injecting %s style metadata: [%s] => [%s].\n\n",
+                    sStyles.IsEmpty() ? "unspecified" : (const char*)sStyles,
+                    pInputFileName, pOutputFileName);
+        }
+        else
+        {
+            printf("Extracting metadata from [%s].\n\n", pInputFileName);
+        }
+    }
+
     // start file processing
     startTime = HX_GET_BETTERTICKCOUNT();
 
-#ifdef TEST_DEFAULT_META_EDITOR_PROCESSOR
-    printf("WARNING: Testing default meta-data processor.\n"
-           "The following commands will not work: kwrem, kwclr.\n\n");
+    if(g_bUseDefaultMetaEditorProcessor)
+    {
+        TPrintf(_T("WARNING: Using default meta-data processor.\n")
+                _T("Some features will not work correctly: %s, %s.\n\n"),
+                PARAM_STRING_KEYWORD_REMOVE, PARAM_STRING_KEYWORD_CLEAR);
 
     // read meta-info by using meta-editor's default meta-data processor
     IHXValues* pExtractedMetaData = 0;
     if(SUCCEEDED(retVal))
     {
         retVal = pEditor->Read(pInputFileName, pExtractedMetaData,
                                    pOptions, (IHXMetaDataEditorResponse*)pResponse);
     }
-    if(SUCCEEDED(retVal) && !g_bSynchronousMode)
+
+        if(SUCCEEDED(retVal) && !g_bUseDTDriverSynchronousMode)
     {
         WaitAsyncDriveEnd();
         retVal = pResponse->GetTerminationStatus();
     }
+
     if(SUCCEEDED(retVal))
     {
-        pProcessor->m_miExtracted.Clear();
-        pProcessor->m_miExtracted.CopyFromValues(pExtractedMetaData);
+            metaProcessorVars.ExtractedMetaInfo.Clear();
+            metaProcessorVars.ExtractedMetaInfo.CopyFromValues(pExtractedMetaData, FALSE, METAINFO_SET_ALL);
     }
+
     HX_RELEASE(pExtractedMetaData);
 
     // write meta-info by using meta-editor's default meta-data processor
     if(SUCCEEDED(retVal) && pOutputFileName)
     {
         IHXValues* pInjectedMetaData = 0;
         retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues,
                                     (void**)&pInjectedMetaData, pCommonClassFactory);
         if(SUCCEEDED(retVal))
         {
-            retVal = pProcessor->CopyAddedKeywordsToInjected();
+                retVal = metaProcessorVars.CopyAddedKeywordsToInjected();
         }
+
         if(SUCCEEDED(retVal))
         {
-            pProcessor->m_miInjected.CopyToValues(pInjectedMetaData);
+                metaProcessorVars.InjectedMetaInfo.CopyToValues(pInjectedMetaData, FALSE, METAINFO_SET_ALL);
 
             retVal = pEditor->Write(pInputFileName, pOutputFileName, pInjectedMetaData,
                                     pOptions, (IHXMetaDataEditorResponse*)pResponse);
         }
+
         HX_RELEASE(pInjectedMetaData);
 
-        if(SUCCEEDED(retVal) && !g_bSynchronousMode)
+            if(SUCCEEDED(retVal) && !g_bUseDTDriverSynchronousMode)
         {
             WaitAsyncDriveEnd();
             retVal = pResponse->GetTerminationStatus();
         }
     }
-#else //TEST_DEFAULT_META_EDITOR_PROCESSOR
-
+    }
+    else
+    {
     // drive meta-info through meta-editor by using custom meta-data processor
     if(SUCCEEDED(retVal))
     {
         retVal = pEditor->Drive(pInputFileName,
                                 pOutputFileName,
                                 (IHXMetaDataProcessor*)pProcessor,
                                 pOptions,
                                 (IHXMetaDataEditorResponse*)pResponse);
 
-        if(SUCCEEDED(retVal) && !g_bSynchronousMode)
+            if(SUCCEEDED(retVal) && !g_bUseDTDriverSynchronousMode)
         {
             WaitAsyncDriveEnd();
             retVal = pResponse->GetTerminationStatus();
         }
     }
-#endif //TEST_DEFAULT_META_EDITOR_PROCESSOR
+    }
 
     if(FAILED(retVal))
     {
         TPrintf(_T("Failed to process input file '%s'.\n"), ptInputFileName);
     }
+
+    // auto dump meta-data if extracting only
+    if(!pOutputFileName)
+    {
+        bPrintMetaData = TRUE;
+    }
+
     if(SUCCEEDED(retVal) && bPrintMetaData)
     {
         TPrintf(_T("--- Extracted meta-data ---\n"));
-        pProcessor->m_miExtracted.Dump();
+        metaProcessorVars.ExtractedMetaInfo.Dump();
         TPrintf(_T("\n"));
 
-#ifndef TEST_DEFAULT_META_EDITOR_PROCESSOR
+        if(!g_bUseDefaultMetaEditorProcessor)
+        {
         if(pOutputFileName)
         {
             TPrintf(_T("--- Injected meta-data ---\n"));
-            pProcessor->m_miOutbound.Dump();
+                metaProcessorVars.OutboundMetaInfo.Dump();
             TPrintf(_T("\n"));
         }
-#endif //!TEST_DEFAULT_META_EDITOR_PROCESSOR
     }
+    }
+
     if(SUCCEEDED(retVal))
     {
-        UINT32 endTime = HX_GET_BETTERTICKCOUNT();
+        ULONG32 endTime = HX_GET_BETTERTICKCOUNT();
         TPrintf(_T("Done. Processing time: %f seconds.\n"), (endTime - startTime) / 1000.0);
     }
 
     // cleanup objects
 cleanup:
     HX_RELEASE(pEditor);
     HX_RELEASE(pProcessor);
     HX_RELEASE(pResponse);
     HX_RELEASE(pOptions);
     HX_RELEASE(pCommonClassFactory);
 
     if(pMediaPlatform)
     {
         pMediaPlatform->Close();
     }
     HX_RELEASE(pMediaPlatform);
+
     if(fpHXMediaPlatformClose)
     {
         fpHXMediaPlatformClose();
     }
     HX_DELETE(pDLLAccess);
+
     EncStrUtils::Deallocate(pInputFileName, EncStrUtils::ALLOC_FLAG_NEW);
     EncStrUtils::Deallocate(pOutputFileName, EncStrUtils::ALLOC_FLAG_NEW);
+    EncStrUtils::Deallocate(pMetaStyleName, EncStrUtils::ALLOC_FLAG_NEW);
 
     return retVal;
 }
datatype_tools_dtdriver_common.diff (text/x-patch, 1.9 KB)
Index: Umakefil
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/common/Umakefil,v
retrieving revision 1.2
diff -d -H -b -B -w -U30 -r1.2 Umakefil
--- Umakefil	8 Dec 2005 17:58:16 -0000	1.2
+++ Umakefil	19 Oct 2009 17:42:19 -0000
@@ -12,38 +12,41 @@
 # http://www.helixcommunity.org/content/rcsl, in which case the RCSL 
 # will apply. You may also obtain the license terms directly from 
 # RealNetworks.  You may not use this file except in compliance with 
 # the RPSL or, if you have a valid RCSL with RealNetworks applicable 
 # to this file, the RCSL.  Please see the applicable RPSL or RCSL for 
 # the rights, obligations and limitations governing use of the 
 # contents of the file. 
 #   
 # This file is part of the Helix DNA Technology. RealNetworks is the 
 # developer of the Original Code and owns the copyrights in the 
 # portions it created. 
 #   
 # This file, and the files included with this file, is distributed 
 # and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY 
 # KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS 
 # ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES 
 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET 
 # ENJOYMENT OR NON-INFRINGEMENT. 
 #  
 # Technology Compatibility Kit Test Suite(s) Location:  
 #    http://www.helixcommunity.org/content/tck  
 #  
 # Contributor(s):  
 #   
 # ***** END LICENSE BLOCK *****  
 
 
 UmakefileVersion(2,0)
 
 project.AddModuleIncludes("common/include",
+                "common/container/pub",
 			  "common/runtime/pub",
-			  "common/dbgtool/pub")
+                "common/dbgtool/pub",
+                "common/util/pub",
+                "datatype/include")
 
 project.AddSources("reporterror.cpp")
 
 LibraryTarget('dtdrcomlib')
 
 DependTarget()
datatype_tools_dtdriver_decoder.diff (text/x-patch, 25.6 KB)
Index: audio/Umakefil
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/decoder/audio/Umakefil,v
retrieving revision 1.4
diff -d -H -b -B -w -U30 -r1.4 Umakefil
--- audio/Umakefil	10 Jan 2005 19:08:46 -0000	1.4
+++ audio/Umakefil	19 Oct 2009 17:42:55 -0000
@@ -21,44 +21,46 @@
 # developer of the Original Code and owns the copyrights in the portions 
 # it created. 
 #  
 # This file, and the files included with this file, is distributed and made 
 # available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
 # EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 # FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 # 
 # Technology Compatibility Kit Test Suite(s) Location: 
 #    http://www.helixcommunity.org/content/tck 
 # 
 # Contributor(s): 
 #  
 # ***** END LICENSE BLOCK ***** 
 # 
 
 UmakefileVersion(2,0)
 
 project.AddIncludes("../../common/pub",
                     "../../engine/pub",
                     "../common/pub")
 
 project.AddModuleIncludes("common/include",
 			  "common/runtime/pub",
 			  "common/dbgtool/pub", 
 			  "common/util/pub", 
 			  "common/container/pub",
 			  "common/system/pub",
                           "datatype/common/container/pub",
+              "datatype/include",
+              "datatype/common/util/pub",
 			  "client/common/container/pub",
                           "client/audiosvc/pub",
 			  "protocol/transport/rtp/include")
 
 project.AddSources( 'adecoder.cpp',
 		    'stubplay.cpp',
 		    'stubastr.cpp')
 
 if project.IsDefined("HELIX_FEATURE_DTDR_MIXER"):
     project.AddSources('amixer.cpp')
 
 LibraryTarget('dtdrauddec')
 
 DependTarget()
Index: audio/adecoder.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/decoder/audio/adecoder.cpp,v
retrieving revision 1.19
diff -d -H -b -B -w -U30 -r1.19 adecoder.cpp
--- audio/adecoder.cpp	24 Jan 2008 19:34:08 -0000	1.19
+++ audio/adecoder.cpp	19 Oct 2009 17:42:58 -0000
@@ -32,60 +32,61 @@
  * Contributor(s): 
  *  
  * ***** END LICENSE BLOCK ***** */ 
 
 #include "hxtypes.h"
 #include "hxcom.h"
 #include "hxplugn.h"
 #include "ihxpckts.h"
 #include "hxcore.h"
 #include "hxrendr.h"
 #include "hxausvc.h"
 #include "hxrasyn.h"
 
 #include "pckunpck.h" // SetCStringProperty
 
 #include "plghand2.h"
 #include "netbyte.h"
 #include "hxtick.h"
 #include "rtptypes.h"
 
 #include "hxsrcin.h"
 #include "csrchdlr.h"
 
 #include "stubastr.h"
 #include "stubplay.h"
 #include "stubstrm.h"
 #include "sdecmlog.h"
 #include "adecoder.h"
 #include "amixer.h"
 #include "reporterror.h"
+#include "metautil.h"
 
 #define _TRUNCATE_AUDIO_TO_ENDTIME
 
 #define AUDIO_STREAM_TIME_TOLERANCE 3
 
 // Maximum unmber of frames that can be handled at the time while 
 // ressampling before an overflow assuming 48KHz sampling rate.
 #define MAX_FRAMES_TO_RESAMPLE_IN_SINGLE_STEP 89478
 
 
 CAudioSourceHandler::CAudioSourceHandler(IUnknown* pContext) :
     CSourceHandler(pContext)
 {
     MLOG_TRACE("%lu CON CAudioSourceHandler this=0x%08x\n",
                HX_GET_BETTERTICKCOUNT(), this);
     m_lRefCount               = 0;
     m_pFileHeaderIn           = NULL;
     m_pStreamHeaderIn         = NULL;
     m_pFileHeaderOut          = NULL;
     m_pStreamHeaderOut        = NULL;
     m_pMimeTypeStr            = NULL;
     m_pRenderer               = NULL;
     m_pAudioPlayer            = NULL;
     m_pStream                 = NULL;
     m_pMixer		      = NULL;
     m_pWriteQueue             = NULL;
     m_cFormat.uChannels       = 0;
     m_cFormat.uBitsPerSample  = 0;
     m_cFormat.ulSamplesPerSec = 0;
     m_cFormat.uMaxBlockSize   = 0;
@@ -1757,60 +1758,63 @@
                 {
                     pszMime = (ulBitsPerSample == 8 ? "audio/L8" : "audio/L16");
                 }
                 else
                 {
                     pszMime = (ulBitsPerSample == 8 ? "audio/L8" : "audio/X-RN-LE16");
                 }
                 SetCStringPropertyCCF(rpValues, "MimeType", pszMime, m_pContext);
             }
 
             // If we have been asked to provide source properties,
             // then fill them in here
             if (m_bSetSrcProperties)
             {
                 // We attempt to recover each source property from
                 // the following sources in this order:
                 // 1) See if present in FILE header
                 // 2) See if present in STREAM header
                 // 3) See if renderer knows this property
                 // 4) See if present in stats (to be implemented later)
                 SetSourcePropertyCString(m_pStreamHeaderOut, "SrcCodec");
                 SetSourcePropertyCString(m_pStreamHeaderOut, "SrcInterleaver");
                 SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcBitRate");
                 SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcVBREnabled");
                 SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcVBRQuality");
 //                SetSourcePropertyCString(m_pStreamHeaderOut, "SrcInterleaved"); // not sure about this one
                 SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcSamplesPerSecond");
                 SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcBitsPerSample");
                 SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcNumChannels");
             }
+
+            // Transfer metadata if present
+            MetaInfo::CopyAllProperties(rpValues, m_pStreamHeaderIn, METAINFO_SET_ALL, FALSE);
         }
     }
 
     return retVal;
 }
 
 HXBOOL CAudioSourceHandler::GetBOOLOption(const char* pszStr, HXBOOL bDefault)
 {
     HXBOOL bRet = bDefault;
 
     if (m_pOptions)
     {
         UINT32 ulValue = 0;
         HX_RESULT rv = m_pOptions->GetPropertyULONG32(pszStr, ulValue);
         if (SUCCEEDED(rv) && ulValue != 0)
         {
             bRet = TRUE;
         }
         else
         {
             bRet = FALSE;
         }
     }
 
     return bRet;
 }
 
 ULONG32 CAudioSourceHandler::GetULONG32Option(const char* pszStr, ULONG32 ulDefault)
 {
     ULONG32 ulRet = ulDefault;
@@ -1931,67 +1935,65 @@
             pValues->SetPropertyULONG32(pszProp, ulValue);
         }
     }
 }
 
 HX_RESULT CAudioSourceHandler::CallOnFileHeader()
 {
     HX_RESULT retVal = HXR_OK;
 
     HX_RELEASE(m_pFileHeaderOut);
     if (m_pFileHeaderIn)
     {
         if (m_bIsPassThru)
         {
             retVal = CopyValues(m_pFileHeaderIn, m_pFileHeaderOut);
         }
         else
         {
             // Create an IHXValues
             retVal = CreateValuesCCF(m_pFileHeaderOut, m_pContext);
             
             if (SUCCEEDED(retVal))
             {
                 IHXBuffer* pBuffer = NULL;
                 
                 // Set the stream count
                 m_pFileHeaderOut->SetPropertyULONG32("StreamCount", 1);
                 // Set the flag saying this is not a real datatype
                 m_pFileHeaderOut->SetPropertyULONG32("IsRealDataType", 0);
 
-                // Transfer TAC if present
-                CopyHdrBuffer("Title", m_pFileHeaderIn, m_pFileHeaderOut);
-                CopyHdrBuffer("Author", m_pFileHeaderIn, m_pFileHeaderOut);
-                CopyHdrBuffer("Copyright", m_pFileHeaderIn, m_pFileHeaderOut);
+                // Transfer metadata if present
+                MetaInfo::CopyAllProperties(m_pFileHeaderOut, m_pFileHeaderIn, METAINFO_SET_ALL, FALSE);
+
                 CopyHdrCString("AudioFormat", m_pFileHeaderIn, 
                                m_pFileHeaderOut);
-                CopyHdrCString("Abstract", m_pFileHeaderIn, m_pFileHeaderOut);
             }
         }
     }
     else
     {
         retVal = HXR_FAIL;
     }
     
     
     if (m_pSourceSink)
     {
         MLOG_TRACE("    sending file header to sink\n");
         m_pSourceSink->OnFileHeader(retVal, m_pFileHeaderOut);
     }
 
     if (FAILED(retVal))
     {
         m_lLastError = retVal;
     }
 
     return retVal;
 }
 
 HXBOOL CAudioSourceHandler::ShouldBePassThru()
 {
     HXBOOL bRet = FALSE;
 
     IHXBuffer* pSrcCodec = NULL;
     IHXBuffer* pSrcIleave = NULL;
     
Index: video/Umakefil
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/decoder/video/Umakefil,v
retrieving revision 1.7
diff -d -H -b -B -w -U30 -r1.7 Umakefil
--- video/Umakefil	17 Oct 2008 07:46:50 -0000	1.7
+++ video/Umakefil	19 Oct 2009 17:42:58 -0000
@@ -26,39 +26,40 @@
 # EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 # FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 # 
 # Technology Compatibility Kit Test Suite(s) Location: 
 #    http://www.helixcommunity.org/content/tck 
 # 
 # Contributor(s): 
 #  
 # ***** END LICENSE BLOCK ***** 
 # 
 
 UmakefileVersion(2,0)
 
 project.AddIncludes("../../common/pub",
                     "../../engine/pub", 
                     "../common/pub")
 
 project.AddModuleIncludes("common/include",
 			  "common/runtime/pub",
 			  "common/dbgtool/pub", 
 			  "common/util/pub", 
 		          "common/container/pub",
 			  "common/system/pub",
 			  "common/log/logutil/pub",
 			  "client/include",
 			  "video/include",
 			  "video/colconverter/pub",
 			  "client/common/container/pub",
 			  "protocol/transport/rtp/include",
+              "datatype/include",
 			  "datatype/common/util/pub")
 
 project.AddModuleLibraries("datatype/common/util[dtutillib.lib]")
 
 project.AddSources( 'vdecoder.cpp', 'vdepacker.cpp', 'stubvplay.cpp', 'stubsite.cpp' )
 
 LibraryTarget('dtdrviddec')
 
 DependTarget()
Index: video/vdecoder.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/decoder/video/vdecoder.cpp,v
retrieving revision 1.32
diff -d -H -b -B -w -U30 -r1.32 vdecoder.cpp
--- video/vdecoder.cpp	26 May 2009 01:34:46 -0000	1.32
+++ video/vdecoder.cpp	19 Oct 2009 17:43:01 -0000
@@ -27,60 +27,61 @@
  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  * 
  * Technology Compatibility Kit Test Suite(s) Location: 
  *    http://www.helixcommunity.org/content/tck 
  * 
  * Contributor(s): 
  *  
  * ***** END LICENSE BLOCK ***** */ 
 
 #include "hxtypes.h"
 #include "hxcom.h"
 #include "hxplugn.h"
 #include "ihxpckts.h"
 #include "hxcore.h"
 #include "hxrendr.h"
 #include "hxausvc.h"
 #include "hxrasyn.h"
 #include "hxbuffer.h"
 #include "multilog.h"
 
 #include "pckunpck.h" // SetCStringProperty
 
 #include "plghand2.h"
 #include "netbyte.h"
 #include "hxtick.h"
 #include "rtptypes.h"
 #include "hxcbobj.h"
 
 #include "hxsrcin.h"
 #include "reporterror.h"
+#include "metautil.h"
 #include "csrchdlr.h"
 #include "stubstrm.h"
 #include "stubvplay.h"
 #include "stubsite.h"
 
 //#define HELIX_FEATURE_LOGLEVEL_NONE // uncomment to disable logging
 #include "hxtlogutil.h"
 #include "resize.h"
 #include "coloracc.h"	
 #include "colormap.h"
 #include "vdecoder.h"
 #include "hlxclib/stdlib.h"
 
 #define HX_VDECODER_CALLBACK_INTERVAL 10
 
 #define HX_NO_COLOR_CONVERSION 0xFFFFFFFF
 #define WIDTHBYTES(i)        ((ULONG32)((i+31)&(~31))/8)
 
 /*
 #ifndef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
 #error "Somehow you are building video support in dtdriver without"
 #error "HELIX_FEATURE_VIDREND_UNTIMED_DECODE defined. This is bad"
 #error "because dtdrive can't simulate a real timeline and needs your"
 #error "video renderer to be built with this option."
 #endif // #ifndef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
 */
 
 #if defined(_DEBUG)
 #define TRACE_TARGET_FILE      0
 #define TRACE_TARGET_DEBUGGER  1
@@ -234,91 +235,69 @@
     // on the options and has changed them since we
     // were initialized
     m_bProcessHeadersOnly = GetBOOLOption("ProcessHeadersOnly",  m_bProcessHeadersOnly);
     m_bMaxSpeed           = GetBOOLOption("MaxSpeed",            m_bMaxSpeed);
     m_bSetSrcProperties   = GetBOOLOption("SetSrcProperties",    m_bSetSrcProperties);
     m_ulStartTime	  = GetULONG32Option("StartTime",        m_ulStartTime);
     m_ulProcessTimeUnits  = GetULONG32Option("ProcessTimeUnits", m_ulProcessTimeUnits);
 
     if (SUCCEEDED(status) && pValues)
     {
         // Save the file header.
         // XXXMEH - not sure that we'll need this,
         // but go ahead and save it for now.
         HX_RELEASE(m_pFileHeaderIn);
         m_pFileHeaderIn = pValues;
         m_pFileHeaderIn->AddRef();
         // Create an IHXValues
         HX_RELEASE(m_pFileHeaderOut);
         retVal = CreateValuesCCF(m_pFileHeaderOut, m_pContext);
         if (SUCCEEDED(retVal))
         {
 	    IHXBuffer* pBuffer = NULL;
 
             // Set the stream count
             m_pFileHeaderOut->SetPropertyULONG32("StreamCount", 1);
 
 	    // TODO determine which inbound properties need to be propogated on
             // Set the flag saying this is not a real datatype
             m_pFileHeaderOut->SetPropertyULONG32("IsRealDataType", 0);
 
-            // Transfer TAC if present
-            m_pFileHeaderIn->GetPropertyBuffer("Title", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyBuffer("Title", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
-            m_pFileHeaderIn->GetPropertyBuffer("Author", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyBuffer("Author", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
-            m_pFileHeaderIn->GetPropertyBuffer("Copyright", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyBuffer("Copyright", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
+            // Transfer metadata if present
+            MetaInfo::CopyAllProperties(m_pFileHeaderOut, m_pFileHeaderIn, METAINFO_SET_ALL, FALSE);
+
             m_pFileHeaderIn->GetPropertyCString("AudioFormat", pBuffer);
             if (pBuffer)
             {
                 m_pFileHeaderOut->SetPropertyCString("AudioFormat", pBuffer);
                 HX_RELEASE(pBuffer);
             }
-            m_pFileHeaderIn->GetPropertyCString("Abstract", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyCString("Abstract", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
 
             // Pass this along to the sink
             if (m_pSourceSink)
             {
                 HXLOGL4(HXLOG_DTDR, "\tCVideoSourceHandler[%p]::OnFileHeader(status=0x%08x,) sending file header to sink", this, status);
                 m_pSourceSink->OnFileHeader(HXR_OK, m_pFileHeaderOut);
             }
         }
     }
     else
     {
         retVal = HXR_FAIL;
     }
 
     // If we failed, then still call to the sink
     if (FAILED(retVal) && m_pSourceSink)
     {
         m_pSourceSink->OnFileHeader(retVal, NULL);
         m_lLastError = retVal;
     }
 
     return retVal;
 }
 
 STDMETHODIMP CVideoSourceHandler::OnStreamHeader( HX_RESULT status, IHXValues* pValues)
 {
     HXLOGL4(HXLOG_DTDR, "CVideoSourceHandler[%p]::OnStreamHeader(status=0x%08x,)", this, status);
     HX_RESULT retVal = HXR_FAIL;
 
     if (SUCCEEDED(status) && pValues)
@@ -818,60 +797,63 @@
 	rpValues->SetPropertyULONG32("Width", nWidth);
 	rpValues->SetPropertyULONG32("Height", nHeight);
 
         // add properties from input stream header
         if (m_pStreamHeaderIn)
         {
             UINT32 ulTmp = 0;
             if (SUCCEEDED(m_pStreamHeaderIn->GetPropertyULONG32("FramesPerMSecond", ulTmp)))
             {
                 rpValues->SetPropertyULONG32("FramesPerMSecond", ulTmp);
             }
         }
         // If we have been asked to provide source properties,
         // then fill them in here
         if (m_bSetSrcProperties)
         {
             // We attempt to recover each source property from
             // the following sources in this order:
             // 1) See if present in FILE header
             // 2) See if present in STREAM header
             // 3) See if renderer knows this property
             // 4) See if present in stats (to be implemented later)
             SetSourcePropertyCString(m_pStreamHeaderOut, "SrcCodec");
             SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcBitRate");
             SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcVBREnabled");
             SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcVBRQuality");
             SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcFramesPerMSecond");
             SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcWidth");
             SetSourcePropertyULONG32(m_pStreamHeaderOut, "SrcHeight");
         }
+
+        // Transfer metadata if present
+        MetaInfo::CopyAllProperties(rpValues, m_pStreamHeaderIn, METAINFO_SET_ALL, FALSE);
     }
 
     return retVal;
 }
 
 STDMETHODIMP CVideoSourceHandler::OnVideoBlt( HXBitmapInfoHeader* pHeader, UCHAR* pData, REF(HXxRect) rSrcRect )
 {
     HXLOGL4(HXLOG_DTDR, "CVideoSourceHandler[%p]::OnVideoBlt()", this);
     HX_RESULT retVal = HXR_FAIL;
 
     UINT32 currentTime = 0;
     m_pRenderTimeLine->GetTimeLineValue(currentTime);
 
     if (m_bDoResizingVideo && !m_bValidResizingInputFormat)
     {
         return HXR_UNSUPPORTED_VIDEO;
     }
 
     if( HXxRect_IsEmpty(rSrcRect) )
     {
 	HXxRect_Set(rSrcRect, 0, 0, pHeader->biWidth, pHeader->biHeight);
     }
 
     if (m_bFirstWrite) 
     {
        // Set input and output width/height size for resizing
        m_ulInputWidth = HXxRECT_WIDTH(rSrcRect);
        m_ulInputHeight = HXxRECT_HEIGHT(rSrcRect);
 
        if(rSrcRect.left != 0 || rSrcRect.top != 0 || rSrcRect.right != pHeader->biWidth || rSrcRect.bottom != pHeader->biHeight)
Index: video/vdepacker.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/decoder/video/vdepacker.cpp,v
retrieving revision 1.3
diff -d -H -b -B -w -U30 -r1.3 vdepacker.cpp
--- video/vdepacker.cpp	30 Jan 2006 21:11:05 -0000	1.3
+++ video/vdepacker.cpp	19 Oct 2009 17:43:01 -0000
@@ -28,60 +28,61 @@
  * ENJOYMENT OR NON-INFRINGEMENT. 
  *  
  * Technology Compatibility Kit Test Suite(s) Location:  
  *    http://www.helixcommunity.org/content/tck  
  *  
  * Contributor(s):  
  *   
  * ***** END LICENSE BLOCK ***** */
 
 #include "hxtypes.h"
 #include "hlxclib/string.h"
 
 #include "hxcom.h"
 #include "hxplugn.h"
 #include "ihxpckts.h"
 #include "hxcore.h"
 #include "hxformt.h"
 #include "hxausvc.h"
 #include "hxrasyn.h"
 #include "hxbuffer.h"
 #include "multilog.h"
 
 #include "pckunpck.h" // SetCStringProperty
 
 #include "plghand2.h"
 #include "netbyte.h"
 #include "hxtick.h"
 #include "rtptypes.h"
 
 #include "hxsrcin.h"
+#include "metautil.h"
 #include "csrchdlr.h"
 #include "stubstrm.h"
 #include "vdepacker.h"
 
 
 #if defined(_DEBUG)
 #define TRACE_TARGET_FILE      0
 #define TRACE_TARGET_DEBUGGER  1
 #else
 #define TRACE_TARGET_FILE      0
 #define TRACE_TARGET_DEBUGGER  0
 #endif
 
 // Create an inline MLOG_TRACE() function
 #ifndef MLOG_TRACE_COMPILED_OUT
 INIT_MULTILOG_GROUP_NO_COREDEBUG(TRACE,
                                  TRACE_TARGET_FILE,
                                  TRACE_TARGET_DEBUGGER,
                                  "sdepacker_trace.log");
 #else
 #define MLOG_TRACE if(0)
 #endif
 
 CVideoSourceDepacketizer::CVideoSourceDepacketizer(IUnknown* pContext) :
 	CSourceHandler(pContext)
 {
     MLOG_TRACE("%lu CON CVideoSourceDepacketizer this=0x%08x\n",
                HX_GET_BETTERTICKCOUNT(), this);
 
     m_lRefCount		      = 0;
@@ -182,91 +183,69 @@
     // in case another object is also holding a ref
     // on the options and has changed them since we
     // were initialized
     m_bProcessHeadersOnly = GetBOOLOption("ProcessHeadersOnly", m_bProcessHeadersOnly);
     m_bMaxSpeed           = GetBOOLOption("MaxSpeed",           m_bMaxSpeed);
     m_bSetSrcProperties   = GetBOOLOption("SetSrcProperties",   m_bSetSrcProperties);
     m_ulStartTime	  = GetULONG32Option("StartTime",	m_ulStartTime);
 
     if (SUCCEEDED(status) && pValues)
     {
         // Save the file header.
         // XXXMEH - not sure that we'll need this,
         // but go ahead and save it for now.
         HX_RELEASE(m_pFileHeaderIn);
         m_pFileHeaderIn = pValues;
         m_pFileHeaderIn->AddRef();
         // Create an IHXValues
         HX_RELEASE(m_pFileHeaderOut);
         retVal = CreateValuesCCF(m_pFileHeaderOut, m_pContext);
         if (SUCCEEDED(retVal))
         {
 	    IHXBuffer* pBuffer = NULL;
 
             // Set the stream count
             m_pFileHeaderOut->SetPropertyULONG32("StreamCount", 1);
 
 	    // TODO determine which inbound properties need to be propogated on
             // Set the flag saying this is not a real datatype
             m_pFileHeaderOut->SetPropertyULONG32("IsRealDataType", 0);
 
-            // Transfer TAC if present
-            m_pFileHeaderIn->GetPropertyBuffer("Title", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyBuffer("Title", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
-            m_pFileHeaderIn->GetPropertyBuffer("Author", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyBuffer("Author", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
-            m_pFileHeaderIn->GetPropertyBuffer("Copyright", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyBuffer("Copyright", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
             m_pFileHeaderIn->GetPropertyCString("AudioFormat", pBuffer);
             if (pBuffer)
             {
                 m_pFileHeaderOut->SetPropertyCString("AudioFormat", pBuffer);
                 HX_RELEASE(pBuffer);
             }
-            m_pFileHeaderIn->GetPropertyCString("Abstract", pBuffer);
-            if (pBuffer)
-            {
-                m_pFileHeaderOut->SetPropertyCString("Abstract", pBuffer);
-                HX_RELEASE(pBuffer);
-            }
+
+            // Transfer metadata if present
+            MetaInfo::CopyAllProperties(m_pFileHeaderOut, m_pFileHeaderIn, METAINFO_SET_ALL, FALSE);
 
             // Pass this along to the sink
             if (m_pSourceSink)
             {
                 MLOG_TRACE("    sending file header to sink\n");
                 m_pSourceSink->OnFileHeader(HXR_OK, m_pFileHeaderOut);
             }
         }
     }
     else
     {
         retVal = HXR_FAIL;
     }
 
     // If we failed, then still call to the sink
     if (FAILED(retVal) && m_pSourceSink)
     {
         m_pSourceSink->OnFileHeader(retVal, NULL);
         m_lLastError = retVal;
     }
 
     return retVal;
 }
 
 STDMETHODIMP CVideoSourceDepacketizer::OnStreamHeader( HX_RESULT status, IHXValues* pValues)
 {
     MLOG_TRACE("%lu CVideoSourceDepacketizer::OnStreamHeader(0x%08x,0x%08x)\n",
                HX_GET_BETTERTICKCOUNT(), status, pValues);
     HX_RESULT retVal = HXR_FAIL;
 
@@ -278,60 +257,65 @@
         HX_RELEASE(m_pStreamHeaderIn);
         m_pStreamHeaderIn = pValues;
         m_pStreamHeaderIn->AddRef();
         // Check our options. We check them again
         // here (we also did in InitSourceHandler() and
         // OnFileHeader()) in case another object is also
         // holding a ref on the options and has changed them
         // since we were initialized,
         m_bProcessHeadersOnly = GetBOOLOption("ProcessHeadersOnly", m_bProcessHeadersOnly);
         m_bMaxSpeed           = GetBOOLOption("MaxSpeed",           m_bMaxSpeed);
         m_bSetSrcProperties   = GetBOOLOption("SetSrcProperties",   m_bSetSrcProperties);
 	m_ulStartTime	      = GetULONG32Option("StartTime",	    m_ulStartTime);
 	// Load the depacker
 	HX_RELEASE(m_pDepacker);
 	retVal = LoadDepackerForStreamHeader(m_pStreamHeaderIn, m_pDepacker);
         if (SUCCEEDED(retVal))
         {
             // Init the depacker
             retVal = InitDepacker(m_pDepacker, m_pStreamHeaderIn);
 
 	    // Get output stream header from depacker
 	    if (SUCCEEDED(retVal))
 	    {
 		HX_RELEASE(m_pStreamHeaderOut);
 		retVal = CreateValuesCCF(m_pStreamHeaderOut, m_pContext);
 	    }
 	    if (SUCCEEDED(retVal))
 	    {
 		retVal = m_pDepacker->GetStreamHeader(m_pStreamHeaderOut);
 	    }
+            if (SUCCEEDED(retVal))
+            {
+                // Transfer metadata if present
+                MetaInfo::CopyAllProperties(m_pStreamHeaderOut, m_pStreamHeaderIn, METAINFO_SET_ALL, FALSE);
+            }
 	    if (SUCCEEDED(retVal) && m_pSourceSink)
 	    {
 		m_pSourceSink->OnStreamHeader(HXR_OK, m_pStreamHeaderOut);
 	    }
 	}
     }
     if (FAILED(retVal) && m_pSourceSink)
     {
         m_pSourceSink->OnTermination(retVal);
         m_lLastError = retVal;
     }
 
     return retVal;
 }
 
 STDMETHODIMP CVideoSourceDepacketizer::OnStreamDone( HX_RESULT status, UINT16 unStreamNumber )
 {
     HX_RESULT retVal = HXR_OK;
     if (FAILED(status) || FAILED(m_lLastError))
     {
 	retVal = HXR_FAIL;
     }
 
     if (m_pSourceSink)
     {
         retVal = m_pSourceSink->OnStreamDone(retVal, unStreamNumber);
     }
 
     return retVal;
 }
datatype_tools_dtdriver_engine.diff (text/x-patch, 25.8 KB)
Index: Umakefil
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/engine/Umakefil,v
retrieving revision 1.26
diff -d -H -b -B -w -U30 -r1.26 Umakefil
--- Umakefil	16 Apr 2009 20:18:22 -0000	1.26
+++ Umakefil	19 Oct 2009 17:43:03 -0000
@@ -16,60 +16,62 @@
 # applicable to this file, the RCSL.  Please see the applicable RPSL or 
 # RCSL for the rights, obligations and limitations governing use of the 
 # contents of the file.  
 #  
 # This file is part of the Helix DNA Technology. RealNetworks is the 
 # developer of the Original Code and owns the copyrights in the portions 
 # it created. 
 #  
 # This file, and the files included with this file, is distributed and made 
 # available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
 # EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 # FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 # 
 # Technology Compatibility Kit Test Suite(s) Location: 
 #    http://www.helixcommunity.org/content/tck 
 # 
 # Contributor(s): 
 #  
 # ***** END LICENSE BLOCK ***** 
 # 
 
 UmakefileVersion(2,0)
 
 project.AddModuleIncludes("common/include",
                           "client/include",
                           "datatype/include",
                           "datatype/rm/include",
                           "common/log/logutil/pub",
                           "common/log/logobserverfile/pub",
+                          "datatype/include",
+                          "datatype/common/util/pub",
                           "datatype/common/filewriter/pub",
 			  "video/include")
 
 project.AddIncludes("../common/pub",
                     "../decoder/common/pub",
                     "../encoder/common/pub",
                     "../include",
                     "../../minicntx/pub")
 
 project.AddModuleIncludes("common/runtime/pub",
                           "common/dbgtool/pub",
                           "common/util/pub",
                           "client/common/container/pub",
                           "common/container/pub",
                           "common/system/pub")
 
 project.AddSources("ffdriver.cpp",
                    "csrchdlrstackfact.cpp",
                    "csrchdlr.cpp",
                    "callbackq.cpp",
                    "csrctrpt.cpp",
                    "csrcsplt.cpp",
                    "csrcsynchdlr.cpp",
                    "merge_sort_src_handler.cpp")
 
 if project.IsDefined("HELIX_FEATURE_DTDR_MUXER"):
     project.AddSources("cmuxsrchandler.cpp")
 
 if project.IsDefined("HELIX_FEATURE_DTDR_MULTIWRITER"):
     project.AddSources("cmultifwriter.cpp")
Index: ffdriver.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/engine/ffdriver.cpp,v
retrieving revision 1.60
diff -d -H -b -B -w -U30 -r1.60 ffdriver.cpp
--- ffdriver.cpp	2 Oct 2009 12:45:21 -0000	1.60
+++ ffdriver.cpp	19 Oct 2009 17:43:09 -0000
@@ -119,60 +119,61 @@
 
 #define CHAR_CR_INDICATOR   "<CR>"
 #define CHAR_LF_INDICATOR   "<LF>"
 
 #define DEFAULT_RATEMODE_INTERVAL   10000
 #define DTDR_INVALID_TS	    0xFFFFFFFF
 #define DTDR_INVALID_STRM   0xFFFF  
 #define DTDR_MAX_TS_DIFF    0x00FFFFFF
 
 
 /****************************************************************************
  *  Includes
  */
 #include "hlxclib/stdio.h"
 #include "hlxclib/stdarg.h"
 #include "hlxclib/string.h"
 #include "hlxclib/ctype.h"
 
 #include "ffdriver.h"
 
 #include "hxstrutl.h"
 #include "hxtick.h"
 #include "hxplugn.h"
 #include "hxccf.h"
 #include "hxasm.h"
 #include "hxver.h"
 #include "hxsmutil.h"
 #include "hxvalues.h"
 
 #include "reporterror.h"
+#include "metautil.h"
 
 #include "chxpckts.h"
 #include "pckunpck.h"
 
 #include "csrchdlr.h"
 #include "csrchdlrstackfact.h"
 #include "stream_desc_hlpr.h"
 
 #include "cmultifwriter.h"
 #define HELIX_FEATURE_LOGLEVEL_NONE // uncomment to disable all logging in this file
 #include "hxtlogutil.h"
 #include "hxloghelper.h"
 
 #include "metainfokeys.h"
 #include "proptools.h"
 //#include "ciddefs.h"
 
 /****************************************************************************
  *  Locals
  */
 
 // WARNING! This Array must be kept aligned with MemoryProbeCategories enum
 static const char* const m_MemCategoryNameArray[] =
 {
        "+-------Context Create & Init",
        "|             File Sys.Create",
        "| +-------------File Sys.Init",
        "| | +--File Obj.Create & Init",
        "| | | +-------File Fmt.Create",
        "| | | |      File Wrtr.Create",
@@ -253,60 +254,61 @@
     , m_ulBwThresholdsSize(0)
     , m_ulNumBwThresholds(0)
     , m_lBwThresholdIdx(0)
     , m_ulCurrentBw(0)
     , m_ulLastThreasholdEventTime(0)
     , m_state(State_Initializing)
     , m_status(HXR_OK)
     , m_pInputFileName(NULL)
     , m_pInputURL(NULL)
     , m_pWriteFileName(NULL)
     , m_pTempDirName(NULL)
     , m_pInputFileProtocol(NULL)
     , m_pInputFileSysShortName(NULL)
     , m_uOptionFlags(DFLT_OPTIONS)
     , m_bUseNuggetFormat(FALSE)
     , m_uBandwidth(0)
     , m_ulRateMode(RATE_MODE_CONSTANT)
     , m_ulRateModeInterval(0)
     , m_ulMinBwThreshold(0)
     , m_ulMaxBwThreshold(0)
     , m_ulStartTime(0)
     , m_ulProcessUntil(0)
     , m_ulProcessTimeUnits(0)
     , m_bBandwidthExplicitlySet(FALSE)
     , m_bStartTimeExplicitlySet(FALSE)
     , m_bParseSDP(FALSE)
     , m_uServerMode(0)
     , m_ulContextEvents(0)
     , m_lTimerValue(-1)
     , m_ulRotationSize(0)
+    , m_ulMetaDataFlavor(0)
     , m_bStop(FALSE)
     , m_bSoftStop(FALSE)
     , m_bPacketReady(FALSE)
     , m_pMemProbeArray(NULL)
     , m_ulGetPacketEvents(0)
     , m_bPadToSize(FALSE)
     , m_ulTargetSize(0)
     , m_ulMediaSize(0)
     , m_pLastWrittenPacket(NULL)
     , m_pLastWrittenFileHeader(NULL)
     , m_pDupPacketTrackerList(NULL)
 #if defined (HELIX_CONFIG_USE_EXTERNAL_CONTEXT)
     , m_bPersistentContext(TRUE)
 #else
     , m_bPersistentContext(FALSE)
 #endif
     , m_ulStartTS(DTDR_INVALID_TS)
     , m_ulStartTick(0)
     , m_ulProcessingRate(0) // 0 = as fast as possible
 #ifdef HELIX_FEATURE_DTDR_USE_RECOGNIZER
     , m_pFileRecognizer(NULL)
 #endif
     , m_bUseFileRecognition(FALSE)
     , m_bLiveSource(FALSE)
     , m_bTerminated(FALSE)
 {
 #ifdef _WRITER_WRITE_SIZE_TEST
     m_bPadToSize = TRUE;
     m_ulTargetSize = WRITER_WRITE_SIZE_TEST_GOAL;
 #endif  // _WRITER_WRITE_SIZE_TEST
@@ -649,60 +651,64 @@
                     m_lTimerValue = (LONG32) uOptValue;
                 }
                 else if (strcmp(pOptName, JUMPSTART_OPTION_NAME) == 0)
                 {
                     m_ulStartTime = uOptValue;
 		    m_bStartTimeExplicitlySet = TRUE;
                 }
                 else if (strcmp(pOptName, PROCESSUNTIL_OPTION_NAME) == 0)
                 {
                     m_ulProcessUntil = uOptValue;
                 }
                 else if (strcmp(pOptName, PROCESSTIMEUNITS_OPTION_NAME) == 0)
                 {
                     m_ulProcessTimeUnits = uOptValue;
                 }
                 else if (strcmp(pOptName, ROTATIONSIZE_OPTION_NAME) == 0)
                 {
                     m_ulRotationSize = uOptValue;
                 }
                 else if (strcmp(pOptName, PROCESSHEADERS_OPTION_NAME) == 0)
                 {
                     if (m_lTimerValue < 0)
                     {
                         m_lTimerValue = 0;
                     }
                 }
                 else if (strcmp(pOptName, FILERECOGNITION_OPTION_NAME) == 0 && uOptValue)
                 {
                     m_bUseFileRecognition = TRUE;
                 }
+                else if (strcmp(pOptName, METADATAFLAVOR_OPTION_NAME) == 0)
+                {
+                    m_ulMetaDataFlavor = uOptValue;
+                }
             }
             Status = pOptions->GetNextPropertyULONG32(pOptName, uOptValue);
         }
     }
 
     // If we are to process packets for 0 amount of time and
     // PROCESSHEADERS_OPTION_NAME is not explicitly set, assume
     // PROCESSHEADERS_OPTION_NAME is needed.
     if ((m_lTimerValue == 0) && m_pOptions)
     {
         ULONG32 ulVal = 0;
         if (FAILED(m_pOptions->GetPropertyULONG32(
             PROCESSHEADERS_OPTION_NAME,
             ulVal)))
         {
             m_pOptions->SetPropertyULONG32(
             PROCESSHEADERS_OPTION_NAME,
             1);
         }
     }
 
     if (MEMORY_TRACKING_NEEDED)
     {
         m_pMemProbeArray = new CHXMemProbe [MEMPRB_MAX];
     }
 
     if (SUCCEEDED(RetVal) &&
     (m_ulRateMode != RATE_MODE_CONSTANT))
     {
         m_ulBwThresholdsSize = 0;
@@ -2026,60 +2032,69 @@
             retVal = pNewProps->SetPropertyULONG32("TrustGivenMediaProperties", 0);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
         if (m_uOptionFlags & PREROLL_OPTION)
         {
             retVal = pNewProps->SetPropertyULONG32("RecomputePreroll", 1);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
         if (m_uOptionFlags & BLASTFILE_OPTION)
         {
             retVal = pNewProps->SetPropertyULONG32("BlastFiles", 1);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
         if (m_uOptionFlags & UTF16OUTPUT_OPTION)
         {
             retVal = pNewProps->SetPropertyULONG32("UTF16Output", 1);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
+        if (m_ulMetaDataFlavor != 0)
+        {
+            retVal = pNewProps->SetPropertyULONG32("MetaDataFlavor",
+                                m_ulMetaDataFlavor);
+        }
+    }
+
+    if (SUCCEEDED(retVal))
+    {
         if (m_uOptionFlags & RELATIVETS_OPTION)
         {
             retVal = pNewProps->SetPropertyULONG32("UseRelativeTS", 1);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
         if (m_ulRotationSize != 0)
         {
             retVal = pNewProps->SetPropertyULONG32("RotationSize", 
                                m_ulRotationSize);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
         if (m_bBandwidthExplicitlySet || 
             (m_uBandwidth != 0) ||
             (m_ulRateMode != RATE_MODE_CONSTANT))
         {
             retVal = pNewProps->SetPropertyULONG32("ForceIntoSingleRate", 1);
         }
     }
 
     if (SUCCEEDED(retVal))
     {
 	ULONG32 ulUseTempFiles = 0;
 	if (SUCCEEDED(m_pOptions->GetPropertyULONG32(USETEMPFILES_OPTION_NAME, ulUseTempFiles)))
 	{
@@ -3977,186 +3992,65 @@
             status = m_pFileWriter->SetFileHeader(pHeader);
         
             HX_RELEASE(m_pLastWrittenFileHeader);
             m_pLastWrittenFileHeader = pHeader;
             pHeader->AddRef();
         }
     }
 
     if (m_uProcessedStreamsCount == 0)
     {
         if (m_pSourceHandlerStack)
         {
             m_pSourceHandlerStack->OnTermination(HXR_CLOSED);
         }
     }
 
     if (SUCCEEDED(m_status))
     {
         m_status = status;
     }
     
     return status;
 }
 
 HX_RESULT FFDriver::ApplyFileHeaderModifications(IHXValues* pHeader)
 {
 	HX_RESULT retVal = HXR_INVALID_PARAMETER;
 
 	if (pHeader)
 	{
-		IHXBuffer* pBuffValue = NULL;
-		HX_RESULT status = HXR_OK;
-		retVal = HXR_OK;
-
-		// Check for Title/Author/Copyright
-		if (SUCCEEDED(m_pOptions->GetPropertyBuffer(TITLE_OPTION_NAME, pBuffValue)))
-		{
-			status = pHeader->SetPropertyBuffer("Title", pBuffValue);
-			if (SUCCEEDED(retVal))
-			{
-				retVal = status;
-			}
-		}
-		HX_RELEASE(pBuffValue);
-
-		if (SUCCEEDED(m_pOptions->GetPropertyBuffer(AUTHOR_OPTION_NAME, pBuffValue)))
-		{
-			status = pHeader->SetPropertyBuffer("Author", pBuffValue);
-			if (SUCCEEDED(retVal))
-			{
-				retVal = status;
-			}
-		}
-		HX_RELEASE(pBuffValue);
-
-		if (SUCCEEDED(m_pOptions->GetPropertyBuffer(COPYRIGHT_OPTION_NAME, pBuffValue)))
-		{
-			status = pHeader->SetPropertyBuffer("Copyright", pBuffValue);
-			if (SUCCEEDED(retVal))
-			{
-				retVal = status;
-			}
-		}
-		HX_RELEASE(pBuffValue);
-
-		// Check for Abstract/Keywords
-		if (SUCCEEDED(m_pOptions->GetPropertyCString(ABSTRACT_OPTION_NAME, pBuffValue)))
-		{
-			status = pHeader->SetPropertyCString("Abstract", pBuffValue);
-			if (SUCCEEDED(retVal))
-			{
-				retVal = status;
-			}
-		}
-		HX_RELEASE(pBuffValue);
-
-		if (SUCCEEDED(m_pOptions->GetPropertyCString(KEYWORDS_OPTION_NAME, pBuffValue)))
-		{
-			status = pHeader->SetPropertyCString("Keywords", pBuffValue);
-			if (SUCCEEDED(retVal))
-			{
-				retVal = status;
-			}
-		}
-		HX_RELEASE(pBuffValue);
-
-		// 3GP meta-data
-		Apply3GPFileHeaderModifications(retVal, pHeader);
+        retVal = MetaInfo::CopyAllProperties(pHeader, m_pOptions, METAINFO_SET_ALL, FALSE);
 	}
-
 	return retVal;
 }
 
-void FFDriver::Apply3GPFileHeaderModifications(HX_RESULT& retVal, IHXValues* pHeader)
-{
-#if defined(HELIX_FEATURE_3GPP_METAINFO) || defined(HELIX_FEATURE_SERVER)
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_TITLE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_AUTHOR_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_COPYRIGHT_KEY, FALSE);
-#ifdef HELIX_FEATURE_3GPP_METAINFO
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_DESCRIPTION_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_PERFORMER_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_GENRE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_RATING_ENTITY_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_RATING_CRITERIA_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_RATING_INFO_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY, FALSE);
-    PropTools::CopyPropertyULONG32(retVal, pHeader, m_pOptions, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_NAME_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, FALSE);
-    PropTools::CopyPropertyULONG32(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_ROLE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_LATITUDE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY, FALSE);
-    PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, _3GPP_META_INFO_ALBUM_TITLE_KEY, FALSE);
-    PropTools::CopyPropertyULONG32(retVal, pHeader, m_pOptions, _3GPP_META_INFO_TRACK_NUMBER_KEY, FALSE);
-    PropTools::CopyPropertyULONG32(retVal, pHeader, m_pOptions, _3GPP_META_INFO_RECORDING_YEAR_KEY, FALSE);
-
-    // keywords
-    ULONG32 ulNewKeywordCount = 0;
-    PropTools::CopyPropertyULONG32(ulNewKeywordCount, m_pOptions, _3GPP_META_INFO_KEYWORD_COUNT_KEY);
-
-    if(ulNewKeywordCount)
-    {
-        // remove old keywords
-        ULONG32 ulOldKeywordCount = 0;
-        PropTools::CopyPropertyULONG32(ulOldKeywordCount, pHeader, _3GPP_META_INFO_KEYWORD_COUNT_KEY);
-        PropTools::RemovePropertyULONG32(pHeader, _3GPP_META_INFO_KEYWORD_COUNT_KEY);
-		
-        for(ULONG32 i = 0; i < ulOldKeywordCount; i++)
-        {
-            char key[128];
-            sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
-            PropTools::RemovePropertyBuffer(pHeader, key);
-        }
-
-        // add new keywords
-        PropTools::CopyPropertyULONG32(pHeader, TRUE, ulNewKeywordCount, _3GPP_META_INFO_KEYWORD_COUNT_KEY, TRUE);
-
-        for(ULONG32 i = 0; i < ulNewKeywordCount; i++)
-        {
-            char key[128];
-            sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
-            if(SUCCEEDED(retVal))
-            {
-                PropTools::CopyPropertyBuffer(retVal, pHeader, m_pOptions, key, TRUE);
-            }
-        }
-    }
-#endif // HELIX_FEATURE_3GPP_METAINFO
-#endif // HELIX_FEATURE_3GPP_METAINFO || HELIX_FEATURE_SERVER
-}
-
 STDMETHODIMP FFDriver::StreamHeaderReady(HX_RESULT status, IHXValues* pHeader)
 {
     HXLOGL3(HXLOG_DTDR, "FFDriver::StreamHeaderReady(status=0x%08x,pHeader=%p)", status, pHeader);
     UINT32 ulStreamNumber = 0;
     if (pHeader)
     {
         pHeader->GetPropertyULONG32("StreamNumber", ulStreamNumber);
     }
     HXLOGL3(HXLOG_DTDR, "FFDriver::StreamHeaderReady(status=0x%08x,) strm=%lu", status, ulStreamNumber);
     HX_RESULT retVal = HXR_OK;
 
     ++m_uStreamHeaders;
 
     if (SUCCEEDED(status) && (m_uStreamHeaders <= m_uStreamCount))
     {
         // First Source header is reserved for file header.
         // Subsequent entries contain stream headers,
         HX_RELEASE(m_pSourceHeaders[m_uStreamHeaders]);
         if (pHeader)
         {
             m_pSourceHeaders[m_uStreamHeaders] = pHeader;
             pHeader->AddRef();
         }
     }
     
     if (SUCCEEDED(status))
     {
         if (m_bParseSDP)
         {
             HX_RESULT sdpParseStatus;
Index: pub/ffdriver.h
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/engine/pub/ffdriver.h,v
retrieving revision 1.44
diff -d -H -b -B -w -U30 -r1.44 ffdriver.h
--- pub/ffdriver.h	2 Oct 2009 12:45:22 -0000	1.44
+++ pub/ffdriver.h	19 Oct 2009 17:43:09 -0000
@@ -50,60 +50,61 @@
 #define LOCALACCESSONLY_OPTION_NAME "LocalAccessOnly"
 #define RATE_OPTION_NAME	    "Rate"
 #define RATEMODE_OPTION_NAME	    "RateMode"
 #define RATEMAX_OPTION_NAME	    "RateMax"
 #define RATEMIN_OPTION_NAME	    "RateMin"
 #define PACE_OPTION_NAME	    "Pace"
 #define RATEMODEINTERVAL_OPTION_NAME "RateModeInterval"
 #define TIMER_OPTION_NAME	    "Timer"
 #define PASSSWOFFPKTS_OPTION_NAME   "PassSwitchOffPackets"
 #define USETEMPFILES_OPTION_NAME    "UseTempFiles"
 #define USENUGGETFORMAT_OPTION_NAME	    "UseNuggetFormat"
 #define NUGGETEXPIRATION_OPTION_NAME	    "NuggetExpiration"
 #define NUGGETCONNECTTIME_OPTION_NAME	    "NuggetConnectTime"
 #define NUGGETREMOTESOURCEURL_OPTION_NAME   "NuggetRemoteSourceURL"
 #define QUIET_OPTION_NAME           "Quiet"
 #define JUMPSTART_OPTION_NAME	    "StartTime"
 #define PROCESSUNTIL_OPTION_NAME    "ProcessUntil"
 #define PROCESSTIMEUNITS_OPTION_NAME    "ProcessTimeUnits"
 #define PROCESSDECODEDTIMEUNITS_OPTION_NAME    "ProcessDecodedTimeUnits"
 #define TIMING_OPTION_NAME	    "Timing"
 #define EVENT_OPTION_NAME	    "Event"
 #define DURATION_OPTION_NAME	    "Duration"
 #define TITLE_OPTION_NAME   	    "Title"
 #define AUTHOR_OPTION_NAME	    "Author"
 #define COPYRIGHT_OPTION_NAME	    "Copyright"
 #define ABSTRACT_OPTION_NAME	    "Abstract"
 #define KEYWORDS_OPTION_NAME	    "Keywords"
 #define PREROLL_OPTION_NAME	    "RecomputePreroll"
 #define BLASTFILE_OPTION_NAME	    "BlastFiles"
 #define UTF16OUTPUT_OPTION_NAME     "UTF16Output"
+#define METADATAFLAVOR_OPTION_NAME  "MetaDataFlavor"
 #define SYNCHRONOUS_OPTION_NAME     "Synchronous"
 #define RECORDASLIVE_OPTION_NAME    "RecordAsLive"
 #define ROTATIONSIZE_OPTION_NAME    "RotationSize"
 #define VIDEOOFFSET_OPTION_NAME	    "VideoTimeOffset"
 #define SOURCEOFFSET_OPTION_NAME    "SourceTimeOffset"
 #define VIDEOTIMESCALE_OPTION_NAME  "VideoTimeScale"
 #define KEYFRAMESONLY_OPTION_NAME   "KeyFramesOnly"
 #define MAXFRAMERATE_OPTION_NAME    "MaxFrameRate"
 #define MINFRAMERATE_OPTION_NAME    "MinFrameRate"
 #define LOOKAHEAD_OPTION_NAME       "LookAhead"
 #define RELATIVETS_OPTION_NAME	    "RelativeTS"
 #define DECRYPT_OPTION_NAME	    "DecryptSource"
 #define DECODE_OPTION_NAME	    "DecodeSource"
 #define DECODEAUDIO_OPTION_NAME	    "DecodeAudio"
 #define DECODEVIDEO_OPTION_NAME	    "DecodeVideo"
 #define DECODENONAV_OPTION_NAME	    "DecodeNonAV"
 #define DECODESTREAM_OPTION_NAME    "DecodeStream"
 #define DECODESTREAMMODE_OPTION_NAME	"DecodeStreamMode"
 #define OUTPUTSAMPLESPERSECOND_OPTION_NAME  "OutputSamplesPerSecond"
 #define OUTPUTCHANNELS_OPTION_NAME	    "OutputChannels"
 #define OUTPUTBITSPERSAMPLE_OPTION_NAME	    "OutputBitsPerSample"	
 #define MINOUTPUTBITSPERSAMPLE_OPTION_NAME  "MinOutputBitsPerSample"	
 #define MAXOUTPUTBITSPERSAMPLE_OPTION_NAME  "MaxOutputBitsPerSample"	
 #define ENCODE_OPTION_NAME	    "EncodeSource"
 #define ENCODEAUDIO_OPTION_NAME	    "EncodeAudioFormat"
 #define ENCODEVIDEO_OPTION_NAME	    "EncodeVideoFormat"
 #define ENCODEAUDIORATE_OPTION_NAME "EncodeAudioRate"
 #define ENCODEAUDIORATETOL_OPTION_NAME "EncodeAudioRateTol"
 #define ENCODEAUDIORATEMAX_OPTION_NAME "EncodeAudioRateMax"
 #define ENCODEAUDIORATECOMPFMTS_OPTION_NAME "EncodeAudioCompFormats"
@@ -498,61 +499,60 @@
 	State_InitFileFormatDone,
 	State_InitFileWriter,
 	State_GetFileHeader,
 	State_FileHeaderDonePending,
 	State_TryAnotherFormat,
 	State_FileHeaderDone,
 	State_InitGetPacketEngine,
 	State_GetStreamHeaders,
 	State_StreamHeadersDonePending,
 	State_StreamHeadersDone,
 	State_Seek,
 	State_SeekDonePending,
 	State_SeekDone,
 	State_PacketsReadyPending,
 	State_StartPackets,
 	State_GetPackets,
 	State_PacketsDone,
 	State_CleanUpReadyPending,
 	State_CleanUp,
 	State_RunReport,
 	State_EndFile,
 	State_DriveDone
     };
 
     HX_RESULT BuildStubFileHeader(IHXValues* &pHeader, UINT16 uStreamCount = 1);
     HX_RESULT BuildStubStreamHeader(UINT16 uStream, IHXValues* &pHeader);
 
     HX_RESULT	InternalizeSource(char *pInputFileName);
     HX_RESULT	InternalizeSourceHandlerList(IHXSourceHandler** pSourceHandlerList);
     HX_RESULT	ApplyFileHeaderModifications(IHXValues* pHeader);
-	void        Apply3GPFileHeaderModifications(HX_RESULT& retVal, IHXValues* pHeader);
     HX_RESULT	CreateWriterProps(IHXValues* &pWriterProps);
     HX_RESULT	InitGetPacketEngine(UINT16 uStreamCount);
     HX_RESULT	ConfigureDecodePosition(void);
     void	CloseGetPacketEngine(HXBOOL bRetainContainer = FALSE);
     void	CloseSourceHeaders(HXBOOL bRetainContainer = FALSE);
 
     HX_RESULT _FileHeaderReady(HX_RESULT status, IHXValues* pHeader);
     HX_RESULT _StreamHeaderReady(HX_RESULT status, IHXValues* pHeader);
     HX_RESULT _PacketReady(HX_RESULT status, IHXPacket* pPacket);
     HX_RESULT StreamDone(HX_RESULT status, UINT16 uStreamNumber);
     HX_RESULT _StreamDone(HX_RESULT status, UINT16 uStreamNumber);
 
     HXBOOL IsMemSpanArrayMember(MemoryProbeCategory MemProbeId);
 
     HX_RESULT EstablishBwThresholds(void);
 
     HX_RESULT ProcessBwControl(IHXPacket* pPacket);
 
     HX_RESULT Subscribe(HXBOOL bSubscribe = TRUE);
     HX_RESULT SubscribeBandwidth(UINT32 ulBandwidth, HXBOOL bSubcribe = TRUE);
     HX_RESULT SubscribeAll(HXBOOL bSubscribe = TRUE);
     HX_RESULT SubscribeAllInStream(IHXValues* pHeader, HXBOOL bSubscribe = TRUE);
 
     HX_RESULT StartPackets(void);
     HX_RESULT SelectNextStream(void);
     HX_RESULT GetNextPacket(UINT16 uStream, UINT32 ulDelay = 0);
     
 #ifndef HELIX_CONFIG_DTDR_DISABLE_LOGGING
     void ReportError(HX_RESULT errVal, const char *format, ...);
 
@@ -623,60 +623,61 @@
     INT32		    m_lBwThresholdIdx;
     INT32		    m_lNextBwThresholdIdx;
     UINT32		    m_ulCurrentBw;
     UINT32		    m_ulLastThreasholdEventTime;
     ProcState               m_state;
     HX_RESULT               m_status;
     char*		    m_pInputFileName;
     char*		    m_pInputURL;
     char*		    m_pWriteFileName;
     char*		    m_pTempDirName;
     char*		    m_pInputFileProtocol;
     char*		    m_pInputFileSysShortName;
     ULONG32		    m_uOptionFlags;
     ULONG32		    m_uBandwidth;
     ULONG32		    m_ulRateMode;
     ULONG32		    m_ulRateModeInterval;
     ULONG32		    m_ulMinBwThreshold;
     ULONG32		    m_ulMaxBwThreshold;
     ULONG32		    m_ulStartTime;
     ULONG32		    m_ulProcessUntil;
     ULONG32                 m_ulProcessTimeUnits;
     HXBOOL		    m_bUseNuggetFormat;
     HXBOOL		    m_bBandwidthExplicitlySet;
     HXBOOL		    m_bStartTimeExplicitlySet;
     HXBOOL		    m_bParseSDP;
     ULONG32		    m_uServerMode;
     ULONG32		    m_ulContextEvents;
     ULONG32		    m_ulGetPacketEvents;
     LONG32		    m_lTimerValue;
     ULONG32		    m_ulRotationSize;
+    ULONG32                 m_ulMetaDataFlavor;
     HXBOOL		    m_bStop;
     HXBOOL		    m_bSoftStop;
     HXBOOL		    m_bAwaitingFirstNonLostPacket;
     HXBOOL		    m_bPacketReady;
     HXBOOL		    m_bPadToSize;
     ULONG32		    m_ulTargetSize;
     ULONG32		    m_ulMediaSize;
     IHXPacket*		    m_pLastWrittenPacket;
     IHXValues*		    m_pLastWrittenFileHeader;
     IHXPacket**		    m_pDupPacketTrackerList;
     HXBOOL		    m_bPersistentContext;
     UINT32		    m_ulStartTS;
     UINT32		    m_ulStartTick;
     UINT32		    m_ulProcessingRate;
     HXBOOL		    m_bLiveSource;
     HXBOOL		    m_bTerminated;
 
     CHXMemProbe		    *m_pMemProbeArray;
 
 
 #ifdef HELIX_FEATURE_DTDR_USE_RECOGNIZER
 public:
     STDMETHOD(GetMimeTypeDone)(THIS_ HX_RESULT status, IHXBuffer* pMimeType);
 private:
     IHXFileRecognizer*      m_pFileRecognizer;
     CHXString               m_strMimeType;
 #endif
     HXBOOL                  m_bUseFileRecognition;
datatype_tools_metaeditor.diff (text/x-patch, 61.6 KB)
Index: Umakefil
===================================================================
RCS file: /cvsroot/datatype/tools/metaeditor/Umakefil,v
retrieving revision 1.1
diff -d -H -b -B -w -U30 -r1.1 Umakefil
--- Umakefil	5 Nov 2007 22:29:46 -0000	1.1
+++ Umakefil	19 Oct 2009 17:43:48 -0000
@@ -1,54 +1,89 @@
 # 
 # ***** BEGIN LICENSE BLOCK *****
-# Source last modified: $Id: Umakefil,v 1.1 2007/11/05 22:29:46 pbasic Exp $
+# Source last modified: $Id: Umakefil_dll,v 1.2 2007/11/06 11:15:54 pbasic Exp $
 # 
 # Portions Copyright (c) 1995-2007 RealNetworks, Inc. All Rights Reserved.
 # 
 # The contents of this file, and the files included with this file,
 # are subject to the current version of the RealNetworks Public
 # Source License (the "RPSL") available at
 # http://www.helixcommunity.org/content/rpsl unless you have licensed
 # the file under the current version of the RealNetworks Community
 # Source License (the "RCSL") available at
 # http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 # will apply. You may also obtain the license terms directly from
 # RealNetworks.  You may not use this file except in compliance with
 # the RPSL or, if you have a valid RCSL with RealNetworks applicable
 # to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 # the rights, obligations and limitations governing use of the
 # contents of the file.
 # 
 # Alternatively, the contents of this file may be used under the
 # terms of the GNU General Public License Version 2 (the
 # "GPL") in which case the provisions of the GPL are applicable
 # instead of those above. If you wish to allow use of your version of
 # this file only under the terms of the GPL, and not to allow others
 # to use your version of this file under the terms of either the RPSL
 # or RCSL, indicate your decision by deleting the provisions above
 # and replace them with the notice and other provisions required by
 # the GPL. If you do not delete the provisions above, a recipient may
 # use your version of this file under the terms of any one of the
 # RPSL, the RCSL or the GPL.
 # 
 # This file is part of the Helix DNA Technology. RealNetworks is the
 # developer of the Original Code and owns the copyrights in the
 # portions it created.
 # 
 # This file, and the files included with this file, is distributed
 # and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 # KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 # ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 # ENJOYMENT OR NON-INFRINGEMENT.
 # 
 # Technology Compatibility Kit Test Suite(s) Location:
 #    http://www.helixcommunity.org/content/tck
 # 
 # Contributor(s):
 # 
 # ***** END LICENSE BLOCK *****
 # 
 
 UmakefileVersion(2,2)
 
-MultiTargetMake("Umakefil_3gp_lib", "Umakefil_dll")
+project.AddModuleIncludes("common/include",
+                          "datatype/tools/dtdriver/engine/pub",
+                          "datatype/tools/minicntx/pub",
+                          "common/system/pub",
+                          "common/container/pub",
+                          "common/dbgtool/pub",
+                          "common/util/pub",
+                          "common/fileio/pub",
+                          "datatype/include",
+                          "datatype/common/util/pub",
+                          "client/common/system/pub",
+                          "client/core",
+                          "client/core/pub")
+
+project.AddModuleLibraries( "client/common/container[contclntlib]",
+			    "client/common/system[sysclntlib]",
+			    "client/common/util[utlclntlib]",
+                            "common/runtime[runtlib]",
+			    "common/dbgtool[debuglib]", 
+			    "common/util[utillib]", 
+			    "common/container[contlib]",
+			    "common/system[syslib]",
+			    "common/fileio[fileiolib]",
+			    "common/log/logutil[logutillib]",
+                "datatype/common/util[dtutillib]")
+
+project.AddSources('srchandler.cpp',
+                   'editor.cpp',
+                   'hxdll.cpp',
+                   'dlliids.cpp')
+
+project.ExportFunction("RMACreateInstance", "IUnknown** ppObj", "common/include", "hxcom.h")
+project.ExportFunction("CanUnload2", "void")
+
+DLLTarget('metaeditor')
+DependTarget()
Index: Umakefil_3gp_lib
===================================================================
RCS file: Umakefil_3gp_lib
diff -N Umakefil_3gp_lib
--- Umakefil_3gp_lib	6 Nov 2007 11:15:54 -0000	1.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,57 +0,0 @@
-# 
-# ***** BEGIN LICENSE BLOCK ***** 
-# Version: RCSL 1.0/RPSL 1.0 
-#  
-# Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
-#      
-# The contents of this file, and the files included with this file, are 
-# subject to the current version of the RealNetworks Public Source License 
-# Version 1.0 (the "RPSL") available at 
-# http://www.helixcommunity.org/content/rpsl unless you have licensed 
-# the file under the RealNetworks Community Source License Version 1.0 
-# (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
-# in which case the RCSL will apply. You may also obtain the license terms 
-# directly from RealNetworks.  You may not use this file except in 
-# compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
-# applicable to this file, the RCSL.  Please see the applicable RPSL or 
-# RCSL for the rights, obligations and limitations governing use of the 
-# contents of the file.  
-#  
-# This file is part of the Helix DNA Technology. RealNetworks is the 
-# developer of the Original Code and owns the copyrights in the portions 
-# it created. 
-#  
-# This file, and the files included with this file, is distributed and made 
-# available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
-# EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
-# FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
-# 
-# Technology Compatibility Kit Test Suite(s) Location: 
-#    http://www.helixcommunity.org/content/tck 
-# 
-# Contributor(s): 
-#  
-# ***** END LICENSE BLOCK ***** 
-# 
-
-UmakefileVersion(2,0)
-
-project.AddModuleIncludes("common/include",
-                          "datatype/include")
-
-project.AddModuleLibraries( "client/common/container[contclntlib]",
-			    "client/common/system[sysclntlib]",
-			    "client/common/util[utlclntlib]",
-                            "common/runtime[runtlib]",
-			    "common/dbgtool[debuglib]", 
-			    "common/util[utillib]", 
-			    "common/container[contlib]",
-			    "common/system[syslib]",
-			    "common/log/logutil[logutillib]")
-
-project.AddSources("metautil3gp.cpp")
-
-LibraryTarget("metautil3gplib")
-
-DependTarget()
Index: Umakefil_dll
===================================================================
RCS file: Umakefil_dll
diff -N Umakefil_dll
--- Umakefil_dll	6 Nov 2007 11:15:54 -0000	1.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,89 +0,0 @@
-# 
-# ***** BEGIN LICENSE BLOCK *****
-# Source last modified: $Id: Umakefil_dll,v 1.2 2007/11/06 11:15:54 pbasic Exp $
-# 
-# Portions Copyright (c) 1995-2007 RealNetworks, Inc. All Rights Reserved.
-# 
-# The contents of this file, and the files included with this file,
-# are subject to the current version of the RealNetworks Public
-# Source License (the "RPSL") available at
-# http://www.helixcommunity.org/content/rpsl unless you have licensed
-# the file under the current version of the RealNetworks Community
-# Source License (the "RCSL") available at
-# http://www.helixcommunity.org/content/rcsl, in which case the RCSL
-# will apply. You may also obtain the license terms directly from
-# RealNetworks.  You may not use this file except in compliance with
-# the RPSL or, if you have a valid RCSL with RealNetworks applicable
-# to this file, the RCSL.  Please see the applicable RPSL or RCSL for
-# the rights, obligations and limitations governing use of the
-# contents of the file.
-# 
-# Alternatively, the contents of this file may be used under the
-# terms of the GNU General Public License Version 2 (the
-# "GPL") in which case the provisions of the GPL are applicable
-# instead of those above. If you wish to allow use of your version of
-# this file only under the terms of the GPL, and not to allow others
-# to use your version of this file under the terms of either the RPSL
-# or RCSL, indicate your decision by deleting the provisions above
-# and replace them with the notice and other provisions required by
-# the GPL. If you do not delete the provisions above, a recipient may
-# use your version of this file under the terms of any one of the
-# RPSL, the RCSL or the GPL.
-# 
-# This file is part of the Helix DNA Technology. RealNetworks is the
-# developer of the Original Code and owns the copyrights in the
-# portions it created.
-# 
-# This file, and the files included with this file, is distributed
-# and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
-# KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
-# ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
-# ENJOYMENT OR NON-INFRINGEMENT.
-# 
-# Technology Compatibility Kit Test Suite(s) Location:
-#    http://www.helixcommunity.org/content/tck
-# 
-# Contributor(s):
-# 
-# ***** END LICENSE BLOCK *****
-# 
-
-UmakefileVersion(2,2)
-
-project.AddModuleIncludes("common/include",
-                          "datatype/tools/dtdriver/engine/pub",
-                          "datatype/tools/minicntx/pub",
-                          "common/system/pub",
-                          "common/container/pub",
-                          "common/dbgtool/pub",
-                          "common/util/pub",
-                          "common/fileio/pub",
-                          "datatype/include",
-                          "client/common/system/pub",
-                          "client/core",
-                          "client/core/pub")
-
-project.AddModuleLibraries( "client/common/container[contclntlib]",
-			    "client/common/system[sysclntlib]",
-			    "client/common/util[utlclntlib]",
-                            "common/runtime[runtlib]",
-			    "common/dbgtool[debuglib]", 
-			    "common/util[utillib]", 
-			    "common/container[contlib]",
-			    "common/system[syslib]",
-			    "common/fileio[fileiolib]",
-			    "common/log/logutil[logutillib]")
-
-project.AddModuleLibraries("datatype/tools/metaeditor[metautil3gplib]")
-
-project.AddSources('srchandler.cpp',
-                   'editor.cpp',
-                   'hxdll.cpp',
-                   'dlliids.cpp')
-
-project.ExportFunction("RMACreateInstance", "IUnknown** ppObj", "common/include", "hxcom.h")
-project.ExportFunction("CanUnload2", "void")
-
-DLLTarget('metaeditor')
-DependTarget()
Index: metautil3gp.cpp
===================================================================
RCS file: metautil3gp.cpp
diff -N metautil3gp.cpp
--- metautil3gp.cpp	5 Nov 2007 22:29:46 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,878 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK ***** 
- * Version: RCSL 1.0/RPSL 1.0 
- *  
- * Portions Copyright (c) 1995-2007 RealNetworks, Inc. All Rights Reserved. 
- *      
- * The contents of this file, and the files included with this file, are 
- * subject to the current version of the RealNetworks Public Source License 
- * Version 1.0 (the "RPSL") available at 
- * http://www.helixcommunity.org/content/rpsl unless you have licensed 
- * the file under the RealNetworks Community Source License Version 1.0 
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
- * in which case the RCSL will apply. You may also obtain the license terms 
- * directly from RealNetworks.  You may not use this file except in 
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
- * applicable to this file, the RCSL.  Please see the applicable RPSL or 
- * RCSL for the rights, obligations and limitations governing use of the 
- * contents of the file.  
- *  
- * This file is part of the Helix DNA Technology. RealNetworks is the 
- * developer of the Original Code and owns the copyrights in the portions 
- * it created. 
- *  
- * This file, and the files included with this file, is distributed and made 
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
- * 
- * Technology Compatibility Kit Test Suite(s) Location: 
- *    http://www.helixcommunity.org/content/tck 
- * 
- * Contributor(s): 
- *  
- * ***** END LICENSE BLOCK ***** */ 
-
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "hxsrcin.h"
-#include "hlxclib/time.h"
-#include "hxtypes.h"
-#include "hxmemprb.h"
-#include "hxtick.h"
-#include "chxpckts.h"
-#include "pckunpck.h"
-#include "metainfokeys.h"
-#include "iso639.h"
-#include "encstr.h"
-#include "proptools.h"
-
-#include "metautil3gp.h"
-
-
-HX_RESULT RemoveKeywordProperties_MetaInfo3GP(IHXValues* pValues)
-{
-    HX_RESULT retVal = HXR_OK;
-
-    UINT32 ulKeywordCount = 0;
-    if(PropTools::CopyPropertyULONG32(ulKeywordCount, pValues, _3GPP_META_INFO_KEYWORD_COUNT_KEY))
-    {
-        PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_KEYWORD_COUNT_KEY);
-
-        for(UINT32 i = 0; i < ulKeywordCount; i++)
-        {
-            char key[128];
-            sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
-            PropTools::RemovePropertyBuffer(retVal, pValues, key);
-        }
-    }
-    return retVal;
-}
-
-HX_RESULT RemoveAllProperties_MetaInfo3GP(IHXValues* pValues)
-{
-    HX_RESULT retVal = HXR_OK;
-
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_TITLE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_AUTHOR_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_COPYRIGHT_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_DESCRIPTION_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_PERFORMER_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_GENRE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_RATING_ENTITY_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_RATING_CRITERIA_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_RATING_INFO_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY);
-    PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_NAME_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY);
-    PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_LOCATION_ROLE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_LATITUDE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY);
-    PropTools::RemovePropertyBuffer(retVal, pValues, _3GPP_META_INFO_ALBUM_TITLE_KEY);
-    PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_TRACK_NUMBER_KEY);
-    PropTools::RemovePropertyULONG32(retVal, pValues, _3GPP_META_INFO_RECORDING_YEAR_KEY);
-
-    if(SUCCEEDED(retVal))
-    {
-        retVal = RemoveKeywordProperties_MetaInfo3GP(pValues);
-    }
-    return retVal;
-}
-
-HX_RESULT CopyKeywordProperties_MetaInfo3GP(IHXValues* dst, IHXValues* src, BOOL bBlast)
-{
-    HX_RESULT retVal = HXR_OK;
-
-    UINT32 ulKeywordCount = 0;
-    if(PropTools::CopyPropertyULONG32(ulKeywordCount, src, _3GPP_META_INFO_KEYWORD_COUNT_KEY))
-    {
-        retVal = RemoveKeywordProperties_MetaInfo3GP(dst);
-
-        PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_KEYWORD_COUNT_KEY, TRUE);
-        for(UINT32 i = 0; i < ulKeywordCount; i++)
-        {
-            if(SUCCEEDED(retVal))
-            {
-                char key[128];
-                sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
-                PropTools::CopyPropertyBuffer(retVal, dst, src, key, TRUE);
-            }
-        }
-    }
-    else if(bBlast)
-    {
-        retVal = RemoveKeywordProperties_MetaInfo3GP(dst);
-    }
-    return retVal;
-}
-
-HX_RESULT CopyAllProperties_MetaInfo3GP(IHXValues* dst, IHXValues* src, BOOL bBlast)
-{
-    HX_RESULT retVal = HXR_OK;
-
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_TITLE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_AUTHOR_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_COPYRIGHT_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_DESCRIPTION_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_PERFORMER_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_GENRE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_RATING_ENTITY_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_RATING_CRITERIA_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_RATING_INFO_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, bBlast);
-    PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_NAME_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, bBlast);
-    PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_LOCATION_ROLE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_LATITUDE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY, bBlast);
-    PropTools::CopyPropertyBuffer(retVal, dst, src, _3GPP_META_INFO_ALBUM_TITLE_KEY, bBlast);
-    PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_TRACK_NUMBER_KEY, bBlast);
-    PropTools::CopyPropertyULONG32(retVal, dst, src, _3GPP_META_INFO_RECORDING_YEAR_KEY, bBlast);
-
-    if(SUCCEEDED(retVal))
-    {
-        retVal = CopyKeywordProperties_MetaInfo3GP(dst, src, bBlast);
-    }
-    return retVal;
-}
-
-MetaInfo3GP::MetaInfo3GP()
-{
-    Clear();
-}
-
-MetaInfo3GP::~MetaInfo3GP()
-{
-    ClearKeywords();
-}
-
-MetaInfo3GP::MetaInfo3GP(const MetaInfo3GP& rhs)
-{
-    *this = rhs;
-}
-
-MetaInfo3GP& MetaInfo3GP::operator=(const MetaInfo3GP& rhs)
-{
-    Clear();
-    Update(rhs);
-    return *this;
-}
-
-void MetaInfo3GP::Dump()
-{
-    Dump("GlobalLanguageEncoding", m_sGlobalLanguageEncoding);
-    Dump("Title", m_sTitle);
-    Dump("Author", m_sAuthor);
-    Dump("Copyright", m_sCopyright);
-    Dump("Description", m_sDescription);
-    Dump("Performer", m_sPerformer);
-    Dump("Genre", m_sGenre);
-    Dump("RatingEntity", m_sRatingEntity);
-    Dump("RatingCriteria", m_sRatingCriteria);
-    Dump("RatingInfo", m_sRatingInfo);
-    Dump("ClassificationEntity", m_sClassificationEntity);
-    Dump("ClassificationTable", m_uClassificationTable, m_bValidClassificationTable);
-    Dump("ClassificationInfo", m_sClassificationInfo);
-
-    for(UINT32 i = 0; i < GetKeywordCount(); i++)
-    {
-        printf("Keyword%d: ", int(i));
-        EncodedString kwd;
-        GetKeyword(i, kwd);
-        kwd.Dump();
-        printf("\n");
-    }
-    Dump("LocationName", m_sLocationName);
-    Dump("LocationAstronomicalBody", m_sLocationAstronomicalBody);
-    Dump("LocationAdditionalNotes", m_sLocationAdditionalNotes);
-    Dump("LocationRole", m_uLocationRole, m_bValidLocationRole);
-    Dump("LocationLongitude", m_sLocationLongitude);
-    Dump("LocationLatitude", m_sLocationLatitude);
-    Dump("LocationAltitude", m_sLocationAltitude);
-    Dump("AlbumTitle", m_sAlbumTitle);
-    Dump("AlbumTrackNumber", m_uAlbumTrackNumber, m_bValidAlbumTrackNumber);
-    Dump("RecordingYear", m_uRecordingYear, m_bValidRecordingYear);
-}
-
-void MetaInfo3GP::Clear()
-{
-    m_sGlobalLanguageEncoding.Clear();
-    m_sTitle.Clear();
-    m_sAuthor.Clear();
-    m_sCopyright.Clear();
-    m_sDescription.Clear();
-    m_sPerformer.Clear();
-    m_sGenre.Clear();
-    m_sRatingEntity.Clear();
-    m_sRatingCriteria.Clear();
-    m_sRatingInfo.Clear();
-    m_sClassificationEntity.Clear();
-    m_bValidClassificationTable = FALSE;
-    m_uClassificationTable = 0;
-    m_sClassificationInfo.Clear();
-    ClearKeywords();
-    m_sLocationName.Clear();
-    m_sLocationAstronomicalBody.Clear();
-    m_sLocationAdditionalNotes.Clear();
-    m_bValidLocationRole = FALSE;
-    m_uLocationRole = 0;
-    m_sLocationLongitude.Clear();
-    m_sLocationLatitude.Clear();
-    m_sLocationAltitude.Clear();
-    m_sAlbumTitle.Clear();
-    m_bValidAlbumTrackNumber = FALSE;
-    m_uAlbumTrackNumber = 0;
-    m_bValidRecordingYear = FALSE;
-    m_uRecordingYear = 0;
-}
-
-void MetaInfo3GP::Update(const MetaInfo3GP& src)
-{
-    Update(m_sGlobalLanguageEncoding, src.m_sGlobalLanguageEncoding);
-    Update(m_sTitle, src.m_sTitle);
-    Update(m_sAuthor, src.m_sAuthor);
-    Update(m_sCopyright, src.m_sCopyright);
-    Update(m_sDescription, src.m_sDescription);
-    Update(m_sPerformer, src.m_sPerformer);
-    Update(m_sGenre, src.m_sGenre);
-    Update(m_sRatingEntity, src.m_sRatingEntity);
-    Update(m_sRatingCriteria, src.m_sRatingCriteria);
-    Update(m_sRatingInfo, src.m_sRatingInfo);
-    Update(m_sClassificationEntity, src.m_sClassificationEntity);
-    Update(m_uClassificationTable, m_bValidClassificationTable, src.m_uClassificationTable, src.m_bValidClassificationTable);
-    Update(m_sClassificationInfo, src.m_sClassificationInfo);
-    Update(m_sLocationName, src.m_sLocationName);
-    Update(m_sLocationAstronomicalBody, src.m_sLocationAstronomicalBody);
-    Update(m_sLocationAdditionalNotes, src.m_sLocationAdditionalNotes);
-    Update(m_uLocationRole, m_bValidLocationRole, src.m_uLocationRole, src.m_bValidLocationRole);
-    Update(m_sLocationLongitude, src.m_sLocationLongitude);
-    Update(m_sLocationLatitude, src.m_sLocationLatitude);
-    Update(m_sLocationAltitude, src.m_sLocationAltitude);
-    Update(m_sAlbumTitle, src.m_sAlbumTitle);
-    Update(m_uAlbumTrackNumber, m_bValidAlbumTrackNumber, src.m_uAlbumTrackNumber, src.m_bValidAlbumTrackNumber);
-    Update(m_uRecordingYear, m_bValidRecordingYear, src.m_uRecordingYear, src.m_bValidRecordingYear);
-
-    for(UINT32 i = 0; i < src.GetKeywordCount(); i++)
-    {
-        EncodedString sTmp;
-        src.GetKeyword(i, sTmp);
-        AddKeyword(sTmp);
-    }
-}
-
-void MetaInfo3GP::CopyToValues(IHXValues* pValues) const
-{
-    if(!pValues)
-    {
-        return;
-    }
-    CopyString(pValues, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, &MetaInfo3GP::GetGlobalLanguageEncoding);
-    CopyString(pValues, _3GPP_META_INFO_TITLE_KEY, &MetaInfo3GP::GetTitle);
-    CopyString(pValues, _3GPP_META_INFO_AUTHOR_KEY, &MetaInfo3GP::GetAuthor);
-    CopyString(pValues, _3GPP_META_INFO_COPYRIGHT_KEY, &MetaInfo3GP::GetCopyright);
-    CopyString(pValues, _3GPP_META_INFO_DESCRIPTION_KEY, &MetaInfo3GP::GetDescription);
-    CopyString(pValues, _3GPP_META_INFO_PERFORMER_KEY, &MetaInfo3GP::GetPerformer);
-    CopyString(pValues, _3GPP_META_INFO_GENRE_KEY, &MetaInfo3GP::GetGenre);
-    CopyString(pValues, _3GPP_META_INFO_RATING_ENTITY_KEY, &MetaInfo3GP::GetRatingEntity);
-    CopyString(pValues, _3GPP_META_INFO_RATING_CRITERIA_KEY, &MetaInfo3GP::GetRatingCriteria);
-    CopyString(pValues, _3GPP_META_INFO_RATING_INFO_KEY, &MetaInfo3GP::GetRatingInfo);
-    CopyString(pValues, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, &MetaInfo3GP::GetClassificationEntity);
-    CopyULONG32(pValues, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, &MetaInfo3GP::GetClassificationTable);
-    CopyString(pValues, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY, &MetaInfo3GP::GetClassificationInfo);
-    CopyString(pValues, _3GPP_META_INFO_LOCATION_NAME_KEY, &MetaInfo3GP::GetLocationName);
-    CopyString(pValues, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, &MetaInfo3GP::GetLocationAstronomicalBody);
-    CopyString(pValues, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, &MetaInfo3GP::GetLocationAdditionalNotes);
-    CopyULONG32(pValues, _3GPP_META_INFO_LOCATION_ROLE_KEY, &MetaInfo3GP::GetLocationRole);
-    CopyString(pValues, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY, &MetaInfo3GP::GetLocationLongitude);
-    CopyString(pValues, _3GPP_META_INFO_LOCATION_LATITUDE_KEY, &MetaInfo3GP::GetLocationLatitude);
-    CopyString(pValues, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY, &MetaInfo3GP::GetLocationAltitude);
-    CopyString(pValues, _3GPP_META_INFO_ALBUM_TITLE_KEY, &MetaInfo3GP::GetAlbumTitle);
-    CopyULONG32(pValues, _3GPP_META_INFO_TRACK_NUMBER_KEY, &MetaInfo3GP::GetAlbumTrackNumber);
-    CopyULONG32(pValues, _3GPP_META_INFO_RECORDING_YEAR_KEY, &MetaInfo3GP::GetRecordingYear);
-
-    // keyword section
-    EncodedString sTmp;
-    UINT32 ulKeywordCount = GetKeywordCount();
-    if(ulKeywordCount)
-    {
-        PropTools::CopyPropertyULONG32(pValues, TRUE, ULONG32(ulKeywordCount),
-                                            _3GPP_META_INFO_KEYWORD_COUNT_KEY, TRUE);
-        for(UINT32 i = 0; i < ulKeywordCount; i++)
-        {
-            char key[128];
-            sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
-            GetKeyword(i, sTmp);
-            PropTools::CopyPropertyBuffer(pValues, sTmp, key, TRUE);
-        }
-    }
-}
-
-void MetaInfo3GP::CopyFromValues(IHXValues* pValues)
-{
-    if(! pValues)
-    {
-        return;
-    }
-    CopyString(&MetaInfo3GP::SetGlobalLanguageEncoding, pValues, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY);
-    CopyString(&MetaInfo3GP::SetTitle, pValues, _3GPP_META_INFO_TITLE_KEY);
-    CopyString(&MetaInfo3GP::SetAuthor, pValues, _3GPP_META_INFO_AUTHOR_KEY);
-    CopyString(&MetaInfo3GP::SetCopyright, pValues, _3GPP_META_INFO_COPYRIGHT_KEY);
-    CopyString(&MetaInfo3GP::SetDescription, pValues, _3GPP_META_INFO_DESCRIPTION_KEY);
-    CopyString(&MetaInfo3GP::SetPerformer, pValues, _3GPP_META_INFO_PERFORMER_KEY);
-    CopyString(&MetaInfo3GP::SetGenre, pValues, _3GPP_META_INFO_GENRE_KEY);
-    CopyString(&MetaInfo3GP::SetRatingEntity, pValues, _3GPP_META_INFO_RATING_ENTITY_KEY);
-    CopyString(&MetaInfo3GP::SetRatingCriteria, pValues, _3GPP_META_INFO_RATING_CRITERIA_KEY);
-    CopyString(&MetaInfo3GP::SetRatingInfo, pValues, _3GPP_META_INFO_RATING_INFO_KEY);
-    CopyString(&MetaInfo3GP::SetClassificationEntity, pValues, _3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY);
-    CopyULONG32(&MetaInfo3GP::SetClassificationTable, pValues, _3GPP_META_INFO_CLASSIFICATION_TABLE_KEY);
-    CopyString(&MetaInfo3GP::SetClassificationInfo, pValues, _3GPP_META_INFO_CLASSIFICATION_INFO_KEY);
-    CopyString(&MetaInfo3GP::SetLocationName, pValues, _3GPP_META_INFO_LOCATION_NAME_KEY);
-    CopyString(&MetaInfo3GP::SetLocationAstronomicalBody, pValues, _3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY);
-    CopyString(&MetaInfo3GP::SetLocationAdditionalNotes, pValues, _3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY);
-    CopyULONG32(&MetaInfo3GP::SetLocationRole, pValues, _3GPP_META_INFO_LOCATION_ROLE_KEY);
-    CopyString(&MetaInfo3GP::SetLocationLongitude, pValues, _3GPP_META_INFO_LOCATION_LONGITUDE_KEY);
-    CopyString(&MetaInfo3GP::SetLocationLatitude, pValues, _3GPP_META_INFO_LOCATION_LATITUDE_KEY);
-    CopyString(&MetaInfo3GP::SetLocationAltitude, pValues, _3GPP_META_INFO_LOCATION_ALTITUDE_KEY);
-    CopyString(&MetaInfo3GP::SetAlbumTitle, pValues, _3GPP_META_INFO_ALBUM_TITLE_KEY);
-    CopyULONG32(&MetaInfo3GP::SetAlbumTrackNumber, pValues, _3GPP_META_INFO_TRACK_NUMBER_KEY);
-    CopyULONG32(&MetaInfo3GP::SetRecordingYear, pValues, _3GPP_META_INFO_RECORDING_YEAR_KEY);
-
-    // keyword section
-    EncodedString sTmp;
-    ULONG32 ulKeywordCount = 0;
-    if(PropTools::CopyPropertyULONG32(ulKeywordCount, pValues, _3GPP_META_INFO_KEYWORD_COUNT_KEY))
-    {
-        for(UINT32 i = 0; i < ulKeywordCount; i++)
-        {
-            char key[128];
-            sprintf(key, _3GPP_META_INFO_KEYWORD_KEY, int(i));
-            if(PropTools::CopyPropertyBuffer(sTmp, pValues, key))
-            {
-                AddKeyword(sTmp);
-            }
-        }
-    }
-    RemoveKeywordDuplicates();
-}
-
-BOOL MetaInfo3GP::GetGlobalLanguageEncoding(EncodedString& out) const
-{
-    return GetString(m_sGlobalLanguageEncoding, out);
-}
-
-BOOL MetaInfo3GP::SetGlobalLanguageEncoding(const EncodedString& val)
-{
-    if(!val.IsAsciiOnly() || (val.GetCodeUnitLength(FALSE, FALSE) != 3))
-    {
-        return FALSE;
-    }
-    EncodedString valConv;
-    val.ConvertToUTF8(valConv);
-    if(!val.GetData())
-    {
-        return FALSE;
-    }
-    CHXISO639LangCodeRegistry lcreg;
-    if(!lcreg.IsValidLangCode(valConv.GetData()))
-    {
-        return FALSE;
-    }
-    return SetString(m_sGlobalLanguageEncoding, valConv);
-}
-
-BOOL MetaInfo3GP::GetTitle(EncodedString& out) const
-{
-    return GetString(m_sTitle, out);
-}
-
-BOOL MetaInfo3GP::SetTitle(const EncodedString& val)
-{
-    return SetString(m_sTitle, val);
-}
-
-BOOL MetaInfo3GP::GetAuthor(EncodedString& out) const
-{
-    return GetString(m_sAuthor, out);
-}
-
-BOOL MetaInfo3GP::SetAuthor(const EncodedString& val)
-{
-    return SetString(m_sAuthor, val);
-}
-
-BOOL MetaInfo3GP::GetCopyright(EncodedString& out) const
-{
-    return GetString(m_sCopyright, out);
-}
-
-BOOL MetaInfo3GP::SetCopyright(const EncodedString& val)
-{
-    return SetString(m_sCopyright, val);
-}
-
-BOOL MetaInfo3GP::GetDescription(EncodedString& out) const
-{
-    return GetString(m_sDescription, out);
-}
-
-BOOL MetaInfo3GP::SetDescription(const EncodedString& val)
-{
-    return SetString(m_sDescription, val);
-}
-
-BOOL MetaInfo3GP::GetPerformer(EncodedString& out) const
-{
-    return GetString(m_sPerformer, out);
-}
-
-BOOL MetaInfo3GP::SetPerformer(const EncodedString& val)
-{
-    return SetString(m_sPerformer, val);
-}
-
-BOOL MetaInfo3GP::GetGenre(EncodedString& out) const
-{
-    return GetString(m_sGenre, out);
-}
-
-BOOL MetaInfo3GP::SetGenre(const EncodedString& val)
-{
-    return SetString(m_sGenre, val);
-}
-
-BOOL MetaInfo3GP::GetRatingEntity(EncodedString& out) const
-{
-    return GetString(m_sRatingEntity, out);
-}
-
-BOOL MetaInfo3GP::SetRatingEntity(const EncodedString& val)
-{
-    return MetaInfo3GP::SetStringAsciiMaxLen(m_sRatingEntity, val, 4);
-}
-
-BOOL MetaInfo3GP::GetRatingCriteria(EncodedString& out) const
-{
-    return GetString(m_sRatingCriteria, out);
-}
-
-BOOL MetaInfo3GP::SetRatingCriteria(const EncodedString& val)
-{
-    return MetaInfo3GP::SetStringAsciiMaxLen(m_sRatingCriteria, val, 4);
-}
-
-BOOL MetaInfo3GP::GetRatingInfo(EncodedString& out) const
-{
-    return GetString(m_sRatingInfo, out);
-}
-
-BOOL MetaInfo3GP::SetRatingInfo(const EncodedString& val)
-{
-    return SetString(m_sRatingInfo, val);
-}
-
-BOOL MetaInfo3GP::GetClassificationEntity(EncodedString& out) const
-{
-    return GetString(m_sClassificationEntity, out);
-}
-
-BOOL MetaInfo3GP::SetClassificationEntity(const EncodedString& val)
-{
-    return MetaInfo3GP::SetStringAsciiMaxLen(m_sClassificationEntity, val, 4);
-}
-
-BOOL MetaInfo3GP::GetClassificationTable(UINT16& out) const
-{
-    return GetUINT16(m_uClassificationTable, m_bValidClassificationTable, out);
-}
-
-BOOL MetaInfo3GP::SetClassificationTable(UINT16 val, BOOL bValid)
-{
-    return SetUINT16(m_uClassificationTable, m_bValidClassificationTable, val, bValid);
-}
-
-BOOL MetaInfo3GP::GetClassificationInfo(EncodedString& out) const
-{
-    return GetString(m_sClassificationInfo, out);
-}
-
-BOOL MetaInfo3GP::SetClassificationInfo(const EncodedString& val)
-{
-    return SetString(m_sClassificationInfo, val);
-}
-
-UINT32 MetaInfo3GP::GetKeywordCount() const
-{
-    return (UINT32)m_aKeywords.GetSize();
-}
-
-BOOL MetaInfo3GP::GetKeyword(UINT32 index, EncodedString& out) const
-{
-    INT32 idx = INT32(index);
-    if(idx < m_aKeywords.GetSize())
-    {
-        out = *((EncodedString*)m_aKeywords[idx]);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-void MetaInfo3GP::ClearKeywords()
-{
-    ClearPropertyStringArray(m_aKeywords);
-}
-
-BOOL MetaInfo3GP::AddKeyword(const EncodedString& val)
-{
-    if(val.GetByteLength() > 255)
-    {
-        return FALSE;
-    }
-    for(INT32 i = 0; i < m_aKeywords.GetSize(); i++)
-    {
-        if(*((EncodedString*)m_aKeywords[i]) == val)
-        {
-            return TRUE;
-        }
-    }
-    m_aKeywords.Add(new EncodedString(val));
-    return TRUE;
-}
-
-void MetaInfo3GP::RemoveKeyword(const EncodedString& val)
-{
-    for(INT32 i = 0; i < m_aKeywords.GetSize(); i++)
-    {
-        EncodedString* s = (EncodedString*)m_aKeywords[i];
-        if(*s == val)
-        {
-            delete s;
-            // Remaining keywords are shifted to fill the hole,
-            // search index must stay the same for new iteration.
-            m_aKeywords.RemoveAt(i--, 1);
-        }
-    }
-}
-
-void MetaInfo3GP::RemoveKeywordDuplicates()
-{
-    CHXPtrArray aTmpKeywords;
-    for(INT32 i = 0; i < m_aKeywords.GetSize(); i++)
-    {
-        aTmpKeywords.Add(new EncodedString(*((EncodedString*)m_aKeywords[i])));
-    }
-    ClearPropertyStringArray(m_aKeywords);
-    for(INT32 i = 0; i < aTmpKeywords.GetSize(); i++)
-    {
-        AddKeyword(*((EncodedString*)aTmpKeywords[i]));
-    }
-    ClearPropertyStringArray(aTmpKeywords);
-}
-
-BOOL MetaInfo3GP::GetLocationName(EncodedString& out) const
-{
-    return GetString(m_sLocationName, out);
-}
-
-BOOL MetaInfo3GP::SetLocationName(const EncodedString& val)
-{
-    return SetString(m_sLocationName, val);
-}
-
-BOOL MetaInfo3GP::GetLocationAstronomicalBody(EncodedString& out) const
-{
-    return GetString(m_sLocationAstronomicalBody, out);
-}
-
-BOOL MetaInfo3GP::SetLocationAstronomicalBody(const EncodedString& val)
-{
-    return SetString(m_sLocationAstronomicalBody, val);
-}
-
-BOOL MetaInfo3GP::GetLocationAdditionalNotes(EncodedString& out) const
-{
-    return GetString(m_sLocationAdditionalNotes, out);
-}
-
-BOOL MetaInfo3GP::SetLocationAdditionalNotes(const EncodedString& val)
-{
-    return SetString(m_sLocationAdditionalNotes, val);
-}
-
-BOOL MetaInfo3GP::GetLocationRole(UINT8& out) const
-{
-    return GetUINT8(m_uLocationRole, m_bValidLocationRole, out);
-}
-
-BOOL MetaInfo3GP::SetLocationRole(UINT8 val, BOOL bValid)
-{
-    return SetUINT8(m_uLocationRole, m_bValidLocationRole, val, bValid);
-}
-
-BOOL MetaInfo3GP::GetLocationLongitude(EncodedString& out) const
-{
-    return GetString(m_sLocationLongitude, out);
-}
-
-BOOL MetaInfo3GP::SetLocationLongitude(const EncodedString& val)
-{
-    return SetStringFixedPointNum(m_sLocationLongitude, val);
-}
-
-BOOL MetaInfo3GP::GetLocationLatitude(EncodedString& out) const
-{
-    return GetString(m_sLocationLatitude, out);
-}
-
-BOOL MetaInfo3GP::SetLocationLatitude(const EncodedString& val)
-{
-    return SetStringFixedPointNum(m_sLocationLatitude, val);
-}
-
-BOOL MetaInfo3GP::GetLocationAltitude(EncodedString& out) const
-{
-    return GetString(m_sLocationAltitude, out);
-}
-
-BOOL MetaInfo3GP::SetLocationAltitude(const EncodedString& val)
-{
-    return SetStringFixedPointNum(m_sLocationAltitude, val);
-}
-
-BOOL MetaInfo3GP::GetAlbumTitle(EncodedString& out) const
-{
-    return GetString(m_sAlbumTitle, out);
-}
-
-BOOL MetaInfo3GP::SetAlbumTitle(const EncodedString& val)
-{
-    return SetString(m_sAlbumTitle, val);
-}
-
-BOOL MetaInfo3GP::GetAlbumTrackNumber(UINT8& out) const
-{
-    return GetUINT8(m_uAlbumTrackNumber, m_bValidAlbumTrackNumber, out);
-}
-
-BOOL MetaInfo3GP::SetAlbumTrackNumber(UINT8 val, BOOL bValid)
-{
-    return SetUINT8(m_uAlbumTrackNumber, m_bValidAlbumTrackNumber, val, bValid);
-}
-
-BOOL MetaInfo3GP::GetRecordingYear(UINT16& out) const
-{
-    return GetUINT16(m_uRecordingYear, m_bValidRecordingYear, out);
-}
-
-BOOL MetaInfo3GP::SetRecordingYear(UINT16 val, BOOL bValid)
-{
-    return SetUINT16(m_uRecordingYear, m_bValidRecordingYear, val, bValid);
-}
-
-BOOL MetaInfo3GP::GetString(const EncodedString& src, EncodedString& out)
-{
-    out = src;
-    return !out.IsEmpty();
-}
-
-BOOL MetaInfo3GP::SetString(EncodedString& dst, const EncodedString& val)
-{
-    dst = val;
-    return TRUE;
-}
-
-BOOL MetaInfo3GP::SetStringAsciiMaxLen(EncodedString& dst, const EncodedString& val, UINT32 maxLen)
-{
-    if(!val.IsAsciiOnly() || (val.GetCodeUnitLength(FALSE, FALSE) > maxLen))
-    {
-        return FALSE;
-    }
-    dst = val;
-    return TRUE;
-}
-
-BOOL MetaInfo3GP::SetStringFixedPointNum(EncodedString& dst, const EncodedString& val)
-{
-    EncodedString normVal = val;
-    if(!PropTools::IsFixedPointNumber(normVal, TRUE))
-    {
-        return FALSE;
-    }
-    dst = normVal;
-    return TRUE;
-}
-
-BOOL MetaInfo3GP::GetUINT16(const UINT16& src, const BOOL& srcValid, UINT16& out)
-{
-    out = src;
-    return srcValid;
-}
-
-BOOL MetaInfo3GP::SetUINT16(UINT16& dst, BOOL& dstValid, UINT16 val, BOOL bValid)
-{
-    dst = val;
-    dstValid = bValid;
-    return TRUE;
-}
-
-BOOL MetaInfo3GP::GetUINT8(const UINT8& src, const BOOL& srcValid, UINT8& out)
-{
-    out = src;
-    return srcValid;
-}
-
-BOOL MetaInfo3GP::SetUINT8(UINT8& dst, BOOL& dstValid, UINT8 val, BOOL bValid)
-{
-    dst = val;
-    dstValid = bValid;
-    return TRUE;
-}
-
-void MetaInfo3GP::Update(EncodedString& dst, const EncodedString& src)
-{
-    if(!src.IsEmpty())
-    {
-        dst = src;
-    }
-}
-
-void MetaInfo3GP::Update(UINT16& dst, BOOL& dstValid, const UINT16& src, const BOOL& srcValid)
-{
-    if(srcValid)
-    {
-        dstValid = srcValid;
-        dst = src;
-    }
-}
-
-void MetaInfo3GP::Update(UINT8& dst, BOOL& dstValid, const UINT8& src, const BOOL& srcValid)
-{
-    if(srcValid)
-    {
-        dstValid = srcValid;
-        dst = src;
-    }
-}
-
-void MetaInfo3GP::Dump(const char* propName, const EncodedString& val)
-{
-    if(!val.IsEmpty())
-    {
-        printf("%s: ", propName);
-        val.Dump();
-        printf("\n");
-    }
-}
-
-void MetaInfo3GP::Dump(const char* propName, const UINT16& val, const BOOL& bValid)
-{
-    if(bValid)
-    {
-        printf("%s: %d\n", propName, int(val));
-    }
-}
-
-void MetaInfo3GP::Dump(const char* propName, const UINT8& val, const BOOL& bValid)
-{
-    if(bValid)
-    {
-        printf("%s: %d\n", propName, int(val));
-    }
-}
-
-void MetaInfo3GP::ClearPropertyStringArray(CHXPtrArray& aStrings)
-{
-    for(INT32 i = 0; i < aStrings.GetSize(); i++)
-    {
-        delete (EncodedString*)aStrings[i];
-    }
-    aStrings.RemoveAll();
-}
-
-void MetaInfo3GP::CopyString(MetaInfo3GP::FnStringSetter setter,
-                        IHXValues* pValues, const char* enginePropName)
-{
-    EncodedString sTmp;
-    if(PropTools::CopyPropertyBuffer(sTmp, pValues, enginePropName))
-    {
-        (this->*setter)(sTmp);
-    }
-}
-
-void MetaInfo3GP::CopyULONG32(MetaInfo3GP::FnUINT16Setter setter,
-                         IHXValues* pValues, const char* enginePropName)
-{
-    ULONG32 uTmp;
-    if(PropTools::CopyPropertyULONG32(uTmp, pValues, enginePropName))
-    {
-        (this->*setter)(UINT16(uTmp), TRUE);
-    }
-}
-
-void MetaInfo3GP::CopyULONG32(MetaInfo3GP::FnUINT8Setter setter,
-                         IHXValues* pValues, const char* enginePropName)
-{
-    ULONG32 uTmp;
-    if(PropTools::CopyPropertyULONG32(uTmp, pValues, enginePropName))
-    {
-        (this->*setter)(UINT8(uTmp), TRUE);
-    }
-}
-
-void MetaInfo3GP::CopyString(IHXValues* pValues, const char* enginePropName,
-                         MetaInfo3GP::FnStringGetter getter) const
-{
-    EncodedString sTmp;
-    (this->*getter)(sTmp);
-    PropTools::CopyPropertyBuffer(pValues, sTmp, enginePropName, TRUE);
-}
-
-void MetaInfo3GP::CopyULONG32(IHXValues* pValues, const char* enginePropName,
-                         MetaInfo3GP::FnUINT16Getter getter) const
-{
-    UINT16 uVal = 0;
-    BOOL bValid = (this->*getter)(uVal);
-    PropTools::CopyPropertyULONG32(pValues, bValid, ULONG32(uVal), enginePropName, TRUE);
-}
-
-void MetaInfo3GP::CopyULONG32(IHXValues* pValues, const char* enginePropName,
-                         MetaInfo3GP::FnUINT8Getter getter) const
-{
-    UINT8 uVal = 0;
-    BOOL bValid = (this->*getter)(uVal);
-    PropTools::CopyPropertyULONG32(pValues, bValid, ULONG32(uVal), enginePropName, TRUE);
-}
-
Index: srchandler.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/metaeditor/srchandler.cpp,v
retrieving revision 1.1
diff -d -H -b -B -w -U30 -r1.1 srchandler.cpp
--- srchandler.cpp	5 Nov 2007 22:29:46 -0000	1.1
+++ srchandler.cpp	19 Oct 2009 17:43:48 -0000
@@ -26,75 +26,74 @@
  * or RCSL, indicate your decision by deleting the provisions above
  * and replace them with the notice and other provisions required by
  * the GPL. If you do not delete the provisions above, a recipient may
  * use your version of this file under the terms of any one of the
  * RPSL, the RCSL or the GPL.
  * 
  * This file is part of the Helix DNA Technology. RealNetworks is the
  * developer of the Original Code and owns the copyrights in the
  * portions it created.
  * 
  * This file, and the files included with this file, is distributed
  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  * ENJOYMENT OR NON-INFRINGEMENT.
  * 
  * Technology Compatibility Kit Test Suite(s) Location:
  *    http://www.helixcommunity.org/content/tck
  * 
  * Contributor(s):
  * 
  * ***** END LICENSE BLOCK ***** */
 
 
 #include "hxtypes.h"
 #include "hxcom.h"
 #include "hxdtdr.h"
 #include "pckunpck.h"
 #include "proptools.h"
+#include "metautil.h"
 
 #include "srchandler.h"
-#include "metautil3gp.h"
 
 
 CSourceHandler::CSourceHandler()
     : m_lRefCount(0)
     , m_pContext(0)
     , m_pSourceSink(0)
     , m_pProcessor(0)
     , m_pExtractedMetaData(0)
     , m_pInjectedMetaData(0)
     , m_pTmpValues(0)
     , m_ulDiscardExtracted(0)
-    , m_eMetaDataFlavor(METADATA_FLAVOR_UNKNOWN)
 {
 }
 
 CSourceHandler::~CSourceHandler()
 {
     HX_RELEASE(m_pContext);
     HX_RELEASE(m_pSourceSink);
     HX_RELEASE(m_pProcessor);
     HX_RELEASE(m_pExtractedMetaData);
     HX_RELEASE(m_pInjectedMetaData);
     HX_RELEASE(m_pTmpValues);
 }
 
 STDMETHODIMP
 CSourceHandler::QueryInterface(REFIID riid, void** ppvObj)
 {
     if(IsEqualIID(riid, IID_IUnknown))
     {
         AddRef();
         *ppvObj = (IUnknown*)this;
         return HXR_OK;
     }
     if(IsEqualIID(riid, IID_IHXSourceInput))
     {
         AddRef();
         *ppvObj = (IHXSourceInput*)(IHXSourceHandler*)this;
         return HXR_OK;
     }
     if(IsEqualIID(riid, IID_IHXSourceHandler))
     {
@@ -120,86 +119,87 @@
 
 STDMETHODIMP_(ULONG32)
 CSourceHandler::Release()
 { 
     if(InterlockedDecrement(&m_lRefCount) > 0)
     {
         return m_lRefCount;
     }
     delete this;
     return 0;
 }
 
 STDMETHODIMP
 CSourceHandler::OnFileHeader(HX_RESULT status, IHXValues* pValues)
 {
     if(!m_pContext)
     {
         return HXR_FAILED;
     }
 
     HX_RESULT retVal = HXR_OK;
 
     // cleanup storage
     PropTools::RemoveAllProperties(retVal, m_pExtractedMetaData);
     PropTools::RemoveAllProperties(retVal, m_pInjectedMetaData);
     PropTools::RemoveAllProperties(retVal, m_pTmpValues);
 
     // collect inbound meta-data
     if(SUCCEEDED(retVal))
     {
-        retVal = ExtractMetaData(m_pExtractedMetaData, pValues);
+        retVal = MetaInfo::CopyAllProperties(m_pExtractedMetaData, pValues, METAINFO_SET_ALL, FALSE);
     }
 
     // collect new meta-data
     if(SUCCEEDED(retVal) && m_pProcessor)
     {
         retVal = m_pProcessor->OnInboundMetaData(m_pExtractedMetaData, m_pTmpValues);
     }
     if(SUCCEEDED(retVal))
     {
-        // filter-out non meta-data
-        retVal = ExtractMetaData(m_pInjectedMetaData, m_pTmpValues);
+        // filter-out non meta-data from injected values
+        retVal = MetaInfo::CopyAllProperties(m_pInjectedMetaData, m_pTmpValues, METAINFO_SET_ALL, FALSE);
     }
 
-    // merge extracted and injected values
+    // merge extracted and injected values into the original storage
     if(m_ulDiscardExtracted)
     {
-        retVal = RemoveMetaData(pValues);
+        retVal = MetaInfo::RemoveAllProperties(pValues, METAINFO_SET_ALL);
     }
     PropTools::CopyAllProperties(retVal, pValues, m_pInjectedMetaData);
 
     // construct copy of outbound meta-data
     PropTools::RemoveAllProperties(retVal, m_pTmpValues);
+
     if(SUCCEEDED(retVal))
     {
-        retVal = ExtractMetaData(m_pTmpValues, pValues);
+        retVal = MetaInfo::CopyAllProperties(m_pTmpValues, pValues, METAINFO_SET_ALL, FALSE);
     }
     if(SUCCEEDED(retVal) && m_pProcessor)
     {
         retVal = m_pProcessor->OnOutboundMetaData(m_pTmpValues);
     }
 
     // call next source handler
     if(SUCCEEDED(retVal) && m_pSourceSink)
     {
         retVal = m_pSourceSink->OnFileHeader(status, pValues);
     }
     return retVal;
 }
 
 STDMETHODIMP
 CSourceHandler::OnStreamHeader(HX_RESULT status, IHXValues* pValues)
 {
     HX_RESULT retVal = HXR_OK;
     if(m_pSourceSink)
     {
         retVal = m_pSourceSink->OnStreamHeader(status, pValues);
     }
     return retVal;
 }
 
 STDMETHODIMP
 CSourceHandler::OnStreamDone(HX_RESULT status, UINT16 unStreamNumber)
 {
     HX_RESULT retVal = HXR_OK;
     if(m_pSourceSink)
@@ -219,110 +219,75 @@
     }
     return retVal;
 }
 
 STDMETHODIMP
 CSourceHandler::OnTermination(HX_RESULT status)
 {
     HX_RESULT retVal = HXR_OK;
     if(m_pSourceSink)
     {
         retVal = m_pSourceSink->OnTermination(status);
     }
     return retVal;
 }
 
 STDMETHODIMP
 CSourceHandler::InitSourceHandler(IHXSourceInput* pSourceSink, IHXValues* pOptions)
 {
     HX_RELEASE(m_pSourceSink);
     m_pSourceSink = pSourceSink;
     HX_ADDREF(m_pSourceSink);
 
     // extract options
     if(pOptions)
     {
         ULONG32 ulBlastMetaData = 0;
         if(SUCCEEDED(pOptions->GetPropertyULONG32(BLASTMETADATA_OPTION_NAME, ulBlastMetaData)))
         {
             m_ulDiscardExtracted = ulBlastMetaData ? 1 : 0;
         }
-        ULONG32 ulMetaDataFlavor = 0;
-        if(SUCCEEDED(pOptions->GetPropertyULONG32(METADATAFLAVOR_OPTION_NAME, ulMetaDataFlavor)))
-        {
-            m_eMetaDataFlavor = (METADATA_FLAVOR)ulMetaDataFlavor;
-        }
     }
     return HXR_OK;
 }
 
 STDMETHODIMP
 CSourceHandler::Close()
 {
     HX_RELEASE(m_pSourceSink);
     return HXR_OK;
 }
 
 STDMETHODIMP
 CSourceHandler::InitMetaDataSourceHandler(IUnknown* pContext)
 {
     if(pContext)
     {
         m_pContext = pContext;
         HX_ADDREF(m_pContext);
 
         // create property stores
         HX_RESULT retVal = HXR_OK;
         retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues, (void**)&m_pExtractedMetaData, m_pContext);
 
         if(SUCCEEDED(retVal))
         {
             retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues, (void**)&m_pInjectedMetaData, m_pContext);
         }
         if(SUCCEEDED(retVal))
         {
             retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues, (void**)&m_pTmpValues, m_pContext);
         }
         return retVal;
     }
     return HXR_FAILED;
 }
 
 STDMETHODIMP
 CSourceHandler::SetProcessor(IHXMetaDataProcessor* pProcessor)
 {
     HX_RELEASE(m_pProcessor);
     m_pProcessor = pProcessor;
     HX_ADDREF(m_pProcessor);
     return HXR_OK;
 }
 
-STDMETHODIMP
-CSourceHandler::ExtractMetaData(IHXValues* pDst, IHXValues* pSrc)
-{
-    switch(m_eMetaDataFlavor)
-    {
-        case METADATA_FLAVOR_3GP:
-            return CopyAllProperties_MetaInfo3GP(pDst, pSrc, FALSE);
-
-        default:
-            // unknown flavor
-            break;
-    }
-    return HXR_OK;
-}
-
-STDMETHODIMP
-CSourceHandler::RemoveMetaData(IHXValues* pValues)
-{
-    switch(m_eMetaDataFlavor)
-    {
-        case METADATA_FLAVOR_3GP:
-            return RemoveAllProperties_MetaInfo3GP(pValues);
-
-        default:
-            // unknown flavor
-            break;
-    }
-    return HXR_OK;
-}
-
Index: srchandler.h
===================================================================
RCS file: /cvsroot/datatype/tools/metaeditor/srchandler.h,v
retrieving revision 1.1
diff -d -H -b -B -w -U30 -r1.1 srchandler.h
--- srchandler.h	5 Nov 2007 22:29:46 -0000	1.1
+++ srchandler.h	19 Oct 2009 17:43:48 -0000
@@ -54,47 +54,42 @@
 #include "ihxmetaeditor.h"
 
 
 class CSourceHandler : public IHXMetaDataSourceHandler
 {
 public:
     CSourceHandler();
     virtual ~CSourceHandler();
 
     // IUnknown methods
     STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj);
     STDMETHOD_(ULONG32, AddRef)();
     STDMETHOD_(ULONG32, Release)();
 
     // IHXSourceInput methods
     STDMETHOD(OnFileHeader)(HX_RESULT status, IHXValues* pValues);
     STDMETHOD(OnStreamHeader)(HX_RESULT status, IHXValues* pValues);
     STDMETHOD(OnStreamDone)(HX_RESULT status, UINT16 unStreamNumber);
     STDMETHOD(OnPacket)(HX_RESULT status, IHXPacket* pPacket);
     STDMETHOD(OnTermination)(HX_RESULT status);
 
     // IHXSourceHandler methods
     STDMETHOD(InitSourceHandler)(IHXSourceInput* pSourceSink, IHXValues* pOptions);
     STDMETHOD(Close)();
 
     // IHXMetaDataSourceHandler methods
     STDMETHOD(InitMetaDataSourceHandler)(IUnknown* pContext);
     STDMETHOD(SetProcessor)(IHXMetaDataProcessor* pProcessor);
 
 private:
-    STDMETHOD(ExtractMetaData)(IHXValues* pDst, IHXValues* pSrc);
-    STDMETHOD(RemoveMetaData)(IHXValues* pValues);
-
-private:
     LONG32 m_lRefCount;
     IUnknown* m_pContext;
     IHXSourceInput* m_pSourceSink;
     IHXMetaDataProcessor* m_pProcessor;
     IHXValues* m_pExtractedMetaData;
     IHXValues* m_pInjectedMetaData;
     IHXValues* m_pTmpValues;
     ULONG32 m_ulDiscardExtracted;
-    METADATA_FLAVOR m_eMetaDataFlavor;
 };
 
 
 #endif // _SRCHANDLER_H
Index: pub/metautil3gp.h
===================================================================
RCS file: pub/metautil3gp.h
diff -N pub/metautil3gp.h
--- pub/metautil3gp.h	5 Nov 2007 22:29:46 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,227 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK ***** 
- * Version: RCSL 1.0/RPSL 1.0 
- *  
- * Portions Copyright (c) 1995-2007 RealNetworks, Inc. All Rights Reserved. 
- *      
- * The contents of this file, and the files included with this file, are 
- * subject to the current version of the RealNetworks Public Source License 
- * Version 1.0 (the "RPSL") available at 
- * http://www.helixcommunity.org/content/rpsl unless you have licensed 
- * the file under the RealNetworks Community Source License Version 1.0 
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
- * in which case the RCSL will apply. You may also obtain the license terms 
- * directly from RealNetworks.  You may not use this file except in 
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
- * applicable to this file, the RCSL.  Please see the applicable RPSL or 
- * RCSL for the rights, obligations and limitations governing use of the 
- * contents of the file.  
- *  
- * This file is part of the Helix DNA Technology. RealNetworks is the 
- * developer of the Original Code and owns the copyrights in the portions 
- * it created. 
- *  
- * This file, and the files included with this file, is distributed and made 
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
- * 
- * Technology Compatibility Kit Test Suite(s) Location: 
- *    http://www.helixcommunity.org/content/tck 
- * 
- * Contributor(s): 
- *  
- * ***** END LICENSE BLOCK ***** */ 
-
-
-#ifndef _METAUTIL3GP_H_
-#define _METAUTIL3GP_H_
-
-#include "hxtypes.h"
-#include "carray.h"
-#include "encstr.h"
-
-
-HX_RESULT RemoveKeywordProperties_MetaInfo3GP(IHXValues* pValues);
-HX_RESULT RemoveAllProperties_MetaInfo3GP(IHXValues* pValues);
-
-HX_RESULT CopyKeywordProperties_MetaInfo3GP(IHXValues* dst, IHXValues* src, BOOL bBlast);
-HX_RESULT CopyAllProperties_MetaInfo3GP(IHXValues* dst, IHXValues* src, BOOL bBlast);
-
-
-class MetaInfo3GP
-{
-public:
-    typedef BOOL (MetaInfo3GP::*FnStringGetter)(EncodedString&) const;
-    typedef BOOL (MetaInfo3GP::*FnStringSetter)(const EncodedString&);
-
-    typedef BOOL (MetaInfo3GP::*FnUINT8Getter)(UINT8&) const;
-    typedef BOOL (MetaInfo3GP::*FnUINT8Setter)(UINT8, BOOL);
-
-    typedef BOOL (MetaInfo3GP::*FnUINT16Getter)(UINT16&) const;
-    typedef BOOL (MetaInfo3GP::*FnUINT16Setter)(UINT16, BOOL);
-
-public:
-    MetaInfo3GP();
-    ~MetaInfo3GP();
-
-    MetaInfo3GP(const MetaInfo3GP& rhs);
-    MetaInfo3GP& operator=(const MetaInfo3GP& rhs);
-
-    void Dump();
-
-    void Clear();
-    void Update(const MetaInfo3GP& src);
-
-    void CopyToValues(IHXValues* pValues) const;
-    void CopyFromValues(IHXValues* pValues);
-
-    // Getters always update <out>.
-    // String getters return TRUE if <out> is empty.
-    // UINT getters return TRUE if the value copied to <out> is considered valid.
-
-    // Exactly 3 ASCII characters, must be valid ISO639.2/T language code
-    BOOL GetGlobalLanguageEncoding(EncodedString& out) const;
-    BOOL SetGlobalLanguageEncoding(const EncodedString& val);
-
-    BOOL GetTitle(EncodedString& out) const;
-    BOOL SetTitle(const EncodedString& val);
-
-    BOOL GetAuthor(EncodedString& out) const;
-    BOOL SetAuthor(const EncodedString& val);
-
-    BOOL GetCopyright(EncodedString& out) const;
-    BOOL SetCopyright(const EncodedString& val);
-
-    BOOL GetDescription(EncodedString& out) const;
-    BOOL SetDescription(const EncodedString& val);
-
-    BOOL GetPerformer(EncodedString& out) const;
-    BOOL SetPerformer(const EncodedString& val);
-
-    BOOL GetGenre(EncodedString& out) const;
-    BOOL SetGenre(const EncodedString& val);
-
-    // Max 4 ASCII characters
-    BOOL GetRatingEntity(EncodedString& out) const;
-    BOOL SetRatingEntity(const EncodedString& val);
-
-    // Max 4 ASCII characters
-    BOOL GetRatingCriteria(EncodedString& out) const;
-    BOOL SetRatingCriteria(const EncodedString& val);
-
-    BOOL GetRatingInfo(EncodedString& out) const;
-    BOOL SetRatingInfo(const EncodedString& val);
-
-    // Max 4 ASCII characters
-    BOOL GetClassificationEntity(EncodedString& out) const;
-    BOOL SetClassificationEntity(const EncodedString& val);
-
-    BOOL GetClassificationTable(UINT16& out) const;
-    BOOL SetClassificationTable(UINT16 val, BOOL bValid=TRUE);
-
-    BOOL GetClassificationInfo(EncodedString& out) const;
-    BOOL SetClassificationInfo(const EncodedString& val);
-
-    UINT32 GetKeywordCount() const;
-
-    // Returns FALSE if <index> is out of range.
-    BOOL GetKeyword(UINT32 index, EncodedString& out) const;
-    void ClearKeywords();
-
-    // Returns FALSE if the byte-length of <val> is greater than 255 (maximum allowed by 3GPP).
-    // Also, maximum number of keywords that can be written to 3GPP file is 255 (this method
-    // does not check this to allow easier addition/removal, so this should be checked after
-    // changes by calling GetKeywordCount and taking appropriate actions).
-    BOOL AddKeyword(const EncodedString& val);
-    void RemoveKeyword(const EncodedString& val);
-    void RemoveKeywordDuplicates();
-
-    BOOL GetLocationName(EncodedString& out) const;
-    BOOL SetLocationName(const EncodedString& val);
-
-    BOOL GetLocationAstronomicalBody(EncodedString& out) const;
-    BOOL SetLocationAstronomicalBody(const EncodedString& val);
-
-    BOOL GetLocationAdditionalNotes(EncodedString& out) const;
-    BOOL SetLocationAdditionalNotes(const EncodedString& val);
-
-    BOOL GetLocationRole(UINT8& out) const;
-    BOOL SetLocationRole(UINT8 val, BOOL bValid=TRUE);
-
-    BOOL GetLocationLongitude(EncodedString& out) const;
-    BOOL SetLocationLongitude(const EncodedString& val);
-
-    BOOL GetLocationLatitude(EncodedString& out) const;
-    BOOL SetLocationLatitude(const EncodedString& val);
-
-    BOOL GetLocationAltitude(EncodedString& out) const;
-    BOOL SetLocationAltitude(const EncodedString& val);
-
-    BOOL GetAlbumTitle(EncodedString& out) const;
-    BOOL SetAlbumTitle(const EncodedString& val);
-
-    BOOL GetAlbumTrackNumber(UINT8& out) const;
-    BOOL SetAlbumTrackNumber(UINT8 val, BOOL bValid=TRUE);
-
-    BOOL GetRecordingYear(UINT16& out) const;
-    BOOL SetRecordingYear(UINT16 val, BOOL bValid=TRUE);
-
-private:
-    static BOOL GetString(const EncodedString& src, EncodedString& out);
-    static BOOL SetString(EncodedString& dst, const EncodedString& val);
-    static BOOL SetStringAsciiMaxLen(EncodedString& dst, const EncodedString& val, UINT32 maxLen);
-    static BOOL SetStringFixedPointNum(EncodedString& dst, const EncodedString& val);
-    static BOOL GetUINT16(const UINT16& src, const BOOL& srcValid, UINT16& out);
-    static BOOL SetUINT16(UINT16& dst, BOOL& dstValid, UINT16 val, BOOL bValid);
-    static BOOL GetUINT8(const UINT8& src, const BOOL& srcValid, UINT8& out);
-    static BOOL SetUINT8(UINT8& dst, BOOL& dstValid, UINT8 val, BOOL bValid);
-    static void Update(EncodedString& dst, const EncodedString& src);
-    static void Update(UINT16& dst, BOOL& dstValid, const UINT16& src, const BOOL& srcValid);
-    static void Update(UINT8& dst, BOOL& dstValid, const UINT8& src, const BOOL& srcValid);
-    static void Dump(const char* propName, const EncodedString& val);
-    static void Dump(const char* propName, const UINT16& val, const BOOL& bValid);
-    static void Dump(const char* propName, const UINT8& val, const BOOL& bValid);
-    static void ClearPropertyStringArray(CHXPtrArray& aStrings);
-
-    void CopyString(MetaInfo3GP::FnStringSetter setter, IHXValues* pValues, const char* enginePropName);
-    void CopyULONG32(MetaInfo3GP::FnUINT16Setter setter, IHXValues* pValues, const char* enginePropName);
-    void CopyULONG32(MetaInfo3GP::FnUINT8Setter setter, IHXValues* pValues, const char* enginePropName);
-
-    void CopyString(IHXValues* pValues, const char* enginePropName, MetaInfo3GP::FnStringGetter getter) const;
-    void CopyULONG32(IHXValues* pValues, const char* enginePropName, MetaInfo3GP::FnUINT16Getter getter) const;
-    void CopyULONG32(IHXValues* pValues, const char* enginePropName, MetaInfo3GP::FnUINT8Getter getter) const;
-
-private:
-    EncodedString m_sGlobalLanguageEncoding;
-    EncodedString m_sTitle;
-    EncodedString m_sAuthor;
-    EncodedString m_sCopyright;
-    EncodedString m_sDescription;
-    EncodedString m_sPerformer;
-    EncodedString m_sGenre;
-    EncodedString m_sRatingEntity;
-    EncodedString m_sRatingCriteria;
-    EncodedString m_sRatingInfo;
-    EncodedString m_sClassificationEntity;
-    BOOL m_bValidClassificationTable;
-    UINT16 m_uClassificationTable;
-    EncodedString m_sClassificationInfo;
-    CHXPtrArray m_aKeywords;
-    EncodedString m_sLocationName;
-    EncodedString m_sLocationAstronomicalBody;
-    EncodedString m_sLocationAdditionalNotes;
-    BOOL m_bValidLocationRole;
-    UINT8 m_uLocationRole;
-    EncodedString m_sLocationLongitude;
-    EncodedString m_sLocationLatitude;
-    EncodedString m_sLocationAltitude;
-    EncodedString m_sAlbumTitle;
-    BOOL m_bValidAlbumTrackNumber;
-    UINT8 m_uAlbumTrackNumber;
-    BOOL m_bValidRecordingYear;
-    UINT16 m_uRecordingYear;
-};
-
-#endif // _METAUTIL3GP_H_
-
helix.bif.diff (text/x-patch, 8.6 KB)
Index: helix.bif
===================================================================
RCS file: /cvsroot/common/build/BIF/helix.bif,v
retrieving revision 1.771
diff -w -B -b -U20 -r1.771 helix.bif
--- helix.bif	15 Oct 2009 17:28:19 -0000	1.771
+++ helix.bif	19 Oct 2009 13:37:02 -0000
@@ -2182,40 +2182,41 @@
          common_dbgtool
          common_container
          common_util
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/COMMON/UTIL  -->
     <module id="datatype_common_util" name="datatype/common/util" group="core">    
       <cvs root="helix"/>
       <includeplatforms>
         unix mac win32 symbian openwave tm1 wince brew
       </includeplatforms>
 
       <source_dependlist>
         common_include
         common_container
         common_util
         common_system
         common_dbgtool
         common_runtime
+        datatype_include
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/COMMON/AUDREND  -->
     <module id="datatype_common_audrend" name="datatype/common/audrend" group="core">    
       <cvs root="helix"/>
       <includeplatforms>
         unix mac win32 symbian openwave wince brew
       </includeplatforms>
 
       <excludeprofiles>
         helix-client-local-net-ra
         helix-client-local-ra
         helix-client-net-ra
         helix-client-local-net-ra-mp3
         helix-client-local-mp3
         helix-client-local-ra-mp3
         helix-client-local-ra-rv-mp3
         helix-client-mobile-local-net-ra-rv-mp3
       </excludeprofiles>
@@ -2495,136 +2496,145 @@
         client_common_netio
         client_medpltfm
         client_netwksvc
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/INCLUDE  -->
     <module id="datatype_tools_dtdriver_include" name="datatype/tools/dtdriver/include" group="core">
       <attribute id="no_build"/>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/COMMON  -->
     <module id="datatype_tools_dtdriver_common" name="datatype/tools/dtdriver/common" group="core">    
       <includeplatforms>
         unix mac win32 symbian openwave wince
       </includeplatforms>
 
       <source_dependlist>
         common_include
         common_runtime
+        common_container
+        common_dbgtool
+        common_util
+        datatype_include
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/DECODER/COMMON  -->
     <module id="datatype_tools_dtdriver_decoder_common" name="datatype/tools/dtdriver/decoder/common" group="core">    
       <includeplatforms>
         unix mac win32 symbian openwave wince
       </includeplatforms>
 
       <source_dependlist>
         common_include
         common_util
         common_runtime
         common_container
         datatype_rm_video_payload_depacker
         datatype_tools_dtdriver_include
         datatype_tools_dtdriver_engine
         datatype_tools_dtdriver_decoder_audio
         datatype_tools_dtdriver_decoder_video
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/DECODER/AUDIO  -->
     <module id="datatype_tools_dtdriver_decoder_audio" name="datatype/tools/dtdriver/decoder/audio" group="core">    
       <includeplatforms>
         unix mac win32 symbian openwave wince
       </includeplatforms>
 
       <source_dependlist>
         common_include
         common_util
         common_runtime
         common_dbgtool
         common_container
         common_system
+        datatype_include
+        datatype_common_util
         datatype_common_container
         datatype_tools_dtdriver_common
         datatype_tools_dtdriver_engine
         datatype_tools_dtdriver_decoder_common
         client_common_container
         protocol_transport_rtp_include
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/DECODER/VIDEO  -->
     <module id="datatype_tools_dtdriver_decoder_video" name="datatype/tools/dtdriver/decoder/video" group="core">    
       <includeplatforms>
         unix mac win32 symbian openwave wince
       </includeplatforms>
       <defines>
         HELIX_FEATURE_VIDREND_UNTIMED_DECODE
       </defines>
 
       <source_dependlist>
         common_include
         common_util
         common_runtime
         common_dbgtool
         common_container
         common_system
         client_common_container
         datatype_rm_video_payload_depacker
+        datatype_include
         datatype_common_util
         protocol_transport_rtp_include
         common_log_logutil
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/DECODER  -->
     <module id="datatype_tools_dtdriver_decoder" name="datatype/tools/dtdriver/decoder" group="core">
       <attribute id="no_build"/>
       <dependlist>
         datatype_tools_dtdriver_decoder_common
         datatype_tools_dtdriver_decoder_audio
         datatype_tools_dtdriver_decoder_video
       </dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/ENGINE  -->
     <module id="datatype_tools_dtdriver_engine" name="datatype/tools/dtdriver/engine" group="core">    
       <includeplatforms>
         unix mac win32 symbian openwave wince brew
       </includeplatforms>
 
       <source_dependlist>
           common_include
           client_include
           datatype_include
           datatype_rm_include
           common_log_logutil
           video_include
           common_util
           common_runtime
           common_dbgtool
           common_container
           common_system
+          datatype_include
+          datatype_common_util
           datatype_tools_dtdriver_include
           datatype_tools_dtdriver_decoder
           datatype_tools_minicntx
           client_encodesvc_include
           client_encodesvc_common_include
           client_encodesvc_common_util
           client_encodesvc_common_system
           client_encodesvc_engine_encsession
           common_log_logobserverfile
           datatype_tools_dtdriver_common
           datatype_tools_dtdriver_decoder
           datatype_common_filewriter
       </source_dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/METADATAENGINE  -->
     <module id="datatype_tools_metadataeng" name="datatype/tools/metadataeng" group="core">    
       <includeplatforms>
         unix mac win32 symbian openwave wince
       </includeplatforms>
@@ -2652,68 +2662,75 @@
     <module id="datatype_tools_metaeditor" name="datatype/tools/metaeditor" group="core">
       <includeplatforms>
         win32 unix
       </includeplatforms>
 
       <dependlist>
         common_include
         common_util
         common_runtime
         common_dbgtool
         common_container
         common_fileio
         common_system
         common_log_logutil
         client_common_container
         client_common_system
         client_common_util
         client_medpltfm
         client_videosvc
         datatype_include
+        datatype_common_util
         datatype_tools_dtdriver_common
         datatype_tools_dtdriver_engine
         datatype_tools_dtdriver_dtdrplin
         datatype_tools_minicntx
       </dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/APPS/META3GP  -->
     <module id="datatype_tools_dtdriver_apps_meta3gp" name="datatype/tools/dtdriver/apps/meta3gp" group="core">
+      <defines>
+        HELIX_FEATURE_3GPP_METAINFO
+        HELIX_FEATURE_ITUNES_METAINFO
+      </defines>
+
       <includeplatforms>
         win32 unix
       </includeplatforms>
 
       <dependlist>
         common_include
         common_util
         common_runtime
         common_dbgtool
         common_container
         common_fileio
         common_system
         common_log_logutil
         client_common_container
         client_common_system
         client_common_util
         client_medpltfm
         client_videosvc
         datatype_include
+        datatype_common_util
         datatype_tools_dtdriver_common
         datatype_tools_dtdriver_engine
         datatype_tools_dtdriver_dtdrplin
         datatype_tools_minicntx
 
         datatype_tools_metaeditor
         filesystem_local
         datatype_mp4_fileformat
         datatype_mp4_filewriter
       </dependlist>
     </module>
 
     <!-- DATATYPE/TOOLS/DTDRIVER/APPS/DTDRIVE  -->
     <module id="datatype_tools_dtdriver_apps_dtdrive" name="datatype/tools/dtdriver/apps/dtdrive" group="core">
       <attribute id="has_version_file"/>
           
       <includeplatforms>
         unix win32 symbian openwave wince
       </includeplatforms>