//#define LOG_NDEBUG 0
#define LOG_TAG "tsdemux"
#include <CDX_Debug.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


#include <base/dtv_base.h>
#include <base/dtv_semaphore.h>
#include <demux/tsc.h>
#include <demux/tsdemux.h>

#include "tsdemux_i.h"

typedef struct filter_info {
	uint8_t *buffer;
	int32_t buf_size;
	int32_t fd;
	int32_t pid;
} filter_info;



int32_t open_file(int32_t pid)
{
	char path[32];
	ALOGD("open file");

	sprintf(&path[0], "/data/media/data-%04d.ts", pid);
	int fd = open(&path[0], O_CREAT | O_RDWR | O_TRUNC, 0644);
	if(fd < 0) {
		ALOGE("open file %s failed. err:%s", path, strerror(errno));
	}
	return fd;
}

static inline int64_t get_pts(const uint8_t* p) {
	int64_t pts = (int64_t)((p[0] >> 1) & 0x07) << 30;
	pts |= (AV_RB16(p + 1) >> 1) << 15;
	pts |= AV_RB16(p + 3) >> 1;
	return pts;
}

static int32_t data_arrive_callback(void* param, void *cookie) {

	filter_t *filter = (filter_t *)cookie;
	if(filter) {
		dtv_sem_up(&filter->wait_data_sem);
	}
	return 0;
}

static int32_t pcr_notify(void* param, void *cookie) {
	mpegts_context_t  *context = (mpegts_context_t *)cookie;
	if(context) {
		context->pcrcallback(param, context->pcr_cookie);
	}
	return 0;
}

static int32_t find_start_code_pos(uint8_t *buf, int32_t len) {
	int32_t pos = -1;
	int32_t i;
	for(i = 2; i < len; i ++) {
		if(buf[i] == 1) {
			if(!buf[i -1] && !buf[i - 2]) {
				pos = i - 2;
			}
			break;
		}
	}
	return pos;
}

static int32_t push_es_data(uint8_t *data, uint32_t len, uint32_t new_frm,
		void *param) {
	uint8_t *dataptr;
	int32_t ret;

	dataptr = data;
	es_filter_t *es = (es_filter_t*) param;
	if (new_frm) {
		if (es->valid_size > 0) {
			es->ctrl_bits |= LAST_PART_BIT;

			//send data
			es->data_info.ctrl_bits = es->ctrl_bits;
			es->data_info.data_len = es->valid_size;
			es->updatedatacb(&es->data_info, es->cookie);

			//clear status
			es->free_size = 0;
			es->valid_size = 0;
			es->ctrl_bits = 0;
			es->payload_size = 0;
		}
	}

	while (len > 0) {
		if (es->free_size == 0) {
			//request buffer
			ret = es->requestbufcb(&es->md_buf, es->cookie);
			//ALOGV("request buf ret %d", ret);

			if (ret != 0 || es->md_buf.buf == NULL) {
				if (es->md_buf.buf_size == 1)
					return 1;
				else
					return -1;
			}

			es->cur_ptr = es->md_buf.buf;
			es->free_size = es->md_buf.buf_size;
		}

		if (new_frm) {
			new_frm = 0;
			es->ctrl_bits |= FIRST_PART_BIT;
			if (es->pts != -1) {
				es->ctrl_bits |= PTS_VALID_BIT;
				es->data_info.pts = es->pts*1000 / 90;
			}

			if (es->rap_flag) {
				es->ctrl_bits |= RANDOM_ACCESS_FRAME_BIT;
				es->rap_flag = 0;
			}
		}

		if (es->free_size > len) {
			memcpy(es->cur_ptr, dataptr, len);
			es->free_size -= len;
			es->cur_ptr += len;
			es->valid_size += len;

			if (es->payload_size > 0 && es->valid_size >= es->payload_size) {
				es->ctrl_bits |= LAST_PART_BIT;

				//send data
				es->data_info.ctrl_bits = es->ctrl_bits;
				es->data_info.data_len = es->valid_size;
				es->updatedatacb(&es->data_info, es->cookie);

				es->free_size = 0;
				es->valid_size = 0;
				es->payload_size = 0;
				es->ctrl_bits = FIRST_PART_BIT;
			}
			break;
		} else {
			memcpy(es->cur_ptr, dataptr, es->free_size);
			len -= es->free_size;
			dataptr += es->free_size;

			es->valid_size += es->free_size;

			if (es->payload_size > 0 && es->valid_size >= es->payload_size) {
				es->ctrl_bits |= LAST_PART_BIT;
				es->payload_size = 0;
			} else {
				if (es->payload_size > 0) {
					if (es->valid_size < es->payload_size)
						es->payload_size -= es->valid_size;
					else
						es->payload_size = 0;
				}
			}

			//send data
			es->data_info.ctrl_bits = es->ctrl_bits;
			es->data_info.data_len = es->valid_size;
			es->updatedatacb(&es->data_info, es->cookie);

			es->free_size = 0;
			es->valid_size = 0;
			es->ctrl_bits = 0;
		}
	}

	return 0;
}

