[Helix-client-dev] CR: Implemented APICData and UITSData metadata support in datatype projects
Petar Basic <[email protected]> Sat, 7 Nov 2009 00:47:01 +0100
| Newsgroups | gmane.comp.multimedia.helix.devel |
|---|---|
| Message-ID | <[email protected]> |
Modified by: pbasic at real.com Date: 2009/11/06 Project: GMP MetaEditor (meta3gp.exe) Synopsis: Implemented APICData and UITSData metadata support in datatype projects Overview: This CR deals with: A.) Implementation of proposal outlined in the document "SOD-CoverArt-UITS-Properties-1.0.txt", also submitted to HC under topic "Statement of Design: Transfer of Cover Art and UITS properties through Helix DNA". B.) Implementation of iTunes covr (Cover Art) atom support. Details: 1.) Bugfixes and additions to common tools: --Added more buffer copying utilities to PropTools. --Added UTF8ContainsNewline utility to EncStrUtils. --Improved input parameter checking in metaeditor DLL's CEditor::Drive. 2.) MetaInfo and ID3Tools updates: --Added APICData and UITSData header property key definitions. --Added custom ID3v2 tag parsing and generation tools. Currently implemented are reading of APIC and PRIV frames (v2.3.0, v2.4.0), writing of APIC and PRIV frames (v2.4.0), reading of ID3v2 tag (v2.3.0, v2.4.0), writing of ID3v2 tag (v2.4.0). --Added support for APICData and UITSData metadata properties to MetaInfo. 3.) FFDriver updates: --Introduced FFDriver "MetaDataIgnore" option which is primarily intended as a hint to file-writers. The value can carry multiple flags each of which can specify a subset of metadata that should be ignored during writing. Currently this is used to suppress precedence of legacy ID32BLOB property over newer properties in MP4 file-writer. 4.) MP4 file-format changes: --Added reading and processing of iTunes covr atom to MP4 file-format. --Added parsing of ID3v2 tag and generation of APICData and UITSData properties via new MetaInfo utilities. --Merged ID32BLOB insertion into the stream header missed by previous GMPMetaEditor CR. 5.) MP4 file-writer changes: --Fixed some constant-definition bugs. --Fixed bug in calculation of free size of 'free' atom inside the 'meta' atom. --Added writing of iTunes covr atom to MP4 file-writer. --Added ID3v2 tag generation from APICData and UITSData properties and writing of the constructed tag to ID32 atom. ID32 atom is outputted by default for M4A brand if UITSData is present in the header. --Writer now has to decide whether to write out legacy ID32BLOB property or construct ID3v2 tag from newly defined APICData and UITSData properties. By default, if legacy ID32BLOB is found in the header, it has precedence over other metadata. However, MP4 file-writer now also observes "MetaDataIgnore" hint which can override the default behaviour. 6.) Metaeditor executable changes: --Added CoverArt injection/extraction options. --Added UITS injection/extraction options. --Completely refactored option processing. 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/util/encstr.cpp common/util/pub/encstr.h common/util/proptools.cpp common/util/pub/proptools.h datatype/include/metainfokeys.h datatype/common/util/metautil.cpp datatype/common/util/pub/metautil.h datatype/tools/metaeditor/editor.cpp datatype/tools/dtdriver/engine/pub/ffdriver.h datatype/tools/dtdriver/engine/ffdriver.cpp datatype/tools/dtdriver/apps/meta3gp/main.cpp datatype/mp4/fileformat/qtatmmgs.cpp datatype/mp4/fileformat/pub/qtatmmgs.h datatype/mp4/fileformat/qtatoms.cpp datatype/mp4/fileformat/pub/qtatoms.h datatype/mp4/fileformat/qtffplin.cpp datatype/mp4/fileformat/qttrack.cpp datatype/mp4/filewriter/3gpmeta.cpp datatype/mp4/filewriter/3gpmeta.h datatype/mp4/filewriter/m4amdatoms.h datatype/mp4/filewriter/mp4sm.cpp datatype/mp4/filewriter/mp4sm.h 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_util.diff
(text/x-patch, 14.4 KB)
Index: encstr.cpp
===================================================================
RCS file: /cvsroot/common/util/encstr.cpp,v
retrieving revision 1.6
diff -d -H -w -U30 -r1.6 encstr.cpp
--- encstr.cpp 23 Oct 2009 09:36:18 -0000 1.6
+++ encstr.cpp 6 Nov 2009 21:04:31 -0000
@@ -208,60 +208,111 @@
return EncStrUtils::PrintTextUTF8(psz);
default:
break;
}
return FALSE;
}
void EncStrUtils::Dump(const char* psz, HX_TEXT_ENCODING_TYPE enc)
{
if(!psz)
{
printf("(null)");
return;
}
// encoding type
EncStrUtils::PrintEncodingType(enc);
// total byte count
printf(" | %d byte(s) | ", int(EncStrUtils::ByteLength(psz, enc, TRUE)));
// hex digits
EncStrUtils::HexDump(psz, enc);
printf(" | ");
// print characters
EncStrUtils::PrintText(psz, enc);
}
#endif // End of #ifndef HELIX_CONFIG_DISABLE_CONSOLE_PRINT
+UINT32 EncStrUtils::UTF8ContainsNewline(const char* psz)
+{
+ if(!psz)
+ {
+ return 0;
+ }
+
+ char ch = *psz;
+
+ while(ch != 0)
+ {
+ if(ch <= 0x7F)
+ {
+ // 1-byte sequence
+ if(ch == '\n' || ch == '\r')
+ {
+ return 1;
+ }
+ psz++;
+ }
+ else
+ {
+ // determine number of bytes in the sequence
+ if((ch & 0xE0) == 0xC0)
+ {
+ // skip 2 bytes
+ psz += 2;
+ }
+ else if((ch & 0xF0) == 0xE0)
+ {
+ // skip 3 bytes
+ psz += 3;
+ }
+ else if((ch & 0xF8) == 0xF0)
+ {
+ // skip 4 bytes
+ psz += 4;
+ }
+ else
+ {
+ // invalid sequence, bail out
+ return -1;
+ }
+ }
+
+ ch = *psz;
+ }
+
+ return 0;
+}
+
HXBOOL EncStrUtils::IsAsciiOnly(const char* psz, HX_TEXT_ENCODING_TYPE enc)
{
if(!psz)
{
return TRUE;
}
if(enc == HX_TEXT_ENCODING_TYPE_UTF16)
{
// assume BE by default
enc = HX_TEXT_ENCODING_TYPE_UTF16BE;
if(EncStrUtils::IsUTF16LE(psz))
{
enc = HX_TEXT_ENCODING_TYPE_UTF16LE;
}
}
switch(enc)
{
case HX_TEXT_ENCODING_TYPE_UTF16BE:
{
// skip byte order mark
if(EncStrUtils::IsUTF16BE(psz))
{
psz += 2;
}
UINT32 count = 0;
return IsUTF16StringAsciiOnly((const UINT16*)psz, MAX_UINT32, TRUE, count);
}
case HX_TEXT_ENCODING_TYPE_UTF16LE:
{
// skip byte order mark
Index: proptools.cpp
===================================================================
RCS file: /cvsroot/common/util/proptools.cpp,v
retrieving revision 1.2
diff -d -H -w -U30 -r1.2 proptools.cpp
--- proptools.cpp 28 Nov 2007 18:59:47 -0000 1.2
+++ proptools.cpp 6 Nov 2009 21:04:31 -0000
@@ -335,111 +335,168 @@
{
CopyPropertyCString(retVal, dst, src, pszPropName, FALSE);
if(SUCCEEDED(retVal))
{
iterResult = src->GetNextPropertyCString(pszPropName, pBuffer);
HX_RELEASE(pBuffer);
}
}
}
HXBOOL PropTools::CopyPropertyBuffer(EncodedString& out, IHXValues* src, const char* propertyName)
{
out.Clear();
if(!propertyName)
{
return FALSE;
}
HXBOOL result = FALSE;
IHXBuffer* pBufValue = 0;
if(SUCCEEDED(src->GetPropertyBuffer(propertyName, pBufValue)))
{
out.Set((const char*)pBufValue->GetBuffer(),
(HX_TEXT_ENCODING_TYPE)GetPropertyBufferEncodingType(src, propertyName));
result = TRUE;
}
HX_RELEASE(pBufValue);
return result;
}
+UINT32 PropTools::CopyPropertyBuffer(UINT8* pDstBuffer, UINT32 dstBufferSize, IHXValues* src, const char* propertyName)
+{
+ UINT32 numBytes = 0;
+
+ if(!src || !propertyName)
+ {
+ return numBytes;
+ }
+
+ IHXBuffer* pBufValue = 0;
+ if(SUCCEEDED(src->GetPropertyBuffer(propertyName, pBufValue)))
+ {
+ if(pDstBuffer && (dstBufferSize >= pBufValue->GetSize()))
+ {
+ memcpy(pDstBuffer, pBufValue->GetBuffer(), pBufValue->GetSize());
+ }
+ numBytes = pBufValue->GetSize();
+ }
+
+ HX_RELEASE(pBufValue);
+
+ return numBytes;
+}
+
HXBOOL PropTools::CopyPropertyULONG32(ULONG32& out, IHXValues* src, const char* propertyName)
{
out = 0;
if(!propertyName)
{
return FALSE;
}
ULONG32 uValue = 0;
if(SUCCEEDED(src->GetPropertyULONG32(propertyName, uValue)))
{
out = uValue;
return TRUE;
}
return FALSE;
}
void PropTools::CopyPropertyBuffer(IHXValues* dst, const EncodedString& val, const char* propertyName, HXBOOL bBlast)
{
if(!propertyName)
{
return;
}
if(val.IsEmpty())
{
if(bBlast)
{
RemovePropertyBuffer(dst, propertyName);
}
return;
}
IHXBuffer* pBuffer = new CHXBuffer();
if(!pBuffer) return;
pBuffer->AddRef();
HX_RESULT retVal = pBuffer->Set((const UCHAR*)val.GetData(), (UINT32)val.GetByteLength(TRUE));
if(SUCCEEDED(retVal))
{
retVal = dst->SetPropertyBuffer(propertyName, pBuffer);
}
HX_RELEASE(pBuffer);
if(SUCCEEDED(retVal))
{
// copy encoding type
CHXString sEncName(propertyName);
sEncName += "_@@_TextEncodingType";
dst->SetPropertyULONG32((const char*)sEncName, val.GetEncoding());
}
}
+HX_RESULT PropTools::CopyPropertyBuffer(IHXValues* dst, const UINT8* pData, UINT32 dataByteSize, const char* propertyName, HXBOOL bBlast)
+{
+ if(!dst || !propertyName || !propertyName[0])
+ {
+ return HXR_INVALID_PARAMETER;
+ }
+
+ if(!pData || !dataByteSize)
+ {
+ if(bBlast)
+ {
+ RemovePropertyBuffer(dst, propertyName);
+ }
+ return HXR_OK;
+ }
+
+ IHXBuffer* pBuffer = new CHXBuffer();
+ if(!pBuffer)
+ {
+ return HXR_OUTOFMEMORY;
+ }
+ pBuffer->AddRef();
+
+ HX_RESULT retVal = pBuffer->Set((const UCHAR*)pData, dataByteSize);
+ if(SUCCEEDED(retVal))
+ {
+ retVal = dst->SetPropertyBuffer(propertyName, pBuffer);
+ }
+ HX_RELEASE(pBuffer);
+
+ return retVal;
+}
+
void PropTools::CopyPropertyULONG32(IHXValues* dst, HXBOOL bValid, ULONG32 val, const char* propertyName, HXBOOL bBlast)
{
if(propertyName)
{
if(bValid)
{
dst->SetPropertyULONG32(propertyName, val);
}
else if(bBlast)
{
RemovePropertyULONG32(dst, propertyName);
}
}
}
HXBOOL PropTools::IsFixedPointNumber(EncodedString& val, HXBOOL bNormalize)
{
if(val.IsEmpty() || !val.IsAsciiOnly())
{
return FALSE;
}
EncodedString valConv;
val.ConvertToUTF8(valConv);
// check for valid characters
const char* input = valConv.GetData();
if(!input)
{
return FALSE;
}
Index: pub/encstr.h
===================================================================
RCS file: /cvsroot/common/util/pub/encstr.h,v
retrieving revision 1.3
diff -d -H -w -U30 -r1.3 encstr.h
--- pub/encstr.h 13 Dec 2007 17:56:52 -0000 1.3
+++ pub/encstr.h 6 Nov 2009 21:04:32 -0000
@@ -55,60 +55,65 @@
#include "hxmemprb.h"
#include "hxsrcin.h"
#include "hxformt.h"
#include "hxvalues.h"
#include "pckunpck.h"
class EncStrUtils
{
public:
#ifndef HELIX_CONFIG_DISABLE_CONSOLE_PRINT
// Prints string in hexadecimal format.
static void HexDump(const char* psz, HX_TEXT_ENCODING_TYPE enc);
// Prints encoding-type string, returns FALSE if encoding was of unknown type.
static HXBOOL PrintEncodingType(HX_TEXT_ENCODING_TYPE enc);
// Prints UTF8 string, returns FALSE if the sequence was invalid.
static HXBOOL PrintTextUTF8(const char* psz);
// Prints string, returns FALSE if the sequence was invalid.
static HXBOOL PrintText(const char* psz, HX_TEXT_ENCODING_TYPE enc);
// Prints string contents (encoding-type, byte-length, hex-dump, characters).
static void Dump(const char* psz, HX_TEXT_ENCODING_TYPE enc);
#endif // End of #ifndef HELIX_CONFIG_DISABLE_CONSOLE_PRINT
+ // Returns 1 if the terminated UTF8 string contains a newline, 0 otherwise.
+ // Newline means CR or LF.
+ // Returns -1 if an invalid sequence of bytes is encountered.
+ static UINT32 UTF8ContainsNewline(const char* psz);
+
// Returns TRUE if the terminated string contains only ASCII characters.
static HXBOOL IsAsciiOnly(const char* psz, HX_TEXT_ENCODING_TYPE enc);
// Returns TRUE if the terminated string is empty (contains only terminator and possibly BOM).
static HXBOOL IsEmpty(const char* psz, HX_TEXT_ENCODING_TYPE enc);
// Returns TRUE if the string starts with "FEFF" big-endian byte-order-mark, FALSE otherwise.
static HXBOOL IsUTF16BE(const char* psz);
// Returns TRUE if the string starts with "FFFE" little-endian byte-order-mark, FALSE otherwise.
static HXBOOL IsUTF16LE(const char* psz);
// Return codes: 0 if the string does not start with byte-order-mark.
// 1 if the string starts with "FFFE" little-endian byte-order-mark.
// 2 if the string starts with "FEFF" big-endian byte-order-mark.
static INT32 IsUTF16(const char* psz);
// Scan flags.
typedef enum {
SCAN_FLAG_UTF16BE = 0x00000001,
SCAN_FLAG_UTF16LE = 0x00000002,
SCAN_FLAGS_UTF16 = SCAN_FLAG_UTF16BE | SCAN_FLAG_UTF16LE,
SCAN_FLAGS_UTF = SCAN_FLAGS_UTF16,
SCAN_FLAGS_ALL = SCAN_FLAGS_UTF
} SCAN_FLAG;
// Scans the string for byte-order-mark and tries to determine it's encoding.
static HX_TEXT_ENCODING_TYPE ScanEncoding(const char* psz, UINT32 scanFlags = SCAN_FLAGS_ALL);
Index: pub/proptools.h
===================================================================
RCS file: /cvsroot/common/util/pub/proptools.h,v
retrieving revision 1.2
diff -d -H -w -U30 -r1.2 proptools.h
--- pub/proptools.h 28 Nov 2007 18:59:48 -0000 1.2
+++ pub/proptools.h 6 Nov 2009 21:04:32 -0000
@@ -70,54 +70,60 @@
// Removes <propertyName> from <pValues>.
static void RemovePropertyCString(HX_RESULT& retVal, IHXValues* pValues, const char* propertyName);
static HX_RESULT RemovePropertyCString(IHXValues* pValues, const char* propertyName);
static void RemovePropertyULONG32(HX_RESULT& retVal, IHXValues* pValues, const char* propertyName);
static HX_RESULT RemovePropertyULONG32(IHXValues* pValues, const char* propertyName);
// Removes all properties from <pValues>.
static void RemoveAllProperties(HX_RESULT& retVal, IHXValues* pValues);
static HX_RESULT RemoveAllProperties(IHXValues* pValues);
// If <propertyName>'s encoding is not found, <notFoundResult> is returned.
static ULONG32 GetPropertyBufferEncodingType(IHXValues* src, const char* propertyName,
ULONG32 notFoundResult = HX_TEXT_ENCODING_TYPE_UTF8);
// If <bBlast> is TRUE, properties not found in <src> are removed from <dst>.
static void CopyPropertyBuffer(HX_RESULT& retVal, IHXValues* dst, IHXValues* src,
const char* propertyName, HXBOOL bBlast);
static void CopyPropertyCString(HX_RESULT& retVal, IHXValues* dst, IHXValues* src,
const char* propertyName, HXBOOL bBlast);
static void CopyPropertyULONG32(HX_RESULT& retVal, IHXValues* dst, IHXValues* src,
const char* propertyName, HXBOOL bBlast);
static void CopyAllProperties(HX_RESULT& retVal, IHXValues* dst, IHXValues* src);
// Returns TRUE if <propertyName> is found in <src>. <out> is set to empty string if <propertyName> is not found.
static HXBOOL CopyPropertyBuffer(EncodedString& out, IHXValues* src, const char* propertyName);
+ // Returns the number of bytes copied to buffer. If <pDstBuffer> is 0, it returns the number of bytes needed.
+ static UINT32 CopyPropertyBuffer(UINT8* pDstBuffer, UINT32 dstBufferSize, IHXValues* src, const char* propertyName);
+
// Returns TRUE if <propertyName> is found in <src>. <out> is set to 0 if <propertyName> is not found.
static HXBOOL CopyPropertyULONG32(ULONG32& out, IHXValues* src, const char* propertyName);
// If <bBlast> is TRUE, property is removed if <val> is empty.
static void CopyPropertyBuffer(IHXValues* dst, const EncodedString& val, const char* propertyName, HXBOOL bBlast);
+ // If <bBlast> is TRUE, property is removed if <pData> is NULL or <dataByteSize> is 0.
+ static HX_RESULT CopyPropertyBuffer(IHXValues* dst, const UINT8* pData, UINT32 dataByteSize, const char* propertyName, HXBOOL bBlast);
+
// If <bBlast> is TRUE, property is removed if <bValid> is FALSE.
static void CopyPropertyULONG32(IHXValues* dst, HXBOOL bValid, ULONG32 val, const char* propertyName, HXBOOL bBlast);
// Returns TRUE if <val> can be converted to fixed-point number.
// If <bNormalize> is TRUE and <val> can be converted, <val> is updated to normalized format, e.g. "-0" -> "0".
static HXBOOL IsFixedPointNumber(EncodedString& val, HXBOOL bNormalize);
// Returns TRUE if <val> can be converted to number which falls inside specified range.
static HXBOOL ExtractUInt32(UINT32& out, const EncodedString& val, UINT32 minVal = 0, UINT32 maxVal = 0xFFFFFFFF);
// Returns TRUE if <val> can be converted to number which falls inside specified range.
static HXBOOL ExtractUInt16(UINT16& out, const EncodedString& val, UINT16 minVal = 0, UINT16 maxVal = 0xFFFF);
// Returns TRUE if <val> can be converted to number which falls inside specified range.
static HXBOOL ExtractUInt8(UINT8& out, const EncodedString& val, UINT8 minVal = 0, UINT8 maxVal = 0xFF);
};
#endif /* _PROPTOOLS_H_ */
datatype_common_util.diff
(text/x-patch, 139.7 KB) - not displayed
datatype_include.diff
(text/x-patch, 7 KB)
Index: metainfokeys.h
===================================================================
RCS file: /cvsroot/datatype/include/metainfokeys.h,v
retrieving revision 1.5
diff -d -H -w -U30 -r1.5 metainfokeys.h
--- metainfokeys.h 23 Oct 2009 11:39:29 -0000 1.5
+++ metainfokeys.h 6 Nov 2009 21:14:41 -0000
@@ -20,99 +20,110 @@
* 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_
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;
+#define _META_INFO_BUFFER_PROPERTY_ID3_TAG_VERSION_MINOR 4
+#define _META_INFO_UITS_OWNER_IDENTIFIER "http://www.uits-data.org/"
+
// 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_DESCRIPTION_KEY "Description"
#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"
+#define _GENERIC_META_INFO_PICTURE_COUNT_KEY "APICDataCount"
+#define _GENERIC_META_INFO_PICTURE_KEY "APICData%d"
+#define _GENERIC_META_INFO_UITS_KEY "UITSData"
// 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_DESCRIPTION_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
+#define _ITUNES_META_INFO_PICTURE_COUNT_KEY _GENERIC_META_INFO_PICTURE_COUNT_KEY
+#define _ITUNES_META_INFO_PICTURE_KEY _GENERIC_META_INFO_PICTURE_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_DESCRIPTION_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
+#define _3GPP_META_INFO_PICTURE_COUNT_KEY _GENERIC_META_INFO_PICTURE_COUNT_KEY
+#define _3GPP_META_INFO_PICTURE_KEY _GENERIC_META_INFO_PICTURE_KEY
+#define _3GPP_META_INFO_UITS_KEY _GENERIC_META_INFO_UITS_KEY
// 3GPP specific set
#define _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY "GlobalLanguageEncoding"
#define _3GPP_META_INFO_RATING_ENTITY_KEY "RatingEntity"
#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_TABLE_KEY "ClassificationTable"
#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_KEYWORD_COUNT_KEY "KeywordCount"
#define _3GPP_META_INFO_KEYWORD_KEY "Keyword%d"
-#define _3GPP_META_INFO_ID32_BLOB_KEY "ID32BLOB"
+#define _3GPP_META_INFO_ID32_BLOB_KEY "ID32BLOB" //obsolete
#endif // _METAINFOKEYS_H_
datatype_mp4_fileformat.diff
(text/x-patch, 40.7 KB)
Index: qtatmmgs.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/fileformat/qtatmmgs.cpp,v
retrieving revision 1.61
diff -d -H -w -U30 -r1.61 qtatmmgs.cpp
--- qtatmmgs.cpp 4 Nov 2009 15:27:11 -0000 1.61
+++ qtatmmgs.cpp 6 Nov 2009 21:30:01 -0000
@@ -84,69 +84,75 @@
{
// There may be multiple 'ID32' atoms with different language codes.
// For now, return the first one.
return (CQT_ID32_Atom*)pMetaAtom->FindPresentChild(QT_ID32);
}
}
}
return NULL;
}
#endif // QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
CQT_iTunes_ilst_Atom* CQT_ManagerTools::FindiTunesIlstAtom(CQT_meta_Atom* pMetaAtom)
{
if(pMetaAtom)
{
// HandlerBox is required to indicate the nature of the contents.
CQT_hdlr_Atom* pHandlerAtom = (CQT_hdlr_Atom*)pMetaAtom->FindPresentChild(QT_hdlr);
if(pHandlerAtom)
{
if(pHandlerAtom->Get_CompSubtype() == QT_mdir)
{
// Search for ilst child.
return (CQT_iTunes_ilst_Atom*)pMetaAtom->FindPresentChild(QT_ilst);
}
}
}
return NULL;
}
-CQT_iTunes_data_Atom* CQT_ManagerTools::FindiTunesDataAtom(CQT_iTunes_ilst_Atom* pIlstAtom, QTAtomType MetaInfoAtomType)
+CQTAtom* CQT_ManagerTools::FindiTunesItemAtom(CQT_iTunes_ilst_Atom* pIlstAtom, QTAtomType ItemAtomType)
{
if(pIlstAtom)
{
- CQTAtom* piTunesMetaInfoAtom = pIlstAtom->FindPresentChild(MetaInfoAtomType);
- if(piTunesMetaInfoAtom)
- {
- return (CQT_iTunes_data_Atom*)piTunesMetaInfoAtom->FindPresentChild(QT_data);
+ return pIlstAtom->FindPresentChild(ItemAtomType);
+ }
+ return NULL;
}
+
+CQT_iTunes_data_Atom* CQT_ManagerTools::FindiTunesDataAtom(CQT_iTunes_ilst_Atom* pIlstAtom, QTAtomType ItemAtomType)
+{
+ CQTAtom* piTunesItemAtom = FindiTunesItemAtom(pIlstAtom, ItemAtomType);
+ if(piTunesItemAtom)
+ {
+ return (CQT_iTunes_data_Atom*)piTunesItemAtom->FindPresentChild(QT_data);
}
return NULL;
}
#endif // QTCONFIG_ITUNES_METAINFO
/****************************************************************************
* Track Edit Manager
*/
#define QT_MAX_MOVIE_DURATION 0xFFFFFFFF
/****************************************************************************
* Constructor/Destructor
*/
CQT_TrackEdit_Manager::CQT_TrackEdit_Manager(void)
: m_pEditListAtom(NULL)
, m_ulMovieTimeScale(1)
, m_ulMediaTimeScale(1)
, m_ulNumEdits(0)
, m_ulCurrentEditIdx(0)
, m_ulCurrentEditTime(0)
, m_ulCurrentInEditTime(0)
, m_ulCurrentEditDuration(QT_MAX_MOVIE_DURATION)
, m_ulCurrentMediaStartTime(0)
{
;
}
CQT_TrackEdit_Manager::~CQT_TrackEdit_Manager(void)
{
HX_RELEASE(m_pEditListAtom);
@@ -2740,175 +2746,178 @@
, m_pClsfAtom(NULL)
, m_pKywdAtom(NULL)
, m_pLociAtom(NULL)
, m_pAlbmAtom(NULL)
, m_pYrrcAtom(NULL)
, m_pID32Atom(NULL)
#endif // QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
, m_piTunesDataAtomA9nam(NULL)
, m_piTunesDataAtomA9ART(NULL)
, m_piTunesDataAtomA9alb(NULL)
, m_piTunesDataAtomA9gen(NULL)
, m_piTunesDataAtomA9day(NULL)
, m_piTunesDataAtomA9cmt(NULL)
, m_piTunesDataAtomA9wrt(NULL)
, m_piTunesDataAtomA9too(NULL)
, m_piTunesDataAtomA9enc(NULL)
, m_piTunesDataAtomA9grp(NULL)
, m_piTunesDataAtomgrup(NULL)
, m_piTunesDataAtomaART(NULL)
, m_piTunesDataAtomcprt(NULL)
, m_piTunesDataAtomA9st3(NULL)
, m_piTunesDataAtomA9lyr(NULL)
, m_piTunesDataAtomtmpo(NULL)
, m_piTunesDataAtomcpil(NULL)
, m_piTunesDataAtomrtng(NULL)
, m_piTunesDataAtomtrkn(NULL)
, m_piTunesDataAtomdisk(NULL)
, m_piTunesDataAtomgnre(NULL)
+ , m_piTunesItemAtomcovr(NULL)
#endif //QTCONFIG_ITUNES_METAINFO
, m_pRTPSDPAtom(NULL)
, m_pRefURL(NULL)
{
;
}
CQT_MovieInfo_Manager::~CQT_MovieInfo_Manager()
{
Clear();
}
void CQT_MovieInfo_Manager::Clear()
{
HX_RELEASE(m_pNameAtom);
#ifdef QTCONFIG_3GPP_TAC
HX_RELEASE(m_pTitlAtom);
HX_RELEASE(m_pAuthAtom);
HX_RELEASE(m_pCprtAtom);
#endif // QTCONFIG_3GPP_TAC
#ifdef QTCONFIG_3GPP_METAINFO
HX_RELEASE(m_pDscpAtom);
HX_RELEASE(m_pPerfAtom);
HX_RELEASE(m_pGnreAtom);
HX_RELEASE(m_pRtngAtom);
HX_RELEASE(m_pClsfAtom);
HX_RELEASE(m_pKywdAtom);
HX_RELEASE(m_pLociAtom);
HX_RELEASE(m_pAlbmAtom);
HX_RELEASE(m_pYrrcAtom);
HX_RELEASE(m_pID32Atom);
#endif // QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
HX_RELEASE(m_piTunesDataAtomA9nam);
HX_RELEASE(m_piTunesDataAtomA9ART);
HX_RELEASE(m_piTunesDataAtomA9alb);
HX_RELEASE(m_piTunesDataAtomA9gen);
HX_RELEASE(m_piTunesDataAtomA9day);
HX_RELEASE(m_piTunesDataAtomA9cmt);
HX_RELEASE(m_piTunesDataAtomA9wrt);
HX_RELEASE(m_piTunesDataAtomA9too);
HX_RELEASE(m_piTunesDataAtomA9enc);
HX_RELEASE(m_piTunesDataAtomA9grp);
HX_RELEASE(m_piTunesDataAtomgrup);
HX_RELEASE(m_piTunesDataAtomaART);
HX_RELEASE(m_piTunesDataAtomcprt);
HX_RELEASE(m_piTunesDataAtomA9st3);
HX_RELEASE(m_piTunesDataAtomA9lyr);
HX_RELEASE(m_piTunesDataAtomtmpo);
HX_RELEASE(m_piTunesDataAtomcpil);
HX_RELEASE(m_piTunesDataAtomrtng);
HX_RELEASE(m_piTunesDataAtomtrkn);
HX_RELEASE(m_piTunesDataAtomdisk);
HX_RELEASE(m_piTunesDataAtomgnre);
+ HX_RELEASE(m_piTunesItemAtomcovr);
#endif //QTCONFIG_ITUNES_METAINFO
HX_VECTOR_DELETE(m_pRefURL);
HX_RELEASE(m_pRTPSDPAtom);
}
/****************************************************************************
* Main Interface
*/
HX_RESULT CQT_MovieInfo_Manager::Init(CQTAtom* pAtom,
CQTTrackManager* pTrackManager)
{
HX_RESULT retVal;
m_ulMovieTimeScale = 0;
m_ulMovieDuration = 0;
HX_RELEASE(m_pNameAtom);
#ifdef QTCONFIG_3GPP_TAC
HX_RELEASE(m_pTitlAtom);
HX_RELEASE(m_pAuthAtom);
HX_RELEASE(m_pCprtAtom);
#endif // QTCONFIG_3GPP_TAC
#ifdef QTCONFIG_3GPP_METAINFO
HX_RELEASE(m_pDscpAtom);
HX_RELEASE(m_pPerfAtom);
HX_RELEASE(m_pGnreAtom);
HX_RELEASE(m_pRtngAtom);
HX_RELEASE(m_pClsfAtom);
HX_RELEASE(m_pKywdAtom);
HX_RELEASE(m_pLociAtom);
HX_RELEASE(m_pAlbmAtom);
HX_RELEASE(m_pYrrcAtom);
HX_RELEASE(m_pID32Atom);
#endif // QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
HX_RELEASE(m_piTunesDataAtomA9nam);
HX_RELEASE(m_piTunesDataAtomA9ART);
HX_RELEASE(m_piTunesDataAtomA9alb);
HX_RELEASE(m_piTunesDataAtomA9gen);
HX_RELEASE(m_piTunesDataAtomA9day);
HX_RELEASE(m_piTunesDataAtomA9cmt);
HX_RELEASE(m_piTunesDataAtomA9wrt);
HX_RELEASE(m_piTunesDataAtomA9too);
HX_RELEASE(m_piTunesDataAtomA9enc);
HX_RELEASE(m_piTunesDataAtomA9grp);
HX_RELEASE(m_piTunesDataAtomgrup);
HX_RELEASE(m_piTunesDataAtomaART);
HX_RELEASE(m_piTunesDataAtomcprt);
HX_RELEASE(m_piTunesDataAtomA9st3);
HX_RELEASE(m_piTunesDataAtomA9lyr);
HX_RELEASE(m_piTunesDataAtomtmpo);
HX_RELEASE(m_piTunesDataAtomcpil);
HX_RELEASE(m_piTunesDataAtomrtng);
HX_RELEASE(m_piTunesDataAtomtrkn);
HX_RELEASE(m_piTunesDataAtomdisk);
HX_RELEASE(m_piTunesDataAtomgnre);
+ HX_RELEASE(m_piTunesItemAtomcovr);
#endif //QTCONFIG_ITUNES_METAINFO
HX_RELEASE(m_pRTPSDPAtom);
if (pAtom && (pAtom->GetType() != QT_moov))
{
pAtom = NULL;
}
#ifdef QTCONFIG_3GPP_METAINFO
m_pID32Atom = FindID32Atom((CQT_moov_Atom*)pAtom);
if(m_pID32Atom)
{
m_pID32Atom->AddRef();
}
#endif // QTCONFIG_3GPP_METAINFO
if (pAtom)
{
CQT_mvhd_Atom *pMovieHeaderAtom = NULL;
pMovieHeaderAtom = (CQT_mvhd_Atom*)
pAtom->FindPresentChild(QT_mvhd);
CQT_rmra_Atom *pRmraHeaderAtom = NULL;
pRmraHeaderAtom = (CQT_rmra_Atom*)
pAtom->FindPresentChild(QT_rmra);
if (pMovieHeaderAtom)
{
m_ulMovieTimeScale = pMovieHeaderAtom->Get_TimeScale();
@@ -3089,60 +3098,63 @@
m_piTunesDataAtomaART = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_aART);
HX_ADDREF(m_piTunesDataAtomaART);
m_piTunesDataAtomcprt = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_cprt);
HX_ADDREF(m_piTunesDataAtomcprt);
m_piTunesDataAtomA9st3 = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_A9st3);
HX_ADDREF(m_piTunesDataAtomA9st3);
m_piTunesDataAtomA9lyr = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_A9lyr);
HX_ADDREF(m_piTunesDataAtomA9lyr);
m_piTunesDataAtomtmpo = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_tmpo);
HX_ADDREF(m_piTunesDataAtomtmpo);
m_piTunesDataAtomcpil = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_cpil);
HX_ADDREF(m_piTunesDataAtomcpil);
m_piTunesDataAtomrtng = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_rtng);
HX_ADDREF(m_piTunesDataAtomrtng);
m_piTunesDataAtomtrkn = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_trkn);
HX_ADDREF(m_piTunesDataAtomtrkn);
m_piTunesDataAtomdisk = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_disk);
HX_ADDREF(m_piTunesDataAtomdisk);
m_piTunesDataAtomgnre = CQT_ManagerTools::FindiTunesDataAtom(pIlstAtom, QT_gnre);
HX_ADDREF(m_piTunesDataAtomgnre);
+
+ m_piTunesItemAtomcovr = (CQT_iTunes_covr_Atom*)CQT_ManagerTools::FindiTunesItemAtom(pIlstAtom, QT_covr);
+ HX_ADDREF(m_piTunesItemAtomcovr);
}
}
}
#endif //QTCONFIG_ITUNES_METAINFO
pAtom = pAtom->FindPresentChild(QT_hnti);
}
ParseMovieHintInfo(pAtom);
retVal = m_ulMovieTimeScale ? HXR_OK : HXR_FAIL;
return retVal;
}
#ifdef QTCONFIG_3GPP_METAINFO
static void MergeLanguageEncoding(HXBOOL& bFound, HXBOOL& bAmbiguous, char lang[4], char out[3])
{
if(!bAmbiguous)
{
CHXISO639LangCodeRegistry lcreg;
if(bFound)
{
if((lang[0] != out[0]) || (lang[1] != out[1]) || (lang[2] != out[2]))
{
bAmbiguous = TRUE;
}
}
else if(lcreg.IsValidLangCode(lang))
{
Index: qtatoms.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/fileformat/qtatoms.cpp,v
retrieving revision 1.15
diff -d -H -w -U30 -r1.15 qtatoms.cpp
--- qtatoms.cpp 23 Oct 2009 09:53:02 -0000 1.15
+++ qtatoms.cpp 6 Nov 2009 21:30:01 -0000
@@ -175,60 +175,62 @@
case QT_A9gen:
return new CQT_iTunes_A9gen_Atom(ulOffset, ulSize, pParent);
case QT_A9day:
return new CQT_iTunes_A9day_Atom(ulOffset, ulSize, pParent);
case QT_A9cmt:
return new CQT_iTunes_A9cmt_Atom(ulOffset, ulSize, pParent);
case QT_A9wrt:
return new CQT_iTunes_A9wrt_Atom(ulOffset, ulSize, pParent);
case QT_A9too:
return new CQT_iTunes_A9too_Atom(ulOffset, ulSize, pParent);
case QT_A9enc:
return new CQT_iTunes_A9enc_Atom(ulOffset, ulSize, pParent);
case QT_A9grp:
return new CQT_iTunes_A9grp_Atom(ulOffset, ulSize, pParent);
case QT_grup:
return new CQT_iTunes_grup_Atom(ulOffset, ulSize, pParent);
case QT_aART:
return new CQT_iTunes_aART_Atom(ulOffset, ulSize, pParent);
case QT_A9st3:
return new CQT_iTunes_A9st3_Atom(ulOffset, ulSize, pParent);
case QT_A9lyr:
return new CQT_iTunes_A9lyr_Atom(ulOffset, ulSize, pParent);
case QT_tmpo:
return new CQT_iTunes_tmpo_Atom(ulOffset, ulSize, pParent);
case QT_cpil:
return new CQT_iTunes_cpil_Atom(ulOffset, ulSize, pParent);
case QT_trkn:
return new CQT_iTunes_trkn_Atom(ulOffset, ulSize, pParent);
case QT_disk:
return new CQT_iTunes_disk_Atom(ulOffset, ulSize, pParent);
+ case QT_covr:
+ return new CQT_iTunes_covr_Atom(ulOffset, ulSize, pParent);
#endif //QTCONFIG_ITUNES_METAINFO
case QT_meta:
return new CQT_meta_Atom(ulOffset, ulSize, pParent);
case QT_minf:
return new CQT_minf_Atom(ulOffset, ulSize, pParent);
case QT_dinf:
return new CQT_dinf_Atom(ulOffset, ulSize, pParent);
case QT_dref:
return new CQT_dref_Atom(ulOffset, ulSize, pParent);
case QT_stbl:
return new CQT_stbl_Atom(ulOffset, ulSize, pParent);
case QT_stts:
return new CQT_stts_Atom(ulOffset, ulSize, pParent);
case QT_ctts:
return new CQT_ctts_Atom(ulOffset, ulSize, pParent);
case QT_stss:
return new CQT_stss_Atom(ulOffset, ulSize, pParent);
case QT_stsd:
return new CQT_stsd_Atom(ulOffset, ulSize, pParent);
case QT_stsz:
return new CQT_stsz_Atom(ulOffset, ulSize, pParent);
case QT_stz2:
return new CQT_stz2_Atom(ulOffset, ulSize, pParent);
case QT_stsc:
return new CQT_stsc_Atom(ulOffset, ulSize, pParent);
case QT_stco:
return new CQT_stco_Atom(ulOffset, ulSize, pParent);
case QT_co64:
return new CQT_co64_Atom(ulOffset, ulSize, pParent);
Index: qtffplin.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/fileformat/qtffplin.cpp,v
retrieving revision 1.80
diff -d -H -w -U30 -r1.80 qtffplin.cpp
--- qtffplin.cpp 26 Oct 2009 21:15:02 -0000 1.80
+++ qtffplin.cpp 6 Nov 2009 21:30:05 -0000
@@ -750,62 +750,70 @@
if(SUCCEEDED(status))
{
status = UpdateHeaderProperty(status, pHeader,
_3GPP_META_INFO_LOCATION_ALTITUDE_KEY, strPos, strlen(strPos));
}
}
}
// 3GP Asset Info: Album
if(SUCCEEDED(status) && m_MovieInfo.GetAlbumTitleLength())
{
status = UpdateHeaderProperty(status, pHeader, _3GPP_META_INFO_ALBUM_TITLE_KEY,
(const char*)m_MovieInfo.GetAlbumTitle(), m_MovieInfo.GetAlbumTitleLength());
}
// track number is optional
if(SUCCEEDED(status) && m_MovieInfo.HasTrackNumber())
{
pHeader->SetPropertyULONG32(_3GPP_META_INFO_TRACK_NUMBER_KEY, (ULONG32) m_MovieInfo.GetTrackNumber());
}
// 3GP Asset Info: Recording Year
if(SUCCEEDED(status) && m_MovieInfo.HasRecordingYear())
{
status = pHeader->SetPropertyULONG32(_3GPP_META_INFO_RECORDING_YEAR_KEY, (ULONG32) m_MovieInfo.GetRecordingYear());
}
// 3GP Asset Info: ID32 BLOB
if(SUCCEEDED(status) && m_MovieInfo.GetID32BlobSize())
{
+ // _3GPP_META_INFO_ID32_BLOB_KEY is a legacy way of injecting ID32 data into the header
status = SetBufferPropertyCCF(pHeader, _3GPP_META_INFO_ID32_BLOB_KEY,
m_MovieInfo.GetID32Blob(), m_MovieInfo.GetID32BlobSize(), m_pContext);
+
+ // 3GP ID32 box may be contained by moov box, in this case
+ // insert results of ID32 blob processing into the file header
+ if(SUCCEEDED(status))
+ {
+ status = ID3Tools::TransformID32BlobToProperties(pHeader, m_MovieInfo.GetID32Blob(), m_MovieInfo.GetID32BlobSize());
+ }
}
// 3GP language encoding, extract as global property for all atoms
if(SUCCEEDED(status))
{
char globalLangEnc[4] = { 0, 0, 0, 0 };
if(m_MovieInfo.GetGlobalLanguageEncoding(globalLangEnc))
{
status = SetCStringPropertyWithNullTermEx(pHeader, _3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY,
(BYTE*)globalLangEnc, 3, m_pContext, HX_TEXT_ENCODING_TYPE_UTF8, SET_AS_BUFFER_PROPERTY);
}
}
#endif // QTCONFIG_3GPP_METAINFO
return status;
}
#endif // QTCONFIG_3GPP_TAC || QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
HX_RESULT CQTFileFormat::ExtractiTunesAssetInfoToHeader(HX_RESULT status, IHXValues* pHeader)
{
// iTunes Asset Info: Song Name
if(SUCCEEDED(status) && m_MovieInfo.GetiTunesSongNameByteLength())
{
status = UpdateHeaderProperty(status, pHeader, _ITUNES_META_INFO_TITLE_KEY,
(const char*)m_MovieInfo.GetiTunesSongName(), m_MovieInfo.GetiTunesSongNameByteLength(),
m_MovieInfo.GetiTunesSongNameEncoding());
}
// iTunes Asset Info: Artist
@@ -958,60 +966,112 @@
// iTunes Asset Info: Content Rating
if(SUCCEEDED(status) && m_MovieInfo.HasiTunesContentRating())
{
status = pHeader->SetPropertyULONG32(_ITUNES_META_INFO_EXPLICIT_CONTENT_KEY, (ULONG32) m_MovieInfo.GetiTunesContentRating());
}
// iTunes Asset Info: Track Number
if(SUCCEEDED(status) && m_MovieInfo.HasiTunesTrackNumber())
{
status = pHeader->SetPropertyULONG32(_ITUNES_META_INFO_TRACK_NUMBER_KEY, (ULONG32) m_MovieInfo.GetiTunesTrackNumber());
}
// iTunes Asset Info: Track Count
if(SUCCEEDED(status) && m_MovieInfo.HasiTunesTrackCount())
{
status = pHeader->SetPropertyULONG32(_ITUNES_META_INFO_TRACK_COUNT_KEY, (ULONG32) m_MovieInfo.GetiTunesTrackCount());
}
// iTunes Asset Info: Disc Number
if(SUCCEEDED(status) && m_MovieInfo.HasiTunesDiscNumber())
{
status = pHeader->SetPropertyULONG32(_ITUNES_META_INFO_DISC_NUMBER_KEY, (ULONG32) m_MovieInfo.GetiTunesDiscNumber());
}
// iTunes Asset Info: Disc Count
if(SUCCEEDED(status) && m_MovieInfo.HasiTunesDiscCount())
{
status = pHeader->SetPropertyULONG32(_ITUNES_META_INFO_DISC_COUNT_KEY, (ULONG32) m_MovieInfo.GetiTunesDiscCount());
}
+ // iTunes Asset Info: Cover Art
+ if(SUCCEEDED(status) && m_MovieInfo.GetiTunesImageCount())
+ {
+ int iAPICDataIndex = 0;
+
+ // go through available iTunes images
+ for(UINT16 index = 0; SUCCEEDED(status) && (index < m_MovieInfo.GetiTunesImageCount()); index++)
+ {
+ const char* szImageMimeType = m_MovieInfo.GetiTunesImageValueMimeType(index);
+ UINT8* pImageData = m_MovieInfo.GetiTunesImageValue(index);
+ UINT32 uImageDataByteLen = m_MovieInfo.GetiTunesImageValueByteLength(index);
+
+ if(szImageMimeType && pImageData && uImageDataByteLen)
+ {
+ status = HXR_OUTOFMEMORY;
+
+ // construct APICFrame
+ ID3Tools::APICFrame* pFrame = new ID3Tools::APICFrame;
+ if(pFrame)
+ {
+ // ID3v2 picture type has no equivalent field in iTunes meta-info structures,
+ // so just use unique value for each injected frame.
+ pFrame->SetPictureType((UINT8)index);
+ pFrame->SetMimeType(szImageMimeType);
+
+ status = pFrame->SetPictureData(pImageData, uImageDataByteLen);
+ }
+
+ // inject frame into the header
+ if(SUCCEEDED(status) && pFrame)
+ {
+ char key[128];
+ sprintf(key, _ITUNES_META_INFO_PICTURE_KEY, int(iAPICDataIndex));
+
+ status = pFrame->SerializeToBufferProperty(pHeader, key);
+ }
+
+ // update image count property
+ if(SUCCEEDED(status))
+ {
+ iAPICDataIndex++;
+
+ PropTools::CopyPropertyULONG32(pHeader, TRUE, iAPICDataIndex,
+ _GENERIC_META_INFO_PICTURE_COUNT_KEY, TRUE);
+ }
+
+ // cleanup
+ delete pFrame;
+ }
+ }
+ }
+
return status;
}
#endif //QTCONFIG_ITUNES_METAINFO
HX_RESULT CQTFileFormat::MakeFileHeader(HX_RESULT status)
{
HX_RESULT retVal;
IHXValues* pHeader = NULL;
// Check the license
#ifdef QTCONFIG_SERVER
if (SUCCEEDED(status) && (m_TrackManager.GetEType() == QT_ETYPE_SERVER))
{
switch (m_TrackManager.GetFType())
{
case QT_FTYPE_QT:
case QT_FTYPE_UNKNOWN:
{
if(!m_bQTLicensed)
{
ReportError(IDS_ERR_QT_NOTLICENSED, HXR_NOT_LICENSED);
return m_pFFResponse->FileHeaderReady(
HXR_NOT_LICENSED, NULL);
}
break;
}
case QT_FTYPE_MP4:
{
UINT32 ulBrand = 0;
m_TrackManager.GetMajorBrand(&ulBrand);
Index: qttrack.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/fileformat/qttrack.cpp,v
retrieving revision 1.39
diff -d -H -w -U30 -r1.39 qttrack.cpp
--- qttrack.cpp 5 Oct 2009 20:50:08 -0000 1.39
+++ qttrack.cpp 6 Nov 2009 21:30:06 -0000
@@ -37,60 +37,61 @@
* Defines
*/
// #define _LOG_DATA_ACCESS
#define QTTRACKCACHE_PAGE_SIZE 0x0000FFFF
#ifdef HELIX_FEATURE_MIN_HEAP
#define QT_MAX_SEEK_SKIPBACK_TIME_CLIENT 20000 // milliseconds
#else
#define QT_MAX_SEEK_SKIPBACK_TIME_CLIENT 300000 // milliseconds
#endif
#define QT_MAX_SEEK_SKIPBACKAHEAD_RATIO_CLIENT 20
#define QT_MAX_SEEK_SKIPBACK_TIME_SERVER 10000 // milliseconds
#define QT_MAX_SEEK_SKIPBACKAHEAD_RATIO_SERVER 5
#define QT_NO_KEY_FRAME_SKIPBACK_TIME 5000
/****************************************************************************
* Includes
*/
#include "qtpktasm.h"
#include "qtffplin.h"
#include "qtpacketizerfct.h"
#include "qttrack.h"
#include "qtffrefcounter.h"
#include "hxstrutl.h"
#include "sdpchunk.h"
#include "sdppyldinfo.h"
+#include "metautil.h"
/****************************************************************************
* Class CQTTrack
*/
/****************************************************************************
* Constructor/Destructor
*/
CQTTrack::CQTTrack(CQTAtom* pTrackAtom)
: m_pTrackAtom((CQT_trak_Atom*) pTrackAtom)
, m_pResponse(NULL)
, m_pFileFormat(NULL)
, m_pPacketAssembler(NULL)
, m_pClassFactory(NULL)
, m_ulTrackID(0)
, m_ulReadSize(0)
, m_ulReadPageSize(0)
, m_ulReadPageOffset(0)
, m_pReadFileNameBuffer(NULL)
, m_pReadFileName(NULL)
, m_PendingState(QTT_Offline)
, m_bTrackDone(FALSE)
, m_uBytesPerCBlock(0)
, m_uSamplesPerCBlock(0)
, m_uStreamNumber(0)
, m_uBaseRuleNumber(0)
, m_pPacketizer(NULL)
, m_pFileSwitcher(NULL)
, m_bIsSubscribed(FALSE)
, m_lRefCount(0)
@@ -526,60 +527,73 @@
if (ulWidth != 0)
{
pHeader->SetPropertyULONG32(QT_WIDTH_METANAME, ulWidth);
}
if (ulHeight != 0)
{
pHeader->SetPropertyULONG32(QT_HEIGHT_METANAME, ulHeight);
}
if (ulFrameWidth != 0)
{
pHeader->SetPropertyULONG32(QT_FRAMEWIDTH_METANAME, ulFrameWidth);
}
if (ulFrameHeight != 0)
{
pHeader->SetPropertyULONG32(QT_FRAMEHEIGHT_METANAME, ulFrameHeight);
}
if (m_TrackInfo.GetTrackType() == QT_vide)
{
UINT32 framesPerMSecond;
if ( (framesPerMSecond=GetFramesPerMSecond(pMovieInfo)) )
{
pHeader->SetPropertyULONG32("FramesPerMSecond", framesPerMSecond);
}
}
}
+#ifdef QTCONFIG_3GPP_METAINFO
+ if (SUCCEEDED(retVal) && m_TrackInfo.GetID32BlobSize())
+ {
+ // 3GP ID32 box may be contained by trak box, in this case
+ // insert results of ID32 blob processing into the stream header
+ ID3Tools::TransformID32BlobToProperties(pHeader, m_TrackInfo.GetID32Blob(), m_TrackInfo.GetID32BlobSize());
+
+ // _3GPP_META_INFO_ID32_BLOB_KEY is a legacy way of injecting ID32 data into the header
+ SetBufferPropertyCCF(pHeader, _3GPP_META_INFO_ID32_BLOB_KEY,
+ m_TrackInfo.GetID32Blob(), m_TrackInfo.GetID32BlobSize(), m_pFileFormat->GetContext());
+ }
+#endif // QTCONFIG_3GPP_METAINFO
+
if (SUCCEEDED(retVal))
{
// .mp4 and .mov files may produce streams with out-of-order time stamps
// Client core does not normally expect this in RDT protocol so set this
// property to alert client core of this fact.
pHeader->SetPropertyULONG32("HasOutOfOrderTS", 1);
}
#ifdef QTCONFIG_ALTERNATE_STREAMS
// If switchable, add the base rule for this stream
if (SUCCEEDED(retVal) && m_TrackInfo.GetSwitchGroupId() != 0)
{
pHeader->SetPropertyULONG32("BaseRule", m_uBaseRuleNumber);
}
#endif
// Set ASM Rule Book
if (SUCCEEDED(retVal))
{
char pRuleBook[256]; /* Flawfinder: ignore */
#ifdef QTCONFIG_SERVER
pHeader->GetPropertyULONG32("RTPPayloadType", ulPayloadType);
if (pTrackManager->GetEType() != QT_ETYPE_CLIENT)
{
// Server Side
retVal = HXR_FAIL;
if (ulPayloadType != QT_BAD_PAYLOAD)
{
Index: pub/qtatmmgs.h
===================================================================
RCS file: /cvsroot/datatype/mp4/fileformat/pub/qtatmmgs.h,v
retrieving revision 1.29
diff -d -H -w -U30 -r1.29 qtatmmgs.h
--- pub/qtatmmgs.h 23 Oct 2009 09:53:02 -0000 1.29
+++ pub/qtatmmgs.h 6 Nov 2009 21:30:08 -0000
@@ -61,61 +61,62 @@
#define QT_TSEL_BANDWIDTH 0x02
#define QT_TSEL_CODEC 0x04
#define QT_TSEL_SCREEN_SIZE 0x08
#define QT_TSEL_MAX_PACKET_SIZE 0x10
#define QT_TSEL_MEDIA_TYPE 0x20
/****************************************************************************
* Includes
*/
#include "qtatoms.h"
#include "hxcomm.h"
class CQTTrackManager;
class CQT_MovieInfo_Manager;
/****************************************************************************
* Manager Tools
*/
class CQT_ManagerTools
{
public:
static CQT_meta_Atom* FindMetaAtom(CQTAtom* pAtom);
#ifdef QTCONFIG_3GPP_METAINFO
static CQT_ID32_Atom* FindID32Atom(CQT_meta_Atom* pMetaAtom);
#endif // QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
static CQT_iTunes_ilst_Atom* FindiTunesIlstAtom(CQT_meta_Atom* pMetaAtom);
- static CQT_iTunes_data_Atom* FindiTunesDataAtom(CQT_iTunes_ilst_Atom* pIlstAtom, QTAtomType MetaInfoAtomType);
+ static CQTAtom* FindiTunesItemAtom(CQT_iTunes_ilst_Atom* pIlstAtom, QTAtomType ItemAtomType);
+ static CQT_iTunes_data_Atom* FindiTunesDataAtom(CQT_iTunes_ilst_Atom* pIlstAtom, QTAtomType ItemAtomType);
#endif // QTCONFIG_ITUNES_METAINFO
};
/****************************************************************************
* Track Edit Manager
* Note: All locally stored times are in media units
*/
class CQT_TrackEdit_Manager
{
public:
/*
* Constructor/Destructor
*/
CQT_TrackEdit_Manager(void);
~CQT_TrackEdit_Manager();
/*
* Main Interface
*/
HX_RESULT Init( CQTAtom* pAtom,
ULONG32 ulMovieTimeScale,
ULONG32 ulMediaTimeScale);
HXBOOL EstablishByMediaTime(ULONG32 ulTime);
HXBOOL EstablishByTime(ULONG32 ulTime) // Given in miliseconds
{
return EstablishByMediaTime(
(ULONG32) (((double) ulTime) / 1000.0 * m_ulMediaTimeScale + 0.5));
}
@@ -1369,60 +1370,85 @@
return m_piTunesDataAtomtrkn ? m_piTunesDataAtomtrkn->IsAtomWellFormed() : FALSE;
}
UINT32 GetiTunesTrackCount(void)
{
return m_piTunesDataAtomtrkn ? m_piTunesDataAtomtrkn->GetSpecialValue_TrackCount() : 0;
}
//*** iTunes disk atom / Disc Number & Count *************************************
HXBOOL HasiTunesDiscNumber(void)
{
return m_piTunesDataAtomdisk ? m_piTunesDataAtomdisk->IsAtomWellFormed() : FALSE;
}
UINT32 GetiTunesDiscNumber(void)
{
return m_piTunesDataAtomdisk ? m_piTunesDataAtomdisk->GetSpecialValue_DiskNumber() : 0;
}
HXBOOL HasiTunesDiscCount(void)
{
return m_piTunesDataAtomdisk ? m_piTunesDataAtomdisk->IsAtomWellFormed() : FALSE;
}
UINT32 GetiTunesDiscCount(void)
{
return m_piTunesDataAtomdisk ? m_piTunesDataAtomdisk->GetSpecialValue_DiskCount() : 0;
}
+ //*** iTunes covr atom / Cover Art *************************************
+
+ UINT16 GetiTunesImageCount(void)
+ {
+ return m_piTunesItemAtomcovr ? m_piTunesItemAtomcovr->GetImageAtomCount() : 0;
+ }
+
+ const char* GetiTunesImageValueMimeType(UINT16 imageIndex)
+ {
+ CQT_iTunes_data_Atom* pDataAtom = m_piTunesItemAtomcovr ? m_piTunesItemAtomcovr->GetImageAtom(imageIndex) : 0;
+ return pDataAtom ? pDataAtom->GetImageValueMimeType() : 0;
+ }
+
+ UINT32 GetiTunesImageValueByteLength(UINT16 imageIndex)
+ {
+ CQT_iTunes_data_Atom* pDataAtom = m_piTunesItemAtomcovr ? m_piTunesItemAtomcovr->GetImageAtom(imageIndex) : 0;
+ return pDataAtom ? pDataAtom->GetImageValueByteLength() : 0;
+ }
+
+ UINT8* GetiTunesImageValue(UINT16 imageIndex)
+ {
+ CQT_iTunes_data_Atom* pDataAtom = m_piTunesItemAtomcovr ? m_piTunesItemAtomcovr->GetImageAtom(imageIndex) : 0;
+ return pDataAtom ? pDataAtom->GetImageValue() : 0;
+ }
+
#endif //QTCONFIG_ITUNES_METAINFO
char* GetRefURL(void)
{
return m_pRefURL;
}
ULONG32 GetSDPLength(void);
UINT8* GetSDP(void);
private:
HX_RESULT ParseMovieHintInfo(CQTAtom* pAtom);
#ifdef QTCONFIG_3GPP_METAINFO
static CQT_ID32_Atom* FindID32Atom(CQT_moov_Atom* pMoovAtom);
#endif // QTCONFIG_3GPP_METAINFO
char *m_pRefURL;
ULONG32 m_ulMovieTimeScale;
ULONG32 m_ulMovieDuration;
CQT_name_Atom* m_pNameAtom;
#ifdef QTCONFIG_3GPP_TAC
CQT_titl_Atom* m_pTitlAtom;
CQT_auth_Atom* m_pAuthAtom;
CQT_cprt_Atom* m_pCprtAtom;
#endif // QTCONFIG_3GPP_TAC
#ifdef QTCONFIG_3GPP_METAINFO
CQT_dscp_Atom* m_pDscpAtom;
@@ -1432,40 +1458,41 @@
CQT_clsf_Atom* m_pClsfAtom;
CQT_kywd_Atom* m_pKywdAtom;
CQT_loci_Atom* m_pLociAtom;
CQT_albm_Atom* m_pAlbmAtom;
CQT_yrrc_Atom* m_pYrrcAtom;
CQT_ID32_Atom* m_pID32Atom;
#endif // QTCONFIG_3GPP_METAINFO
#ifdef QTCONFIG_ITUNES_METAINFO
CQT_iTunes_data_Atom* m_piTunesDataAtomA9nam;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9ART;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9alb;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9gen;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9day;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9cmt;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9wrt;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9too;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9enc;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9grp;
CQT_iTunes_data_Atom* m_piTunesDataAtomgrup;
CQT_iTunes_data_Atom* m_piTunesDataAtomaART;
CQT_iTunes_data_Atom* m_piTunesDataAtomcprt;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9st3;
CQT_iTunes_data_Atom* m_piTunesDataAtomA9lyr;
CQT_iTunes_data_Atom* m_piTunesDataAtomtmpo;
CQT_iTunes_data_Atom* m_piTunesDataAtomcpil;
CQT_iTunes_data_Atom* m_piTunesDataAtomrtng;
CQT_iTunes_data_Atom* m_piTunesDataAtomtrkn;
CQT_iTunes_data_Atom* m_piTunesDataAtomdisk;
CQT_iTunes_data_Atom* m_piTunesDataAtomgnre;
+ CQT_iTunes_covr_Atom* m_piTunesItemAtomcovr;
#endif //QTCONFIG_ITUNES_METAINFO
CQT_rtp_Atom* m_pRTPSDPAtom;
};
#ifdef QTCONFIG_SPEED_OVER_SIZE
#include "qtatmmgs_inline.h"
#endif // QTCONFIG_SPEED_OVER_SIZE
#endif // _QTATMMGS_H_
Index: pub/qtatoms.h
===================================================================
RCS file: /cvsroot/datatype/mp4/fileformat/pub/qtatoms.h,v
retrieving revision 1.36
diff -d -H -w -U30 -r1.36 qtatoms.h
--- pub/qtatoms.h 23 Oct 2009 09:53:02 -0000 1.36
+++ pub/qtatoms.h 6 Nov 2009 21:30:12 -0000
@@ -1587,82 +1587,112 @@
case QT_A9too:
case QT_A9enc:
case QT_A9grp:
case QT_grup:
case QT_aART:
case QT_cprt:
case QT_A9st3:
case QT_A9lyr:
return ((tc == TypeIndicatorTypeCode_Implicit || tc == TypeIndicatorTypeCode_UTF8) && (valueSize >= 1))
|| ((tc == TypeIndicatorTypeCode_UTF16BE) && (valueSize >= 2) && (valueSize % 2 == 0));
case QT_tmpo: //4 bytes per iTMF spec, most tools expect 2 bytes
case QT_cpil: //1 byte per iTMF spec
case QT_rtng: //1 byte per iTMF spec
// tolerate integer sizes 1,2,4 for any pure integer field
return (tc == TypeIndicatorTypeCode_Implicit || tc == TypeIndicatorTypeCode_Integer)
&& ((valueSize == 1) || (valueSize == 2) || (valueSize == 4));
case QT_trkn:
// 7 bytes per iTMF spec, most tools expect and write out 8 bytes, we need only 6
return (tc == TypeIndicatorTypeCode_Implicit) && (valueSize >= 6);
case QT_disk:
// 6 bytes per iTMF spec, but we can tolerate anything larger
return (tc == TypeIndicatorTypeCode_Implicit) && (valueSize >= 6);
case QT_gnre:
// list of 2-byte entries
return (tc == TypeIndicatorTypeCode_Implicit || tc == TypeIndicatorTypeCode_Genres)
&& (valueSize >= 2) && (valueSize % 2 == 0);
+
+ case QT_covr:
+ // currently we support JPEG and PNG
+ return (tc == TypeIndicatorTypeCode_JPEG || tc == TypeIndicatorTypeCode_PNG);
}
return FALSE;
}
HX_TEXT_ENCODING_TYPE GetStringValueEncoding()
{
return IsAtomWellFormed()
? ((GetTypeCode() == TypeIndicatorTypeCode_UTF16BE) ? HX_TEXT_ENCODING_TYPE_UTF16BE : HX_TEXT_ENCODING_TYPE_UTF8)
: HX_TEXT_ENCODING_TYPE_UNKNOWN;
}
- ULONG32 GetStringValueByteLength()
+ UINT32 GetStringValueByteLength()
{
return IsAtomWellFormed() ? GetValueSize() : 0;
}
UINT8* GetStringValue()
{
return IsAtomWellFormed() ? ((Data*) m_pData)->pValue : 0;
}
- ULONG32 GetIntegerValue()
+ const char* GetImageValueMimeType()
+ {
+ if(IsAtomWellFormed())
+ {
+ switch(GetTypeCode())
+ {
+ case TypeIndicatorTypeCode_JPEG:
+ return "image/jpeg";
+
+ case TypeIndicatorTypeCode_PNG:
+ return "image/png";
+ }
+ }
+ return 0;
+ }
+
+ UINT32 GetImageValueByteLength()
+ {
+ return IsAtomWellFormed() ? GetValueSize() : 0;
+ }
+
+ UINT8* GetImageValue()
+ {
+ return IsAtomWellFormed() ? ((Data*) m_pData)->pValue : 0;
+ }
+
+ UINT32 GetIntegerValue()
{
UINT32 val = 0;
if(IsAtomWellFormed())
{
switch(GetValueSize())
{
case 1:
val = UINT32(*(((Data*)m_pData)->pValue));
break;
case 2:
val = UINT32(GetUI16(((Data*)m_pData)->pValue));
break;
case 4:
val = UINT32(GetUL32(((Data*)m_pData)->pValue));
break;
}
}
return FilterIntegerValueByAtomType(val);
}
UINT32 GetSpecialValue_PredefinedGenreCount()
{
// gnre: 2 bytes for each predefined entry
return IsAtomWellFormed() ? (GetValueSize() / 2) : 0;
}
UINT16 GetSpecialValue_PredefinedGenreEntry(UINT32 ulListIndex)
@@ -1690,60 +1720,62 @@
return IsAtomWellFormed() ? UINT32(GetUI16(((Data*)m_pData)->pValue + 2)) : 0;
}
UINT32 GetSpecialValue_DiskCount()
{
// disk: 2 bytes reserved, 2 bytes disc number, 2 bytes disc count
return IsAtomWellFormed() ? UINT32(GetUI16(((Data*)m_pData)->pValue + 4)) : 0;
}
protected:
UINT32 GetValueSize()
{
// (value size) = (atom size) - (8 bytes atom size/type fields)
// - (4 bytes type-indicator field) - (4 bytes locale)
const UINT32 headerSize = 16;
UINT32 atomSize = GetSize();
return (atomSize > headerSize) ? (atomSize - headerSize) : 0;
}
QTAtomType GetParentAtomType()
{
CQTAtom* pParent = GetParent();
return pParent ? pParent->GetType() : 0;
}
enum TypeIndicatorTypeCode
{
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_JPEG = 13, //in JFIF wrapper
+ TypeIndicatorTypeCode_PNG = 14, //in PNG wrapper
TypeIndicatorTypeCode_Genres = 18, //special enumeration
TypeIndicatorTypeCode_Integer = 21 //signed big-endian integer in 1,2,3,4,8 bytes
};
TypeIndicatorTypeCode GetTypeCode()
{
return (TypeIndicatorTypeCode)((Data*)m_pData)->pTypeIndicatorTypeCode[0];
}
UINT32 GetLocale()
{
return UINT32(GetUL32(((Data*)m_pData)->pLocale));
}
UINT32 FilterIntegerValueByAtomType(UINT32 value)
{
switch(GetParentAtomType())
{
case QT_cpil: //1 byte boolean per iTMF spec
case QT_rtng: //1 byte boolean per iTMF spec
return value ? 1 : 0;
}
return value;
}
};
/****************************************************************************
* iTunes A9nam Atom Class
*/
class CQT_iTunes_A9nam_Atom : public CQTAtom
@@ -2178,60 +2210,98 @@
/*
* Required Virtual Methods
*/
virtual HXBOOL IsLeafType(void) { return FALSE; }
virtual QTAtomType GetType(void) { return QT_trkn; }
};
/****************************************************************************
* iTunes disk Atom Class
*/
class CQT_iTunes_disk_Atom : public CQTAtom
{
public:
/*
* Constructor/Destructor
*/
CQT_iTunes_disk_Atom(ULONG32 ulOffset,
ULONG32 ulSize,
CQTAtom *pParent) : CQTAtom(ulOffset,
ulSize,
pParent) {;}
/*
* Required Virtual Methods
*/
virtual HXBOOL IsLeafType(void) { return FALSE; }
virtual QTAtomType GetType(void) { return QT_disk; }
};
+/****************************************************************************
+ * iTunes covr Atom Class
+ */
+class CQT_iTunes_covr_Atom : public CQTAtom
+{
+public:
+ /*
+ * Constructor/Destructor
+ */
+ CQT_iTunes_covr_Atom(ULONG32 ulOffset,
+ ULONG32 ulSize,
+ CQTAtom *pParent) : CQTAtom(ulOffset,
+ ulSize,
+ pParent) {;}
+
+ /*
+ * Required Virtual Methods
+ */
+ virtual HXBOOL IsLeafType(void) { return FALSE; }
+ virtual QTAtomType GetType(void) { return QT_covr; }
+
+ /*
+ * Data Access Methods
+ */
+ UINT16 GetImageAtomCount()
+ {
+ return (UINT16)GetPresentChildCount();
+ }
+ CQT_iTunes_data_Atom* GetImageAtom(UINT16 index)
+ {
+ if(index < GetPresentChildCount())
+ {
+ return (CQT_iTunes_data_Atom*)GetPresentChild(index);
+ }
+ return 0;
+ }
+};
+
#endif //QTCONFIG_ITUNES_METAINFO
/****************************************************************************
* name Atom Class
*/
class CQT_name_Atom : public CQTAtom
{
public:
/*
* Leaf Data Format
*/
struct Data
{
UINT8 pName[1];
} PACKING;
/*
* Constructor/Destructor
*/
CQT_name_Atom(ULONG32 ulOffset,
ULONG32 ulSize,
CQTAtom *pParent) : CQTAtom(ulOffset,
ulSize,
pParent) {;}
/*
* Required Virtual Methods
*/
virtual HXBOOL IsLeafType(void) { return TRUE; }
virtual QTAtomType GetType(void) { return QT_name; }
datatype_mp4_filewriter.diff
(text/x-patch, 52.6 KB)
Index: 3gpmeta.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/3gpmeta.cpp,v
retrieving revision 1.3
diff -d -H -w -U30 -r1.3 3gpmeta.cpp
--- 3gpmeta.cpp 23 Oct 2009 09:47:54 -0000 1.3
+++ 3gpmeta.cpp 6 Nov 2009 21:45:31 -0000
@@ -502,58 +502,65 @@
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_RESULT C3GPAtom_ID32::SetBlob(UCHAR* pData, UINT32 size)
{
HX_VECTOR_DELETE(m_pBlob);
- m_uBlobSize = size;
+ m_uBlobSize = 0;
+
m_pBlob = new UCHAR[size];
+ if(m_pBlob)
+ {
+ m_uBlobSize = size;
memcpy(m_pBlob, pData, size);
+ return HXR_OK;
+ }
+ return HXR_OUTOFMEMORY;
}
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.5
diff -d -H -w -U30 -r1.5 3gpmeta.h
--- 3gpmeta.h 23 Oct 2009 09:47:54 -0000 1.5
+++ 3gpmeta.h 6 Nov 2009 21:45:33 -0000
@@ -271,41 +271,41 @@
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);
+ HX_RESULT 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.7
diff -d -H -w -U30 -r1.7 m4amdatoms.h
--- m4amdatoms.h 23 Oct 2009 09:47:54 -0000 1.7
+++ m4amdatoms.h 6 Nov 2009 21:45:33 -0000
@@ -11,60 +11,61 @@
* (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 ***** */
// m4amdatoms.h: atoms specific to m4a metadata
#ifndef _M4AMDATOMS_H_
#define _M4AMDATOMS_H_
#include "mp4atoms.h"
+#include "metautil.h"
//iTunes stype meta info
// meta; this is the top level atom inside the udta, and all
// metadata atoms live inside it
class CiTunesAtom_meta : public CMP4VersionedAtom
{
public:
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 CiTunesAtom_hdlr : public CMP4VersionedAtom
{
public:
@@ -285,108 +286,158 @@
{
// 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( SetSpecial_PredefinedGenreEntries ) (THIS_ CHXPtrArray& genreEntries )
{
if(!genreEntries.GetSize())
{
return HXR_FAILED;
}
// 2*count bytes
const UINT32 dataLength = genreEntries.GetSize() * 2;
HX_RESULT retVal = AllocBuffer(dataLength);
if( SUCCEEDED(retVal) )
{
UCHAR* pTmp = m_ucByteBuf;
- for(UINT32 i = 0; i < genreEntries.GetSize(); i++)
+ for(int i = 0; i < genreEntries.GetSize(); i++)
{
UINT16 entry = (UINT16)(UINT32)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( SetPicture ) (THIS_ const ID3Tools::APICFrame* pFrame )
+ {
+ HX_RESULT retVal = HXR_FAILED;
+
+ if(pFrame && pFrame->GetPictureDataSize())
+ {
+ TypeIndicatorTypeCode tc = TypeIndicatorTypeCode_Implicit;
+
+ if(pFrame->GetMimeType() == "image/jpeg")
+ {
+ tc = TypeIndicatorTypeCode_JPEG;
+ retVal = HXR_OK;
+ }
+ else if(pFrame->GetMimeType() == "image/png")
+ {
+ tc = TypeIndicatorTypeCode_PNG;
+ retVal = HXR_OK;
+ }
+
+ if(SUCCEEDED(retVal))
+ {
+ retVal = AllocBuffer(pFrame->GetPictureDataSize());
+ }
+
+ if(SUCCEEDED(retVal) && m_ucByteBuf && m_uiByteBufLength)
+ {
+ memcpy(m_ucByteBuf, pFrame->GetPictureData(), m_uiByteBufLength);
+ }
+
+ if(SUCCEEDED(retVal))
+ {
+ SetTypeIndicatorTypeCode(tc);
+ }
+ }
+ return retVal;
+ }
+ static HXBOOL IsSupportedPictureType( const ID3Tools::APICFrame* pFrame )
+ {
+ if(pFrame && pFrame->GetPictureDataSize())
+ {
+ if((pFrame->GetMimeType() == "image/jpeg") ||
+ (pFrame->GetMimeType() == "image/png"))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
protected:
void ClearData()
{
m_uiByteBufLength = 0;
HX_VECTOR_DELETE( m_ucByteBuf );
SetTypeIndicatorTypeCode(TypeIndicatorTypeCode_Implicit);
}
HX_RESULT AllocBuffer(ULONG32 len)
{
ClearData();
HX_RESULT retVal = HXR_INVALID_PARAMETER;
if(len)
{
retVal = HXR_OUTOFMEMORY;
m_ucByteBuf = new UCHAR[len];
if(m_ucByteBuf)
{
m_uiByteBufLength = len;
memset(m_ucByteBuf, 0, len);
retVal = HXR_OK;
}
}
return retVal;
}
enum TypeIndicatorTypeCode
{
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_JPEG = 13, //in JFIF wrapper
+ TypeIndicatorTypeCode_PNG = 14, //in PNG wrapper
TypeIndicatorTypeCode_Genres = 18, //special enumeration
TypeIndicatorTypeCode_Integer = 21 //signed big-endian integer in 1,2,3,4,8 bytes
};
void SetTypeIndicatorTypeCode(TypeIndicatorTypeCode tc)
{
m_typeIndicatorTypeCode = (UCHAR)tc;
}
private:
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 CiTunesAtom_A9nam : public CMP4ContainerAtom
{
public:
CiTunesAtom_A9nam() : CMP4ContainerAtom(MP4_BUILD_ATOMID(0xA9,'n','a','m'))
{}
};
// track subtitle
// string
class CiTunesAtom_A9st3 : public CMP4ContainerAtom
@@ -540,31 +591,40 @@
{}
};
// 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'))
{}
};
+// cover art
+// byte array
+class CiTunesAtom_covr : public CMP4ContainerAtom
+{
+public:
+ CiTunesAtom_covr() : CMP4ContainerAtom(MP4_BUILD_ATOMID('c','o','v','r'))
+ {}
+};
+
#endif /* _M4AMDATOMS_H_ */
Index: mp4sm.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.cpp,v
retrieving revision 1.20
diff -d -H -w -U30 -r1.20 mp4sm.cpp
--- mp4sm.cpp 23 Oct 2009 09:47:54 -0000 1.20
+++ mp4sm.cpp 6 Nov 2009 21:45:39 -0000
@@ -629,124 +629,134 @@
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_bIgnoreID32Blob(FALSE)
+ , m_bFileHeaderCarriesUITSData(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 )
{
UINT32 ulVal = 0;
// Meta-data flavor options
PropTools::CopyPropertyULONG32(ulVal, pProperties, "MetaDataFlavor");
- const UINT32 METADATA_FLAVOR_3GPP = 0x00000001; //from ihxmetaeditor.h
- m_bRequestedOutputMetaFlavor3GPP = (ulVal & METADATA_FLAVOR_3GPP) != 0;
+ const UINT32 METADATA_FLAVOR_3GPP = 0x00000010; //from ihxmetaeditor.h
+ m_bRequestedOutputMetaFlavor3GPP = (ulVal & METADATA_FLAVOR_3GPP) ? TRUE : FALSE;
- const UINT32 METADATA_FLAVOR_ITUNES = 0x00000010; //from ihxmetaeditor.h
- m_bRequestedOutputMetaFlavorITUNES = (ulVal & METADATA_FLAVOR_ITUNES) != 0;
+ const UINT32 METADATA_FLAVOR_ITUNES = 0x00000100; //from ihxmetaeditor.h
+ m_bRequestedOutputMetaFlavorITUNES = (ulVal & METADATA_FLAVOR_ITUNES) ? TRUE : FALSE;
+
+ // Meta-data ignore options
+ ulVal = 0;
+ PropTools::CopyPropertyULONG32(ulVal, pProperties, "MetaDataIgnore");
+
+ const UINT32 METADATAIGNORE_ID32BLOB = 0x00000001; //from ffdriver.h
+ m_bIgnoreID32Blob = (ulVal & METADATAIGNORE_ID32BLOB) ? TRUE : FALSE;
// UTF16 output option
+ ulVal = 0;
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;
}
@@ -796,60 +806,70 @@
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;
m_ulStreamDoneReceived = 0;
+ // check if the header carries UITS data
+ m_bFileHeaderCarriesUITSData = FALSE;
+
+ IHXBuffer* pUITSDataBuffer = 0;
+ if(SUCCEEDED(m_pFileHeader->GetPropertyBuffer(_3GPP_META_INFO_UITS_KEY, pUITSDataBuffer)) && pUITSDataBuffer)
+ {
+ m_bFileHeaderCarriesUITSData = TRUE;
+ }
+ HX_RELEASE(pUITSDataBuffer);
+
return retVal;
}
STDMETHODIMP CMP4StreamMixer::SetStreamHeader( THIS_ IHXValues* pStreamHeader )
{
HX_RESULT retVal = HXR_OK;
//save the stream header
UINT32 ulStreamNumber = m_ulStreamCount;
pStreamHeader->GetPropertyULONG32("StreamNumber",ulStreamNumber);
if (ulStreamNumber >= m_ulStreamCount)
{
return HXR_INVALID_PARAMETER;
}
// Save the stream group number
UINT32 ulStreamGroupNumber = HX_INVALID_STREAM_GROUP_NUMBER;
pStreamHeader->GetPropertyULONG32("StreamGroupNumber", ulStreamGroupNumber);
// If we have a "StreamGroupCount" in the file header, then we
// should have a stream group number in each stream header
if (m_ulStreamGroupCount && ulStreamGroupNumber >= m_ulStreamGroupCount)
{
return HXR_INVALID_PARAMETER;
}
// Save the stream group number
m_pStreamInfo[ulStreamNumber].m_ulStreamGroupNumber = ulStreamGroupNumber;
@@ -1604,64 +1624,65 @@
}
}
}
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_bRequestedOutputMetaFlavorITUNES || (m_eMetaFlavor == META_ITUNES))
{
// Build iTunes meta-data
BuildiTunesMetaData(pUdta);
}
- if (m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP))
+ if (m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP)
+ || m_bFileHeaderCarriesUITSData)
{
// Build 3GP meta-data
- Build3GPMetaData(pUdta, pMoov);
+ Build3GPPMetaData(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 );
}
}
}
@@ -1804,61 +1825,61 @@
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);
+ retVal = Build3GPPMetaDataID32(m_pStreamInfo[usStreamNum].m_pStreamHeader, &pMeta, FALSE);
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;
@@ -2005,64 +2026,66 @@
{
// 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 3GPP meta-data OR we
- // are generating hint tracks.
+ // we are either generating iTunes or 3GPP meta-data OR
+ // we need to write out UITS data OR
+ // we are generating hint tracks.
return (m_bRequestedOutputMetaFlavorITUNES || m_eMetaFlavor == META_ITUNES
|| m_bRequestedOutputMetaFlavor3GPP || m_eMetaFlavor == META_3GPP
+ || m_bFileHeaderCarriesUITSData
|| 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))
@@ -3651,132 +3674,112 @@
}
CMP4Atom_free* pFree = NULL;
CiTunesAtom_ilst* pIlst = NULL;
if( SUCCEEDED( retVal ) )
{
retVal = HXR_OUTOFMEMORY;
// hdlr
CiTunesAtom_hdlr* pHdlr = new CiTunesAtom_hdlr();
if( pHdlr )
{
retVal = HXR_OK;
pMeta->AddChild( pHdlr );
}
// ilst
if( SUCCEEDED( retVal ) )
{
retVal = HXR_OUTOFMEMORY;
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 ) )
{
// string properties
// Although not mentioned by iTMF spec, iTunes have 255 character limit on string properties.
const UINT32 ulStringLengthLimit = 255;
iTunesStringTransferPort stringTranferPort;
stringTranferPort.SetLengthLimit(ulStringLengthLimit);
stringTranferPort.SetUTF16Output(m_bUTF16Output);
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_TITLE_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9nam());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_COMPOSER_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9wrt());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_COPYRIGHT_KEY, stringTranferPort, pIlst, new CiTunesAtom_cprt());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_COMMENT_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9cmt());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_ARTIST_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9ART());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_GENRE_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9gen());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_ALBUM_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9alb());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_TRACK_SUBTITLE_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9st3());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_GENERATOR_TOOL_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9too());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_ENCODED_BY_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9enc());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_ALBUM_ARTIST_KEY, stringTranferPort, pIlst, new CiTunesAtom_aART());
// Grouping is represented by two iTunes atoms: older and newer version. Output both.
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_GROUPING_KEY, stringTranferPort, pIlst, new CiTunesAtom_grup());
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_GROUPING_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9grp());
// 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, _ITUNES_META_INFO_LYRICS_KEY, stringTranferPort, pIlst, new CiTunesAtom_A9lyr());
// predefined genre
if(SUCCEEDED(retVal))
{
// 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))
{
// need UTF8 to compare with ID3 names
EncodedString strGenresUTF8;
if(strGenres.ConvertToUTF8(strGenresUTF8))
{
// iTunes user defined genre can be a comma separated list
CHXPtrArray genreEntries;
if(ID3Tools::ParseGenreNameList(genreEntries, strGenresUTF8.GetData(), FALSE, ',', TRUE))
{
// iTunes stores genre ordinals with ID3 value +1
- for(UINT32 i = 0; i < genreEntries.GetSize(); i++)
+ for(int i = 0; i < genreEntries.GetSize(); i++)
{
UINT8 uGenreOrdinal = (UINT8)(ULONG32)genreEntries.GetAt(i) + 1;
genreEntries.SetAt(i, (void*)(ULONG32)uGenreOrdinal);
}
retVal = HXR_OUTOFMEMORY;
CiTunesAtom_gnre* pItem = new CiTunesAtom_gnre();
CiTunesAtom_data* pData = new CiTunesAtom_data();
if(pItem && pData)
{
retVal = pData->SetSpecial_PredefinedGenreEntries(genreEntries);
}
MetaiTunes_LinkAtoms(retVal, pIlst, pItem, pData);
}
}
}
}
// recording year (type conversion), always outputed as UTF8
iTunesRecordingYearTransferPort recYearTranferPort;
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_RELEASE_DATE_KEY, recYearTranferPort, pIlst, new CiTunesAtom_A9day());
// BPM should be 32 bits according to iTMF spec, but most implementations expect 16 bits
iTunesUInteger16TransferPort uint16TranferPort;
MetaiTunes_AddItemAtom(retVal, _ITUNES_META_INFO_BEATS_PER_MINUTE_KEY, uint16TranferPort, pIlst, new CiTunesAtom_tmpo());
// uint8 properties
@@ -3806,69 +3809,156 @@
}
MetaiTunes_LinkAtoms(retVal, pIlst, pItem, pData);
}
}
// disc number/count
if(SUCCEEDED(retVal))
{
UINT32 ulDiscNumber = 0;
HXBOOL bHaveDN = PropTools::CopyPropertyULONG32(ulDiscNumber, m_pFileHeader, _ITUNES_META_INFO_DISC_NUMBER_KEY);
UINT32 ulDiscCount = 0;
HXBOOL bHaveDC = PropTools::CopyPropertyULONG32(ulDiscCount, m_pFileHeader, _ITUNES_META_INFO_DISC_COUNT_KEY);
if(bHaveDN || bHaveDC)
{
retVal = HXR_OUTOFMEMORY;
CiTunesAtom_disk* pItem = new CiTunesAtom_disk();
CiTunesAtom_data* pData = new CiTunesAtom_data();
if(pItem && pData)
{
retVal = pData->SetSpecial_DiscNumberCount(ulDiscNumber, ulDiscCount);
}
MetaiTunes_LinkAtoms(retVal, pIlst, pItem, pData);
}
}
+
+ // pictures
+ if(SUCCEEDED(retVal))
+ {
+ // extract APIC frames from buffer properties
+ UINT32 uAPICDataCount = 0;
+ PropTools::CopyPropertyULONG32(uAPICDataCount, m_pFileHeader, _ITUNES_META_INFO_PICTURE_COUNT_KEY);
+
+ if(uAPICDataCount)
+ {
+ // keep count of successfully transfered pictures
+ UINT32 uPictureCount = 0;
+
+ // create covr atom
+ CiTunesAtom_covr* pItem = new CiTunesAtom_covr();
+ if(!pItem)
+ {
+ retVal = HXR_OUTOFMEMORY;
}
- // Resize our free atom (if present) given our new metadata
- if( SUCCEEDED( retVal ) && pFree )
+ // add data atoms to covr atom
+ for(UINT32 uAPICData = 0; SUCCEEDED(retVal) && (uAPICData < uAPICDataCount); uAPICData++)
+ {
+ retVal = HXR_OUTOFMEMORY;
+
+ // construct APIC frame
+ ID3Tools::APICFrame* pFrame = new ID3Tools::APICFrame;
+ if(pFrame)
+ {
+ char key[128];
+ sprintf(key, _ITUNES_META_INFO_PICTURE_KEY, int(uAPICData));
+
+ retVal = pFrame->DeserializeFromBufferProperty(m_pFileHeader, key);
+
+ // skip unsupported picture types
+ if(SUCCEEDED(retVal) && CiTunesAtom_data::IsSupportedPictureType(pFrame))
+ {
+ retVal = HXR_OUTOFMEMORY;
+
+ // transfer picture to data atom
+ CiTunesAtom_data* pData = new CiTunesAtom_data();
+ if(pData)
+ {
+ retVal = pData->SetPicture(pFrame);
+ }
+
+ // link data atom to item atom
+ if(SUCCEEDED(retVal) && pData)
+ {
+ uPictureCount++;
+ pItem->AddChild(pData);
+ }
+ else
+ {
+ delete pData;
+ }
+ }
+ }
+
+ // cleanup frame
+ delete pFrame;
+ }
+
+ // link item atom to ilst atom
+ if(SUCCEEDED(retVal) && uPictureCount)
+ {
+ pIlst->AddChild(pItem);
+ }
+ else
+ {
+ delete pItem;
+ }
+ }
+ }
+ }
+
+ // free. only create this if we are putting moov in the middle
+ if( SUCCEEDED( retVal ) )
{
UINT32 size = pUdta->GetCurrentSize( TRUE );
- size -= MP4_DEFAULT_METADATA_RESERVE_SIZE;
+ if( !m_bMoovAtEnd && !m_bForceMoovFirst && (MP4_DEFAULT_METADATA_RESERVE_SIZE > size))
+ {
+ retVal = HXR_OUTOFMEMORY;
+
+ pFree = new CMP4Atom_free();
+
+ if( pFree )
+ {
+ retVal = HXR_OK;
+
+ // reserve space for metadata
pFree->SetFreeSize( MP4_DEFAULT_METADATA_RESERVE_SIZE - size );
+ pMeta->AddChild( pFree );
+ }
+ }
}
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;
@@ -4023,61 +4113,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, CMP4Atom* pMoov )
+HX_RESULT CMP4StreamMixer::Build3GPPMetaDataStandardSet( 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;
@@ -4298,124 +4388,227 @@
{
pAlbm->SetTrackNumber(TRUE, UINT8(uTrackNum));
}
Meta3GP_SetLanguageEncoding(pAlbm);
pUdta->AddChild(pAlbm);
}
else
{
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
{
HX_DELETE(pYrrc);
}
}
+ return retVal;
+}
+
+HX_RESULT CMP4StreamMixer::Build3GPPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov )
+{
+ HX_RESULT retVal = HXR_OK;
+
+ // standard 3GPP meta-data set
+ if(m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP))
+ {
+ retVal = Build3GPPMetaDataStandardSet(pUdta, pMoov);
+ }
+
// ID32, setup box hierarchy: file/moov/meta/[hdlr, ID32]
- CMP4Atom_meta* pMeta = NULL;
if(SUCCEEDED(retVal))
{
- retVal = Build3GPMetaDataID32(m_pFileHeader, &pMeta);
+ CMP4Atom_meta* pMeta = NULL;
+ retVal = Build3GPPMetaDataID32(m_pFileHeader, &pMeta, TRUE);
+
if(SUCCEEDED(retVal) && pMeta)
{
retVal = pMoov->AddChild(pMeta);
}
}
return retVal;
}
-HX_RESULT CMP4StreamMixer::Build3GPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta )
-{
- if(!ppMeta)
+HX_RESULT CMP4StreamMixer::Build3GPPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta, HXBOOL bFileHeader )
{
- return HXR_POINTER;
- }
- if(!pHeader)
+ if(!ppMeta || !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)))
+ // If there's a complete ID32 blob present, use it as ID32 atom contents
+ if(!m_bIgnoreID32Blob)
+ {
+ IHXBuffer* pID32BlobBuffer = NULL;
+ if(SUCCEEDED(pHeader->GetPropertyBuffer(_3GPP_META_INFO_ID32_BLOB_KEY, pID32BlobBuffer)) && pID32BlobBuffer)
+ {
+ retVal = Build3GPPMetaDataID32(pHeader, ppMeta, pID32BlobBuffer->GetBuffer(), pID32BlobBuffer->GetSize());
+ }
+
+ if(pID32BlobBuffer)
+ {
+ HX_RELEASE(pID32BlobBuffer);
+ return retVal;
+ }
+ }
+
+ // Construct ID3v2 tag from header properties
+ ID3Tools::ID3v2Tag tag;
+
+ // Extract APIC frames from buffer properties.
+ if(m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP))
+ {
+ UINT32 uAPICDataCount = 0;
+ PropTools::CopyPropertyULONG32(uAPICDataCount, pHeader, _3GPP_META_INFO_PICTURE_COUNT_KEY);
+
+ if(uAPICDataCount)
+ {
+ for(UINT32 uAPICData = 0; SUCCEEDED(retVal) && (uAPICData < uAPICDataCount); uAPICData++)
+ {
+ retVal = HXR_OUTOFMEMORY;
+ ID3Tools::APICFrame* pFrame = new ID3Tools::APICFrame;
+ if(pFrame)
+ {
+ char key[128];
+ sprintf(key, _3GPP_META_INFO_PICTURE_KEY, int(uAPICData));
+
+ retVal = pFrame->DeserializeFromBufferProperty(pHeader, key);
+
+ if(SUCCEEDED(retVal))
+ {
+ retVal = tag.AddFrame(pFrame);
+ }
+ }
+ }
+ }
+ }
+
+ // Extract UITS data from buffer property. Write UITS to file header only.
+ if(bFileHeader && m_bFileHeaderCarriesUITSData)
+ {
+ EncodedString sUITSData;
+ if(PropTools::CopyPropertyBuffer(sUITSData, m_pFileHeader, _3GPP_META_INFO_UITS_KEY))
+ {
+ retVal = HXR_OUTOFMEMORY;
+ ID3Tools::PRIVFrame* pFrame = new ID3Tools::PRIVFrame;
+ if(pFrame)
+ {
+ pFrame->SetOwnerIdentifier(_META_INFO_UITS_OWNER_IDENTIFIER);
+ retVal = pFrame->SetPrivateData((const UINT8*)sUITSData.GetData(), sUITSData.GetByteLength(FALSE));
+
+ if(SUCCEEDED(retVal))
+ {
+ retVal = tag.AddFrame(pFrame);
+ }
+ }
+ }
+ }
+
+ // write out the tag into the ID32 box
+ if(SUCCEEDED(retVal) && tag.GetNumFrames())
{
retVal = HXR_OUTOFMEMORY;
+ // construct ID32 payload buffer
+ UINT32 ulID32BlobSize = tag.CalcSerializationBufferSize();
+ UINT8* pID32Blob = new UINT8[ulID32BlobSize];
+ if(pID32Blob)
+ {
+ retVal = tag.SerializeToBuffer(pID32Blob, ulID32BlobSize);
+ }
+
+ if(SUCCEEDED(retVal))
+ {
+ retVal = Build3GPPMetaDataID32(pHeader, ppMeta, pID32Blob, ulID32BlobSize);
+ }
+
+ // cleanup
+ HX_VECTOR_DELETE(pID32Blob);
+ }
+
+ return retVal;
+}
+
+HX_RESULT CMP4StreamMixer::Build3GPPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta, const UINT8* pID32Blob, UINT32 ulID32BlobSize )
+{
+ if(!ppMeta || !pHeader || !pID32Blob || !ulID32BlobSize)
+ {
+ return HXR_INVALID_PARAMETER;
+ }
+
+ *ppMeta = NULL;
+ HX_RESULT retVal = HXR_OK;
+
// 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());
+ retVal = pID32->SetBlob((UCHAR*)pID32Blob, ulID32BlobSize);
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);
Index: mp4sm.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.h,v
retrieving revision 1.13
diff -d -H -w -U30 -r1.13 mp4sm.h
--- mp4sm.h 23 Oct 2009 09:47:54 -0000 1.13
+++ mp4sm.h 6 Nov 2009 21:45:39 -0000
@@ -187,62 +187,64 @@
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 BuildiTunesMetaData( CMP4Atom* pUdta );
HX_RESULT BuildPSPMetaData( CMP4Atom* pUsmt );
- HX_RESULT Build3GPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov );
- HX_RESULT Build3GPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta );
+ HX_RESULT Build3GPPMetaDataStandardSet( CMP4Atom* pUdta, CMP4Atom* pMoov );
+ HX_RESULT Build3GPPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov );
+ HX_RESULT Build3GPPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta, HXBOOL bFileHeader );
+ HX_RESULT Build3GPPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta, const UINT8* pID32Blob, UINT32 ulID32BlobSize);
// 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);
@@ -306,58 +308,59 @@
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_3GPP,
META_PSP
};
MetaFlavor m_eMetaFlavor;
HXBOOL m_bRequestedOutputMetaFlavor3GPP;
HXBOOL m_bRequestedOutputMetaFlavorITUNES;
-
+ HXBOOL m_bIgnoreID32Blob;
+ HXBOOL m_bFileHeaderCarriesUITSData;
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, 107.6 KB) - not displayed
datatype_tools_dtdriver_engine.diff
(text/x-patch, 14.4 KB)
Index: ffdriver.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/engine/ffdriver.cpp,v
retrieving revision 1.61
diff -d -H -w -U30 -r1.61 ffdriver.cpp
--- ffdriver.cpp 23 Oct 2009 09:46:03 -0000 1.61
+++ ffdriver.cpp 6 Nov 2009 21:22:14 -0000
@@ -255,60 +255,61 @@
, 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_ulMetaDataIgnore(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
@@ -655,60 +656,64 @@
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;
}
+ else if (strcmp(pOptName, METADATAIGNORE_OPTION_NAME) == 0)
+ {
+ m_ulMetaDataIgnore = 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;
@@ -2034,67 +2039,76 @@
}
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",
+ retVal = pNewProps->SetPropertyULONG32(METADATAFLAVOR_OPTION_NAME,
m_ulMetaDataFlavor);
}
}
if (SUCCEEDED(retVal))
{
+ if (m_ulMetaDataIgnore != 0)
+ {
+ retVal = pNewProps->SetPropertyULONG32(METADATAIGNORE_OPTION_NAME,
+ m_ulMetaDataIgnore);
+ }
+ }
+
+ 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)))
{
Index: pub/ffdriver.h
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/engine/pub/ffdriver.h,v
retrieving revision 1.45
diff -d -H -w -U30 -r1.45 ffdriver.h
--- pub/ffdriver.h 23 Oct 2009 09:46:04 -0000 1.45
+++ pub/ffdriver.h 6 Nov 2009 21:22:14 -0000
@@ -51,60 +51,61 @@
#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 METADATAIGNORE_OPTION_NAME "MetaDataIgnore"
#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"
@@ -130,60 +131,63 @@
#define PROCESSHEADERS_OPTION_NAME "ProcessHeadersOnly"
#define SETSRCPROP_OPTION_NAME "SetSrcProperties"
#define OPTIMIZEDTRANSCODE_OPTION_NAME "OptimizedTranscode"
#define FILERECOGNITION_OPTION_NAME "UseFileRecognition"
#define COLORCONVERT_OPTION_NAME "ColorConvert"
#define MAXNUMIMAGEOUTPUTFILES_OPTION_NAME "MaximumNumImageOutputFiles"
#define DECODED_VIDEO_RESIZE_WIDTH_OPTION_NAME "DecodedVideoResizeWidth"
#define DECODED_VIDEO_RESIZE_HEIGHT_OPTION_NAME "DecodedVideoResizeHeight"
#define DECODED_VIDEO_RESIZE_PRESERVE_ASPECT_OPTION_NAME "DecodedVideoResizePreserveAspect"
#define COMPATIBILITY_OPTION_NAME "Compatibility"
// Merge sorter related options
#define MERGESORTFF_OPTION_NAME "MergeSortFileFormat"
#define MERGESORTDEC_OPTION_NAME "MergeSortDecode"
#define MERGESORTENC_OPTION_NAME "MergeSortEncode"
#define MERGESORTFFDEPTH_OPTION_NAME "MergeSortMaxQueueDepthPostFileFormat"
#define MERGESORTFFTIME_OPTION_NAME "MergeSortMaxQueueTimespanFileFormat"
#define MERGESORTFFBYTES_OPTION_NAME "MergeSortMaxQueueBytesFileFormat"
#define MERGESORTDECDEPTH_OPTION_NAME "MergeSortMaxQueueDepthDecode"
#define MERGESORTDECTIME_OPTION_NAME "MergeSortMaxQueueTimespanDecode"
#define MERGESORTDECBYTES_OPTION_NAME "MergeSortMaxQueueBytesDecode"
#define MERGESORTENCDEPTH_OPTION_NAME "MergeSortMaxQueueDepthEncode"
#define MERGESORTENCTIME_OPTION_NAME "MergeSortMaxQueueTimespanEncode"
#define MERGESORTENCBYTES_OPTION_NAME "MergeSortMaxQueueBytesEncode"
#define RATE_MODE_CONSTANT 0
#define RATE_MODE_UPDOWN 1
#define RATE_MODE_UP 2
#define RATE_MODE_DOWN 3
+// MetaDataIgnore values
+#define METADATAIGNORE_ID32BLOB 0x00000001
+
/****************************************************************************
* Includes
*/
#include "hlxclib/stdio.h"
#include "hlxclib/stdarg.h"
#include "minicntx.h"
#include "hxmemprb.h"
#include "hxsrcin.h"
#include "hxformt.h"
#include "hxfiles.h"
#include "hxfwrtr.h"
#include "hxengin.h"
#include "hxslist.h"
#ifdef HELIX_FEATURE_DTDR_USE_RECOGNIZER
#include "recognizer.h"
#endif
/****************************************************************************
*
* Class:
*
@@ -624,60 +628,61 @@
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;
+ ULONG32 m_ulMetaDataIgnore;
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, 2.4 KB)
Index: editor.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/metaeditor/editor.cpp,v
retrieving revision 1.1
diff -d -H -w -U30 -r1.1 editor.cpp
--- editor.cpp 5 Nov 2007 22:29:46 -0000 1.1
+++ editor.cpp 6 Nov 2009 21:18:57 -0000
@@ -229,72 +229,80 @@
{
if(m_bDrivingFile)
{
return HXR_UNEXPECTED;
}
HX_RELEASE(m_pContext);
HX_RESULT retVal = Stop();
if(FAILED(retVal))
{
return retVal;
}
if(!pContext)
{
return HXR_INVALID_PARAMETER;
}
m_pContext = pContext;
HX_ADDREF(m_pContext);
return HXR_OK;
}
STDMETHODIMP
CEditor::Drive(const char* pszInputFilename, const char* pszOutputFilename,
IHXMetaDataProcessor* pProcessor, IHXValues* pOptions,
IHXMetaDataEditorResponse* pResponse)
{
if(!m_pContext)
{
return HXR_FAILED;
}
+
// cannot start while previous file operation is in progress
if(m_bDrivingFile)
{
return HXR_UNEXPECTED;
}
// check arguments
- if(!pProcessor || !pOptions || !pszInputFilename)
+ if(!pProcessor || !pOptions ||
+ !pszInputFilename || (pszInputFilename && !strlen(pszInputFilename)))
{
return HXR_INVALID_PARAMETER;
}
+ // adjust arguments for ffdriver
+ if(pszOutputFilename && !strlen(pszOutputFilename))
+ {
+ pszOutputFilename = 0;
+ }
+
// check for input file existence
if(!CHXFileSpecUtils::FileExists(CHXFileSpecifier(pszInputFilename)))
{
return HXR_FAILED;
}
BOOL bWritingFile = (pszOutputFilename != 0);
if(bWritingFile)
{
// writing to input file is not allowed
if(!strcmp(pszInputFilename, pszOutputFilename))
{
return HXR_INVALID_PARAMETER;
}
ULONG32 ulOverwriteFile = 0;
pOptions->GetPropertyULONG32(BLASTFILE_OPTION_NAME, ulOverwriteFile);
// check for output file existence
if(CHXFileSpecUtils::FileExists(CHXFileSpecifier(pszOutputFilename)) && !ulOverwriteFile)
{
return HXR_FAILED;
}
}
HX_RESULT retVal = HXR_OK;
// make a private copy of options
IHXValues* pPrivateOptions = 0;
if(SUCCEEDED(retVal))
{