[datatype-dev] CR:Changes to support rmra, rmda, rdrf atom in mov file
Varun Kathuria vkathuria at real.comHi Eric, Please find the attached updated diff. & see replies inline. Thanks Varun Kathuria ----- Original Message ----- From: "Eric Hyche" <ehyche at real.com> To: "'Varun Kathuria'" <vkathuria at real.com>; <datatype-dev at helixcommunity.org> Sent: Thursday, March 26, 2009 8:41 PM Subject: RE: [datatype-dev] CR:Changes to support rmra, rmda,rdrf atom in mov file > Varun, > > Here are my comments: > > STDMETHODIMP CQTFileFormat::GetPacket(UINT16 unStreamNumber) > { > + if(m_pRedirectFFObject) > + { > + return m_pRedirectFFObject->GetPacket(unStreamNumber); > + } > + > > You should set the state, like this: > > STDMETHODIMP CQTFileFormat::GetPacket(UINT16 unStreamNumber) > { > + if(m_pRedirectFFObject) > + { > + m_state = QTFF_GetPacket; > + return m_pRedirectFFObject->GetPacket(unStreamNumber); > + } > + > > STDMETHODIMP CQTFileFormat::Seek(ULONG32 ulOffset) > { > + if(m_pRedirectFFObject) > + { > + return m_pRedirectFFObject->Seek(ulOffset); > + } > + > > Same thing here - set the state to QTFF_SeekPending > before calling m_pRedirectFFObject->Seek(ulOffset). > > STDMETHODIMP CQTFileFormat::SeekDone(HX_RESULT status) > { > + if(m_State == QTFF_Atomize) > + { > + return m_pFFResponse->SeekDone(status); > + } > > This is not correct. You are assuming here that > the outer FF always stays in the state QTFF_Atomize. > It should not. The state of the outer FF should be > updating to the correct states even though it is proxying > calls to the inner FF. The states should be: > > - Set to QTFF_Offline upon creation of CQTFileFormat until > InitFileFormat is called. > - Set to QTFF_Init upon call to InitFileFormat and then > set to QTFF_Ready when IHXFormatResponse::InitDone() is called. > - Set to QTFF_Atomize when GetFileHeader() is called and > then set back to QTFF_Ready() right before FileHeaderReady() is called. > - Set to QTFF_GetPacket when GetPacket() is called and > returned to QTFF_Ready right before PacketReady() is called. > - Set the QTFF_SeekPending when Seek() is called > and then reset to QTFF_Ready right before SeekDone() is called. > > So the code above should be: > > STDMETHODIMP CQTFileFormat::SeekDone(HX_RESULT status) > { > + if (m_pRedirectFFObject && m_State == QTFF_SeekPending) > + { > + m_State = QTFF_Ready; > + return m_pFFResponse->SeekDone(status); > + } > > > > } > - > + HX_RELEASE(m_pRedirectFFObject); > m_TrackManager.CloseTracks(); > You need to call Close() on the m_pRedirectFFObject > before releasing it. > > > + status = > m_MovieInfo.Init(pRootAtom->FindPresentChild(QT_moov), &m_TrackManager); > Don't think you need to call pRootAtom->FindPresentChild(QT_moov) > again here. You already have the moov atom in pMoovAtom > from above. Varun: There is no need of calling pRootAtom->FindPresentChild(QT_moov) again.Replaced it with pMoovAtom > + if(purl.IsRelativeURL()) > + { > + //If the URL is relative, then this code > changes it to absolute URL. > + const char *poriginal_url = NULL; > + m_pRequest->GetURL(poriginal_url); > + const char *prel = > strrchr(poriginal_url,'/'); > + szURL = poriginal_url; > + szURL = szURL.Left(prel-poriginal_url+1); > + szURL += pszReferenceURL; > + } > > Has this code been tested? Have you found a > .mov with a relative URL? Varun: The code for URL is tested for both relative & absolute URL. > + retVal = > CreateNewFileFormatObject(szURL.GetBuffer(0)); > > Why szURL.GetBuffer()? Don't you just need the > const char* that this CHXString represents? If so, > then you should just cast the CHXString to const char*, like this: > > + retVal = CreateNewFileFormatObject((const > char*) szURL); > > > + status = > m_MovieInfo.Init(pRootAtom->FindPresentChild(QT_moov), &m_TrackManager); > + if (SUCCEEDED(status)) > + { > + retVal = HXR_FAIL; > + // Get the Reference Url > + const char* pszReferenceURL = NULL; > + pszReferenceURL = m_MovieInfo.GetRefURL(); > + if(pszReferenceURL) > + { > + CHXString szURL=""; > + CHXURL purl(pszReferenceURL,m_pContext); > + if(purl.IsRelativeURL()) > + { > + //If the URL is relative, then this code > changes it to absolute URL. > + const char *poriginal_url = NULL; > + m_pRequest->GetURL(poriginal_url); > + const char *prel = > strrchr(poriginal_url,'/'); > + szURL = poriginal_url; > + szURL = szURL.Left(prel-poriginal_url+1); > + szURL += pszReferenceURL; > + } > + else > + { > + szURL = pszReferenceURL; > + } > + retVal = > CreateNewFileFormatObject(szURL.GetBuffer(0)); > + } > + } > + return retVal; > > Make sure you handle the failure case correctly. Right now > if we fail to create the file format for some reason, > then the outerFF will hang, since it will just return > a failure code in AtomReady(), but it will never make > a call to FileHeaderReady(). This will hang the HXFileSource > which is waiting on the FileHeaderReady() call. Varun: For handling failure case correctly. I have replaced + return retVal with + if(SUCCEDDED(retVal)) + { + return retVal + } Now if we fail to create fileformat due to some reason then it will not return. It will call MakeFileHeader() in AtomReady() which will call FileHeaderReady() with in itself & it will not hang filesource. > STDMETHOD(GetSupportedPacketFormats) (THIS_ > REF(const char**) pFormats); > > STDMETHOD(SetPacketFormat) (THIS_ > const char* pFormat); > > STDMETHOD(ConvertFileOffsetToDur) (THIS_ > UINT32 /*IN*/ ulLastReadOffset, > UINT32 /*IN*/ ulCompleteFileSize, > REF(UINT32) /*OUT*/ ulREFDuration); > > STDMETHOD(GetFileDuration) (THIS_ > UINT32 /*IN*/ ulCompleteFileSize, > REF(UINT32) /*OUT*/ ulREFDur); > > These methods also need to be redirected to the inner FF. > + pRequest->SetURL((const char*)purl); // Set the reference URL > + pRequestHandler->SetRequest(pRequest); > > You probably also need to take the request headers > from the request passed to the outer FF and copy > them into this request that is passed to the inner FF. Varun: I have taken request headers from outer FF & passes them into inner file format request. > + if (FAILED(pPlugin->InitPlugin((IUnknown*) (IHXStreamSource*)this))) > > This looks like a cut-n-paste error. CQTFileFormat does not implement > IHXStreamSource, so this is not correct. The outer FF should > just pass along the context it received in InitPlugin(). So this > should just be: > > + if (FAILED(pPlugin->InitPlugin(m_pContext))) > > + theErr = > m_pRedirectFFObject->InitFileFormat(pRequest,this,pFileObject); > > You need to cast the "this" pointer to (IHXFormatResponse*) here. > > + STDMETHODIMP CQTFileFormat::PacketReady(THIS_ > + HX_RESULT status, > + IHXPacket* pPacket) > + { > + return m_pFFResponse->PacketReady(status,pPacket); > + } > + > + STDMETHODIMP CQTFileFormat::FileHeaderReady (THIS_ > + HX_RESULT status, > + IHXValues* pHeader) > + { > + return m_pFFResponse->FileHeaderReady(status,pHeader); > + } > + > + STDMETHODIMP CQTFileFormat::StreamHeaderReady (THIS_ > + HX_RESULT status, > + IHXValues* pHeader) > + { > + return m_pFFResponse->StreamHeaderReady(status,pHeader); > + } > + > + STDMETHODIMP CQTFileFormat::StreamDone(THIS_ > + UINT16 unStreamNumber) > + { > + return m_pFFResponse->StreamDone(unStreamNumber); > + } > + > > In all of these the outer FF needs to reset m_state back to > the appropriate state before making the IHXFormatResponse call. > > + * IHXFormatResponse methods > + */ > + > + STDMETHOD(PacketReady) (THIS_ > + HX_RESULT status, > + IHXPacket* pPacket); > + > + STDMETHOD(FileHeaderReady) (THIS_ > + HX_RESULT status, > + IHXValues* pHeader) ; > + > + STDMETHOD(StreamHeaderReady) (THIS_ > + HX_RESULT status, > + IHXValues* pHeader) ; > + > + STDMETHOD(StreamDone) (THIS_ > + UINT16 unStreamNumber) ; > + > + /* > > Please include InitDone() and SeekDone() but comment > them out and include a comment that these methods > are duplicated in IHXFileResponse, which explains > why they would be commented out. > > + HX_RESULT CreateNewFileFormatObject(char* purl); > > This should be const char* instead of char*. > > > ======================================= > Eric Hyche (ehyche at real.com) > Principal Engineer > RealNetworks, Inc. > > -------------- next part -------------- Index: qtffplin.cpp =================================================================== RCS file: /cvsroot/datatype/mp4/fileformat/qtffplin.cpp,v retrieving revision 1.60.2.5 diff -u -r1.60.2.5 qtffplin.cpp --- qtffplin.cpp 31 Dec 2008 11:22:02 -0000 1.60.2.5 +++ qtffplin.cpp 27 Mar 2009 08:35:54 -0000 @@ -89,6 +89,7 @@ #include "qtoffsetmpr.h" #include "metainfokeys.h" +#include "hxurl.h" /**************************************************************************** * Constants @@ -185,6 +186,7 @@ , m_pOffsetToTimeMapper(NULL) , m_pFileObject(NULL) , m_ulNextPacketTime(0) + , m_pRedirectFFObject(NULL) { g_nRefCount_qtff++; } @@ -1651,6 +1653,12 @@ */ STDMETHODIMP CQTFileFormat::GetPacket(UINT16 unStreamNumber) { + if(m_pRedirectFFObject) + { + m_State = QTFF_GetPacket; + return m_pRedirectFFObject->GetPacket(unStreamNumber); + } + HX_RESULT retVal; if (unStreamNumber < m_TrackManager.GetNumStreams()) @@ -1783,6 +1791,12 @@ */ STDMETHODIMP CQTFileFormat::Seek(ULONG32 ulOffset) { + if(m_pRedirectFFObject && m_State == QTFF_Ready) + { + m_State = QTFF_SeekPending; + return m_pRedirectFFObject->Seek(ulOffset); + } + UINT16 uStreamNum; HX_RESULT retVal = HXR_OK; @@ -1841,6 +1855,11 @@ */ STDMETHODIMP CQTFileFormat::SeekDone(HX_RESULT status) { + if(m_pRedirectFFObject && m_State == QTFF_SeekPending) + { + m_State = QTFF_Ready; + return m_pFFResponse->SeekDone(status); + } return HXR_UNEXPECTED; } @@ -1885,7 +1904,11 @@ m_pFileObject->Close(); HX_RELEASE(m_pFileObject); } - + if(m_pRedirectFFObject) + { + m_pRedirectFFObject->Close(); + HX_RELEASE(m_pRedirectFFObject); + } m_TrackManager.CloseTracks(); return HXR_OK; @@ -1910,6 +1933,12 @@ { HX_RESULT retVal = HXR_OK; + if(m_pRedirectFFObject && m_State == QTFF_Init) + { + m_State = QTFF_Atomize; + return m_pRedirectFFObject->GetFileHeader(); + } + switch (m_State) { case QTFF_Init: @@ -2020,7 +2049,7 @@ m_pAtomizer->Close(); m_pAtomizer->Release(); m_pAtomizer = NULL; - } + } } else { @@ -2057,9 +2086,54 @@ } } #endif // QTCONFIG_PACKETIZER_FACTORY - + if (SUCCEEDED(status)) { + CQT_moov_Atom *pMoovAtom = NULL; + pMoovAtom = (CQT_moov_Atom *)pRootAtom->FindPresentChild(QT_moov); + if(pMoovAtom) + { + HX_RESULT retVal = HXR_OK; + CQT_mvhd_Atom *pMovieHeaderAtom = NULL; + pMovieHeaderAtom = (CQT_mvhd_Atom*)pMoovAtom->FindPresentChild(QT_mvhd); + CQT_rmra_Atom *pRmraHeaderAtom = NULL; + pRmraHeaderAtom = (CQT_rmra_Atom*)pMoovAtom->FindPresentChild(QT_rmra); + if(!pMovieHeaderAtom && pRmraHeaderAtom) + { + status = m_MovieInfo.Init(pMoovAtom, &m_TrackManager); + if (SUCCEEDED(status)) + { + status = HXR_FAIL; + // Get the Reference Url + const char* pszReferenceURL = NULL; + pszReferenceURL = m_MovieInfo.GetRefURL(); + if(pszReferenceURL) + { + CHXString szURL=""; + CHXURL purl(pszReferenceURL,m_pContext); + if(purl.IsRelativeURL()) + { + //If the URL is relative, then this code changes it to absolute URL. + const char *poriginal_url = NULL; + m_pRequest->GetURL(poriginal_url); + const char *prel = strrchr(poriginal_url,'/'); + szURL = poriginal_url; + szURL = szURL.Left(prel-poriginal_url+1); + szURL += pszReferenceURL; + } + else + { + szURL = pszReferenceURL; + } + status = CreateNewFileFormatObject((const char*)szURL); + } + } + if(SUCCEEDED(status)) + { + return status; + } + } + } HXBOOL bIgnoreHintTracks = FALSE; do { @@ -2169,6 +2243,17 @@ STDMETHODIMP CQTFileFormat::Subscribe(UINT16 uStreamNum, UINT16 uRuleNumber) { + if(m_pRedirectFFObject) + { + IHXASMSource* pASMSource=NULL; + HX_RESULT retVal = HXR_FAIL; + if(SUCCEEDED(m_pRedirectFFObject->QueryInterface(IID_IHXASMSource,(void **)&pASMSource))) + { + retVal = pASMSource->Subscribe(uStreamNum,uRuleNumber); + HX_RELEASE(pASMSource); + } + return retVal; + } return m_TrackManager.Subscribe(uStreamNum, uRuleNumber); } @@ -2178,6 +2263,17 @@ STDMETHODIMP CQTFileFormat::Unsubscribe(UINT16 uStreamNum, UINT16 uRuleNumber) { + if(m_pRedirectFFObject) + { + IHXASMSource* pASMSource=NULL; + HX_RESULT retVal = HXR_FAIL; + if(SUCCEEDED(m_pRedirectFFObject->QueryInterface(IID_IHXASMSource,(void **)&pASMSource))) + { + retVal = pASMSource->Unsubscribe(uStreamNum,uRuleNumber); + HX_RELEASE(pASMSource); + } + return retVal; + } return m_TrackManager.Unsubscribe(uStreamNum, uRuleNumber); } @@ -2193,6 +2289,17 @@ REF(const char**) /*OUT*/ pPacketFormats ) { + if(m_pRedirectFFObject) + { + HX_RESULT retVal = HXR_FAIL; + IHXPacketFormat* pPacketFormat = 0; + if(SUCCEEDED(m_pRedirectFFObject->QueryInterface (IID_IHXPacketFormat,(void**)&pPacketFormat))) + { + retVal = pPacketFormat->GetSupportedPacketFormats(pPacketFormats); + HX_RELEASE(pPacketFormat); + } + return retVal; + } pPacketFormats = (const char**) zm_pPacketFormats; return HXR_OK; } @@ -2208,6 +2315,17 @@ const char* pPacketFormat ) { + if(m_pRedirectFFObject) + { + HX_RESULT retVal = HXR_FAIL; + IHXPacketFormat* pPktFormat = 0; + if(SUCCEEDED(m_pRedirectFFObject->QueryInterface(IID_IHXPacketFormat,(void**)&pPktFormat))) + { + retVal = pPktFormat->SetPacketFormat(pPacketFormat); + HX_RELEASE(pPktFormat); + } + return retVal; + } if (strcasecmp(pPacketFormat, "rtp") == 0) { m_ulPacketFormat = QTFF_RTP_FORMAT; @@ -2256,6 +2374,17 @@ UINT32 /*IN*/ ulCompleteFileSize, REF(UINT32) /*OUT*/ ulREFDur) { + if(m_pRedirectFFObject) + { + HX_RESULT retVal = HXR_FAIL; + IHXMediaBytesToMediaDur* pMediaBytesToMediaDur = 0; + if(SUCCEEDED(m_pRedirectFFObject->QueryInterface (IID_IHXMediaBytesToMediaDur,(void**)&pMediaBytesToMediaDur))) + { + retVal = pMediaBytesToMediaDur->ConvertFileOffsetToDur(ulLastReadOffset,ulCompleteFileSize,ulREFDur); + HX_RELEASE(pMediaBytesToMediaDur); + } + return retVal; + } HX_RESULT retVal = HXR_OK; UINT32 ulDurOut = HX_PROGDOWNLD_UNKNOWN_DURATION; @@ -2339,6 +2468,17 @@ CQTFileFormat::GetFileDuration(UINT32 /*IN*/ ulCompleteFileSize, REF(UINT32) /*OUT*/ ulREFDur) { + if(m_pRedirectFFObject) + { + HX_RESULT retVal = HXR_FAIL; + IHXMediaBytesToMediaDur* pMediaBytesToMediaDur = 0; + if(SUCCEEDED(m_pRedirectFFObject->QueryInterface (IID_IHXMediaBytesToMediaDur,(void**)&pMediaBytesToMediaDur))) + { + retVal = pMediaBytesToMediaDur->GetFileDuration(ulCompleteFileSize,ulREFDur); + HX_RELEASE(pMediaBytesToMediaDur); + } + return retVal; + } HX_RESULT retVal = HXR_OK; UINT32 ulDuration = HX_PROGDOWNLD_UNKNOWN_DURATION; @@ -2905,6 +3045,7 @@ { { GET_IIDHANDLE(IID_IUnknown), (IUnknown*) (IHXPlugin*) this}, { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*) this}, + { GET_IIDHANDLE(IID_IHXFormatResponse), (IHXFormatResponse*) this}, { GET_IIDHANDLE(IID_IHXFileFormatObject), (IHXFileFormatObject*) this}, { GET_IIDHANDLE(IID_IHXAtomizerResponse), (IHXAtomizerResponse*) this}, { GET_IIDHANDLE(IID_IHXAtomizationCommander), (IHXAtomizationCommander*) this}, @@ -3003,6 +3144,11 @@ */ STDMETHODIMP CQTFileFormat::GetStreamHeader(UINT16 unStreamNumber) { + if(m_pRedirectFFObject && m_State == QTFF_Ready) + { + return m_pRedirectFFObject->GetStreamHeader(unStreamNumber); + } + HX_RESULT retVal; IHXValues* pHeader; @@ -3015,3 +3161,186 @@ return retVal; } +HX_RESULT CQTFileFormat::CreateNewFileFormatObject(const char* purl) +{ + HX_RESULT theErr = HXR_FAIL; + char* pExtension = "mov"; //rmra can only contain QuickTime movie reference + IHXPluginHandler3* pPlugin2Handler3 = NULL; + IHXPlugin* pPlugin = NULL; + IUnknown* pCurrentFileFormatUnk = NULL; + IHXPluginSearchEnumerator* pFileFormatEnumerator = NULL; + IHXFileObject* pFileObject = NULL; + IHXRequest* pRequest = NULL; + IUnknown* pUnknown = NULL; + IUnknown* pObject = NULL; + IHXFileSystemObject* pFSObject = NULL; + IHXPlugin2Handler* pPlugin2Handler = NULL; + IHXPlugin *pHXPlugin = NULL; + IHXRequestHandler* pRequestHandler=NULL; + + const char* pProtocolEnd = HXFindChar(purl,':'); + if (!pProtocolEnd) + { + return HXR_UNEXPECTED; + } + + int nLength = pProtocolEnd - purl; + CHXString strProtocol(purl,nLength); + + if (FAILED(m_pContext->QueryInterface(IID_IHXPlugin2Handler, (void**)&pPlugin2Handler))) + { + goto exit; + } + + if (FAILED( pPlugin2Handler->FindPluginUsingStrings(PLUGIN_CLASS, PLUGIN_FILESYSTEM_TYPE, + PLUGIN_FILESYSTEMPROTOCOL, (char*)(const char*)strProtocol, NULL, NULL, pUnknown))) + { + goto exit; + } + + if(FAILED(pUnknown->QueryInterface(IID_IHXFileSystemObject, (void**) &pFSObject))) + { + goto exit; + } + + if (FAILED (pFSObject->QueryInterface(IID_IHXPlugin,(void**)&pHXPlugin))) + { + goto exit; + } + + if (FAILED(pHXPlugin->InitPlugin(m_pContext))) + { + goto exit; + } + + if (FAILED(pFSObject->CreateFile(&pObject))) + { + goto exit; + } + + if (FAILED(pObject->QueryInterface(IID_IHXFileObject, (void**)&pFileObject))) + { + goto exit; + } + + if (FAILED(pObject->QueryInterface(IID_IHXRequestHandler, (void**)&pRequestHandler))) + { + goto exit; + } + + if(m_pClassFactory && (HXR_OK !=m_pClassFactory->CreateInstance(CLSID_IHXRequest, (void**) &pRequest))) + { + goto exit; + } + + if (pRequest) + { + IHXValues* pRequestHeaders = NULL; + pRequest->SetURL((const char*)purl); // Set the reference URL + if (SUCCEEDED(m_pRequest->GetRequestHeaders(pRequestHeaders)) && pRequestHeaders) + { + pRequest->SetRequestHeaders(pRequestHeaders); + pRequestHeaders->Release(); + } + pRequestHandler->SetRequest(pRequest); + } + + if(m_pContext && (HXR_OK != m_pContext->QueryInterface(IID_IHXPluginHandler3, (void**) &pPlugin2Handler3))) + { + goto exit; + } + + if (FAILED(pPlugin2Handler3->FindGroupOfPluginsUsingStrings(PLUGIN_CLASS, PLUGIN_FILEFORMAT_TYPE, + PLUGIN_FILEEXTENSIONS, pExtension, 0 ,0, pFileFormatEnumerator))) + { + goto exit; + } + + if (pFileFormatEnumerator) + { + pFileFormatEnumerator->GetNextPlugin(pCurrentFileFormatUnk, NULL); + HX_ASSERT(pCurrentFileFormatUnk != NULL); + } + + if (FAILED( pCurrentFileFormatUnk->QueryInterface(IID_IHXFileFormatObject, (void**) &m_pRedirectFFObject))) + { + goto exit; + } + m_State = QTFF_Offline; + if (FAILED(m_pRedirectFFObject->QueryInterface(IID_IHXPlugin,(void**)&pPlugin))) + { + goto exit; + } + + if (FAILED(pPlugin->InitPlugin(m_pContext))) + { + goto exit; + } + m_State = QTFF_Init; + theErr = m_pRedirectFFObject->InitFileFormat(pRequest,(IHXFormatResponse*)this,pFileObject); + +exit: + HX_RELEASE(pPlugin2Handler); + HX_RELEASE(pUnknown); + HX_RELEASE(pFSObject); + HX_RELEASE(pHXPlugin); + HX_RELEASE(pObject); + HX_RELEASE(pFileObject); + HX_RELEASE(pRequestHandler); + HX_RELEASE(pRequest); + HX_RELEASE(pPlugin2Handler3); + HX_RELEASE(pFileFormatEnumerator); + HX_RELEASE(pCurrentFileFormatUnk); + HX_RELEASE(pPlugin); + return theErr; +} + + STDMETHODIMP CQTFileFormat::PacketReady(THIS_ + HX_RESULT status, + IHXPacket* pPacket) + { + HX_RESULT retVal = HXR_FAIL; + if(m_pRedirectFFObject) + { + m_State = QTFF_Ready; + retVal = m_pFFResponse->PacketReady(status,pPacket); + } + return retVal; + } + + STDMETHODIMP CQTFileFormat::FileHeaderReady (THIS_ + HX_RESULT status, + IHXValues* pHeader) + { + HX_RESULT retVal = HXR_FAIL; + if(m_pRedirectFFObject && m_State==QTFF_Atomize) + { + m_State = QTFF_Ready; + retVal = m_pFFResponse->FileHeaderReady(status,pHeader); + } + return retVal; + } + + STDMETHODIMP CQTFileFormat::StreamHeaderReady (THIS_ + HX_RESULT status, + IHXValues* pHeader) + { + HX_RESULT retVal = HXR_FAIL; + if(m_pRedirectFFObject && m_State == QTFF_Ready) + { + retVal = m_pFFResponse->StreamHeaderReady(status,pHeader); + } + return retVal; + } + + STDMETHODIMP CQTFileFormat::StreamDone(THIS_ + UINT16 unStreamNumber) + { + HX_RESULT retVal = HXR_FAIL; + if(m_pRedirectFFObject) + { + retVal = m_pFFResponse->StreamDone(unStreamNumber); + } + return retVal; + } + Index: pub/qtffplin.h =================================================================== RCS file: /cvsroot/datatype/mp4/fileformat/pub/qtffplin.h,v retrieving revision 1.17.8.2 diff -u -r1.17.8.2 qtffplin.h --- pub/qtffplin.h 28 Apr 2008 17:30:19 -0000 1.17.8.2 +++ pub/qtffplin.h 27 Mar 2009 08:35:54 -0000 @@ -84,6 +84,7 @@ */ class CQTFileFormat : public IHXPlugin, public IHXFileFormatObject, + public IHXFormatResponse, public IHXFileResponse, public IHXAtomizationCommander, public IHXAtomizerResponse, @@ -171,6 +172,36 @@ HX_RESULT status); /* + * IHXFormatResponse methods + */ + + STDMETHOD(PacketReady) (THIS_ + HX_RESULT status, + IHXPacket* pPacket); + + STDMETHOD(FileHeaderReady) (THIS_ + HX_RESULT status, + IHXValues* pHeader) ; + + STDMETHOD(StreamHeaderReady) (THIS_ + HX_RESULT status, + IHXValues* pHeader) ; + + STDMETHOD(StreamDone) (THIS_ + UINT16 unStreamNumber) ; + + /* + These methods are duplicated in IHXFileResponse. + + STDMETHOD(InitDone) (THIS_ + HX_RESULT status); + + STDMETHOD(SeekDone) (THIS_ + HX_RESULT status); + + */ + + /* * IHXAtomizationCommander */ STDMETHOD_(QTAtomizerCmd,GetAtomCommand) (THIS_ @@ -309,7 +340,7 @@ HX_RESULT GetResourceErrorString(UINT32 ulErrorID, CHXString& rErrorStr); void WarnIfNotHinted(HX_RESULT status, HXBOOL bIgnoreHintTracks); - + HX_RESULT CreateNewFileFormatObject(const char* purl); IHXScheduler* m_pScheduler; IHXErrorMessages* m_pErrorMessages; @@ -365,6 +396,7 @@ CQTOffsetToTimeMapper* m_pOffsetToTimeMapper; IHXFileObject* m_pFileObject; UINT32 m_ulNextPacketTime; // in milliseconds + IHXFileFormatObject* m_pRedirectFFObject; };