/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */

/*
 * Disclaimer of Warranty
 *
 * These software programs are available to the user without any license fee or
 * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
 * any and all warranties, whether express, implied, or statuary, including any
 * implied warranties or merchantability or of fitness for a particular
 * purpose.  In no event shall the copyright-holder be liable for any
 * incidental, punitive, or consequential damages of any kind whatsoever
 * arising from the use of these programs.
 *
 * This disclaimer of warranty extends to the user of these programs and user's
 * customers, employees, agents, transferees, successors, and assigns.
 *
 * The MPEG Software Simulation Group does not represent or warrant that the
 * programs furnished hereunder are free of infringement of any third-party
 * patents.
 *
 * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
 * are subject to royalty fees to patent holders.  Many of these patents are
 * general enough such that they are unavoidable regardless of implementation
 * design.
 *
 */

//#include "global.h"
#include "getbit.h"
#include "gethdr.h"
#include "store.h"


static char l_szBuffer[_MAX_PATH];

static double frame_rate_Table[16] = 
{
	0.0,
	((24.0*1000.0)/1001.0),
	24.0,
	25.0,
	((30.0*1000.0)/1001.0),
	30.0,
	50.0,
	((60.0*1000.0)/1001.0),
	60.0,

	-1,		// reserved
	-1,
	-1,
	-1,
	-1,
	-1,
	-1
};

static char *AspectRatio[5] = {
	"", "1 : 1", "4 : 3", "16 : 9", "2.21 : 1"
};

__forceinline static void group_of_pictures_header(void);
__forceinline static void picture_header(void);

static void sequence_extension(void);
static void sequence_display_extension(void);
static void quant_matrix_extension(void);
static void picture_display_extension(void);
static void picture_coding_extension(void);
static void copyright_extension(void);
static int  extra_bit_information(void);
static void extension_and_user_data(void);
static void Statistics(void);

/* decode headers from one input stream */
int Get_Hdr(void)
{
	for (;;)
	{
		/* look for next_start_code */
		next_start_code();

		switch (Get_Bits(32))
		{
			case SEQUENCE_HEADER_CODE:
				sequence_header();
				break;

			case GROUP_START_CODE:
				group_of_pictures_header();
				break;

			case PICTURE_START_CODE:
				picture_header();
				return 1;
		}
	}
}

/* decode sequence header */
void sequence_header(void)
{
	DVD_T("sequence_header");
	int constrained_parameters_flag;
	int bit_rate_value;
	int vbv_buffer_size;
	int i;

	g_PicInfo.horizontal_size             = Get_Bits(12);
	g_PicInfo.vertical_size               = Get_Bits(12);
	g_DVDGlobals.aspect_ratio_information    = Get_Bits(4);
	g_DVDGlobals.frame_rate_code             = Get_Bits(4);
	bit_rate_value              = Get_Bits(18);
	Flush_Buffer(1);	// marker bit
	vbv_buffer_size             = Get_Bits(10);
	constrained_parameters_flag = Get_Bits(1);

	if (g_DVDGlobals.load_intra_quantizer_matrix = Get_Bits(1))
	{
		for (i=0; i<64; i++)
			g_DVDGlobals.intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8);
	}
	else
	{
		for (i=0; i<64; i++)
			g_DVDGlobals.intra_quantizer_matrix[i] = default_intra_quantizer_matrix[i];
	}

	if (g_DVDGlobals.load_non_intra_quantizer_matrix = Get_Bits(1))
	{
		for (i=0; i<64; i++)
			g_DVDGlobals.non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8);
	}
	else
	{
		for (i=0; i<64; i++)
			g_DVDGlobals.non_intra_quantizer_matrix[i] = 16;
	}

	/* copy luminance to chrominance matrices */
	for (i=0; i<64; i++)
	{
		g_DVDGlobals.chroma_intra_quantizer_matrix[i] = g_DVDGlobals.intra_quantizer_matrix[i];
		g_DVDGlobals.chroma_non_intra_quantizer_matrix[i] = g_DVDGlobals.non_intra_quantizer_matrix[i];
	}
	extension_and_user_data();
}

