/*******************************************************************
                         GOP List Interface
 *******************************************************************/

#include "picture_header.h"

#define GOP_LIST_C
#include "gop_list.h"

int create_gop_list(MPEG_IO *in, GOP_LIST *out);
int release_gop_list(GOP_LIST *p);
GOP_ENTRY * find_gop(GOP_LIST *p, int frame);

/*******************************************************************/
int create_gop_list(MPEG_IO *in, GOP_LIST *out)
{
	int i;
	int frame;
	unsigned int code;
	GOP_ENTRY *p;
	GOP_ENTRY *c;
	PICTURE_HEADER pic;

	while(next_marker(in)){
		code = get_bits(in, 32);
		if(code == 0x100){
			/* stream has no-gop layer */
			return 0;
		}else if(code == 0x1B8){
			c = (GOP_ENTRY *)malloc(sizeof(GOP_ENTRY));
			c->index = 0;
			c->frame = 0;
			c->prev = NULL;
			frame = 0;
			c->offset = mpeg_io_tell(in) - 4;
			p = c;
			break;
		}
	}

	while(next_marker(in)){
		code = get_bits(in, 32);
		if(code == 0x100){
			frame += 1;
			read_picture_header(in, &pic);
			if(pic.picture_coding_type == 1){
				c->frame += pic.temporal_reference;
			}
		}else if(code == 0x1B8){
			c = (GOP_ENTRY *)malloc(sizeof(GOP_ENTRY));
			c->index = p->index + 1;
			c->frame = p->frame + frame;
			c->prev = (void *)p;
			p->next = (void *)c;
			frame = 0;
			c->offset = mpeg_io_tell(in) - 4;
			p = c;
		}
	}

	out->num_of_frame = c->frame + frame + 1;
	out->num_of_gop = c->index + 1;
	out->gops = (GOP_ENTRY *)malloc((out->num_of_gop)*sizeof(GOP_ENTRY));

	for(i=out->num_of_gop-1;i>=0;i--){
		out->gops[i].index = i;
		out->gops[i].offset = c->offset;
		out->gops[i].frame = c->frame;
		out->gops[i].prev = (void *)(out->gops + i - 1);
		out->gops[i].next = (void *)(out->gops + 1 + 1);
		p = (GOP_ENTRY *)c->prev;
		free(c);
		c = p;
	}
	out->gops[0].prev = NULL;
	out->gops[out->num_of_gop-1].next = NULL;
	
	return 1;
}
/*******************************************************************/
int release_gop_list(GOP_LIST *p)
{
	free(p->gops);
	memset(p, 0, sizeof(GOP_LIST));

	return 1;
}
/*******************************************************************/
GOP_ENTRY *find_gop(GOP_LIST *p, int frame)
{
	int first, last;
	int i;

	if(frame < p->gops[0].index || frame > p->num_of_frame-1){
		return NULL;
	}

	if(p->gops[p->num_of_gop-1].index < frame){
		return (p->gops + p->num_of_gop - 1);
	}

	first = 0;
	last = p->num_of_gop - 1;

	i = last/2;
	
	while(1){
		if(p->gops[i].frame <= frame && p->gops[i+1].frame > frame){
			return p->gops + i;
		}else if(p->gops[i].frame < frame){
			first = i;
		}else{
			last = i;
		}
		i = first + (last - first)/2;
		if(first == last){
			return NULL;
		}
	}
}