qtatmmgs.cpp

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

CPP
2,238
字号
/* ***** 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 _IGNORE_MP4_AUDIO

#define TRACK_SDP_CHUNK_SIZE	512

/****************************************************************************
 *  Includes
 */
#include "qtatmmgs.h"
#include "qttrkmgr.h"
#include "mp4desc.h"
#include "hxstrutl.h"

#include "rtptypes.h"
#include "rtsputil.h"

#ifndef QTCONFIG_SPEED_OVER_SIZE
#include "qtatmmgs_inline.h"
#endif	// QTCONFIG_SPEED_OVER_SIZE

/****************************************************************************
 *  Track Edit Manager
 */
#define QT_MAX_MOVIE_DURATION	0xFFFFFFFF

/****************************************************************************
 *  Constructor/Destructor
 */
CQT_TrackEdit_Manager::CQT_TrackEdit_Manager(void)
    : m_pEditListAtom(NULL)
    , m_ulMovieTimeScale(1)
    , m_ulMediaTimeScale(1)
    , m_ulNumEdits(0)
    , m_ulCurrentEditIdx(0)
    , m_ulCurrentEditTime(0)
    , m_ulCurrentInEditTime(0)
    , m_ulCurrentEditDuration(QT_MAX_MOVIE_DURATION)
    , m_ulCurrentMediaStartTime(0)
{
    ;
}

CQT_TrackEdit_Manager::~CQT_TrackEdit_Manager(void)
{
    HX_RELEASE(m_pEditListAtom);
}

/****************************************************************************
 *  Main Interface
 */
/****************************************************************************
 *  Init
 */
HX_RESULT CQT_TrackEdit_Manager::Init(CQTAtom* pAtom,
				      ULONG32 ulMovieTimeScale,
				      ULONG32 ulMediaTimeScale)
{
    HX_RESULT retVal = HXR_OK;

    HX_ASSERT(ulMovieTimeScale);
    HX_ASSERT(ulMediaTimeScale);
    
    m_ulMovieTimeScale = ulMovieTimeScale;
    m_ulMediaTimeScale = ulMediaTimeScale;
    m_ulNumEdits = 0;
    
    HX_RELEASE(m_pEditListAtom);

    if (pAtom)
    {
	if (pAtom->GetType() == QT_elst)
	{
	    m_pEditListAtom = (CQT_elst_Atom*) pAtom;
	}
	else
	{
	    m_pEditListAtom = (CQT_elst_Atom*) pAtom->FindPresentChild(QT_elst);
	}

	if (m_pEditListAtom)
	{
	    m_pEditListAtom->AddRef();
	    m_ulNumEdits = m_pEditListAtom->Get_NumEntries();
	}
    }

    if (!EstablishByTime(0))
    {
	retVal = HXR_FAIL;

	// Reset State
	HX_RELEASE(m_pEditListAtom);
	m_ulNumEdits = 0;
	EstablishByTime(0);
    }

    return retVal;
}


/****************************************************************************
 *  EstablishByMovieTime
 */
BOOL CQT_TrackEdit_Manager::EstablishByTime(ULONG32 ulTime)
{
    m_ulCurrentEditIdx = 0;
    m_ulCurrentEditTime = 0;
    m_ulCurrentInEditTime = (ULONG32) (ulTime / 1000.0 *
				       m_ulMediaTimeScale +
				       0.5);

    if (m_ulNumEdits > 0)
    {
	m_ulCurrentEditDuration = MovieToMediaUnits(
				    m_pEditListAtom->Get_TrackDuration(0));
	m_ulCurrentMediaStartTime = m_pEditListAtom->Get_MediaTime(0);
	return SequenceToEdit();
    }
    else
    {
	m_ulCurrentEditDuration = QT_MAX_MOVIE_DURATION;
	m_ulCurrentMediaStartTime = 0;
    }

    return TRUE;
}

/****************************************************************************
 *  Private Methods
 */
/****************************************************************************
 *  SequenceToEdit
 */
