/********************************************************************
 * Copyright(c) 2006-2009 Broadcom Corporation.
 *
 *  Name: libcrystalhd_parser.h
 *
 *  Description: Driver Interface library Internal.
 *
 *  AU
 *
 *  HISTORY:
 *
 ********************************************************************
 *
 * This file is part of libcrystalhd.
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 *******************************************************************/

#include <stdlib.h>
#include "7411d.h"
#include "libcrystalhd_if.h"
#include "libcrystalhd_priv.h"
#include "libcrystalhd_parser.h"

//Check Number of Reference
//NAL Unit
//#include "NALUnit.h"

//Advanced Profile
static const uint8_t b_asf_vc1_frame_scode[4]={0x00, 0x00, 0x01, 0x0D};
//Simple / Main Profile

//SP/MP Code-In Magic Word
static const uint8_t b_asf_vc1_sm_codein_scode[4] = {0x5a, 0x5a, 0x5a, 0x5a};
static const uint8_t b_asf_vc1_sm_codein_data_suffix[1] = {0x0D};
static const uint8_t b_asf_vc1_sm_codein_sl_suffix[1] = {0x0F};
static const uint8_t b_asf_vc1_sm_codein_pts_suffix[1] = {0xBD};

static const uint8_t b_asf_vc1_sm_seqheader_scode[4] = {0x00, 0x00, 0x01, 0x0F};
static const uint8_t b_asf_vc1_sm_picheader_scode[4] = {0x00, 0x00, 0x01, 0x0D};
static const uint8_t b_asf_vc1_sm_codein_header[16] = {0x5a, 0x5a, 0x5a, 0x5a,
	                                                   0x00, 0x00, 0x00, 0x00,
	                                                   0x00, 0x00, 0x00, 0x00,
	                                                   0x5a, 0x5a, 0x5a, 0x5a};


static const uint8_t b_asf_vc1_sm_codein_seqhdr[32] = {0x5a, 0x5a, 0x5a, 0x5a,
	                                                   0x00, 0x00, 0x00, 0x20,
	                                                   0x00, 0x00, 0x00, 0x07,
	                                                   0x5a, 0x5a, 0x5a, 0x5a,
													   0x0f, 0x00, 0x00, 0x00,
	                                                   0x00, 0x00, 0x00, 0x00,
													   0x00, 0x00, 0x00, 0x00,
													   0x00, 0x00, 0x00, 0x00};

static const uint8_t b_asf_vc1_sm_seqhdr[12] = {0x00, 0x00, 0x01, 0x0F,
                                                0x00, 0x00, 0x00, 0x00,
												0x00, 0x00, 0x00, 0x00};

//Swap Data
uint32_t DWORD_SWAP(uint32_t x)
{
	return ((uint32_t)(((x) << 24) | ((x) >> 24) | (((x) & 0xFF00) << 8) | (((x) & 0xFF0000) >> 8)));
}

uint16_t WORD_SWAP(uint16_t x)
{
	return ((uint16_t)(((x) << 8) | ((x) >> 8)));
}

uint64_t ULONGLONG_SWAP(uint64_t x)
{
	return ((uint64_t)(((x) << 56) | ((x) >> 56) | (((x) & 0xFF00LL) << 40) | (((x) & 0xFF000000000000LL) >> 40) | (((x) & 0xFF0000LL) << 24) | (((x) & 0xFF0000000000LL) >> 24) | (((x) & 0xFF000000LL) << 8) | (((x) & 0xFF00000000LL) >> 8)));
}

void PTS2MakerBit5Bytes(uint8_t* pMakerBit, int64_t llPTS)
{
	//4 Bits: '0010'
	//3 Bits: PTS[32:30]
	//1 Bit: '1'
	//15 Bits: PTS[29:15]
	//1 Bit: '1'
	//15 Bits: PTS[14:0]
	//1 Bit : '1'
	//0010 xxx1 xxxx xxxx xxxx xxx1 xxxx xxxx xxxx xxx1

	//Swap
	uint64_t ullSwap = ULONGLONG_SWAP(llPTS);

	uint8_t *pPTS = (uint8_t *)(&ullSwap);

	//Reserved the last 5 bytes, using the last 33 bits of PTS
	//0000 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
	pPTS = pPTS + 3;

	//1st Byte: 0010 xxx1
	*(pMakerBit) = 0x21 | ((*(pPTS) & 0x01) << 3) | ((*(pPTS + 1) & 0xC0) >> 5);

	//2nd Byte: xxxx xxxx
	*(pMakerBit + 1) = ((*(pPTS + 1) & 0x3F) << 2) | ((*(pPTS + 2) & 0xC0) >> 6);

	//3rd Byte: xxxx xxx1
	*(pMakerBit + 2) = 0x01 | ((*(pPTS + 2) & 0x3F) << 2) | ((*(pPTS + 3) & 0x80) >> 6);

	//4th Byte: xxxx xxxx
	*(pMakerBit + 3) = ((*(pPTS + 3) & 0x7F) << 1) | ((*(pPTS + 4) & 0x80) >> 7);

	//5th Byte: xxxx xxx1
	*(pMakerBit + 4) = 0x01 | ((*(pPTS + 4) & 0x7F) << 1);
}

/*
void PESHeaderPTSInsert(uint8_t *pPESHdr, uint64_t llPTS)
{
	//Swap
	uint64_t ullSwap = ULONGLONG_SWAP(llPTS);

	uint8_t *pPTS = (uint8_t *)(&ullSwap);

	//PES Header Bit[8~12] PTS 5Bytes Field
	//0010 xxx1 xxxx xxxx
	//xxxx xxx1 xxxx xxxx
	//xxxx xxx1

}
*/

BC_STATUS DtsReleasePESConverter(HANDLE hDevice)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	if (Ctx->PESConvParams.m_pSpsPpsBuf)
		free(Ctx->PESConvParams.m_pSpsPpsBuf);
	Ctx->PESConvParams.m_pSpsPpsBuf = NULL;

	if (Ctx->PESConvParams.pStartcodePendBuff)
		free(Ctx->PESConvParams.pStartcodePendBuff);
	Ctx->PESConvParams.pStartcodePendBuff = NULL;

	return BC_STS_SUCCESS;
}