static int32_t push_pes_data(uint8_t *data, uint32_t len, uint32_t is_start,
		void *param) {

	pes_filter_t *pes = (pes_filter_t*) param;
	if(!pes->started && !is_start) {
		ALOGD("wating first complete PES packet");
		return 0;
	}

	if (is_start) {
		//ALOGV("new pes, valid size %d", pes->valid_size);
		if (pes->valid_size > 0) {
			pes->ctrl_bits |= LAST_PART_BIT;

			//send data
			pes->data_info.ctrl_bits = pes->ctrl_bits;
			pes->data_info.data_len = pes->valid_size;
			pes->updatedatacb(&pes->data_info, pes->cookie);

			//clear status
			pes->free_size = 0;
			pes->valid_size = 0;
			pes->ctrl_bits = 0;
		}
		if(!pes->started) {
			pes->started = 1;
		}
	}
	int32_t err;
	uint8_t *buf = data;
	while (len > 0) {
		if (pes->free_size == 0) {
			//request buffer
			err = pes->requestbufcb(&pes->md_buf, pes->cookie);

			if (err != 0 || pes->md_buf.buf == NULL) {
				if (pes->md_buf.buf_size == 1)
					return 1;
				else
					return -1;
			}

			pes->cur_ptr = pes->md_buf.buf;
			pes->free_size = pes->md_buf.buf_size;
		}

		if (is_start) {
			is_start = 0;
			pes->ctrl_bits |= FIRST_PART_BIT;
		}

		int32_t copy_size = pes->free_size > len ? len : pes->free_size;
		memcpy(pes->cur_ptr, buf, copy_size);
		pes->free_size -= copy_size;
		pes->cur_ptr += copy_size;
		pes->valid_size += copy_size;
		buf += copy_size;
		len -= copy_size;

		if(pes->free_size <= 0 || pes->valid_size >= pes->total_size) {
			//buffer is not enough, or we get a complete PES packet,
			//or PES packet length is unkown.
			pes->ctrl_bits |= LAST_PART_BIT;
			//send data
			pes->data_info.ctrl_bits = pes->ctrl_bits;
			pes->data_info.data_len = pes->valid_size;
			pes->updatedatacb(&pes->data_info, pes->cookie);

			pes->free_size = 0;
			pes->valid_size = 0;
			if(pes->free_size == 0) {
				//we send a complete PES packet.
				pes->ctrl_bits = FIRST_PART_BIT;
			} else {
				pes->ctrl_bits = 0;
			}
		}

	}
	return 0;
}

static int32_t push_ts_data(uint8_t *data, uint32_t len, uint32_t new_frm,
		void *param) {
	uint8_t *dataptr;
	uint32_t tmp;
	tmp = new_frm;
	dataptr = data;
	ts_filter_t *ts = (ts_filter_t*) param;

	while (len > 0) {
		//request buffer
		ts->requestbufcb(&ts->md_buf, ts->cookie);
		if (ts->md_buf.buf == NULL) {
			return -1;
		}

		ts->cur_ptr = ts->md_buf.buf;
		ts->free_size = ts->md_buf.buf_size;

		if (ts->free_size < len) {
			memcpy(ts->cur_ptr, dataptr, ts->free_size);
			ts->updatedatacb(&ts->free_size, ts->cookie);
			len -= ts->free_size;
			ts->free_size = 0;
			ts->cur_ptr = NULL;
		} else {
			memcpy(ts->cur_ptr, dataptr, len);
			ts->updatedatacb(&len, ts->cookie);
			len = 0;
			ts->free_size = 0;
			ts->cur_ptr = NULL;
		}
	}

	return 0;
}

static int32_t push_section_data(uint8_t *data, uint32_t len,
		uint32_t new_section, void *param) {
	uint8_t *dataptr;

	dataptr = data;

	section_filter_t *tss = (section_filter_t*) param;
	if (new_section) {
		tss->free_size = 0;
		tss->cur_ptr = NULL;
		if (tss->section_h_size > 0) {
			if (tss->end_of_section_reached != 0) {
				//find nes section,
				//but the last section has not closed, discard the parsed datas
				tss->updatedatacb(&tss->section_h_size, tss->cookie);
				tss->free_size = 0;
			} else {
				tss->cur_ptr = tss->md_buf.buf;
				tss->free_size = tss->md_buf.buf_size;
			}
		}

		tss->end_of_section_reached = 0;
		tss->section_index = 0;
		tss->section_h_size = (AV_RB16(dataptr + 1) & 0xfff) + 3;
		if (tss->section_h_size > MAX_SECTION_SIZE) {
			tss->section_h_size = MAX_SECTION_SIZE;
		}
	}

	while (len > 0) {
		if (tss->free_size == 0) {
			//request buffer
			tss->requestbufcb(&tss->md_buf, tss->cookie);
			if (tss->md_buf.buf == NULL) {
				return -1;
			}

			tss->cur_ptr = tss->md_buf.buf;
			tss->free_size = tss->md_buf.buf_size;
		} //if tss->free_size

		if (tss->free_size < len) {
			memcpy(tss->cur_ptr, dataptr, tss->free_size);
			tss->cur_ptr += tss->free_size;
			tss->section_index += tss->free_size;
			len = 0;

			tss->free_size = 0;
			tss->end_of_section_reached = 1;
			tss->updatedatacb(&tss->section_h_size, tss->cookie);
			tss->section_h_size = 0;
		} else {
			memcpy(tss->cur_ptr, dataptr, len);
			tss->free_size -= len;
			tss->cur_ptr += len;
			tss->section_index += len;
			len = 0;
		} //end if else

		if ((tss->section_h_size != 0)
				&& (tss->section_index >= tss->section_h_size)) {
			tss->end_of_section_reached = 1;
			tss->updatedatacb(&tss->section_h_size, tss->cookie);
			tss->free_size = 0;
			tss->section_h_size = 0;
		}
	}

	return 0;
}

static int32_t push_recoder_data(uint8_t *data, uint32_t len, uint32_t new_frm,
		void *param) {

	uint8_t *dataptr = data;
	uint32_t tmp;

	tmp = new_frm;
	recorder_filter_t *recorder = (recorder_filter_t*) param;
	int32_t err = 0;
	int32_t offset = 0;
	while(len > 0) {
		md_buf_t md_buf;
		memset(&md_buf, 0, sizeof(md_buf_t));
		err = recorder->requestbufcb(&md_buf, recorder->cookie);
		if(err || md_buf.buf == NULL) {
			err = -1;
			break;
		}
		if(md_buf.buf_size > len) {
			md_buf.buf_size = len;
		}
		else
		{
			ALOGW("packets len is too long, len %d!", len);
		}

		memcpy(md_buf.buf, dataptr + offset, md_buf.buf_size);

		recorder->updatedatacb(&md_buf.buf_size, recorder->cookie);
		len -= md_buf.buf_size;
		offset += md_buf.buf_size;
		if(len > 0) {
			usleep(10*1000);
		}
	}

	return err;
}