BOOL CQT_TrackEdit_Manager::SequenceToEdit(void)
{
    while ((m_ulCurrentMediaStartTime == QT_EMPTY_EDIT) ||
	   (m_ulCurrentInEditTime >= m_ulCurrentEditDuration))
    {
	m_ulCurrentEditIdx++;

	if (m_ulCurrentEditIdx < m_ulNumEdits)
	{
	    if (m_ulCurrentMediaStartTime != QT_EMPTY_EDIT)
	    {
		m_ulCurrentInEditTime -= m_ulCurrentEditDuration;
	    }
	    m_ulCurrentEditTime += m_ulCurrentEditDuration;
	    m_ulCurrentEditDuration = MovieToMediaUnits(
					m_pEditListAtom->Get_TrackDuration(
					    m_ulCurrentEditIdx));
	    m_ulCurrentMediaStartTime = m_pEditListAtom->Get_MediaTime(
					    m_ulCurrentEditIdx);
	}
	else
	{
	    m_ulCurrentEditIdx--;
	    return FALSE;
	}
    }

    return TRUE;
}


/****************************************************************************
 *  Sample To Chunk Manager
 */
#define QT_MAX_SAMPLES_PER_CHUNK	0xFFFFFFFF
#define QT_NULL_CHUNK_NUM		0

/****************************************************************************
 *  Constructor/Destructor
 */
CQT_SampleToChunk_Manager::CQT_SampleToChunk_Manager(void)
    : m_ulNumEntries(0)
    , m_pSampleToChunkAtom(NULL)
    , m_ulSampleInChunkNum(0)
    , m_ulCurrentChunk(0)
    , m_ulNextEntryChunk(QT_NULL_CHUNK_NUM)
    , m_ulCurrentEntryIdx(0)
    , m_ulSamplesPerChunk(QT_MAX_SAMPLES_PER_CHUNK)
    , m_ulSampleNumber(0)
    , m_ulSampleDescIdx(QT_BAD_IDX)
#ifdef _STCO_ZERO_BASED_IQ
    , m_ulChunkNumOffset(0)
#endif	// _STCO_ZERO_BASED_IQ
{
    ;
}

CQT_SampleToChunk_Manager::~CQT_SampleToChunk_Manager()
{
    HX_RELEASE(m_pSampleToChunkAtom);
}

/****************************************************************************
 *  Init
 */
HX_RESULT CQT_SampleToChunk_Manager::Init(CQTAtom* pAtom)
{
    HX_RESULT retVal = HXR_OK;

    HX_RELEASE(m_pSampleToChunkAtom);
    m_ulNumEntries = 0;
    m_ulSampleNumber = 0;

    if (pAtom)
    {
	if (pAtom->GetType() == QT_stsc)
	{
	    m_pSampleToChunkAtom = (CQT_stsc_Atom*) pAtom;
	}
	else
	{
	    m_pSampleToChunkAtom = (CQT_stsc_Atom*) pAtom->FindPresentChild(QT_stsc);
	}

	if (m_pSampleToChunkAtom)
	{
	    m_pSampleToChunkAtom->AddRef();
	    m_ulNumEntries = m_pSampleToChunkAtom->Get_NumEntries();
	}
    }

    if (m_ulNumEntries == 0)
    {
	EstablishBySample(0);
	retVal = HXR_NO_DATA;
    }
    else
    {
	m_ulSampleNumber = 2;  // Force full initialization
	retVal = EstablishBySample(1) ? HXR_OK : HXR_FAIL;

#ifdef _STCO_ZERO_BASED_IQ
	m_ulChunkNumOffset = 0;

	if (retVal == HXR_OK)
	{
	    if ((m_ulCurrentChunk == 0) ||
		(m_ulSampleDescIdx == ((ULONG32) -1)))
	    {
		m_ulCurrentChunk = 1;
		m_ulNextEntryChunk++;
		m_ulSampleDescIdx++;
		m_ulChunkNumOffset = 1;
	    }
	}
#endif	// _STCO_ZERO_BASED_IQ
    }

    return retVal;
}

/****************************************************************************
 *  EstablishBySample
 */