BC_STATUS DtsInitPESConverter(HANDLE hDevice)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	Ctx->PESConvParams.m_bIsFirstByteStreamNALU = true;
	Ctx->PESConvParams.m_pSpsPpsBuf = NULL;
	Ctx->PESConvParams.m_iSpsPpsLen = 0;
	Ctx->PESConvParams.m_lStartCodeDataSize = 0;

	Ctx->PESConvParams.pStartcodePendBuff = NULL;
	Ctx->PESConvParams.lPendBufferSize = 0;

	Ctx->PESConvParams.m_SymbInt.m_nSize = 0;
	Ctx->PESConvParams.m_SymbInt.m_nUsed = 0;
	Ctx->PESConvParams.m_SymbInt.m_pCurrent = NULL;
	Ctx->PESConvParams.m_SymbInt.m_pInputBuffer = NULL;
	Ctx->PESConvParams.m_SymbInt.m_pInputBufferEnd = NULL;
	Ctx->PESConvParams.m_SymbInt.m_ulMask = 0;
	Ctx->PESConvParams.m_SymbInt.m_ulOffset = 0;
	Ctx->PESConvParams.m_SymbInt.m_ulZero = 0;

	Ctx->PESConvParams.m_bAddSpsPps = true;
	Ctx->PESConvParams.m_bIsAdd_SCode_CodeIn = false;
	Ctx->PESConvParams.m_bRangered = false;
	Ctx->PESConvParams.m_bFinterpFlag = false;
	Ctx->PESConvParams.m_bMaxbFrames = false;

	return BC_STS_SUCCESS;

}

BC_STATUS DtsSetVC1SH(HANDLE hDevice)
{
	DTS_LIB_CONTEXT *Ctx = NULL;

	int sts = 0;

	DTS_GET_CTX(hDevice,Ctx);

	//Send SPS and PPS
	//unused uint8_t *pSrc = NULL;
	//unused uint8_t *pDes = NULL;

	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA))
	{
		Ctx->PESConvParams.m_iSpsPpsLen = Ctx->VidParams.MetaDataSz;
		sts = posix_memalign((void**)&Ctx->PESConvParams.m_pSpsPpsBuf, 8, Ctx->PESConvParams.m_iSpsPpsLen);
		if(sts)
			return BC_STS_INSUFF_RES;
		memcpy(Ctx->PESConvParams.m_pSpsPpsBuf, Ctx->VidParams.pMetaData, Ctx->PESConvParams.m_iSpsPpsLen);
	}
	else
	{
		if (Ctx->DevId == BC_PCI_DEVID_LINK)
		{
			if (Ctx->PESConvParams.m_pSpsPpsBuf)
				free(Ctx->PESConvParams.m_pSpsPpsBuf);
			Ctx->PESConvParams.m_iSpsPpsLen = 32;
			sts = posix_memalign((void**)&Ctx->PESConvParams.m_pSpsPpsBuf, 8, Ctx->PESConvParams.m_iSpsPpsLen);
			if(sts)
				return BC_STS_INSUFF_RES;
			memcpy(Ctx->PESConvParams.m_pSpsPpsBuf, b_asf_vc1_sm_codein_seqhdr, Ctx->PESConvParams.m_iSpsPpsLen);
			*((uint16_t*)(Ctx->PESConvParams.m_pSpsPpsBuf + 17)) = WORD_SWAP((uint16_t)Ctx->VidParams.WidthInPixels);
			*((uint16_t*)(Ctx->PESConvParams.m_pSpsPpsBuf + 19)) = WORD_SWAP((uint16_t)Ctx->VidParams.HeightInPixels);
			memcpy(Ctx->PESConvParams.m_pSpsPpsBuf + 21, Ctx->VidParams.pMetaData, 4);
		}
		else if (Ctx->DevId == BC_PCI_DEVID_FLEA)
		{
			if (Ctx->PESConvParams.m_pSpsPpsBuf)
				free(Ctx->PESConvParams.m_pSpsPpsBuf);
			Ctx->PESConvParams.m_iSpsPpsLen = 12;
			sts = posix_memalign((void**)&Ctx->PESConvParams.m_pSpsPpsBuf, 8, Ctx->PESConvParams.m_iSpsPpsLen);
			if(sts)
				return BC_STS_INSUFF_RES;
			memcpy(Ctx->PESConvParams.m_pSpsPpsBuf, b_asf_vc1_sm_seqhdr, Ctx->PESConvParams.m_iSpsPpsLen);
			*((uint16_t*)(Ctx->PESConvParams.m_pSpsPpsBuf + 4)) = WORD_SWAP((uint16_t)Ctx->VidParams.WidthInPixels);
			*((uint16_t*)(Ctx->PESConvParams.m_pSpsPpsBuf + 6)) = WORD_SWAP((uint16_t)Ctx->VidParams.HeightInPixels);
			memcpy(Ctx->PESConvParams.m_pSpsPpsBuf + 8, Ctx->VidParams.pMetaData, 4);
		}
	}
	return BC_STS_SUCCESS;
}

BC_STATUS DtsSetSpsPps(HANDLE hDevice)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	//Send SPS and PPS
	uint8_t *pSrc = NULL;
	uint8_t *pDes = NULL;
	uint8_t NALtype = 0;

	int iSHStart[40];
	int iSHStop[40];
	int iPktIdx = 0;
	int i = 0;
	int j = 0;
	unsigned int iSize = 0;

	int iStartSize = 2;

	DTS_GET_CTX(hDevice,Ctx);
