// ****************** Copyright (c) 2013 by Gigaset Communications GmbH ******
// Filename : tdav_codec_fsl_vpu_h263.c
// Owner    : Souparna Lodh [STC]
//-------------------------------------------------------------------------
// Defintion : H.263-1996 and H.263-1998 codec plugins from Freescale VPU Libraries.
// RTP payloader follows RFC 4629 for H263+ and RFC 2190 for H263.
//-------------------------------------------------------------------------
// 05-07-2013, Gigaset Communications GmbH
// Added FSL VPU H263  codec plugin to Doubango Framework
//*************************************************************************

/*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/

#undef VPU_OPTIMUM

#include <stdint.h>
#include <errno.h>

#include "tinydav/codecs/h263/tdav_codec_fsl_vpu_h263.h"

#include "tinydav/video/tdav_converter_video.h"

#include "tinyrtp/rtp/trtp_rtp_packet.h"

#include "tnet_endianness.h"

#include "tinymedia/tmedia_params.h"

#include "tsk_string.h"
#include "tsk_time.h"
#include "tsk_memory.h"
#include "tsk_debug.h"

#include <libavcodec/avcodec.h>

#include "vpu_lib.h"
#include "vpu_io.h"

//#ifdef VPU_OPTIMUM
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
//#endif

#define TDAV_H263_GOP_SIZE_IN_SECONDS		25
#define RTP_PAYLOAD_SIZE	750
#define RTP_PAYLOAD_CORRECTION 5

#define H263_HEADER_MODE_A_SIZE 4
#define H263_HEADER_MODE_B_SIZE 8
#define H263_HEADER_MODE_C_SIZE 12

#define TDAV_CODEC_FSL_VPU_H263(self) ((tdav_codec_fsl_vpu_h263_t*)(self))

#define STREAM_BUF_SIZE		0xF00000
#define PS_SAVE_SIZE		0x080000
#define STREAM_END_SIZE		0
#define SIZE_USER_BUF            0x1000

#define NUM_FRAME_BUFS	32
#define FB_INDEX_MASK	(NUM_FRAME_BUFS - 1)

//#define CLOCKTICKSPERSECOND 10000

enum {
    MODE420 = 0,
    MODE422 = 1,
    MODE224 = 2,
    MODE444 = 3,
    MODE400 = 4
};

struct frame_buf {
	    int addrY;
	    int addrCb;
	    int addrCr;
	    int strideY;
	    int strideC;
	    int mvColBuf;
	    vpu_mem_desc desc;
    };

static int fb_index;
static struct frame_buf *fbarray[NUM_FRAME_BUFS];
static struct frame_buf fbpool[NUM_FRAME_BUFS];

static tsk_bool_t decoder_stream_parsed;

typedef enum tdav_codec_fsl_vpu_h263_type_e
{
	tdav_codec_fsl_vpu_h263_1996,
}
tdav_codec_fsl_vpu_h263_type_t;

/** Freescale VPU H.263-1996 codec */
typedef struct tdav_codec_fsl_vpu_h263_s
{
	TMEDIA_DECLARE_CODEC_VIDEO;

	tdav_codec_fsl_vpu_h263_type_t type;

	struct{
		uint8_t* ptr;
		tsk_size_t size;
	} rtp;

    // Encoder
	struct{
		void* buffer;
        tsk_size_t buffer_size;
		tsk_bool_t force_idr;

        vpu_mem_desc* mem_desc;
        EncHandle handle;		/* Encoder handle */
	    PhysicalAddress phy_bsbuf_addr; /* Physical bitstream buffer */
	    uint32_t virt_bsbuf_addr;		/* Virtual bitstream buffer */
	    int enc_picwidth;	/* Encoded Picture width */
	    int enc_picheight;	/* Encoded Picture height */
	    int src_picwidth;        /* Source Picture width */
	    int src_picheight;       /* Source Picture height */
	    int totalfb;	/* Total number of framebuffers allocated */
	    int src_fbid;	/* Index of frame buffer that contains YUV image */
	    FrameBuffer *fb; /* frame buffer base given to encoder */
	    struct frame_buf **pfbpool; /* allocated fb pointers are stored here */
	    int minFrameBufferCount;

	} encoder;

	// decoder
	struct{
		AVCodecContext* context;

		void* accumulator;
		uint8_t ebit;
		tsk_size_t accumulator_pos;
		uint16_t last_seq;

        vpu_mem_desc* mem_desc;
        DecHandle handle;
	    PhysicalAddress phy_bsbuf_addr;
	    uint32_t virt_bsbuf_addr;
	    int picwidth;
	    int picheight;
	    int stride;
	    int regfbcount;
	    int minfbcount;
	    FrameBuffer *fb;
	    struct frame_buf **pfbpool;
	    Rect picCropRect;
	    //DecReportInfo userData;

	} decoder;
}
tdav_codec_fsl_vpu_h263_t;

#define TDAV_DECLARE_CODEC_FSL_VPU_H263 tdav_codec_fsl_vpu_h263_t __codec_h263__

static int	freadn(int fd, void **vptr, size_t n);
static void framebuf_init(void);
static int mem_copy(const void *inputBuff, void *destBuff, int n);
static int dec_fill_bsbuffer(const void* inputBuff, DecHandle handle, uint32_t bs_va_startaddr, uint32_t bs_va_endaddr,
		uint32_t bs_pa_startaddr, int defaultsize,
		int *eos, int *fill_end_bs);
static int dec_parse(tdav_codec_fsl_vpu_h263_t* self);
static struct frame_buf *get_framebuf(void);
static struct frame_buf *framebuf_alloc(int stdMode, int format, int strideY, int height, int mvCol);
static void put_framebuf(struct frame_buf *fb);
static void framebuf_free(struct frame_buf *fb);
//static void memwriten(void *vptr, size_t n, void *out_data);
static void saveCropYuvImageHelper(tdav_codec_fsl_vpu_h263_t* self, uint8_t *buf, Rect cropRect, void *out_data);
static void saveNV12ImageHelper(uint8_t *pYuv, tdav_codec_fsl_vpu_h263_t* self, uint8_t *buf);
static void write_to_output(tdav_codec_fsl_vpu_h263_t* self, Rect cropRect, int index, void **out_data, tsk_size_t* out_max_size);
static int encoder_allocate_framebuffer(tdav_codec_fsl_vpu_h263_t* self);
static int encoder_readbs_reset_buffer(tdav_codec_fsl_vpu_h263_t* self, PhysicalAddress paBsBufAddr, int bsBufsize, void **out_data, tsk_size_t* out_max_size);
static int encode_one_frame(tdav_codec_fsl_vpu_h263_t* self, const void* in_data, tsk_size_t in_size, void **out_data, tsk_size_t* out_max_size);
static void encoder_free_framebuffer(tdav_codec_fsl_vpu_h263_t* self);
static int decoder_allocate_framebuffer(tdav_codec_fsl_vpu_h263_t* self);
static int decode_one_frame(tdav_codec_fsl_vpu_h263_t* self, void **out_data, tsk_size_t* out_max_size, int mode);
static void decoder_free_framebuffer(tdav_codec_fsl_vpu_h263_t* self);

static int tdav_codec_fsl_vpu_h263_init(tdav_codec_fsl_vpu_h263_t* self, tdav_codec_fsl_vpu_h263_type_t type);
static int tdav_codec_fsl_vpu_h263_deinit(tdav_codec_fsl_vpu_h263_t* self);
static int tdav_codec_fsl_vpu_h263_open_encoder(tdav_codec_fsl_vpu_h263_t* self);
static int tdav_codec_fsl_vpu_h263_open_decoder(tdav_codec_fsl_vpu_h263_t* self);
static int tdav_codec_fsl_vpu_h263_close_encoder(tdav_codec_fsl_vpu_h263_t* self);
static int tdav_codec_fsl_vpu_h263_close_decoder(tdav_codec_fsl_vpu_h263_t* self);

static void tdav_codec_fsl_vpu_h263_rtp_callback(tdav_codec_fsl_vpu_h263_t *self, const void *data, tsk_size_t size, tsk_bool_t marker);

static void tdav_codec_fsl_vpu_h263_encap(const tdav_codec_fsl_vpu_h263_t* h263, const uint8_t* pdata, tsk_size_t size);


static int tdav_codec_fsl_vpu_h263_set(tmedia_codec_t* self, const tmedia_param_t* param)
{
	tdav_codec_fsl_vpu_h263_t* h263 = (tdav_codec_fsl_vpu_h263_t*)self;
	if(!self->opened){
		TSK_DEBUG_ERROR("Codec not opened");
		return -1;
	}
	if(param->value_type == tmedia_pvt_int32){
		if(tsk_striequals(param->key, "action")){
			tmedia_codec_action_t action = (tmedia_codec_action_t)TSK_TO_INT32((uint8_t*)param->value);
			switch(action){
				case tmedia_codec_action_encode_idr:
					{
						h263->encoder.force_idr = tsk_true;
						break;
					}
				case tmedia_codec_action_bw_down:
					{
						break;
					}
				case tmedia_codec_action_bw_up:
					{
						break;
					}
			}
			return 0;
		}
	}
	return -1;
}

/* Read n bytes from a file descriptor */
int	freadn(int fd, void **vptr, size_t n)
{
	int nleft = 0;
	int nread = 0;
    char  *ptr;

	ptr = *vptr;
	nleft = n;

    if(nleft == -1) { //meaning read complete file
        struct stat fileStat;
        if(fstat(fd, &fileStat) < 0) {
            return -1;
        }
        nleft = fileStat.st_size;
        //__android_log_print("Teleca", "FSL VPU H263", "freadn nleft = %ld\n", nleft);

        if(ptr == NULL) {
            ptr = (char *) (tsk_calloc(nleft, sizeof(uint8_t)));
            if(ptr == NULL) {
                return -1;
            }
            *vptr = (void *) ptr;
        }
    }

    while (nleft > 0) {
        if ( (nread = read(fd, ptr, nleft)) <= 0) {
			if (nread == 0)
				return (n - nleft);

			perror("read");
			return (-1);			/* error EINTR XXX */
		}

		nleft -= nread;
		ptr   += nread;
	}

    return (nread);
}

void framebuf_init(void)
{
	int i;

	for (i = 0; i < NUM_FRAME_BUFS; i++) {
		fbarray[i] = &fbpool[i];
	}
}

int mem_copy(const void *inputBuff, void *destBuff, int n)
{
    memcpy(destBuff, inputBuff, n);
    return n; //TODO: Remove this return and its dependencies in the whole code
}

