/********************************************************************************
 *																				*
 * 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):													*
 *		- Heavily modified and optimized code + MIPS ASM						*
 *																				*
 ********************************************************************************/


// INCLUDE

#include "global.h"
#include "../decore.h"


// FUNCTION DECLARATIONS

extern void IVOP_macroblock();
extern void PVOP_macroblock();

unsigned char Decode_MPEG4_Picture (unsigned char *Frame_Buffer, unsigned char Render_Flag);
static void make_edge (unsigned char *frame_pic, int width, int height, int edge);
static void PictureDisplay(unsigned char *bmp);
static void Decode_I_Frame(unsigned char *Frame_Buffer);
static void Decode_P_Frame(unsigned char *Frame_Buffer);

#ifdef MIPS_ASM_64
	#include "MIPS_functions.c"
#endif

// Purpose: decode and display a Vop

unsigned char Decode_MPEG4_Picture(unsigned char *Frame_Buffer, unsigned char Render_Flag)
{

	mp4_hdr.mba = 0;
	mp4_hdr.mb_xpos = 0;
	mp4_hdr.mb_ypos = 0;
	
	switch (mp4_hdr.prediction_type) {

		case I_VOP: 
			Decode_I_Frame(Frame_Buffer);
			break;
		case P_VOP: 
			Decode_P_Frame(Frame_Buffer);
			break;
		case B_VOP:
			return 1;
		default:                
			break;
	}
	
	return 0;
}

static void Decode_I_Frame(unsigned char *Frame_Buffer) 
{
	#ifdef MIPS_ASM_64
	CPU_64_on();
	#endif

	do {
		IVOP_macroblock();
		mp4_hdr.mba++; 
	} while ((nextbits_bytealigned(23)) && (mp4_hdr.mba < mp4_hdr.mba_size));

	#ifdef MIPS_ASM_64
	CPU_64_off();
	#endif

	mp4_hdr.last_prediction_type=mp4_hdr.prediction_type;

	PictureDisplay(Frame_Buffer);
}
	
static void Decode_P_Frame(unsigned char *Frame_Buffer) 
{
	// exchange ref and for frames
	unsigned char i;
	unsigned char *tmp;
	for (i = 0; i < 3; i++) {
		tmp = frame_ref[i];
		frame_ref[i] = frame_for[i];
		frame_for[i] = tmp;
	}
	
	#ifdef MIPS_ASM_64
	CPU_64_on();
	#endif

	// add edge to decoded frame
		
	make_edge (frame_for[0], mp4_hdr.coded_picture_width, mp4_hdr.coded_picture_height, 32);
	make_edge (frame_for[1], mp4_hdr.coded_picture_width>>1, mp4_hdr.coded_picture_height>>1, 16);
	make_edge (frame_for[2], mp4_hdr.coded_picture_width>>1, mp4_hdr.coded_picture_height>>1, 16);

	// macroblock reconstruction

	do {
		PVOP_macroblock();
		mp4_hdr.mba++; 
	} while ((nextbits_bytealigned(23)) && (mp4_hdr.mba < mp4_hdr.mba_size));

	#ifdef MIPS_ASM_64
	CPU_64_off();
	#endif

	mp4_hdr.last_prediction_type=mp4_hdr.prediction_type;
	
	PictureDisplay(Frame_Buffer);
}

static void make_edge (unsigned char *frame_pic,
                int edged_width, int edged_height, int edge)
{
	int j;

	int width = edged_width - (edge<<1);
	int height = edged_height - (edge<<1);
	unsigned char *p_border;
	
	// left and right edges
	
	p_border = frame_pic;

	for (j = height;j!=0 ;j--)
	{

		#ifdef MIPS_ASM_64

		MIPS_MEM_SET((p_border - edge), *(p_border), edge);
		MIPS_MEM_SET((p_border + width),*(p_border + (width-1)), edge);

		#else

		memset((p_border - edge), *(p_border), edge);
		memset((p_border + width),*(p_border + (width-1)), edge);

		#endif

		p_border += edged_width;
	}

	// top edge
	p_border = frame_pic-edge;
	for (j = edge;j>0; j--)
	{
		#ifdef MIPS_ASM_64
		MIPS_edge_copy(p_border-edged_width, p_border, edged_width);
		#else
		memcpy(p_border-edged_width, p_border, edged_width);
		#endif
		p_border-=edged_width;
	}

	// bottom edge

	p_border = frame_pic-edge+(edged_width*(height-1));
	
	for (j = edge;j>0; j--)
	{
		#ifdef MIPS_ASM_64
		MIPS_edge_copy(p_border+edged_width, p_border, edged_width);
		#else
		memcpy(p_border+edged_width, p_border, edged_width);
		#endif
		p_border+=edged_width;
	}
	
}
/**/

// Purpose: manages a one frame buffer for re-ordering frames prior to 
// displaying or writing to a file

static void PictureDisplay(unsigned char *bmp)
{ 
	AVPicture * p=(AVPicture *) bmp;
	p->data[0]=frame_ref[0];
	p->data[1]=frame_ref[1];
	p->data[2]=frame_ref[2];
	p->linesize[0]=mp4_hdr.coded_picture_width;
	p->linesize[1]=mp4_hdr.coded_picture_width>>1;
	p->linesize[2]=mp4_hdr.coded_picture_width>>1;
#ifdef ARM
	p->last_picture[0]=frame_for[0];
	p->last_picture[1]=frame_for[1];
	p->last_picture[2]=frame_for[2];
#endif

}
