mp4tpyld.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 559 行

CPP
559
字号
/* ***** 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 MP4T_RN_3GPP_TEXT_PAYLOAD_MIME_TYPE "video/X-RN-3GPP-TEXT"

#define FLUSH_ALL_PACKETS   0xFFFFFFFF

#define FORMAT_PARAMETERS_PREFIX	"a=fmtp:0 "
#define FORMAT_PARAMETERS_PREFIX_SIZE	(sizeof(FORMAT_PARAMETERS_PREFIX) - 1)

#define MAX_INT_TEXT_LENGTH	10

// /XXXEH- need to revisit this.  How (if at all) is a sparse data stream
// handled in RDT:
#define _3GPPT_DEFAULT_SAMPLES_PER_SEC 10

/****************************************************************************
 *  Includes
 */
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxcom.h"
#include "hxcomm.h"

#include "hxassert.h"
#include "hxslist.h"
#include "hxstrutl.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxformt.h"
#include "hxrendr.h"
#include "hxformt.h"
#include "hxengin.h"

#include "rule2flg.h" // /For RuleToFlagMap (ASM-rule-to-flag map)

#include "qtatmmgs.h" // /For CQT_TrackInfo_Manager
#include "qttrack.h"  // /For CQTTrack

#include "mp4desc.h"
#include "mp4tpyld.h"


MP4TPayloadFormat::MP4TPayloadFormat(CQTTrack* pTrack,
	    CQT_TrackInfo_Manager* pTrackInfoMgr,
	    CHXBufferMemoryAllocator* pAllocator)
    : m_lRefCount	(0)
    , m_pClassFactory	(NULL)
    , m_pStreamHeader	(NULL)
    , m_pTextHeader	(NULL)
    , m_ulTextCfgHeaderSize (0)
    , m_ulSamplesPerSecond(1000)
    , m_bFlushed	(FALSE)
    , m_bFirstPacket	(TRUE)
    , m_bUsesRTPPackets (FALSE)
    , m_bRTPPacketTested(FALSE)
    , m_pAllocator	(pAllocator)
    , m_bPacketize	(FALSE)
    , m_PayloadID	(PYID_X_HX_3GPP_TEXT)
    , m_pTrack          (pTrack)
    , m_pTrackInfoMgr   (pTrackInfoMgr)
    , m_pRuleToFlagMap(NULL)
    , m_ulPriorPacketContentBeginTime(0)
{
    if (m_pAllocator)
    {
	m_pAllocator->AddRef();
    }
}

MP4TPayloadFormat::~MP4TPayloadFormat()
{
    FlushPackets(FLUSH_ALL_PACKETS);

    if (m_pRuleToFlagMap)
    {
	if (m_pRuleToFlagMap->rule_to_flag_map)
	{
	    delete[] m_pRuleToFlagMap->rule_to_flag_map;
	}
	delete m_pRuleToFlagMap;
	m_pRuleToFlagMap = NULL;
    }

    HX_VECTOR_DELETE(m_pTextHeader);
    if (m_pAllocator)
    {
        m_pAllocator->Release();
        m_pAllocator = NULL;
    }
    HX_RELEASE(m_pClassFactory);
    HX_RELEASE(m_pStreamHeader);
}

// *** IUnknown methods ***

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IUnknown::QueryInterface
//  Purpose:
//	Implement this to export the interfaces supported by your
//	object.
//
STDMETHODIMP
MP4TPayloadFormat::QueryInterface(REFIID riid, void** ppvObj)
{
    QInterfaceList qiList[] =
    {
	{ GET_IIDHANDLE(IID_IUnknown), this },
	{ GET_IIDHANDLE(IID_IHXPayloadFormatObject), (IHXPayloadFormatObject*) this },
    };
    return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IUnknown::AddRef
//  Purpose:
//	Everyone usually implements this the same... feel free to use
//	this implementation.
//
STDMETHODIMP_(ULONG32)
MP4TPayloadFormat::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IUnknown::Release
//  Purpose:
//	Everyone usually implements this the same... feel free to use
//	this implementation.
//
STDMETHODIMP_(ULONG32)
MP4TPayloadFormat::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}