// 	if ((Ctx->VidParams.MediaSubType != BC_MSUBTYPE_AVC1) &&
// 		(Ctx->VidParams.MediaSubType != BC_MSUBTYPE_H264) &&
// 		(Ctx->VidParams.MediaSubType != BC_MSUBTYPE_DIVX) )
// 		return BC_STS_SUCCESS;

	// MSUBTYPE_H264 does not have codec_type to generate separate SPS/PPS
	if ((Ctx->VidParams.MediaSubType != BC_MSUBTYPE_AVC1) &&
		(Ctx->VidParams.MediaSubType != BC_MSUBTYPE_DIVX) )
		return BC_STS_SUCCESS;

	int iSHSize = Ctx->VidParams.MetaDataSz;
	pSrc = Ctx->VidParams.pMetaData;

	if((iSHSize > 0) && (pSrc))
	{
		if (pSrc[0]==0x00 && pSrc[1]==0x00 && pSrc[2]==0x01)
		{
			iStartSize = 3;
			iSHStart[iPktIdx] = 3;
			for (i = 3; i < iSHSize; i ++)
			{
				if (pSrc[i-2]==0x00 && pSrc[i-1]==0x00 && pSrc[i]==0x01)
				{
					iSHStop[iPktIdx] = i - 3;

					if (i < iSHSize)
					{
						iPktIdx++;
						iSHStart[iPktIdx] = i + 1;
					}
				}

			}
			iSHStop[iPktIdx++] = i-1;
		}
		else if (pSrc[0]==0x00 && pSrc[1]==0x00 && pSrc[2]==0x00 && pSrc[3]==0x01)
		{
			iStartSize = 4;
			iSHStart[iPktIdx] = 4;
			for (i = 4; i < iSHSize; i ++)
			{
				if (pSrc[i-3] == 0x00 && pSrc[i-2]==0x00 && pSrc[i-1]==0x00 && pSrc[i]==0x01)
				{
					iSHStop[iPktIdx] = i - 4;

					if (i < iSHSize)
					{
						iPktIdx++;
						iSHStart[iPktIdx] = i + 1;
					}
				}

			}
			iSHStop[iPktIdx++] = i-1;
		}
		else
		{
			while (i < iSHSize)
			{
				iSize = (pSrc[i] << 8) + pSrc[i+1];
				iSHStart[iPktIdx] = i + 2;
				iSHStop[iPktIdx] = iSHStart[iPktIdx] + iSize - 1;
				iPktIdx++;
				i += (2 + iSize);
			}
		}
		Ctx->PESConvParams.m_iSpsPpsLen = iSHSize + (BRCM_START_CODE_SIZE - iStartSize) * (iPktIdx);
		if(Ctx->PESConvParams.m_pSpsPpsBuf)
			free(Ctx->PESConvParams.m_pSpsPpsBuf);
		if(!posix_memalign((void**)&Ctx->PESConvParams.m_pSpsPpsBuf, 8, Ctx->PESConvParams.m_iSpsPpsLen))
		{
			memset(Ctx->PESConvParams.m_pSpsPpsBuf, 0, Ctx->PESConvParams.m_iSpsPpsLen);
			pDes = Ctx->PESConvParams.m_pSpsPpsBuf;
			pSrc = Ctx->VidParams.pMetaData;

			for(i=0;i<iPktIdx;i++)
			{
				// NAREN - Add only SPS and PPS from the sequence header to send to the HW
				// If there is other invalid data in the sequence header do not pass it along
				// Similarly if there is any other NAL unit type do not pass it along
				// NAL unit type for SPS is 7 and for PPS is 8 for H.264
				// NAL unit type is the first byte of the header portion and can be between 0 and 31
				// For MPEG-4 part 2 In general the demuxers give all of Video Object Layer start codes in the sequence header
				// Haali for example copies the entire MPEG-4 header up to the first Video Object Plane start
				// We may need to handle error checking for the MPEG4 part 2 streams, but for now we just copy the entire sequence header
				// and assume that demuxers do not give us any part of a VOP. Otherwise the same issue will exist for MP4p2
				NALtype = Ctx->VidParams.pMetaData[iSHStart[i]] & 0x1F;
				if((((NALtype == 0x7) || (NALtype == 0x8)) && (Ctx->VidParams.MediaSubType != BC_MSUBTYPE_DIVX)) ||
							(Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX))
				{
					//Start Code
					//Add to Pending Buffer
					for(j=0; j<BRCM_START_CODE_SIZE - 1;j++)
					{
						pDes[j] = 0;
					}

					pDes[BRCM_START_CODE_SIZE - 1] = 1;
					//Get Size
					iSize = iSHStop[i] - iSHStart[i] + 1;
					pDes = pDes + BRCM_START_CODE_SIZE;
					pSrc = pSrc + iStartSize;
					//Copy Sequence Header
					if(iSize > (Ctx->PESConvParams.m_iSpsPpsLen - (pDes - Ctx->PESConvParams.m_pSpsPpsBuf)))
						return BC_STS_ERROR;
					memcpy(pDes, pSrc, iSize);
					//Update
					pDes += iSize;
				}
				pSrc += iSize;
			}
		}
		else
			return BC_STS_INSUFF_RES;
	}
	return BC_STS_SUCCESS;
}

BC_STATUS DtsSetPESConverter( HANDLE hDevice)
{
	DTS_LIB_CONTEXT *Ctx = NULL;

	DTS_GET_CTX(hDevice,Ctx);

	DtsInitPESConverter(hDevice);

	uint8_t* pSeqHeader = Ctx->VidParams.pMetaData;

	//SoftRave (VC-1 S/M and Divx)
	if ((Ctx->DevId == BC_PCI_DEVID_FLEA) &&
		((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMV3) ||
		(Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX) ||
		(Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX311) ))
	{
		Ctx->PESConvParams.m_bSoftRave = true;
	}
	else
	{
		Ctx->PESConvParams.m_bSoftRave = false;
	}

	if ((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_AVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_H264) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX))
	{
		DtsSetSpsPps(hDevice);
		if (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_AVC1)
			Ctx->PESConvParams.m_bIsAdd_SCode_CodeIn = true;
	}
	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMV3) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA))
	{
		Ctx->PESConvParams.m_bIsAdd_SCode_CodeIn = true;
		if (pSeqHeader)
		{
			if (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMV3)
			{
				DWORD dwSH = DWORD_SWAP(*(DWORD *)pSeqHeader);
				Ctx->PESConvParams.m_bRangered = (0x00000080 & dwSH) == 0x00000080;
				Ctx->PESConvParams.m_bMaxbFrames = (0x00000070 & dwSH) == 0x00000070;
				Ctx->PESConvParams.m_bFinterpFlag = (0x00000002 & dwSH) == 0x00000002;
			}
		}
		DtsSetVC1SH(hDevice);
	}
	return BC_STS_SUCCESS;
}

