/* producer-consumer with a circular buffer */

#include "DecTest.h"

#include<stdio.h>
#include<stdlib.h>


/* shared mem. */
volatile ringBuffer g_NAL_Buf;		 // buffer 1
volatile secRingBuffer g_SEC_Buf;	 // buffer 2
volatile thirRingBuffer g_THIR_Buf;  // buffer 3
/* end */


/* only for linux 32bit */ 
static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
    return (int32_t)(smp_malloc(size));
}

static void Free(void *userData, int32_t ptr) {
	smp_free((void *)(ptr));
}


volatile AVCHandle *g_TmpHandle = NULL;

volatile int* H264_File_NULL;

FILE *in_fd ,*out_fd;




int initAVCDecoder(){


	/* initialize the mutex */
	/* assign mutex id */
	g_NAL_Buf.mutex = NALBUF_MUTEX_NUM;
	g_SEC_Buf.mutex = SECBUF_MUTEX_NUM;
	g_THIR_Buf.mutex = THIRBUF_MUTEX_NUM;


	/* Block ram , for uncache data or flag */
	// base address 0x84410000
	int base_addr_g_NAL = BLOCK_RAM_BASE_ADDR;
	g_NAL_Buf.m_front = (void*)base_addr_g_NAL;
	g_NAL_Buf.m_rear = (void*)base_addr_g_NAL+4;

	int base_addr_g_SEC = base_addr_g_NAL + 16;
	g_SEC_Buf.m_front = (void*)base_addr_g_SEC;
	g_SEC_Buf.m_rear = (void*)base_addr_g_SEC+4;

	int base_addr_g_THIR = base_addr_g_SEC + 16;
	g_THIR_Buf.m_front = (void*)base_addr_g_THIR;
	g_THIR_Buf.m_rear = (void*)base_addr_g_THIR+4;


	int base_addr_g_flag = base_addr_g_THIR + 16;
	H264_File_NULL = (void*)base_addr_g_flag;


	/* initialize buffer */
	*g_NAL_Buf.m_front = 0;
	*g_NAL_Buf.m_rear = 0;


	*g_SEC_Buf.m_front = 0;
	*g_SEC_Buf.m_rear = 0;


	*g_THIR_Buf.m_front = 0;
	*g_THIR_Buf.m_rear = 0;


	/* initialize global variable */
	*H264_File_NULL = 0;

	/* global flag in Blcok ram , if buffer empty , enable */
	volatile int *pbr ,*pbr2,*pbr3,*pbr4;
	pbr = (void*)0x84410C00L;	// buffer 1
	pbr2 = (void*)0x84410C04L;	// buffer 2
	pbr3 = (void*)0x84410C08L;	// buffer 3
	pbr4 = (void*)0x84410C0CL;

	*pbr = 0;
	*pbr2 = 0;
	*pbr3 = 0;
	*pbr4 = 0;

	volatile int *pbr_bufferInit1,*pbr_bufferInit2;
	pbr_bufferInit1 = (void*)0x84410C10L;
	pbr_bufferInit2 = (void*)0x84410C14L;
	*pbr_bufferInit1 = 0;
	*pbr_bufferInit2 = 0;



	return 0;

}