int dec_fill_bsbuffer(const void* inputBuff, DecHandle handle, uint32_t bs_va_startaddr, uint32_t bs_va_endaddr,
		uint32_t bs_pa_startaddr, int defaultsize,
		int *eos, int *fill_end_bs)
{
    //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer in\n");
	RetCode ret;
	PhysicalAddress pa_read_ptr, pa_write_ptr;
	uint32_t target_addr, space;
	int size;
	int nread, room;
	*eos = 0;

	ret = vpu_DecGetBitstreamBuffer(handle, &pa_read_ptr, &pa_write_ptr,
					&space);
	if (ret != RETCODE_SUCCESS) {
        //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer vpu_DecGetBitstreamBuffer failed\n");
		TSK_DEBUG_ERROR("vpu_DecGetBitstreamBuffer failed\n");
		return -1;
	}

	/* Decoder bitstream buffer is empty */
	if (space <= 0) {
        //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer no space!!!\n");
		return 0;
    }

	if (defaultsize > 0) {
		if (space < defaultsize) {
            //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer not enuf space!!!\n");
			return 0;
        }
		size = defaultsize;
	} else {
		size = ((space >> 9) << 9);
	}

	if (size == 0) {
        //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer space == 0!!!\n");
		return 0;
    }
	/* Fill the bitstream buffer */
	target_addr = bs_va_startaddr + (pa_write_ptr - bs_pa_startaddr);
	if ( (target_addr + size) > bs_va_endaddr) {
        //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - 1\n");
		room = bs_va_endaddr - target_addr;
		nread = mem_copy(inputBuff, (void *)target_addr, room);
		if (nread <= 0) {
			/* EOF or error */
			if (nread < 0) {
				if (nread == -EAGAIN)
					return 0;

				return -1;
			}

			*eos = 1;
		} else {
			/* unable to fill the requested size, so back off! */
			if (nread != room)
				goto update;

			/* read the remaining */
			space = nread;
            //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - 2\n");
			nread = mem_copy(inputBuff, (void *)bs_va_startaddr, (size - room));
			if (nread <= 0) {
				/* EOF or error */
				if (nread < 0) {
					if (nread == -EAGAIN)
						return 0;

					return -1;
				}

				*eos = 1;
			}

			nread += space;
		}
	} else {
        //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - 3\n");
		nread = mem_copy(inputBuff, (void *)target_addr, size);
		if (nread <= 0) {
            //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - 3 - error\n");
			/* EOF or error */
			if (nread < 0) {
				if (nread == -EAGAIN)
					return 0;

				return -1;
			}

			*eos = 1;
		}
	}

update:
	if (*eos == 0) {
        //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - attempted vpu_DecUpdateBitstreamBuffer\n");
		ret = vpu_DecUpdateBitstreamBuffer(handle, nread);
		if (ret != RETCODE_SUCCESS) {
            //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - vpu_DecUpdateBitstreamBuffer failed\n");
			TSK_DEBUG_ERROR("vpu_DecUpdateBitstreamBuffer failed\n");
			return -1;
		}
		*fill_end_bs = 0;
	} else {
		if (!*fill_end_bs) {
            //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - attempted vpu_DecUpdateBitstreamBuffer\n");
			ret = vpu_DecUpdateBitstreamBuffer(handle,
					STREAM_END_SIZE);
			if (ret != RETCODE_SUCCESS) {
                //__android_log_print("Teleca", "FSL VPU H263", "dec_fill_bsbuffer - vpu_DecUpdateBitstreamBuffer failed\n");
				TSK_DEBUG_ERROR("vpu_DecUpdateBitstreamBuffer failed"
								"\n");
				return -1;
			}
			*fill_end_bs = 1;
		}

	}

	return nread;
}

int dec_parse(tdav_codec_fsl_vpu_h263_t* self)
{
	DecInitialInfo initinfo = {0};
	DecHandle handle = self->decoder.handle;
	int align, profile, level, extended_fbcount;
	RetCode ret;
	char *count;

	/*
	 * If userData report is enabled, buffer and comamnd need to be set
 	 * before DecGetInitialInfo for MJPG.
	 */
	/*if (self->decoder.userData.enable) {
		self->decoder.userData.size = SIZE_USER_BUF;
		self->decoder.userData.addr = tsk_malloc(SIZE_USER_BUF);
		if (!self->decoder.userData.addr)
			TSK_DEBUG_ERROR("tsk_malloc_error\n");
	}*/

	/* Parse bitstream and get width/height/framerate etc */
	vpu_DecSetEscSeqInit(handle, 1);
	ret = vpu_DecGetInitialInfo(handle, &initinfo);
	vpu_DecSetEscSeqInit(handle, 0);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("vpu_DecGetInitialInfo failed, ret:%d, errorcode:%ld\n",
		         ret, initinfo.errorcode);
		return -1;
	}

	/*
	 * It is suggested to add two more buffers than minFrameBufferCount:
	 *
	 * vpu_DecClrDispFlag is used to control framebuffer whether can be
	 * used for decoder again. One framebuffer dequeue from IPU is delayed
	 * for performance improvement and one framebuffer is delayed for
	 * display flag clear.
	 *
	 * Performance is better when more buffers are used if IPU performance
	 * is bottleneck.
	 *
	 * Two more buffers may be needed for interlace stream from IPU DVI view
	 */
	self->decoder.minfbcount = initinfo.minFrameBufferCount;
	count = getenv("VPU_EXTENDED_BUFFER_COUNT");
	if (count)
		extended_fbcount = atoi(count);
	else
		extended_fbcount = 2;

	if (initinfo.interlace)
		self->decoder.regfbcount = self->decoder.minfbcount + extended_fbcount + 2;
	else
		self->decoder.regfbcount = self->decoder.minfbcount + extended_fbcount;

    //__android_log_print("Teleca", "FSL VPU H263", "minfbcount = %d\n", self->decoder.minfbcount);
    //__android_log_print("Teleca", "FSL VPU H263", "regfbcount = %d\n", self->decoder.regfbcount);

	self->decoder.picwidth = ((initinfo.picWidth + 15) & ~15);

    //__android_log_print("Teleca", "FSL VPU H263", "picwidth from vpu= %d\n", self->decoder.picwidth);

	align = 16;
	
	self->decoder.picheight = ((initinfo.picHeight + align - 1) & ~(align - 1));

    //__android_log_print("Teleca", "FSL VPU H263", "picheight from vpu = %d\n", self->decoder.picheight);

	if ((self->decoder.picwidth == 0) || (self->decoder.picheight == 0))
		return -1;

	/* Add non-h264 crop support, assume left=top=0 */
	if ((self->decoder.picwidth > initinfo.picWidth ||
		self->decoder.picheight > initinfo.picHeight) &&
		(!initinfo.picCropRect.left &&
		!initinfo.picCropRect.top &&
		!initinfo.picCropRect.right &&
		!initinfo.picCropRect.bottom)) {
        //__android_log_print("Teleca", "FSL VPU H263", "Getting in Add non-h264 crop support\n");
		initinfo.picCropRect.left = 0;
		initinfo.picCropRect.top = 0;
		initinfo.picCropRect.right = initinfo.picWidth;
		initinfo.picCropRect.bottom = initinfo.picHeight;
	}

    /*__android_log_print("Teleca", "FSL VPU H263", "CROP left/top/right/bottom %lu %lu %lu %lu\n",
					initinfo.picCropRect.left,
					initinfo.picCropRect.top,
					initinfo.picCropRect.right,
					initinfo.picCropRect.bottom);*/

	memcpy(&(self->decoder.picCropRect), &(initinfo.picCropRect),
					sizeof(initinfo.picCropRect));

	/* worstSliceSize is in kilo-byte unit */
	//self->decoder.phy_slicebuf_size = initinfo.worstSliceSize * 1024;
	self->decoder.stride = self->decoder.picwidth;

	return 0;
}

struct frame_buf *get_framebuf(void)
{
	struct frame_buf *fb;

	fb = fbarray[fb_index];
	fbarray[fb_index] = 0;

	++fb_index;
	fb_index &= FB_INDEX_MASK;

	return fb;
}

struct frame_buf *framebuf_alloc(int stdMode, int format, int strideY, int height, int mvCol)
{
	struct frame_buf *fb;
	int err;
	int divX, divY;

	fb = get_framebuf();
	if (fb == NULL) {
        TSK_DEBUG_ERROR("framebuf_alloc - get_framebuf == NULL\n");
		return NULL;
    }

    divX = (format == MODE420 || format == MODE422) ? 2 : 1;
	divY = (format == MODE420 || format == MODE224) ? 2 : 1;

	memset(&(fb->desc), 0, sizeof(vpu_mem_desc));
	fb->desc.size = (strideY * height  + strideY / divX * height / divY * 2);
	if (mvCol)
		fb->desc.size += strideY / divX * height / divY;

	err = IOGetPhyMem(&fb->desc);
	if (err) {
        TSK_DEBUG_ERROR("framebuf_alloc - IOGetPhyMem error!\n");
		memset(&(fb->desc), 0, sizeof(vpu_mem_desc));
		return NULL;
	}

	fb->addrY = fb->desc.phy_addr;
	fb->addrCb = fb->addrY + strideY * height;
	fb->addrCr = fb->addrCb + strideY / divX * height / divY;
	fb->strideY = strideY;
	fb->strideC =  strideY / divX;
	if (mvCol)
		fb->mvColBuf = fb->addrCr + strideY / divX * height / divY;

	fb->desc.virt_uaddr = IOGetVirtMem(&(fb->desc));
	if (fb->desc.virt_uaddr <= 0) {
        TSK_DEBUG_ERROR("framebuf_alloc - IOGetVirtMem error!\n");
		IOFreePhyMem(&fb->desc);
		memset(&(fb->desc), 0, sizeof(vpu_mem_desc));
		return NULL;
	}

	return fb;
}

void put_framebuf(struct frame_buf *fb)
{
	--fb_index;
	fb_index &= FB_INDEX_MASK;

	fbarray[fb_index] = fb;
}

void framebuf_free(struct frame_buf *fb)
{
	if (fb == NULL)
		return;

	if (fb->desc.virt_uaddr) {
		IOFreeVirtMem(&fb->desc);
	}

	if (fb->desc.phy_addr) {
		IOFreePhyMem(&fb->desc);
	}

	memset(&(fb->desc), 0, sizeof(vpu_mem_desc));
	put_framebuf(fb);
}