static void handle_payload_by_es(uint8_t *buf, int32_t buf_size, int32_t is_start,
		es_filter_t *es) {
	uint8_t *p;
	int32_t len;
	int32_t code;
	uint32_t first;
	int32_t j;

	first = 0;

	if (is_start) {
		es->state = MPEGTS_HEADER;
		es->data_index = 0;
		es->payload_size = 0;
	}

	p = buf;
	while (buf_size > 0) {
		switch (es->state) {
		case MPEGTS_HEADER:
			len = PES_START_SIZE - es->data_index;

			if (len > buf_size)
				len = buf_size;

			for (j = 0; j < len; j++) {
				es->header[es->data_index++] = *p++;
			}

			buf_size -= len;
			int32_t skip = 1;
			if (es->data_index == PES_START_SIZE) {
				/* we got all the PES or section header. We can now decide */
				if (es->header[0] == 0x00 && es->header[1] == 0x00
						&& es->header[2] == 0x01) {
					//it must be an mpeg2 PES stream
					code = es->header[3] | 0x100;
					if ((code >= 0x1c0 && code <= 0x1df)
							|| (code >= 0x1e0 && code <= 0x1ef)
							|| (code == 0x1bd) || (code == 0x1fd)) {

						es->state = MPEGTS_PESHEADER_FILL;

						//if pes->total_size = 0, it means the byte num followed is umlimited
						es->total_size = AV_RB16(es->header + 4);

						//NOTE: a zero total size means the PES size is unbounded
						if (es->total_size)
							es->total_size += 6;

						es->pes_header_size = es->header[8] + 9;

						if (es->total_size > 6) {
							es->payload_size = es->total_size - es->pes_header_size;
						}
						//because we have encountered stream with pes started not with an es start code,
						//we decide to check start code when the new_frm flag is set.
						//if it is not started with a start code, we clear the new_frm flag and treat the
						//data as part of the previous frame.
						//to prevend from sending data when valid_size is bigger than the payload_size,
						//we need to set the payload size to zero.
						if(es->codec_type == DMX_CODEC_AVC)
							es->payload_size = 0;
						skip = 0;
					}
				}

				if(skip) {
					//not a pes or unsuppored stream id
					es->state = MPEGTS_SKIP;
					continue;
				}
			}
			break;

			/**********************************************/
			/* PES packing parsing */
		case MPEGTS_PESHEADER_FILL:
			len = es->pes_header_size - es->data_index;
			if (len > buf_size)
				len = buf_size;

			for (j = 0; j < len; j++) {
				es->header[es->data_index++] = *p++;
			}
			buf_size -= len;
			if (es->data_index == es->pes_header_size) {
				const uint8_t* r;
				uint32_t flags;

				flags = es->header[7];
				r = es->header + 9;
				es->pts = (int64_t) - 1;

				if ((flags & 0xc0) == 0x80) { //PTS
					es->pts = get_pts(r);
					r += 5;
				} else if ((flags & 0xc0) == 0xc0) { //PTS and DTS
					es->pts = get_pts(r);
					r += 10;
				}
				/* we got the full header. We parse it and get the payload */
				es->state = MPEGTS_PAYLOAD;
				es->is_first = 1;
			}
			break;

		case MPEGTS_PAYLOAD:
			if (es->total_size) {
				len = es->total_size - es->data_index;
				if ((len > buf_size) || (len < 0)) {
					len = buf_size;
				}
			} else {
				len = buf_size;
			}

			if (len > 0) {
				first = es->is_first;
				if(first && es->codec_type == DMX_CODEC_AVC) {
					int pos = find_start_code_pos(p, len);
					if(pos > 0) {
						es->push_es_data(p, pos, 0, es);
						p += pos;
						len -= pos;
					} else if(pos < 0) {
						first = 0;
					} else {
						//pos is 0, this is what we wanted most.
					}
				}
				es->push_es_data(p, len, first, es);
				if(es->codec_type == DMX_CODEC_AVC) {
					if(first) {
						es->is_first = 0;
					}
				} else {
					es->is_first = 0;
				}
				if (es->pts != (int64_t) - 1)
					es->pre_pts = es->pts;

				es->pts = -1;
				return;
			} //if len
			buf_size = 0;
			break;

		case MPEGTS_SKIP:
			buf_size = 0;
			break;
		}
	}
}

static void handle_payload_by_pes(uint8_t* buf, int32_t buf_size,
		int32_t is_start, pes_filter_t* pes) {

	uint8_t *p = buf;

	if(is_start) {
		pes->total_size = AV_RB16(p + 4);
		if(pes->total_size) {
			pes->total_size += 6;
		} else {
			ALOGW("pes length is unkown.");
		}
	}
	pes->push_pes_data(p, buf_size, is_start, pes);
}

static void handle_es_packets(uint8_t* pktdata, uint32_t pkt_num, es_filter_t* es) {
	int32_t i;
	uint8_t* pkt;
	uint8_t* p;
	uint8_t* p_end;
	int32_t is_start;
	int32_t afc;

	pkt = pktdata - 188;
	for (i = pkt_num; i > 0; i--) {
		pkt += 188;

		is_start = pkt[1] & 0x40;

		/* skip adaptation field */
		afc = (pkt[3] >> 4) & 3;
		p = pkt + 4;
		if (afc == 0 || afc == 2) /* reserved value */
			continue;

		if (afc == 3) {
			/* skip adaptation field */
			if (is_start && (p[0] > 0)) {
				es->rap_flag = (p[1] & 0x40) >> 6; //get random_access_indicator
			}

			p += p[0] + 1;
		}

		/* if past the end of packet, ignore */
		p_end = pkt + 188;
		if (p >= p_end)
			continue;

		handle_payload_by_es(p, p_end - p, is_start, es);
	}
}

static void handle_pes_packets(uint8_t* pktdata, uint32_t pkt_num,
		pes_filter_t* pes) {
	int32_t i;
	uint8_t* pkt;
	uint8_t* p;
	uint8_t* p_end;
	int32_t is_start;
	int32_t afc;

	pkt = pktdata - 188;
	for (i = pkt_num; i > 0; i--) {
		pkt += 188;

		is_start = pkt[1] & 0x40;

		/* skip adaptation field */
		afc = (pkt[3] >> 4) & 3;
		p = pkt + 4;
		if (afc == 0 || afc == 2) /* reserved value */
			continue;

		if (afc == 3) {
			p += p[0] + 1;
		}

		/* if past the end of packet, ignore */
		p_end = pkt + 188;
		if (p >= p_end)
			continue;

		handle_payload_by_pes(p, p_end - p, is_start, pes);
	}
}