/* producer thread , simulate ARM */
int producer() {
	
	AVCHandle *mHandle=NULL;
	int mSPSSeen,mPPSSeen;
	int H264_Size,H264_Offset;
	uint8_t *H264_File;

    char *fileName = INPUT_FILE_NAME;
    char *outfileName = OUTPUT_FILE_NAME;

	in_fd = sysace_fopen (fileName ,"r" );
	if(in_fd == NULL){
		mutex_lock(APP_MUTEX_NUM);
		xil_printf("error : file %s not find \n\r",fileName);
		mutex_unlock(APP_MUTEX_NUM);
		return 0;
	}

	mutex_lock(APP_MUTEX_NUM);
	xil_printf("input_filename %s \n\r",fileName);
	mutex_unlock(APP_MUTEX_NUM);

	H264_File = (unsigned char *) smp_malloc (8388608);
	H264_Size = sysace_fread(H264_File,8388608,1,in_fd);

    sysace_fclose(in_fd);

    /* already load data */
	*H264_File_NULL = 0;
	
	// ready output file out_fd

	out_fd= sysace_fopen(outfileName,"w");

	mutex_lock(APP_MUTEX_NUM);
	xil_printf("output_filename %s \n\r",outfileName);
	mutex_unlock(APP_MUTEX_NUM);


	g_TmpHandle = (AVCHandle*)smp_malloc( sizeof(AVCHandle));;

	AVCDecInit((AVCHandle*)g_TmpHandle , &mSPSSeen , &mPPSSeen , &H264_Offset );

	const uint8_t *NALUnit;
	int NALSize,Read_res=0,Dec_res=0;
	
	/* set timer */


	/* unlock all core */
	mutex_unlock(INITIAL_MUTEX);
	mutex_lock(BUFFINIT_MUTEX);

	volatile int *pbr_bufferInit1,*pbr_bufferInit2;
	pbr_bufferInit1 = (void*)0x84410C10L;
	pbr_bufferInit2 = (void*)0x84410C14L;

	if(!(*pbr_bufferInit1) || !(*pbr_bufferInit2)){}

	/* get start time tick */
	int start_time = tmr_get_value();

	while(H264_File!=NULL)
	{
		/* check ring buffer , lock */

        while(1){
        	if((*g_NAL_Buf.m_rear+1) %BUF_DEPTH == *g_NAL_Buf.m_front ){
        			smp_sleep(1000);
            }
            else
                break;
        }


		/* check ring buffer end */

		Read_res=ReadNALUnit( H264_File , H264_Offset , H264_Size , &NALUnit , &NALSize );
		if(Read_res==-1){
			break;//fail
		}

		Dec_res = DecNALUnit((AVCHandle*)g_TmpHandle,NALUnit,NALSize,&mSPSSeen,&mPPSSeen);
		//*g_nal_count++;
		if(Dec_res== -1){
			mutex_lock(APP_MUTEX_NUM);
			printf("Dec_res fail \n");
			mutex_unlock(APP_MUTEX_NUM);
			break;//fail
		}
		else
		{				      
			if (NALSize + 4 == H264_Size){	//end
				mutex_lock(g_NAL_Buf.mutex );
					(*g_NAL_Buf.m_rear) = (*g_NAL_Buf.m_rear+1)%BUF_DEPTH;
				mutex_unlock(g_NAL_Buf.mutex  );
					break;
			}
			else 
			{			
				H264_Offset = H264_Offset+NALSize+4;
				H264_Size = H264_Size-NALSize-4;
			}
			
		}
		//finish sent data
		mutex_lock(g_NAL_Buf.mutex );

			*g_NAL_Buf.m_rear = (*g_NAL_Buf.m_rear+1)%BUF_DEPTH;

		mutex_unlock(g_NAL_Buf.mutex );


	}

	/*  for syn.  */
	volatile int *pbr ,*pbr2,*pbr3;
	volatile int *pbr4;
	pbr = (void*)0x84410C00L;
	pbr2 = (void*)0x84410C04L;
	pbr3 = (void*)0x84410C08L;
	pbr4 = (void*)0x84410C0CL;

	while( !(*pbr) || !(*pbr2) || !(*pbr3)  ){    // include sps pps
		smp_sleep(3500);
	}

	/* finish */
	*H264_File_NULL = 1;


	while(!(*pbr4)){
		smp_sleep(800);
	}

	/* output decode time */
	mutex_lock(APP_MUTEX_NUM);
	printf("time : %.0f\n",(tmr_get_value()-start_time)*CLOCKS_PER_MICROSEC);
	mutex_unlock(APP_MUTEX_NUM);


	if(H264_File!=NULL)
		smp_free(H264_File);

	smp_free(mHandle);

	return 0;
}

