/*******************************************************************
                           VG - View GOP
 *******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include "mpeg_io.h"
#include "picture_header.h"
#include "sequence_header.h"
#include "timecode.h"
#include "gop_list.h"

void vg(char *path, int frame);
void show_mpeg_video_info(SEQUENCE_HEADER *in, FILE *out);
void show_time(time_t t, FILE *out);

int main(int argc, char **argv)
{
	int i;
	time_t t;
	
	if(argc < 3){
		fprintf(stderr, "Usage:\n");
		fprintf(stderr, "%s mpeg2video frame", argv[0]);
		exit(EXIT_FAILURE);
	}

	t = time(NULL);
	
	vg(argv[1], atoi(argv[2]));

	fprintf(stdout, "elapsed time: ");
	show_time(time(NULL) - t, stdout);
	fprintf(stdout, "\n");
	
	return EXIT_SUCCESS;
}

void vg(char *path, int frame)
{
	int i;
	MPEG_IO p;
	SEQUENCE_HEADER seq;
	PICTURE_HEADER pic;
	GOP_LIST g;
	GOP_ENTRY *e;
	int in_gop;
	int intra_offset;
	int code;
	size_t offset;
	
	char picture_type[8] = {
		' ', 'I', 'P', 'B', 'D', ' ', ' ',
	};
	
	if(!open_mpeg_file(path, &p)){
		fprintf(stderr, "%s - can't open\n", path);
		exit(EXIT_FAILURE);
	}

	if(!next_marker(&p)){
		fprintf(stderr, "%s - is not MPEG file\n", path);
		exit(EXIT_FAILURE);
	}

	code = get_bits(&p, 32);
	if(code != 0x1B3){
		fprintf(stderr, "%s - is not MPEG Video file\n", path);
		fprintf(stderr, "[DEBUG] code=%d\n", code);
		exit(EXIT_FAILURE);
	}

	if(!read_sequence_header(&p, &seq)){
		fprintf(stderr, "%s - has invalid sequence header\n", path);
		exit(EXIT_FAILURE);
	}

	show_mpeg_video_info(&seq, stdout);

	create_gop_list(&p, &g);

	e = find_gop(&g, frame);
	if(e == NULL){
		fprintf(stderr, "frame: %d - out of range\n", frame);
		exit(EXIT_FAILURE);
	}

	mpeg_io_seek(&p, e->offset, SEEK_SET);

	in_gop = 0;
	while(next_marker(&p)){
		code = get_bits(&p, 32);
		if(code == 0x1B8){
			fprintf(stdout, "GOP - %d, OFFSET - %d\n", e[in_gop].index, mpeg_io_tell(&p)-4);
			in_gop += 1;
		}else if(in_gop && code == 0x100){
			offset = mpeg_io_tell(&p)-4;
			read_picture_header(&p, &pic);
			if(pic.picture_coding_type == 1){
				intra_offset = pic.temporal_reference;
			}
			fprintf(stdout, "%4d, %c, %10d\n", e[in_gop-1].frame - intra_offset + pic.temporal_reference, picture_type[pic.picture_coding_type], offset);
			if(e[in_gop-1].frame - intra_offset + pic.temporal_reference == frame){
				break;
			}
		}
	}
	
	release_gop_list(&g);
	close_mpeg_file(&p);
}
	
void show_mpeg_video_info(SEQUENCE_HEADER *in, FILE *out)
{
	static const char yuv[4][16] = {
		"invalid",
		"4:2:0",
		"4:2:2",
		"4:4:4",
	};
	
	fprintf(out, "%dx%d, ", in->h_size, in->v_size);
	fprintf(out, "%d.%d fps, ", in->fps.frame / in->fps.scale, ((in->fps.frame % in->fps.scale) * 1000 / in->fps.scale));
	fprintf(out, "%d bps, ", in->bit_rate * 400);
	if(in->mpeg1){
		fprintf(out, "MPEG-1 Video\n");
	}else{
		if(in->se.progressive){
			fprintf(out, "Progressive");
		}else{
			fprintf(out, "Interlace");
		}
		fprintf(out, " MPEG-2 Video");
		fprintf(out, " YUV=%s\n", yuv[in->se.chroma_format]);
	}
}

void show_time(time_t t, FILE *out)
{
	int dd,hh,mm,ss;

	ss = t % 60;
	mm = t / 60 % 60;
	hh = t / 60 / 60 % 24;
	dd = t / 60 / 60 / 24;

	if(dd){
		fprintf(out, "%02d:%02d:%02d:%02d", dd,hh,mm,ss);
	}else{
		fprintf(out, "%02d:%02d:%02d", hh,mm,ss);
	}
}