static void handle_section_packets(uint8_t* pktdata, uint32_t pkt_num,
		section_filter_t* section) {
	uint32_t i;
	uint8_t* pkt;
	uint8_t* p;
	uint8_t* p_end;
	int32_t is_start;
	int32_t afc;
	int32_t cc;
	int32_t cc_ok;
	int32_t len;

	pkt = pktdata - 188;
	for (i = pkt_num; i > 0; i--) {
		pkt += 188;
		is_start = pkt[1] & 0x40;
		if (is_start == 0) {
			if (section->need_start)
				continue;
		}

		/* skip adaptation field */
		afc = (pkt[3] >> 4) & 3;
		p = pkt + 4;
		if (afc == 0 || afc == 2) /* reserved value */
			continue;

		if (afc == 3)
			p += p[0] + 1;

		/* if past the end of packet, ignore */
		p_end = pkt + 188;
		if (p >= p_end)
			continue;

		cc = pkt[3] & 0xf; //get continuity_counter field
		cc_ok = (section->last_cc < 0)
				|| (((section->last_cc + 1) & 0xf) == cc);
		section->last_cc = cc;

		if (is_start) {
			//pointer field present.
			len = *p++;
			if ((p + len) > p_end)
				return;

			if (len && cc_ok && !section->need_start) {
				section->push_section_data(p, len, 0, section);
			}

			p += len;
			if (p < p_end) {
				section->push_section_data(p, p_end - p, is_start, section);
			}
		} else if (cc_ok) {
			section->push_section_data(p, p_end - p, is_start, section);
		}

		if (is_start)
			section->need_start = 0;
	}

	return;
}

static void handle_recorder_packets(uint8_t* pktdata, uint32_t pkt_num,
		recorder_filter_t* recorder) {

	uint8_t *pkt = pktdata - 188;
	int32_t i;
	int32_t err = 0;
	if(recorder->count == 1 && recorder->pid[0] == 8192) {
		//push all ts packet.
		err = recorder->push_data(pkt, 188*pkt_num, 0, recorder);
	}
	else{
		for (i = pkt_num; i > 0; i--) {
			pkt += 188;
			if(err) {
				//ALOGE("error occurs while pushing recorder data.");
				break;
			}
			if(pkt[0] != 0x47) {
				ALOGE("packet not sync, sync bytes 0x%02x, pktnum %d, i %d", pkt[0], pkt_num, i);
				err = -1;
				continue;
			}

			int32_t j;
			int32_t pid = (pkt[1] << 8 | pkt[2]) & 0x1fff;
			for(j = 0; j < recorder->count; j ++) {
				if(recorder->pid[j] == pid) {
					//filter this pid.
					//ALOGD("pushing pid 0x%04x, count %d", pid, recorder->count);
					uint32_t len = 188;
					err = recorder->push_data(pkt, len, 0, recorder);
					break;
				}
			}
		}
	}
}

static void* es_main_task(void* arg) {
	int32_t result;
	tsf_data_t tsf_data;

	filter_t *filter = (filter_t *) arg;
	es_filter_t *es = &filter->u.es_filter;
	int32_t chan = filter->chan;
	ts_dev_t *tsc_handle = filter->tsc_handle;
	ALOGI("thread start, pid %d, stream type %d, codec type %d",
			es->pid, es->stream_type, es->codec_type);
	while (filter->status != DEMUX_STATUS_STOPPED) {
		//wait for data
		pthread_mutex_lock(&filter->mutex);
		if(filter->status == DEMUX_STATUS_STARTED) {
			//get data buffer pointer
			result = tsc_handle->request_channel_data(tsc_handle->cookie, chan, &tsf_data);
			if (result != 0) {
				pthread_mutex_unlock(&filter->mutex);
				break;
			}
			//ALOGD("packet num %d vs %d", tsf_data.pkt_num, tsf_data.ring_pkt_num);
			//handle packets

			if (tsf_data.pkt_num) {
				handle_es_packets(tsf_data.data, tsf_data.pkt_num, es);
			}

			if (tsf_data.ring_pkt_num) {
				handle_es_packets(tsf_data.ring_data, tsf_data.ring_pkt_num, es);
			}
			tsc_handle->flush_channel_data(tsc_handle->cookie, chan,
					tsf_data.pkt_num + tsf_data.ring_pkt_num);
		} else if(filter->status == DEMUX_STATUS_STOPPED) {
			//TODO:nothing to do
		} else {
			pthread_cond_wait(&filter->condition, &filter->mutex);
		}
		pthread_mutex_unlock(&filter->mutex);
		usleep(5 * 1000);
	}
	pthread_exit(NULL);
	return NULL;
}

static void* pes_main_task(void* arg) {

	int32_t result;
	tsf_data_t tsf_data;

	filter_t *filter = (filter_t *) arg;
	pes_filter_t *pes = &filter->u.pes_filter;
	int32_t chan = filter->chan;
	ts_dev_t *tsc_handle = filter->tsc_handle;

	while (filter->status != DEMUX_STATUS_STOPPED) {
		//get data buffer pointer
		result = tsc_handle->request_channel_data(tsc_handle->cookie, chan, &tsf_data);
		ALOGD("###result: %d", result);
		if (result != 0)
			break;
		//handle packets
		if (tsf_data.pkt_num) {
			handle_pes_packets(tsf_data.data, tsf_data.pkt_num, pes);
		}
		if (tsf_data.ring_pkt_num) {
			handle_pes_packets(tsf_data.ring_data, tsf_data.ring_pkt_num, pes);
		}

		tsc_handle->flush_channel_data(tsc_handle->cookie, chan,
				tsf_data.pkt_num + tsf_data.ring_pkt_num);
		usleep(10 * 1000);
	}
	pthread_exit(NULL);
	return NULL;
}

