/* puthdr.c, generation of headers                                          */

/* 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 "mpeg2enc.h"


/* generate sequence header (6.2.2.1, 6.3.3)
 *
 * matrix download not implemented
 */

void 
MpegEncoder::putseqhdr()
{
	int i;

	alignbits();
	putbits(SEQ_START_CODE,32); /* sequence_header_code */
	putbits(m_horizontal_size,12); /* horizontal_size_value */
	putbits(m_vertical_size,12); /* vertical_size_value */
	putbits(m_aspectratio,4); /* aspect_ratio_information */
	putbits(m_frame_rate_code,4); /* frame_rate_code */
	putbits((int)ceil(m_bit_rate/400.0),18); /* bit_rate_value */
	putbits(1,1); /* marker_bit */
	putbits(m_vbv_buffer_size, 10); /* vbv_buffer_size_value */
	putbits(m_constrparms, 1); /* constrained_parameters_flag */

	putbits(m_load_iquant, 1); /* load_intra_quantizer_matrix */

	if (m_load_iquant)
	{
		for (i=0; i<64; i++)  /* matrices are always downloaded in zig-zag order */
		{
			putbits(m_intra_q[m_zig_zag_scan[i]],8); /* intra_quantizer_matrix */
		}
	}

	putbits(m_load_niquant,1); /* load_non_intra_quantizer_matrix */

	if (m_load_niquant)
	{
		for (i=0; i<64; i++)
		{
			putbits(m_inter_q[m_zig_zag_scan[i]],8); /*
													* non_intra_quantizer_matrix */
		}
	}
}

/* generate sequence extension (6.2.2.3, 6.3.5) header (MPEG-2 only) */

void 
MpegEncoder::putseqext()
{
	alignbits();
	putbits(EXT_START_CODE,32); /* extension_start_code */
	putbits(SEQ_ID,4); /* extension_start_code_identifier */
	putbits((m_profile << 4) | m_level, 8); /* profile_and_level_indication */
	putbits(m_prog_seq,1); /* progressive sequence */
	putbits(m_chroma_format,2); /* chroma_format */
	putbits(m_horizontal_size >> 12,2); /* horizontal_size_extension */
	putbits(m_vertical_size>>12,2); /* vertical_size_extension */
	putbits(((int)ceil(m_bit_rate/400.0))>>18,12); /* bit_rate_extension */
	putbits(1,1); /* marker_bit */
	putbits(m_vbv_buffer_size>>10,8); /* vbv_buffer_size_extension */
	putbits(0,1); /* low_delay  -- currently not implemented */
	putbits(0,2); /* frame_rate_extension_n */
	putbits(0,5); /* frame_rate_extension_d */
}

/* generate sequence display extension (6.2.2.4, 6.3.6)
 *
 * content not yet user setable
 */

void 
MpegEncoder::putseqdispext()
{
	alignbits();
	putbits(EXT_START_CODE,32); /* extension_start_code */
	putbits(DISP_ID,4); /* extension_start_code_identifier */
	putbits(m_video_format,3); /* video_format */
	putbits(1,1); /* colour_description */
	putbits(m_color_primaries,8); /* colour_primaries */
	putbits(m_transfer_characteristics,8); /* transfer_characteristics */
	putbits(m_matrix_coefficients,8); /* matrix_coefficients */
	putbits(m_display_horizontal_size, 14); /* display_horizontal_size */
	putbits(1,1); /* marker_bit */
	putbits(m_display_vertical_size, 14); /* display_vertical_size */
}

/* output a zero terminated string as user data (6.2.2.2.2, 6.3.4.1)
 *
 * string must not emulate start codes
 */
void 
MpegEncoder::putuserdata(char* userdata)
{
	alignbits();
	putbits(USER_START_CODE,32); /* user_data_start_code */
	while (*userdata)
		putbits(*userdata++,8);
}

