/*******************************************************************
                       CF - count frame number
 *******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "mpeg_io.h"
#include "sequence_header.h"
#include "timecode.h"

void cf(char *path);
void show_mpeg_video_info(SEQUENCE_HEADER *in, FILE *out);
int  get_fps(SEQUENCE_HEADER *in);
int  get_dpm(SEQUENCE_HEADER *in);

int main(int argc, char **argv)
{
	if(argc < 2){
		fprintf(stderr, "Usage:\n");
		fprintf(stderr, "%s mpeg2video", argv[0]);
		exit(EXIT_FAILURE);
	}

	cf(argv[1]);

	return EXIT_SUCCESS;
}

void cf(char *path)
{
	int GOP;
	MPEG_IO p;
	SEQUENCE_HEADER s;
	int code;
	int fps;
	int dpm;
	int temporal_reference;
	int first_frame;
	int last_frame;
	size_t offset;

	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, &s)){
		fprintf(stderr, "%s - has invalid sequence header\n", path);
		exit(EXIT_FAILURE);
	}

	show_mpeg_video_info(&s, stdout);

	GOP = 0;
	while(next_marker(&p)){
		code = get_bits(&p, 32);
		if(!GOP && code == 0x100){
			fprintf(stderr, "%s - has no GOP\n", path);
			exit(EXIT_FAILURE);
		}
		if(code == 0x1B8){
			TIMECODE t;
			
			GOP += 1;
			get_timecode(&p, &t);

			fps = get_fps(&s);
			dpm = get_dpm(&s);

			first_frame = timecode2frame(&t, fps, dpm);

			break;
		}
	}
			
	fseek(p.stream, - (s.bit_rate * 50), SEEK_END);
	erase_bits(&p, 32);

	while(next_marker(&p)){
		code = get_bits(&p, 32);
		if(code == 0x1B8){
			TIMECODE t;
			
			offset = ftell(p.stream);

			GOP += 1;
			get_timecode(&p, &t);

			last_frame = timecode2frame(&t, fps, dpm);
		}
	}
	
	temporal_reference = 0;

	fseek(p.stream, offset, SEEK_SET);
	erase_bits(&p, 32);
	
	while(next_marker(&p)){
		code = get_bits(&p, 32);
		if(code == 0x100){
			code = get_bits(&p, 10);
			if(code > temporal_reference){
				temporal_reference = code;
			}
			printf("debug, code=%d\n", code);
		}
	}
	
	last_frame += temporal_reference;
	
	fprintf(stdout, "total frame %d\n", last_frame - first_frame + 1);

	fprintf(stdout, "[DEBUG] first_frame: %d, last_frame:%d\n", first_frame, last_frame);
	close_mpeg_file(&p);

}
	
void show_mpeg_video_info(SEQUENCE_HEADER *in, FILE *out)
{
	static const char frame_rate[16][16] = {
		"invalid",   /* 0000 */
		"23.976",    /* 0001 */
		"24",        /* 0010 */
		"25",        /* 0011 */
		"29.97",     /* 0100 */
		"30",        /* 0101 */
		"50",        /* 0110 */
		"59.94",     /* 0111 */
		"60",        /* 1000 */
		"reserved",  /* 1001 */
		"reserved",  /* 1010 */
		"reserved",  /* 1011 */
		"reserved",  /* 1100 */
		"reserved",  /* 1101 */
		"reserved",  /* 1110 */
		"reserved",  /* 1111 */
	};

	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, "%s fps, ", frame_rate[in->frame_rate]);
	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]);
	}
}

int  get_fps(SEQUENCE_HEADER *in)
{
	static const int fps[16] = {
		0, 24, 24, 25, 30, 30, 50, 60,
		60, 0,  0,  0,  0,  0,  0,  0, 
	};
	
	return fps[in->frame_rate];
}
		
int  get_dpm(SEQUENCE_HEADER *in)
{
	static const int dpm[16] = {
		0, 1, 0, 0, 2, 0, 0, 4,
		0, 0, 0, 0, 0, 0, 0, 0,
	};

	return dpm[in->frame_rate];
}
	