static void* ts_main_task(void *arg) {
	int32_t result;
	tsf_data_t tsf_data;

	filter_t *filter = (filter_t *) arg;
	ts_filter_t *ts = &filter->u.ts_filter;
	int32_t chan = filter->chan;
	ts_dev_t *tsc_handle = filter->tsc_handle;

	while (filter->status != DEMUX_STATUS_STOPPED) {
		//get data buffer pointer
		result = tsc_handle->request_channel_data(tsc_handle->cookie, chan, &tsf_data);
		if (result != 0)
			break;

		//handle packets
		if (tsf_data.pkt_num) {
			ts->push_ts_data(tsf_data.data, tsf_data.pkt_num * 188, 0,
					(void*) ts);
		}
		if (tsf_data.ring_pkt_num) {
			ts->push_ts_data(tsf_data.ring_data, tsf_data.ring_pkt_num * 188, 0,
					(void*) ts);
		}
		tsc_handle->flush_channel_data(tsc_handle->cookie, chan,
				tsf_data.pkt_num + tsf_data.ring_pkt_num);
		usleep(5 * 1000);
	}
	pthread_exit(NULL);
	return NULL;
}

static void* section_main_task(void* arg) {
	int32_t result;
	tsf_data_t tsf_data;

	filter_t *filter = (filter_t *) arg;
	section_filter_t *section = &filter->u.section_filter;
	int32_t chan = filter->chan;
	ts_dev_t *tsc_handle = filter->tsc_handle;

	section->need_start = 1;
	section->end_of_section_reached = 0;
	while (filter->status != DEMUX_STATUS_STOPPED) {
		//get data buffer pointer
		result = tsc_handle->request_channel_data(tsc_handle->cookie, chan, &tsf_data);
		if (result != 0)
			break;
		//handle packets
		if (tsf_data.pkt_num) {
			handle_section_packets(tsf_data.data, tsf_data.pkt_num, section);
		}
		if (tsf_data.ring_pkt_num) {
			handle_section_packets(tsf_data.ring_data, tsf_data.ring_pkt_num,
					section);

		}
		tsc_handle->flush_channel_data(tsc_handle->cookie, chan,
				tsf_data.pkt_num + tsf_data.ring_pkt_num);

		usleep(20*1000);
	}
	pthread_exit(NULL);
	return NULL;
}

static void* recorder_main_task(void* arg) {
	ALOGV("recorder_main_task");
	tsf_data_t tsf_data;
	recorder_filter_t *recorder = (recorder_filter_t *)arg;
	ts_dev_t *tsc_handle = recorder->tsc_handle;
	int32_t chan = recorder->chan;

	memset(&tsf_data, 0, sizeof(tsf_data_t));//add by xhw

	while (recorder->thread_exit == 0) {
		//get data buffer pointer
		 int32_t result = tsc_handle->request_channel_data(tsc_handle->cookie, chan, &tsf_data);
		if (result != 0)
			break;
		//handle packets
		if (tsf_data.pkt_num) {
			handle_recorder_packets(tsf_data.data, tsf_data.pkt_num, (void*) recorder);
		}
		if (tsf_data.ring_pkt_num) {
			handle_recorder_packets(tsf_data.ring_data, tsf_data.ring_pkt_num, (void*) recorder);
		}

		tsc_handle->flush_channel_data(tsc_handle->cookie, chan,
				tsf_data.pkt_num + tsf_data.ring_pkt_num);
		usleep(1 * 1000);
	}

	pthread_exit(NULL);
	return NULL;
}

static int32_t allocate_filter(int32_t pid, demux_filter_param_t* filter_param,
		mpegts_context_t* ctx) {
	//int32_t err;
	filter_t* filter;
	es_filter_t* es;
	pes_filter_t* pes;
	ts_filter_t* ts;
	section_filter_t* section;

	pthread_mutex_lock(&ctx->mutex);

	if (ctx->pids[pid]) {
		//pid aready exists
		ALOGE("pid %d already opend", pid);
		pthread_mutex_unlock(&ctx->mutex);
		return -1;
	}

	filter = (filter_t*) malloc(sizeof(filter_t));
	if (NULL == filter) {
		pthread_mutex_unlock(&ctx->mutex);
		return -1;
	}
	memset(filter, 0, sizeof(filter_t));

	dtv_sem_init(&filter->wait_data_sem, 0);
	//for TS and section, we start immediately.
	filter->status = DEMUX_STATUS_STARTED;
	if (filter_param->filter_type == DMX_FILTER_TYPE_ES) {
		es = &filter->u.es_filter;
		es->pid = pid;
		es->requestbufcb = filter_param->request_buffer_cb;
		es->updatedatacb = filter_param->update_data_cb;
		es->push_es_data = push_es_data;
		es->stream_type = filter_param->stream_type;
		es->codec_type = filter_param->codec_type;
		es->cookie = filter_param->cookie;
		filter->status = DEMUX_STATUS_IDLE;
	} else if (filter_param->filter_type == DMX_FILTER_TYPE_PES) {
		pes = &filter->u.pes_filter;
		pes->pid = pid;
		pes->requestbufcb = filter_param->request_buffer_cb;
		pes->updatedatacb = filter_param->update_data_cb;
		pes->push_pes_data = push_pes_data;
		pes->cookie = filter_param->cookie;
	} else if (filter_param->filter_type == DMX_FILTER_TYPE_TS) {
		ts = &filter->u.ts_filter;
		ts->pid = pid;
		ts->requestbufcb = filter_param->request_buffer_cb;
		ts->updatedatacb = filter_param->update_data_cb;
		ts->push_ts_data = (push_data_cb)push_ts_data;
		ts->cookie = filter_param->cookie;
	} else {
		section = &filter->u.section_filter;
		section->last_cc = -1;
		section->pid = pid;
		section->requestbufcb = filter_param->request_buffer_cb;
		section->updatedatacb = filter_param->update_data_cb;
		section->push_section_data = push_section_data;
		section->cookie = filter_param->cookie;
	}
	pthread_cond_init(&filter->condition, NULL);
	pthread_mutex_init(&filter->mutex, NULL);

	filter->pid = pid;
	filter->type = filter_param->filter_type;
	filter->tsc_handle = ctx->tsc_handle;

	ctx->pids[pid] = filter;
	pthread_mutex_unlock(&ctx->mutex);

	return 0;
}

