qtffplin.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:58k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- /****************************************************************************
- * Defines
- */
- #define NO_STREAM_SET 0xFFFF
- #define FSWCHR_MAX_CHILD_COUNT 20
- /****************************************************************************
- * Includes
- */
- #include "qtffplin.ver"
- #include "hxtypes.h"
- #include "hxcom.h"
- #include "hxstrutl.h"
- #include "hxcomm.h"
- #include "ihxpckts.h"
- #include "hxfiles.h"
- #include "hxformt.h"
- #include "hxplugn.h"
- #include "hxpends.h"
- #include "hxengin.h"
- #include "hxerror.h"
- #include "hxupgrd.h"
- #include "hxmon.h"
- #include "hxbrdcst.h"
- #include "hxcore.h"
- #include "hxprefs.h"
- #include "defslice.h"
- #include "qtres.h"
- #include "hxsdesc.h"
- #include "hxstring.h"
- #include "qtffplin.h"
- #include "netbyte.h"
- #include "hxver.h"
- #include "hxxres.h"
- #include "hxxrsmg.h"
- #include "dbcs.h"
- #include "sdpchunk.h"
- #include "sdppyldinfo.h"
- #include "qtffrefcounter.h"
- #include "qttrack.h"
- #include "qtpktasm.h"
- /****************************************************************************
- * Constants
- */
- #define QTFF_AU_PREFIX "FileFormat/"
- #define QTFF_AU_PREFIX_SIZE (sizeof(QTFF_AU_PREFIX) - 1)
- #define MAX_EXTENSION_SIZE 256
- #define QTBUFFERFRAGMENT_POOL_SIZE 50
- #define QTBUFFERFRAGMENT_INITIAL_POOL_SIZE 5
- const char* const CQTFileFormat::zm_pDescription = "RealNetworks Mpeg4 File Format Plugin";
- const char* const CQTFileFormat::zm_pCopyright = HXVER_COPYRIGHT;
- const char* const CQTFileFormat::zm_pMoreInfoURL = HXVER_MOREINFO;
- #define EXT_3GP "3gp"
- #define EXT_3G2 "3g2"
- #define EXT_MP4 "mp4"
- #define EXT_M4A "m4a"
- #define EXT_MOV "mov", "qt"
- #define ONM_3GP "3GPP-MP4 Files (*.3gp, *.3g2)"
- #define ONM_MP4 "MP4 Files (*.mp4)"
- #define ONM_MOV "QuickTime Files (*.mov, *.qt)"
- const char* const CQTFileFormat::zm_pFileMimeTypes[] = {"application/x-pn-quicktime-stream", "audio/3gpp", "video/3gpp", NULL};
- const char* const CQTFileFormat::zm_pFileExtensions[] = {EXT_MOV, EXT_MP4, EXT_3GP, EXT_3G2, EXT_M4A, NULL};
- const char* const CQTFileFormat::zm_pFileOpenNames[] = {ONM_MOV, ONM_MP4, ONM_3GP, NULL};
- const char* const CQTFileFormat::zm_pPacketFormats[] = {"rtp", "rdt", NULL};
- #define WIDTH_METANAME "Width"
- #define HEIGHT_METANAME "Height"
- /****************************************************************************
- * Globals
- */
- g_base_nRefCount_qtff_TypeModifier INT32 g_base_nRefCount_qtff = 0;
- /****************************************************************************
- * Constructor/Destructor
- */
- CQTFileFormat::CQTFileFormat()
- : m_lRefCount(0)
- , m_pContext(NULL)
- , m_pFFResponse(NULL)
- , m_pClassFactory(NULL)
- , m_pScheduler(NULL)
- , m_pRequest(NULL)
- , m_pFileSwitcher(NULL)
- , m_pAtomizer(NULL)
- , m_pPacketAssembler(NULL)
- , m_State(QTFF_Offline)
- , m_pPacketCache(NULL)
- , m_uNextPacketStreamNum(NO_STREAM_SET)
- , m_ulPendingSeekTime(0)
- , m_pErrorMessages(NULL)
- , m_bQTLicensed(FALSE)
- , m_bMP4Licensed(FALSE)
- , m_uFormatFlavor(MAX_QTFORMAT_FLAVOR)
- , m_bViewSourceRequest(FALSE)
- #ifdef QTCONFIG_BFRAG_FACTORY
- , m_pBufferFragmentFactory(NULL)
- #endif // QTCONFIG_BFRAG_FACTORY
- , m_ulStreamMetaInfoMask(META_INFO_NONE)
- {
- g_nRefCount_qtff++;
- }
- CQTFileFormat::~CQTFileFormat()
- {
- Close();
- g_nRefCount_qtff--;
- }
- /************************************************************************
- * IHXPlugin methods
- */
- /************************************************************************
- * IHXPlugin::InitPlugin
- * Purpose:
- * Initializes the plugin for use. This interface must always be
- * called before any other method is called. This is primarily needed
- * so that the plugin can have access to the context for creation of
- * IHXBuffers and IMalloc.
- */
- STDMETHODIMP CQTFileFormat::InitPlugin(IUnknown* /*IN*/ pContext)
- {
- HX_RESULT retVal = HXR_OK;
- if (pContext)
- {
- m_pContext = pContext;
- m_pContext->AddRef();
- }
- else
- {
- retVal = HXR_INVALID_PARAMETER;
- }
- /*
- * Check for license
- */
- if (SUCCEEDED(retVal))
- {
- retVal = CheckLicense();
- }
- if (SUCCEEDED(retVal))
- {
- HX_ASSERT(!m_pErrorMessages);
- pContext->QueryInterface(IID_IHXErrorMessages,
- (void**) &m_pErrorMessages);
- retVal = pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pClassFactory);
- }
- if (SUCCEEDED(retVal))
- {
- retVal = pContext->QueryInterface(IID_IHXScheduler,
- (void**)&m_pScheduler);
- }
- return retVal;
- }
- /************************************************************************
- * IHXPlugin::GetPluginInfo
- * Purpose:
- * Returns the basic information about this plugin. Including:
- *
- * bLoadMultiple whether or not this plugin DLL can be loaded
- * multiple times. All File Formats must set
- * this value to TRUE.
- * pDescription which is used in about UIs (can be NULL)
- * pCopyright which is used in about UIs (can be NULL)
- * pMoreInfoURL which is used in about UIs (can be NULL)
- */
- STDMETHODIMP CQTFileFormat::GetPluginInfo
- (
- REF(BOOL) bLoadMultiple,
- REF(const char*) pDescription,
- REF(const char*) pCopyright,
- REF(const char*) pMoreInfoURL,
- REF(ULONG32) ulVersionNumber
- )
- {
- bLoadMultiple = TRUE; // Must be true for file formats.
- pDescription = (const char*) zm_pDescription;
- pCopyright = (const char*) zm_pCopyright;
- pMoreInfoURL = (const char*) zm_pMoreInfoURL;
- ulVersionNumber = TARVER_ULONG32_VERSION;
- return HXR_OK;
- }
- /************************************************************************
- * IHXFileFormatObject methods
- */
- /************************************************************************
- * GetFileFormatInfo
- * Purpose:
- * If this object is a file format object this method returns
- * information vital to the instantiation of file format plugins.
- * If this object is not a file format object, it should return
- * HXR_UNEXPECTED.
- */
- STDMETHODIMP CQTFileFormat::GetFileFormatInfo
- (
- REF(const char**) /*OUT*/ pFileMimeTypes,
- REF(const char**) /*OUT*/ pFileExtensions,
- REF(const char**) /*OUT*/ pFileOpenNames
- )
- {
- pFileMimeTypes = (const char**) zm_pFileMimeTypes;
- pFileExtensions = (const char**) zm_pFileExtensions;
- pFileOpenNames = (const char**) zm_pFileOpenNames;
- return HXR_OK;
- }
- /************************************************************************
- * InitFileFormat
- */
- STDMETHODIMP CQTFileFormat::InitFileFormat
- (
- IHXRequest* /*IN*/ pRequest,
- IHXFormatResponse* /*IN*/ pFileFormatResponse,
- IHXFileObject* /*IN*/ pFileObject
- )
- {
- HX_RESULT retVal = HXR_OK;
- if (m_State != QTFF_Offline)
- {
- return HXR_UNEXPECTED;
- }
- m_State = QTFF_Init;
- if ((pFileFormatResponse == NULL) ||
- (pFileObject == NULL))
- {
- retVal = HXR_FAIL;
- }
- HX_RELEASE(m_pFFResponse);
- m_pFFResponse = pFileFormatResponse;
- m_pFFResponse->AddRef();
- HX_RELEASE(m_pRequest);
- m_pRequest = pRequest;
- if (m_pRequest)
- {
- m_pRequest->AddRef();
- }
- if (SUCCEEDED(retVal) && m_pRequest)
- {
- IHXValues* pRequestHeaders = NULL;
- if (SUCCEEDED(m_pRequest->GetRequestHeaders(pRequestHeaders)) &&
- pRequestHeaders)
- {
- ULONG32 ulVal = 0;
- if (SUCCEEDED(pRequestHeaders->GetPropertyULONG32(
- "ViewSourceInfoHeaders",
- ulVal)))
- {
- m_bViewSourceRequest = ((ulVal == 0) ? FALSE : TRUE);
- }
- IHXBuffer* pBuffer = NULL;
- retVal = pRequestHeaders->GetPropertyCString("AcceptMetaInfo",
- pBuffer);
- if(SUCCEEDED(retVal))
- {
- retVal = ExtractAcceptMetaInfo(pBuffer);
- }
- // We want to proceed even if metadata fails.
- retVal = HXR_OK;
- HX_RELEASE(pBuffer);
- }
- HX_RELEASE(pRequestHeaders);
- }
- if (SUCCEEDED(retVal))
- {
- HX_RELEASE(m_pFileSwitcher);
- HX_RELEASE(m_pAtomizer);
- #ifdef QTCONFIG_FSWITCHER
- m_pFileSwitcher = (IHXFileSwitcher*) new CFileSwitcher();
- #else // QTCONFIG_FSWITCHER
- m_pFileSwitcher = (IHXFileSwitcher*) new CFileSwitcherPassthrough();
- #endif // QTCONFIG_FSWITCHER
- if (m_pFileSwitcher)
- {
- m_pFileSwitcher->AddRef();
- }
- else
- {
- retVal = HXR_OUTOFMEMORY;
- }
- }
- if (SUCCEEDED(retVal))
- {
- m_pAtomizer = new CAtomizer();
- if (m_pAtomizer)
- {
- m_pAtomizer->AddRef();
- }
- else
- {
- retVal = HXR_OUTOFMEMORY;
- }
- }
- if (SUCCEEDED(retVal))
- {
- m_pPacketAssembler = new CQTPacketAssembler();
- if (m_pPacketAssembler)
- {
- m_pPacketAssembler->AddRef();
- retVal = m_pPacketAssembler->Init(this);
- }
- else
- {
- retVal = HXR_OUTOFMEMORY;
- }
- }
- if (SUCCEEDED(retVal))
- {
- retVal = m_pFileSwitcher->Init(pFileObject,
- HX_FILE_READ | HX_FILE_BINARY,
- (IHXFileResponse*) this,
- m_pContext,
- FSWCHR_MAX_CHILD_COUNT);
- }
-
- if (FAILED(retVal))
- {
- m_State = QTFF_Error;
- }
- return retVal;
- }
- HX_RESULT
- CQTFileFormat::ExtractAcceptMetaInfo(IHXBuffer* pRequestedInfoBuffer)
- {
- HX_RESULT res = HXR_OK;
- if(!pRequestedInfoBuffer)
- {
- res = HXR_POINTER;
- HX_ASSERT(FALSE);
- return res;
- }
- const char* pRequestedInfo = NULL;
- if (pRequestedInfoBuffer)
- {
- pRequestedInfo = (const char*) pRequestedInfoBuffer->GetBuffer();
- }
- if(*pRequestedInfo == '*')
- {
- m_ulStreamMetaInfoMask |= META_INFO_ALL;
- }
- #ifdef QTCONFIG_SERVER
- else if (pRequestedInfo)
- {
- const char* pName;
- ULONG32 ulNameLength;
- // Set requested Meta Info
- do
- {
- pName = pRequestedInfo;
-
- while ((*pRequestedInfo != ' ') &&
- (*pRequestedInfo != ','))
- {
- pRequestedInfo++;
- }
-
- ulNameLength = (ULONG32) (pRequestedInfo - pName);
- if (ulNameLength > 0)
- {
- if ((strlen(WIDTH_METANAME) == ulNameLength) &&
- (strncmp(pName, WIDTH_METANAME, ulNameLength) == 0))
- {
- m_ulStreamMetaInfoMask |= META_INFO_WIDTH;
- }
- else if ((strlen(HEIGHT_METANAME) == ulNameLength) &&
- (strncmp(pName, HEIGHT_METANAME, ulNameLength) == 0))
- {
- m_ulStreamMetaInfoMask |= META_INFO_HEIGHT;
- }
- }
- if (*pRequestedInfo == ' ')
- {
- break;
- }
- pRequestedInfo++;
- } while (TRUE);
- }
- #endif // QTCONFIG_SERVER
- return res;
- }
- HX_RESULT CQTFileFormat::MakeFileHeader(HX_RESULT status)
- {
- HX_RESULT retVal;
- IHXValues* pHeader = NULL;
- IHXBuffer* pTitle = NULL;
- // Check the license
- #ifdef QTCONFIG_SERVER
- if(SUCCEEDED(status))
- {
- switch(m_TrackManager.GetFType())
- {
- case QT_FTYPE_QT:
- case QT_FTYPE_UNKNOWN:
- {
- if(!m_bQTLicensed)
- {
- ReportError(IDS_ERR_QT_NOTLICENSED, HXR_NOT_LICENSED);
- return m_pFFResponse->FileHeaderReady(
- HXR_NOT_LICENSED, NULL);
- }
- break;
- }
- case QT_FTYPE_MP4:
- {
- if(!m_bMP4Licensed)
- {
- ReportError(IDS_ERR_MP4_NOTLICENSED, HXR_NOT_LICENSED);
- return m_pFFResponse->FileHeaderReady(
- HXR_NOT_LICENSED, NULL);
- }
- break;
- }
- }
- }
- #endif // QTCONFIG_SERVER
- // Create needed buffers
- if (SUCCEEDED(status))
- {
- status = m_pClassFactory->CreateInstance(CLSID_IHXValues,
- (void**) &pHeader);
- }
-
- if (SUCCEEDED(status))
- {
- status = m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**) &pTitle);
- }
- // Set Title
- if (SUCCEEDED(status) && (m_MovieInfo.GetNameLength() > 0))
- {
- UCHAR* pTitleMem;
- ULONG32 ulTitleMemLength = 0;
-
- status = pTitle->SetSize(m_MovieInfo.GetNameLength() + 1);
- if (SUCCEEDED(status))
- {
- pTitle->Get(pTitleMem, ulTitleMemLength);
- memcpy(pTitleMem, m_MovieInfo.GetName(), ulTitleMemLength - 1); /* Flawfinder: ignore */
- pTitleMem[ulTitleMemLength - 1] = ' ';
- pHeader->SetPropertyBuffer("Title", pTitle);
- }
- }
- HX_RELEASE(pTitle);
- if (SUCCEEDED(status))
- {
- status = GetSessionIdentity(pHeader, &m_MovieInfo);
- }
- #ifdef QTCONFIG_ALTERNATE_STREAMS
- // Set stream groupings
- if (SUCCEEDED(status))
- {
- UINT16 uStrmIdx;
- ULONG32 ulGroupID;
- ULONG32 ulGroupBitrate;
- CQTTrack* pTrack;
- IHXValues* pGroupInfo = NULL;
- for (uStrmIdx = 0;
- uStrmIdx < m_TrackManager.GetNumStreams();
- uStrmIdx++)
- {
- pTrack = m_TrackManager.GetStreamTrack(uStrmIdx);
- if (pTrack->m_TrackInfo.GetSDPLength() > 0)
- {
- retVal = SDPParseChunk(
- (char*) pTrack->m_TrackInfo.GetSDP(),
- pTrack->m_TrackInfo.GetSDPLength(),
- pGroupInfo,
- m_pClassFactory,
- SDPCTX_Group,
- FALSE);
- if (pGroupInfo &&
- (pGroupInfo->GetPropertyULONG32("AlternateGroupID",
- ulGroupID)
- == HXR_OK))
- {
- if (pGroupInfo->GetPropertyULONG32("AlternateGroupBitrate",
- ulGroupBitrate)
- != HXR_OK)
- {
- ulGroupBitrate = 0;
- }
- status = m_TrackManager.AddStreamToGroup(
- uStrmIdx,
- (UINT16) ulGroupID,
- ulGroupBitrate);
- }
-
- HX_RELEASE(pGroupInfo);
- if (FAILED(status))
- {
- break;
- }
- }
- }
- }
- // Make Default subscriptions
- if (SUCCEEDED(status))
- {
- status = m_TrackManager.SubscribeDefault();
- }
- // If we are running in player, eliminate inactive stream tracks
- if (SUCCEEDED(status))
- {
- IHXClientEngine *pPlayer = NULL;
- if (SUCCEEDED(m_pContext->QueryInterface(IID_IHXClientEngine,
- (void**) &pPlayer)))
- {
- // Running in player
- status = m_TrackManager.RemoveInactiveStreams();
- }
- HX_RELEASE(pPlayer);
- }
- #endif // QTCONFIG_ALTERNATE_STREAMS
- // Set General properties, Stream Count and duration
- if (SUCCEEDED(status))
- {
- pHeader->SetPropertyULONG32("IsRealDataType", 0);
- pHeader->SetPropertyULONG32("StreamCount",
- m_TrackManager.GetNumStreams());
- pHeader->SetPropertyULONG32("Duration",
- (ULONG32) ((1000.0 * ((double) m_MovieInfo.GetMovieDuration())) /
- m_MovieInfo.GetMovieTimeScale()));
- }
- // Set the licensing information: Basically this information is used by the
- // Broadcast Receiver plug-in to check and see if the RealServer is actually
- // licensed to receive this content
- #ifdef QTCONFIG_SERVER
- if(SUCCEEDED(status) && (!m_bViewSourceRequest))
- {
- switch(m_TrackManager.GetFType())
- {
- case QT_FTYPE_QT:
- case QT_FTYPE_UNKNOWN:
- {
- IHXBuffer* pFileTypeBuf = NULL;
- IHXBuffer* pLicenseKeyBuf = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pFileTypeBuf);
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pLicenseKeyBuf);
- pFileTypeBuf->Set((const BYTE*)"QuickTime", strlen("QuickTime") + 1);
- pLicenseKeyBuf->Set((const BYTE*)REGISTRY_QUICKTIME_ENABLED, strlen(REGISTRY_QUICKTIME_ENABLED) + 1);
- pHeader->SetPropertyCString("FileType", pFileTypeBuf);
- pHeader->SetPropertyCString("LicenseKey", pLicenseKeyBuf);
- pHeader->SetPropertyULONG32("DefaultLicenseValue", LICENSE_QUICKTIME_ENABLED);
- HX_RELEASE(pFileTypeBuf);
- HX_RELEASE(pLicenseKeyBuf);
- break;
- }
- case QT_FTYPE_MP4:
- {
- IHXBuffer* pFileTypeBuf = NULL;
- IHXBuffer* pLicenseKeyBuf = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pFileTypeBuf);
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pLicenseKeyBuf);
- pFileTypeBuf->Set((const BYTE*)"MPEG4", strlen("MPEG4") + 1);
- pLicenseKeyBuf->Set((const BYTE*)REGISTRY_REALMP4_ENABLED, strlen(REGISTRY_REALMP4_ENABLED) + 1);
- pHeader->SetPropertyCString("FileType", pFileTypeBuf);
- pHeader->SetPropertyCString("LicenseKey", pLicenseKeyBuf);
- pHeader->SetPropertyULONG32("DefaultLicenseValue", LICENSE_REALMP4_ENABLED);
- HX_RELEASE(pFileTypeBuf);
- HX_RELEASE(pLicenseKeyBuf);
- break;
- }
- }
- }
- #endif // QTCONFIG_SERVER
- // Set Requested Meta Information
- if (SUCCEEDED(status))
- {
- IHXValues* pHeaders = NULL;
- IHXBuffer* pBuffer = NULL;
-
- if (m_pRequest &&
- (m_pRequest->GetRequestHeaders(pHeaders) == HXR_OK) &&
- pHeaders)
- {
- pHeaders->Release();
- }
- status = AddMetaInfo(pHeader);
-
- // We no longer need the request so release it
- HX_RELEASE(m_pRequest);
- }
- // Set View Source specific information
- #ifdef HELIX_FEATURE_VIEWSOURCE
- if (SUCCEEDED(status) && m_bViewSourceRequest)
- {
- IHXBuffer* pCStringBuffer = NULL;
- status = m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**) &pCStringBuffer);
- if (SUCCEEDED(status))
- {
- const char* pString = "Not Hinted";
- if (m_TrackManager.IsHinted())
- {
- pString = "Hinted";
- }
- status = pCStringBuffer->Set((UINT8*) pString, strlen(pString) + 1);
- }
- if (SUCCEEDED(status))
- {
- status = pHeader->SetPropertyCString("Characteristic", pCStringBuffer);
- }
- HX_RELEASE(pCStringBuffer);
- if (SUCCEEDED(status))
- {
- status = pHeader->SetPropertyULONG32("ViewSourceInfoHeaders", 1);
- }
- }
- #endif // HELIX_FEATURE_VIEWSOURCE
- if (FAILED(status))
- {
- HX_RELEASE(pHeader);
- }
- retVal = m_pFFResponse->FileHeaderReady(status, pHeader);
- HX_RELEASE(pHeader);
- return retVal;
- }
- HX_RESULT CQTFileFormat::ObtainStreamHeader(UINT16 unStreamNumber,
- IHXValues* &pHeader)
- {
- HX_RESULT retVal = HXR_OK;
- CQTTrack* pTrack = NULL;
-
- pHeader = NULL;
- // Check Entry requirements
- if (m_State != QTFF_Ready)
- {
- retVal = HXR_UNEXPECTED;
- }
- if (SUCCEEDED(retVal))
- {
- retVal = HXR_INVALID_PARAMETER;
- if (unStreamNumber < m_TrackManager.GetNumStreams())
- {
- retVal = HXR_OK;
- }
- }
- // See if made header is already available
- if (SUCCEEDED(retVal))
- {
- pTrack = m_TrackManager.GetStreamTrack(unStreamNumber);
- if (pTrack->m_TrackInfo.GetHeader(pHeader) != HXR_OK)
- {
- retVal = BuildStreamHeader(pHeader,
- pTrack,
- &pTrack->m_TrackInfo,
- &m_MovieInfo,
- &m_TrackManager,
- m_pClassFactory);
- }
- }
- if (SUCCEEDED(retVal))
- {
- HX_ASSERT(pHeader);
- pHeader->SetPropertyULONG32("StreamNumber", unStreamNumber);
- }
- return retVal;
- }
- HX_RESULT CQTFileFormat::BuildStreamHeader(IHXValues* &pHeader,
- CQTTrack* pTrack,
- CQT_TrackInfo_Manager* pTrackInfo,
- CQT_MovieInfo_Manager* pMovieInfo,
- CQTTrackManager* pTrackManager,
- IHXCommonClassFactory* pClassFactory)
- {
- IHXBuffer* pName = NULL;
- IHXBuffer* pASMRuleBook = NULL;
- IHXBuffer* pMimeType = NULL;
- ULONG32 ulPayloadType = QT_BAD_PAYLOAD;
- ULONG32 ulAvgBitRate = 0;
- ULONG32 ulMaxBitRate = 0;
- ULONG32 ulPreroll = 0;
- ULONG32 ulPredata = 0;
- ULONG32 ulWidth = 0;
- ULONG32 ulHeight = 0;
- ULONG32 ulChannels = 0;
- HX_RESULT retVal = HXR_OK;
- // Create needed buffers
- if (!pHeader)
- {
- retVal = pClassFactory->CreateInstance(CLSID_IHXValues,
- (void**) &pHeader);
- }
- if (SUCCEEDED(retVal))
- {
- retVal = pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**) &pName);
- }
- if (SUCCEEDED(retVal))
- {
- retVal = pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**) &pASMRuleBook);
- }
- // Set Stream Name
- if (SUCCEEDED(retVal) && (pTrackInfo->GetNameLength() > 0))
- {
- UCHAR* pNameMem;
- ULONG32 ulNameMemLength = 0;
-
- retVal = pName->SetSize(pTrackInfo->GetNameLength() + 1);
- if (SUCCEEDED(retVal))
- {
- pName->Get(pNameMem, ulNameMemLength);
- memcpy(pNameMem, pTrackInfo->GetName(), /* Flawfinder: ignore */
- ulNameMemLength - 1);
- pNameMem[ulNameMemLength - 1] = ' ';
- pHeader->SetPropertyCString("StreamName", pName);
- }
- }
- HX_RELEASE(pName);
- // Set Opaque Data - if any
- if (SUCCEEDED(retVal) && (pTrackInfo->GetOpaqueDataLength() > 0))
- {
- IHXBuffer* pOpaqueData = NULL;
- retVal = pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**) &pOpaqueData);
- if (SUCCEEDED(retVal))
- {
- UCHAR* pOpaqueDataMem;
- ULONG32 ulOpaqueDataLength = 0;
-
- retVal = pOpaqueData->SetSize(pTrackInfo->GetOpaqueDataLength());
- if (SUCCEEDED(retVal))
- {
- pOpaqueData->Get(pOpaqueDataMem, ulOpaqueDataLength);
- memcpy(pOpaqueDataMem, /* Flawfinder: ignore */
- pTrackInfo->GetOpaqueData(),
- ulOpaqueDataLength);
- pHeader->SetPropertyBuffer("OpaqueData", pOpaqueData);
- }
- }
- HX_RELEASE(pOpaqueData);
- }
- if (SUCCEEDED(retVal))
- {
- retVal = GetPayloadIdentity(pHeader, pTrack, pTrackInfo);
- }
-
- // Set Duration, AvgBitRate and Preroll
- if (SUCCEEDED(retVal))
- {
- ULONG32 ulDuration;
-
- ulDuration = (ULONG32) ((pTrackInfo->GetTrackDuration()
- * 1000.0)
- / pMovieInfo->GetMovieTimeScale());
- ulAvgBitRate = pTrackInfo->GetAvgBitrate();
- ulMaxBitRate = pTrackInfo->GetMaxBitrate();
- ulPreroll = pTrackInfo->GetPreroll();
- ulPredata = pTrackInfo->GetPredata();
- ulWidth = pTrackInfo->GetTrackWidth();
- ulHeight= pTrackInfo->GetTrackHeight();
- if ((ulAvgBitRate == 0) && (ulDuration > 0))
- {
- ULONG32 ulTrackSize = pTrackInfo->GetTrackSize();
- if (ulTrackSize == 0)
- {
- pTrack->ComputeTrackSize(ulTrackSize);
- }
- ulAvgBitRate = (ULONG32) ((((double) ulTrackSize) * 8000.0)
- / ulDuration + 0.5);
- }
- if (ulAvgBitRate == 0)
- {
- ulAvgBitRate = SDPMapPayloadToBitrate(ulPayloadType);
- }
- pHeader->SetPropertyULONG32("Duration", ulDuration);
- if (ulAvgBitRate != 0)
- {
- pHeader->SetPropertyULONG32("AvgBitRate", ulAvgBitRate);
- }
- if (ulMaxBitRate != 0)
- {
- pHeader->SetPropertyULONG32("MaxBitRate", ulMaxBitRate);
- }
- if (ulPreroll != 0)
- {
- pHeader->SetPropertyULONG32("Preroll", ulPreroll);
- }
- if (ulPredata != 0)
- {
- pHeader->SetPropertyULONG32("Predata", ulPredata);
- }
- if(ulWidth != 0)
- {
- pHeader->SetPropertyULONG32(WIDTH_METANAME, ulWidth);
- }
- if(ulHeight != 0)
- {
- pHeader->SetPropertyULONG32(HEIGHT_METANAME, ulHeight);
- }
- }
- if (SUCCEEDED(retVal))
- {
- // .mp4 and .mov files may produce streams with out-of-order time stamps
- // Client core does not normally expect this in RDT protocol so set this
- // property to alert client core of this fact.
- pHeader->SetPropertyULONG32("HasOutOfOrderTS", 1);
- }
- // Set ASM Rule Book
- if (SUCCEEDED(retVal))
- {
- char pRuleBook[128]; /* Flawfinder: ignore */
- #ifdef QTCONFIG_SERVER
- pHeader->GetPropertyULONG32("RTPPayloadType", ulPayloadType);
- if (pTrackManager->GetEType() != QT_ETYPE_CLIENT)
- {
- // Server Side
- retVal = HXR_FAIL;
- if (ulPayloadType != QT_BAD_PAYLOAD)
- {
- retVal = HXR_OK;
- }
- if (SUCCEEDED(retVal))
- {
- BOOL bSupportedPayload = SDPIsKnownPayload(ulPayloadType);
- pHeader->GetPropertyCString("MimeType", pMimeType);
- // This is not a standard payload -
- // but maybe the encoding is standard
- if (!bSupportedPayload && pMimeType)
- {
- bSupportedPayload = (SDPMapMimeToPayload(pMimeType,
- ulPayloadType)
- == HXR_OK);
- }
- // Set the ASM rule book
- if ((ulAvgBitRate > 0)
- #ifndef QTFORCE_AVG_BITRATE_DELIVERY
- && bSupportedPayload
- && SDPIsFixedRatePayload(ulPayloadType)
- #endif // QTFORCE_AVG_BITRATE_DELIVERY
- )
- {
- // divide avg bitrate
- UINT32 ulAvgBandwidth = ulAvgBitRate / 2;
- SafeSprintf(pRuleBook, 128,
- "Marker=%d,AverageBandwidth=%d;"
- "Marker=%d,AverageBandwidth=%d;",
- (QTASM_MARKER_ON_RULE == 0) ? 1 : 0,
- ulAvgBitRate - ulAvgBandwidth,
- (QTASM_MARKER_ON_RULE == 0) ? 0 : 1,
- ulAvgBandwidth);
- }
- else
- {
- if (ulAvgBitRate > 0)
- {
- SafeSprintf(pRuleBook, 128, "Marker=%d,AverageBandwidth=%d,TimeStampDelivery=TRUE;"
- "Marker=%d,AverageBandwidth=0,TimeStampDelivery=TRUE;",
- (QTASM_MARKER_ON_RULE == 0) ? 1 : 0,
- ulAvgBitRate,
- (QTASM_MARKER_ON_RULE == 0) ? 0 : 1);
- }
- else
- {
- SafeSprintf(pRuleBook, 128, "Marker=%d,TimeStampDelivery=TRUE;"
- "Marker=%d,TimeStampDelivery=TRUE;",
- (QTASM_MARKER_ON_RULE == 0) ? 1 : 0,
- (QTASM_MARKER_ON_RULE == 0) ? 0 : 1);
- }
- }
- }
- }
- else
- #endif // QTCONFIG_SERVER
- {
- // Player Side
- SafeSprintf(pRuleBook, 128, "Marker=%d;Marker=%d;",
- (QTASM_MARKER_ON_RULE == 0) ? 1 : 0,
- (QTASM_MARKER_ON_RULE == 0) ? 0 : 1);
- }
- if (SUCCEEDED(retVal))
- {
- retVal = pASMRuleBook->Set((UCHAR*) pRuleBook, strlen(pRuleBook) + 1);
- }
- if (SUCCEEDED(retVal))
- {
- pHeader->SetPropertyCString("ASMRuleBook", pASMRuleBook);
- }
- }
- HX_RELEASE(pASMRuleBook);
- HX_RELEASE(pMimeType);
- return retVal;
- }
- HX_RESULT CQTFileFormat::GetSessionIdentity(IHXValues* pHeader,
- CQT_MovieInfo_Manager* pMovieInfo)
- {
- return HXR_OK;
- }
- HX_RESULT CQTFileFormat::GetPayloadIdentity(IHXValues* pHeader,
- CQTTrack* pTrack,
- CQT_TrackInfo_Manager* pTrackInfo)
- {
- HX_RESULT retVal = HXR_OK;
- if (SUCCEEDED(retVal))
- {
- const char* pMimeType = pTrackInfo->GetMimeType();
- retVal = HXR_FAIL;
- if (pMimeType)
- {
- IHXBuffer* pMimeTypeBuffer = NULL;
- UINT32 ulMimeTypeLength = strlen(pMimeType);
- retVal = m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**) &pMimeTypeBuffer);
- if (SUCCEEDED(retVal))
- {
- retVal = pMimeTypeBuffer->SetSize(ulMimeTypeLength + 1);
- }
- if (SUCCEEDED(retVal))
- {
- memcpy(pMimeTypeBuffer->GetBuffer(), /* Flawfinder: ignore */
- pMimeType,
- ulMimeTypeLength + 1);
- retVal = pHeader->SetPropertyCString("MimeType", pMimeTypeBuffer);
- }
- HX_RELEASE(pMimeTypeBuffer);
- }
- }
- if (SUCCEEDED(retVal))
- {
- ULONG32 ulTimeScale = pTrackInfo->GetMediaTimeScale();
- retVal = HXR_FAIL;
- if (ulTimeScale != 0)
- {
- retVal = pHeader->SetPropertyULONG32("SamplesPerSecond", ulTimeScale);
- }
- }
- if (SUCCEEDED(retVal))
- {
- ULONG32 ulPayloadType = pTrackInfo->GetPayloadType();
- retVal = HXR_FAIL;
- if (ulPayloadType != QT_BAD_PAYLOAD)
- {
- retVal = pHeader->SetPropertyULONG32("RTPPayloadType", ulPayloadType);
- }
- }
- return retVal;
- }
- /************************************************************************
- * GetPacket
- * Method:
- * IHXFileFormatObject::GetPacket
- * Purpose:
- * Called by controller to ask the file format for the next packet
- * for a particular stream in the file. The file format should call
- * IHXFileFormatResponse::Data*() for the IHXFileFormatResponse
- * object that was passed in during initialization, when the packet
- * is available.
- */
- STDMETHODIMP CQTFileFormat::GetPacket(UINT16 unStreamNumber)
- {
- HX_RESULT retVal;
- if (unStreamNumber < m_TrackManager.GetNumStreams())
- {
- switch (m_State)
- {
- case QTFF_Ready:
- if (unStreamNumber == m_uNextPacketStreamNum)
- {
- // Process this packet request
- // - but replace stream's cache first
- HX_ASSERT(m_pPacketCache);
- m_State = QTFF_GetPacket;
- return m_TrackManager.GetStreamTrack(unStreamNumber)->
- GetPacket(unStreamNumber);
- }
- else if (m_pPacketCache)
- {
- // Delay processing packet for stream until its turn
- if (!m_pPacketCache[unStreamNumber].bStreamDone)
- {
- if (!m_pPacketCache[unStreamNumber].bPending)
- {
- m_pPacketCache[unStreamNumber].bPending = TRUE;
- return HXR_OK;
- }
- else
- {
- retVal = HXR_UNEXPECTED;
- }
- }
- else
- {
- retVal = m_pFFResponse->StreamDone(unStreamNumber);
- }
- }
- else
- {
- // Packet Cache not primed - start priming
- // To save memory, release streams not used
- m_TrackManager.RemoveInactiveStreams(TRUE);
- m_State = QTFF_PrimeCache;
- m_pPacketCache = new
- CPacketCache[m_TrackManager.GetNumStreams()];
- if (m_pPacketCache)
- {
- m_pPacketCache[unStreamNumber].bPending = TRUE;
- if (m_TrackManager.IsStreamTrackActive(0))
- {
- return m_TrackManager.GetStreamTrack(0)->
- GetPacket(0);
- }
- else
- {
- return PacketReady(0,
- HXR_STREAM_DONE,
- NULL);
- }
- }
- else
- {
- retVal = HXR_OUTOFMEMORY;
- m_State = QTFF_Error;
- }
- }
- break;
- case QTFF_GetPacket:
- case QTFF_PrimeCache:
- // Delay processing packet for stream until Ready
- HX_ASSERT(m_pPacketCache);
- if (!m_pPacketCache[unStreamNumber].bStreamDone)
- {
- if (!m_pPacketCache[unStreamNumber].bPending)
- {
- m_pPacketCache[unStreamNumber].bPending = TRUE;
- return HXR_OK;
- }
- else
- {
- retVal = HXR_UNEXPECTED;
- }
- }
- else
- {
- retVal = m_pFFResponse->StreamDone(unStreamNumber);
- }
- break;
- default:
- retVal = HXR_UNEXPECTED;
- break;
- }
- }
- else
- {
- retVal = HXR_INVALID_PARAMETER;
- }
- return retVal;
- }
- /************************************************************************
- * Seek
- * Purpose:
- * Called by controller to tell the file format to seek to the
- * nearest packet to the requested offset. The file format should
- * call IHXFileFormatResponse::SeekDone() for the IHXFileFormat-
- * Session object that was passed in during initialization, when
- * the seek has completed.
- */
- STDMETHODIMP CQTFileFormat::Seek(ULONG32 ulOffset)
- {
- UINT16 uStreamNum;
- HX_RESULT retVal = HXR_OK;
- switch (m_State)
- {
- case QTFF_Ready:
- for (uStreamNum = 0;
- uStreamNum < m_TrackManager.GetNumStreams();
- uStreamNum++)
- {
- if (m_TrackManager.IsStreamTrackActive(uStreamNum))
- {
- m_TrackManager.GetStreamTrack(uStreamNum)->Seek(ulOffset);
- }
- }
- m_uNextPacketStreamNum = NO_STREAM_SET;
- HX_VECTOR_DELETE(m_pPacketCache);
- retVal = m_pFFResponse->SeekDone(HXR_OK);
- break;
- case QTFF_GetPacket:
- case QTFF_PrimeCache:
- case QTFF_SeekPending:
- m_State = QTFF_SeekPending;
- m_ulPendingSeekTime = ulOffset;
- break;
- default:
- retVal = HXR_UNEXPECTED;
- break;
- }
- return retVal;
- }
- /************************************************************************
- * WriteDone
- * Purpose:
- * Notification interface provided by users of the IHXFileObject
- * interface. This method is called by the IHXFileObject when the
- * last write to the file is complete.
- */
- STDMETHODIMP CQTFileFormat::WriteDone(HX_RESULT status)
- {
- return HXR_UNEXPECTED;
- }
- /************************************************************************
- * SeekDone
- * Purpose:
- * Notification interface provided by users of the IHXFileObject
- * interface. This method is called by the IHXFileObject when the
- * last seek in the file is complete.
- */
- STDMETHODIMP CQTFileFormat::SeekDone(HX_RESULT status)
- {
- return HXR_UNEXPECTED;
- }
- /************************************************************************
- * Close
- */
- STDMETHODIMP CQTFileFormat::Close()
- {
- m_State = QTFF_Error;
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pRequest);
- HX_RELEASE(m_pFFResponse);
- HX_RELEASE(m_pClassFactory);
- HX_RELEASE(m_pScheduler);
- HX_RELEASE(m_pErrorMessages);
- if (m_pFileSwitcher)
- {
- m_pFileSwitcher->Close(this);
- m_pFileSwitcher->Release();
- m_pFileSwitcher = NULL;
- }
- if (m_pAtomizer)
- {
- m_pAtomizer->Close();
- m_pAtomizer->Release();
- m_pAtomizer = NULL;
- }
- HX_RELEASE(m_pPacketAssembler);
- #ifdef QTCONFIG_BFRAG_FACTORY
- HX_RELEASE(m_pBufferFragmentFactory);
- #endif // QTCONFIG_BFRAG_FACTORY
- HX_VECTOR_DELETE(m_pPacketCache);
- m_TrackManager.CloseTracks();
- return HXR_OK;
- }
- /************************************************************************
- * IHXFileResponse
- */
- /************************************************************************
- * InitDone
- * Purpose:
- * Notification interface provided by users of the IHXFileObject
- * interface. This method is called by the IHXFileObject when the
- * initialization of the file is complete, and the Mime type is
- * available for the request file. If the URL is not valid for the
- * file system, the status HXR_FAILED should be returned,
- * with a mime type of NULL. If the URL is valid but the mime type
- * is unknown, then the status HXR_OK should be returned with
- * a mime type of NULL.
- */
- STDMETHODIMP CQTFileFormat::InitDone(HX_RESULT status)
- {
- HX_RESULT retVal = HXR_OK;
- switch (m_State)
- {
- case QTFF_Init:
- if (SUCCEEDED(status))
- {
- status = m_pAtomizer->Init((IUnknown*)(IHXFileSwitcher*) m_pFileSwitcher,
- (IUnknown*)(IHXAtomizerResponse*) this,
- (IUnknown*)(IHXAtomizationCommander*) this);
- }
-
- m_State = SUCCEEDED(status) ? QTFF_Ready : QTFF_Error;
- retVal = m_pFFResponse->InitDone(status);
- break;
- default:
- retVal = HXR_UNEXPECTED;
- break;
- }
- return retVal;
- }
- /************************************************************************
- * CloseDone
- * Purpose:
- * Notification interface provided by users of the IHXFileObject
- * interface. This method is called by the IHXFileObject when the
- * close of the file is complete.
- */
- STDMETHODIMP CQTFileFormat::CloseDone(HX_RESULT status)
- {
- // nothing to do
- return HXR_OK;
- }
- /************************************************************************
- * ReadDone
- * Purpose:
- * Notification interface provided by users of the IHXFileObject
- * interface. This method is called by the IHXFileObject when the
- * last read from the file is complete and a buffer is available.
- */
- STDMETHODIMP CQTFileFormat::ReadDone(HX_RESULT status,
- IHXBuffer* pBuffer)
- {
- return HXR_UNEXPECTED;
- }
- /************************************************************************
- * IHXAtomizationCommander
- */
- /************************************************************************
- * GetAtomCommand
- */
- QTAtomizerCmd CQTFileFormat::GetAtomCommand(QTAtomType AtomType, CQTAtom* pParent)
- {
- QTAtomizerCmd eCmd = ATMZR_CMD_LOAD;
- switch (AtomType)
- {
- case QT_udta:
- if (pParent->GetType() == QT_HXROOT)
- {
- eCmd = ATMZR_CMD_SKIP;
- }
- break;
- default:
- // do nothing;
- break;
- }
- return eCmd;
- }
- /************************************************************************
- * IHXAtomizerResponse
- */
- /************************************************************************
- * AtomReady
- */
- HX_RESULT CQTFileFormat::AtomReady(HX_RESULT status, CQTAtom* pRootAtom)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- CQTPacketizerFactory* pPacketizerFactory = NULL;
- switch (m_State)
- {
- case QTFF_Atomize:
- if (SUCCEEDED(status))
- {
- HX_ASSERT(pRootAtom);
-
- pRootAtom->AddRef();
-
- if (m_pAtomizer)
- {
- m_pAtomizer->Close();
- m_pAtomizer->Release();
- m_pAtomizer = NULL;
- }
- }
- else
- {
- pRootAtom = NULL;
- }
-
- if (SUCCEEDED(status))
- {
- IHXClientEngine* pPlayer = NULL;
- if (SUCCEEDED(m_pContext->QueryInterface(IID_IHXClientEngine,
- (void**)&pPlayer)))
- {
- m_TrackManager.SetEType(QT_ETYPE_CLIENT);
- }
- else
- {
- m_TrackManager.SetEType(QT_ETYPE_SERVER);
- }
- HX_RELEASE(pPlayer);
- }
- if (SUCCEEDED(status))
- {
- status = m_TrackManager.ManageTracks(pRootAtom);
- }
- #ifdef QTCONFIG_PACKETIZER_FACTORY
- if (SUCCEEDED(status))
- {
- pPacketizerFactory = BuildPacketizerFactory();
- if (!pPacketizerFactory)
- {
- status = HXR_OUTOFMEMORY;
- }
- }
- #endif // QTCONFIG_PACKETIZER_FACTORY
-
- if (SUCCEEDED(status))
- {
- BOOL bIgnoreHintTracks = FALSE;
- while (1)
- {
- status = m_TrackManager.ReadyTracks(bIgnoreHintTracks,
- m_bViewSourceRequest);
- if (SUCCEEDED(status))
- {
- status = m_MovieInfo.Init(pRootAtom->FindPresentChild(QT_moov),
- &m_TrackManager);
- }
- if (SUCCEEDED(status))
- {
- /*
- * return some error to indicate try something else
- */
- status = m_TrackManager.InitTracks(this,
- m_pPacketAssembler,
- pPacketizerFactory);
-
- if ((HXR_NOT_SUPPORTED == status) &&
- (bIgnoreHintTracks = !bIgnoreHintTracks))
- {
- m_MovieInfo.Clear();
- m_TrackManager.ResetTracks();
- }
- else
- {
- /*
- * Until we add support for unhinted content on the server....
- *
- * Verify that hint tracks are present and log a warning message if
- * they're missing
- */
- WarnIfNotHinted(status, bIgnoreHintTracks);
-
- /*
- * XXXGo - Change warning to take into account
- * hintrack and license for dynamic pktization
- * e.g. force pktization yet not licensed for dynamic pktization...
- */
-
- if (FAILED(status) && m_bViewSourceRequest)
- {
- // For view source, proceed attempting to return as much
- // information as possible
- status = HXR_OK;
- }
- break;
- }
- }
- else
- {
- break;
- }
- }
- }
-
- HX_DELETE(pPacketizerFactory);
- #ifdef QTCONFIG_BFRAG_FACTORY
- if (SUCCEEDED(status))
- {
- HX_RELEASE(m_pBufferFragmentFactory);
- m_pBufferFragmentFactory = new CBufferFragmentFactory(
- m_TrackManager.GetNumStreams() * QTBUFFERFRAGMENT_POOL_SIZE,
- m_TrackManager.GetNumStreams() * QTBUFFERFRAGMENT_INITIAL_POOL_SIZE);
- retVal = HXR_OUTOFMEMORY;
- if (m_pBufferFragmentFactory)
- {
- m_pBufferFragmentFactory->AddRef();
- retVal = HXR_OK;
- }
- }
- #endif // QTCONFIG_BFRAG_FACTORY
- HX_RELEASE(pRootAtom);
- m_State = SUCCEEDED(status) ? QTFF_Ready : QTFF_Error;
- retVal = MakeFileHeader(status);
- break;
- default:
- // nothing to do
- break;
- }
- return retVal;
- }
- /************************************************************************
- * IHXASMSource
- */
- /************************************************************************
- * Subscribe
- */
- STDMETHODIMP CQTFileFormat::Subscribe(UINT16 uStreamNum,
- UINT16 uRuleNumber)
- {
- return m_TrackManager.Subscribe(uStreamNum);
- }
- /************************************************************************
- * Unsubscribe
- */
- STDMETHODIMP CQTFileFormat::Unsubscribe(UINT16 uStreamNum,
- UINT16 uRuleNumber)
- {
- return m_TrackManager.Unsubscribe(uStreamNum);
- }
- /************************************************************************
- * Method:
- * IHXPacketFormat::GetSupportedPacketFormats
- * Purpose:
- * Obtains a list of packet formats supported by this file format
- */
- STDMETHODIMP CQTFileFormat::GetSupportedPacketFormats
- (
- REF(const char**) /*OUT*/ pPacketFormats
- )
- {
- pPacketFormats = (const char**) zm_pPacketFormats;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXPacketFormat::SetPacketFormat
- * Purpose:
- * Sets the packet type for this file format
- */
- STDMETHODIMP CQTFileFormat::SetPacketFormat
- (
- const char* pPacketFormat
- )
- {
- if (strcasecmp(pPacketFormat, "rtp") == 0)
- {
- m_ulPacketFormat = QTFF_RTP_FORMAT;
- }
- else
- {
- m_ulPacketFormat = QTFF_RDT_FORMAT;
- }
- return HXR_OK;
- }
- /************************************************************************
- * Main Interface
- */
- /************************************************************************
- * PacketReady
- */
- HX_RESULT CQTFileFormat::PacketReady(UINT16 uStreamNum,
- HX_RESULT status,
- IHXPacket* pPacket)
- {
- HX_RESULT retVal;
- IHXPacket *pPacketToSend;
- switch (m_State)
- {
- case QTFF_GetPacket:
- pPacketToSend = m_pPacketCache[uStreamNum].pPacket;
- HX_ASSERT(pPacketToSend);
- if (status == HXR_OK)
- {
- HX_ASSERT(pPacket);
- m_pPacketCache[uStreamNum].pPacket = pPacket;
- pPacket->AddRef();
- }
- else
- {
- m_pPacketCache[uStreamNum].pPacket = NULL;
- m_pPacketCache[uStreamNum].bStreamDone = TRUE;
- if (status == HXR_STREAM_DONE)
- {
- status = HXR_OK;
- }
- }
- AddRef(); // Make Sure we do not die as a result of PacketReady
- m_pPacketCache[uStreamNum].bPending = FALSE;
- retVal = m_pFFResponse->PacketReady(status, pPacketToSend);
- if (pPacketToSend)
- {
- pPacketToSend->Release();
- }
- // Make sure the state did not change as result of PacketReady()
- // The possible change is due to invocation of Close on PacketReady
- if (m_State == QTFF_GetPacket)
- {
- m_State = QTFF_Ready;
- // see if a pending request needs to be fullfilled
- m_uNextPacketStreamNum = GetNextPacketStreamNum();
- if ((m_uNextPacketStreamNum != NO_STREAM_SET) &&
- m_pPacketCache[m_uNextPacketStreamNum].bPending)
- {
- m_State = QTFF_GetPacket;
- retVal = m_TrackManager.GetStreamTrack(m_uNextPacketStreamNum)->
- GetPacket(m_uNextPacketStreamNum);
- }
- }
- Release();
- return retVal;
- case QTFF_PrimeCache:
- if (status == HXR_OK)
- {
- HX_ASSERT(pPacket);
- m_pPacketCache[uStreamNum].pPacket = pPacket;
- pPacket->AddRef();
- }
- else
- {
- m_pPacketCache[uStreamNum].pPacket = NULL;
- m_pPacketCache[uStreamNum].bStreamDone = TRUE;
- if (status == HXR_STREAM_DONE)
- {
- if (m_pPacketCache[uStreamNum].bPending)
- {
- AddRef(); // Make sure we do not die
- m_pPacketCache[uStreamNum].bPending = FALSE;
- retVal = m_pFFResponse->StreamDone(uStreamNum);
- if (m_State != QTFF_PrimeCache)
- {
- // StreamDone must have closed us
- Release();
- break;
- }
- Release();
- }
- }
- else
- {
- // Fatal failure
- retVal = HandleFailure(status);
- break;
- }
- }
- uStreamNum++;
- if (uStreamNum < m_TrackManager.GetNumStreams())
- {
- // we still have stream packets to prime
- if (m_TrackManager.IsStreamTrackActive(uStreamNum))
- {
- retVal = m_TrackManager.GetStreamTrack(uStreamNum)->
- GetPacket(uStreamNum);
- }
- else
- {
- retVal = PacketReady(uStreamNum,
- HXR_STREAM_DONE,
- NULL);
- }
- }
- else
- {
- // we are done priming the packets
- retVal = HXR_OK;
- m_State = QTFF_Ready;
- // see if a pending request needs to be fullfilled
- m_uNextPacketStreamNum = GetNextPacketStreamNum();
- if ((m_uNextPacketStreamNum != NO_STREAM_SET) &&
- m_pPacketCache[m_uNextPacketStreamNum].bPending)
- {
- m_State = QTFF_GetPacket;
- retVal = m_TrackManager.
- GetStreamTrack(m_uNextPacketStreamNum)->
- GetPacket(m_uNextPacketStreamNum);
- }
- }
- break;
- case QTFF_SeekPending:
- HX_VECTOR_DELETE(m_pPacketCache);
- m_uNextPacketStreamNum = NO_STREAM_SET;
- m_State = QTFF_Ready;
- retVal = Seek(m_ulPendingSeekTime);
- break;
- default:
- retVal = HXR_UNEXPECTED;
- break;
- }
- return retVal;
- }
- /************************************************************************
- * Protected Methods
- */
- CQTPacketizerFactory* CQTFileFormat::BuildPacketizerFactory(void)
- {
- #ifdef QTCONFIG_PACKETIZER_FACTORY
- return new CQTPacketizerFactory();
- #else // QTCONFIG_PACKETIZER_FACTORY
- return NULL;
- #endif // QTCONFIG_PACKETIZER_FACTORY
- }
- /************************************************************************
- * Private Methods
- */
- /************************************************************************
- * GetNextPacketStreamNum
- */
- inline UINT16 CQTFileFormat::GetNextPacketStreamNum(void)
- {
- UINT16 uStreamNum;
- ULONG32 ulLowestTime = 0xFFFFFFFF;
- UINT16 uNextPacketStream = NO_STREAM_SET;
- HX_ASSERT(m_pPacketCache);
- for (uStreamNum = 0;
- uStreamNum < m_TrackManager.GetNumStreams();
- uStreamNum++)
- {
- if (!m_pPacketCache[uStreamNum].bStreamDone)
- {
- HX_ASSERT(m_pPacketCache[uStreamNum].pPacket);
- if (ulLowestTime >
- m_pPacketCache[uStreamNum].pPacket->GetTime())
- {
- uNextPacketStream = uStreamNum;
- ulLowestTime = m_pPacketCache[uStreamNum].
- pPacket->GetTime();
- }
- }
- }
- return uNextPacketStream;
- }
- /************************************************************************
- * HandleFailure
- */
- HX_RESULT CQTFileFormat::HandleFailure(HX_RESULT status)
- {
- HX_RESULT retVal = HXR_OK;
- HX_ASSERT(FAILED(status));
- switch (m_State)
- {
- case QTFF_PrimeCache:
- {
- UINT16 uStreamNum = 0;
- m_State = QTFF_Error;
-
- AddRef();
- while (m_pPacketCache &&
- (uStreamNum < m_TrackManager.GetNumStreams()))
- {
- if (m_pPacketCache[uStreamNum].bPending)
- {
- m_pPacketCache[uStreamNum].bPending = FALSE;
- m_pFFResponse->PacketReady(status, NULL);
- }
- uStreamNum++;
- }
- Release();
- }
- break;
- default:
- retVal = HXR_UNEXPECTED;
- break;
- }
- return retVal;
- }
- /************************************************************************
- * a standard way of pulling a error string out of a resource file in a
- * localization friendly manner :)
- */
- void
- CQTFileFormat::ReportError(UINT32 ulErrorID, HX_RESULT retVal)
- {
- // Try to get the string from the resource manager
- CHXString cErrStr;
- HX_RESULT errRet = GetResourceErrorString(ulErrorID, cErrStr);
- if (errRet != HXR_OK)
- {
- switch (ulErrorID)
- {
- case IDS_ERR_QT_NOTLICENSED:
- cErrStr = ERRSTR_QT_NOTLICENSED;
- break;
- default:
- cErrStr = ERRSTR_QT_GENERALERROR;
- break;
- }
- }
-
- if (m_pErrorMessages)
- {
- m_pErrorMessages->Report(HXLOG_CRIT, retVal, 0, (const char*) cErrStr, NULL);
- }
- }
- HX_RESULT
- CQTFileFormat::GetResourceErrorString(UINT32 ulErrorID, CHXString& rErrorStr)
- {
- IHXExternalResourceManager* pResMgr = NULL;
- HX_RESULT retVal = m_pContext->QueryInterface(IID_IHXExternalResourceManager, (void**) &pResMgr);
- if (retVal != HXR_OK)
- {
- return retVal;
- }
- IHXExternalResourceReader* pResRdr = NULL;
- retVal = pResMgr->CreateExternalResourceReader(CORE_RESOURCE_SHORT_NAME, pResRdr);
- if (retVal != HXR_OK)
- {
- HX_RELEASE(pResMgr);
- return retVal;
- }
- IHXXResource* pRes = pResRdr->GetResource(HX_RT_STRING, ulErrorID);
- if(!pRes)
- {
- HX_RELEASE(pResRdr);
- HX_RELEASE(pResMgr);
- return HXR_FAIL;
- }
- // Assign the error string to the out parameter
- rErrorStr = (const char*) pRes->ResourceData();
- // Release all references
- HX_RELEASE(pRes);
- HX_RELEASE(pResRdr);
- HX_RELEASE(pResMgr);
- return HXR_OK;
- }
- /************************************************************************
- * AddMetaInfo
- */
- HX_RESULT CQTFileFormat::AddMetaInfo(IHXValues* pHeader)
- {
- BOOL bAddAll;
- ULONG32 ulPresentationWidth = 0;
- ULONG32 ulPresentationHeight = 0;
-
- HX_ASSERT(pHeader);
- if ((m_TrackManager.GetEType() == QT_ETYPE_CLIENT) ||
- (m_ulStreamMetaInfoMask & META_INFO_ALL) ||
- (m_ulStreamMetaInfoMask & META_INFO_WIDTH) ||
- (m_ulStreamMetaInfoMask & META_INFO_HEIGHT))
- {
- UINT16 uStreamCount;
- CQTTrack* pTrack;
- // Collect Meta Info
- for (uStreamCount = m_TrackManager.GetNumStreams();
- uStreamCount != 0;
- uStreamCount--)
- {
- pTrack = m_TrackManager.GetStreamTrack(uStreamCount - 1);
-
- ulPresentationWidth += pTrack->m_TrackInfo.GetTrackWidth();
- ulPresentationHeight += pTrack->m_TrackInfo.GetTrackHeight();
- }
- }
- bAddAll = ((m_TrackManager.GetEType() == QT_ETYPE_CLIENT) ||
- (m_ulStreamMetaInfoMask & META_INFO_ALL));
- if (bAddAll)
- {
- if (ulPresentationWidth > 0)
- {
- pHeader->SetPropertyULONG32(WIDTH_METANAME,
- ulPresentationWidth);
- }
- if (ulPresentationHeight > 0)
- {
- pHeader->SetPropertyULONG32(HEIGHT_METANAME,
- ulPresentationHeight);
- }
- }
- #ifdef QTCONFIG_SERVER
- else if((m_ulStreamMetaInfoMask & META_INFO_ALL) ||
- (m_ulStreamMetaInfoMask & META_INFO_WIDTH) ||
- (m_ulStreamMetaInfoMask & META_INFO_HEIGHT))
- {
- if (ulPresentationWidth > 0 &&
- ((m_ulStreamMetaInfoMask & META_INFO_ALL) ||
- (m_ulStreamMetaInfoMask & META_INFO_WIDTH)))
- {
- pHeader->SetPropertyULONG32(WIDTH_METANAME,
- ulPresentationWidth);
- }
- if (ulPresentationHeight > 0 &&
- ((m_ulStreamMetaInfoMask & META_INFO_ALL) ||
- (m_ulStreamMetaInfoMask & META_INFO_HEIGHT)))
- {
- pHeader->SetPropertyULONG32(HEIGHT_METANAME,
- ulPresentationHeight);
- }
- }
- #endif // QTCONFIG_SERVER
- return HXR_OK;
- }
- #ifdef QTCONFIG_SERVER
- /************************************************************************
- * CheckLicense
- */
- HX_RESULT CQTFileFormat::CheckLicense(void)
- {
- HX_ASSERT(m_pContext);
-
- IHXClientEngine* pPlayer = NULL;
- IHXRemoteBroadcastServices* pRBServices = NULL;
- if (SUCCEEDED(m_pContext->QueryInterface(IID_IHXClientEngine, (void**)&pPlayer))
- || SUCCEEDED(m_pContext->QueryInterface(IID_IHXRemoteBroadcastServices, (void**)&pRBServices)))
- {
- // Data types are always licensed on the Player and iqslta
- m_bQTLicensed = TRUE;
- m_bMP4Licensed = TRUE;
- }
- else
- {
- // On the Server, check the license section of the registry
- IHXRegistry* pRegistry = NULL;
- if (HXR_OK != m_pContext->QueryInterface(IID_IHXRegistry,
- (void**)&pRegistry))
- {
- return HXR_UNEXPECTED;
- }
- INT32 nLicensed = 0;
- if (!SUCCEEDED(pRegistry->GetIntByName(REGISTRY_QUICKTIME_ENABLED,
- nLicensed)))
- {
- /* take default */
- nLicensed = LICENSE_QUICKTIME_ENABLED;
- }
- m_bQTLicensed = (nLicensed) ? (TRUE) : (FALSE);
- if (!SUCCEEDED(pRegistry->GetIntByName(REGISTRY_REALMP4_ENABLED,
- nLicensed)))
- {
- /* take default */
- nLicensed = LICENSE_REALMP4_ENABLED;
- }
- m_bMP4Licensed = (nLicensed) ? (TRUE) : (FALSE);
- HX_RELEASE(pRegistry);
- }
- HX_RELEASE(pPlayer);
- HX_RELEASE(pRBServices);
- return HXR_OK;
- }
- /************************************************************************
- * WarnIfNotHinted
- */
- void CQTFileFormat::WarnIfNotHinted(HX_RESULT status, BOOL bIgnoreHintTracks)
- {
- /*
- * log what's going on...
- */
- if ((m_TrackManager.GetEType() == QT_ETYPE_SERVER) && m_pErrorMessages
- && HXR_OK == status)
- {
- /*
- * Check the registry to see if warnings are disabled.
- */
- INT32 nWarningDisabled = 0;
- IHXRegistry* pRegistry = NULL;
- if (m_pContext &&
- (HXR_OK == m_pContext->QueryInterface(IID_IHXRegistry,
- (void**)&pRegistry)))
- {
- pRegistry->GetIntByName("config.DisableHintingWarning",
- nWarningDisabled);
- }
- HX_RELEASE(pRegistry);
- if (nWarningDisabled)
- {
- return;
- }
- const char* pszIgnore =
- "Handling HINTED content - ignoring Hint Tracks (URL: /%s)n";
- const char* pszHint =
- "Handling HINTED content - using Hint Tracks (URL: /%s)n";
- const char* pszNotHinted =
- "Handling UNHINTED content (URL: /%s)n";
- const char* pszMsg;
-
- if (bIgnoreHintTracks)
- {
- pszMsg = pszIgnore;
- }
- else if (m_TrackManager.IsHinted())
- {
- pszMsg = pszHint;
- HX_ASSERT(HXR_NOT_LICENSED != status); // can't ever be this error
- }
- else
- {
- pszMsg = pszNotHinted;
- }
- const char* pReqURL = NULL;
- UINT32 ulMaxURLLen = 1024 * 2;
- UINT32 ulBuffLen = ulMaxURLLen + strlen(pszMsg) + 1;
- HX_RESULT status = HXR_OK;
- if (m_pRequest)
- {
- status = m_pRequest->GetURL(pReqURL);
- }
- if (SUCCEEDED(status) && pReqURL)
- {
- UINT32 ulURLLen = strlen(pReqURL);
- if (ulURLLen > ulMaxURLLen)
- {
- pReqURL += ulURLLen - ulMaxURLLen;
- }
- }
- else
- {
- pReqURL = " ";
- }
- NEW_FAST_TEMP_STR(pszTmpStr, 4096, ulBuffLen);
- snprintf(pszTmpStr, ulBuffLen, pszMsg, pReqURL);
- m_pErrorMessages->Report(HXLOG_WARNING, HXR_OK, 0, pszTmpStr, NULL);
- DELETE_FAST_TEMP_STR(pszTmpStr);
- }
- }
- #else // QTCONFIG_SERVER
- HX_RESULT CQTFileFormat::CheckLicense(void)
- {
- return HXR_OK;
- }
- void CQTFileFormat::WarnIfNotHinted(HX_RESULT status, BOOL bIgnoreHintTracks)
- {
- return;
- }
- #endif // QTCONFIG_SERVER
- /************************************************************************
- * Method:
- * IHXThreadSafeMethods::IsThreadSafe
- */
- STDMETHODIMP_(UINT32) CQTFileFormat::IsThreadSafe()
- {
- return HX_THREADSAFE_METHOD_FF_GETPACKET |
- HX_THREADSAFE_METHOD_FSR_READDONE;
- }
- /************************************************************************
- * IUnknown methods
- */
- STDMETHODIMP CQTFileFormat::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*) (IHXPlugin*) this},
- { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*) this},
- { GET_IIDHANDLE(IID_IHXFileFormatObject), (IHXFileFormatObject*) this},
- { GET_IIDHANDLE(IID_IHXAtomizerResponse), (IHXAtomizerResponse*) this},
- { GET_IIDHANDLE(IID_IHXAtomizationCommander), (IHXAtomizationCommander*) this},
- #ifdef QTCONFIG_ALTERNATE_STREAMS
- { GET_IIDHANDLE(IID_IHXASMSource), (IHXASMSource*) this},
- #endif // QTCONFIG_ALTERNATE_STREAMS
- { GET_IIDHANDLE(IID_IHXPacketFormat), (IHXPacketFormat*) this},
- { GET_IIDHANDLE(IID_IHXFileSwitcher), (IHXFileSwitcher*) m_pFileSwitcher},
- { GET_IIDHANDLE(IID_IHXCommonClassFactory), m_pClassFactory},
- { GET_IIDHANDLE(IID_IHXScheduler), m_pScheduler}
- };
- return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- STDMETHODIMP_(ULONG32) CQTFileFormat::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- STDMETHODIMP_(ULONG32) CQTFileFormat::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- /************************************************************************
- * GetFileHeader
- * Purpose:
- * Called by controller to ask the file format for the number of
- * headers in the file. The file format should call the
- * IHXFormatResponse::StreamCountReady() for the IHXFileFormat-
- * Session object that was passed in during initialization, when the
- * header count is available.
- */
- STDMETHODIMP CQTFileFormat::GetFileHeader()
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_State == QTFF_Ready)
- {
- if (m_pAtomizer)
- {
- // This must be the first call to GetFileHeader - Atomize
- m_State = QTFF_Atomize;
- retVal = m_pAtomizer->Atomize();
- }
- else
- {
- retVal = MakeFileHeader(HXR_OK);
- }
- }
-
- return retVal;
- }
- /************************************************************************
- * GetStreamHeader
- * Purpose:
- * Called by controller to ask the file format for the header for
- * a particular stream in the file. The file format should call
- * IHXFileFormatResponse::HeaderReady() for the IHXFileFormatResponse
- * object that was passed in during initialization, when the header
- * is available.
- */
- STDMETHODIMP CQTFileFormat::GetStreamHeader(UINT16 unStreamNumber)
- {
- HX_RESULT retVal;
- IHXValues* pHeader;
- retVal = ObtainStreamHeader(unStreamNumber, pHeader);
- if (SUCCEEDED(retVal))
- {
- retVal = m_pFFResponse->StreamHeaderReady(retVal, pHeader);
- }
- HX_RELEASE(pHeader);
- return retVal;
- }