BC_STATUS DtsCheckProfile(HANDLE hDevice)
{
/*
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	uint8_t* pSequenceHeader = Ctx->VidParams.pMetaData;
	LONG lSize = Ctx->VidParams.MetaDataSz;

	Ctx->VidParams.NumOfRefFrames = 0;
	Ctx->VidParams.LevelIDC = 0;

	if (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX && Ctx->DevId != BC_PCI_DEVID_FLEA)
		return BC_STS_ERROR;
	if((Ctx->VidParams.MediaSubType != BC_MSUBTYPE_AVC1) && (Ctx->VidParams.MediaSubType != BC_MSUBTYPE_H264))
		return BC_STS_SUCCESS;
	if (pSequenceHeader == NULL || lSize <= 0)
		return BC_STS_SUCCESS;

	//Get SPS Size
	int iSPSSize = (pSequenceHeader[0] << 8) + pSequenceHeader[1];
	uint8_t *pSPS = &pSequenceHeader[2];

	if (iSPSSize <=0)
		return BC_STS_SUCCESS;

	NALUnit nalu(pSPS, iSPSSize);
	if(nalu.Type() == NALUnit::NAL_Sequence_Params)
	{
		SeqParamSet sq;
		if(sq.Parse(&nalu))
		{
			int cx = sq.EncodedWidth();
			int cy = sq.EncodedHeight();
			bool bInterlace = sq.Interlaced();
			unsigned int iNumRefFrames = sq.NumRefFrames();

			// In Link we allocated 12 HD buffers for VDEC processing. This implies 12 * 1920 * 1088 bytes of memory storage.
			// The actual number of reference pictures allowed will be 2 less than the number of buffers allocated.
			// 2 is the number of pictures for processing overhead.
			// For various resolutions the amount of memory required per buffer is as follows -
			// 288x352 - 172032
			// 144x176 - 65536
			// 1088x1920 - 3194880
			// 576x720	- 688128
			// 320x352	- 196608
			// 160x176	- 65536
			// 720x1280 - 1474560
			// Use these values to determine the number of reference pictures we can support without errors in the HW

			unsigned int iNumRefPicturesSupported;

			// Just handle the two large cases. Assume that no clips exist with greater than 24 reference pictures
			// since no valid Profile/Level exists for that case. However x264 allows crazy things to happen. So change if needed.
			if(cy > 720)
				iNumRefPicturesSupported = ((12 * 3194880) / 3194880) - 2;
			else
				iNumRefPicturesSupported = ((12 * 3194880) / 1474560) - 2;

			if(iNumRefFrames > iNumRefPicturesSupported)
			{
				//Reject
				return BC_STS_ERROR;
			}
			Ctx->VidParams.NumOfRefFrames = iNumRefFrames;
			Ctx->VidParams.LevelIDC = sq.LevelIDC();
		}
	}
*/
	return BC_STS_SUCCESS;
}

BOOL DtsChkAVCSps(HANDLE hDevice, uint8_t *pBuffer, uint32_t ulSize)
{
	NALU_t Nalu;
	int ret = 0;
	uint32_t Pos = 0;

	while (1)
	{
		ret=DtsGetNaluType(hDevice, pBuffer + Pos,ulSize - Pos,&Nalu, false);
		if (ret <= 0)
		{
			return FALSE;
		}
		Pos += ret;

		if (Nalu.NalUnitType == NALU_TYPE_SPS)
			return TRUE;
	}
	return FALSE;
}


BOOL DtsCheckSpsPps(HANDLE hDevice, uint8_t *pBuffer, uint32_t ulSize)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_H264) ||
	   (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_AVC1) ||
	   (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX) ||
	   (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX311))
		return DtsChkAVCSps(hDevice, pBuffer, ulSize);
	else
		return FALSE;

}

BC_STATUS DtsAddH264SCode(HANDLE hDevice, uint8_t **ppBuffer, uint32_t *pUlDataSize, uint64_t *pTimeStamp)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	uint32_t lPendActualSize = 0;
	uint8_t *pPendCurrentPos = NULL;

	uint8_t *pStart = NULL;
	uint32_t lDataRemained = 0;
	//unused uint64_t timestamp = *pTimeStamp;

	uint8_t *pNALU = NULL;
	uint32_t ulNalSize = 0;

	int sts;

	if(Ctx->PESConvParams.lPendBufferSize < (*pUlDataSize*2))
	{
		if (Ctx->PESConvParams.pStartcodePendBuff)
			free(Ctx->PESConvParams.pStartcodePendBuff);

		Ctx->PESConvParams.lPendBufferSize = *pUlDataSize * 2;
		if (Ctx->PESConvParams.lPendBufferSize < 1024)
			Ctx->PESConvParams.lPendBufferSize = 1024;
		// minimum 8 byte aligned since posix_memalign needs to have min of size of (void *) and on 64-bit this is 8 bytes
		sts = posix_memalign((void**)&Ctx->PESConvParams.pStartcodePendBuff, 8, Ctx->PESConvParams.lPendBufferSize);
		if(sts != 0)
		  return BC_STS_INSUFF_RES;
	}
	//Replace Start Code
	lDataRemained = *pUlDataSize;
	pStart = *ppBuffer;

	lPendActualSize = 0;
	pPendCurrentPos = Ctx->PESConvParams.pStartcodePendBuff;

	while(1)
	{
		if(Ctx->PESConvParams.m_lStartCodeDataSize != 0)
		{
			//Remained
			if(Ctx->PESConvParams.m_lStartCodeDataSize >= lDataRemained)
			{
				//Pre-Update Size
				lPendActualSize = lPendActualSize + lDataRemained;

				//Check Copy Size
				if(lPendActualSize > Ctx->PESConvParams.lPendBufferSize)
				{
					//Error
					Ctx->PESConvParams.m_lStartCodeDataSize = 0;
					return BC_STS_ERROR;
				}

				//Copy to Pend Buffer
				memcpy(pPendCurrentPos, pStart, lDataRemained);

				//Update Pending Buffer
				pPendCurrentPos = pPendCurrentPos + lDataRemained;

				//Update Source Buffer
				pStart = pStart + lDataRemained;
				Ctx->PESConvParams.m_lStartCodeDataSize = Ctx->PESConvParams.m_lStartCodeDataSize - lDataRemained;
				lDataRemained = 0;
				//Done
				break;
			}
			else
			{
				//Get Start Code Position

				//Pre-Update Size
				lPendActualSize = lPendActualSize + Ctx->PESConvParams.m_lStartCodeDataSize;

				//Check Copy Size
				if(lPendActualSize > Ctx->PESConvParams.lPendBufferSize)
				{
					//Error
					Ctx->PESConvParams.m_lStartCodeDataSize = 0;
					return BC_STS_ERROR;
				}


				//Copy to Pend Buffer
				memcpy(pPendCurrentPos, pStart, Ctx->PESConvParams.m_lStartCodeDataSize);

				//Update Pending Buffer
				pPendCurrentPos = pPendCurrentPos + Ctx->PESConvParams.m_lStartCodeDataSize;

				//Update Source Buffer
				pStart = pStart + Ctx->PESConvParams.m_lStartCodeDataSize;
				lDataRemained = lDataRemained - Ctx->PESConvParams.m_lStartCodeDataSize;
				Ctx->PESConvParams.m_lStartCodeDataSize = 0;
			}
		}

		//Get Start Code
		uint8_t *StartCode = pStart;
		if(lDataRemained > Ctx->VidParams.StartCodeSz)
		{
			//Get Size
			for(uint32_t i = 0;i < Ctx->VidParams.StartCodeSz;i++)
			{
				Ctx->PESConvParams.m_lStartCodeDataSize <<= 8;
				Ctx->PESConvParams.m_lStartCodeDataSize += StartCode[i];
			}

			if(Ctx->PESConvParams.m_lStartCodeDataSize < 0)
			{
				//Error
				Ctx->PESConvParams.m_lStartCodeDataSize = 0;
				return BC_STS_ERROR;
			}
			else if(Ctx->PESConvParams.m_lStartCodeDataSize == 1)
			{
				//Could be Alreay a Start Code
				Ctx->PESConvParams.m_lStartCodeDataSize = 0;
				Ctx->PESConvParams.m_bIsAdd_SCode_CodeIn = false;
				if (Ctx->PESConvParams.pStartcodePendBuff)
					free(Ctx->PESConvParams.pStartcodePendBuff);
				Ctx->PESConvParams.lPendBufferSize = 0;
				Ctx->PESConvParams.pStartcodePendBuff = NULL;
				return BC_STS_SUCCESS;
			}
			else if(Ctx->PESConvParams.m_lStartCodeDataSize < *pUlDataSize)
			{
				//Succeeded

				//Check NAL Unit Type
				pNALU = pStart + Ctx->VidParams.StartCodeSz;
				ulNalSize = Ctx->PESConvParams.m_lStartCodeDataSize;

				//BRCM Start Code
				//Pre-Update Size
				lPendActualSize = lPendActualSize + BRCM_START_CODE_SIZE;

				//Check Copy Size
				if(lPendActualSize >Ctx->PESConvParams.lPendBufferSize)
				{
					//Error
					Ctx->PESConvParams.m_lStartCodeDataSize = 0;
					return BC_STS_ERROR;
				}

				//Add to Pending Buffer
				for(int i=0;i<BRCM_START_CODE_SIZE - 1;i++)
				{
					pPendCurrentPos[i] = 0;
				}

				pPendCurrentPos[BRCM_START_CODE_SIZE - 1] = 1;

				//Update Pending Buffer
				pPendCurrentPos = pPendCurrentPos + BRCM_START_CODE_SIZE;

				//Update Source Buffer
				pStart = pStart + Ctx->VidParams.StartCodeSz;
				lDataRemained = lDataRemained - Ctx->VidParams.StartCodeSz;
			}
		}
		else
		{
			//Error
			return BC_STS_IO_XFR_ERROR;
		}
	}//While
	//Use Pending Buffer Directly

	*ppBuffer = Ctx->PESConvParams.pStartcodePendBuff;
	*pUlDataSize = lPendActualSize;
	return BC_STS_SUCCESS;
}