static int32_t free_filter(int32_t pid, mpegts_context_t* ctx) {
	//int32_t err;
	filter_t* filter;

	pthread_mutex_lock(&ctx->mutex);
	filter = ctx->pids[pid];
	if (filter == NULL) {
		pthread_mutex_unlock(&ctx->mutex);
		return -1;
	}
	pthread_cond_destroy(&filter->condition);
	pthread_mutex_destroy(&filter->mutex);
	dtv_sem_deinit(&filter->wait_data_sem);
	free(filter);
	ctx->pids[pid] = NULL;

	pthread_mutex_unlock(&ctx->mutex);

	return 0;
}

static filter_t* open_filter(int32_t pid, demux_filter_param_t* filter_param,
		mpegts_context_t* ctx) {
	int32_t err;
	int32_t result;
	int32_t chan;
	filter_t* filter;
	chan_register_t chan_register;

	result = allocate_filter(pid, filter_param, ctx);
	if (result < 0) {
		ALOGE("allocate filter fail.");
		return NULL;
	}

	filter = ctx->pids[pid];

	chan_register.pid = filter->pid;
	chan_register.callback = (ptsc_callback_t)data_arrive_callback;
	chan_register.callbackparam = (void*)filter;
	chan_register.chan_type = CHAN_TYPE_LIVE;
	if(filter_param->stream_type == DMX_STREAM_VIDEO)
		chan_register.stream_type = TS_STREAM_VIDEO;
	else if(filter_param->stream_type == DMX_STREAM_AUDIO)
		chan_register.stream_type = TS_STREAM_AUDIO;
	else if(filter_param->stream_type == DMX_STREAM_SUBTITLE)
		chan_register.stream_type = TS_STREAM_SUBTITLE;
	else if(filter_param->stream_type == DMX_STREAM_SECTION)
		chan_register.stream_type = TS_STREAM_SECTION;
	else
		chan_register.stream_type = TS_STREAM_UNKOWN;

	chan = filter->tsc_handle->open_channel(filter->tsc_handle->cookie, &chan_register);
	if (chan < 0) {
		ALOGE("open tsc pid channel fail, pid = %d.", pid);
		return NULL;
	}

	filter->chan = chan;

	if (filter_param->filter_type == DMX_FILTER_TYPE_ES)
		err = pthread_create(&filter->thread_id, NULL, es_main_task,
				(void*) filter);
	else if (filter_param->filter_type == DMX_FILTER_TYPE_PES)
		err = pthread_create(&filter->thread_id, NULL, pes_main_task,
				(void*) filter);
	else if (filter_param->filter_type == DMX_FILTER_TYPE_TS)
		err = pthread_create(&filter->thread_id, NULL, ts_main_task,
				(void*) filter);
	else
		err = pthread_create(&filter->thread_id, NULL, section_main_task,
				(void*) filter);

	if (err != 0) {
		filter->status = DEMUX_STATUS_STOPPED;
		ALOGE("create thread fail.");
		filter->tsc_handle->close_channel(filter->tsc_handle->cookie, filter->chan);
		return NULL;
	}

	return filter;
}

static void close_filter(filter_t* filter, mpegts_context_t* ctx) {
	int32_t err;
	ALOGV("close filter");
	pthread_mutex_lock(&filter->mutex);
	filter->status = DEMUX_STATUS_STOPPED;
	pthread_cond_signal(&filter->condition);
	pthread_mutex_unlock(&filter->mutex);

	if (filter->thread_id > 0) {
		dtv_sem_up(&filter->wait_data_sem);
		err = pthread_join(filter->thread_id, NULL);
		ALOGV("chan %d, thread exit", filter->chan);
	}

	filter->tsc_handle->close_channel(filter->tsc_handle->cookie, filter->chan);
	free_filter(filter->pid, ctx);

	return;
}

void* ts_demux_open(int type) {
	//int32_t err;
	mpegts_context_t* mp;
	ALOGV("ts_demux_open");
	mp = (mpegts_context_t*) malloc(sizeof(mpegts_context_t));
	if (mp == NULL)
		return NULL;

	memset(mp, 0, sizeof(mpegts_context_t));

	pthread_mutex_init(&mp->mutex, NULL);
	if(type == DEMUX_TYPE_LIVE_AND_RECORDE) {
		mp->tsc_handle = tsc_dev_open();
	} else if(type == DEMUX_TYPE_INJECT){
		mp->tsc_handle = ts_parser_open();
	}
	if (mp->tsc_handle == NULL) {
		ALOGE("open tsc fail.");
		pthread_mutex_destroy(&mp->mutex);
		free(mp);
		return NULL;
	}
	mp->demux_type = type;
	return (void*) mp;
}

int32_t ts_demux_close(void* handle) {
	int32_t i;
	ALOGV("ts_demux_close");

	mpegts_context_t *mp = (mpegts_context_t*) handle;
	for (i = 0; i < NB_PID_MAX; i++) {
		if (mp->pids[i]) {
			close_filter(mp->pids[i], mp);
			mp->pids[i] = NULL;
		}
	}

	if (mp->detectpcr)
		ts_demux_close_pcr_filter(handle);

	if(mp->demux_type == DEMUX_TYPE_LIVE_AND_RECORDE) {
		tsc_dev_close(mp->tsc_handle);
	} else {
		ts_parser_close(mp->tsc_handle);
	}
	pthread_mutex_destroy(&mp->mutex);
	free(mp);

	return 0;
}

int32_t ts_demux_open_filter(void* handle, int32_t pid,
		demux_filter_param_t* filter_param) {
	mpegts_context_t* mp;
	ALOGV("open filter, pid %d", pid);
	mp = (mpegts_context_t*) handle;

	open_filter(pid, filter_param, mp);

	if (mp->pids[pid] != NULL)
		return 0;
	else
		return -1;
}

int32_t ts_demux_close_filter(void* handle, int32_t pid) {
	mpegts_context_t* mp;
	ALOGV("close filter, pid:%d", pid);
	mp = (mpegts_context_t*) handle;
	if (mp->pids[pid]) {
		close_filter(mp->pids[pid], mp);
		mp->pids[pid] = NULL;
	}

	return 0;
}

