[Helix-client-dev] CN: Added ability to output ID3v2 v2.3.0; added DTDriver engine parameter for controlling the ID3v2 output in MP4 writer
Petar Basic <[email protected]> Wed, 6 Jan 2010 18:49:44 +0100
| Newsgroups | gmane.comp.multimedia.helix.devel |
|---|---|
| Message-ID | <[email protected]> |
Modified by: pbasic at real.com Reviewed by: ehyche at real.com Date: 2010/01/06 Project: GMP MetaEditor (meta3gp.exe) Synopsis: Added ability to output ID3v2 v2.3.0; added DTDriver engine parameter for controlling the ID3v2 output in MP4 writer Overview: To allow testing of meta-data outputted by MP4 file-writer with other software and with MP4 file-format it is useful to be able to output an older version of ID3v2 tag. Details: 1.) Extended ID3Tools methods to allow writing of ID3v2 according to v2.3.0 specs. 2.) Added DTDriver engine parameter which controls the behaviour of MP4 file-writer during ID3v2 tag output. 3.) Added ID3v2 related command-line options to GMPMetaEditor. These are mapped to DTDriver engine parameters. Testing: Verified that the portion of meta-info injected as ID3v2 by GMP MetaEditor can be read with other software (iTunes 9, CT metadata extractor 1.3) regardless of the version of ID3v2 outputted (v2.4.0 or v2.3.0). Verified that meta-info injected by other software can be read with GMP MetaEditor. Files Modified: datatype/common/util/metautil.cpp datatype/common/util/pub/metautil.h datatype/mp4/filewriter/mp4sm.cpp datatype/mp4/filewriter/mp4sm.h datatype/tools/dtdriver/engine/ffdriver.cpp datatype/tools/dtdriver/engine/pub/ffdriver.h datatype/tools/dtdriver/apps/meta3gp/main.cpp 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
datatype_common_util.diff
(text/x-patch, 38.6 KB)
Index: metautil.cpp
===================================================================
RCS file: /cvsroot/datatype/common/util/metautil.cpp,v
retrieving revision 1.12
diff -d -H -w -U30 -r1.12 metautil.cpp
--- metautil.cpp 12 Nov 2009 22:22:42 -0000 1.12
+++ metautil.cpp 6 Jan 2010 17:31:22 -0000
@@ -459,60 +459,69 @@
// network byte order
pBuffer[0] = UINT8((val & 0x0FE00000) >> 21);
pBuffer[1] = UINT8((val & 0x001FC000) >> 14);
pBuffer[2] = UINT8((val & 0x00003F80) >> 7);
pBuffer[3] = UINT8(val & 0x0000007F);
return TRUE;
}
HXBOOL ID3Tools::DecodeSynchSafeIntegerFromBuffer(const UINT8* pBuffer, UINT32& out)
{
// leading bits in each byte must be zeroed out in SynchSafe integer
for(int i = 0; i < 4; i++)
{
if(pBuffer[i] & 0x80)
{
return FALSE;
}
}
// network byte order
out = ((UINT32(pBuffer[0]) & 0x0000007F) << 21) |
((UINT32(pBuffer[1]) & 0x0000007F) << 14) |
((UINT32(pBuffer[2]) & 0x0000007F) << 7) |
(UINT32(pBuffer[3]) & 0x0000007F);
return TRUE;
}
+void ID3Tools::WriteIntegerToBuffer(UINT8* pBuffer, UINT32 val)
+{
+ // network byte order
+ pBuffer[0] = UINT8((val >> 24) & 0x000000FF);
+ pBuffer[1] = UINT8((val >> 16) & 0x000000FF);
+ pBuffer[2] = UINT8((val >> 8) & 0x000000FF);
+ pBuffer[3] = UINT8(val & 0x000000FF);
+}
+
void ID3Tools::ReadIntegerFromBuffer(const UINT8* pBuffer, UINT32& out)
{
// network byte order
out = (UINT32(pBuffer[0]) << 24) |
(UINT32(pBuffer[1]) << 16) |
(UINT32(pBuffer[2]) << 8) |
(UINT32(pBuffer[3]));
}
HX_TEXT_ENCODING_TYPE ID3Tools::ID3v2Frame::HelixTextEncodingFromID3TextEncoding(eTextEncoding enc)
{
HX_TEXT_ENCODING_TYPE textEnc = HX_TEXT_ENCODING_TYPE_UNKNOWN;
switch(enc)
{
case TextEncoding_ISO88591:
textEnc = HX_TEXT_ENCODING_TYPE_ISO8859_1;
break;
case TextEncoding_UTF8:
textEnc = HX_TEXT_ENCODING_TYPE_UTF8;
break;
case TextEncoding_UTF16BE:
textEnc = HX_TEXT_ENCODING_TYPE_UTF16BE;
break;
case TextEncoding_UTF16BOM:
textEnc = HX_TEXT_ENCODING_TYPE_UTF16;
break;
}
@@ -617,126 +626,145 @@
HX_RESULT ID3Tools::ID3v2Frame::ReadISO88591StringFromBufferAndInc(CHXString& dst, const UINT8*& pBuffer, UINT32& ulRemainingBufferSize)
{
if(pBuffer && (ulRemainingBufferSize >= 1))
{
UINT32 len = strlen((const char*)pBuffer);
if(len < ulRemainingBufferSize)
{
UINT32 lenWithTerm = len + 1;
dst = (const char*)pBuffer;
pBuffer += lenWithTerm;
ulRemainingBufferSize -= lenWithTerm;
return HXR_OK;
}
}
return HXR_FAILED;
}
HX_RESULT ID3Tools::ID3v2Frame::WriteISO88591StringToBufferAndInc(UINT8*& pBuffer, const char* pSrc)
{
if(pBuffer && pSrc)
{
strcpy((char*)pBuffer, pSrc);
pBuffer += strlen(pSrc) + 1;
return HXR_OK;
}
return HXR_FAILED;
}
HX_RESULT ID3Tools::ID3v2Frame::WriteFrameHeaderAndInc(UINT8*& pBuffer, const char frameID[4],
- UINT32 ulFramePayloadSize, UINT8 ulFrameFlags[2])
+ UINT32 ulFramePayloadSize, UINT8 ulFrameFlags[2],
+ UINT8 uTagVersionMinor)
+{
+ if((uTagVersionMinor != 3) && (uTagVersionMinor != 4))
{
+ // unsupported tag version
+ return HXR_FAILED;
+ }
+
// ID3 Frame header: ID, 4 bytes
WriteBytesToBufferAndInc(pBuffer, (const UINT8*)frameID, 4);
- // ID3 Frame header: payload size, 4 bytes sychsafe integer
+ // ID3 Frame header: payload size
+ if(uTagVersionMinor == 3)
+ {
+ // 4 bytes big endian order
+ WriteIntegerToBuffer(pBuffer, ulFramePayloadSize);
+ }
+ else if(uTagVersionMinor == 4)
+ {
+ // 4 bytes SynchSafe integer
if(!EncodeAsSynchSafeIntegerToBuffer(pBuffer, ulFramePayloadSize))
{
return HXR_FAILED;
}
+ }
+
pBuffer += 4;
// ID3 Frame header: flags, 2 bytes
WriteBytesToBufferAndInc(pBuffer, ulFrameFlags, 2);
return HXR_OK;
}
HXBOOL ID3Tools::ID3v2Frame::IsValidFrameID(const UINT8 frameID[4])
{
for(UINT32 i = 0; i < 4; i++)
{
char ch = (char)frameID[i];
if((ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9'))
{
return FALSE;
}
}
return TRUE;
}
HX_RESULT ID3Tools::ID3v2Frame::ReadFrameHeader(ID3v2FrameHeader& out, UINT8 uTagVersionMinor,
const UINT8*& pBuffer, UINT32& uRemainingBufferSize)
{
if(!pBuffer)
{
return HXR_INVALID_PARAMETER;
}
// frame header v2.3 and v2.4 have the same format except for size field
if((uTagVersionMinor != 3) && (uTagVersionMinor != 4))
{
return HXR_INVALID_VERSION;
}
// need 10 bytes at least
if(uRemainingBufferSize < FrameHeaderSize)
{
return HXR_FAILED;
}
// ID3 Frame header: ID, 4 bytes
memcpy(out.FrameID, pBuffer, 4);
if(!IsValidFrameID(out.FrameID))
{
return HXR_FAILED;
}
- // ID3 Frame header: frame size, 4 bytes sychsafe integer
+ // ID3 Frame header: frame size
if(uTagVersionMinor == 3)
{
+ // 4 bytes big endian order
ReadIntegerFromBuffer(pBuffer + 4, out.FrameSize);
}
else if(uTagVersionMinor == 4)
{
+ // 4 bytes SynchSafe integer
if(!DecodeSynchSafeIntegerFromBuffer(pBuffer + 4, out.FrameSize))
{
return HXR_FAILED;
}
}
// Calc total frame size
out.TotalFrameSize = out.FrameSize + FrameHeaderSize;
// ID3 Frame header: flags, 2 bytes
memcpy(out.Flags, pBuffer + 8, 2);
// check size
if(uRemainingBufferSize < out.TotalFrameSize)
{
return HXR_FAILED;
}
// Calc payload offset and retrieve extra fields
out.PayloadOffset = FrameHeaderSize;
// order of extra fields is defined by flag values
UINT8 uFrameFormatFlags = out.Flags[1];
if(uTagVersionMinor == 3)
{
if(uFrameFormatFlags & FFF23_UnknownBits)
{
return HXR_FAILED;
}
@@ -857,61 +885,61 @@
}
// skip header
if(SUCCEEDED(res))
{
pBuffer += out.PayloadOffset;
uRemainingBufferSize -= out.PayloadOffset;
}
return res;
}
HX_RESULT ID3Tools::ID3v2Frame::SerializeToBufferProperty(IUnknown* pContext, IHXValues* pDst, const char* pszPropertyName) const
{
if(!pDst || !pszPropertyName)
{
return HXR_INVALID_PARAMETER;
}
HX_RESULT res = HXR_FAILED;
UINT32 bufferSize = CalcSerializationBufferSize();
if(bufferSize)
{
res = HXR_OUTOFMEMORY;
UINT8* pBuffer = new UINT8[bufferSize];
if(pBuffer)
{
// class specific serialization
- res = SerializeToBuffer(pBuffer, bufferSize);
+ res = SerializeToBuffer(pBuffer, bufferSize, BufferPropertyTagVersionMinor);
if(SUCCEEDED(res))
{
// copy bytes
res = PropTools::CopyPropertyBuffer(pContext, pDst, pBuffer, bufferSize, pszPropertyName, TRUE);
}
}
HX_VECTOR_DELETE(pBuffer);
}
return res;
}
HX_RESULT ID3Tools::ID3v2Frame::DeserializeFromBufferProperty(IHXValues* pSrc, const char* pszPropertyName)
{
if(!pSrc || !pszPropertyName)
{
return HXR_INVALID_PARAMETER;
}
HX_RESULT result = HXR_FAILED;
// obtain required buffer size
UINT32 ulBufferSize = PropTools::CopyPropertyBuffer(0, 0, pSrc, pszPropertyName);
if(ulBufferSize)
{
result = HXR_OUTOFMEMORY;
UINT8* pBuffer = new UINT8[ulBufferSize];
if(pBuffer)
{
// copy bytes
@@ -966,78 +994,78 @@
memcpy(pFrame->m_pPrivateData, m_pPrivateData, m_ulPrivateDataSize);
}
}
if(FAILED(res))
{
HX_DELETE(pFrame);
}
}
return pFrame;
}
UINT32 ID3Tools::PRIVFrame::CalcSerializationBufferSize() const
{
return FrameHeaderSize + CalcPayloadSize();
}
UINT32 ID3Tools::PRIVFrame::CalcPayloadSize() const
{
// PRIV frame structure:
// ID3 frame header: 10 bytes, not counted here
// Owner identifier: <text string> $00
// Private data: <binary data>
UINT32 size = m_strOwnerIdentifier.GetLength() + 1; //Owner identifier with terminator
size += m_ulPrivateDataSize; //Private Data
return size;
}
-HX_RESULT ID3Tools::PRIVFrame::SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const
+HX_RESULT ID3Tools::PRIVFrame::SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) const
{
UINT32 ulRequiredBufferSize = CalcSerializationBufferSize();
if(!pBuffer || (ulBufferSize < ulRequiredBufferSize))
{
return HXR_INVALID_PARAMETER;
}
// must have binary private data
if(!m_ulPrivateDataSize || !m_pPrivateData || m_strOwnerIdentifier.IsEmpty())
{
return HXR_FAILED;
}
// ID3v2 Frame header
UINT8 ulFrameFlags[2] = { 0, 0 };
- HX_RESULT res = WriteFrameHeaderAndInc(pBuffer, "PRIV", CalcPayloadSize(), ulFrameFlags);
+ HX_RESULT res = WriteFrameHeaderAndInc(pBuffer, "PRIV", CalcPayloadSize(), ulFrameFlags, uTagVersionMinor);
if(FAILED(res))
{
return res;
}
// PRIV: Owner identifier: <text string> $00
WriteISO88591StringToBufferAndInc(pBuffer, (const char*)m_strOwnerIdentifier);
// PRIV: Private data: <binary data>
WriteBytesToBufferAndInc(pBuffer, m_pPrivateData, m_ulPrivateDataSize);
// done
return HXR_OK;
}
HX_RESULT ID3Tools::PRIVFrame::DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor)
{
// PRIV v2.3 and v2.4 have the same layout except for the header
if(!pBuffer || !ulBufferSize)
{
return HXR_INVALID_PARAMETER;
}
// reset
Clear();
UINT32 ulRemainingSize = ulBufferSize;
// process frame header
ID3v2FrameHeader header;
HX_RESULT result = ReadFrameHeaderAndInc(header, uTagVersionMinor, pBuffer, ulRemainingSize, "PRIV");
@@ -1239,78 +1267,78 @@
{
Clear();
}
return result;
}
UINT32 ID3Tools::APICFrame::CalcPayloadSize() const
{
// APIC frame structure:
// ID3 frame header: 10 bytes, not counted here
// Text encoding: $xx
// MIME type: <text string> $00
// Picture type: $xx
// Description: <text string according to encoding> $00 (00)
// Picture data: <binary data>
UINT32 size = 1 + 1; //Text encoding + Picture type
size += m_strMimeType.GetLength() + 1; //MIME type with terminator
size += m_strDescription.GetByteLength(TRUE); //Description with terminator
size += m_ulPictureDataSize; //Picture Data
return size;
}
UINT32 ID3Tools::APICFrame::CalcSerializationBufferSize() const
{
return FrameHeaderSize + CalcPayloadSize();
}
-HX_RESULT ID3Tools::APICFrame::SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const
+HX_RESULT ID3Tools::APICFrame::SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) const
{
UINT32 ulRequiredBufferSize = CalcSerializationBufferSize();
if(!pBuffer || (ulBufferSize < ulRequiredBufferSize))
{
return HXR_INVALID_PARAMETER;
}
// must have binary picture data
if(!m_ulPictureDataSize || !m_pPictureData || m_strMimeType.IsEmpty())
{
return HXR_FAILED;
}
// ID3v2 Frame header
UINT8 ulFrameFlags[2] = { 0, 0 };
- HX_RESULT res = WriteFrameHeaderAndInc(pBuffer, "APIC", CalcPayloadSize(), ulFrameFlags);
+ HX_RESULT res = WriteFrameHeaderAndInc(pBuffer, "APIC", CalcPayloadSize(), ulFrameFlags, uTagVersionMinor);
if(FAILED(res))
{
return res;
}
// APIC: Text encoding: $xx
WriteByteToBufferAndInc(pBuffer, (UINT8)m_textEncoding);
// APIC: MIME type: <text string> $00
WriteISO88591StringToBufferAndInc(pBuffer, (const char*)m_strMimeType);
// APIC: Picture type: $xx
WriteByteToBufferAndInc(pBuffer, m_ulPictureType);
// APIC: Description: <text string according to encoding> $00 (00)
WriteEncodedStringToBufferAndInc(pBuffer, m_strDescription);
// APIC: Picture data: <binary data>
WriteBytesToBufferAndInc(pBuffer, m_pPictureData, m_ulPictureDataSize);
// done
return HXR_OK;
}
HX_RESULT ID3Tools::APICFrame::SavePictureDataToImageFile(const char* pszFileName)
{
if(!pszFileName || !pszFileName[0])
{
return HXR_INVALID_PARAMETER;
}
@@ -1433,178 +1461,185 @@
{
return HXR_INVALID_PARAMETER;
}
FreePictureDataBuffer();
HX_RESULT res = AllocatePictureDataBuffer(ulBufferSize);
if(SUCCEEDED(res))
{
memcpy(m_pPictureData, pBuffer, ulBufferSize);
}
return res;
}
ID3Tools::ID3v2Tag::ID3v2Tag()
{
}
ID3Tools::ID3v2Tag::~ID3v2Tag()
{
DeleteFrames(m_framesAPIC);
DeleteFrames(m_framesPRIV);
}
void ID3Tools::ID3v2Tag::Clear()
{
DeleteFrames(m_framesAPIC);
DeleteFrames(m_framesPRIV);
}
-HX_RESULT ID3Tools::ID3v2Tag::WriteTagHeaderAndInc(UINT8*& pBuffer, UINT8 ulTagFlags, UINT32 ulTagPayloadSize)
+HX_RESULT ID3Tools::ID3v2Tag::WriteTagHeaderAndInc(UINT8*& pBuffer, UINT8 ulTagFlags, UINT32 ulTagPayloadSize,
+ UINT8 uTagVersionMinor)
{
+ if((uTagVersionMinor != 3) && (uTagVersionMinor != 4))
+ {
+ // unsupported version
+ return HXR_FAILED;
+ }
+
// ID3 tag header: tag identifier, 3 bytes
WriteBytesToBufferAndInc(pBuffer, (const UINT8*)"ID3", 3);
// ID3 tag header: version, 2 bytes
- UINT8 ulVersion[2] = { 4, 0 }; //v2.4.0
+ UINT8 ulVersion[2] = { uTagVersionMinor, 0 }; //v2.4.0 or v2.3.0
WriteBytesToBufferAndInc(pBuffer, ulVersion, 2);
// ID3 tag header: flags, 2 bytes
WriteByteToBufferAndInc(pBuffer, ulTagFlags);
- // ID3 tag header: payload size, 4 bytes sychsafe integer
+ // ID3 tag header: payload size, 4 bytes SynchSafe integer
if(!EncodeAsSynchSafeIntegerToBuffer(pBuffer, ulTagPayloadSize))
{
return HXR_FAILED;
}
pBuffer += 4;
return HXR_OK;
}
UINT32 ID3Tools::ID3v2Tag::CalcPayloadSize() const
{
// no extended header, no padding, no footer
UINT32 size = 0;
// collect frame sizes
size += CalcSerializationBufferSize(m_framesAPIC);
size += CalcSerializationBufferSize(m_framesPRIV);
return size;
}
UINT32 ID3Tools::ID3v2Tag::CalcSerializationBufferSize() const
{
return TagHeaderSize + CalcPayloadSize();
}
-HX_RESULT ID3Tools::ID3v2Tag::SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const
+HX_RESULT ID3Tools::ID3v2Tag::SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) const
{
UINT32 ulRequiredBufferSize = CalcSerializationBufferSize();
if(!pBuffer || (ulBufferSize < ulRequiredBufferSize))
{
return HXR_INVALID_PARAMETER;
}
// must have at least one frame and no duplicates
if(!GetNumFrames() || ContainsAPICFrameDuplicates() || ContainsPRIVFrameDuplicates())
{
return HXR_FAILED;
}
// tag header
UINT8 ulTagFlags = 0; //unsychnronization not applied, no extended header, not experimental, no footer
- WriteTagHeaderAndInc(pBuffer, ulTagFlags, CalcPayloadSize());
+ WriteTagHeaderAndInc(pBuffer, ulTagFlags, CalcPayloadSize(), uTagVersionMinor);
ulBufferSize -= TagHeaderSize;
// serialize all frames
HX_RESULT result = HXR_OK;
if(SUCCEEDED(result))
{
- result = SerializeToBufferAndInc(pBuffer, ulBufferSize, m_framesAPIC);
+ result = SerializeToBufferAndInc(pBuffer, ulBufferSize, m_framesAPIC, uTagVersionMinor);
}
if(SUCCEEDED(result))
{
- result = SerializeToBufferAndInc(pBuffer, ulBufferSize, m_framesPRIV);
+ result = SerializeToBufferAndInc(pBuffer, ulBufferSize, m_framesPRIV, uTagVersionMinor);
}
return result;
}
HX_RESULT ID3Tools::ID3v2Tag::DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize)
{
if(!pBuffer || !ulBufferSize)
{
return HXR_INVALID_PARAMETER;
}
// reset
Clear();
// Read tag header. Need 10 bytes at least.
if(ulBufferSize < TagHeaderSize)
{
return HXR_FAILED;
}
// ID3 standard headers v2.3 and v2.4 have the same layout except for "Footer present" flag.
if(memcmp(pBuffer, (void*)"ID3", 3))
{
return HXR_FAILED;
}
UINT8 ulTagVersionMinor = pBuffer[3];
// ignore tags with unsupported versions
if((ulTagVersionMinor != 3) && (ulTagVersionMinor != 4))
{
return HXR_INVALID_VERSION;
}
UINT8 ulTagVersionRev = pBuffer[4];
UINT8 ulTagFlags = pBuffer[5];
// ignore tags with unknown flags
if(((ulTagVersionMinor == 3) && (ulTagFlags & TF23_UnknownBits)) ||
((ulTagVersionMinor == 4) && (ulTagFlags & TF24_UnknownBits)) ||
(ulTagFlags & TF_Unsynchronisation) ||
(ulTagFlags & TF_ExperimentalIndicator))
{
return HXR_INVALID_VERSION;
}
- // check tag size
+ // check tag size, 4 bytes SynchSafe integer
UINT32 ulTagPayloadSize = 0;
if(!DecodeSynchSafeIntegerFromBuffer(pBuffer + 6, ulTagPayloadSize))
{
return HXR_FAILED;
}
UINT32 ulTagTotalSize = ulTagPayloadSize + TagHeaderSize; //add standard header size
if(ulTagFlags & TF_FooterPresent)
{
ulTagTotalSize += TagFooterSize; //add footer size
}
if(ulBufferSize < ulTagTotalSize)
{
return HXR_FAILED;
}
// skip standard header
pBuffer += TagHeaderSize;
UINT32 ulRemainingTagSize = ulTagTotalSize - TagHeaderSize;
// skip extended header
UINT32 ulTotalExtendedHeaderSize = 0;
if(ulTagFlags & TF_ExtendedHeader)
{
// need at least 4 bytes to read the size field
if(ulRemainingTagSize < 4)
{
return HXR_FAILED;
}
@@ -1989,70 +2024,71 @@
return ContainsDuplicates(m_framesAPIC, fc);
}
ID3Tools::PRIVFrame* ID3Tools::ID3v2Tag::GetPRIVFrameByID(const CHXString& ownerIdentifier) const
{
ID3Tools::PRIVFrameByIDComparator fc(ownerIdentifier);
return (PRIVFrame*)FindFrame(m_framesPRIV, fc);
}
HXBOOL ID3Tools::ID3v2Tag::ContainsPRIVFrameDuplicates() const
{
ID3Tools::PRIVFrameByIDComparator fc;
return ContainsDuplicates(m_framesPRIV, fc);
}
UINT32 ID3Tools::ID3v2Tag::CalcSerializationBufferSize(const CHXPtrArray& frames) const
{
UINT32 size = 0;
for(int i = 0; i < frames.GetSize(); i++)
{
ID3v2Frame* pFrame = (ID3v2Frame*)frames.GetAt(i);
if(pFrame)
{
size += pFrame->CalcSerializationBufferSize();
}
}
return size;
}
-HX_RESULT ID3Tools::ID3v2Tag::SerializeToBufferAndInc(UINT8*& pBuffer, UINT32& ulBufferSize, const CHXPtrArray& frames) const
+HX_RESULT ID3Tools::ID3v2Tag::SerializeToBufferAndInc(UINT8*& pBuffer, UINT32& ulBufferSize, const CHXPtrArray& frames,
+ UINT8 uTagVersionMinor) const
{
HX_RESULT result = HXR_OK;
for(int i = 0; SUCCEEDED(result) && (i < frames.GetSize()); i++)
{
ID3v2Frame* pFrame = (ID3v2Frame*)frames.GetAt(i);
if(pFrame)
{
- result = pFrame->SerializeToBuffer(pBuffer, ulBufferSize);
+ result = pFrame->SerializeToBuffer(pBuffer, ulBufferSize, uTagVersionMinor);
if(SUCCEEDED(result))
{
UINT32 size = pFrame->CalcSerializationBufferSize();
if(size > 0)
{
pBuffer += size;
ulBufferSize -= size;
}
else
{
result = HXR_FAILED;
}
}
}
}
return result;
}
HX_RESULT ID3Tools::TransformID32BlobToProperties(IUnknown* pContext, IHXValues* pDst, const UINT8* pID32Blob, UINT32 ulID32Blob)
{
if(!pContext || !pDst || !pID32Blob || !ulID32Blob)
{
return HXR_INVALID_PARAMETER;
}
ID3v2Tag tag;
HX_RESULT result = tag.DeserializeFromBuffer(pID32Blob, ulID32Blob);
if(SUCCEEDED(result))
{
Index: pub/metautil.h
===================================================================
RCS file: /cvsroot/datatype/common/util/pub/metautil.h,v
retrieving revision 1.7
diff -d -H -w -U30 -r1.7 metautil.h
--- pub/metautil.h 9 Nov 2009 19:41:57 -0000 1.7
+++ pub/metautil.h 6 Jan 2010 17:31:24 -0000
@@ -114,197 +114,197 @@
HXBOOL bCaseSensitiveSearch = TRUE);
static const char* GenreNameFromOrdinal(UINT8 uGenreOrdinal);
// returns number of entries
static UINT32 ParseGenreNameList(CHXPtrArray& outGenreOrdinals, const char* szGenreNames,
HXBOOL bCaseSensitiveSearch = TRUE, char separator = ',',
HXBOOL bTrimWhitespace = TRUE);
static void MakeGenreNameList(CHXString& outGenreNames, const CHXPtrArray& genreOrdinals,
const char* szSeparator = ",");
static HX_RESULT DetermineMimeTypeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize, CHXString& outMimeType);
static HXBOOL StartsWithJPEGSignature(const UINT8* pData, UINT32 ulDataLen);
static HXBOOL StartsWithPNGSignature(const UINT8* pData, UINT32 ulDataLen);
static HX_RESULT ReadBytesFromBufferAndInc(UINT8* dst, UINT32 count, const UINT8*& pBuffer, UINT32& ulRemainingBufferSize);
static HX_RESULT ReadByteFromBufferAndInc(UINT8& dst, const UINT8*& pBuffer, UINT32& ulRemainingBufferSize)
{
return ReadBytesFromBufferAndInc(&dst, 1, pBuffer, ulRemainingBufferSize);
}
static HX_RESULT WriteBytesToBufferAndInc(UINT8*& pBuffer, const UINT8* src, UINT32 count);
static HX_RESULT WriteByteToBufferAndInc(UINT8*& pBuffer, UINT8 src)
{
return WriteBytesToBufferAndInc(pBuffer, &src, 1);
}
static HXBOOL EncodeAsSynchSafeIntegerToBuffer(UINT8* pBuffer, UINT32 val);
static HXBOOL DecodeSynchSafeIntegerFromBuffer(const UINT8* pBuffer, UINT32& out);
+ static void WriteIntegerToBuffer(UINT8* pBuffer, UINT32 val);
static void ReadIntegerFromBuffer(const UINT8* pBuffer, UINT32& out);
struct ID3v2FrameHeader
{
UINT8 FrameID[4];
UINT8 Flags[2];
UINT32 FrameSize;
UINT32 TotalFrameSize;
UINT32 PayloadOffset; //from the beginning of the frame
UINT32 DataLengthIndicator; //DecompressedSize
UINT8 EncryptionMethod;
UINT8 GroupingIdentity;
HXBOOL NeedsSpecialProcessing;
ID3v2FrameHeader()
{
memset(FrameID, 0, 4);
memset(Flags, 0, 2);
FrameSize = 0;
TotalFrameSize = 0;
PayloadOffset = 0;
DataLengthIndicator = 0;
EncryptionMethod = 0;
GroupingIdentity = 0;
NeedsSpecialProcessing = FALSE;
}
};
class ID3v2Frame
{
public:
enum eFrameType
{
FrameType_Unknown = 0,
FrameType_PRIV,
- FrameType_APIC,
+ FrameType_APIC
};
enum eFrameFlags
{
// v2.3 frame format flags (second byte)
FFF23_Compression = 0x80,
FFF23_Encryption = 0x40,
FFF23_GroupingIdentity = 0x20,
FFF23_UnknownBits = 0x1F,
// v2.4 frame format flags (second byte)
FFF24_GroupingIdentity = 0x40,
FFF24_Compression = 0x08,
FFF24_Encryption = 0x04,
FFF24_Unsynchronisation = 0x02,
FFF24_DataLengthIndicator = 0x01,
FFF24_UnknownBits = 0xB0
};
enum eTextEncoding
{
TextEncoding_ISO88591 = 0x00,
TextEncoding_UTF16BOM = 0x01,
TextEncoding_UTF16BE = 0x02,
TextEncoding_UTF8 = 0x03,
TextEncoding_Count
};
enum
{
FrameHeaderSize = 10,
BufferPropertyTagVersionMinor = _META_INFO_BUFFER_PROPERTY_ID3_TAG_VERSION_MINOR
};
static HX_TEXT_ENCODING_TYPE HelixTextEncodingFromID3TextEncoding(eTextEncoding enc);
static HX_RESULT ConvertToEncoding(EncodedString& dst, eTextEncoding dstEnc,
const EncodedString& src, HXBOOL bNewlinesAllowed);
static HX_RESULT ReadEncodedStringFromBufferAndInc(EncodedString& dst, eTextEncoding dstEnc,
const UINT8*& pBuffer, UINT32& ulRemainingBufferSize);
static HX_RESULT WriteEncodedStringToBufferAndInc(UINT8*& pBuffer, const EncodedString& src);
static HX_RESULT ReadISO88591StringFromBufferAndInc(CHXString& dst, const UINT8*& pBuffer, UINT32& ulRemainingBufferSize);
static HX_RESULT WriteISO88591StringToBufferAndInc(UINT8*& pBuffer, const char* pSrc);
static HXBOOL IsValidFrameID(const UINT8 frameID[4]);
static HX_RESULT ReadFrameHeader(ID3v2FrameHeader& out, UINT8 uTagVersionMinor,
const UINT8*& pBuffer, UINT32& uRemainingBufferSize);
static HX_RESULT ReadFrameHeaderAndInc(ID3v2FrameHeader& out, UINT8 uTagVersionMinor,
const UINT8*& pBuffer, UINT32& uRemainingBufferSize,
const char szExpectedFrameID[4]);
static HX_RESULT WriteFrameHeaderAndInc(UINT8*& pBuffer, const char frameID[4],
- UINT32 ulFramePayloadSize, UINT8 ulFrameFlags[2]);
+ UINT32 ulFramePayloadSize, UINT8 ulFrameFlags[2],
+ UINT8 uTagVersionMinor);
ID3v2Frame()
{ }
virtual ~ID3v2Frame()
{ }
// Buffer properties always carry the format defined by ID3v2 BufferPropertyTagVersionMinor
HX_RESULT SerializeToBufferProperty(IUnknown* pContext, IHXValues* pDst, const char* pszPropertyName) const;
// Returns HXR_INVALID_VERSION if the frame requires special processing
HX_RESULT DeserializeFromBufferProperty(IHXValues* pSrc, const char* pszPropertyName);
virtual eFrameType GetFrameType() const = 0;
virtual void Clear() = 0;
virtual ID3v2Frame* Clone() const = 0;
virtual UINT32 CalcSerializationBufferSize() const = 0;
- virtual HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const = 0;
- virtual HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize,
- UINT8 uTagVersionMinor = BufferPropertyTagVersionMinor) = 0;
+ virtual HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) const = 0;
+ virtual HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) = 0;
private:
ID3v2Frame(const ID3v2Frame&);
ID3v2Frame& operator=(const ID3v2Frame&);
};
struct ID3v2FrameComparator
{
virtual ~ID3v2FrameComparator() {}
virtual HXBOOL Equal(const ID3v2Frame* p1, const ID3v2Frame* p2) const = 0;
virtual HXBOOL Matches(const ID3v2Frame* p) const = 0;
};
class PRIVFrame : public ID3v2Frame
{
public:
PRIVFrame();
virtual ~PRIVFrame();
virtual eFrameType GetFrameType() const { return FrameType_PRIV; }
virtual void Clear();
virtual PRIVFrame* Clone() const;
virtual UINT32 CalcSerializationBufferSize() const;
- virtual HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const;
- virtual HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize,
- UINT8 uTagVersionMinor = BufferPropertyTagVersionMinor);
+ virtual HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) const;
+ virtual HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor);
const char* GetOwnerIdentifier() const
{
return (const char*)m_strOwnerIdentifier;
}
void SetOwnerIdentifier(const char* szOwnerIdentifier);
UINT32 GetPrivateDataSize() const
{
return m_ulPrivateDataSize;
}
const UINT8* GetPrivateData() const
{
return m_pPrivateData;
}
HX_RESULT SetPrivateData(const UINT8* pBuffer, UINT32 ulBufferSize);
private:
HX_RESULT AllocatePrivateDataBuffer(UINT32 ulSize);
void FreePrivateDataBuffer();
UINT32 CalcPayloadSize() const;
CHXString m_strOwnerIdentifier;
UINT32 m_ulPrivateDataSize;
UINT8* m_pPrivateData;
};
struct PRIVFrameByIDComparator : public ID3v2FrameComparator
{
CHXString OwnerIdentifier;
@@ -346,94 +346,93 @@
PictureType_CoverFront,
PictureType_CoverBack,
PictureType_LeafletPage, //0x05
PictureType_Media,
PictureType_LeadArtist,
PictureType_Artist,
PictureType_Conductor,
PictureType_Band, //0x0A
PictureType_Composer,
PictureType_Lyricist,
PictureType_RecordingLocation,
PictureType_DuringRecording,
PictureType_DuringPerformance, //0x0F
PictureType_ScreenCapture,
PictureType_BrightColouredFish,
PictureType_Illustration,
PictureType_ArtistLogotype,
PictureType_PublisherLogotype, //0x14
PictureType_Count //special
};
static HXBOOL IsPredefinedPictureType(UINT8 ulPictureType);
APICFrame();
virtual ~APICFrame();
virtual eFrameType GetFrameType() const { return FrameType_APIC; }
virtual void Clear();
virtual APICFrame* Clone() const;
virtual UINT32 CalcSerializationBufferSize() const;
- virtual HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const;
- virtual HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize,
- UINT8 uTagVersionMinor = BufferPropertyTagVersionMinor);
+ virtual HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor) const;
+ virtual HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor);
HX_RESULT SavePictureDataToImageFile(const char* pszFileName);
HX_RESULT LoadPictureDataFromImageFile(const char* pszFileName, HXBOOL bOnlyKnownMimeTypes);
UINT8 GetPictureType() const
{
return m_ulPictureType;
}
void SetPictureType(UINT8 ulPictureType);
UINT32 GetPictureDataSize() const
{
return m_ulPictureDataSize;
}
const UINT8* GetPictureData() const
{
return m_pPictureData;
}
HX_RESULT SetPictureData(const UINT8* pBuffer, UINT32 ulBufferSize);
const CHXString& GetMimeType() const
{
return m_strMimeType;
}
void SetMimeType(const CHXString& mimeType);
eTextEncoding GetTextEncoding() const
{
return m_textEncoding;
}
- // must be set prior to description
+ // encoding must be set before setting description
HX_RESULT SetTextEncoding(eTextEncoding enc);
void GetDescription(EncodedString& out) const
{
out = m_strDescription;
}
HX_RESULT SetDescription(const EncodedString& es);
private:
HX_RESULT AllocatePictureDataBuffer(UINT32 ulSize);
void FreePictureDataBuffer();
UINT32 CalcPayloadSize() const;
eTextEncoding m_textEncoding;
CHXString m_strMimeType;
UINT8 m_ulPictureType;
EncodedString m_strDescription;
UINT32 m_ulPictureDataSize;
UINT8* m_pPictureData;
};
struct APICFrameByTypeComparator : public ID3v2FrameComparator
{
UINT8 PictureType;
APICFrameByTypeComparator(UINT8 picType = 0)
: PictureType(picType)
{ }
virtual HXBOOL Equal(const ID3v2Frame* p1, const ID3v2Frame* p2) const
@@ -450,107 +449,109 @@
virtual HXBOOL Matches(const ID3v2Frame* p) const
{
APICFrame* pFrame = (APICFrame*)p;
if(pFrame)
{
return pFrame->GetPictureType() == PictureType;
}
return FALSE;
}
};
class ID3v2Tag
{
public:
enum eTagFlags
{
TF_Unsynchronisation = 0x80,
TF_ExtendedHeader = 0x40,
TF_ExperimentalIndicator = 0x20,
TF_FooterPresent = 0x10,
TF23_UnknownBits = 0x1F,
TF24_UnknownBits = 0x0F
};
enum
{
TagHeaderSize = 10,
TagFooterSize = 10
};
- static HX_RESULT WriteTagHeaderAndInc(UINT8*& pBuffer, UINT8 ulTagFlags, UINT32 ulTagPayloadSize);
+ static HX_RESULT WriteTagHeaderAndInc(UINT8*& pBuffer, UINT8 ulTagFlags, UINT32 ulTagPayloadSize,
+ UINT8 uTagVersionMinor);
static HXBOOL IsPadding(const UINT8* pBuffer, UINT32 ulBufferSize);
static HXBOOL StartsWithFrameID(const UINT8* pBuffer, UINT32 ulBufferSize);
static HX_RESULT CreateFrameObjectFromID(const char frameID[4], ID3v2Frame** ppFrame);
ID3v2Tag();
virtual ~ID3v2Tag();
void Clear();
UINT32 CalcSerializationBufferSize() const;
- HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize) const;
+ HX_RESULT SerializeToBuffer(UINT8* pBuffer, UINT32 ulBufferSize, UINT8 uTagVersionMinor = 4) const;
// Returns HXR_INVALID_VERSION if it encounters unsupported version of ID3v2
HX_RESULT DeserializeFromBuffer(const UINT8* pBuffer, UINT32 ulBufferSize);
UINT32 GetNumAPICFrames() const
{
return m_framesAPIC.GetSize();
}
HX_RESULT AddFrame(APICFrame* pFrame);
UINT32 GetNumPRIVFrames() const
{
return m_framesPRIV.GetSize();
}
HX_RESULT AddFrame(PRIVFrame* pFrame);
UINT32 GetNumFrames() const;
HX_RESULT AddFrame(ID3v2Frame* pFrame);
HX_RESULT CopyAPICFramesToProperties(IUnknown* pContext, IHXValues* pDst) const;
HX_RESULT CopyPRIVFramesToProperties(IUnknown* pContext, IHXValues* pDst) const;
HX_RESULT CopyFramesToProperties(IUnknown* pContext, IHXValues* pDst) const;
private:
HXBOOL ContainsDuplicates(const CHXPtrArray& a, ID3v2FrameComparator& fc) const;
ID3v2Frame* FindFrame(const CHXPtrArray& a, ID3v2FrameComparator& fc) const;
void DeleteFrames(CHXPtrArray& frames);
APICFrame* GetAPICFrameByType(UINT8 APICFramePictureType) const;
HXBOOL ContainsAPICFrameDuplicates() const;
PRIVFrame* GetPRIVFrameByID(const CHXString& ownerIdentifier) const;
HXBOOL ContainsPRIVFrameDuplicates() const;
UINT32 CalcSerializationBufferSize(const CHXPtrArray& frames) const;
- HX_RESULT SerializeToBufferAndInc(UINT8*& pBuffer, UINT32& ulBufferSize, const CHXPtrArray& frames) const;
+ HX_RESULT SerializeToBufferAndInc(UINT8*& pBuffer, UINT32& ulBufferSize, const CHXPtrArray& frames,
+ UINT8 uTagVersionMinor) const;
UINT32 CalcPayloadSize() const;
CHXPtrArray m_framesAPIC;
CHXPtrArray m_framesPRIV;
};
static HX_RESULT TransformID32BlobToProperties(IUnknown* pContext, IHXValues* pDst, const UINT8* pID32Blob, UINT32 ulID32Blob);
};
//
// Known metadata tools
//
class MetaInfo
{
public:
static HX_RESULT RemoveBufferPropertyArray(IHXValues* pValues,
const char* szCountPropName, const char* szItemPropName);
static HX_RESULT RemoveKeywordProperties(IHXValues* pValues);
static HX_RESULT RemovePictureProperties(IHXValues* pValues);
static HX_RESULT CopyBufferPropertyArray(IHXValues* dst, IHXValues* src, HXBOOL bBlast,
const char* szCountPropName, const char* szItemPropName);
static HX_RESULT CopyKeywordProperties(IHXValues* dst, IHXValues* src, HXBOOL bBlast);
static HX_RESULT CopyPictureProperties(IHXValues* dst, IHXValues* src, HXBOOL bBlast);
static HX_RESULT RemoveAllProperties(IHXValues* pValues, UINT32 metaInfoSetFlags);
static HX_RESULT CopyAllProperties(IHXValues* dst, IHXValues* src, UINT32 metaInfoSetFlags, HXBOOL bBlast);
static UINT32 GetSetsFromFlavors(UINT32 metaFlavorFlags);
static CHXString GetFlavorName(METADATA_FLAVOR flavor);
datatype_mp4_filewriter.diff
(text/x-patch, 10.2 KB)
Index: mp4sm.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.cpp,v
retrieving revision 1.23
diff -d -H -w -U30 -r1.23 mp4sm.cpp
--- mp4sm.cpp 6 Jan 2010 16:15:18 -0000 1.23
+++ mp4sm.cpp 6 Jan 2010 17:24:24 -0000
@@ -633,60 +633,61 @@
: 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_uID3TagVersionMinorOutput(4)
, 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 );
}
@@ -704,60 +705,84 @@
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 = 0x00000010; //from ihxmetaeditor.h
m_bRequestedOutputMetaFlavor3GPP = (ulVal & METADATA_FLAVOR_3GPP) ? TRUE : FALSE;
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;
+ // Meta-data ID3v2 output control
+ ulVal = 0;
+ PropTools::CopyPropertyULONG32(ulVal, pProperties, "MetaDataID3Version");
+
+ const UINT32 METADATAID3VERSION_230 = 0x00020300; //from ffdriver.h
+ const UINT32 METADATAID3VERSION_240 = 0x00020400;
+ const UINT32 METADATAID3VERSION_NONE = 0x01000000;
+
+ switch(ulVal)
+ {
+ case METADATAID3VERSION_NONE:
+ m_uID3TagVersionMinorOutput = 0;
+ break;
+
+ case METADATAID3VERSION_230:
+ m_uID3TagVersionMinorOutput = 3;
+ break;
+
+ case METADATAID3VERSION_240:
+ default:
+ m_uID3TagVersionMinorOutput = 4;
+ break;
+ }
+
// 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)
{
@@ -4470,60 +4495,66 @@
if(m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP))
{
retVal = Build3GPPMetaDataStandardSet(pUdta, pMoov);
}
// ID32, setup box hierarchy: file/moov/meta/[hdlr, ID32]
if(SUCCEEDED(retVal))
{
CMP4Atom_meta* pMeta = NULL;
retVal = Build3GPPMetaDataID32(m_pFileHeader, &pMeta, TRUE);
if(SUCCEEDED(retVal) && pMeta)
{
retVal = pMoov->AddChild(pMeta);
}
}
return retVal;
}
HX_RESULT CMP4StreamMixer::Build3GPPMetaDataID32( IHXValues* pHeader, CMP4Atom_meta** ppMeta, HXBOOL bFileHeader )
{
if(!ppMeta || !pHeader)
{
return HXR_INVALID_PARAMETER;
}
*ppMeta = NULL;
HX_RESULT retVal = HXR_OK;
+ // check if we need to skip writing-out ID32
+ if(!m_uID3TagVersionMinorOutput)
+ {
+ return retVal;
+ }
+
// 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;
@@ -4548,61 +4579,61 @@
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);
+ retVal = tag.SerializeToBuffer(pID32Blob, ulID32BlobSize, m_uID3TagVersionMinorOutput);
}
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)
Index: mp4sm.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.h,v
retrieving revision 1.15
diff -d -H -w -U30 -r1.15 mp4sm.h
--- mp4sm.h 6 Jan 2010 16:15:18 -0000 1.15
+++ mp4sm.h 6 Jan 2010 17:24:25 -0000
@@ -313,58 +313,59 @@
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;
+ UINT8 m_uID3TagVersionMinorOutput;
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, 20.4 KB)
Index: main.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/main.cpp,v
retrieving revision 1.6
diff -d -H -w -U30 -r1.6 main.cpp
--- main.cpp 3 Dec 2009 15:36:11 -0000 1.6
+++ main.cpp 6 Jan 2010 17:13:29 -0000
@@ -31,61 +31,61 @@
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/****************************************************************************
* Includes
*/
#include <stdlib.h>
#include <stdarg.h>
#include "hlxclib/time.h"
#include "hlxclib/stdio.h"
#include "hlxclib/wchar.h"
#include "hxtypes.h"
#include "hlxosstr.h"
#include "ffdriver.h"
#include "cstrmsrt.h"
#include "hxmemprb.h"
#include "hxtick.h"
#include "chxpckts.h"
#include "pckunpck.h"
#include "dllpath.h"
#include "filespecutils.h"
#include "metainfokeys.h"
#include "uniconv.h"
#include "proptools.h"
#include "dllacces.h"
#include "ihxmetaeditor.h"
-#include "hxxmlinputparser.h"
+#include "HXXmlInputParser.h"
#include "metautil.h"
#ifdef HELIX_FEATURE_METAEDIT_AUDIO_HASH
#include "mycrypt.h"
#endif
/****************************************************************************
* Meta-data command line editor.
* Build-time configuration options.
*/
// uncomment to force usage of legacy strings on Windows
// (only relevant for command-line argument transfer)
//#define FORCE_LEGACY_CHAR 1
/****************************************************************************
* Component operational modes
*/
HXBOOL g_bUseDefaultMetaEditorProcessor = FALSE;
HXBOOL g_bUseDTDriverSynchronousMode = FALSE;
/****************************************************************************
* System character type macros
*/
#ifdef USE_WIDE_CHAR
#undef USE_WIDE_CHAR
#endif
@@ -128,72 +128,75 @@
#define TUTF8EncodedStringCCPCtor(Val) EncodedString((const char*)::UTF8FromCCP(Val), HX_TEXT_ENCODING_TYPE_UTF8)
#endif //USE_WIDE_CHAR
/****************************************************************************
* Build-time messages
*/
#ifdef _WINDOWS
#ifdef USE_WIDE_CHAR
# pragma message("Using wide-string command-line arguments")
#else
# pragma message("Using legacy-string command-line arguments")
#endif
#endif //_WINDOWS
/****************************************************************************
* DLLAccessPath Variable
*/
ENABLE_DLLACCESS_PATHS(g_Meta3GPAccessPath);
/****************************************************************************
* Defines
*/
#define PROGRAM_NAME_STRING "RealNetworks meta-data editor"
#define PROGRAM_COPYRIGHT_STRING "Copyright (c) RealNetworks 2009"
-#define PROGRAM_VERSION_STRING "1.0.1"
+#define PROGRAM_VERSION_STRING "1.0.3"
// input/output control
#define OPTION_STRING_SYNCMODE "dev-syncmode"
#define OPTION_STRING_DEFMETAPROC "dev-defmetaproc"
#define OPTION_STRING_INPUTFILE "if"
#define OPTION_STRING_OUTPUTFILE "of"
#define OPTION_STRING_XMLINPUTFILE "xmlin"
#define OPTION_STRING_XMLOUTPUTFILE "xmlout"
#define OPTION_STRING_CLEARMETADATA "metaclear"
#define OPTION_STRING_METASTYLE "metastyle"
#define OPTION_STRING_UTF16OUTPUT "utf16"
+#define OPTION_STRING_ID3V240OUTPUT "id3v240"
+#define OPTION_STRING_ID3V230OUTPUT "id3v230"
+#define OPTION_STRING_ID3V2NOOUTPUT "id3v2no"
#define OPTION_STRING_OVERWRITEFILE "overwrite"
#define OPTION_STRING_PRINTMETADATA "print"
#define OPTION_STRING_HELP "help"
#define OPTION_STRING_GENERATEHASH "audiohash"
// common metadata
#define OPTION_STRING_TITLE "title"
#define OPTION_STRING_ARTIST "artist"
#define OPTION_STRING_ALBUM "album"
#define OPTION_STRING_GENRE "genre"
#define OPTION_STRING_COMPOSER "composer"
#define OPTION_STRING_COMMENT "comment"
#define OPTION_STRING_TRACKNUMBER "track"
#define OPTION_STRING_YEAR "year"
#define OPTION_STRING_PICTURE_ADD "addpic"
#define OPTION_STRING_PICTURE_REMOVE "rempic"
#define OPTION_STRING_PICTURE_CLEAR "clrpic"
#define OPTION_STRING_PICTURE_EXTRACT "savepic"
#define OPTION_STRING_UITS_INSERT "insertsignature"
#define OPTION_STRING_UITS_EXTRACT "extractsignature"
// iTunes specific metadata
#define OPTION_STRING_SOFTWARE "software"
#define OPTION_STRING_ENCODEDBY "encodedby"
#define OPTION_STRING_GROUPING "grouping"
#define OPTION_STRING_ALBUMARTIST "albumartist"
#define OPTION_STRING_LYRICS "lyrics"
#define OPTION_STRING_SUBTITLE "subtitle"
@@ -402,63 +405,65 @@
return od;
}
}
return NULL;
}
void InitializeXmlPairs(CParsedXmlPairs *xmlPairs)
{
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* desc = (OptionDesc*)descs.GetAt(i);
CHXString xpath(desc->GetXPath());
if (!xpath.IsEmpty())
{
xmlPairs->Add(new XmlPair(xpath, CHXString("")));
}
}
}
private:
CHXPtrArray descs;
};
void DisplayUsage(const TCHAR* argv0, OptionRegistry& optionReg)
{
const char* pszDbg = "";
#if defined(DEBUG) || defined(_DEBUG)
pszDbg = ".debug";
#endif
+ CHXString exeName = CHXFileSpecUtils::GetCurrentApplication().GetName();
+
printf("\n--- %s ---\n %s\n Version %s%s\n\n",
PROGRAM_NAME_STRING, PROGRAM_COPYRIGHT_STRING, PROGRAM_VERSION_STRING, pszDbg);
- printf("usage: %s [ -option [value]... ]...\n", argv0);
+ printf("usage: %s [ -option [value]... ]...\n", (const char*)exeName);
printf("with options:\n");
optionReg.PrintColumns(2);
}
/****************************************************************************
* Asynchronous mode helpers
*/
void SignalAsyncDriveEnd()
{
#ifdef _WINDOWS
::PostMessage(0, (WM_USER + 202), 0, 0);
#else
printf("ERROR: SignalAsyncDriveEnd not implemented.\n");
#endif
}
void WaitAsyncDriveEnd()
{
#ifdef _WINDOWS
MSG msg;
while(GetMessage(&msg, 0, 0, 0))
{
if(msg.message == (WM_USER + 202))
{
break;
}
DispatchMessage(&msg);
}
@@ -1525,106 +1530,114 @@
CHXFileSpecifier exeFileSpec;
UINT32 startTime = 0;
DLLAccess* pDLLAccess = 0;
FPHXMEDIAPLATFORMOPEN fpHXMediaPlatformOpen = 0;
FPHXCREATEMEDIAPLATFORM fpHXCreateMediaPlatform = 0;
FPHXMEDIAPLATFORMCLOSE fpHXMediaPlatformClose = 0;
IHXMediaPlatform* pMediaPlatform = 0;
IHXCommonClassFactory* pCommonClassFactory = 0;
IHXMetaDataEditor* pEditor = 0;
CResponse* pResponse = 0;
CProcessor* pProcessor = 0;
IHXValues* pOptions = 0;
char pDllPath[_MAX_PATH] = {0};
char pDllFile[_MAX_PATH] = {0};
const char* pszHelixLibs = 0;
CHXString strInputFileName;
CHXString strOutputFileName;
CHXString strPictureFileNamePrefix;
CHXString strUITSDataOutputFileName;
CHXString strMetaStyleName;
HXBOOL bDisplayHelp = FALSE;
HXBOOL bOverwriteFile = FALSE;
HXBOOL bPrintMetaData = FALSE;
HXBOOL bExtractPicturesToFiles = FALSE;
HXBOOL bUTF16Output = FALSE;
+ UINT32 ulMetaDataID3VersionOutput = METADATAID3VERSION_240;
MetaProcessorVars metaProcessorVars;
OptionRegistry optionReg;
// input options parsed from the command line and xml file
InputOptions inputOptions;
// xml parser to parse xml input file
CHXXmlInputParser* pInputParser = 0;
// initialize Helix DNA client media-platform
HX_RESULT retVal = HXR_OK;
// load Helix media-platform library
pDLLAccess = new DLLAccess();
if(!pDLLAccess)
{
retVal = HXR_OUTOFMEMORY;
goto cleanup;
}
// extract plugin directory
#ifdef _WINDOWS
exeFileSpec = CHXFileSpecUtils::GetCurrentApplication();
strncpy(pDllPath, (const char*)exeFileSpec.GetParentDirectory().GetPathName(), _MAX_PATH);
snprintf(pDllFile, _MAX_PATH, "%s\\%s", pDllPath, "hxmedpltfm.dll");
#else
pszHelixLibs = getenv("HELIX_LIBS");
if(pszHelixLibs)
{
strncpy(pDllPath, pszHelixLibs, _MAX_PATH);
snprintf(pDllFile, _MAX_PATH, "%s/%s", pDllPath, "hxmedpltfm.so");
}
else
{
printf("Missing HELIX_LIBS environment variable\n");
goto cleanup;
}
#endif
pDllPath[_MAX_PATH - 1] = '\0';
pDllFile[_MAX_PATH - 1] = '\0';
if(pDLLAccess->open(pDllFile) != DLLAccess::DLL_OK)
{
printf("Failed to access Helix DNA client media-platform library file: %s\n", pDllFile);
+
+ const char* szError = pDLLAccess->getErrorString();
+ if(szError)
+ {
+ printf("Error description: %s\n", szError);
+ }
+
goto cleanup;
}
// initialize Helix media-platform
fpHXMediaPlatformOpen = (FPHXMEDIAPLATFORMOPEN) pDLLAccess->getSymbol("HXMediaPlatformOpen");
fpHXCreateMediaPlatform = (FPHXCREATEMEDIAPLATFORM) pDLLAccess->getSymbol("HXCreateMediaPlatform");
fpHXMediaPlatformClose = (FPHXMEDIAPLATFORMCLOSE) pDLLAccess->getSymbol("HXMediaPlatformClose");
if(!fpHXMediaPlatformOpen || !fpHXCreateMediaPlatform || !fpHXMediaPlatformClose)
{
retVal = HXR_FAILED;
}
if(SUCCEEDED(retVal))
{
retVal = fpHXMediaPlatformOpen();
}
if(SUCCEEDED(retVal))
{
retVal = fpHXCreateMediaPlatform((IHXMediaPlatform**)&pMediaPlatform);
}
if(SUCCEEDED(retVal))
{
retVal = pMediaPlatform->AddPluginPath("Meta3GP", pDllPath);
}
if(SUCCEEDED(retVal))
{
@@ -1680,60 +1693,63 @@
if(FAILED(retVal))
{
printf("Failed to initialize Helix meta-data editor plugin.\n");
goto cleanup;
}
// create xml parser
pInputParser = new CHXXmlInputParser();
pInputParser->AddRef();
if(SUCCEEDED(retVal))
{
retVal = pInputParser->Init(pCommonClassFactory);
}
if(FAILED(retVal))
{
printf("Failed to initialize xml parser.\n");
goto cleanup;
}
// construct option registry
optionReg.Add(new OptionDesc(OPTION_STRING_INPUTFILE, "<filename>", "input file", 1, "/albums/album/track/mediaFile/fileName"));
optionReg.Add(new OptionDesc(OPTION_STRING_OUTPUTFILE, "<filename>", "output file", 1, "/albums/album/track/outputFileName"));
optionReg.Add(new OptionDesc(OPTION_STRING_XMLINPUTFILE, "<filename>", "xml file with input parameters", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_OVERWRITEFILE, 0, "overwrite output file if it exists", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_CLEARMETADATA, 0, "clear all extracted metadata before injection", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_METASTYLE, "<3GPP | iTunes>", "flavor of injected metadata, default=all", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_UTF16OUTPUT, 0, "inject metadata strings in UTF16 format", 0));
+ optionReg.Add(new OptionDesc(OPTION_STRING_ID3V240OUTPUT, 0, "inject ID3v2 version 2.4.0, default", 0));
+ optionReg.Add(new OptionDesc(OPTION_STRING_ID3V230OUTPUT, 0, "inject ID3v2 version 2.3.0", 0));
+ optionReg.Add(new OptionDesc(OPTION_STRING_ID3V2NOOUTPUT, 0, "skip injecting ID3v2 tag", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_PRINTMETADATA, 0, "print updated metadata", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_EXTRACT, "[filename-prefix]", "save extracted pictures", -1));
optionReg.Add(new OptionDesc(OPTION_STRING_GENERATEHASH, 0, "generate hash", 0));
optionReg.Add(new OptionDesc());
optionReg.Add(new OptionDesc(OPTION_STRING_TITLE, "<string>", "update title", 1, "/albums/album/track/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_ARTIST, "<string>", "update 3GPP performer, iTunes artist", 1, "/albums/album/track/artist/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_ALBUM, "<string>", "update album", 1, "/albums/album/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_GENRE, "<string>", "update genre", 1, "/albums/album/track/style/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_COMPOSER, "<string>", "update 3GPP author, iTunes composer", 1, "/albums/album/track/artist/composer"));
optionReg.Add(new OptionDesc(OPTION_STRING_COMMENT, "<string>", "update 3GPP description, iTunes comment", 1, "/albums/album/pline"));
optionReg.Add(new OptionDesc(OPTION_STRING_COPYRIGHT, "<string>", "update copyright", 1, "/albums/album/cline"));
optionReg.Add(new OptionDesc(OPTION_STRING_TRACKNUMBER, "<integer 0..255>", "update track number", 1, "/albums/album/track/sequence"));
optionReg.Add(new OptionDesc(OPTION_STRING_YEAR, "<integer 0..65536>", "update 3GPP recording year, iTunes release date", 1, "/albums/album/OrigReleaseYear"));
optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_ADD, "<filename>", "add picture", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_REMOVE, "<APIC picture type>", "remove picture", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_CLEAR, 0, "clear all extracted pictures", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_UITS_INSERT, "<filename>", "insert UITS signature from file", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_UITS_EXTRACT, "<filename>", "extract UITS signature into file", 1));
optionReg.Add(new OptionDesc());
optionReg.Add(new OptionDesc(OPTION_STRING_SOFTWARE, "<string>", "update iTunes generator tool", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_ENCODEDBY, "<string>", "update iTunes encoded by", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_GROUPING, "<string>", "update iTunes grouping", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_ALBUMARTIST, "<string>", "update iTunes album artist", 1, "/albums/album/artist/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_LYRICS, "<string>", "update iTunes lyrics", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_SUBTITLE, "<string>", "update iTunes track subtitle", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_BPM, "<integer>", "update iTunes beats per minute", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_PARTOFCOMP, "<0 | 1>", "update iTunes part of compilation", 1, "/albums/album/compilation"));
optionReg.Add(new OptionDesc(OPTION_STRING_EXPLICIT, "<0 | 1>", "update iTunes content rating", 1, "/albums/album/explicit"));
optionReg.Add(new OptionDesc(OPTION_STRING_TRACKSTOTAL, "<integer>", "update iTunes track count", 1, "/albums/album/trackCount"));
optionReg.Add(new OptionDesc(OPTION_STRING_DISKNUMBER, "<integer>", "update iTunes disc number", 1, "/albums/album/track/discNumber"));
@@ -1860,60 +1876,72 @@
// do nothing, since it was already done what needs to be done
}
else if(strOption == OPTION_STRING_METASTYLE)
{
strMetaStyleName = strOptionValue;
if(clpp == CLPP_IndependentOptions)
{
if(SUCCEEDED(retVal) && !strMetaStyleName.IsEmpty())
{
if(!strMetaStyleName.CompareNoCase("3gpp"))
{
metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_3GPP;
}
else if(!strMetaStyleName.CompareNoCase("itunes"))
{
metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
}
else
{
retVal = HXR_PARSE_ERROR;
ReportInvalidValueForOptionA(OPTION_STRING_METASTYLE, (const char*)strMetaStyleName);
}
}
}
}
else if(strOption == OPTION_STRING_UTF16OUTPUT)
{
bUTF16Output = TRUE;
}
+ else if(strOption == OPTION_STRING_ID3V240OUTPUT)
+ {
+ ulMetaDataID3VersionOutput = METADATAID3VERSION_240;
+ }
+ else if(strOption == OPTION_STRING_ID3V230OUTPUT)
+ {
+ ulMetaDataID3VersionOutput = METADATAID3VERSION_230;
+ }
+ else if(strOption == OPTION_STRING_ID3V2NOOUTPUT)
+ {
+ ulMetaDataID3VersionOutput = METADATAID3VERSION_NONE;
+ }
else if(strOption == OPTION_STRING_TITLE)
{
retVal = ProcessDependentStringOption(clpp, option,
metaProcessorVars, MetaInfo::StringMetaItem_Title);
}
else if(strOption == OPTION_STRING_ARTIST)
{
retVal = ProcessDependentStringOption(clpp, option,
metaProcessorVars, MetaInfo::StringMetaItem_Artist);
}
else if(strOption == OPTION_STRING_ALBUM)
{
retVal = ProcessDependentStringOption(clpp, option,
metaProcessorVars, MetaInfo::StringMetaItem_Album);
}
else if(strOption == OPTION_STRING_GENRE)
{
retVal = ProcessDependentStringOption(clpp, option,
metaProcessorVars, MetaInfo::StringMetaItem_Genre);
}
else if(strOption == OPTION_STRING_COMPOSER)
{
retVal = ProcessDependentStringOption(clpp, option,
metaProcessorVars, MetaInfo::StringMetaItem_Composer);
}
else if(strOption == OPTION_STRING_COMMENT)
{
retVal = ProcessDependentStringOption(clpp, option,
metaProcessorVars, MetaInfo::StringMetaItem_Description);
}
@@ -2208,60 +2236,66 @@
{
retVal = HXR_FAIL;
}
}
if(FAILED(retVal))
{
goto cleanup;
}
// initialize options
retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues,
(void**)&pOptions, pCommonClassFactory);
if(SUCCEEDED(retVal))
{
retVal = pOptions->SetPropertyULONG32(SYNCHRONOUS_OPTION_NAME, g_bUseDTDriverSynchronousMode ? 1 : 0);
}
if(SUCCEEDED(retVal))
{
retVal = pOptions->SetPropertyULONG32(BLASTFILE_OPTION_NAME, bOverwriteFile ? 1 : 0);
}
if(SUCCEEDED(retVal))
{
retVal = pOptions->SetPropertyULONG32(UTF16OUTPUT_OPTION_NAME, bUTF16Output ? 1 : 0);
}
if(SUCCEEDED(retVal))
{
+ // Notify writer about the version of ID3 tag it should output.
+ retVal = pOptions->SetPropertyULONG32(METADATAID3VERSION_OPTION_NAME, ulMetaDataID3VersionOutput);
+ }
+
+ if(SUCCEEDED(retVal))
+ {
// Notify meta-editor about the flavor of meta-data it should process.
retVal = pOptions->SetPropertyULONG32(METADATAFLAVOR_OPTION_NAME, metaProcessorVars.InjectedMetaFlavors);
}
if(SUCCEEDED(retVal))
{
// Legacy ID32_BLOB property must not get in the way of newly defined properties.
// Tell file-writer to ignore it.
retVal = pOptions->SetPropertyULONG32(METADATAIGNORE_OPTION_NAME, METADATAIGNORE_ID32BLOB);
}
if(SUCCEEDED(retVal))
{
if(g_bUseDefaultMetaEditorProcessor)
{
retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME, metaProcessorVars.ClearMetaData ? 1 : 0);
}
else
{
// Notify meta-editor that we do not want it to perform any default internal meta-data merging.
// Custom processor in this application performs special merging of extracted and injected meta-data.
retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME, 1);
}
}
if(FAILED(retVal))
{
printf("Failed to initialize options.\n");
goto cleanup;
}
datatype_tools_dtdriver_engine.diff
(text/x-patch, 14.2 KB)
Index: ffdriver.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/engine/ffdriver.cpp,v
retrieving revision 1.63
diff -d -H -w -U30 -r1.63 ffdriver.cpp
--- ffdriver.cpp 2 Dec 2009 08:08:07 -0000 1.63
+++ ffdriver.cpp 6 Jan 2010 17:15:49 -0000
@@ -256,60 +256,61 @@
, 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_ulMetaDataID3Version(METADATAID3VERSION_240)
, 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
@@ -660,60 +661,64 @@
{
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;
}
+ else if (strcmp(pOptName, METADATAID3VERSION_OPTION_NAME) == 0)
+ {
+ m_ulMetaDataID3Version = 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;
@@ -2055,60 +2060,69 @@
}
if (SUCCEEDED(retVal))
{
if (m_uOptionFlags & UTF16OUTPUT_OPTION)
{
retVal = pNewProps->SetPropertyULONG32("UTF16Output", 1);
}
}
if (SUCCEEDED(retVal))
{
if (m_ulMetaDataFlavor != 0)
{
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_ulMetaDataID3Version != 0)
+ {
+ retVal = pNewProps->SetPropertyULONG32(METADATAID3VERSION_OPTION_NAME,
+ m_ulMetaDataID3Version);
+ }
+ }
+
+ 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.46
diff -d -H -w -U30 -r1.46 ffdriver.h
--- pub/ffdriver.h 9 Nov 2009 19:45:16 -0000 1.46
+++ pub/ffdriver.h 6 Jan 2010 17:15:50 -0000
@@ -52,60 +52,61 @@
#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 METADATAID3VERSION_OPTION_NAME "MetaDataID3Version"
#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"
@@ -134,60 +135,65 @@
#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
+// MetaDataID3Version values
+#define METADATAID3VERSION_230 0x00020300
+#define METADATAID3VERSION_240 0x00020400
+#define METADATAID3VERSION_NONE 0x01000000
+
/****************************************************************************
* 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:
*
@@ -629,60 +635,61 @@
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;
+ ULONG32 m_ulMetaDataID3Version;
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;