STDMETHODIMP
MP4TPayloadFormat::Init(IUnknown* pContext,
			BOOL bPacketize)
{
    HX_RESULT retVal = HXR_OK;

    HX_RELEASE(m_pClassFactory);

    m_bPacketize = bPacketize;

    if (SUCCEEDED(retVal))
    {
	retVal = pContext->QueryInterface(IID_IHXCommonClassFactory,
					  (void**) &m_pClassFactory);
    }

    return retVal;
}

STDMETHODIMP
MP4TPayloadFormat::Reset()
{
    // Release all input packets we have stored
    FlushPackets(FLUSH_ALL_PACKETS);

    m_bFlushed = FALSE;
    m_bFirstPacket = TRUE;
    m_bUsesRTPPackets = FALSE;
    m_bRTPPacketTested = FALSE;

    m_TSConverter.Reset();

    return HXR_OK;
}

STDMETHODIMP
MP4TPayloadFormat::SetStreamHeader(IHXValues* pHeader)
{
    HX_RESULT retVal = HXR_OK;

    HX_ASSERT(pHeader);

    HX_RELEASE(m_pStreamHeader);
    m_pStreamHeader = pHeader;
    if (m_pStreamHeader)
    {
	m_pStreamHeader->AddRef();
    }
    // /We need to add an ASM rulebook with n rules, one for each sample
    // description.  Note: in future, we may have multiple rules that map to
    // a particular sample description, so we use a RuleToFlagMap to
    // make sure the renderer knows which maps to which:
    IHXBuffer* pASMRuleBook = NULL;
    if (!m_pClassFactory  ||  !m_pTrackInfoMgr)
    {
	retVal = HXR_UNEXPECTED;
    }
    else
    {
	// /3GPP Timed Text renderer needs width, height, and matrix (for
	// origin offset),
	HX_ASSERT(m_pTrackInfoMgr->GetTrackWidth());
	if (m_pTrackInfoMgr->GetTrackWidth())
	{
	    m_pStreamHeader->SetPropertyULONG32("3GPPTextTrackWidth",
		    m_pTrackInfoMgr->GetTrackWidth());
	}

	HX_ASSERT(m_pTrackInfoMgr->GetTrackHeight());
	if (m_pTrackInfoMgr->GetTrackHeight())
	{
	    m_pStreamHeader->SetPropertyULONG32("3GPPTextTrackHeight",
		    m_pTrackInfoMgr->GetTrackHeight());
	}

	if (m_pTrackInfoMgr->GetTrackTransformX())
	{
	    m_pStreamHeader->SetPropertyULONG32("3GPPTextTrackTransformX",
		    m_pTrackInfoMgr->GetTrackTransformX());
	}

	if (m_pTrackInfoMgr->GetTrackTransformY())
	{
	    m_pStreamHeader->SetPropertyULONG32("3GPPTextTrackTransformY",
		    m_pTrackInfoMgr->GetTrackTransformY());
	}


	retVal = m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
					       (void**) &pASMRuleBook);

	// /XXXEH- should the rule(s) contain "priority=10" as well?:
	char* pszNewRuleStr = "TimestampDelivery=TRUE;";
	UINT32 ulNewRuleStrLen = (UINT32)strlen(pszNewRuleStr);
	UINT32 ulNumEntries = m_pTrackInfoMgr->GetNumSamplesInOpaqueData();
	char* pRuleBook = new char[(ulNumEntries * ulNewRuleStrLen) + 1];
	if (pRuleBook)
	{
	    char* pTmp = pRuleBook;
	    for (UINT32 ulIi = 0; ulIi<ulNumEntries;
		    ulIi++, pTmp += ulNewRuleStrLen)
	    {
		memcpy(pTmp, pszNewRuleStr, ulNewRuleStrLen); /* Flawfinder: ignore */
	    }
	    *pTmp = '\0';
	}
	else
	{
	    retVal = HXR_OUTOFMEMORY;
	}

	// /Next, build the RuleToFlagMap so the renderer can map each
	// text sample (one per packet) to its sample description (array of
	// which is in the stream header's "OpaqueData" property):
	IHXBuffer* p3GPPTTRuleToFlagMapBuffer = NULL;
	if (SUCCEEDED(retVal)  &&  HXR_OK ==
		m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
		(void**)&p3GPPTTRuleToFlagMapBuffer))
	{
	    m_pRuleToFlagMap = new RuleToFlagMap;
	    m_pRuleToFlagMap->num_rules = (UINT16)ulNumEntries;

	    m_pRuleToFlagMap->rule_to_flag_map =
		    new UINT16[m_pRuleToFlagMap->num_rules];

	    // /Note: if more rules get added, above, this will need redoing:
	    for (UINT16 uiI = 0; uiI<m_pRuleToFlagMap->num_rules; uiI++)
	    {
		m_pRuleToFlagMap->rule_to_flag_map[uiI] = uiI;
	    }

	    p3GPPTTRuleToFlagMapBuffer->SetSize(sizeof(UINT16) +
		    (sizeof(UINT16) * m_pRuleToFlagMap->num_rules));

	    UINT32 ulSize;
	    // /Put it into network-order (Big-endian):
	    m_pRuleToFlagMap->pack(
		    p3GPPTTRuleToFlagMapBuffer->GetBuffer(), ulSize);

	    HX_ASSERT(ulSize == p3GPPTTRuleToFlagMapBuffer->GetSize());

	    m_pStreamHeader->SetPropertyBuffer(HX_3GPPTT_RULE_TO_FLAG_MAP_PROPERTY,
		    p3GPPTTRuleToFlagMapBuffer);

	    HX_RELEASE(p3GPPTTRuleToFlagMapBuffer);
	}


	if (SUCCEEDED(retVal))
	{
	    retVal = pASMRuleBook->Set((UCHAR*) pszNewRuleStr,
		    strlen(pszNewRuleStr) + 1);
	}

	if (SUCCEEDED(retVal))
	{
	    m_pStreamHeader->SetPropertyCString("ASMRuleBook", pASMRuleBook);
	}
    }
    HX_RELEASE(pASMRuleBook);


    if (m_pStreamHeader)
    {
	m_pStreamHeader->AddRef();
    }

    return retVal;
}