/*void memwriten(void *vptr, size_t n, void *out_data)
{
	memcpy(out_data, vptr, n);
}*/

void saveCropYuvImageHelper(tdav_codec_fsl_vpu_h263_t* self, uint8_t *buf, Rect cropRect, void *out_data)
{
	uint8_t *pCropYuv;
	int cropWidth, cropHeight;
	int i;

	int width = self->decoder.picwidth;
	int height = self->decoder.picheight;
	
	if (!buf) {
		TSK_DEBUG_ERROR("buffer point should not be NULL.\n");
		return;
	}

	pCropYuv = buf;
	cropWidth = cropRect.right - cropRect.left;
	cropHeight = cropRect.bottom - cropRect.top;

	pCropYuv += width * cropRect.top;
	pCropYuv += cropRect.left;

	for (i = 0; i < cropHeight; i++) {
		//memwriten(pCropYuv, cropWidth, out_data);
        mem_copy(pCropYuv, out_data, cropWidth);
		pCropYuv += width;
	}

	cropWidth /= 2;
	cropHeight /= 2;
	pCropYuv = buf + (width * height);
	pCropYuv += (width / 2) * (cropRect.top / 2);
	pCropYuv += cropRect.left / 2;

	for (i = 0; i < cropHeight; i++) {
		//memwriten(pCropYuv, cropWidth, out_data);
        mem_copy(pCropYuv, out_data, cropWidth);
		pCropYuv += width / 2;
	}

	pCropYuv = buf + (width * height) * 5 / 4;
	pCropYuv += (width / 2) * (cropRect.top / 2);
	pCropYuv += cropRect.left / 2;

	for (i = 0; i < cropHeight; i++) {
		//memwriten(pCropYuv, cropWidth, out_data);
        mem_copy(pCropYuv, out_data, cropWidth);
		pCropYuv += width / 2;
	}
}

/*
 * This function is to convert framebuffer from interleaved Cb/Cr mode
 * to non-interleaved Cb/Cr mode.
 *
 * Note: This function does _NOT_ really store this framebuffer into file.
 */
void saveNV12ImageHelper(uint8_t *pYuv, tdav_codec_fsl_vpu_h263_t* self, uint8_t *buf)
{
	int Y, Cb;
	uint8_t *Y1, *Cb1, *Cr1;
	int img_size;
	int y, x;
	uint8_t *tmp;
	int height = self->decoder.picheight;
	int stride = self->decoder.stride;

	if (!pYuv || !buf) {
		TSK_DEBUG_ERROR("pYuv or buf should not be NULL.\n");
		return;
	}

	img_size = stride * height;

	Y = (int)buf;
	Cb = Y + img_size;

	Y1 = pYuv;
	Cb1 = Y1 + img_size;
	Cr1 = Cb1 + (img_size >> 2);

	memcpy(Y1, (uint8_t *)Y, img_size);

	for (y = 0; y < (self->decoder.picheight / 2); y++) {
		tmp = (uint8_t *)(Cb + self->decoder.picwidth * y);
		for (x = 0; x < self->decoder.picwidth; x += 2) {
			*Cb1++ = tmp[x];
			*Cr1++ = tmp[x + 1];
		}
	}
}

void write_to_output(tdav_codec_fsl_vpu_h263_t* self, Rect cropRect, int index, void **out_data, tsk_size_t* out_max_size)
{
	int height = (self->decoder.picheight + 15) & ~15 ;
	int stride = self->decoder.stride;
	int chromaInterleave = 1;
	int img_size;
	uint8_t *pYuv = NULL, *pYuv0 = NULL, *buf;
	struct frame_buf *pfb = NULL;
	int cropping;

	cropping = cropRect.left | cropRect.top | cropRect.bottom | cropRect.right;

	pfb = self->decoder.pfbpool[index];
	buf = (uint8_t *)(pfb->addrY + pfb->desc.virt_uaddr - pfb->desc.phy_addr);

	img_size = stride * height * 3 / 2;

    if(!(*out_data)) {
        if(!(*out_data = tsk_malloc(img_size))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
		}
		*out_max_size = img_size;
    } else if(*out_max_size != img_size) {
        if(!(out_data = tsk_realloc(out_data, img_size))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
		}
		*out_max_size = img_size;
    }

	/*
	 * There could be these three cases:
	 * interleave == 0, cropping == 1
	 * interleave == 1, cropping == 0
	 * interleave == 1, cropping == 1
	 */
	if (chromaInterleave) {
		if (!pYuv) {
			pYuv0 = pYuv = tsk_malloc(img_size);
			if (!pYuv)
				TSK_DEBUG_ERROR("malloc error\n");
		}

        //__android_log_print("Teleca", "FSL VPU H263", "write_to_output - saveNV12ImageHelper\n");
		saveNV12ImageHelper(pYuv, self, buf);
	}

	if (cropping) {
        //__android_log_print("Teleca", "FSL VPU H263", "write_to_output - cropping\n");
		if (!pYuv0) {
			pYuv0 = pYuv = tsk_malloc(img_size);
			if (!pYuv)
				TSK_DEBUG_ERROR("malloc error\n");

			saveCropYuvImageHelper(self, buf, cropRect, *out_data);
		} else {/* process the buf beginning at pYuv0 again for Crop. */
			pYuv = pYuv0;
			saveCropYuvImageHelper(self, pYuv, cropRect, *out_data);
		}

	} else {
        //__android_log_print("Teleca", "FSL VPU H263", "write_to_output - NO cropping\n");
		//memwriten((uint8_t *)pYuv0, img_size, out_data);
        mem_copy((uint8_t *)pYuv0, *out_data, img_size);
	}

out:
	if (pYuv0) {
		TSK_FREE(pYuv0);
		pYuv0 = NULL;
		pYuv = NULL;
	}

	return;
}

int encoder_allocate_framebuffer(tdav_codec_fsl_vpu_h263_t* self)
{
    EncHandle handle = self->encoder.handle;
	int i, enc_stride, src_stride, src_fbid;
	int totalfb, minfbcount, srcfbcount, extrafbcount;
	RetCode ret;
	FrameBuffer *fb;
	PhysicalAddress subSampBaseA = 0, subSampBaseB = 0;
	struct frame_buf **pfbpool;
	EncExtBufInfo extbufinfo = {0};
	int enc_fbwidth, enc_fbheight, src_fbwidth, src_fbheight;

	minfbcount = self->encoder.minFrameBufferCount;
	srcfbcount = 1;

	/*enc_fbwidth = (self->encoder.enc_picwidth + 15) & ~15;
	enc_fbheight = (self->encoder.enc_picheight + 15) & ~15;
	src_fbwidth = (self->encoder.src_picwidth + 15) & ~15;
	src_fbheight = (self->encoder.src_picheight + 15) & ~15;*/
    enc_fbwidth = self->encoder.enc_picwidth;
	enc_fbheight = self->encoder.enc_picheight;
	src_fbwidth = self->encoder.src_picwidth;
	src_fbheight = self->encoder.src_picheight;

	if (cpu_is_mx6x()) 
        extrafbcount = 2; /* Subsamp buffer [2] */
	else
		extrafbcount = 0;

	self->encoder.totalfb = totalfb = minfbcount + extrafbcount + srcfbcount;

	/* last framebuffer is used as src frame in the test */
	self->encoder.src_fbid = src_fbid = totalfb - 1;

	fb = self->encoder.fb = tsk_calloc(totalfb, sizeof(FrameBuffer));
	if (fb == NULL) {
		TSK_DEBUG_ERROR("Failed to allocate enc->fb\n");
		return -1;
	}

	pfbpool = self->encoder.pfbpool = tsk_calloc(totalfb,
					sizeof(struct frame_buf *));
	if (pfbpool == NULL) {
		TSK_DEBUG_ERROR("Failed to allocate enc->pfbpool\n");
		TSK_FREE(fb);
		return -1;
	}

	/* All buffers are linear */
	for (i = 0; i < minfbcount + extrafbcount; i++) {
		pfbpool[i] = framebuf_alloc(STD_H263, /*enc->mjpg_fmt*/0,
					    enc_fbwidth, enc_fbheight, 0);
		if (pfbpool[i] == NULL) {
			goto err1;
		}
	}
	
	for (i = 0; i < minfbcount + extrafbcount; i++) {
		fb[i].myIndex = i;
		fb[i].bufY = pfbpool[i]->addrY;
		fb[i].bufCb = pfbpool[i]->addrCb;
		fb[i].bufCr = pfbpool[i]->addrCr;
		fb[i].strideY = pfbpool[i]->strideY;
		fb[i].strideC = pfbpool[i]->strideC;
	}

	if (cpu_is_mx6x() ) {
		subSampBaseA = fb[minfbcount].bufY;
		subSampBaseB = fb[minfbcount + 1].bufY;
	}

	/*enc_stride = (self->encoder.enc_picwidth + 15) & ~15;
	src_stride = (self->encoder.src_picwidth + 15 ) & ~15;*/
    enc_stride = self->encoder.enc_picwidth;
	src_stride = self->encoder.src_picwidth;

	//extbufinfo.scratchBuf = self->encoder.scratchBuf;
	ret = vpu_EncRegisterFrameBuffer(handle, fb, minfbcount, enc_stride, src_stride,
					    subSampBaseA, subSampBaseB, &extbufinfo);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("Register frame buffer failed\n");
		goto err1;
	}

	/* Allocate a single frame buffer for source frame */
	pfbpool[src_fbid] = framebuf_alloc(STD_H263, /*enc->mjpg_fmt*/0,
					   src_fbwidth, src_fbheight, 0);
	if (pfbpool[src_fbid] == NULL) {
		TSK_DEBUG_ERROR("failed to allocate single framebuf\n");
		goto err1;
	}

	fb[src_fbid].myIndex = self->encoder.src_fbid;
	fb[src_fbid].bufY = pfbpool[src_fbid]->addrY;
	fb[src_fbid].bufCb = pfbpool[src_fbid]->addrCb;
	fb[src_fbid].bufCr = pfbpool[src_fbid]->addrCr;
	fb[src_fbid].strideY = pfbpool[src_fbid]->strideY;
	fb[src_fbid].strideC = pfbpool[src_fbid]->strideC;
	
	return 0;

err1:
	for (i = 0; i < totalfb; i++) {
		framebuf_free(pfbpool[i]);
	}

	TSK_FREE(fb);
	TSK_FREE(pfbpool);
	return -1;
}

