/*******************************************************************
                         GOP List Interface
 *******************************************************************/

#include "picture_header.h"
#include "gop.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 gop_list_find_gop(void *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 *)malloc((out->num_of_gop)*sizeof(GOP));

	for(i=out->num_of_gop-1;i>=0;i--){
		out->gops[i].offset = c->offset;
		out->gops[i].frame = c->frame;
		p = (GOP_ENTRY *)c->prev;
		free(c);
		c = p;
	}
	
	return 1;
}
/*******************************************************************/
int release_gop_list(GOP_LIST *p)
{
	free(p->gops);
	memset(p, 0, sizeof(GOP_LIST));

	return 1;
}
/*******************************************************************/
GOP gop_list_find_gop(void *p, int frame)
{
	int first, last;
	int i;

	GOP_LIST *gl;
	
	static const GOP r = {
		0, -1,
	};

	gl = (GOP_LIST *)p;
	
	if(frame < gl->gops[0].frame || frame > gl->num_of_frame-1){
		return r;
	}

	if(gl->gops[gl->num_of_gop-1].frame < frame){
		return gl->gops[gl->num_of_gop-1];
	}

	first = 0;
	last = gl->num_of_gop - 1;

	i = last/2;
	
	while(1){
		if(gl->gops[i].frame <= frame && gl->gops[i+1].frame > frame){
			return gl->gops[i];
		}else if(gl->gops[i].frame < frame){
			first = i;
		}else{
			last = i;
		}
		i = first + (last - first)/2;
		if(first == last){
			return r;
		}
	}
}