//
// C++ Implementation: Soften
//
// Description: 
//
// See .h file
//
// Author: mean <fixounet@free.fr>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//

//
//	This is the very unoptimized version
//	could use some stuff and some mmx too
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <assert.h>
#include <math.h>
#include <math.h>
#include <iconv.h>
#include "config.h"


#include "fourcc.h"
#include "avio.hxx"

#include "avi_vars.h"

#include "ADM_toolkit/toolkit.hxx"
#include "ADM_editor/ADM_edit.hxx"
#include "ADM_video/ADM_genvideo.hxx"

#include "ADM_toolkit/ADM_debugID.h"
#define MODULE_NAME MODULE_FILTER
#include "ADM_toolkit/ADM_debug.h"



#include "ADM_vidSoften.h"
#include "ADM_dialog/DIA_enter.h"

BUILD_CREATE(soften_create,ADMVideoMaskedSoften);

extern uint8_t distMatrix[256][256];
extern uint32_t fixMul[16];


uint8_t ADMVideoMaskedSoften::configure( AVDMGenericVideoStream *instream)
{
	_in=instream;
	int radius;
	
		radius=_param->radius;
		if(DIA_GetIntegerValue(&radius,2,60, "Radius","Radius:"))
			_param->radius=radius;
			
		radius=_param->luma;
		if(DIA_GetIntegerValue(&radius,0,255, "Luma Threshold","Luma Threshold:"))
			_param->luma=radius;
		
		radius=_param->chroma;
		if(DIA_GetIntegerValue(&radius,0,255, "Chroma Threshold","Chroma Threshold:"))
			_param->chroma=radius;
					
		
	return 1;	
 	
}
uint8_t	ADMVideoMaskedSoften::getCoupledConf( CONFcouple **couples)
{

			*couples=new CONFcouple(3);

			CSET(radius);
			CSET(luma);
			CSET(chroma);

		return 1;	
}
char *ADMVideoMaskedSoften::printConf( void )
{
 	static char buf[50];
 	
 	sprintf((char *)buf," Soften : radius: %lu l:%lu c:%lu\n", 
		_param->radius,_param->luma, _param->chroma);
        return buf;
}

ADMVideoMaskedSoften::~ADMVideoMaskedSoften()
{
	if(_uncompressed)
 		delete []_uncompressed;	
 	_uncompressed=NULL;
}


 ADMVideoMaskedSoften::ADMVideoMaskedSoften( AVDMGenericVideoStream *in,CONFcouple *couples)
{
		
		_uncompressed=NULL;
		_in=in;
		assert(in);
		if(!couples)
		{
			
			_param=NEW(MaskedSoften_CONF);
	    		_param->radius=3; 
	    		_param->luma=5;
			_param->chroma=5;
			
	    	}
		else
		{
			_param=NEW(MaskedSoften_CONF);
			GET(radius);
			GET(luma);
			GET(chroma);
			
						
		}
		assert(in);
		
		memcpy(&_info,_in->getInfo(),sizeof(_info));	
			    	
	    	_uncompressed=new uint8_t[3*_info.width*_info.height];	
		

}
uint8_t ADMVideoMaskedSoften::getFrameNumberNoAlloc(uint32_t frame,
							uint32_t *len,
							uint8_t *data,
							uint32_t *flags)
{
		uint32_t page=_info.width*_info.height;
		int32_t radius=_param->radius;
		uint32_t offset;
		
		int blockx,blocky;
		
		*len=(page*3)>>1;
		if(frame>=_info.nb_frames) return 0;		
		
				
		if(!_in->getFrameNumberNoAlloc(frame, len,_uncompressed,flags))
				 		return 0;

		// do luma only ATM
		// copy chroma
		memcpy(data+page,_uncompressed+page,page>>1);
		
		// for luma, the radius first lines /last lines are unchanged
		memcpy(data,_uncompressed,radius*_info.width);
		
		offset=page-_info.width*radius-1;
		
		memcpy(data+offset,
			_uncompressed+offset,
			radius*_info.width);

		uint8_t *src,*dst;
		uint32_t val,cur,coef;
		
		// We use a intermediate buffer to maximize cache
		// effectiveness
		// Each line is replaced by the oldest one
		//
		//	0	4
		//	1	1
		//	2  ->	2
		
		
		uint32_t modulo=0;
		uint32_t line=2*radius+1;
		
		uint8_t matrix[line][line];
		
		
		
		for(uint32_t x=radius;x<_info.width-radius;x++)
		{
			printf("X:%lu\n",x);
			src=_uncompressed+radius*_info.width+radius;
			dst=data+radius*_info.width+radius;
			for(uint32_t i=0;i<line;i++)
			{
				memcpy(matrix[i],_uncompressed+x-radius+i*_info.width,line);
			}
			modulo=0;
			for(uint32_t y=radius;y<_info.height-radius;y++)
			{
				uint8_t *cmp;
				coef=0;
				val=0;			
				cmp=matrix[0];
				for(blocky=line*line;blocky>0;blocky--)
				{
					cur=*cmp++;
					if( distMatrix[cur][*src]<=_param->luma)
					{
							coef++;
							val+=cur;
					}	
				}
				assert(coef);
				//printf("Coeff:%d\n",coef);
				val=(val+(coef>>1))/coef;
				*dst=val;
				dst+=_info.width;
				src+=_info.width;
				// replace the oldest line
				memcpy(matrix[modulo],
						_uncompressed+x-radius+
						(radius+y+1)*_info.width,
						line);
				modulo++;
				modulo%=line;
			}
		
		}
		//delete [] matrix;
			
	return 1;
}