int encoder_readbs_reset_buffer(tdav_codec_fsl_vpu_h263_t* self, PhysicalAddress paBsBufAddr, int bsBufsize, void **out_data, tsk_size_t* out_max_size)
{
	uint32_t vbuf;

	vbuf = self->encoder.virt_bsbuf_addr + paBsBufAddr - self->encoder.phy_bsbuf_addr;

    if(!(*out_data)) {
        if(!(*out_data = tsk_malloc(bsBufsize))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
            return -1;
		}
		*out_max_size = bsBufsize;
    } else if(*out_max_size != bsBufsize) {
        if(!(*out_data = tsk_realloc(*out_data, bsBufsize))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
			return -1;
		}
        //__android_log_print("Teleca", "FSL VPU H263", "encoder_readbs_reset_buffer *out_max_size != bsBufsize = %lu\n", bsBufsize);
		*out_max_size = bsBufsize;
    }

    void *out_data_copy = *out_data;

    if(bsBufsize == mem_copy((void *)vbuf, out_data_copy, bsBufsize))
        return 0;
    else
        return -1;
}

int encode_one_frame(tdav_codec_fsl_vpu_h263_t* self, const void* in_data, tsk_size_t in_size, void **out_data, tsk_size_t* out_max_size)
{
    EncHandle handle = self->encoder.handle;
	EncParam  enc_param = {0};
	EncOutputInfo outinfo = {0};
	RetCode ret = 0;
	int src_fbid = self->encoder.src_fbid, img_size;
	FrameBuffer *fb = self->encoder.fb;
	struct frame_buf **pfbpool = self->encoder.pfbpool;
	struct frame_buf *pfb;
	uint32_t yuv_addr;
	//struct timeval tenc_begin,tenc_end, total_start, total_end;
	int /*sec, usec, */loop_id;
	//float tenc_time = 0, total_time=0;
	
	enc_param.sourceFrame = &(self->encoder.fb[src_fbid]);
	enc_param.quantParam = 5;
	enc_param.forceIPicture = self->encoder.force_idr ? 1:0;
	enc_param.skipPicture = 0;
	enc_param.enableAutoSkip = 0;

	enc_param.encLeftOffset = 0;
	enc_param.encTopOffset = 0;
	
    /*if ((enc_param.encLeftOffset + enc->enc_picwidth) > enc->src_picwidth) {
		err_msg("Configure is failure for width and left offset\n");
		return -1;
	}
	if ((enc_param.encTopOffset + enc->enc_picheight) > enc->src_picheight) {
		err_msg("Configure is failure for height and top offset\n");
		return -1;
	}*/

	img_size = self->encoder.src_picwidth * self->encoder.src_picheight * 3 / 2;
    if(img_size != in_size) {
        //__android_log_print("Teleca", "FSL VPU H263", "encode_one_frame - input size and detected input size do not match!!!\n");
    }
		
	//gettimeofday(&total_start, NULL);

	pfb = pfbpool[src_fbid];
	yuv_addr = pfb->addrY + pfb->desc.virt_uaddr -
			pfb->desc.phy_addr;
	memcpy((void *)yuv_addr, in_data, img_size);

    //__android_log_print("Teleca", "FSL VPU H263", "encode_one_frame - in_data reading done\n");

	//gettimeofday(&tenc_begin, NULL);

    loop_id = 0;
    while (vpu_IsBusy()) {
		vpu_WaitForInt(1);
		if (loop_id == 5000) {
            //__android_log_print("Teleca", "FSL VPU H263", "encode_one_frame - decoder reset!\n");
			ret = vpu_SWReset(self->decoder.handle, 0);
			return -1;
		}
		loop_id ++;
	}
	ret = vpu_EncStartOneFrame(handle, &enc_param);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("vpu_EncStartOneFrame failed Err code:%d\n",ret);
		return ret;
	}

	loop_id = 0;
	while (vpu_IsBusy()) {
		vpu_WaitForInt(2);
		if (loop_id == 2000) {
            //__android_log_print("Teleca", "FSL VPU H263", "encode_one_frame - encoder reset!\n");
			ret = vpu_SWReset(handle, 0);
			return -1;
		}
		loop_id ++;
	}

	/*gettimeofday(&tenc_end, NULL);
	sec = tenc_end.tv_sec - tenc_begin.tv_sec;
	usec = tenc_end.tv_usec - tenc_begin.tv_usec;

	if (usec < 0) {
		sec--;
		usec = usec + 1000000;
	}

	tenc_time += (sec * 1000000) + usec;*/

	ret = vpu_EncGetOutputInfo(handle, &outinfo);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("vpu_EncGetOutputInfo failed Err code: %d\n",ret);
		return -1;
	}

    //__android_log_print("Teleca", "FSL VPU H263", "encode_one_frame - encoding one frame successfull\n");

	if (outinfo.skipEncoded)
		TSK_DEBUG_WARN("Skip encoding one Frame!\n");

	ret = encoder_readbs_reset_buffer(self, outinfo.bitstreamBuffer, outinfo.bitstreamSize, out_data, out_max_size);
	if (ret) {
		TSK_DEBUG_ERROR("writing bitstream buffer failed\n");
		return -1;
	}
	
    return outinfo.bitstreamSize;

	/*gettimeofday(&total_end, NULL);
	sec = total_end.tv_sec - total_start.tv_sec;
	usec = total_end.tv_usec - total_start.tv_usec;
	if (usec < 0) {
		sec--;
		usec = usec + 1000000;
	}
	total_time = (sec * 1000000) + usec;

	info_msg("Finished encoding: %d frames\n", frame_id);
	info_msg("enc fps = %.2f\n", (frame_id / (tenc_time / 1000000)));
	info_msg("total fps= %.2f \n",(frame_id / (total_time / 1000000)));*/
}

void encoder_free_framebuffer(tdav_codec_fsl_vpu_h263_t* self)
{
	int i;

	for (i = 0; i < self->encoder.totalfb; i++) {
		framebuf_free(self->encoder.pfbpool[i]);
	}

	TSK_FREE(self->encoder.fb);
	TSK_FREE(self->encoder.pfbpool);
}

int decoder_allocate_framebuffer(tdav_codec_fsl_vpu_h263_t* self)
{
	DecBufInfo bufinfo;
	int i, regfbcount = self->decoder.regfbcount, totalfb, img_size, mvCol;
    RetCode ret;
	DecHandle handle = self->decoder.handle;
	FrameBuffer *fb;
	struct frame_buf **pfbpool;
	int stride, divX, divY;
	
	totalfb = regfbcount; // + dec->extrafb;

	fb = self->decoder.fb = tsk_calloc(totalfb, sizeof(FrameBuffer));
	if (fb == NULL) {
		TSK_DEBUG_ERROR("Failed to allocate fb\n");
		return -1;
	}

	pfbpool = self->decoder.pfbpool = tsk_calloc(totalfb, sizeof(struct frame_buf *));
	if (pfbpool == NULL) {
		TSK_DEBUG_ERROR("Failed to allocate pfbpool\n");
		TSK_FREE(self->decoder.fb);
		self->decoder.fb = NULL;
		return -1;
	}

	mvCol = 1;

	/* All buffers are linear */
	for (i = 0; i < totalfb; i++) {
        pfbpool[i] = framebuf_alloc(STD_H263, /*self->decoder.mjpg_fmt*/0,
				    self->decoder.stride, self->decoder.picheight, mvCol);
		if (pfbpool[i] == NULL)
			goto err;
	}

	for (i = 0; i < totalfb; i++) {
		fb[i].myIndex = i;
		fb[i].bufY = pfbpool[i]->addrY;
		fb[i].bufCb = pfbpool[i]->addrCb;
		fb[i].bufCr = pfbpool[i]->addrCr;
		if (!cpu_is_mx27()) {
			fb[i].bufMvCol = pfbpool[i]->mvColBuf;
		}
	}

	stride = ((self->decoder.stride + 15) & ~15);

	/* User needs to fill max suported macro block value of frame as following*/
	bufinfo.maxDecFrmInfo.maxMbX = self->decoder.stride / 16;
	bufinfo.maxDecFrmInfo.maxMbY = self->decoder.picheight / 16;
	bufinfo.maxDecFrmInfo.maxMbNum = self->decoder.stride * self->decoder.picheight / 256;
	ret = vpu_DecRegisterFrameBuffer(handle, fb, self->decoder.regfbcount, stride, &bufinfo);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("Register frame buffer failed, ret=%d\n", ret);
		goto err1;
	}

	return 0;

err1:

err:
    for (i = 0; i < totalfb; i++) {
	    framebuf_free(pfbpool[i]);
    }

	TSK_FREE(self->decoder.fb);
	TSK_FREE(self->decoder.pfbpool);
	self->decoder.fb = NULL;
	self->decoder.pfbpool = NULL;
	return -1;
}

int decode_one_frame(tdav_codec_fsl_vpu_h263_t* self, void **out_data, tsk_size_t* out_max_size, int mode)
{
    //__android_log_print("Teleca", "FSL VPU H263", "decode_one_frame - in\n");
    int ret = 0, actual_display_index = -1;

    DecHandle handle = self->decoder.handle;
	DecOutputInfo outinfo = {0};
	DecParam decparam = {0};

    decparam.dispReorderBuf = 0;

	/*if (!cpu_is_mx6x()) {
		decparam.prescanEnable = 0;
		decparam.prescanMode = 0;
	}*/

	decparam.skipframeMode = 0;
	decparam.skipframeNum = 0;

	/*
	 * once iframeSearchEnable is enabled, prescanEnable, prescanMode
	 * and skipframeMode options are ignored.
	 */
	decparam.iframeSearchEnable = 0;

    int loop_id = 0;
    while(vpu_IsBusy()) {
        if(loop_id == 2000) {
            //__android_log_print("Teleca", "FSL VPU H263", "decode_one_frame - encoder reset!\n");
            vpu_SWReset(self->encoder.handle, 0);
            TSK_DEBUG_ERROR("VPU Hanged, SW Reset Command sent\n");
            return -1;
        }
        vpu_WaitForInt(2);
        loop_id++;
    }
    ret = vpu_DecStartOneFrame(handle, &decparam);

    if (ret != RETCODE_SUCCESS) {
        TSK_DEBUG_ERROR("vpu_DecStartOneFrame failed, ret=%d\n", ret);
        return ret;
	}

    loop_id = 0;
    while(vpu_IsBusy()) {
        //TSK_DEBUG_INFO("vpu_IsBusy - %d\n", loop_id);
        if(loop_id == 5000) {
            //__android_log_print("Teleca", "FSL VPU H263", "decode_one_frame - decoder reset!\n");
            vpu_SWReset(handle, 0);
            TSK_DEBUG_ERROR("VPU Hanged, SW Reset Command sent\n");
            return -1;
        }
        vpu_WaitForInt(1);
        loop_id++;
    }

    ret = vpu_DecGetOutputInfo(handle, &outinfo);

    if (ret != RETCODE_SUCCESS) {
        TSK_DEBUG_ERROR("vpu_DecGetOutputInfo failed, ret=%d\n", ret);
        return ret;
	}

    /* BIT don't have picture to be displayed */
	if ((outinfo.indexFrameDisplay == -3) ||
			(outinfo.indexFrameDisplay == -2)) {
        TSK_DEBUG_INFO("decode_one_frame - No Frame to be outputted!!!\n");
        //__android_log_print("Teleca", "FSL VPU H263", "decode_one_frame - no Frame to be outputted!!!\n");

        TSK_DEBUG_ERROR("No frame to be outputted\n");

        return -31; //No more frames in the Bit stream buffer
	} else if(outinfo.indexFrameDisplay == -1) {
        return -32; //End of stream
    }

    actual_display_index = outinfo.indexFrameDisplay;
    
    if(mode != -1/* && out_data*/) {
        write_to_output(self, self->decoder.picCropRect, actual_display_index, out_data, out_max_size);
        //__android_log_print("Teleca", "FSL VPU H263", "decode_one_frame - display index outputted - %d\n", actual_display_index);
    }

    if (actual_display_index >= 0) {
		ret = vpu_DecClrDispFlag(handle, actual_display_index);
		if (ret) {
			TSK_DEBUG_ERROR("vpu_DecClrDispFlag failed Error code %d\n", ret);
            return ret;
        }
	}

    return 0;
}

