amr-depack.cpp

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

CPP
589
字号
/* ***** 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 ***** */ 
 
#include "hlxclib/string.h"
#include "amr-depack.h"
#include "amr_toc.h"
#include "amr_rs_itr.h"
#include "bitstream.h"


AMRDepack::AMRDepack() :
    m_flavor(NarrowBand),
    m_ulTimestampInc(0),
    m_bOctetAlign(FALSE),
    m_ulModeSet(0),
    m_bHasCRC(FALSE),
    m_ulMaxInterleave(0),
    m_ulPtime(0),
    m_ulChannels(0),
    m_pUserData(0),
    m_pCallback(0),
    m_bPacketsLost(FALSE),
    m_bLastTimeValid(FALSE),
    m_ulLastTimestamp(0),
    m_ulIleavIndex(0),
    m_ulIleavLength(0),
    m_ulIleavBlockCount(0),
    m_ulIleavBaseTime(0)
{}

AMRDepack::~AMRDepack()
{}

BOOL AMRDepack::Init(AMRFlavor flavor,
		     BOOL    bOctetAlign,
		     ULONG32 ulModeSet,
		     ULONG32 ulChangePeriod,
		     BOOL    bChangeNeighbor,
		     ULONG32 ulMaxPtime,
		     BOOL    bHasCRC,
		     BOOL    bRobustSort,
		     ULONG32 ulMaxInterleave,
		     ULONG32 ulPtime,
		     ULONG32 ulChannels,
		     OnFrameCB pFrameCB,
		     void* pUserData)
{
    BOOL ret = FALSE;
    
    if ((pFrameCB) &&
	(ulChannels < 7) &&
	((flavor == NarrowBand) || (flavor == WideBand)))
    {
	m_flavor = flavor;

	if (ulChannels)
	    m_ulChannels = ulChannels;
	else
	    m_ulChannels = 1;
	
	if (ulModeSet)
	    m_ulModeSet = ulModeSet;
	else
	    m_ulModeSet = 0x81ff;
	
	m_ulPtime = ulPtime;

	m_pCallback = pFrameCB;
	m_pUserData = pUserData;
	
	ULONG32 ulMaxFrameBytes = 1 + ((GetMaxFrameBits() + 7) >> 3);

	m_blockBuf.Init(flavor, m_ulChannels);

	m_ulIleavIndex = 0;
	m_ulIleavLength = 0;

	if ((bOctetAlign) ||
	    (bHasCRC) ||
	    (bRobustSort) ||
	    (ulMaxInterleave))
	{
	    // Octet aligned mode
	    
	    m_bOctetAlign   = TRUE;
	    m_bHasCRC       = bHasCRC;
	    m_bRobustSort   = bRobustSort;
	    m_ulMaxInterleave = ulMaxInterleave;
	}
	else
	{
	    m_bOctetAlign     = FALSE;
	    m_bHasCRC         = FALSE;
	    m_bRobustSort     = FALSE;
	    m_ulMaxInterleave = 0;
	}

	ret = TRUE;
    }

    return ret;
}

BOOL AMRDepack::Reset() // Completely reset the depacketizer state
{
    m_bPacketsLost = FALSE;

    // Clear interleave state info
    m_ulIleavIndex = 0;
    m_ulIleavLength = 0;
    m_ulIleavBaseTime = 0;

    m_bLastTimeValid = FALSE;
    m_ulLastTimestamp = 0;

    return TRUE;
}

BOOL AMRDepack::Flush() // Indicates end of stream
{
    if (m_ulMaxInterleave > 0)
    {
	DispatchBlocks(m_ulIleavBaseTime);
    }

    return TRUE;
}

