[Helix-client-dev] CR/CN: Metadata atom order modification: udta-box comes before ID3-tag related meta-box [GMPMetaEditor branch]
Petar Basic <[email protected]> Fri, 15 Jan 2010 17:43:11 +0100
| Newsgroups | gmane.comp.multimedia.helix.devel |
|---|---|
| Message-ID | <[email protected]> |
Modified by: pbasic at real.com Date: 2010/01/15 Project: GMPMetaEditor (meta3gp.exe) Synopsis: Metadata atom order modification: udta-box comes before ID3-tag related meta-box [GMPMetaEditor branch] Details: Recognition of file type and metadata display work incorrectly with particular metadata atom order on some HTC handsets. 'meta' atom which contains ID3 tag comes before 'udta' atom which contains 3GPP assets in files produced by meta3gp, and the opposite is true for files produced by CodingTech. HTC code obviously gets confused while parsing 'meta' atom or ID3 tag within it. With CodingTech files, HTC first reads textual metadata from 'udta' atom then proceeds parsing ID3 and fails. With meta3gp files, HTC finds ID3 first and fails before reading textual metadata in 'udta' atom. This is why the files produced by CodingTech work better to some extent if CoverArt is injected (i.e. ID3 tag stored in the file). To improve compatibility with HTC handsets, MP4 filewriter has been changed to produce metadata atom order in which 'udta' atom always comes before ID3-tag related 'meta' atom. This does not influence the position of other atoms in the file. Files Modified: datatype/mp4/filewriter/mp4sm.cpp datatype/mp4/filewriter/mp4sm.h Platforms and Profiles Affected: All Image Size and Heap Use impact: None Platforms and Profiles Build Verified: system id: win32-i386-vc7, sunos-5.10-sparc-studio11 profile: helix-client-all-defines Platforms and Profiles Functionality Verified: x86 Windows XP SP2 Sparc SunOS 5.10 Branch: GMPMetaEditor 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_mp4_filewriter.diff
(application/octet-stream, 10.2 KB)
Index: mp4sm.cpp
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.cpp,v
retrieving revision 1.24.2.1
diff -d -H -w -U30 -r1.24.2.1 mp4sm.cpp
--- mp4sm.cpp 11 Jan 2010 17:43:16 -0000 1.24.2.1
+++ mp4sm.cpp 15 Jan 2010 16:10:14 -0000
@@ -1682,86 +1682,101 @@
retVal = HXR_OK;
// Call out to build the trak tree
BuildTrack( (UINT16)i, pTrak );
pMoov->AddChild( pTrak );
if (ulTrackType == MP4_BUILD_ATOMID('v','i','d','e'))
{
bHasVideo = TRUE;
}
}
}
}
}
for (iStream = 0; iStream < m_ulStreamCount && SUCCEEDED(retVal); ++iStream)
{
HintInfo *hi = m_pStreamInfo[iStream].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);
}
+
+ CMP4Atom_meta* pMeta = 0;
+
if (m_bRequestedOutputMetaFlavor3GPP || (m_eMetaFlavor == META_3GPP)
|| m_bFileHeaderCarriesUITSData)
{
// Build 3GP meta-data
- Build3GPPMetaData(pUdta, pMoov);
+ Build3GPPMetaData(pUdta, pMoov, &pMeta);
}
+
// 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);
+
+ // Add meta box as a child of the moov box.
+ // XXXPB: Add 'meta' after the 'udta' to improve
+ // compatibility of output file with some handsets (HTC).
+ if(pMeta)
+ {
+ pMoov->AddChild(pMeta);
+ }
}
}
// 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 );
}
}
}
if( SUCCEEDED( retVal ) )
{
// Set the duration in our new atoms to the reported one
UpdateDuration( m_ulReportedDuration );
// Set the base offsets for our atoms.
// In the default case, where a duration is available, all the atom
// data is written in a padding block preceding the actual content.
// This lets us set a write offset for the root atom at 0 and be done with
@@ -4461,79 +4476,84 @@
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 CMP4StreamMixer::Build3GPPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov, CMP4Atom_meta** ppMeta )
+{
+ if(!ppMeta || *ppMeta)
{
+ return HXR_INVALID_PARAMETER;
+ }
+
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]
if(SUCCEEDED(retVal))
{
- CMP4Atom_meta* pMeta = NULL;
- retVal = Build3GPPMetaDataID32(m_pFileHeader, &pMeta, TRUE);
+ retVal = Build3GPPMetaDataID32(m_pFileHeader, ppMeta, TRUE);
- if(SUCCEEDED(retVal) && pMeta)
+ if(FAILED(retVal) && *ppMeta)
{
- retVal = pMoov->AddChild(pMeta);
+ delete *ppMeta;
+ *ppMeta = 0;
}
}
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());
}
Index: mp4sm.h
===================================================================
RCS file: /cvsroot/datatype/mp4/filewriter/mp4sm.h,v
retrieving revision 1.16
diff -d -H -w -U30 -r1.16 mp4sm.h
--- mp4sm.h 6 Jan 2010 17:40:10 -0000 1.16
+++ mp4sm.h 15 Jan 2010 16:10:15 -0000
@@ -189,61 +189,61 @@
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 Build3GPPMetaDataStandardSet( CMP4Atom* pUdta, CMP4Atom* pMoov );
- HX_RESULT Build3GPPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov );
+ HX_RESULT Build3GPPMetaData( CMP4Atom* pUdta, CMP4Atom* pMoov, CMP4Atom_meta** ppMeta );
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