/* decode group of pictures header */
/* ISO/IEC 13818-2 section 6.2.2.6 */
static void group_of_pictures_header(void)
{
	int gop_hour;
	int gop_minute;
	int gop_sec;
	int gop_frame;

	int drop_flag;
	int closed_gop;
	int broken_link;

	drop_flag   = Get_Bits(1);
	gop_hour    = Get_Bits(5);
	gop_minute  = Get_Bits(6);
	Flush_Buffer(1);	// marker bit
	gop_sec     = Get_Bits(6);
	gop_frame	= Get_Bits(6);
	closed_gop  = Get_Bits(1);
	broken_link = Get_Bits(1);

	extension_and_user_data();
}

/* decode picture header */
/* ISO/IEC 13818-2 section 6.2.3 */
static void picture_header(void)
{
	int vbv_delay;
	int full_pel_forward_vector;
	int forward_f_code;
	int full_pel_backward_vector;
	int backward_f_code;
	int Extra_Information_Byte_Count;

	g_DVDGlobals.temporal_reference  = Get_Bits(10);
	g_DVDGlobals.picture_coding_type = Get_Bits(3);

	g_DVDGlobals.d2v_current.type = g_DVDGlobals.picture_coding_type;

	if (g_DVDGlobals.d2v_current.type==I_TYPE)
	{
		g_DVDGlobals.d2v_current.file = process.startfile = g_Flags.File_Flag;
		process.startloc = _telli64(g_DVDGlobals.Infile[g_Flags.File_Flag]);
		g_InfoFunctions.TrackProgress((int)((process.run+process.startloc)*TRACK_PITCH/process.total));

		g_DVDGlobals.d2v_current.lba = process.startloc/BUFFER_SIZE - 2;

		if (g_DVDGlobals.d2v_current.lba < 0)
		{
			if (g_DVDGlobals.d2v_current.file > 0)
			{
				g_DVDGlobals.d2v_current.file --;
				g_DVDGlobals.d2v_current.lba = process.length[g_DVDGlobals.d2v_current.file]/BUFFER_SIZE - 1;
			}
			else
				g_DVDGlobals.d2v_current.lba = 0;
		}

		if (process.locate==LOCATE_RIP)
		{
			process.file = g_DVDGlobals.d2v_current.file;
			process.lba = g_DVDGlobals.d2v_current.lba;
		}

		if (g_Flags.File_Flag==process.endfile && process.startloc>=process.endloc)		// D2V END
		{
			g_Flags.Fault_Flag = 97;
			Write_Frame(NULL, g_DVDGlobals.d2v_current, 0);
		}

		if (g_Flags.Statistics_Flag)
			Statistics();
	}

	vbv_delay = Get_Bits(16);

	if (g_DVDGlobals.picture_coding_type==P_TYPE || g_DVDGlobals.picture_coding_type==B_TYPE)
	{
		full_pel_forward_vector = Get_Bits(1);
		forward_f_code = Get_Bits(3);
	}

	if (g_DVDGlobals.picture_coding_type==B_TYPE)
	{
		full_pel_backward_vector = Get_Bits(1);
		backward_f_code = Get_Bits(3);
	}

	Extra_Information_Byte_Count = extra_bit_information();
	extension_and_user_data();
}

