/********************************************************************************
 *																				*
 * This code has been developed by Project Mayo. This software is an			*
 * implementation of a part of one or more MPEG-4 Video tools as				*
 * specified in ISO/IEC 14496-2 standard.  Those intending to use this			*
 * software module in hardware or software products are advised that its		*
 * use may infringe existing patents or copyrights, and any such use			*
 * would be at such party's own risk.  The original developer of this			*
 * software module and his/her company, and subsequent editors and their		*
 * companies (including Project Mayo), will have no liability for use of		*
 * this software or modifications or derivatives thereof.						*
 *																				*
 ********************************************************************************
 *																				*	
 * This program is free software; you can redistribute it and/or modify			*
 * it under the terms of the GNU General Public License as published by			*
 * the Free Software Foundation; either version 2 of the License, or			*
 * (at your option) any later version.											*
 *																				*
 * The GPL can be found at: http://www.gnu.org/copyleft/gpl.html				*
 *																				*
 * Authors:																		*
 *																				*
 *	Andrea	Graziani	(Ag):													*
 *		- Original source code (Open Divx Decoder 0.4a).						*		
 *																				*
 *	Marc	Dukette		(Md) and												*
 *	Pedro	Mateu		(Pm):													*
 *		- Optimized code					 									*
 *																				*
 ********************************************************************************/

// mp4_header.c //

#include "global.h"
#include "mp4_header.h"

void next_start_code();

/**/

static Log_2(unsigned int data)
{
	unsigned int i = 0;
	while (data!=0) {
		data >>= 1;
		i++;
	}
    return i;
}

int getvolhdr()
{
	if (showbits(27) == VO_START_CODE)
	{
		int visual_object_layer_verid;
		int is_object_layer_identifier;
		flushbits(73); // start_code + vo_id + vol_id +...
		
		is_object_layer_identifier = getbits1();
		if (is_object_layer_identifier) {
			visual_object_layer_verid = getbits(4);
			flushbits(7);
		} 
		else {
			visual_object_layer_verid = 1;
			flushbits(4);
		}
		if (getbits1())
		{
			flushbits(3);
			if (getbits1())
			{
				flushbits(79);
			}
		}
		flushbits(3);
		mp4_hdr.time_increment_resolution = getbits(16);
		flushbits(1); // marker
		if (getbits1()) { //fixed_vop_rate
			int bits = Log_2(mp4_hdr.time_increment_resolution);
			if (bits < 1) bits = 1;
			flushbits(bits);
		}

		flushbits(1); // marker
		mp4_hdr.width = getbits(13);
		flushbits(1); // marker
		mp4_hdr.height = getbits(13);
		flushbits(3); // marker + interlaced + obmc_disable
		if (visual_object_layer_verid == 1) {
			flushbits(1);
		} 
		else {
			flushbits(2);
		}
			
		if (getbits1() == 1) 
		{
			mp4_hdr.quant_precision = getbits(4);
			flushbits(5);
		}
		else 
		{
			mp4_hdr.quant_precision = 5;
			flushbits(1); // quant type
		}

		if (visual_object_layer_verid/*ident*/ != 1) {
			flushbits(1);
		} 

		flushbits(4);

  	return 1;
  }
  
  return 0; // no VO start code
}

/**/

int getvophdr()
{
	next_start_code();
	while (showbits(32) != (int) VOP_START_CODE)
	{
		flushbits(8);
		next_start_code();
	}
	flushbits(32);
	mp4_hdr.prediction_type = getbits(2);
	if (mp4_hdr.prediction_type == B_VOP)
	{	
		mp4_hdr.last_prediction_type=mp4_hdr.prediction_type;
		return 0;
	}
	while (getbits1() == 1); // temporal time base
	{
		int bits = Log_2(mp4_hdr.time_increment_resolution);
		if (bits < 1) bits = 1;
		flushbits(bits+2);
	}
	if (getbits1() == 0) 
	{
		//next_start_code();
		return 0;
	}  

	if (mp4_hdr.prediction_type == P_VOP)
	{
		mp4_hdr.rounding_type = getbits1();
	} 

	flushbits(3);// intra_dc_vlc_thr
	mp4_hdr.quantizer = getbits(mp4_hdr.quant_precision); // vop quant

	if (mp4_hdr.prediction_type != I_VOP) 
	{
		mp4_hdr.fcode_for = getbits(3); 
	}
		
	return 1;
}

// Purpose: look nbit forward for an alignement
int bytealigned(int nbit) 
{
	return (!((ld.bitcnt + nbit)<<29));
}

int bytealigned0() 
{
	return (!(ld.bitcnt << 29));
}
/**/

void next_start_code()
{
	if (!bytealigned0())
	{
		flushbits((8-(ld.bitcnt&(0x7))));

	}
}

/**/

int nextbits_bytealigned(int nbit)
{
	int code;
	int skipcnt = 0;
	if (bytealigned0())
	{
		// stuffing bits
 		if (showbits(8) == 127) {
			skipcnt += 8;
		}
	}
	else
	{
		// bytealign
		while (! bytealigned(skipcnt)) {
			skipcnt += 1;
		}
	}
	code = showbits(nbit + skipcnt);
	return ((code << skipcnt) >> skipcnt);
}