/* consumer thread , simulate DSP */
int consumer( unsigned int core_id ) {


	while( !(*H264_File_NULL) ){

		/* remove an item from the buffer */

        while(1){

        	if((*g_NAL_Buf.m_front == *g_NAL_Buf.m_rear)  ){

            }
            else{
                break;
            }
        	if(*H264_File_NULL == 1)
        		break;

        }
        if(*H264_File_NULL == 1)
        	break;

		/* decode slice */
		AVCDec_Status res;
		int tmp_num = (*g_NAL_Buf.m_front+1)%BUF_DEPTH;


		/* cache coherence issue */
		microblaze_invalidate_dcache_range(&g_NAL_Buf.buf[tmp_num],sizeof(InputBuf));
		microblaze_invalidate_dcache_range(g_NAL_Buf.buf[tmp_num].ptr,sizeof(g_NAL_Buf.buf[tmp_num].nal_size));


		if( g_NAL_Buf.buf[tmp_num].nalType == AVC_NALTYPE_SPS)
		{	
            res = PVAVCDecSeqParamSet(
            		(AVCHandle*)g_TmpHandle,
					(uint8_t *)(g_NAL_Buf.buf[tmp_num].ptr),
                    (g_NAL_Buf.buf[tmp_num].nal_size));
            mutex_lock(APP_MUTEX_NUM);
            xil_printf("===========END SPS=============\n\r");
            mutex_unlock(APP_MUTEX_NUM);
		}
		else if( g_NAL_Buf.buf[tmp_num].nalType == AVC_NALTYPE_PPS)
		{	
            res = PVAVCDecPicParamSet(
            		(AVCHandle*)g_TmpHandle,
				   (uint8_t *)(g_NAL_Buf.buf[tmp_num].ptr),
                   (g_NAL_Buf.buf[tmp_num].nal_size));
            mutex_lock(APP_MUTEX_NUM);
            xil_printf("===========END PPS=============\n\r");
            mutex_unlock(APP_MUTEX_NUM);

		}
		else if	(  g_NAL_Buf.buf[tmp_num].nalType == AVC_NALTYPE_IDR ||
				 g_NAL_Buf.buf[tmp_num].nalType == AVC_NALTYPE_SLICE)// decode slice
		{
			res = FlushDataToConsumer((AVCHandle*)g_TmpHandle,
					(uint8_t *)(g_NAL_Buf.buf[tmp_num].ptr),
					(g_NAL_Buf.buf[tmp_num].nal_size));

			//*g_nal_count--;
		}
		else
		{
            mutex_lock(APP_MUTEX_NUM);
            printf("wrong nal type\n");
            mutex_unlock(APP_MUTEX_NUM);
            res = 0;
		}
		
		if( res == AVCDEC_FAIL){
			mutex_lock(APP_MUTEX_NUM);
			printf("Decode error\n");
			mutex_unlock(APP_MUTEX_NUM);
			return 0;
		}


		// finish get a nal
		mutex_lock(g_NAL_Buf.mutex );
			*g_NAL_Buf.m_front = (*g_NAL_Buf.m_front+1)%BUF_DEPTH;

			int *pbr ;
			pbr = (void*)0x84410C00L;

			/* for syn. */
			if(*g_NAL_Buf.m_front == *g_NAL_Buf.m_rear){
				*pbr = 1;
			}
			else{
				*pbr = 0;
			}


		mutex_unlock(g_NAL_Buf.mutex );

	}

	AVCDec_Status status =AVCDEC_SUCCESS;
	while(status==AVCDEC_SUCCESS){
		int32_t index;
		int32_t Release;
		AVCFrameIO Output;
		Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
		AVCDec_Status status = PVAVCDecGetOutput((AVCHandle*)g_TmpHandle, &index, &Release, &Output);
		if (status != AVCDEC_SUCCESS) {
			break;
		}

#ifdef dumpFile
		sysace_fwrite(Output.YCbCr[0],Output.pitch*Output.height,1,out_fd); //Y
		sysace_fwrite(Output.YCbCr[1],(Output.pitch/2)*(Output.height/2),1,out_fd); //Cb
		sysace_fwrite(Output.YCbCr[2],(Output.pitch/2)*(Output.height/2),1,out_fd); //Cr
#endif
	}
	
	volatile int *pbr4;
	pbr4 = (void*)0x84410C0CL;

	*pbr4 = 1;

	mutex_lock(APP_MUTEX_NUM);
	printf("Decode Over \n");
	mutex_unlock(APP_MUTEX_NUM);

    sysace_fclose(out_fd);
    smp_free((AVCHandle*)g_TmpHandle);

	return 0;
}