void decoder_free_framebuffer(tdav_codec_fsl_vpu_h263_t* self)
{
	int i, totalfb;

	totalfb = self->decoder.regfbcount;// + self->decoder.extrafb;

	for (i = 0; i < totalfb; i++) {
		if (self->decoder.pfbpool)
			framebuf_free(self->decoder.pfbpool[i]);
	}

	if (self->decoder.fb) {
		TSK_FREE(self->decoder.fb);
		self->decoder.fb = NULL;
	}
	if (self->decoder.pfbpool) {
		TSK_FREE(self->decoder.pfbpool);
		self->decoder.pfbpool = NULL;
	}

	return;
}

int tdav_codec_fsl_vpu_h263_init(tdav_codec_fsl_vpu_h263_t* self, tdav_codec_fsl_vpu_h263_type_t type)
{
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_init in\n");
	int ret = 0;
	
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	
	self->type = type;

    framebuf_init();

    //__android_log_print("Teleca", "FSL VPU H263", "Teleca tdav_codec_fsl_vpu_h263_init before vpu init\n");

    ret = vpu_Init(NULL);

    //__android_log_print("Teleca", "FSL VPU H263", "Teleca tdav_codec_fsl_vpu_h263_init after vpu init = %d\n", ret);

    if (ret) {
		TSK_DEBUG_ERROR("VPU Init Failure.\n");
	}

	/* allocations MUST be done by open() */
	
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_init out\n");

    return ret;
}

int tdav_codec_fsl_vpu_h263_deinit(tdav_codec_fsl_vpu_h263_t* self)
{
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

    vpu_UnInit();

	// FFMpeg resources are destroyed by close()
	
	TSK_FREE(self->rtp.ptr);
	self->rtp.size = 0;

	return 0;
}



/* ============ H.263-1996 Plugin interface ================= */

//
//	H.263-1996 object definition
//
static int tdav_codec_fsl_vpu_h263_open(tmedia_codec_t* self)
{
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open in\n");
	int ret;

	tdav_codec_fsl_vpu_h263_t* h263 = (tdav_codec_fsl_vpu_h263_t*)self;

	if(!h263){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	/* the caller (base class) already checked that the codec is not opened */

	//	Encoder
	if((ret = tdav_codec_fsl_vpu_h263_open_encoder(h263))){
		return ret;
	}

	//	Decoder
	if((ret = tdav_codec_fsl_vpu_h263_open_decoder(h263))){
		return ret;
	}

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open out\n");

	return ret;
}

static int tdav_codec_fsl_vpu_h263_close(tmedia_codec_t* self)
{
	tdav_codec_fsl_vpu_h263_t* h263 = (tdav_codec_fsl_vpu_h263_t*)self;
	int ret;

	if(!h263){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	/* the caller (base class) already checked that the codec is opened */
	
	//	Encoder
	ret = tdav_codec_fsl_vpu_h263_close_encoder(h263);
	//	Decoder
	ret = tdav_codec_fsl_vpu_h263_close_decoder(h263);

	return ret;
}

static tsk_size_t tdav_codec_fsl_vpu_h263_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size)
{
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_encode in\n");   
	int ret;
	//int size;

	tdav_codec_fsl_vpu_h263_t* h263 = (tdav_codec_fsl_vpu_h263_t*)self;

	if(!self || !in_data || !in_size || !out_data){
		TSK_DEBUG_ERROR("Invalid parameter");
		return 0;
	}

    ret = encode_one_frame(h263, in_data, in_size, &(h263->encoder.buffer), &(h263->encoder.buffer_size));
    if(ret > 0){
        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_encode encode_one_frame return = %ld & in_size = %ld\n", ret, in_size);
		tdav_codec_fsl_vpu_h263_encap(h263, h263->encoder.buffer, (tsk_size_t)ret);
	}

	h263->encoder.force_idr = tsk_false;

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_encode out\n");

	return 0;
}

static tsk_size_t tdav_codec_fsl_vpu_h263_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr)
{
    //TSK_DEBUG_INFO("tdav_codec_fsl_vpu_h263_decode in\n");
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode in\n");    
	uint8_t F, P, sbit, ebit;
	const uint8_t* pdata = in_data;
	const uint8_t* pay_ptr;
	tsk_size_t pay_size;
	tsk_size_t hdr_size;
	tsk_size_t xsize, retsize = 0;
	int got_picture_ptr;
	int ret;

    int eos = 0, fill_end_bs = 0;

	tdav_codec_fsl_vpu_h263_t* h263 = (tdav_codec_fsl_vpu_h263_t*)self;
	const trtp_rtp_header_t* rtp_hdr = proto_hdr;
	tsk_bool_t is_idr = tsk_false;


	if(!self || !in_data || !in_size || !out_data || !h263->decoder.context){
		TSK_DEBUG_ERROR("Invalid parameter");
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode return 0\n");
		return 0;
	}

	/*	RFC 2190
		get F and P bits, used to determine the header Mode (A, B or C)
		F: 1 bit 
		The flag bit indicates the mode of the payload header. F=0, mode A;
		F=1, mode B or mode C depending on P bit defined below.
		P: 1 bit
		Optional PB-frames mode as defined by the H.263 [4]. "0" implies
		normal I or P frame, "1" PB-frames. When F=1, P also indicates modes:
		mode B if P=0, mode C if P=1.

		I:  1 bit.
	   Picture coding type, bit 9 in PTYPE defined by H.263[4], "0" is
	   intra-coded, "1" is inter-coded.
	*/
	F = *pdata >> 7;
	P = (*pdata >> 6) & 0x01;

	/* SBIT and EBIT */
	sbit = (*pdata >> 3) & 0x0F;
	ebit = (*pdata & 0x07);
	
	if(F == 0){
		/*	MODE A
			0                   1                   2                   3
			0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			|F|P|SBIT |EBIT | SRC |I|U|S|A|R      |DBQ| TRB |    TR         |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		*/
		hdr_size = H263_HEADER_MODE_A_SIZE;
		is_idr = (in_size >= 2) && !(pdata[1] & 0x10) /* I==1 */;
	}
	else if(P == 0){ // F=1 and P=0
		/* MODE B
			 0                   1                   2                   3
			0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			|F|P|SBIT |EBIT | SRC | QUANT   |  GOBN   |   MBA           |R  |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			|I|U|S|A| HMV1        | VMV1        | HMV2        | VMV2        |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		*/
		hdr_size = H263_HEADER_MODE_B_SIZE;
		is_idr = (in_size >= 5) && !(pdata[4] & 0x80) /* I==1 */;
	}
	else{ // F=1 and P=1
		/* MODE C 
			 0                   1                   2                   3
			0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			|F|P|SBIT |EBIT | SRC | QUANT   |  GOBN   |   MBA           |R  |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			|I|U|S|A| HMV1        | VMV1        | HMV2        | VMV2        |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			| RR                                  |DBQ| TRB |    TR         |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		*/
		hdr_size = H263_HEADER_MODE_C_SIZE;
		is_idr = (in_size >= 5) && !(pdata[4] & 0x80) /* I==1 */;
	}

	/* Check size */
	if(in_size < hdr_size){
		TSK_DEBUG_ERROR("Too short");
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode return 0 in_size < hdr_size\n");
		return 0;
	}

	pay_ptr = (pdata + hdr_size);
	pay_size = (in_size - hdr_size);

    xsize = avpicture_get_size(h263->decoder.context->pix_fmt, h263->decoder.context->width, h263->decoder.context->height);

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode xsize = %ld\n", xsize);  

	/* Packet lost? */
	if(h263->decoder.last_seq != (rtp_hdr->seq_num - 1) && h263->decoder.last_seq){
		if(h263->decoder.last_seq == rtp_hdr->seq_num){
			// Could happen on some stupid emulators
			TSK_DEBUG_INFO("Packet duplicated, seq_num=%d", rtp_hdr->seq_num);
                        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode Packet Lost!!! return 0\n");
			return 0;
		}
		TSK_DEBUG_INFO("Packet lost, seq_num=%d", rtp_hdr->seq_num);
	}
	h263->decoder.last_seq = rtp_hdr->seq_num;
	
	if((int)(h263->decoder.accumulator_pos + pay_size) <= xsize){
		if((h263->decoder.ebit + sbit) == 8){ /* Perfect one Byte to clean up */
			if(h263->decoder.accumulator_pos){
				((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos-1] = (((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos-1] & (0xFF << h263->decoder.ebit)) |
					(*pay_ptr & (0xFF >> sbit));
			}
			pay_ptr++, pay_size--;
		}
		h263->decoder.ebit = ebit;

		memcpy(&((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos], pay_ptr, pay_size);
		h263->decoder.accumulator_pos += pay_size;
	}
	else{
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode overflow!!! return 0\n");
		TSK_DEBUG_WARN("Buffer overflow");
		h263->decoder.accumulator_pos = 0;
		return 0;
	}
	
	if(rtp_hdr->marker){
		//AVPacket packet;
		/* allocate destination buffer */
		if(*out_max_size < xsize){
			if(!(*out_data = tsk_realloc(*out_data, xsize))){
				TSK_DEBUG_ERROR("Failed to allocate new buffer");
				h263->decoder.accumulator_pos = 0;
				*out_max_size = 0;
                                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode out_max_size not done!!! return 0\n");
				return 0;
			}
			*out_max_size = xsize;
		}		

        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode accumulator_pos = %ld\n", h263->decoder.accumulator_pos);

        ret = dec_fill_bsbuffer(h263->decoder.accumulator, h263->decoder.handle, h263->decoder.virt_bsbuf_addr,
		        (h263->decoder.virt_bsbuf_addr + STREAM_BUF_SIZE),
			    h263->decoder.phy_bsbuf_addr, h263->decoder.accumulator_pos, &eos, &fill_end_bs);

        if (ret < 0) {
	        TSK_DEBUG_ERROR("dec_fill_bsbuffer failed\n");
            h263->decoder.accumulator_pos = 0;
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode - dec_fill_bsbuffer failed return 0\n");
	        return 0;
        }

#ifndef VPU_OPTIMUM
        //stream not yet parsed
        if(decoder_stream_parsed == tsk_false) {
            ret = dec_parse(h263);
            if(ret) {
                TSK_DEBUG_ERROR("VPU_Decoder Parsing error\n");
                h263->decoder.accumulator_pos = 0;
                return 0;
            }

            /* allocate frame buffers */
	        ret = decoder_allocate_framebuffer(h263);
	        if (ret) {
                TSK_DEBUG_ERROR("VPU_Decoder Framebuffer Allocation error\n");
                h263->decoder.accumulator_pos = 0;
		        return 0;
            }

            decoder_stream_parsed = tsk_true;
            //frameCount = 1;
        }
#endif
        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode - Attempting
        ret = decode_one_frame(h263, out_data, out_max_size, 0);//out_max_size might be changed by decode_one_frame()

        if (ret /*&& ret != -31*/) { //-31 means no frame to be outputted
            TSK_DEBUG_WARN("Failed to decode the buffer with error code = %d", ret);
			if(TMEDIA_CODEC_VIDEO(self)->in.callback){
				TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_error;
				TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr;
				TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result);
			}
        }
        else {
            retsize = *out_max_size;
			// Is it IDR frame?
			if(is_idr && TMEDIA_CODEC_VIDEO(self)->in.callback){
				TSK_DEBUG_INFO("Decoded H.263 IDR");
				TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_idr;
				TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr;
				TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result);
			}
            TMEDIA_CODEC_VIDEO(h263)->in.width = h263->decoder.context->width;
			TMEDIA_CODEC_VIDEO(h263)->in.height = h263->decoder.context->height;
        }

		/* in all cases: reset accumulator */
		h263->decoder.accumulator_pos = 0;		
	}
    /*else {
        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode - missed packet payload!!!\n"); 
    }*/

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_decode out with decoded size = %lu\n", retsize);   

	return retsize;
}

static tsk_bool_t tdav_codec_fsl_vpu_h263_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
{
        __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_match in\n");
	if(tsk_striequals(att_name, "fmtp")){
		unsigned width, height, fps;
		if(tmedia_parse_video_fmtp(att_value, TMEDIA_CODEC_VIDEO(codec)->pref_size, &width, &height, &fps)){
			TSK_DEBUG_ERROR("Failed to match fmtp=%s", att_value);
                        __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_match - fmtp match failed\n");
			return tsk_false;
		}
                __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_match - width = %d,height = %d\n", width, height);
		TMEDIA_CODEC_VIDEO(codec)->in.width = TMEDIA_CODEC_VIDEO(codec)->out.width = width;
		TMEDIA_CODEC_VIDEO(codec)->in.height = TMEDIA_CODEC_VIDEO(codec)->out.height = height;
		TMEDIA_CODEC_VIDEO(codec)->in.fps = TMEDIA_CODEC_VIDEO(codec)->out.fps = fps;
	}
#if 0
	else if(tsk_striequals(att_name, "imageattr")){
		unsigned in_width, in_height, out_width, out_height;
		if(tmedia_parse_video_imageattr(att_value, TMEDIA_CODEC_VIDEO(codec)->pref_size, &in_width, &in_height, &out_width, &out_height) != 0){
                        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_match - imageattr - Failed\n");
			return tsk_false;
		}
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_match - imageattr - in_width = %d, in_height = %d, out_width = %d, out_height = %d\n", in_width, in_height, out_width, out_height);
		TMEDIA_CODEC_VIDEO(codec)->in.width = in_width;
		TMEDIA_CODEC_VIDEO(codec)->in.height = in_height;
		TMEDIA_CODEC_VIDEO(codec)->out.width = out_width;
		TMEDIA_CODEC_VIDEO(codec)->out.height = out_height;
	}
#endif

        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_match out\n");
	return tsk_true;
}

static char* tdav_codec_fsl_vpu_h263_sdp_att_get(const tmedia_codec_t* codec, const char* att_name)
{
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_get in\n");
	if(tsk_striequals(att_name, "fmtp")){
		tmedia_pref_video_size_t cif_vs;
		if(tmedia_video_get_closest_cif_size(TMEDIA_CODEC_VIDEO(codec)->pref_size, &cif_vs)){
			TSK_DEBUG_ERROR("Failed to get closest CIF family size");
            __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_get - CIF Failed\n");
			return tsk_null;
		}
		__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_get - fmtp out - %s\n", tmedia_get_video_fmtp(cif_vs));
		return tmedia_get_video_fmtp(cif_vs);
	}
#if 0
	else if(tsk_striequals(att_name, "imageattr")){
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_get - imageattr out - %s\n", tmedia_get_video_imageattr(TMEDIA_CODEC_VIDEO(codec)->pref_size,
                        TMEDIA_CODEC_VIDEO(codec)->in.width, TMEDIA_CODEC_VIDEO(codec)->in.height, TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height));
		return tmedia_get_video_imageattr(TMEDIA_CODEC_VIDEO(codec)->pref_size, 
			TMEDIA_CODEC_VIDEO(codec)->in.width, TMEDIA_CODEC_VIDEO(codec)->in.height, TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height);
	}