BOOL AMRDepack::OnPacket(ULONG32 ulTime, 
			 const UINT8* pData, ULONG32 ulSize, 
			 BOOL bMarker)
{
    BOOL bFailed = FALSE;

    Bitstream bs;

    bs.SetBuffer(pData);

    // Skip the CMR since we don't care about it
    if (m_bOctetAlign)
    {
	// 3GPP TS26.235 v5.0.0 Annex B Section B.4.4.1
	bs.GetBits(8);
    }
    else
    {
	// 3GPP TS26.235 v5.0.0 Annex B Section B.4.3.1
	bs.GetBits(4);
    }

    if (m_ulMaxInterleave > 0)
    {
	// 3GPP TS26.235 v5.0.0 Annex B Section B.4.4.1
	ULONG32 ulILL = bs.GetBits(4);
	ULONG32 ulILP = bs.GetBits(4);

	bFailed = !UpdateIleavInfo(ulILL, ulILP, ulTime);
    }
    
    if (bFailed == FALSE)
    {
	AMRTOCInfo tocInfo;

	GetTOCInfo(bs, tocInfo);

	if (m_bHasCRC)
	{
	    // 3GPP TS26.235 v5.0.0 Annex B Section B.4.4.2.1
	    SkipCRCInfo(bs, tocInfo);
	}

	// Update the block count to make sure we have
	// enough space in m_blockBuf for this data
	UpdateBlockCount(tocInfo.EntryCount() / m_ulChannels);


	ULONG32 ulStartBlock = 0;
	ULONG32 ulBlockInc = 1;

	// Adjust the ulStartBlock and ulBlockInc if the
	// data is interleaved
	if (m_ulMaxInterleave > 0)
	{
	    ulStartBlock = m_ulIleavIndex;
	    ulBlockInc = m_ulIleavLength;
	}

	if (m_bRobustSort)
	{
	    // Copy robust sorted frame data to m_blockBuf
	    SortedCopy(bs, ulStartBlock, ulBlockInc, tocInfo);
	}
	else
	{
	    // Copy linear frame data to m_blockBuf
	    LinearCopy(bs, ulStartBlock, ulBlockInc, tocInfo);
	}

	if (m_ulMaxInterleave > 0)
	{
	    // We are deinterleaving.
	    // Increment the interleave index now
	    // that we are done with this packet.
	    m_ulIleavIndex++;

	    // See if we have all the packets in this
	    // interleave block
	    if (m_ulIleavIndex == m_ulIleavLength)
	    {
		// Yep. Dispatch the frame blocks
		DispatchBlocks(m_ulIleavBaseTime);
	    }
	}
	else
	{
	    // This data is not interleaved so
	    // dispatch it now
	    DispatchBlocks(ulTime);
	}
    }

    return !bFailed;
}

BOOL AMRDepack::OnLoss(ULONG32 ulNumPackets) // called to indicate lost packets
{
    if (m_ulMaxInterleave > 0)
    {
	ULONG32 delta = m_ulIleavLength - m_ulIleavIndex;

	if (ulNumPackets < delta)
	{
	    // We have lost only a few blocks in the middle
	    m_ulIleavIndex += ulNumPackets;
	}
	else
	{
	    // We have lost all the remaining blocks
	    // in the current interleave block.
	    // Dispatch what we have
	    DispatchBlocks(m_ulIleavBaseTime);
	}
    }
    else
	m_bPacketsLost = TRUE;

    return TRUE;
}

void AMRDepack::SetTSSampleRate(ULONG32 ulTSSampleRate)
{
    // Determine the number of timestamp units to increment
    // per frame.
    m_ulTimestampInc = (CAMRFrameInfo::FrameDuration() * ulTSSampleRate) / 1000;
}

BOOL AMRDepack::UpdateIleavInfo(ULONG32 ulILL, ULONG32 ulILP, ULONG32 ulTime)
{
    BOOL bFailed = FALSE;

    if ((ulILP > ulILL) ||
	((m_ulIleavLength != 0) &&
	 (ulILP != m_ulIleavIndex)))
    {
	bFailed = TRUE;
    }
    else if (ulILP == 0)
    {
	// This is the expected case
	
	m_ulIleavIndex = 0;
	m_ulIleavLength = ulILL + 1;
	
	m_ulIleavBaseTime = ulTime;
    }
    else if (m_ulIleavLength == 0)
    {
	// This case occurs when loss happens
	
	m_ulIleavIndex = ulILP;
	m_ulIleavLength = ulILL + 1;
	
	// We need the base time to be valid even if we
	// do not start at the beginning of a superblock
	// Each packet starts 1 frame later than
	// the previous one.
	m_ulIleavBaseTime = ulTime - (m_ulTimestampInc) * m_ulIleavIndex;
    }

    return !bFailed;
}