BC_STATUS DtsAddVC1SCode(HANDLE hDevice, uint8_t **ppBuffer, uint32_t *pUlDataSize, uint64_t *pTimeStamp)
{
	uint32_t iCount = 0;

	int sts = 0;
	DTS_LIB_CONTEXT *Ctx = NULL;

	DTS_GET_CTX(hDevice,Ctx);

	uint64_t timestamp = *pTimeStamp;

	//Check Start Code for AP and SP/MP
	if(((*ppBuffer)[0] == 0x00) && ((*ppBuffer)[1] == 0x00) && ((*ppBuffer)[2] == 0x01) && (((*ppBuffer)[3] == 0x0F) || ((*ppBuffer)[3] == 0x0D) || ((*ppBuffer)[3] == 0xE0)))
	{
		Ctx->PESConvParams.m_bIsAdd_SCode_CodeIn = false;
		if (Ctx->PESConvParams.pStartcodePendBuff)
			free(Ctx->PESConvParams.pStartcodePendBuff);
		Ctx->PESConvParams.lPendBufferSize = 0;
		Ctx->PESConvParams.pStartcodePendBuff = NULL;
		return BC_STS_SUCCESS;
	}

	if(Ctx->PESConvParams.lPendBufferSize < (*pUlDataSize*2))
	{
		if (Ctx->PESConvParams.pStartcodePendBuff)
			free(Ctx->PESConvParams.pStartcodePendBuff);

		Ctx->PESConvParams.lPendBufferSize = *pUlDataSize * 2;
		if (Ctx->PESConvParams.lPendBufferSize < 1024)
			Ctx->PESConvParams.lPendBufferSize = 1024;
		sts = posix_memalign((void**)&Ctx->PESConvParams.pStartcodePendBuff, 8, Ctx->PESConvParams.lPendBufferSize);
		if(sts)
			return BC_STS_INSUFF_RES;
	}

	//unused uint8_t* pSequenceHeader = Ctx->VidParams.pMetaData;
	//unused LONG iSHSize = Ctx->VidParams.MetaDataSz;

	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA))
	{

		//Copy Start Code
		LONG lStartCodeSize = 4;

		memcpy(Ctx->PESConvParams.pStartcodePendBuff + iCount, (uint8_t *)b_asf_vc1_frame_scode, lStartCodeSize);
		iCount += lStartCodeSize;

		//Copy Data
		memcpy(Ctx->PESConvParams.pStartcodePendBuff + iCount, (uint8_t *)*ppBuffer, *pUlDataSize);
		iCount +=*pUlDataSize;
		*pTimeStamp = timestamp;
	}
	else
	{
		//SP / MP

		uint8_t* pData = *ppBuffer;
		uint8_t* pDst = Ctx->PESConvParams.pStartcodePendBuff;

		if (Ctx->DevId == BC_PCI_DEVID_LINK)
		{
			LONG lCIHeaderSize = 17;
			LONG lCIPacketSize = 0;
			LONG lCIZeroPaddingSize = 0;
			LONG lCILastDataLoc = *pUlDataSize - 1;

			if ((lCIHeaderSize + *pUlDataSize) & 0x1F)
				lCIPacketSize = (((lCIHeaderSize + *pUlDataSize) / 32) + 1) * 32;
			else
				lCIPacketSize = (lCIHeaderSize + *pUlDataSize);

			//Code-In Zero Padding
			lCIZeroPaddingSize = lCIPacketSize - (lCIHeaderSize + *pUlDataSize);

			memcpy(pDst, b_asf_vc1_sm_codein_header, 16);
			*((uint32_t *)(pDst + 4)) = DWORD_SWAP((uint32_t)lCIPacketSize);
			*((uint32_t *)(pDst + 8)) = DWORD_SWAP((uint32_t)lCILastDataLoc);

			memcpy(pDst + 16, (uint8_t *)b_asf_vc1_sm_codein_data_suffix, 1);
			memcpy(pDst + 17, pData, *pUlDataSize);
			memset(pDst + 17 + *pUlDataSize, 0, lCIZeroPaddingSize);
			iCount = lCIPacketSize;
		}
		else if (Ctx->DevId == BC_PCI_DEVID_FLEA)
		{
			memcpy(pDst, b_asf_vc1_sm_picheader_scode, 4);
			memcpy(pDst + 4, pData, *pUlDataSize);
			iCount = *pUlDataSize + 4;
		}
	}

	*ppBuffer = Ctx->PESConvParams.pStartcodePendBuff;
	*pUlDataSize  = iCount;
	return BC_STS_SUCCESS;
}