#endif
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_sdp_att_get - Failed\n");
	return tsk_null;
}

/* constructor */
static tsk_object_t* tdav_codec_fsl_vpu_h263_ctor(tsk_object_t * self, va_list * app)
{
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_ctor in\n");
	tdav_codec_fsl_vpu_h263_t *h263 = self;
	if(h263){
		/* init base: called by tmedia_codec_create() */
		/* init self */
		tdav_codec_fsl_vpu_h263_init(TDAV_CODEC_FSL_VPU_H263(self), tdav_codec_fsl_vpu_h263_1996);
	}
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_ctor out\n");
	return self;
}
/* destructor */
static tsk_object_t* tdav_codec_fsl_vpu_h263_dtor(tsk_object_t * self)
{ 
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_dtor in\n");
	tdav_codec_fsl_vpu_h263_t *h263 = self;
	if(h263){
		/* deinit base */
		tmedia_codec_video_deinit(h263);
		/* deinit self */
		tdav_codec_fsl_vpu_h263_deinit(TDAV_CODEC_FSL_VPU_H263(self));
		
	}
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_dtor out\n");
	return self;
}
/* object definition */
static const tsk_object_def_t tdav_codec_fsl_vpu_h263_def_s = 
{
	sizeof(tdav_codec_fsl_vpu_h263_t),
	tdav_codec_fsl_vpu_h263_ctor, 
	tdav_codec_fsl_vpu_h263_dtor,
	tmedia_codec_cmp, 
};
/* plugin definition*/
static const tmedia_codec_plugin_def_t tdav_codec_fsl_vpu_h263_plugin_def_s = 
{
	&tdav_codec_fsl_vpu_h263_def_s,

	tmedia_video,
	tmedia_codec_id_h263,
	"H263",
	"H263-1996 codec",
	TMEDIA_CODEC_FORMAT_H263,
	tsk_false,
	90000, // rate
	
	/* audio */
	{ 0 },

	/* video */
	{176, 144, 15},

	tdav_codec_fsl_vpu_h263_set,
	tdav_codec_fsl_vpu_h263_open,
	tdav_codec_fsl_vpu_h263_close,
	tdav_codec_fsl_vpu_h263_encode,
	tdav_codec_fsl_vpu_h263_decode,
	tdav_codec_fsl_vpu_h263_sdp_att_match,
	tdav_codec_fsl_vpu_h263_sdp_att_get
};
const tmedia_codec_plugin_def_t *tdav_codec_fsl_vpu_h263_plugin_def_t = &tdav_codec_fsl_vpu_h263_plugin_def_s;