void AMRDepack::GetTOCInfo(Bitstream& bs, AMRTOCInfo& tocInfo)
{
    ULONG32 ulTocBits;
    ULONG32 ulTocMask;
    
    ULONG32 ulShift;

    if (m_bOctetAlign)
    {
	// This header is defined in
	// 3GPP TS26.235 v5.0.0 Annex B Section B.4.4.2
	//   7   6   5   4   3   2   1   0
	// +---+---------------+---+---+---+
	// | F |       FT      | Q | P | P |
	// +---+---------------+---+---+---+
	//
	// F  = more frames flag
	// FT = frame type
	// Q  = quality indicator
	// P  = padding

	ulTocBits = 8;
	ulTocMask = 0x80;
	ulShift = 2;
    }
    else
    {
	// This header is defined in
	// 3GPP TS26.235 v5.0.0 Annex B Section B.4.3.2
	//   5   4   3   2   1   0
	// +---+---------------+---+
	// | F |       FT      | Q |
	// +---+---------------+---+
	//
	// F  = more frames flag
	// FT = frame type
	// Q  = quality indicator
	ulTocBits = 6;
	ulTocMask = 0x20;
	ulShift = 0;
    }
    
    BOOL bDone = FALSE;

    while(!bDone)
    {
	ULONG32 entry = bs.GetBits(ulTocBits);
	UINT8 type = (UINT8)(entry >> (ulShift + 1)) & 0x0f;
	UINT8 quality = (UINT8)(entry >> ulShift) & 0x01;
	
	tocInfo.AddInfo(type, quality);
	
	if ((entry & ulTocMask) == 0)
	    bDone = TRUE;
    }    
}

void AMRDepack::SkipCRCInfo(Bitstream& bs, const AMRTOCInfo& tocInfo)
{
    // Skip CRCs if they are present since we don't
    // care about them.
    for (ULONG32 i = 0; i < tocInfo.EntryCount(); i++)
    {
	if (tocInfo.GetType(i)  < 14)
	    bs.GetBits(8);
    }
}


void AMRDepack::UpdateBlockCount(ULONG32 ulBlockCount)
{
    if (m_ulMaxInterleave > 0)
    {
	if (m_ulIleavIndex == 0)
	{
	    m_ulIleavBlockCount = ulBlockCount;
	    
	    // Make sure we have enough block space in the
	    // buffer
	    m_blockBuf.SetBlockCount(m_ulIleavBlockCount * m_ulIleavLength);
	}
    }
    else
    {
	// Make sure we have enough block space in the
	// buffer for this packet
	m_blockBuf.SetBlockCount(ulBlockCount);
    }
}

void AMRDepack::LinearCopy(Bitstream& bs, 
			   ULONG32 ulStartBlock, ULONG32 ulBlockInc,
			   const AMRTOCInfo& tocInfo)
{
    ULONG32 ulBlockIndex = ulStartBlock;
    ULONG32 ulFrameIndex = 0;
    
    for (ULONG32 j = 0; j < m_blockBuf.GetBlockCount(); j++)
    {
	UINT8* pStart = m_blockBuf.GetBlockBuf(ulBlockIndex);
	
	ULONG32 ulFrameSize = GetFrameBlock(bs,
					    pStart, 
					    tocInfo, ulFrameIndex,
					    m_ulChannels);
	
	if (ulFrameSize)
	{
	    // Store frame size information
	    m_blockBuf.SetBlockSize(ulBlockIndex, ulFrameSize);
	    
	    // Update the block index
	    ulBlockIndex += ulBlockInc;
	    
	    // Update the frame index. Each frame block
	    // consumes m_ulChannels frames
	    ulFrameIndex += m_ulChannels;
	}
	else
	    break;
    }
}

