/*
 *   MediaMVP Server Library
 *
 *   (C) 2004 Dave Kelly
 *
 *   Return the height, width and frame rate index from an MPEG file
 *
 *   $Id: mpeginfo.c,v 1.1 2004/05/11 19:26:06 dom Exp $
 *   $Date: 2004/05/11 19:26:06 $
 *
 */



#include "libmvp_internal.h"

typedef struct _ntsc_lookup {
	double rate;
	int		is_ntsc;
} ntsc_lookup_t;

struct _mpeginfo {
	int width;
	int height;
	int frame_rate_index;
};

ntsc_lookup_t rate_table[] = {
	{0., 0},
	{24000. / 1001., 1},
	{24., 0},
	{25., 0},
	{30000. / 1001., 1},
	{30., 1},
	{50., 1},
	{60000. / 1001., 1},
	{60., 1}
};

static char get_byte(int file, char *byte_value)
{
	return read(file, byte_value, 1);
}

static char get_int(int file, off_t offset, int *int_value)
{
	char a = 0, b = 0;

	lseek(file, offset, SEEK_SET);

	if( (get_byte(file, &a) != 1)  || (get_byte(file, &b) != 1) ) {
		*int_value = 0;
		return 0;
	}

	*int_value = (a * 256) + b;

	return 2;
}

mpeginfo_t *new_mpeg_info()
{
	mpeginfo_t *info;

	info = (mpeginfo_t *)malloc(sizeof(mpeginfo_t));

	info->width = 0;
	info->height = 0;
	info->frame_rate_index = 0;


	return info;
}

void delete_mpeg_info(mpeginfo_t *info)
{
	free(info);
}

int mpeg_get_width(mpeginfo_t *info)
{
	if ( !info ) {
		return 0;
	}

	return info->width;
}

int mpeg_get_height(mpeginfo_t *info)
{
	if ( !info ) {
		return 0;
	}

	return info->height;
}

int mpeg_get_rate_index(mpeginfo_t *info)
{
	if( !info ) {
		return 0;
	}

	return info->frame_rate_index;
}

mpeginfo_t *mpeg_get_info_fd(int mpeg_file)
{
	unsigned char frame_rate_index = 0;
	unsigned char byte;
	int hsize, vsize;
	off_t offset, old_offset;
	mpeginfo_t *info = NULL;

	if ( mpeg_file < 0 ) {
		return info;
	}

	old_offset = lseek(mpeg_file, 0, SEEK_CUR);

	while ( 1 ) {
		if ( get_byte(mpeg_file, &byte) != 1 ) {
			goto failure;
		}

		if ( byte != 0x00 ) {
			continue;
		}

		if ( get_byte(mpeg_file, &byte) != 1 ) {
			goto failure;
		}

		if ( byte != 0x00 ) {
			continue;
		}

		if ( get_byte(mpeg_file, &byte) != 1 ) {
			goto failure;
		}

		if ( byte != 0x01 ) {
			continue;
		}

		if ( get_byte(mpeg_file, &byte) != 1 ) {
			goto failure;
		}

		if ( byte == 0xB3 ) {
			break;
		}
	}

	offset = lseek(mpeg_file, 0, SEEK_CUR);

	if ( get_int(mpeg_file, offset, &hsize) != 2 ) {
		goto failure;
	}

	Dprintf(DEBUG, "HSize: (%u) %u\n", hsize, hsize >> 4);

	if ( get_int(mpeg_file, offset+1, &vsize) != 2 ) {
		goto failure;
	}

	Dprintf(DEBUG, "VSize: (%u) %u\n", vsize, vsize  & 0x0FFF);

	if ( get_byte(mpeg_file, &frame_rate_index) != 1 ) {
		goto failure;
	}

	frame_rate_index &= 0x0F;
	Dprintf(DEBUG, "Frame Rate Index: %u\n", frame_rate_index);
	if ( frame_rate_index > 8 ) {
		frame_rate_index = 0;
	}
	
	Dprintf(DEBUG, "Frame Rate: %g\n", rate_table[frame_rate_index].rate);

	info = new_mpeg_info();
	info->width = hsize;
	info->height= vsize;
	info->frame_rate_index = frame_rate_index;

failure:
	lseek(mpeg_file, old_offset, SEEK_SET);

	return info;
}

mpeginfo_t *mpeg_get_info_file(char *mpeg_filename)
{
	mpeginfo_t *info;
	int mpeg_file;

	mpeg_file = open(mpeg_filename, O_RDONLY);

	if ( mpeg_file < 0 ) {
		return NULL;
	}

	info = mpeg_get_info_fd(mpeg_file);

	close(mpeg_file);

	return info;
}


/*
 * Local Variables:
 *  indent-tabs-mode:nil
 *  require-final-newline:t
 *  c-basic-offset: 4
 * End:
 */
