/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#include "sys_inc.h"
#include "bs.h"
#include "h264.h"
#include "h264_util.h"


void h264_parser_init(h264_t * h)
{
	h->i_width = 0;
	h->i_height = 0;
	h->b_key = 0;

	h->i_nal_type = -1;
	h->i_ref_idc = -1;
	h->i_idr_pic_id = -1;
	h->i_frame_num = -1;
	h->i_log2_max_frame_num = 0;
	h->i_poc = -1;
	h->i_poc_type = -1; 
}

void h264_parser_parse(h264_t * h, nal_t * nal, int * pb_nal_start)
{
	bs_t s;

	*pb_nal_start = 0;

	if (nal->i_type == H264_NAL_SPS || nal->i_type == H264_NAL_PPS)
	{
		*pb_nal_start = 1;
    }
    
	bs_init(&s, nal->p_payload, nal->i_payload);

	if (nal->i_type == H264_NAL_SPS)
	{
		int i_tmp;

		i_tmp = bs_read(&s, 8);
		bs_skip(&s, 1+1+1 + 5 + 8);

		/* sps id */
		bs_read_ue(&s);

		if (i_tmp >= 100)
		{
			bs_read_ue(&s); // chroma_format_idc
			bs_read_ue(&s); // bit_depth_luma_minus8
			bs_read_ue(&s); // bit_depth_chroma_minus8
			bs_skip(&s, 1); // qpprime_y_zero_transform_bypass_flag

			if (bs_read(&s, 1)) // seq_scaling_matrix_present_flag
			{
				int i, j;
				
				for (i = 0; i < 8; i++)
				{
					if (bs_read(&s, 1)) // seq_scaling_list_present_flag[i]
					{
						uint8 i_tmp = 8;
						
						for (j = 0; j < (i<6?16:64); j++)
						{
							i_tmp += bs_read_se(&s);
							
							if (i_tmp == 0)
							{
								break;
							}	
						}
					}
				}
			}
		}

		/* Skip i_log2_max_frame_num */
		h->i_log2_max_frame_num = bs_read_ue(&s) + 4;

		/* Read poc_type */
		h->i_poc_type = bs_read_ue(&s);
		
		if (h->i_poc_type == 0)
		{
			h->i_log2_max_poc_lsb = bs_read_ue(&s) + 4;
		}
		else if (h->i_poc_type == 1)
		{
			int i_cycle;

			/* skip b_delta_pic_order_always_zero */
			bs_skip(&s, 1);

			/* skip i_offset_for_non_ref_pic */
			bs_read_se(&s);

			/* skip i_offset_for_top_to_bottom_field */
			bs_read_se(&s);

			/* read i_num_ref_frames_in_poc_cycle */
			i_cycle = bs_read_ue(&s); 
			if (i_cycle > 256)
			{
			    i_cycle = 256;
            }
            
			while (i_cycle > 0)
			{
				/* skip i_offset_for_ref_frame */
				bs_read_se(&s);
				i_cycle--;
			}
		}

		/* i_num_ref_frames */
		bs_read_ue(&s);

		/* b_gaps_in_frame_num_value_allowed */
		bs_skip(&s, 1);

		/* Read size */
		h->i_width  = 16 * (bs_read_ue( &s ) + 1);
		h->i_height = 16 * (bs_read_ue( &s ) + 1);

		/* b_frame_mbs_only */
		i_tmp = bs_read(&s, 1);
		if (i_tmp == 0)
		{
			bs_skip(&s, 1);
		}

		/* b_direct8x8_inference */
		bs_skip(&s, 1);

		/* crop ? */
		i_tmp = bs_read(&s, 1);
		if (i_tmp)
		{
			/* left */
			h->i_width -= 2 * bs_read_ue(&s);

			/* right */
			h->i_width -= 2 * bs_read_ue(&s);

			/* top */
			h->i_height -= 2 * bs_read_ue(&s);

			/* bottom */
			h->i_height -= 2 * bs_read_ue(&s);
		}
		/* vui: ignored */
	}
	else if (nal->i_type >= H264_NAL_SLICE && nal->i_type <= H264_NAL_IDR)
	{
		int i_tmp;

		/* i_first_mb */
		bs_read_ue(&s);

		/* picture type */
		switch (bs_read_ue(&s))
		{
		case 0: case 5: /* P */
		case 1: case 6: /* B */
		case 3: case 8: /* SP */
			h->b_key = 0;
			break;

		case 2: case 7: /* I */
		case 4: case 9: /* SI */
			h->b_key = (nal->i_type == H264_NAL_IDR);
			break;
		}

		/* pps id */
		bs_read_ue(&s);

		/* frame num */
		i_tmp = bs_read(&s, h->i_log2_max_frame_num);
		if (i_tmp != h->i_frame_num)
		{
			*pb_nal_start = 1;
        }
        
		h->i_frame_num = i_tmp;
		
		if (nal->i_type == H264_NAL_IDR)
		{
			i_tmp = bs_read_ue(&s);
			
			if (h->i_nal_type == H264_NAL_IDR && h->i_idr_pic_id != i_tmp)
			{
				*pb_nal_start = 1;
			}	

			h->i_idr_pic_id = i_tmp;
		}

		if (h->i_poc_type == 0)
		{
			i_tmp = bs_read(&s, h->i_log2_max_poc_lsb);
			if (i_tmp != h->i_poc)
			{
				*pb_nal_start = 1;
			}	

			h->i_poc = i_tmp;
		}
	}

	h->i_nal_type = nal->i_type;
	h->i_ref_idc = nal->i_ref_idc; 
}




