qtffplin.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 2,308 行 · 第 1/4 页

CPP
2,308
字号
/* ***** 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 != '\0') &&
		   (*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 == '\0')
	    {
		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] = '\0';

	    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)
		    {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?