BOOL CQT_SampleToChunk_Manager::EstablishBySample(ULONG32 ulSampleNum)
{
    if (m_ulNumEntries > 0)
    {
	HX_ASSERT(ulSampleNum);

	if (ulSampleNum >= m_ulSampleNumber)
	{
	    // Search Forward
	    m_ulSampleInChunkNum += (ulSampleNum - m_ulSampleNumber);
	    m_ulSampleNumber = ulSampleNum;

	    return SequenceToChunk();
	}
	else if (ulSampleNum > (m_ulSampleNumber >> 1))
	{
	    // Search in Reverse
	    m_ulSampleInChunkNum = m_ulSamplesPerChunk -
				   m_ulSampleInChunkNum +
				   m_ulSampleNumber -
				   ulSampleNum +
				   1;
	    m_ulSampleNumber = ulSampleNum;

	    if (SequenceReverseToChunk())
	    {
		m_ulSampleInChunkNum = m_ulSamplesPerChunk -
				       m_ulSampleInChunkNum +
				       1;

		return TRUE;
	    }
	}
	else
	{
	    // Search Forward from the beginning
	    m_ulSampleInChunkNum = ulSampleNum;
	    m_ulCurrentEntryIdx = 0;
	    m_ulCurrentChunk = m_pSampleToChunkAtom->Get_FirstChunk(0)
#ifdef _STCO_ZERO_BASED_IQ
			       + m_ulChunkNumOffset
#endif	// _STCO_ZERO_BASED_IQ
			       ;
	    m_ulSamplesPerChunk = m_pSampleToChunkAtom->Get_SamplesPerChunk(0);
	    m_ulSampleDescIdx = m_pSampleToChunkAtom->Get_SampleDescID(0) - 1
#ifdef _STCO_ZERO_BASED_IQ
			        + m_ulChunkNumOffset
#endif	// _STCO_ZERO_BASED_IQ
			       ;

	    if (m_ulNumEntries > 1)
	    {
		m_ulNextEntryChunk = m_pSampleToChunkAtom->
		    Get_FirstChunk(1)
#ifdef _STCO_ZERO_BASED_IQ
		    + m_ulChunkNumOffset
#endif	// _STCO_ZERO_BASED_IQ
		    ;
	    }
	    else
	    {
		// No more chunk entries
		m_ulNextEntryChunk = QT_NULL_CHUNK_NUM;
	    }

	    m_ulSampleNumber = ulSampleNum;

	    return SequenceToChunk();
	}
    }	
    else
    {
	m_ulSampleNumber = 0;
	m_ulSampleInChunkNum = 0;
	m_ulCurrentChunk = 0;
	m_ulSamplesPerChunk = QT_MAX_SAMPLES_PER_CHUNK;
	m_ulSampleDescIdx = QT_BAD_IDX;
#ifdef _STCO_ZERO_BASED_IQ
	m_ulChunkNumOffset = 0;
#endif	// _STCO_ZERO_BASED_IQ
    }

    return FALSE;
}

/****************************************************************************
 *  Private Methods
 */
/****************************************************************************
 *  SequenceToChunk
 */
#ifdef STCMGR_USE_MODULUS_SEQUENCING

// This sequencing algorithm has better efficiency (than non-modulus 
// sequencing) on files containing many chunks per table entry and/or those 
// whose progression through the table is irratic (has skipps).
BOOL CQT_SampleToChunk_Manager::SequenceToChunk(void)
{
    ULONG32 ulTargetChunk;
    BOOL bEntryIdxChanged;

    if (m_ulSampleInChunkNum > m_ulSamplesPerChunk)
    {
	bEntryIdxChanged = FALSE;

	do
	{
	    if (m_ulSamplesPerChunk == 0)
	    {
		ulTargetChunk = m_ulCurrentChunk + 1;
	    }
	    else
	    {
		ulTargetChunk = m_ulCurrentChunk +
		    		(m_ulSampleInChunkNum - 1) /
				m_ulSamplesPerChunk;
	    }

	    if ((ulTargetChunk >= m_ulNextEntryChunk) &&
		(m_ulNextEntryChunk != QT_NULL_CHUNK_NUM))
	    {
		m_ulSampleInChunkNum -= (m_ulNextEntryChunk -
					 m_ulCurrentChunk) *
					m_ulSamplesPerChunk;
		m_ulCurrentChunk = m_ulNextEntryChunk;
		m_ulCurrentEntryIdx++;
		bEntryIdxChanged = TRUE;

		m_ulSamplesPerChunk = m_pSampleToChunkAtom->
		    Get_SamplesPerChunk(m_ulCurrentEntryIdx);
		
		if ((m_ulCurrentEntryIdx + 1) < m_ulNumEntries)
		{
		    m_ulNextEntryChunk = m_pSampleToChunkAtom->
			Get_FirstChunk(m_ulCurrentEntryIdx + 1);
		}
		else
		{
		    // No more chunk entries
		    m_ulNextEntryChunk = QT_NULL_CHUNK_NUM;
		}
	    }
	    else
	    {
		m_ulCurrentChunk = ulTargetChunk;
		if (m_ulSamplesPerChunk != 0)
		{  
		    m_ulSampleInChunkNum = (m_ulSampleInChunkNum - 1) %
					    m_ulSamplesPerChunk +
					    1;
		}
		else
		{
		    // encountered empty chunk at the end of table
		    return FALSE;
		}
	    }
	} while (m_ulSampleInChunkNum > m_ulSamplesPerChunk);

	if (bEntryIdxChanged)
	{
	    m_ulSampleDescIdx = m_pSampleToChunkAtom->
		Get_SampleDescID(m_ulCurrentEntryIdx) - 1
#ifdef _STCO_ZERO_BASED_IQ
		+ m_ulChunkNumOffset
#endif	// _STCO_ZERO_BASED_IQ
			       ;
	}
    }

    return TRUE;
}