ULONG32 AMRDepack::GetFrameBlock(Bitstream& bs,
				 UINT8* pStart, 
				 const AMRTOCInfo& tocInfo,
				 ULONG32 ulStartEntry,
				 ULONG32 ulChannels)
{
    ULONG32 ulRet = 0;

    ULONG32 ulEnd = ulChannels + ulStartEntry;

    if (ulEnd <= tocInfo.EntryCount())
    {
	BOOL bFailed = FALSE;
	UINT8* pCurrent = pStart;

	for (ULONG32 i = ulStartEntry; i < ulEnd; i++)
	{
	    ULONG32 ulFrameType = tocInfo.GetType(i);
	    
	    if ((ulFrameType < 9) || (ulFrameType == 15))
	    {
		ULONG32 ulFrameBits = GetFrameBits(ulFrameType);
		ULONG32 ulFrameBytes = (ulFrameBits + 7) >> 3;
		
		if (m_bOctetAlign)
		{
		    // Octet Aligned contains padding already
		    ulFrameBits = ulFrameBytes << 3;
		}

		// Create frame header.
		// This header is defined in
                // 3GPP TS26.235 v5.0.0 Annex B Section B.5.3
                //   7   6   5   4   3   2   1   0
                // +---+---------------+---+---+---+
                // | P |       FT      | Q | P | P |
                // +---+---------------+---+---+---+
                //
                // P  = padding
                // FT = frame type
                // Q  = quality indicator
		*pCurrent++ = (UINT8)((ulFrameType << 3) | 
				      (tocInfo.GetQuality(i) << 2));

		if (ulFrameBytes > 0)
		{
		    // Set last byte of frame to 0 for padding
		    pCurrent[ulFrameBytes - 1] = 0;
		    
		    // Copy frame bits into the buffer
		    bs.GetBits(ulFrameBits, pCurrent);

		    // Move current pointer to just past this frame
		    pCurrent += ulFrameBytes;
		}
	    }
	    else
	    {
		bFailed = TRUE;
		break;
	    }
	}

	if (bFailed == FALSE)
	    ulRet = pCurrent - pStart;
    }

    return ulRet;
}

void AMRDepack::SortedCopy(Bitstream& bs, 
			   ULONG32 ulStartBlock, ULONG32 ulBlockInc,
			   const AMRTOCInfo& tocInfo)
{
    // This function copies robust sorted data from the packet.
    // Unfortunately this is not very efficient because the bytes
    // of each frame are interleaved with eachother. The
    // AMRRobustSortingItr class provides us with the block number
    // and block byte offset for each byte in the sorted data.

    AMRRobustSortingItr itr;

    itr.Init(m_flavor, m_ulChannels, ulStartBlock, ulBlockInc, tocInfo);

    for (;itr.More(); itr.Next())
    {
	UINT8* pDest = m_blockBuf.GetBlockBuf(itr.Block()) + itr.Offset();

	// Copy the byte
	*pDest = (UINT8)bs.GetBits(8);
    }
}

void AMRDepack::DispatchFrameBlock(ULONG32 ulTimestamp,
				   const UINT8* pFrame, ULONG32 ulFrameSize)
{
    // We can get duplicate frames so we need to make
    // a check to see if we have already sent this frame
    if (((m_bLastTimeValid == FALSE) ||
	 (ulTimestamp > m_ulLastTimestamp)) &&
	(m_pCallback))
    {
	m_pCallback(m_pUserData,
		    ulTimestamp,
		    pFrame, ulFrameSize,
		    m_bPacketsLost);
	
	// Update last timestamp
	m_ulLastTimestamp = ulTimestamp;
	m_bLastTimeValid = TRUE;
    }
    
    // Clear packet flag
    m_bPacketsLost = FALSE;
}

void AMRDepack::DispatchBlocks(ULONG32 ulTimestamp)
{
    for (ULONG32 i = 0; i < m_blockBuf.GetBlockCount(); i++)
    {
	ULONG32 ulFrameSize = m_blockBuf.GetBlockSize(i);
	
	if (ulFrameSize)
	{
	    DispatchFrameBlock(ulTimestamp, 
			       m_blockBuf.GetBlockBuf(i), ulFrameSize);
	}
	else
	{
	    // Signal that loss has occured
	    m_bPacketsLost = TRUE;
	}

	// Increment the timestamp
	ulTimestamp += m_ulTimestampInc;
    }
    
    // Clear interleave state info
    m_ulIleavIndex = 0;
    m_ulIleavLength = 0;
}

⌨️ 快捷键说明

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