BC_STATUS DtsCheckKeyFrame(HANDLE hDevice, uint8_t *pBuffer)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	//unused BC_STATUS sts = BC_STS_SUCCESS;
	bool bKeyFrame = false;
	int iType = 0;


	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA))
	{
		//Advanced Profile

		//0: P Type
		//1: B Type
		//2: I Type
		//3: BI Type

		//Interlaced Check
		if(!Ctx->VidParams.Progressive)
		{
			//Interlaced
			//Skip FCM with 2 bits

			//Get Type
			//--xx xxxx
			//--?
			if((pBuffer[0] & 0x20) == 0)
			{
				iType = 0;
			}
			//--1?
			else if((pBuffer[0] & 0x10) == 0)
			{
				iType = 1;
			}
			//--11 ?
			else if((pBuffer[0] & 0x08) == 0)
			{
				iType = 2;
			}
			//--11 1?
			else if((pBuffer[0] & 0x04) == 0)
			{
				iType = 3;
			}
		}
		else
		{
			//Progress
			//Get Type
			//xxxx xxxx
			//?
			if((pBuffer[0] & 0x80) == 0)
			{
				iType = 0;
			}
			//1?
			else if((pBuffer[0] & 0x40) == 0)
			{
				iType = 1;
			}
			//11?
			else if((pBuffer[0] & 0x20) == 0)
			{
				iType = 2;
			}
			//111?
			else if((pBuffer[0] & 0x10) == 0)
			{
				iType = 3;
			}
		}

		//Check Key Frame
		if(iType == 2)
		{
			bKeyFrame = true;
		}
	}
	else
	{
		//SP / MP

		//0: P Type
		//1: B Type
		//2: I Type
		//3: BI Type

		int iCurrentBit = 0;
		//Check Finterpflag
		if(Ctx->PESConvParams.m_bFinterpFlag)
		{
			iCurrentBit = iCurrentBit + 1;
		}

		//Drop 2 bits
		iCurrentBit = iCurrentBit + 2;

		//Check Rangered
		if(Ctx->PESConvParams.m_bRangered)
		{
			iCurrentBit = iCurrentBit + 1;
		}

		//Check Bit
		uint8_t bFirstCheck = 0;
		uint8_t bSecondCheck = 0;
		if(iCurrentBit == 2)
		{
			bFirstCheck = 0x20;
			bSecondCheck = 0x10;
		}
		else if(iCurrentBit == 3)
		{
			bFirstCheck = 0x10;
			bSecondCheck = 0x08;
		}
		else if(iCurrentBit == 4)
		{
			bFirstCheck = 0x08;
			bSecondCheck = 0x04;
		}

		if(pBuffer[0] & bFirstCheck)
		{
			iType = 0;
		}
		else if(!Ctx->PESConvParams.m_bMaxbFrames)
		{
			iType = 2;
		}
		else if(pBuffer[0] & bSecondCheck)
		{
			iType = 2;
		}
		else
		{
			iType = 1;
		}

		//Check Key Frame
		if(iType == 2)
		{
			bKeyFrame = true;
		}
	}

	if (bKeyFrame)
	{
		Ctx->PESConvParams.m_bAddSpsPps = true;
	}
	return BC_STS_SUCCESS;
}

BC_STATUS DtsAddStartCode(HANDLE hDevice, uint8_t **ppBuffer, uint32_t *pUlDataSize, uint64_t * pTimeStamp)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	//unused BC_STATUS sts = BC_STS_SUCCESS;


	if (!Ctx->PESConvParams.m_bIsAdd_SCode_CodeIn)
		return BC_STS_SUCCESS;

	if(Ctx->VidParams.MediaSubType == BC_MSUBTYPE_AVC1 || Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX)
		return DtsAddH264SCode(hDevice, ppBuffer, pUlDataSize, pTimeStamp);

	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMV3) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_VC1))
		return DtsAddVC1SCode(hDevice, ppBuffer, pUlDataSize, pTimeStamp);

	return BC_STS_SUCCESS;
}

int DtsFindBSStartCode (unsigned char *Buf, int ZerosInStartcode)
{
	BOOL bStartCode = TRUE;
	int i;

	for (i = 0; i < ZerosInStartcode; i++)
		if(Buf[i] != 0)
			bStartCode = FALSE;

	if(Buf[i] != 1)
		bStartCode = FALSE;
	return bStartCode;
}