int tdav_codec_fsl_vpu_h263_open_encoder(tdav_codec_fsl_vpu_h263_t* self)
{
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder in\n");
	int ret;

	//encoder buffer to be initailised when actual encoded data size is known
    self->encoder.buffer = NULL;
    self->encoder.buffer_size = 0;

	// RTP Callback
	switch(self->type){
		case tdav_codec_fsl_vpu_h263_1996:
			{	// H263 - 1996 
                __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder H263 - 1996 OK\n");
				break;
			}
	}

	// Open encoder
	
    //vpu_mem_desc mem_desc = {0};
    self->encoder.mem_desc = (vpu_mem_desc *) tsk_malloc(sizeof(vpu_mem_desc));

    EncHandle handle = {0};
	EncOpenParam encop = {0};

    /* get physical contigous bit stream buffer */
	self->encoder.mem_desc->size = STREAM_BUF_SIZE;
	ret = IOGetPhyMem((self->encoder.mem_desc));
	if (ret) {
		TSK_DEBUG_ERROR("VPU - Unable to obtain physical memory\n");
		return -1;
	}

	/* mmap that physical buffer */
	self->encoder.virt_bsbuf_addr = IOGetVirtMem((self->encoder.mem_desc));
	if (self->encoder.virt_bsbuf_addr <= 0) {
		TSK_DEBUG_ERROR("VPU - Unable to map physical memory\n");
		IOFreePhyMem((self->encoder.mem_desc));
		return -1;
	}

    self->encoder.phy_bsbuf_addr = self->encoder.mem_desc->phy_addr;

    /* Fill up parameters for encoding */
	encop.bitstreamBuffer = self->encoder.phy_bsbuf_addr;
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - encop.bitstreamBuffer=%ld\n", encop.bitstreamBuffer);
	encop.bitstreamBufferSize = STREAM_BUF_SIZE;
	encop.bitstreamFormat = STD_H263;
	encop.mapType = LINEAR_FRAME_MAP;
	encop.linear2TiledEnable = 0;
	
    self->encoder.src_picwidth = TMEDIA_CODEC_VIDEO(self)->out.width;
	self->encoder.src_picheight = TMEDIA_CODEC_VIDEO(self)->out.height;
	
	self->encoder.enc_picwidth = TMEDIA_CODEC_VIDEO(self)->out.width;
	self->encoder.enc_picheight = TMEDIA_CODEC_VIDEO(self)->out.height;
	
	encop.picWidth = TMEDIA_CODEC_VIDEO(self)->out.width;
	encop.picHeight = TMEDIA_CODEC_VIDEO(self)->out.height;
	__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - encop.picWidth=%ld & encop.picHeight=%ld\n", encop.picWidth, encop.picHeight);

	/*Note: Frame rate cannot be less than 15fps per H.263 spec */
    /*uint32_t num = CLOCKTICKSPERSECOND;//Calculating based on the 1 second = 10,000 ticks presumption. 
    uint32_t den = (uint32_t)(((float)num / (float)(TMEDIA_CODEC_VIDEO(self)->out.fps)) - 1);
    uint32_t frameRateInfo = den << 16;
    frameRateInfo = frameRateInfo | num;
	encop.frameRateInfo = frameRateInfo;
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - encop.frameRateInfo=%ld\n", encop.frameRateInfo);
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - out.fps=%ld\n", TMEDIA_CODEC_VIDEO(self)->out.fps);
    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - calculated fps=%ld\n", (frameRateInfo & 0xffff) /((frameRateInfo >> 16) + 1));*/

    encop.frameRateInfo = 30;

	encop.bitRate = 0;
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - encop.bitRate=%ld\n", encop.bitRate);
	encop.gopSize = 10;
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder - encop.gopSize=%ld\n", encop.gopSize);
	encop.slicemode.sliceMode = 0;	/* 0: 1 slice per picture; 1: Multiple slices per picture */
	encop.slicemode.sliceSizeMode = 0; /* 0: silceSize defined by bits; 1: sliceSize defined by MB number*/
	encop.slicemode.sliceSize = 4000;  /* Size of a slice in bits or MB numbers */

	encop.initialDelay = 0;
	encop.vbvBufferSize = 0;        /* 0 = ignore 8 */
	encop.intraRefresh = 0;
	encop.sliceReport = 0;
	encop.mbReport = 0;
	encop.mbQpReport = 0;
	encop.rcIntraQp = 5;
	encop.userQpMax = 2;
	encop.userQpMin = 10;
	encop.userQpMinEnable = 0;
	encop.userQpMaxEnable = 0;

	encop.IntraCostWeight = 0;
	encop.MEUseZeroPmv  = 0;
	/* (3: 16x16, 2:32x16, 1:64x32, 0:128x64, H.263(Short Header : always 3) */
	encop.MESearchRange = 3;

	encop.userGamma = (Uint32)(0.75*32768);         /*  (0*32768 <= gamma <= 1*32768) */
	encop.RcIntervalMode = 1;        /* 0:normal, 1:frame_level, 2:slice_level, 3: user defined Mb_level */
	encop.MbInterval = 0;
	encop.avcIntra16x16OnlyModeEnable = 0;

	encop.ringBufferEnable = 0;
	encop.dynamicAllocEnable = 0;
	encop.chromaInterleave = 0;

    switch(self->type) {
		case tdav_codec_fsl_vpu_h263_1996:
		{	// H263 - 1996 

            __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder H263 - 1996 OK\n");

            encop.EncStdParam.h263Param.h263_annexIEnable = 0;
	        encop.EncStdParam.h263Param.h263_annexJEnable = 1;
	        encop.EncStdParam.h263Param.h263_annexKEnable = 0;
	        encop.EncStdParam.h263Param.h263_annexTEnable = 0;
			break;
		}
    }

    ret = vpu_EncOpen(&handle, &encop);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("Encoder open failed %d\n", ret);

        IOFreeVirtMem((self->encoder.mem_desc));
    	IOFreePhyMem((self->encoder.mem_desc));
		return -1;
	}

	self->encoder.handle = handle;

    EncInitialInfo initinfo = {0};
	
	ret = vpu_EncGetInitialInfo(handle, &initinfo);
	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("Encoder GetInitialInfo failed: %d\n", ret);

        IOFreeVirtMem((self->encoder.mem_desc));
    	IOFreePhyMem((self->encoder.mem_desc));
		return -1;
	}

	self->encoder.minFrameBufferCount = initinfo.minFrameBufferCount;

    ret = encoder_allocate_framebuffer(self);
    if (ret) {
		TSK_DEBUG_ERROR("encoder_allocate_framebuffer failed\n");

        IOFreeVirtMem((self->encoder.mem_desc));
    	IOFreePhyMem((self->encoder.mem_desc));
		return -1;
	}

    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_encoder out\n");

	return ret;
}

int tdav_codec_fsl_vpu_h263_open_decoder(tdav_codec_fsl_vpu_h263_t* self)
{
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder in\n");   
	int ret, size;

	if(self->decoder.context){
		TSK_DEBUG_ERROR("Decoder already opened");
		return -1;
	}

	self->decoder.context = avcodec_alloc_context();
	avcodec_get_context_defaults(self->decoder.context);
	
	self->decoder.context->pix_fmt = PIX_FMT_YUV420P;
	self->decoder.context->width = TMEDIA_CODEC_VIDEO(self)->in.width;
	self->decoder.context->height = TMEDIA_CODEC_VIDEO(self)->in.height;

    __android_log_print("Teleca", "FSL VPU H263", "picwidth from TMEDIA = %d\n", self->decoder.context->width);
    __android_log_print("Teleca", "FSL VPU H263", "picheight from TMEDIA = %d\n", self->decoder.context->height);

	size = avpicture_get_size(PIX_FMT_YUV420P, self->decoder.context->width, self->decoder.context->height);
	if(!(self->decoder.accumulator = tsk_calloc((size + FF_INPUT_BUFFER_PADDING_SIZE), sizeof(uint8_t)))){
		TSK_DEBUG_ERROR("Failed to allocate decoder buffer");
		return -2;
	}

    //vpu_mem_desc mem_desc = {0};
    self->decoder.mem_desc = (vpu_mem_desc *) tsk_malloc(sizeof(vpu_mem_desc));

    DecHandle handle = {0};
	DecOpenParam oparam = {0};

    int eos = 0, fill_end_bs = 0, fillsize = 0;

    self->decoder.mem_desc->size = STREAM_BUF_SIZE;
	ret = IOGetPhyMem((self->decoder.mem_desc));
	if (ret) {
		TSK_DEBUG_ERROR("VPU - Unable to obtain physical mem\n");
		return -1;
	}

	if (IOGetVirtMem((self->decoder.mem_desc)) <= 0) {
		TSK_DEBUG_ERROR("VPU - Unable to obtain virtual mem\n");
		IOFreePhyMem((self->decoder.mem_desc));
		return -1;
	}

    self->decoder.phy_bsbuf_addr = self->decoder.mem_desc->phy_addr;
	self->decoder.virt_bsbuf_addr = self->decoder.mem_desc->virt_uaddr;

	//self->decoder.userData.enable = 0;

    oparam.bitstreamFormat = STD_H263;
	oparam.bitstreamBuffer = self->decoder.phy_bsbuf_addr;
	oparam.bitstreamBufferSize = STREAM_BUF_SIZE;
	oparam.pBitStream = self->decoder.virt_bsbuf_addr;
	oparam.reorderEnable = 0;
    oparam.chromaInterleave = 1;
	oparam.mjpg_thumbNailDecEnable = 0;
    oparam.mapType = LINEAR_FRAME_MAP;
	oparam.tiled2LinearEnable = 0;
    oparam.picWidth = TMEDIA_CODEC_VIDEO(self)->in.width;
    oparam.picHeight = TMEDIA_CODEC_VIDEO(self)->in.height;
    oparam.bitstreamMode = 1;

	ret = vpu_DecOpen(&handle, &oparam);

    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder vpu_DecOpen return = %d\n", ret);

	if (ret != RETCODE_SUCCESS) {
		TSK_DEBUG_ERROR("VPU - Decoder Open Failure\n");
        IOFreeVirtMem((self->decoder.mem_desc));
    	IOFreePhyMem((self->decoder.mem_desc));

        return -1;
	}
    else {
	    self->decoder.handle = handle;
    }

    decoder_stream_parsed = tsk_false;

#ifdef VPU_OPTIMUM
    int input_fd = open("/data/1.h263", O_RDONLY, 0);
	if (input_fd < 0) {
		TSK_DEBUG_ERROR("VPU_Decoder File Opening error\n");
        IOFreeVirtMem((self->decoder.mem_desc));
    	IOFreePhyMem((self->decoder.mem_desc));
		return -1;
	}

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - file opened!!!\n");

    void *inputBuff = NULL;

    int bytesRead = freadn(input_fd, &inputBuff, -1);

    if(bytesRead <= 0) {
        close(input_fd);
        IOFreeVirtMem((self->decoder.mem_desc));
    	IOFreePhyMem((self->decoder.mem_desc));
        return -1;
    }

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - file read - bytesread = %ld, inputBuff = %ld\n", bytesRead, inputBuff);

    //Successful read
    close(input_fd);

    ret = dec_fill_bsbuffer(inputBuff, self->decoder.handle, self->decoder.virt_bsbuf_addr,
	        (self->decoder.virt_bsbuf_addr + STREAM_BUF_SIZE),
		    self->decoder.phy_bsbuf_addr, bytesRead, &eos, &fill_end_bs);

    //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - bs buffer filled!!!\n");

    //inputBuff is used and needs to be freed
    TSK_FREE(inputBuff);

    if (ret < 0) {
        TSK_DEBUG_ERROR("dec_fill_bsbuffer failed\n");
        IOFreeVirtMem((self->decoder.mem_desc));
    	IOFreePhyMem((self->decoder.mem_desc));
        return -1;
    }

    //stream not yet parsed
    if(decoder_stream_parsed == tsk_false) {
        ret = dec_parse(self);
        if(ret) {
            //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - dec_parse error!!!\n");
            TSK_DEBUG_ERROR("VPU_Decoder Parsing error\n");
            IOFreeVirtMem((self->decoder.mem_desc));
    	    IOFreePhyMem((self->decoder.mem_desc));
            return -1;
        }

        /* allocate frame buffers */
        ret = decoder_allocate_framebuffer(self);
        if (ret) {
            //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - decoder_allocate_framebuffer error!!!\n");
            TSK_DEBUG_ERROR("VPU_Decoder Framebuffer Allocation error\n");
            IOFreeVirtMem((self->decoder.mem_desc));
    	    IOFreePhyMem((self->decoder.mem_desc));
            return -1;
        }

        decoder_stream_parsed = tsk_true;
        //frameCount = 1;
    }

    while(!ret) {
        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - first decode run flushing attempt!!!\n");
        ret = decode_one_frame(self, NULL, -1);//flushing the "black frame" 
        if (ret && ret != -31) {
            //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder - first decode run flushing error!!!\n");
            TSK_DEBUG_ERROR("decode_one_frame error\n");
            IOFreeVirtMem((self->decoder.mem_desc));
    	    IOFreePhyMem((self->decoder.mem_desc));
            return -1;
        } else if(ret && ret == -31) {
            return 0;//flushing done. OK. 
        }
    }
#endif

    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_open_decoder out\n");

	return ret;
}

