📄 vbrdepack.cpp
字号:
/* ***** 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 "hxtypes.h"
#include "hxcom.h"
#include "ihxpckts.h"
#include "hxcomm.h"
#include "hxslist.h"
#include "vbrdepack.h"
CVBRSimpleDepacketizer::CVBRSimpleDepacketizer()
{
m_pCommonClassFactory = NULL;
m_pFragQueue = NULL;
m_pOutputQueue = NULL;
m_dAUDuration = 0.0;
m_usStreamNum = 0;
m_usKeyFrameRuleNum = 0;
m_ulLastQueuedPacketEndTime = 0;
m_bSeeked = FALSE;
m_bGenerateLossPackets = TRUE;
}
CVBRSimpleDepacketizer::~CVBRSimpleDepacketizer()
{
ClearQueue(m_pFragQueue);
ClearQueue(m_pOutputQueue);
HX_RELEASE(m_pCommonClassFactory);
HX_DELETE(m_pFragQueue);
HX_DELETE(m_pOutputQueue);
}
HX_RESULT CVBRSimpleDepacketizer::Init(IUnknown* pContext, double dAUDuration,
UINT16 usStreamNum, UINT16 usKeyFrameRuleNum,
BOOL bGenerateLossPackets)
{
HX_RESULT retVal = HXR_FAIL;
if (pContext)
{
// Save the AU duration
m_dAUDuration = dAUDuration;
// Save the stream num
m_usStreamNum = usStreamNum;
// Save the keyframe rule num
m_usKeyFrameRuleNum = usKeyFrameRuleNum;
// Save the loss packets flag
m_bGenerateLossPackets = bGenerateLossPackets;
// Get the common class factory
HX_RELEASE(m_pCommonClassFactory);
retVal = pContext->QueryInterface(IID_IHXCommonClassFactory,
(void**) &m_pCommonClassFactory);
if (SUCCEEDED(retVal))
{
// Zero out the last queued packet end time
m_ulLastQueuedPacketEndTime = 0;
// Clear the seeked flag
m_bSeeked = FALSE;
}
}
return retVal;
}
HX_RESULT CVBRSimpleDepacketizer::PutPacket(IHXPacket* pPacket)
{
HX_RESULT retVal = HXR_FAIL;
if (pPacket)
{
// Is the packet lost?
if (!pPacket->IsLost())
{
// Get the IHXBuffer
IHXBuffer* pBuffer = pPacket->GetBuffer();
if (pBuffer)
{
// Get the buffer
BYTE* pBuf = pBuffer->GetBuffer();
if (pBuf)
{
// Parse the packet
UINT32 ulNumAU = 0;
BOOL bFragmented = FALSE;
retVal = ParseVBRPacket(pBuf, pBuffer->GetSize(), ulNumAU, bFragmented);
if (SUCCEEDED(retVal))
{
// Check if we have a gap in timestamps. However, if
// we seeked we don't want to interpret this as a
// gap in timestamps
if (pPacket->GetTime() > (m_ulLastQueuedPacketEndTime + TIMESTAMP_GAP_FUDGE_FACTOR) &&
!m_bSeeked)
{
// We probably had some loss, so we need to queue
// some loss packets
if (m_bGenerateLossPackets)
{
retVal = GenerateAndQueueLossPackets(m_ulLastQueuedPacketEndTime,
pPacket->GetTime());
}
if (SUCCEEDED(retVal))
{
// Update the last queued packet end time
m_ulLastQueuedPacketEndTime = pPacket->GetTime();
}
}
// If m_bSeeked == TRUE, then this is the
// first packet we've received after the seek.
if (m_bSeeked)
{
// Clear the frag queue
ClearQueue(m_pFragQueue);
// Set the last queued packet end time to be
// the current time. Otherwise, if this packet
// is a fragmented packet, then the next packet
// will be interpreted as loss.
m_ulLastQueuedPacketEndTime = pPacket->GetTime();
// Clear the seek flag
m_bSeeked = FALSE;
}
// Is this a fragmented AU?
if (bFragmented)
{
// Remove any packets from the frag queue
// which do not have the same timestamp
// as this packet. These were probably packets
// which were left over from a previous lost
// fragmented AU.
RemoveDifferingPackets(pPacket->GetTime());
// If this is a fragmented packet, then we
// add it to the frag queue
retVal = AddToQueue(m_pFragQueue, pPacket);
if (SUCCEEDED(retVal))
{
// Attempt to defrag the AU from the packets
// on the frag queue
if (CanDefrag())
{
IHXPacket* pOutPacket = NULL;
retVal = Defrag(pOutPacket);
if (SUCCEEDED(retVal))
{
// We successfully generated a defragmented
// packet, so we can clear the frag queue
ClearQueue(m_pFragQueue);
// Add the packet to the output queue
retVal = AddToQueue(m_pOutputQueue, pOutPacket);
if (SUCCEEDED(retVal))
{
// Set the end time of the last packet
// that we put in the output queue
m_ulLastQueuedPacketEndTime = pOutPacket->GetTime() + ((UINT32) m_dAUDuration);
}
}
HX_RELEASE(pOutPacket);
}
}
}
else
{
// This is NOT a fragmented packet
//
// We can clear the frag queue. If there was no
// loss in the last fragmented AU, then it was
// cleared after the packet was created. If there
// WAS loss in the last fragmented AU, then we
// just handled it by generating loss packets.
ClearQueue(m_pFragQueue);
// Step through the packet creating packets
UINT32 ulAUDataSizeSum = 0;
for (UINT32 i = 0; i < ulNumAU && SUCCEEDED(retVal); i++)
{
UINT32 ulAUSize = UnPackUINT16(pBuf + 2 + (i << 1));
UINT32 ulTSOffset = (UINT32) (i * m_dAUDuration);
IHXPacket* pOutPacket = NULL;
retVal = CreatePacket(pBuf + 2 + ulNumAU * 2 + ulAUDataSizeSum,
ulAUSize,
pPacket->GetTime() + ulTSOffset,
FALSE,
pOutPacket);
if (SUCCEEDED(retVal))
{
// Add the packet to the output queue
retVal = AddToQueue(m_pOutputQueue, pOutPacket);
if (SUCCEEDED(retVal))
{
ulAUDataSizeSum += ulAUSize;
}
}
HX_RELEASE(pOutPacket);
}
if (SUCCEEDED(retVal))
{
// Set the end time of the last packet
// that we put in the output queue
UINT32 ulTSOffset = (UINT32) (ulNumAU * m_dAUDuration);
m_ulLastQueuedPacketEndTime = pPacket->GetTime() + ulTSOffset;
}
}
}
}
}
HX_RELEASE(pBuffer);
}
else
{
// The packet is lost, but don't return failure
retVal = HXR_OK;
}
}
return retVal;
}
HX_RESULT CVBRSimpleDepacketizer::GetPacket(REF(IHXPacket*) rpPacket)
{
HX_RESULT retVal = HXR_FAIL;
if (m_pOutputQueue && m_pOutputQueue->GetCount() > 0)
{
// Get the head packet
IHXPacket* pPacket = (IHXPacket*) m_pOutputQueue->RemoveHead();
if (pPacket)
{
HX_RELEASE(rpPacket);
rpPacket = pPacket;
rpPacket->AddRef();
retVal = HXR_OK;
}
HX_RELEASE(pPacket);
}
return retVal;
}
HX_RESULT CVBRSimpleDepacketizer::OnSeek(UINT32 ulOldTime, UINT32 ulNewTime)
{
HX_RESULT retVal = HXR_OK;
// Set the seeked flag
m_bSeeked = TRUE;
return retVal;
}
void CVBRSimpleDepacketizer::ClearQueue(CHXSimpleList* pList)
{
if (pList)
{
LISTPOSITION pos = pList->GetHeadPosition();
while (pos)
{
IHXPacket* pPacket = (IHXPacket*) pList->GetNext(pos);
HX_RELEASE(pPacket);
}
pList->RemoveAll();
}
}
HX_RESULT CVBRSimpleDepacketizer::CreatePacket(BYTE* pBuf,
UINT32 ulSize,
UINT32 ulTime,
BOOL bLost,
REF(IHXPacket*) rpPacket)
{
HX_RESULT retVal = HXR_FAIL;
if (m_pCommonClassFactory)
{
// Create an IHXBuffer.
IHXBuffer* pBuffer = NULL;
if (!bLost)
{
// Packet was NOT lost so we have to have a buffer
if (pBuf && ulSize)
{
retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void**) &pBuffer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -