diff -r 000000000000 -r 951a5db380a0 videoeditorengine/avcedit/src/vedavceditimp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/avcedit/src/vedavceditimp.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,1005 @@ +/* +* 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 +#include + +#include "biblin.h" +#include "bitbuffer.h" +#include "vld.h" +#include "vedavceditimp.h" + +// Debug print macro +#ifdef _DEBUG +#include +#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(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(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( temp1->Des().Ptr() ); + ppsPtr = const_cast( 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 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( temp1->Des().Ptr() ); + ppsPtr = const_cast( temp2->Des().Ptr() ); + + numSPS = ReturnNumSPS(iAvcDecoder); + numPPS = ReturnNumPPS(iAvcDecoder); + + for (i=0; i> 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> 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 + +