AVCDec_Status FlushDataToConsumer(AVCHandle *avcHandle, uint8 *buffer,
        int buf_size)
{
	AVCDec_Status res=0;
    AVCDecObject *decvid = (AVCDecObject*) avcHandle->AVCObject;
    AVCCommonObj *video;
	video = decvid->common;

	while(true){

		res = PVAVCDecodeSlice(avcHandle,buffer,buf_size);
		if( res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS ){
			return AVCDEC_SUCCESS;
		}
		else if( res == AVCDEC_PICTURE_OUTPUT_READY ){
			int32_t index;
			int32_t Release;
			AVCFrameIO Output;
			Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
			AVCDec_Status status = PVAVCDecGetOutput((AVCHandle*)g_TmpHandle, &index, &Release, &Output);


#ifdef dumpFile
			sysace_fwrite(Output.YCbCr[0],Output.pitch*Output.height,1,out_fd); //Y
			sysace_fwrite(Output.YCbCr[1],(Output.pitch/2)*(Output.height/2),1,out_fd); //Cb
			sysace_fwrite(Output.YCbCr[2],(Output.pitch/2)*(Output.height/2),1,out_fd); //Cr
#endif
			if (status != AVCDEC_SUCCESS)
			{
				mutex_lock(APP_MUTEX_NUM);
				printf("PVAVCDecGetOutput returned error %d\n", status);
				mutex_unlock(APP_MUTEX_NUM);
				break;
			}
		}
		else{
			mutex_lock(APP_MUTEX_NUM);

			printf("Decode slice Something fail\n");
			mutex_unlock(APP_MUTEX_NUM);
			return AVCDEC_FAIL;
		}
	}
	return AVCDEC_PICTURE_OUTPUT_READY;
}

int consumer_mc()
{

	/* sleep until ARM finish initialization */

    uint8   tmp_intra_pred_left[17]; /* a column of pixel for intra prediction */
    uint8   tmp_intra_pred_left_cb[9];
    uint8   tmp_intra_pred_left_cr[9];

	uint8	tmp_intra_pred_topleft = 0;
	uint8	tmp_intra_pred_topleft_cb = 0;
	uint8	tmp_intra_pred_topleft_cr = 0;

	uint8 tmp_intra_pred_top[PICWIDTHINMBS<<4];
	uint8 tmp_intra_pred_top_cb[PICWIDTHINMBS<<3];
	uint8 tmp_intra_pred_top_cr[PICWIDTHINMBS<<3];



	while( !(*H264_File_NULL) ){

		/* remove an item from the buffer */
        while(1){
        	if((*g_SEC_Buf.m_front == *g_SEC_Buf.m_rear) ){
            }
            else{
                break;
            }

        }


        int num_tmp;
		num_tmp = (*g_SEC_Buf.m_front+1)%BUF_DEPTH;

		AVCCommonObj *video;
		video = (AVCCommonObj *)localMemAddr_fir[num_tmp];

		while(!video->finish_flag_1){
		}



		/* not sure , 2013/10/25 */
		microblaze_invalidate_dcache_range(video->currMB,sizeof(AVCMacroblock));

		AVCMacroblock *currMB = video->currMB;

		video->intra_pred_top = tmp_intra_pred_top;
		video->intra_pred_top_cb = tmp_intra_pred_top_cb;
		video->intra_pred_top_cr = tmp_intra_pred_top_cr;

		video->intra_pred_left = tmp_intra_pred_left;
		video->intra_pred_left_cb = tmp_intra_pred_left_cb;
		video->intra_pred_left_cr = tmp_intra_pred_left_cr;


		//bind
		if(currMB->mbMode != AVC_SKIP ){
			video->intra_pred_topleft = tmp_intra_pred_topleft;
			video->intra_pred_topleft_cb = tmp_intra_pred_topleft_cb;
			video->intra_pred_topleft_cr = tmp_intra_pred_topleft_cr;
		}


		/* do Intra/Inter prediction, together with the residue compensation */
		/* This part should be common between the skip and no-skip */


		if(currMB->mbMode != AVC_SKIP ){
			if (currMB->mbMode == AVC_I4 || currMB->mbMode == AVC_I16){
				IntraMBPrediction(video);
			}
			else{
				InterMBPrediction(video);
			}
		}

		if(currMB->mbMode == AVC_SKIP)
			video->mb_skip_run--;

		SaveNeighborForIntraPred(video, 0);

		/* backup */


		tmp_intra_pred_topleft = video->intra_pred_topleft;
		tmp_intra_pred_topleft_cb = video->intra_pred_topleft_cb;
		tmp_intra_pred_topleft_cr = video->intra_pred_topleft_cr;


		while(1){

			if((*g_THIR_Buf.m_rear+1) % BUF_DEPTH == *g_THIR_Buf.m_front ){
			}
			else
				break;

		}


		video->finish_flag_2 = 1;


		lm_transfer((void*)localMemAddr_sec[(*g_THIR_Buf.m_rear+1)%BUF_DEPTH], (void*)localMemAddr_fir[(*g_SEC_Buf.m_front+1)%BUF_DEPTH], sizeof(AVCCommonObj));


	    while(transfer_status()){};


		// finish to sent data to buffer
		mutex_lock( g_THIR_Buf.mutex );
			*g_THIR_Buf.m_rear = (*g_THIR_Buf.m_rear+1)%BUF_DEPTH;

		mutex_unlock(g_THIR_Buf.mutex);

		// finish get data
		mutex_lock( g_SEC_Buf.mutex );

			video->finish_flag_1 = 0;

			*g_SEC_Buf.m_front = (*g_SEC_Buf.m_front+1)%BUF_DEPTH;
			int *pbr ;
			pbr = (void*)0x84410C04L;
			if(*g_SEC_Buf.m_front == *g_SEC_Buf.m_rear){
				*pbr = 1;
			}
			else{
				*pbr = 0;
			}

        mutex_unlock(g_SEC_Buf.mutex);
	}
	return 0;
}