int DtsGetNaluType(HANDLE hDevice, uint8_t* pInputBuf, uint32_t ulSize, NALU_t* pNalu, bool bSkipSyncMarker)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	int b20sInSC, b30sInSC ;
	int bStartCodeFound, Rewind;
	int nLeadingZero8BitsCount=0, TrailingZero8Bits=0;
	//unused bool bSetIDR = true;
	//unused static BOOL fOne = TRUE;
	uint32_t Pos = 0;

	DTS_GET_CTX(hDevice,Ctx);

	if (bSkipSyncMarker)
	{
		pNalu->NalUnitType = (pInputBuf[0]) & 0x1f;
		pNalu->Len = ulSize;
		return 1;
	}
	while(Pos <= ulSize)
	{
		if( (pInputBuf[Pos++]) == 0)
			continue;
		else
			break;
	}
	if(pInputBuf[Pos-1] != 1)
	{
		return -1;
	}
	if(Pos < 3)
	{
		return -1;
	}
	else if(Pos == 3)
	{
		pNalu->StartcodePrefixLen = 3;
		nLeadingZero8BitsCount = 0;
	}
	else
	{
		nLeadingZero8BitsCount = Pos-4;
		pNalu->StartcodePrefixLen = 4;
	}

	//the 1st byte stream NAL unit can has nLeadingZero8BitsCount, but subsequent ones are not
	//allowed to contain it since these zeros(if any) are considered trailing_zero_8bits
	//of the previous byte stream NAL unit.
	if(!Ctx->PESConvParams.m_bIsFirstByteStreamNALU && nLeadingZero8BitsCount>0)
	{
//		DbgLog((LOG_TRACE, 1, TEXT("GetNaluType : ret 3\n")));
		return -1;
	}
	Ctx->PESConvParams.m_bIsFirstByteStreamNALU = false;

	bStartCodeFound = 0;
	b20sInSC = 0;
	b30sInSC = 0;

	while( (!bStartCodeFound) && (Pos < ulSize))
	{
		Pos++;
		if(Pos > ulSize)
		{
//			DbgLog((LOG_TRACE, 1, TEXT("GetNaluType : Pos > size = %d\n"),ulSize));

		}
		b30sInSC = DtsFindBSStartCode( (pInputBuf + Pos- 4), 3);
		if(b30sInSC != 1)
			b20sInSC = DtsFindBSStartCode( (pInputBuf + Pos -3), 2);
		bStartCodeFound = (b20sInSC  || b30sInSC);
	}

	Rewind = 0;
	if(!bStartCodeFound)
	{
//		DbgLog((LOG_TRACE, 1, TEXT("GetNaluType : ret 4 Pos = %d size = %d\n"),Pos,ulSize));

		//even if next start code is not found pprocess this NAL.
#if 0
		return -1;
#endif

	}

	if(bStartCodeFound)
	{
		//Count the trailing_zero_8bits
		//TrailingZero8Bits is present only for start code 00 00 00 01
		if(b30sInSC)
		{
			while(pInputBuf[Pos-5-TrailingZero8Bits]==0)
				TrailingZero8Bits++;
		}
		// Here, we have found another start code (and read length of startcode bytes more than we should
		// have.  Hence, go back in the file

		if(b30sInSC)
			Rewind = -4;
		else if (b20sInSC)
			Rewind = -3;
	}

	// Here the leading zeros(if any), Start code, the complete NALU, trailing zeros(if any)
	// until the  next start code .
	// Total size traversed is Pos, Pos+rewind are the number of bytes excluding the next
	// start code, and (Pos+rewind)-StartcodePrefixLen-LeadingZero8BitsCount-TrailingZero8Bits
	// is the size of the NALU.

	pNalu->Len = (Pos+Rewind)-pNalu->StartcodePrefixLen-nLeadingZero8BitsCount-TrailingZero8Bits;

	pNalu->NalUnitType = (pInputBuf[nLeadingZero8BitsCount+pNalu->StartcodePrefixLen]) & 0x1f;

	return (Pos+Rewind);
}

BC_STATUS DtsParseAVC(HANDLE hDevice, uint8_t* pInputBuf, ULONG ulSize, uint32_t* Offset, bool bIDR, int *pNalType)
{
	NALU_t Nalu;
	int ret = 0;
	uint32_t Pos = 0;
	bool bResult = false;

	*pNalType = -1;

	while (1)
	{
		ret=DtsGetNaluType(hDevice, pInputBuf + Pos,ulSize - Pos,&Nalu, false);
		if (ret <= 0)
		{
			return BC_STS_ERROR;
		}
		Pos += ret;

		switch (Nalu.NalUnitType)
		{
		case NALU_TYPE_SLICE:
		case NALU_TYPE_IDR:
			bResult = true;
			break;
		case NALU_TYPE_SEI:
		case NALU_TYPE_PPS:
		case NALU_TYPE_SPS:
			if(!bIDR)
				bResult = true;
			break;
		case NALU_TYPE_DPA:
		case NALU_TYPE_DPC:
		case NALU_TYPE_AUD:
		case NALU_TYPE_EOSEQ:
		case NALU_TYPE_EOSTREAM:
		case NALU_TYPE_FILL:
		default:
			break;
		}
		if(bResult)
		{
			*Offset = Pos;
			break;
		}
	}
	*pNalType = Nalu.NalUnitType;

	return BC_STS_SUCCESS;
}

BC_STATUS DtsFindIDR(HANDLE hDevice, uint8_t* pInputBuffer, uint32_t ulSizeInBytes, uint32_t* pOffset)
{
	int	nNalType = 0;
	uint32_t ulPos = 0;

	DtsParseAVC(hDevice, pInputBuffer, ulSizeInBytes, &ulPos, true, &nNalType);

	if( (nNalType == NALU_TYPE_SLICE) | (nNalType == NALU_TYPE_IDR))
	{
		*pOffset = ulPos;
		return BC_STS_SUCCESS;
	}

	return BC_STS_ERROR;
}