int32_t ts_demux_open_pcr_filter(void* handle, int32_t pid,
		pdemux_callback_t callback, void* cookie) {
	mpegts_context_t* mp;

	mp = (mpegts_context_t*) handle;

	pthread_mutex_lock(&mp->mutex);
	if (mp->detectpcr)
		ts_demux_close_pcr_filter(handle);

	mp->detectpcr = 1;
	mp->pcrid = pid;
	mp->pcrcallback = callback;
	mp->pcr_cookie = cookie;

	chan_register_t chan_register;
	chan_register.pid = mp->pcrid;
	chan_register.callback = (ptsc_callback_t)pcr_notify;
	chan_register.callbackparam = mp;
	mp->tsc_handle->open_pcr_detect(mp->tsc_handle->cookie, &chan_register);
	pthread_mutex_unlock(&mp->mutex);

	return 0;
}

int32_t ts_demux_close_pcr_filter(void *handle) {
	mpegts_context_t *mp = (mpegts_context_t*) handle;
	pthread_mutex_lock(&mp->mutex);
	if (mp->detectpcr) {
		mp->tsc_handle->close_pcr_detect(mp->tsc_handle->cookie);
		mp->detectpcr = 0;
		mp->pcrid = 0;
		mp->pcrcallback = NULL;
		mp->pcr_cookie = NULL;
	}
	pthread_mutex_unlock(&mp->mutex);

	return 0;
}

int ts_demux_open_recorder(void *handle, demux_recoder_param_t *param)
{
	ALOGV("ts_demux_open_recoder");
	mpegts_context_t *mp = (mpegts_context_t*) handle;
	if(!mp || !param) {
		return -1;
	}
	if(param->count <= 0) {
		ALOGE("stream count is %d", param->count);
	}
	pthread_mutex_lock(&mp->mutex);
	if(mp->recorder) {
		ALOGE("recorder has started");

		pthread_mutex_unlock(&mp->mutex);
		return -1;
	}
	recorder_filter_t *recorder = (recorder_filter_t *)malloc(sizeof(recorder_filter_t));
	if(recorder == NULL) {
		ALOGE("malloc recorder filter failed");
		free(recorder);
		pthread_mutex_unlock(&mp->mutex);
		return -1;
	}
	recorder->tsc_handle = mp->tsc_handle;
	chan_register_t chan_register;
	chan_register.chan_type = CHAN_TYPE_RECORDE;
	chan_register.pid = 8192;
	chan_register.callback = (ptsc_callback_t)data_arrive_callback;
	chan_register.stream_type = TS_STREAM_UNKOWN;

	int32_t chan = mp->tsc_handle->open_channel(mp->tsc_handle->cookie, &chan_register);
	if (chan < 0) {
		ALOGE("open tsc pid channel for recorder fail");
		free(recorder);
		pthread_mutex_unlock(&mp->mutex);
		return -1;
	}
	recorder->chan = chan;

	recorder->cookie		= param->cookie;
	recorder->requestbufcb	= param->request_buffer_cb;
	recorder->updatedatacb	= param->update_data_cb;
	recorder->push_data		= (push_data_cb)push_recoder_data;
	recorder->count			= param->count;
	mp->recorder			= recorder;
	memcpy(&recorder->pid[0], param->pids, sizeof(int) * param->count);

	recorder->thread_exit = 0;
	int32_t err = pthread_create(&recorder->thread_id, NULL, recorder_main_task,
				(void*) recorder);

	if (err != 0) {
		recorder->thread_exit = 1;
		ALOGE("create thread fail.");
		mp->tsc_handle->close_channel(mp->tsc_handle->cookie, recorder->chan);

		free(recorder);
		mp->recorder = NULL;

		pthread_mutex_unlock(&mp->mutex);
		return -1;
	}
	ALOGI("recording pid num %d", recorder->count);

	pthread_mutex_unlock(&mp->mutex);
	return 0;
}

int ts_demux_close_recorder(void *handle)
{
	ALOGV("ts_demux_close_recoder");
	mpegts_context_t *mp = (mpegts_context_t*) handle;
	if(!mp) {
		return 0;
	}
	pthread_mutex_lock(&mp->mutex);
	recorder_filter_t *recorder = mp->recorder;
	if(recorder) {
		if (recorder->thread_id > 0 && recorder->thread_exit == 0) {
			recorder->thread_exit = 1;
			int32_t err = pthread_join(recorder->thread_id, NULL);
			ALOGV("chan %d, thread exit", recorder->chan);
		}

		mp->tsc_handle->close_channel(mp->tsc_handle->cookie, recorder->chan);

		free(recorder);
		mp->recorder = NULL;
	}
	pthread_mutex_unlock(&mp->mutex);
	return 0;
}

int ts_demux_clear(void *handle)
{
	ALOGV("ts_demux_clear");
	mpegts_context_t *mp = (mpegts_context_t*) handle;
	if(!mp) {
		return -1;
	}
	int32_t i;
	pthread_mutex_lock(&mp->mutex);
	if(mp->tsc_handle->clear) {
		mp->tsc_handle->clear(mp->tsc_handle->cookie);
	}
	for(i = 0; i < NB_PID_MAX; i ++) {
		filter_t *filter = mp->pids[i];
		if(filter && filter->type == DMX_FILTER_TYPE_ES) {
			pthread_mutex_lock(&filter->mutex);
			es_filter_t *es = &filter->u.es_filter;
			es->cur_ptr = 0;
			es->free_size = 0;
			es->valid_size = 0;
			es->ctrl_bits = 0;
			es->rap_flag = 0;
			es->state = MPEGTS_HEADER;

			es->is_first = 0;
			es->pre_pts = -1;
			es->pts = -1;
			es->data_index = 0;
			es->total_size = 0;
			es->payload_size = 0;
			es->pes_header_size = 0;
			pthread_mutex_unlock(&filter->mutex);
		}
	}
	pthread_mutex_unlock(&mp->mutex);
	return 0;
}