int consumer_deblock(unsigned int core_id)
{


	while( !(*H264_File_NULL) ){
		/* remove an item from the buffer */

        while(1){
        	if((*g_THIR_Buf.m_front == *g_THIR_Buf.m_rear) ){
        		//smp_sleep(100);
            }
            else{
                break;
            }

        }


		int num_tmp;

		num_tmp = (*g_THIR_Buf.m_front+1)%BUF_DEPTH;


		AVCCommonObj *video;
		video = (AVCCommonObj *)localMemAddr_sec[num_tmp];
		while(!video->finish_flag_2){
		}


#ifdef MB_BASED_DEBLOCK

		MBInLoopDeblock(video); /* MB-based deblocking */


		// finish get data
		mutex_lock( g_THIR_Buf.mutex );
			*g_THIR_Buf.m_front = (*g_THIR_Buf.m_front+1)%BUF_DEPTH;

			video->finish_flag_2 = 0;

			int *pbr ;
			pbr = (void*)0x84410C08L;

			if(*g_THIR_Buf.m_front == *g_THIR_Buf.m_rear){
				*pbr = 1;
			}
			else{
				*pbr = 0;
			}


        mutex_unlock(g_THIR_Buf.mutex);

#endif

	}

	return 0;
}


void AVCDecInit(AVCHandle * mHandle,int *mSPSSeen,int *mPPSSeen,int * H264_Offset){

	memset(mHandle, 0, sizeof(AVCHandle));
    mHandle->AVCObject = NULL;
    mHandle->userData = NULL;
    mHandle->CBAVC_Malloc = Malloc;                 // if u want how to implement those function
    mHandle->CBAVC_Free = Free;                     // u can see AVCDecoder.cpp
	*mSPSSeen = 0;
    *mPPSSeen = 0;
	*H264_Offset=0;
	
}

