/*
* Copyright (c) 2010 Ixonos Plc.
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - Initial contribution
*
* Contributors:
* Ixonos Plc
*
* Description:
* Implementation class for AVC editing operations.
*
*/
#include <e32svr.h>
#include <mmf/devVideo/avc.h>
#include "biblin.h"
#include "bitbuffer.h"
#include "vld.h"
#include "vedavceditimp.h"
// Debug print macro
#ifdef _DEBUG
#include <e32svr.h>
#define PRINT(x) RDebug::Print x;
#else
#define PRINT(x)
#endif
// An assertion macro wrapper to clean up the code a bit
#define VPASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CVedAVCEdit"), -10000))
// ================= MEMBER FUNCTIONS =======================
// Two-phased constructor
CVedAVCEditImp* CVedAVCEditImp::NewL()
{
CVedAVCEditImp* self = new (ELeave) CVedAVCEditImp();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
// C++ default constructor
CVedAVCEditImp::CVedAVCEditImp()
{
}
// Symbian OS default constructor can leave
void CVedAVCEditImp::ConstructL()
{
iAvcDecoder = avcdOpen();
if (!iAvcDecoder)
{
User::Leave(KErrNoMemory);
}
#ifdef VIDEOEDITORENGINE_AVC_EDITING
iNalLengthSize = 4;
iOutputLevel = 10;
#endif
}
// Destructor
CVedAVCEditImp::~CVedAVCEditImp()
{
avcdClose(iAvcDecoder);
}
// ---------------------------------------------------------7
// AVCEditParser::ProcessAVCBitStream
// Process one input AVC frame, i.e., convert to MDF NAL unit
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVedAVCEditImp::ProcessAVCBitStreamL(TDes8& aBuf, TInt& aFrameLen, TInt aDecInfoSize, TBool aFirstFrame)
{
TUint8* dataBuffer = (TUint8*)(aBuf.Ptr());
// Calculate NAL header start offset
TInt offset = (((aFrameLen - 1) / 4) + 1) * 4; // Align at 32-bit boundrary
TInt numNALUnits = 0;
if (aFirstFrame) // There are several NAL units: decoder info and the frame
{
// how many bytes used for length
iFrameLengthBytes = ( dataBuffer[4] & 0x3 ) + 1;
// Index where to read configuration data
TInt index = 5; // Skip version and length information
TInt numOfSPS = dataBuffer[index] & 0x1f;
index++;
// Loop all SPS units
for (TInt i = 0; i < numOfSPS; ++i)
{
TInt SPSSize = (dataBuffer[index] << 8) + dataBuffer[index + 1];
index += 2;
// Set NAL start offset
dataBuffer[offset + 0] = TUint8(index & 0xff);
dataBuffer[offset + 1] = TUint8((index >> 8) & 0xff);
dataBuffer[offset + 2] = TUint8((index >> 16) & 0xff);
dataBuffer[offset + 3] = TUint8((index >> 24) & 0xff);
// Set NAL size
dataBuffer[offset + 4] = TUint8(SPSSize & 0xff);
dataBuffer[offset + 5] = TUint8((SPSSize >> 8) & 0xff);
dataBuffer[offset + 6] = TUint8((SPSSize >> 16) & 0xff);
dataBuffer[offset + 7] = TUint8((SPSSize >> 24) & 0xff);
offset += 8;
index += SPSSize;
numNALUnits++;
}
TInt numOfPPS = dataBuffer[index];
index++;
// Loop all PPS units
for (TInt i = 0; i < numOfPPS; ++i)
{
TInt PPSSize = (dataBuffer[index] << 8) + dataBuffer[index + 1];
index += 2;
// Set NAL start offset
dataBuffer[offset + 0] = TUint8(index & 0xff);
dataBuffer[offset + 1] = TUint8((index >> 8) & 0xff);
dataBuffer[offset + 2] = TUint8((index >> 16) & 0xff);
dataBuffer[offset + 3] = TUint8((index >> 24) & 0xff);
// Set NAL size
dataBuffer[offset + 4] = TUint8(PPSSize & 0xff);
dataBuffer[offset + 5] = TUint8((PPSSize >> 8) & 0xff);
dataBuffer[offset + 6] = TUint8((PPSSize >> 16) & 0xff);
dataBuffer[offset + 7] = TUint8((PPSSize >> 24) & 0xff);
offset += 8;
index += PPSSize;
numNALUnits++;
}
TInt totalFrameSize = aFrameLen;
TInt currentProcessed = aDecInfoSize + 4; // skip DCR & length
TUint8* frameLenPtr = const_cast<TUint8*>(aBuf.Ptr()) + aDecInfoSize;
TInt frameSize = 0;
// loop all slice NAL units
while (currentProcessed < totalFrameSize)
{
// Set the NAL start offset
dataBuffer[offset + 0] = TUint8(currentProcessed & 0xff);
dataBuffer[offset + 1] = TUint8((currentProcessed >> 8) & 0xff);
dataBuffer[offset + 2] = TUint8((currentProcessed >> 16) & 0xff);
dataBuffer[offset + 3] = TUint8((currentProcessed >> 24) & 0xff);
frameSize = (frameLenPtr[0] << 24) + (frameLenPtr[1] << 16) +
(frameLenPtr[2] << 8) + frameLenPtr[3];
// Set the NAL size
dataBuffer[offset + 4] = TUint8(frameSize & 0xff);
dataBuffer[offset + 5] = TUint8((frameSize >> 8) & 0xff);
dataBuffer[offset + 6] = TUint8((frameSize >> 16) & 0xff);
dataBuffer[offset + 7] = TUint8((frameSize >> 24) & 0xff);
frameLenPtr += (4 + frameSize);
currentProcessed += (4 + frameSize);
offset += 8;
numNALUnits++;
}
// Set Number of NAL units
dataBuffer[offset + 0] = TUint8(numNALUnits & 0xff);
dataBuffer[offset + 1] = TUint8((numNALUnits >> 8) & 0xff);
dataBuffer[offset + 2] = TUint8((numNALUnits >> 16) & 0xff);
dataBuffer[offset + 3] = TUint8((numNALUnits >> 24) & 0xff);
aFrameLen = offset + 4;
}
else
{ // process just the frame
TInt totalFrameSize = aFrameLen;
TInt currentProcessed = 4; // skip length
TUint8* frameLenPtr = const_cast<TUint8*>(aBuf.Ptr());
TInt frameSize = 0;
// loop all slice NAL units
while (currentProcessed < totalFrameSize)
{
// Set the NAL start offset
dataBuffer[offset + 0] = TUint8(currentProcessed & 0xff);
dataBuffer[offset + 1] = TUint8((currentProcessed >> 8) & 0xff);
dataBuffer[offset + 2] = TUint8((currentProcessed >> 16) & 0xff);
dataBuffer[offset + 3] = TUint8((currentProcessed >> 24) & 0xff);
frameSize = (frameLenPtr[0] << 24) + (frameLenPtr[1] << 16) +
(frameLenPtr[2] << 8) + frameLenPtr[3];
// Set the NAL size
dataBuffer[offset + 4] = TUint8(frameSize & 0xff);
dataBuffer[offset + 5] = TUint8((frameSize >> 8) & 0xff);
dataBuffer[offset + 6] = TUint8((frameSize >> 16) & 0xff);
dataBuffer[offset + 7] = TUint8((frameSize >> 24) & 0xff);
frameLenPtr += (4 + frameSize);
currentProcessed += (4 + frameSize);
offset += 8;
numNALUnits++;
}
// Number of NAL units
dataBuffer[offset + 0] = TUint8(numNALUnits & 0xff);
dataBuffer[offset + 1] = TUint8((numNALUnits >> 8) & 0xff);
dataBuffer[offset + 2] = TUint8((numNALUnits >> 16) & 0xff);
dataBuffer[offset + 3] = TUint8((numNALUnits >> 24) & 0xff);
aFrameLen = offset + 4;
}
//iDataLength = iCurrentFrameLength;
}
// ---------------------------------------------------------
// CVedAVCEditImp::GetMaxAVCFrameBuffering
// Calculate maximum amount of buffered AVC frames
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CVedAVCEditImp::GetMaxAVCFrameBuffering(TInt aLevel, TSize aResolution)
{
TReal maxDPB = 0.0;
switch (aLevel)
{
case 11:
maxDPB = 337.5;
break;
case 12:
maxDPB = 891.0;
break;
case 10:
case 101:
default:
maxDPB = 148.5;
break;
}
TInt mbWidth = aResolution.iWidth / 16;
TInt mbHeight = aResolution.iHeight / 16;
TInt maxDPBSize = TInt( ( TReal(1024.0) * maxDPB ) / ( TReal(mbWidth*mbHeight*384.0) ) );
maxDPBSize = min(maxDPBSize, 16);
return maxDPBSize;
}
// ---------------------------------------------------------
// CVedAVCEditImp::GetLevel
// Get input bitstream level from SPS
// ---------------------------------------------------------
//
TInt CVedAVCEditImp::GetLevel(TDesC8& aBuf, TInt& aLevel)
{
TUint8* buffer = (TUint8*)(aBuf.Ptr());
TInt index = 5; // Skip version and length information
#ifdef _DEBUG
TInt numOfSPS = buffer[index] & 0x1f;
VPASSERT(numOfSPS == 1);
#endif
index++;
TUint SPSSize = (buffer[index] << 8) + buffer[index + 1];
index += 2;
TInt error = avcdParseLevel(iAvcDecoder, (void*)&buffer[index], &SPSSize, aLevel);
if (error != KErrNone)
return error;
return KErrNone;
}
// ---------------------------------------------------------
// CVedAVCEditImp::GetResolution
// Get input bitstream resolution from SPS
// ---------------------------------------------------------
//
TInt CVedAVCEditImp::GetResolution(TDesC8& aBuf, TSize& aResolution)
{
TUint8* buffer = (TUint8*)(aBuf.Ptr());
TInt index = 5; // Skip version and length information
#ifdef _DEBUG
TInt numOfSPS = buffer[index] & 0x1f;
VPASSERT(numOfSPS == 1);
#endif
index++;
TUint SPSSize = (buffer[index] << 8) + buffer[index + 1];
index += 2;
TInt error = avcdParseResolution(iAvcDecoder, (void*)&buffer[index], &SPSSize,
aResolution.iWidth, aResolution.iHeight);
if (error != KErrNone)
return error;
return KErrNone;
}
#ifdef VIDEOEDITORENGINE_AVC_EDITING
// ---------------------------------------------------------
// AVCEditParser::SaveAVCDecoderConfigurationRecordL
// Saves SPS/PPS Nal units from AVCDecoderConfigurationRecord
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVedAVCEditImp::SaveAVCDecoderConfigurationRecordL(TDes8& aBuf, TBool aFromEncoder)
{
TUint8* buffer = (TUint8*)(aBuf.Ptr());
TInt index = 5; // Skip version and length information
TInt numOfSPS = buffer[index] & 0x1f;
index++;
// Loop all SPS units
for (TInt i = 0; i < numOfSPS; ++i)
{
TUint SPSSize = (buffer[index] << 8) + buffer[index + 1];
index += 2;
// feed NAL for saving to ParseParameterSet()
User::LeaveIfError( ParseParameterSet( (void*)&buffer[index], &SPSSize, aFromEncoder ) );
index += SPSSize;
}
TInt numOfPPS = buffer[index];
index++;
// Loop all PPS units
for (TInt i = 0; i < numOfPPS; ++i)
{
TUint PPSSize = (buffer[index] << 8) + buffer[index + 1];
index += 2;
// feed NAL for saving to ParseParameterSet()
User::LeaveIfError( ParseParameterSet( (void*)&buffer[index], &PPSSize, aFromEncoder ) );
index += PPSSize;
}
}
// ---------------------------------------------------------
// CVedAVCEditImp::ConvertAVCHeader
// Convert AVC specific decoder config info to
// AVCDecoderConfigurationRecord -format
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVedAVCEditImp::ConvertAVCHeaderL( TDesC8& aSrcBuf, TDes8& aDstBuf )
{
TUint8* inputPtr = (TUint8*)(aSrcBuf.Ptr());
TUint8* outputPtr = (TUint8*)(aDstBuf.Ptr());
TUint8* spsPtr;
TUint8* ppsPtr;
TUint numSPS = 0;
TUint numPPS = 0;
TUint totalSPSLength = 0;
TUint totalPPSLength = 0;
TUint headerLength = aSrcBuf.Length();
TUint endIndex = headerLength;
TInt nalType = 0;
TUint nalLength;
TUint nalIndex;
TUint nalOffset;
// Allocate memory for the temporary buffers
HBufC8* temp1 = (HBufC8*) HBufC8::NewLC(1000);
HBufC8* temp2 = (HBufC8*) HBufC8::NewLC(5000);
spsPtr = const_cast<TUint8*>( temp1->Des().Ptr() );
ppsPtr = const_cast<TUint8*>( temp2->Des().Ptr() );
TUint numNalUnits = inputPtr[endIndex-4] + (inputPtr[endIndex-3]<<8) + (inputPtr[endIndex-2]<<16) + (inputPtr[endIndex-1]<<24);
// Move endIndex to point to the first NAL unit's offset information
endIndex = headerLength - numNalUnits*8 - 4;
nalIndex = 0;
TUint8* copyPtr = inputPtr;
while (nalIndex < numNalUnits)
{
nalIndex++;
TInt tmp1 = inputPtr[endIndex++];
TInt tmp2 = inputPtr[endIndex++]<<8;
TInt tmp3 = inputPtr[endIndex++]<<16;
TInt tmp4 = inputPtr[endIndex++]<<24;
nalOffset = tmp1 + tmp2 + tmp3 + tmp4;
tmp1 = inputPtr[endIndex++];
tmp2 = inputPtr[endIndex++]<<8;
tmp3 = inputPtr[endIndex++]<<16;
tmp4 = inputPtr[endIndex++]<<24;
nalLength = tmp1 + tmp2 + tmp3 + tmp4;
nalType = inputPtr[nalOffset] & 0x1F;
if(nalType == 7)
{
numSPS++;
// First store the SPS unit length with two bytes
spsPtr[totalSPSLength] = (nalLength >> 8) & 0xFF;
spsPtr[totalSPSLength+1] = nalLength & 0xFF;
// Copy the SPS unit to the buffer
Mem::Copy(&spsPtr[totalSPSLength+2], copyPtr , nalLength);
totalSPSLength += nalLength + 2; // Two more for the size
}
else if(nalType == 8)
{
numPPS++;
// First store the SPS unit length with two bytes
ppsPtr[totalPPSLength] = (nalLength >> 8) & 0xFF;
ppsPtr[totalPPSLength+1] = nalLength & 0xFF;
// Copy the SPS unit to the buffer
Mem::Copy(&ppsPtr[totalPPSLength+2], copyPtr , nalLength);
totalPPSLength += nalLength + 2; // Two more for the size
}
else
{
// [KW]: Check later if this is an error!!!
}
copyPtr += nalLength;
}
// When the header has been parsed, form the AVCDecoderConfigurationRecord
outputPtr[0] = 0x01; // configurationVersion
outputPtr[1] = 0x42; // Profile indicator
// Profile compatibility, i.e. all 4 constrain set flags + reserved 4 zero bits
outputPtr[2] = 0x80; // Bitstream obeys all baseline constraints
if ( iOutputLevel == 101 )
{
// For level 1b, the 4th bit shall be == 1, otherwise it must be zero
outputPtr[2] |= 0x10;
}
else
{
outputPtr[2] &= 0xEF;
}
outputPtr[3] = (iOutputLevel == 101) ? 11 : iOutputLevel; // level
outputPtr[4] = 0x03; // lengthSizeMinusOne
outputPtr[4] |= 0x0FC; // 6 reserved bits (all 1)
outputPtr[5] = numSPS;
outputPtr[5] |= 0xE0; // 3 reserved bits (all 1)
TInt len = 6;
// Copy the SPS unit(s) to the buffer
Mem::Copy(&outputPtr[6], spsPtr , totalSPSLength);
len += totalSPSLength;
outputPtr[6+totalSPSLength] = numPPS;
len += 1;
// Copy the PPS unit(s) to the buffer
Mem::Copy(&outputPtr[6+totalSPSLength+1], ppsPtr , totalPPSLength);
len += totalPPSLength;
aDstBuf.SetLength(len);
CleanupStack::Pop(2);
// Free the temporary buffers
delete temp1;
delete temp2;
}
// ---------------------------------------------------------
// CVedAVCEditImp::ParseOneNAL
// Saves one SPS/PPS NAL unit for later use
// ---------------------------------------------------------
//
TInt CVedAVCEditImp::ParseParameterSet(void *aNalUnitData, TUint* aNalUnitLength, TBool aFromEncoder)
{
TInt retCode;
// Pass the information about the frame origin to the decoder
FrameIsFromEncoder(iAvcDecoder, aFromEncoder);
// Just call the decoder's parser function
retCode = avcdParseParameterSet(iAvcDecoder, aNalUnitData, aNalUnitLength);
return retCode;
}
TInt CVedAVCEditImp::ParseOneNAL(void *aNalUnitData, TUint* aNalUnitLength, TBool aFromEncoder)
{
TInt retCode;
// Pass the information about the frame origin to the decoder
FrameIsFromEncoder(iAvcDecoder, aFromEncoder);
// Just call the decoder's parser function
retCode = avcdParseOneNal(iAvcDecoder, aNalUnitData, aNalUnitLength);
return retCode;
}
// ---------------------------------------------------------
// CVedAVCEditImp::ParseFrame
// Update slice header information
// ---------------------------------------------------------
//
TInt CVedAVCEditImp::ParseFrame(HBufC8*& aBuf, TBool aContainsDCR, TBool aFromEncoder)
{
TUint nalSize;
TUint nalOrigSize = 0;
TUint nalLengthSize = 0;
// TInt nalType;
// TInt nalRefIdc;
TInt skip = 0;
TUint bufferLength = aBuf->Length();
TPtr8 bufferPtr(aBuf->Des());
TUint8* srcPtr = (TUint8*)(bufferPtr.Ptr());
TInt error;
HBufC8* temp1 = 0;
TRAP( error, temp1 = (HBufC8*) HBufC8::NewL(10) );
if (error != KErrNone)
return error;
TPtr8 tempPtr(temp1->Des());
// TUint tmpLength1;
// TUint tmpLength2;
TUint8* tempData1;
tempPtr.Append(5);
// Jump over the AVC decoder information if it's included
if(aContainsDCR)
{
// skip 4 bytes for
// configVersion, profile, profile compatibility and Level
skip += 4;
// skip 1 byte for lengthSizeMinusOne
skip += 1;
// skip 1 byte for number of sequence parameter sets
TInt numOfSSP = 0x1F & srcPtr[skip];
skip += 1;
for (TInt i = 0; i < numOfSSP; i++)
{
TInt sspSize = srcPtr[skip]*256 + srcPtr[skip+1];
skip += 2;
skip += sspSize;
}
TInt numOfPSP = srcPtr[skip];
skip += 1;
for (TInt i = 0; i < numOfPSP; i++)
{
TInt pspSize = srcPtr[skip]*256 + srcPtr[skip+1];
skip += 2;
skip += pspSize;
}
}
while (skip < bufferLength)
{
TInt retVal = 0;
nalLengthSize = iNalLengthSize;
switch (nalLengthSize)
{
case 1:
nalOrigSize = nalSize = srcPtr[skip];
skip += 1;
break;
case 2:
nalOrigSize = nalSize = (srcPtr[skip] << 8) + srcPtr[skip+1];
skip += 2;
break;
case 4:
nalOrigSize = nalSize = (srcPtr[skip] << 24) + (srcPtr[skip+1] << 16) +
(srcPtr[skip+2] << 8) + srcPtr[skip+3];
skip += 4;
break;
}
// nalType = srcPtr[skip] & 0x1F;
// nalRefIdc = srcPtr[skip] & 0x60;
// [KW]: Alloc memory here instead of sequence.cpp
tempData1 = (TUint8*) User::Alloc(nalOrigSize+100);
if (tempData1 == 0)
{
User::Free(temp1);
return KErrNoMemory;
}
Mem::Copy(tempData1, &srcPtr[skip], nalOrigSize*sizeof(TUint8));
Mem::FillZ(&tempData1[nalOrigSize], 100*sizeof(TUint8));
// Call ParseOneNaL function
retVal = ParseOneNAL(tempData1, &nalSize, aFromEncoder);
if (retVal != KErrNone)
{
User::Free(tempData1);
User::Free(temp1);
return retVal;
}
// Copy data back to the srcPtr
Mem::Copy(&srcPtr[skip],tempData1,nalOrigSize*sizeof(TUint8));
// tmpLength1 = aBuf->Length();
if(nalSize > nalOrigSize)
{
TUint diff = nalSize - nalOrigSize;
for (TInt i=0; i<diff; i++)
{
tempPtr.Delete(0,1);
tempPtr.Append(tempData1[nalOrigSize+i]);
// tmpLength2 = tempPtr.Length();
// Insert byte(s) into the buffer
if((bufferPtr.Length() + 1) > bufferPtr.MaxLength())
{
// extend buffer size
TUint newSize = bufferPtr.Length() + 1;
// round up to the next full kilobyte
newSize = (newSize + 1023) & (~1023);
TRAP(error, (aBuf = aBuf->ReAllocL(newSize)) );
if (error != KErrNone)
{
User::Free(tempData1);
User::Free(temp1);
return error;
}
bufferPtr.Set(aBuf->Des());
}
bufferPtr.Insert(skip+nalOrigSize+i,tempPtr);
// tmpLength1 = aBuf->Length();
}
bufferLength += diff;
}
else if(nalSize < nalOrigSize)
{
TUint diff = nalOrigSize - nalSize;
// Delete diff bytes from the buffer
bufferPtr.Delete(skip+nalOrigSize-diff,diff);
bufferLength -= diff;
}
// Update the NAL unit's size information in the buffer
srcPtr[skip-4] = TUint8((nalSize >> 24) & 0xff);
srcPtr[skip-3] = TUint8((nalSize >> 16) & 0xff);
srcPtr[skip-2] = TUint8((nalSize >> 8) & 0xff);
srcPtr[skip-1] = TUint8(nalSize & 0xff);
// Free the temporary data
User::Free(tempData1);
skip += nalSize;
}
User::Free(temp1);
return KErrNone;
}
// ---------------------------------------------------------
// CVedAVCEditImp::ConstructAVCDecoderConfigurationRecordL
// Constructs AVCDecoderConfigurationRecord for output
// ---------------------------------------------------------
//
void CVedAVCEditImp::ConstructAVCDecoderConfigurationRecordL( TDes8& aDstBuf )
{
TUint8* outputPtr = (TUint8*)(aDstBuf.Ptr());
TUint8* spsPtr;
TUint8* ppsPtr;
TUint numSPS = 0;
TUint numPPS = 0;
TUint totalSPSLength = 0;
TUint totalPPSLength = 0;
TInt i;
TUint spsLength;
TUint ppsLength;
TInt len = 6;
TUint8* copyPtr;
// Allocate memory for the temporary buffers
HBufC8* temp1 = (HBufC8*) HBufC8::NewLC(1000);
HBufC8* temp2 = (HBufC8*) HBufC8::NewLC(5000);
spsPtr = const_cast<TUint8*>( temp1->Des().Ptr() );
ppsPtr = const_cast<TUint8*>( temp2->Des().Ptr() );
numSPS = ReturnNumSPS(iAvcDecoder);
numPPS = ReturnNumPPS(iAvcDecoder);
for (i=0; i<numSPS; i++)
{
copyPtr = ReturnSPSSet(iAvcDecoder,i,&spsLength);
// First store the SPS unit length with two bytes
spsPtr[totalSPSLength] = (spsLength >> 8) & 0xFF;
spsPtr[totalSPSLength+1] = spsLength & 0xFF;
// Copy the SPS unit to the buffer
Mem::Copy(&spsPtr[totalSPSLength+2], copyPtr , spsLength);
totalSPSLength += spsLength + 2; // Two more for the size
}
for (i=0; i<numPPS; i++)
{
copyPtr = ReturnPPSSet(iAvcDecoder,i,&ppsLength);
// First store the PPS unit length with two bytes
ppsPtr[totalPPSLength] = (ppsLength >> 8) & 0xFF;
ppsPtr[totalPPSLength+1] = ppsLength & 0xFF;
// Copy the PPS unit to the buffer
Mem::Copy(&ppsPtr[totalPPSLength+2], copyPtr , ppsLength);
totalPPSLength += ppsLength + 2; // Two more for the size
}
// When the header has been parsed, form the AVCDecoderConfigurationRecord
outputPtr[0] = 0x01;
outputPtr[1] = 0x42; // Profile indicator, baseline profile
// Profile compatibility, i.e. all 4 constrain set flags + reserved 4 zero bits
outputPtr[2] = 0x80; // Bitstream obeys all baseline constraints
if ( iOutputLevel == 101 )
{
// For level 1b, the 4th bit shall be == 1, otherwise it must be zero
outputPtr[2] |= 0x10;
}
else
{
outputPtr[2] &= 0xEF;
}
outputPtr[3] = (iOutputLevel == 101) ? 11 : iOutputLevel; // level
outputPtr[4] = 0x03; // lengthSizeMinusOne
outputPtr[5] = numSPS;
// Copy the SPS unit(s) to the buffer
Mem::Copy(&outputPtr[6], spsPtr , totalSPSLength);
len += totalSPSLength;
outputPtr[6+totalSPSLength] = numPPS;
len += 1;
// Copy the PPS unit(s) to the buffer
Mem::Copy(&outputPtr[6+totalSPSLength+1], ppsPtr , totalPPSLength);
len += totalPPSLength;
aDstBuf.SetLength(len);
CleanupStack::Pop(2);
// Free the temporary buffers
delete temp1;
delete temp2;
}
// ---------------------------------------------------------
// CVedAVCEditImp::EncodeUntilIDR
// Returns whether frames have to be encoded until next IDR frame
// ---------------------------------------------------------
//
TBool CVedAVCEditImp::EncodeUntilIDR()
{
if (iAvcDecoder)
{
return (ReturnEncodeUntilIDR(iAvcDecoder));
}
else
{
return EFalse;
}
}
// ---------------------------------------------------------
// CVedAVCEditImp::IsNALUnitIDR
// Returns whether passed frame is an IDR frame
// ---------------------------------------------------------
//
TBool CVedAVCEditImp::IsNALUnitIDR( TDes8& aNalBuf )
{
TUint8* bufferPtr = (TUint8*)(aNalBuf.Ptr());
// skip 4 bytes of length information
if((bufferPtr[4] & 0x1F) == 5)
return ETrue;
else
return EFalse;
}
// ---------------------------------------------------------
// CVedAVCEditImp::StoreCurrentPPSId
// Stores the PPS id of passed frame for later use
// ---------------------------------------------------------
//
void CVedAVCEditImp::StoreCurrentPPSId( TDes8& aNalBuf )
{
TUint8* bufferPtr = (TUint8*)(aNalBuf.Ptr());
TUint bufferLength = aNalBuf.Length();
switch (iNalLengthSize)
{
case 1:
bufferLength = bufferPtr[0];
bufferPtr += 1;
break;
case 2:
bufferLength = (bufferPtr[0] << 8) + bufferPtr[1];
bufferPtr += 2;
break;
case 4:
bufferLength = (bufferPtr[0] << 24) + (bufferPtr[1] << 16) +
(bufferPtr[2] << 8) + bufferPtr[3];
bufferPtr += 4;
break;
}
avcdStoreCurrentPPSId(iAvcDecoder, bufferPtr, bufferLength);
}
// ---------------------------------------------------------
// CVedAVCEditImp::GenerateNotCodedFrame
// Generates a not coded (empty) frame
// ---------------------------------------------------------
//
TInt CVedAVCEditImp::GenerateNotCodedFrame( TDes8& aNalBuf, TUint aFrameNumber )
{
TUint8* bufferPtr = (TUint8*)(aNalBuf.Ptr());
TUint bufferLength = aNalBuf.Length();
TInt frameLength = 0;
frameLength = avcdGenerateNotCodedFrame(iAvcDecoder, bufferPtr, bufferLength, aFrameNumber);
if(frameLength > 0)
{
TInt i;
// Make room for iNalLengthSize bytes of length information to the start
for (i=frameLength-1; i>=0; i--)
{
bufferPtr[i+iNalLengthSize] = bufferPtr[i];
}
// Add the NAL size information to the buffer
switch (iNalLengthSize)
{
case 1:
bufferPtr[0] = TUint8(frameLength & 0xff);
frameLength++;
break;
case 2:
bufferPtr[0] = TUint8((frameLength >> 8) & 0xff);
bufferPtr[1] = TUint8(frameLength & 0xff);
frameLength += 2;
break;
case 4:
bufferPtr[0] = TUint8((frameLength >> 24) & 0xff);
bufferPtr[1] = TUint8((frameLength >> 16) & 0xff);
bufferPtr[2] = TUint8((frameLength >> 8) & 0xff);
bufferPtr[3] = TUint8(frameLength & 0xff);
frameLength += 4;
break;
}
return frameLength;
}
else
return 0;
}
// ---------------------------------------------------------
// CVedAVCEditImp::ModifyFrameNumber
// Modifies the frame number of input NAL unit
// ---------------------------------------------------------
//
void CVedAVCEditImp::ModifyFrameNumber( TDes8& aNalBuf, TUint aFrameNumber )
{
TUint8* bufferPtr = (TUint8*)(aNalBuf.Ptr());
TUint bufferLength = aNalBuf.Length();
switch (iNalLengthSize)
{
case 1:
bufferLength = bufferPtr[0];
bufferPtr += 1;
break;
case 2:
bufferLength = (bufferPtr[0] << 8) + bufferPtr[1];
bufferPtr += 2;
break;
case 4:
bufferLength = (bufferPtr[0] << 24) + (bufferPtr[1] << 16) +
(bufferPtr[2] << 8) + bufferPtr[3];
bufferPtr += 4;
break;
}
if (bufferPtr[0]==0x01 && bufferPtr[1]==0x42)
return;
avcdModifyFrameNumber(iAvcDecoder, bufferPtr, bufferLength, aFrameNumber);
}
#endif
// End of file