/* decode slice header */
/* ISO/IEC 13818-2 section 6.2.4 */
int slice_header(void)
{
	int slice_vertical_position_extension;
	int quantizer_scale_code;
	int slice_picture_id_enable = 0;
	int slice_picture_id = 0;
	int extra_information_slice = 0;

	slice_vertical_position_extension = g_PicInfo.vertical_size>2800 ? Get_Bits(3) : 0;

	quantizer_scale_code = Get_Bits(5);
	g_DVDGlobals.quantizer_scale = g_DVDGlobals.q_scale_type ? Non_Linear_quantizer_scale[quantizer_scale_code] : quantizer_scale_code<<1;

	/* slice_id introduced in March 1995 as part of the video corridendum
	   (after the IS was drafted in November 1994) */
	if (Get_Bits(1))
	{
		Get_Bits(1);	// intra slice

		slice_picture_id_enable = Get_Bits(1);
		slice_picture_id = Get_Bits(6);

		extra_information_slice = extra_bit_information();
	}

	return slice_vertical_position_extension;
}

/* decode extension and user data */
/* ISO/IEC 13818-2 section 6.2.2.2 */
static void extension_and_user_data(void)
{
	int code, ext_ID;

	next_start_code();

	while ((code = Show_Bits(32))==EXTENSION_START_CODE || code==USER_DATA_START_CODE)
	{
		if (code==EXTENSION_START_CODE)
		{
			Flush_Buffer(32);
			ext_ID = Get_Bits(4);

			switch (ext_ID)
			{
				case SEQUENCE_EXTENSION_ID:
					sequence_extension();
					break;
				case SEQUENCE_DISPLAY_EXTENSION_ID:
					sequence_display_extension();
					break;
				case QUANT_MATRIX_EXTENSION_ID:
					quant_matrix_extension();
					break;
				case PICTURE_DISPLAY_EXTENSION_ID:
					picture_display_extension();
					break;
				case PICTURE_CODING_EXTENSION_ID:
					picture_coding_extension();
					break;
				case COPYRIGHT_EXTENSION_ID:
					copyright_extension();
					break;
			}
			next_start_code();
		}
		else
		{
			Flush_Buffer(32);	// ISO/IEC 13818-2  sections 6.3.4.1 and 6.2.2.2.2
			next_start_code();	// skip user data
		}
	}
}

/* decode sequence extension */
/* ISO/IEC 13818-2 section 6.2.2.3 */
static void sequence_extension(void)
{
	int profile_and_level_indication;
	int low_delay;
	int frame_rate_extension_n;
	int frame_rate_extension_d;

	int horizontal_size_extension;
	int vertical_size_extension;
	int bit_rate_extension;
	int vbv_buffer_size_extension;

	profile_and_level_indication = Get_Bits(8);
	g_DVDGlobals.progressive_sequence         = Get_Bits(1);
	g_DVDGlobals.chroma_format                = Get_Bits(2);
	horizontal_size_extension    = Get_Bits(2);
	vertical_size_extension      = Get_Bits(2);
	bit_rate_extension           = Get_Bits(12);
	Flush_Buffer(1);	// marker bit
	vbv_buffer_size_extension    = Get_Bits(8);
	low_delay                    = Get_Bits(1);
 
	frame_rate_extension_n       = Get_Bits(2);
	frame_rate_extension_d       = Get_Bits(5);
	g_DVDGlobals.frame_rate = (float)(frame_rate_Table[g_DVDGlobals.frame_rate_code] * (frame_rate_extension_n+1)/(frame_rate_extension_d+1));

	g_PicInfo.horizontal_size = (horizontal_size_extension<<12) | (g_PicInfo.horizontal_size&0x0fff);
	g_PicInfo.vertical_size = (vertical_size_extension<<12) | (g_PicInfo.vertical_size&0x0fff);
}

/* decode sequence display extension */
static void sequence_display_extension(void)
{
	int video_format;  
	int color_description;
	int color_primaries;
	int transfer_characteristics;
	int matrix_coefficients;
	int display_horizontal_size;
	int display_vertical_size;

	video_format      = Get_Bits(3);
	color_description = Get_Bits(1);

	if (color_description)
	{
		color_primaries          = Get_Bits(8);
		transfer_characteristics = Get_Bits(8);
		matrix_coefficients      = Get_Bits(8);
	}

	display_horizontal_size = Get_Bits(14);
	Flush_Buffer(1);	// marker bit
	display_vertical_size   = Get_Bits(14);
}