BC_STATUS DtsFindStartCode(HANDLE hDevice, uint8_t* pInputBuffer, uint32_t ulSizeInBytes, uint32_t* pOffset)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	uint32_t i=0;
	uint8_t	Suffix1 = 0;
	uint8_t	Suffix2 = 0;
	*pOffset = 0;

	DTS_GET_CTX(hDevice,Ctx);

	if (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1 || Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA || Ctx->VidParams.MediaSubType == BC_MSUBTYPE_VC1)
	{
		Suffix1 = VC1_FRM_SUFFIX;
		Suffix2 = VC1_SEQ_SUFFIX;
	}
	else if (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_MPEG2VIDEO)
	{
		Suffix1 = MPEG2_FRM_SUFFIX;
		Suffix2 = MPEG2_SEQ_SUFFIX;
	}
	else if (Ctx->VidParams.MediaSubType ==BC_MSUBTYPE_WMV3)
	//For VC-1 SP/MP
	{
		Suffix1 = VC1_SM_FRM_SUFFIX;
	}

	if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_H264) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_AVC1) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_DIVX))
	{
		int	nNalType = 0;
		uint32_t ulPos = 0;
		if (DtsParseAVC(hDevice, pInputBuffer,ulSizeInBytes,&ulPos,false, &nNalType) != BC_STS_SUCCESS)
			return BC_STS_ERROR;

		if( (nNalType == NALU_TYPE_SEI) || (nNalType == NALU_TYPE_PPS) || (nNalType == NALU_TYPE_SPS))
		{
			*pOffset = ulPos;
			return BC_STS_SUCCESS;
		}
		else if( (nNalType == NALU_TYPE_SLICE) | (nNalType == NALU_TYPE_IDR))
		{
			*pOffset = 0;
			return BC_STS_SUCCESS;
		}
		return BC_STS_ERROR;

	}
	else if((Ctx->VidParams.MediaSubType == BC_MSUBTYPE_MPEG2VIDEO) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WVC1) ||
		(Ctx->VidParams.MediaSubType == BC_MSUBTYPE_WMVA) || (Ctx->VidParams.MediaSubType ==BC_MSUBTYPE_WMV3) || (Ctx->VidParams.MediaSubType == BC_MSUBTYPE_VC1))

	{
		while(i < ulSizeInBytes)
		{
			if( (*(pInputBuffer +i) == Suffix1) || (*(pInputBuffer +i) == Suffix2))
			{
				if(i >= 3)
				{
					if( (*(pInputBuffer+(i-3)) == 0x00) && (*(pInputBuffer+(i-2)) == 0x00) && (*(pInputBuffer+(i-1)) == 0x01))
					{
						*pOffset = i-3;
						return BC_STS_SUCCESS;
					}
				}
			}
			i++;
		}
		return BC_STS_ERROR;

	}
	return BC_STS_SUCCESS;
}

BOOL DtsFindPTSInfoCode(HANDLE hDevice, uint8_t* pInputBuffer, uint32_t ulSizeInBytes)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	if((Ctx->VidParams.MediaSubType  != BC_MSUBTYPE_WMV3) && (Ctx->VidParams.MediaSubType  != BC_MSUBTYPE_WMVA))
		return FALSE;

	//Move PES Header
	uint32_t ulCurrent = 8;
	uint8_t bPESHeaderLen = pInputBuffer[ulCurrent];

	ulCurrent = ulCurrent + bPESHeaderLen + 1;

	//Check PES Payload for PTS Info
	if((ulSizeInBytes - ulCurrent) == 32)
	{
		DWORD dwFirstCode = *(DWORD *)&pInputBuffer[ulCurrent];
		ulCurrent = ulCurrent + 12;

		DWORD dwSecondCode = *(DWORD *)&pInputBuffer[ulCurrent];
		ulCurrent = ulCurrent + 4;

		if((dwFirstCode == VC1_SM_MAGIC_WORD) && (dwSecondCode == VC1_SM_MAGIC_WORD) && (pInputBuffer[ulCurrent] == VC1_SM_PTS_INFO_START_CODE))
		{
			return TRUE;
		}
	}

	return FALSE;

}

BC_STATUS DtsSymbIntSiBuffer (HANDLE hDevice, uint8_t* pInputBuffer, ULONG ulSize)
{
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	SYMBINT *pSymbint = &(Ctx->PESConvParams.m_SymbInt);
	pSymbint->m_pCurrent = pSymbint->m_pInputBuffer   = (uint8_t*) pInputBuffer;
	pSymbint->m_nSize =  ulSize;
	pSymbint->m_pInputBufferEnd  = pSymbint->m_pInputBuffer + ulSize;
	pSymbint->m_nUsed  = 1;
	pSymbint->m_ulOffset = 0;
	pSymbint->m_ulMask   = 0x80;

	return BC_STS_SUCCESS;
}

BC_STATUS DtsSymbIntSiUe (HANDLE hDevice, ULONG* pCode)
{
	uint32_t	ulSuffix;
	int     nLeadingZeros;
	int     nBit;
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	SYMBINT *pSymbint = &(Ctx->PESConvParams.m_SymbInt);

	nLeadingZeros = -1;
	for (nBit = 0; nBit == 0; nLeadingZeros++)
	{
		nBit = DtsSymbIntNextBit(hDevice);
		if(pSymbint->m_nUsed >= pSymbint->m_nSize)
			return BC_STS_ERROR;
	}

	*pCode = (1 << nLeadingZeros) - 1;

	ulSuffix = 0;
	while (nLeadingZeros-- > 0 )
	{
		ulSuffix = (ulSuffix << 1) | DtsSymbIntNextBit(hDevice);
		if(pSymbint->m_nUsed >= pSymbint->m_nSize)
			return BC_STS_ERROR;
	}
	*pCode += ulSuffix;

	return BC_STS_SUCCESS;
}

inline int DtsSymbIntNextBit ( HANDLE hDevice )
{
	int   nBit;
	DTS_LIB_CONTEXT *Ctx = NULL;
	DTS_GET_CTX(hDevice,Ctx);

	SYMBINT *pSymbint = &(Ctx->PESConvParams.m_SymbInt);

	nBit = (pSymbint->m_pCurrent[0] & pSymbint->m_ulMask) ? 1 : 0;

	if ((pSymbint->m_ulMask >>= 1) == 0)
	{
		pSymbint->m_ulMask = 0x80;

		if ( pSymbint->m_nUsed == pSymbint->m_nSize )
			pSymbint->m_pCurrent = pSymbint->m_pInputBuffer;//reset look again
		else
		{
			if ( ++pSymbint->m_pCurrent == pSymbint->m_pInputBufferEnd )
				pSymbint->m_pCurrent = pSymbint->m_pInputBuffer;
			pSymbint->m_nUsed++;
		}
	}
	pSymbint->m_ulOffset++;
	return nBit;
}

#if 0
void *DtsAlignedMalloc(size_t size, size_t alignment)
{
    void *p1 ,*p2; // basic pointer needed for computation.

    if((p1 =(void *) malloc(size + alignment + sizeof(size_t)))==NULL)
        return NULL;

    size_t addr = (size_t)p1 + alignment + sizeof(size_t);
    p2 = (void *)(addr - (addr%alignment));

    *((size_t *)p2-1) = (size_t)p1;

    return p2;
}

void DtsAlignedFree(void *ptr)
{
    if (ptr)
        free((void *)(*((size_t *) ptr-1)));
}

#endif