STDMETHODIMP
MP4TPayloadFormat::GetStreamHeader(REF(IHXValues*) pHeader)
{
    HX_RESULT retVal = HXR_FAIL;

    HX_ASSERT(m_pStreamHeader);
    if (m_pStreamHeader)
    {
	retVal = HXR_OK;
	pHeader = m_pStreamHeader;
	pHeader->AddRef();
    }

    return retVal;
}


STDMETHODIMP
MP4TPayloadFormat::SetPacket(IHXPacket* pOrigPacket)
{
    HX_RESULT retVal;

    HX_ASSERT(pOrigPacket);

    IHXBuffer* pBuffer = pOrigPacket->GetBuffer();
    if (!pBuffer  ||  !m_pTrackInfoMgr  ||  !m_pTrack)
    {
	HX_ASSERT(pBuffer);
	HX_ASSERT(m_pTrackInfoMgr);
	HX_ASSERT(m_pTrack);
	retVal = HXR_UNEXPECTED;
    }
    else
    {
	if (!m_bRTPPacketTested)
	{
	    IHXRTPPacket* pRTPPacket = NULL;

	    m_bUsesRTPPackets = (pOrigPacket->QueryInterface(
				    IID_IHXRTPPacket,
				    (void**) &pRTPPacket)
				== HXR_OK);

	    m_bRTPPacketTested = TRUE;

	    HX_RELEASE(pRTPPacket);

	    if (!m_bUsesRTPPackets)
            {
		m_ulSamplesPerSecond = _3GPPT_DEFAULT_SAMPLES_PER_SEC; // RDT time stamp
            }

	    HX_ASSERT(m_ulSamplesPerSecond != 0);

	    m_TSConverter.SetBase(m_ulSamplesPerSecond,
				  m_ulSamplesPerSecond);
	}

	// /Now, set the ASM rule # to map to the sample desc index:

	// / For 3GPP Text tracks, we'll use the ASM rule number to
	// map to the sample description index for the renderer's use:
	UINT32 ulSamplDescIndx = m_pTrack->GetLastSampleDescIdx();
	// Search through m_pRuleToFlagMap to find one whose flag
	// matches this sampleDescr index:
	// /First, see if it's a 1-1 mapping to save time in most cases:
	UINT16 uiASMRuleNum = 0;
	if (m_pRuleToFlagMap->rule_to_flag_map[ulSamplDescIndx] ==
		ulSamplDescIndx)
	{
	    uiASMRuleNum = (UINT16)ulSamplDescIndx;
        }
	else
	{
	    for (UINT16 uii=0; uii < m_pRuleToFlagMap->num_rules; uii++)
            {
		if (m_pRuleToFlagMap->rule_to_flag_map[uii] == ulSamplDescIndx)
                {
		    uiASMRuleNum = uii;
		    break; // /Found it
                }
            }
        }

#if defined(HELIX_FEATURE_3GPPTT_STREAMING)
	UINT32 ulTimeStamp = m_ulPriorPacketContentBeginTime;
#else
        // /Just make every packet a time-0 packet.  This will have to be
        // revisited as soon as we handle post-Rel5 version of 3GPP-TT.
        // Rel5 specifies that all packets should be delivered up front:
        // (Helps fix Helix Issue #667: allows for seeking without
        // packet-offset problems, and Negates Helix issue #675: allows
        // for "streaming" without packet-offset problems) :
        UINT32 ulTimeStamp = 0; 
#endif // /XXXEH_TESTING_FIXING_SEEKING_AND_STREAMING
        UINT32 ulRTPTime = pOrigPacket->GetTime();
	UINT16 uiStream = pOrigPacket->GetStreamNumber();
	UINT16 uiASMFlags = pOrigPacket->GetASMRuleNumber();


        if (!m_bUsesRTPPackets)
        {
            retVal = pOrigPacket->Set(pBuffer, ulTimeStamp, uiStream,
                    uiASMFlags, uiASMRuleNum);
        }
        else
        {
            // /Set the time stamp to the prior packet's time so it gets
            // to the renderer in time to set the prior packet's end time,
            // then set the RTP time to the begin time of the contents:
            retVal = ((IHXRTPPacket*) pOrigPacket) ->SetRTP(
                    pBuffer,
                    ulTimeStamp,
                    ulRTPTime,
                    uiStream,
                    uiASMFlags,
                    uiASMRuleNum);
        }

        m_ulPriorPacketContentBeginTime = ulRTPTime; // /Save for next pkt

	// Add this packet to our list of input packets
	pOrigPacket->AddRef();
	m_InputPackets.AddTail(pOrigPacket);
    }

    return retVal;
}

STDMETHODIMP
MP4TPayloadFormat::GetPacket(REF(IHXPacket*) pOutPacket)
{
    HX_RESULT retVal = HXR_OK;

    retVal = GetPacketizerPacket(pOutPacket);

    return retVal;
}

HX_RESULT
MP4TPayloadFormat::GetPacketizerPacket(IHXPacket* &pOutPacket)
{
    HX_RESULT retVal = HXR_INCOMPLETE;

    if (!m_InputPackets.IsEmpty())
    {
	pOutPacket = (IHXPacket*) m_InputPackets.RemoveHead();
	retVal = HXR_OK;
    }
    else if (m_bFlushed)
    {
	retVal = HXR_STREAM_DONE;
    }

    return retVal;
}

void
MP4TPayloadFormat::FlushPackets(ULONG32 ulCount)
{
    IHXPacket* pDeadPacket;

    while ((ulCount > 0) && (!m_InputPackets.IsEmpty()))
    {
	pDeadPacket = (IHXPacket*) m_InputPackets.RemoveHead();
	HX_RELEASE(pDeadPacket);
	if (ulCount != FLUSH_ALL_PACKETS)
	{
	    ulCount--;
	}
    }
}


STDMETHODIMP
MP4TPayloadFormat::Flush()
{
    m_bFlushed = TRUE;

    return HXR_OK;
}


ULONG32
MP4TPayloadFormat::GetPacketTime(IHXPacket* pPacket)
{
    ULONG32 ulTime;

    HX_ASSERT(pPacket);

    if (m_bUsesRTPPackets && (m_ulSamplesPerSecond != 0))
    {
	ulTime = ((IHXRTPPacket*) pPacket)->GetRTPTime();

	ulTime = m_TSConverter.Convert(ulTime);
    }
    else
    {
	ulTime = pPacket->GetTime();
    }

    return ulTime;
}

⌨️ 快捷键说明

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