/* decode quant matrix entension */
/* ISO/IEC 13818-2 section 6.2.3.2 */
static void quant_matrix_extension(void)
{
	int i;

	if (g_DVDGlobals.load_intra_quantizer_matrix = Get_Bits(1))
		for (i=0; i<64; i++)
			g_DVDGlobals.chroma_intra_quantizer_matrix[scan[ZIG_ZAG][i]]
				= g_DVDGlobals.intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8);

	if (g_DVDGlobals.load_non_intra_quantizer_matrix = Get_Bits(1))
		for (i=0; i<64; i++)
			g_DVDGlobals.chroma_non_intra_quantizer_matrix[scan[ZIG_ZAG][i]]
				= g_DVDGlobals.non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8);

	if (g_DVDGlobals.load_chroma_intra_quantizer_matrix = Get_Bits(1))
		for (i=0; i<64; i++)
			g_DVDGlobals.chroma_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8);

	if (g_DVDGlobals.load_chroma_non_intra_quantizer_matrix = Get_Bits(1))
		for (i=0; i<64; i++)
			g_DVDGlobals.chroma_non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8);
}

/* decode picture display extension */
/* ISO/IEC 13818-2 section 6.2.3.3. */
static void picture_display_extension(void)
{
	int frame_center_horizontal_offset[3];
	int frame_center_vertical_offset[3];

	int i;
	int number_of_frame_center_offsets;

	/* based on ISO/IEC 13818-2 section 6.3.12 
	   (November 1994) Picture display extensions */

	/* derive number_of_frame_center_offsets */
	if (g_DVDGlobals.progressive_sequence)
	{
		if (g_PicInfo.repeat_first_field)
		{
			if (g_PicInfo.top_field_first)
				number_of_frame_center_offsets = 3;
			else
				number_of_frame_center_offsets = 2;
		}
		else
			number_of_frame_center_offsets = 1;
	}
	else
	{
		if (g_PicInfo.picture_structure!=FRAME_PICTURE)
			number_of_frame_center_offsets = 1;
		else
		{
			if (g_PicInfo.repeat_first_field)
				number_of_frame_center_offsets = 3;
			else
				number_of_frame_center_offsets = 2;
		}
	}

	/* now parse */
	for (i=0; i<number_of_frame_center_offsets; i++)
	{
		frame_center_horizontal_offset[i] = Get_Bits(16);
		Flush_Buffer(1);	// marker bit

		frame_center_vertical_offset[i] = Get_Bits(16);
		Flush_Buffer(1);	// marker bit
	}
}

/* decode picture coding extension */
static void picture_coding_extension(void)
{
	int chroma_420_type;
	int composite_display_flag;
	int v_axis;
	int field_sequence;
	int sub_carrier;
	int burst_amplitude;
	int sub_carrier_phase;

	g_PicInfo.f_code[0][0] = Get_Bits(4);
	g_PicInfo.f_code[0][1] = Get_Bits(4);
	g_PicInfo.f_code[1][0] = Get_Bits(4);
	g_PicInfo.f_code[1][1] = Get_Bits(4);

	g_PicInfo.intra_dc_precision			= Get_Bits(2);
	g_PicInfo.picture_structure			= Get_Bits(2);
	g_PicInfo.top_field_first				= Get_Bits(1);
	g_PicInfo.frame_pred_frame_dct		= Get_Bits(1);
	g_PicInfo.concealment_motion_vectors	= Get_Bits(1);
	g_DVDGlobals.q_scale_type				= Get_Bits(1);
	g_PicInfo.intra_vlc_format			= Get_Bits(1);
	g_DVDGlobals.alternate_scan				= Get_Bits(1);
	g_PicInfo.repeat_first_field			= Get_Bits(1);
	chroma_420_type				= Get_Bits(1);
	g_PicInfo.progressive_frame			= Get_Bits(1);
	composite_display_flag		= Get_Bits(1);

	g_DVDGlobals.d2v_current.pf = g_PicInfo.progressive_frame;
	g_DVDGlobals.d2v_current.trf = (g_PicInfo.top_field_first<<1) + g_PicInfo.repeat_first_field;

	if (composite_display_flag)
	{
		v_axis            = Get_Bits(1);
		field_sequence    = Get_Bits(3);
		sub_carrier       = Get_Bits(1);
		burst_amplitude   = Get_Bits(7);
		sub_carrier_phase = Get_Bits(8);
	}
}