int DecNALUnit (AVCHandle *mHandle,const uint8_t *NALUnit,const int NALSize,int *mSPSSeen,int *mPPSSeen)
{
    int nalType;
    int nalRefIdc;
    AVCDec_Status res =PVAVCDecGetNALType((uint8_t *)(NALUnit), NALSize,&nalType, &nalRefIdc);



    if (res != AVCDEC_SUCCESS) {
		printf("cannot determine nal type\n");
    } else if (nalType == AVC_NALTYPE_SPS || nalType == AVC_NALTYPE_PPS|| (*mSPSSeen &&* mPPSSeen)) {
        switch (nalType) {
            case AVC_NALTYPE_SPS:
            {	
                *mSPSSeen = true;
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].ptr = (uint8_t *)(NALUnit);
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nal_size = NALSize;
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nalType = AVC_NALTYPE_SPS;
				
                if (res != AVCDEC_SUCCESS) {
                	mutex_lock(APP_MUTEX_NUM);
					printf("PVAVCDecSeqParamSet returned error %d\n", res);
					mutex_unlock(APP_MUTEX_NUM);
                    return -1;//fail
                }		
				return 0;//ok,but no data
                break;
            }

            case AVC_NALTYPE_PPS:
            {	
				*mPPSSeen = true;
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].ptr = (uint8_t *)(NALUnit);
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nal_size = NALSize;
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nalType = AVC_NALTYPE_PPS;
                if (res != AVCDEC_SUCCESS) {
                	mutex_lock(APP_MUTEX_NUM);
					printf("PVAVCDecPicParamSet returned error %d", res);
					mutex_unlock(APP_MUTEX_NUM);
                   return -1;
                }
				return 0;//ok,but no data
                break;
            }

            case AVC_NALTYPE_SLICE:
            {
				/* send NAL unit to input buffer */
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].ptr = (uint8_t *)(NALUnit);
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nal_size = NALSize;
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nalType = AVC_NALTYPE_SLICE;
                if (res == AVCDEC_PICTURE_OUTPUT_READY) {
					//return 0;
                    break;
                }

				else if( res == AVCDEC_SUCCESS || res == AVCDEC_PICTURE_READY){
					// return 1;
				}
				else {
					mutex_lock(APP_MUTEX_NUM);
					printf("Slice , PVAVCDecodeSlice returned error %d", res);
					mutex_lock(APP_MUTEX_NUM);
					return -1;
				}
                break;
            }
            case AVC_NALTYPE_IDR:
            {
				/* send NAL unit to input buffer */
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].ptr = (uint8_t *)(NALUnit);
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nal_size = NALSize;
				g_NAL_Buf.buf[(*g_NAL_Buf.m_rear+1)%BUF_DEPTH].nalType = AVC_NALTYPE_IDR;
                if (res == AVCDEC_PICTURE_OUTPUT_READY) {
					//return 0;
                    break;
                }

				else if( res == AVCDEC_SUCCESS || res == AVCDEC_PICTURE_READY){
					// return 1;
				}
				else {
					mutex_lock(APP_MUTEX_NUM);
					printf("IDR , PVAVCDecodeSlice returned error %d", res);
					mutex_lock(APP_MUTEX_NUM);
					return -1;
				}
                break;
            }

            case AVC_NALTYPE_SEI:
            {
				// not support ????
                // res = PVAVCDecSEI(
                        // mHandle, (uint8_t *)(NALUnit),
                        // NALSize);

                if (res != AVCDEC_SUCCESS) {
                    return -1;
                }

                break;
            }

            case AVC_NALTYPE_AUD:
            case AVC_NALTYPE_FILL:
            case AVC_NALTYPE_EOSEQ:
			{
			
                break;
            }

            default:
            {
              //  LOGE("Should not be here, unknown nalType %d", nalType);
              //  CHECK(!"Should not be here");
				return -1;
                break;
            }
        }
    } else {
        // We haven't seen SPS or PPS yet.
    }
	return 0;//ok,but no data

}

int ReadNALUnit(const uint8_t * H264_File , int H264_Offset ,int H264_Size ,const uint8_t ** NALUnit ,int *NALSize ){

	const uint8_t *data =
        (const uint8_t *)H264_File + H264_Offset;

	int size = H264_Size;

	if(size < 4){                  
		return -1 ; //fail
	}
	if(memcmp(kStartCode, data, 4)){
		return -1 ; //fail
	}

	int offset = 4;
    while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) {//find next NAL startcode
        ++offset;
    }

    *NALUnit = &data[4];
    if (offset + 3 >= size) {
        *NALSize = size - 4;
    } else {
        *NALSize = offset - 4;
    }
	return 1 ;


}