int tdav_codec_fsl_vpu_h263_close_encoder(tdav_codec_fsl_vpu_h263_t* self)
{
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_close_encoder in\n");

	if(self->encoder.buffer){
		TSK_FREE(self->encoder.buffer);
	}

    encoder_free_framebuffer(self);

    int ret = 0;

	ret = vpu_EncClose(self->encoder.handle);
	if (ret == RETCODE_FRAME_NOT_COMPLETE) {
		vpu_SWReset(self->encoder.handle, 0);
		ret = vpu_EncClose(self->encoder.handle);
        if (ret != RETCODE_SUCCESS)
			TSK_DEBUG_ERROR("vpu_EncClose failed\n");
	}

    IOFreeVirtMem((self->encoder.mem_desc));
	IOFreePhyMem((self->encoder.mem_desc));
    
    TSK_FREE((self->encoder.mem_desc));

    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_close_encoder out\n");

    return ret;
}

int tdav_codec_fsl_vpu_h263_close_decoder(tdav_codec_fsl_vpu_h263_t* self)
{
    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_close_decoder in\n");

    if(self->decoder.context){
		avcodec_close(self->decoder.context);
		av_free(self->decoder.context);
		self->decoder.context = tsk_null;
	}

	if(self->decoder.accumulator){
		TSK_FREE(self->decoder.accumulator);
		self->decoder.accumulator_pos = 0;
	}

    int ret = 0;

    ret = vpu_DecClose(self->decoder.handle);
	if (ret == RETCODE_FRAME_NOT_COMPLETE) {
		vpu_SWReset(self->decoder.handle, 0);
		ret = vpu_DecClose(self->decoder.handle);
		if (ret != RETCODE_SUCCESS)
			TSK_DEBUG_ERROR("vpu_DecClose failed\n");
	}

    decoder_free_framebuffer(self);

    IOFreeVirtMem((self->decoder.mem_desc));
    IOFreePhyMem((self->decoder.mem_desc));

    TSK_FREE((self->decoder.mem_desc));

    __android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_close_decoder out\n");

	return ret;
}

/* ============ Callbacks ================= */

static void tdav_codec_fsl_vpu_h263_encap(const tdav_codec_fsl_vpu_h263_t* h263, const uint8_t* pdata, tsk_size_t size)
{
#if 0
        /*Default Doubango RTP Encapsulation error due to following code - this expects only ONE RTP packet per Video Frame*/
	tsk_bool_t frag = tsk_false;
	register uint32_t i, last_index = 0;

	if(size < RTP_PAYLOAD_SIZE){
		goto last;
	}

	for(i = 0; i < (size - 0); i++){
		if(pdata[i] == 0x00 && pdata[i+1] == 0x00 && pdata[i+2]>=0x80){  /* PSC or (GBSC) found */
                        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_encap PSC found - (i - last_index) = %ld\n", (i - last_index));
			if((i - last_index) >= RTP_PAYLOAD_SIZE || tsk_true/* FIXME */){
				switch(h263->type){
					case tdav_codec_fsl_vpu_h263_1996:
						tdav_codec_fsl_vpu_h263_rtp_callback((tdav_codec_fsl_vpu_h263_t*) h263, pdata+last_index,
							(i - last_index), (last_index == size));
						break;
				}
				last_index = i;
			}
		}
	}
last:
        //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_encap last\n");
	if(last_index < size){
		switch(h263->type){
			case tdav_codec_fsl_vpu_h263_1996:
				tdav_codec_fsl_vpu_h263_rtp_callback((tdav_codec_fsl_vpu_h263_t*) h263, pdata + last_index,
					(size - last_index), tsk_true);
				break;
		}
	}
#endif

    register uint32_t i;

    if(pdata[0] == 0x00 && pdata[1] == 0x00 && (pdata[2] & 0xfc)==0x80) { /* PSC or (GBSC) found */
        for(i = 0; i < size; i += (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION)) {
            tdav_codec_fsl_vpu_h263_rtp_callback((tdav_codec_fsl_vpu_h263_t*) h263, pdata + i,
					    ((size - i) >= (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION)) ? (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION) : (size - i), !((size - i) > (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION)));
            //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_encap - start = %ld, size = %ld, last true = %d\n", i, (((size - i) >= (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION)) ? (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION) : (size - i)), !((size - i) > (RTP_PAYLOAD_SIZE - RTP_PAYLOAD_CORRECTION)));
        }
    }
}


static void tdav_codec_fsl_vpu_h263_rtp_callback(tdav_codec_fsl_vpu_h263_t *self, const void *data, tsk_size_t size, tsk_bool_t marker)
{
	uint8_t* pdata = (uint8_t*)data;

	if(self->rtp.size < (size + H263_HEADER_MODE_A_SIZE)){
		if(!(self->rtp.ptr = tsk_realloc(self->rtp.ptr, (size + H263_HEADER_MODE_A_SIZE)))){
			TSK_DEBUG_ERROR("Failed to allocate new buffer");
			return;
		}
		self->rtp.size = (size + H263_HEADER_MODE_A_SIZE);
	}
	memcpy((self->rtp.ptr + H263_HEADER_MODE_A_SIZE), data, size);

	/* http://eu.sabotage.org/www/ITU/H/H0263e.pdf section 5.1
	* 5.1.1 Picture Start Code (PSC) (22 bits) - PSC is a word of 22 bits. Its value is 0000 0000 0000 0000 1 00000.

	*
	* 5.1.1 Picture Start Code (PSC) (22 bits)
	* 5.1.2 Temporal Reference (TR) (8 bits)
	* 5.1.3 Type Information (PTYPE) (Variable Length)
	*	\96 Bit 1: Always "1", in order to avoid start code emulation.
	*	\96 Bit 2: Always "0", for distinction with Recommendation H.261.
	
	*	\96 Bit 3: Split screen indicator, "0" off, "1" on.
	*	\96 Bit 4: Document camera indicator, "0" off, "1" on.
	*	\96 Bit 5: Full Picture Freeze Release, "0" off, "1" on.
	*	\96 Bits 6-8: Source Format, "000" forbidden, "001" sub-QCIF, "010" QCIF, "011" CIF,
		"100" 4CIF, "101" 16CIF, "110" reserved, "111" extended PTYPE.
		If bits 6-8 are not equal to "111", which indicates an extended PTYPE (PLUSPTYPE), the following
		five bits are also present in PTYPE:
		\96 Bit 9: Picture Coding Type, "0" INTRA (I-picture), "1" INTER (P-picture).
		\96 Bit 10: Optional Unrestricted Motion Vector mode (see Annex D), "0" off, "1" on.
		\96 Bit 11: Optional Syntax-based Arithmetic Coding mode (see Annex E), "0" off, "1" on.
		\96 Bit 12: Optional Advanced Prediction mode (see Annex F), "0" off, "1" on.
		\96 Bit 13: Optional PB-frames mode (see Annex G), "0" normal I- or P-picture, "1" PB-frame.
	*/
	if(pdata[0] == 0x00 && pdata[1] == 0x00 && (pdata[2] & 0xfc)==0x80){ /* PSC */
		/* RFC 2190 -5.1 Mode A
			0                   1                   2                   3
			0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
			|F|P|SBIT |EBIT | SRC |I|U|S|A|R      |DBQ| TRB |    TR         |
			+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		
		SRC : 3 bits
		Source format, bit 6,7 and 8 in PTYPE defined by H.263 [4], specifies
		the resolution of the current picture.
		
		I:  1 bit.
		Picture coding type, bit 9 in PTYPE defined by H.263[4], "0" is
		intra-coded, "1" is inter-coded.
		*/
		
		// PDATA[4] ======> Bits 3-10 of PTYPE
		uint32_t rtp_hdr = 0;
		uint8_t format, pict_type;
		
		// Source Format = 4,5,6
		format = (pdata[4] & 0x3C)>>2;
		// Picture Coding Type = 7
		pict_type = (pdata[4] & 0x02)>>1;
		// RTP mode A header
		((uint8_t*)&rtp_hdr)[1] = (format <<5) | (pict_type << 4);
		//rtp_hdr = tnet_htonl(rtp_hdr);
		memcpy(self->rtp.ptr, &rtp_hdr, sizeof(rtp_hdr));
                //__android_log_print("Teleca", "FSL VPU H263", "tdav_codec_fsl_vpu_h263_RTP_callback PSC found\n");
	}

	// Send data over the network
	if(TMEDIA_CODEC_VIDEO(self)->out.callback){
		TMEDIA_CODEC_VIDEO(self)->out.result.buffer.ptr = self->rtp.ptr;
		TMEDIA_CODEC_VIDEO(self)->out.result.buffer.size = (size + H263_HEADER_MODE_A_SIZE);
		TMEDIA_CODEC_VIDEO(self)->out.result.duration =  (uint32_t)((1./(double)TMEDIA_CODEC_VIDEO(self)->out.fps) * TMEDIA_CODEC(self)->plugin->rate);
		TMEDIA_CODEC_VIDEO(self)->out.result.last_chunck = marker;
		TMEDIA_CODEC_VIDEO(self)->out.callback(&TMEDIA_CODEC_VIDEO(self)->out.result);
	}
}