/* decode extra bit information */
/* ISO/IEC 13818-2 section 6.2.3.4. */
static int extra_bit_information(void)
{
	int Byte_Count = 0;

	while (Get_Bits(1))
	{
		Flush_Buffer(8);
		Byte_Count++;
	}

	return Byte_Count;
}

/* Copyright extension */
/* ISO/IEC 13818-2 section 6.2.3.6. */
/* (header added in November, 1994 to the IS document) */
static void copyright_extension(void)
{
	int copyright_flag;
	int copyright_identifier;
	int original_or_copy;
	int copyright_number_1;
	int copyright_number_2;
	int copyright_number_3;

	int reserved_data;

	copyright_flag =       Get_Bits(1); 
	copyright_identifier = Get_Bits(8);
	original_or_copy =     Get_Bits(1);
  
	/* reserved */
	reserved_data = Get_Bits(7);

	Flush_Buffer(1); // marker bit
	copyright_number_1 =   Get_Bits(20);
	Flush_Buffer(1); // marker bit
	copyright_number_2 =   Get_Bits(22);
	Flush_Buffer(1); // marker bit
	copyright_number_3 =   Get_Bits(22);
}

static void Statistics(void)
{
#if 0
	static int Old_NTSC_Purity;
	int pts;

	sprintf(l_szBuffer, "%s", AspectRatio[g_DVDGlobals.aspect_ratio_information]);
	g_InfoFunctions.AspectRatio(l_szBuffer);

	sprintf(l_szBuffer, "%.3f fps", g_DVDGlobals.Frame_Rate);
	g_InfoFunctions.FrameRate(l_szBuffer);

	if (g_Flags.Track_Flag!=TRACK_NONE)
	{
		switch (g_DVDGlobals.CH[g_Flags.Track_Flag])
		{
			case FORMAT_AC3:
				sprintf(l_szBuffer, "DD %s %d", AC3Mode[g_DVDGlobals.ac3[g_Flags.Track_Flag].mode], AC3Rate[g_DVDGlobals.ac3[g_Flags.Track_Flag].rate]);
				g_InfoFunctions.AudioType(l_szBuffer);
				break;

			case FORMAT_MPA:
				g_InfoFunctions.AudioType("MPEG Audio");
				break;

			case FORMAT_LPCM:
				g_InfoFunctions.AudioType("Linear PCM");
				break;

			case FORMAT_DTS:
				g_InfoFunctions.AudioType("DTS");
				break;

			default:
				g_InfoFunctions.AudioType("UNKNOWN");
				break;
		}
	}
	else
		g_InfoFunctions.AudioType("NONE");

	if (g_Flags.SystemStream_Flag && process.locate!=LOCATE_INIT)
	{
		pts = g_PicInfo.AudioPTS/90000;
		sprintf(l_szBuffer, "%d:%02d:%02d", pts/3600, (pts%3600)/60, pts%60);
		g_InfoFunctions.TimeStamp(l_szBuffer);
	}
	else
		g_InfoFunctions.TimeStamp("");

	if (process.locate==LOCATE_RIP)
	{
		if (g_DVDGlobals.NTSC_Purity || g_DVDGlobals.FILM_Purity)
		{
			if (!g_DVDGlobals.FILM_Purity)
			{
				if (g_DVDGlobals.frame_rate==25)
					sprintf(l_szBuffer, "PAL");
				else
					sprintf(l_szBuffer, "NTSC");
			}
			else if (!g_DVDGlobals.NTSC_Purity)
				sprintf(l_szBuffer, "FILM");
			else if (g_DVDGlobals.NTSC_Purity > Old_NTSC_Purity)
				sprintf(l_szBuffer, "NTSC %2d %%", 100 - (g_DVDGlobals.FILM_Purity*100)/(g_DVDGlobals.FILM_Purity+g_DVDGlobals.NTSC_Purity));
			else
				sprintf(l_szBuffer, "FILM %2d %%", (g_DVDGlobals.FILM_Purity*100)/(g_DVDGlobals.FILM_Purity+g_DVDGlobals.NTSC_Purity));

			Old_NTSC_Purity = g_DVDGlobals.NTSC_Purity;
			g_InfoFunctions.VideoType(l_szBuffer);
		}

		if (process.op)
		{
			process.ed = timeGetTime();
			process.elapsedMs = process.ed-process.op;
			process.elapsed = process.elapsedMs/1000;
			process.percent = (float)(100.0*(process.run-process.start+_telli64(g_DVDGlobals.Infile[g_Flags.File_Flag]))/(process.end-process.start));
			process.remain = (int)(process.elapsedMs*(100.0-process.percent)/process.percent)/1000;

			sprintf(l_szBuffer, "%d:%02d:%02d", process.elapsed/3600, (process.elapsed%3600)/60, process.elapsed%60);
			g_InfoFunctions.Elapsed(l_szBuffer);

			sprintf(l_szBuffer, "%d:%02d:%02d", process.remain/3600, (process.remain%3600)/60, process.remain%60);
			g_InfoFunctions.Remain(l_szBuffer);

			if (g_Flags.AVI_Flag)
			{
				sprintf(l_szBuffer, "%.1f Mb", ((double)g_PicInfo.avi_size)/1024.0/1024.0);
				g_InfoFunctions.FileSize(l_szBuffer);
				
				if (g_PicInfo.avi_size && g_PicInfo.frame_count)
				{
					sprintf(l_szBuffer, "%.0f kbps", (double)((((double)g_PicInfo.avi_size / (double)g_PicInfo.frame_count) * ((double)g_DVDGlobals.Frame_Rate) * 8.0) / 1000.0));
					g_InfoFunctions.FileAvgBitRate( l_szBuffer);
					
					if (g_PicInfo.kframe_count)
					{
						sprintf(l_szBuffer, "1:%d", g_PicInfo.frame_count/g_PicInfo.kframe_count);
						g_InfoFunctions.FileKFRatio( l_szBuffer);
					}
					else
						g_InfoFunctions.FileKFRatio( "N/A");
					
					sprintf(l_szBuffer, "%.2f b/p", (double)((((double)g_PicInfo.avi_size / (double)g_PicInfo.frame_count) * 8.0)/ (double)g_PicInfo.Resize_Width) / (double)g_PicInfo.Resize_Height);
					g_InfoFunctions.FileAvgRes(l_szBuffer);
					
					if (process.percent)
					{
						sprintf(l_szBuffer, "%.1f Mb", (((double)g_PicInfo.avi_size)/1024.0/1024.0) / (((double)process.percent)/100.0)); 
						g_InfoFunctions.FileEstSize( l_szBuffer);
					}
				}
				
				if (process.elapsedMs)
				{
					sprintf(l_szBuffer, "%.1f fps", (double)(1000*g_PicInfo.frame_count) / (double)process.elapsedMs);
					g_InfoFunctions.AvgFPS ( l_szBuffer);
				}
			}
		}
	}
#endif
}