#else	// STCMGR_USE_MODULUS_SEQUENCING

// This sequencing algorithm is more efficient for files
// containing fewer chunks per table entry and/or those
// whose progression through the chunks involves fewer
// skipps.
BOOL CQT_SampleToChunk_Manager::SequenceToChunk(void)
{
    BOOL bEntryIdxChanged;

    if (m_ulSampleInChunkNum > m_ulSamplesPerChunk)
    {
	bEntryIdxChanged = FALSE;

	do
	{
	    m_ulSampleInChunkNum = m_ulSampleInChunkNum - m_ulSamplesPerChunk;
	    m_ulCurrentChunk++;
	    
	    if (m_ulCurrentChunk == m_ulNextEntryChunk)
	    {
		m_ulCurrentEntryIdx++;
		bEntryIdxChanged = TRUE;
		
		m_ulSamplesPerChunk = m_pSampleToChunkAtom->
		    Get_SamplesPerChunk(m_ulCurrentEntryIdx);
		
		if ((m_ulCurrentEntryIdx + 1) < m_ulNumEntries)
		{
		    m_ulNextEntryChunk = m_pSampleToChunkAtom->
			Get_FirstChunk(m_ulCurrentEntryIdx + 1)
#ifdef _STCO_ZERO_BASED_IQ
			+ m_ulChunkNumOffset
#endif	// _STCO_ZERO_BASED_IQ
			;
		}
		else
		{
		    // No more chunk entries
		    m_ulNextEntryChunk = QT_NULL_CHUNK_NUM;
		}
	    }
	    else if ((m_ulSamplesPerChunk == 0) && 
		(m_ulNextEntryChunk == QT_NULL_CHUNK_NUM))
	    {
		return FALSE;
	    }
	} while (m_ulSampleInChunkNum > m_ulSamplesPerChunk);

	if (bEntryIdxChanged)
	{
	    m_ulSampleDescIdx = m_pSampleToChunkAtom->
		Get_SampleDescID(m_ulCurrentEntryIdx) - 1
#ifdef _STCO_ZERO_BASED_IQ
		+ m_ulChunkNumOffset
#endif	// _STCO_ZERO_BASED_IQ
		;
	}
    }

    return TRUE;
}

#endif	// STCMGR_USE_MODULUS_SEQUENCING

/****************************************************************************
 *  SequenceReverseToChunk
 */
BOOL CQT_SampleToChunk_Manager::SequenceReverseToChunk(void)
{
    ULONG32 ulEntryFirstChunk;
    BOOL bEntryIdxChanged;

    if (m_ulSampleInChunkNum > m_ulSamplesPerChunk)
    {
	bEntryIdxChanged = FALSE;

	ulEntryFirstChunk = m_pSampleToChunkAtom->
	    Get_FirstChunk(m_ulCurrentEntryIdx);

	do
	{
	    m_ulSampleInChunkNum = m_ulSampleInChunkNum - m_ulSamplesPerChunk;
	    m_ulCurrentChunk--;
	    
	    if (m_ulCurrentChunk < ulEntryFirstChunk)
	    {
		if (m_ulCurrentEntryIdx == 0)
		{
		    return FALSE;
		}

		m_ulCurrentEntryIdx--;

⌨️ 快捷键说明

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