/* generate group of pictures header (6.2.2.6, 6.3.9)
 *
 * uses tc0 (timecode of first frame) and frame0 (number of first frame)
 */

void 
MpegEncoder::putgophdr(int frame, int closed_gop)
{
	int tc;

	alignbits();
	putbits(GOP_START_CODE,32); /* group_start_code */
	tc = frametotc(m_tc0 + frame);
	putbits(tc,25); /* time_code */
	putbits(closed_gop,1); /* closed_gop */
	putbits(0,1); /* broken_link */
}

/* convert frame number to time_code
 *
 * drop_frame not implemented
 */

int 
MpegEncoder::frametotc(int frame)
{
	int fps, pict, sec, minute, hour, tc;

	fps = (int)(m_frame_rate + 0.5);
	pict = frame%fps;
	frame = (frame-pict)/fps;
	sec = frame%60;
	frame = (frame-sec)/60;
	minute = frame%60;
	frame = (frame-minute)/60;
	hour = frame%24;
	tc = (hour<<19) | (minute<<13) | (1<<12) | (sec<<6) | pict;

	return tc;
}

/* generate picture header (6.2.3, 6.3.10) */

void 
MpegEncoder::putpicthdr()
{
	alignbits();
	putbits(PICTURE_START_CODE,32); /* picture_start_code */
	calc_vbv_delay();
	putbits(m_temp_ref, 10); /* temporal_reference */
	putbits(m_pict_type, 3); /* picture_coding_type */
	putbits(m_vbv_delay, 16); /* vbv_delay */

	if (m_pict_type == P_TYPE || m_pict_type == B_TYPE)
	{
		putbits(0,1); /* full_pel_forward_vector */

		if (m_mpeg1)
		{
			putbits(m_forw_hor_f_code, 3);
		}
		else
		{
			putbits(7,3); /* forward_f_code */
		}
	}

	if (m_pict_type == B_TYPE)
	{
		putbits(0,1); /* full_pel_backward_vector */

		if (m_mpeg1)
		{
			putbits(m_back_hor_f_code, 3);
		}
		else
		{
			putbits(7,3); /* backward_f_code */
		}
	}

	putbits(0,1); /* extra_bit_picture */
}

/* generate picture coding extension (6.2.3.1, 6.3.11)
 *
 * composite display information (v_axis etc.) not implemented
 */

void 
MpegEncoder::putpictcodext()
{
	alignbits();
	putbits(EXT_START_CODE,32); /* extension_start_code */
	putbits(CODING_ID,4); /* extension_start_code_identifier */
	putbits(m_forw_hor_f_code, 4); /* forward_horizontal_f_code */
	putbits(m_forw_vert_f_code,4); /* forward_vertical_f_code */
	putbits(m_back_hor_f_code,4); /* backward_horizontal_f_code */
	putbits(m_back_vert_f_code,4); /* backward_vertical_f_code */
	putbits(m_dc_prec,2); /* intra_dc_precision */
	putbits(m_pict_struct,2); /* picture_structure */
	putbits((m_pict_struct == FRAME_PICTURE)? m_topfirst:0,1); /* top_field_first */
	putbits(m_frame_pred_dct, 1); /* frame_pred_frame_dct */
	putbits(0,1); /* concealment_motion_vectors  -- currently not implemented */
	putbits(m_q_scale_type, 1); /* q_scale_type */
	putbits(m_intravlc,1); /* intra_vlc_format */
	putbits(m_altscan,1); /* alternate_scan */
	putbits(m_repeatfirst,1); /* repeat_first_field */
	putbits(m_prog_frame,1); /* chroma_420_type */
	putbits(m_prog_frame,1); /* progressive_frame */
	putbits(0,1); /* composite_display_flag */
}

/* generate sequence_end_code (6.2.2) */
void 
MpegEncoder::putseqend()
{
	alignbits();
	putbits(SEQ_END_CODE,32);
}