int ts_demux_start(void *handle)
{
	ALOGV("ts_demux_start");
	mpegts_context_t *mp = (mpegts_context_t*) handle;
	if(!mp) {
		return -1;
	}
	int32_t i;
	pthread_mutex_lock(&mp->mutex);
	for(i = 0; i < NB_PID_MAX; i ++) {
		filter_t *filter = mp->pids[i];
		if(filter && (filter->type == DMX_FILTER_TYPE_ES)) {
			pthread_mutex_lock(&filter->mutex);
			mp->tsc_handle->reset_channel(mp->tsc_handle->cookie, filter->chan);
			filter->status = DEMUX_STATUS_STARTED;
			pthread_cond_signal(&filter->condition);
			pthread_mutex_unlock(&filter->mutex);
		}
	}
	pthread_mutex_unlock(&mp->mutex);
	return 0;
}

int ts_demux_pause(void *handle)
{
	ALOGV("ts_demux_pause");
	mpegts_context_t *mp = (mpegts_context_t*) handle;
	if(!mp) {
		return -1;
	}
	int32_t i;
	pthread_mutex_lock(&mp->mutex);
	for(i = 0; i < NB_PID_MAX; i ++) {
		filter_t *filter = mp->pids[i];
		if(filter && (filter->type == DMX_FILTER_TYPE_ES)) {
			ALOGI("pause filter %d", i);
			pthread_mutex_lock(&filter->mutex);
			filter->status = DEMUX_STATUS_PAUSED;
			pthread_mutex_unlock(&filter->mutex);
		}
	}
	pthread_mutex_unlock(&mp->mutex);
	return 0;
}

int32_t ts_demux_get_free_filter_num(void* handle) {
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	if(mp) {
		mp->tsc_handle->get_free_channel_num(mp->tsc_handle->cookie);
	}
	return 32;
}

int32_t ts_demux_get_ts_packet_num(void* handle) {
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	int32_t packet_num = 0;
	if(mp) {
		int32_t i;
		for (i = 0; i < NB_PID_MAX; i++) {
			if (mp->pids[i]) {
				packet_num += mp->tsc_handle->get_channel_packet_num(mp->tsc_handle->cookie, mp->pids[i]->chan);
			}
		}
	}

	return packet_num;
}

int ts_demux_set_buffer_size(void *handle, int size)
{
	ALOGV("ts_demux_set_buffer_size");
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	if(mp == NULL) {
		ALOGE("invalid handle");
		return -1;
	}
	if(mp->demux_type == DEMUX_TYPE_INJECT) {
		mp->tsc_handle->set_buffer_size(mp->tsc_handle->cookie, size);
	}
	return 0;
}

int ts_demux_write_data(void *handle, void *buf, int size)
{
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	if(mp == NULL) {
		ALOGE("invalid handle");
		return -1;
	}
	if(mp->demux_type == DEMUX_TYPE_INJECT) {
		return mp->tsc_handle->write_data(mp->tsc_handle->cookie,
				buf, size);
	}
	return 0;
}

int ts_demux_open_descramble(void* handle, int pid)
{
	int32_t i;
	int32_t ret = -1;
	int32_t chan = -1;
	int32_t index = -1;
	filter_t *filter = NULL;
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	if(mp == NULL) {
		ALOGE("invalid handle");
		return -1;
	}

	pthread_mutex_lock(&mp->mutex);
	filter = mp->pids[pid];
	if(filter && (filter->pid == pid))
	{
		chan = filter->chan;
	}

	for(i=0; i<MAX_DESCRAMBLE; i++)
	{
		if(mp->descramble[i].is_open && mp->descramble[i].pid==pid)
		{
			ALOGE("pid %d descramble have alloc\n",pid);
			index = -1;
			break;
		}
		else if(!mp->descramble[i].is_open && index < 0)
		{
			index = i;
		}
	}
	pthread_mutex_unlock(&mp->mutex);

	if(chan < 0)
	{
		ALOGE("pid %d filter have not alloc\n",pid);
		return -1;
	}
	if(index < 0)
	{
		ALOGE("alloc descramble is failed\n");
		return -1;
	}

	ALOGV("ts_demux_open_descramble in, pid 0x%x\n",pid);

	pthread_mutex_lock(&mp->mutex);
	mp->descramble[index].chan = chan;
	mp->descramble[index].pid = pid;
	mp->descramble[index].des_indx = mp->tsc_handle->open_descramble(mp->tsc_handle->cookie, chan);
	if(mp->descramble[index].des_indx >= 0)
	{
		mp->descramble[index].is_open = 1;
		ret = index;
	}
	pthread_mutex_unlock(&mp->mutex);

	return ret;
}

int ts_demux_close_descramble(void* handle, int index)
{
	int ret = -1;
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	if(mp == NULL) {
		ALOGE("invalid handle");
		return -1;
	}

	if(index >= MAX_DESCRAMBLE || index < 0)
	{
		ALOGE("invalid index %d\n",index);
		return -1;
	}

	pthread_mutex_lock(&mp->mutex);
	if(mp->descramble[index].is_open != 1)
	{
		pthread_mutex_unlock(&mp->mutex);
		ALOGE("invalid index %d\n",index);
		return -1;
	}
	ret = mp->tsc_handle->close_descramble(mp->tsc_handle->cookie, index);
	if(ret < 0)
	{
		ALOGE("close_descramble failed, ret %d\n",ret);
	}
	mp->descramble[index].is_open = 0;
	pthread_mutex_unlock(&mp->mutex);

	return ret;
}

int ts_demux_set_descramble_cw(void* handle, int index, ts_demux_cw_type_e cw_type, unsigned int cw_value)
{
	int ret = -1;
	mpegts_context_t* mp = (mpegts_context_t*) handle;
	if(mp == NULL) {
		ALOGE("invalid handle");
		return -1;
	}

	if(index >= MAX_DESCRAMBLE || index < 0)
	{
		ALOGE("invalid index %d\n",index);
		return -1;
	}

	pthread_mutex_lock(&mp->mutex);
	if(mp->descramble[index].is_open != 1)
	{
		pthread_mutex_unlock(&mp->mutex);
		ALOGE("invalid index %d\n",index);
		return -1;
	}

	ret = mp->tsc_handle->set_descramble_cw(mp->tsc_handle->cookie, index, cw_type, cw_value);

	if(ret < 0)
	{
		ALOGE("close_descramble failed, ret %d\n",ret);
	}

	pthread_mutex_unlock(&mp->mutex);

	return ret;
}