// avi.cpp: implementation of the CMyAvi class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "extractor.h"
#include "avi.h"
#include "direct.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define DISTANCE(a,b) (a>b)?(a-b):(b-a)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//Construct a CMyAvi object
CMyAvi::CMyAvi()
{
	::AVIFileInit();
	m_wWidth=0;
	m_wHeight=0;

	this->m_pBmpData=NULL;
	this->m_pAviFileInfo=NULL;
	this->m_byFilterType=0;
	this->m_byIFrameType=1;
	this->m_nPixelThreshold=20;
	this->m_fIFrameThresdRelative=1.0;

	this->m_byPFrameType=0;
	this->m_byIFrameType=1;
	this->m_iMaxIFrameInterval=100;
	this->m_iProbeInterval=10;
	this->m_byRunningProbeFlag=0;
	this->m_wPFrameThreshold=15;
}

//destroy a CMyAvi object 
CMyAvi::~CMyAvi()
{
	if(m_wWidth!=0)
		::AVIFileExit();

	if(this->m_pAviFileInfo!=NULL)
		delete this->m_pAviFileInfo;
	this->m_pAviFileInfo=NULL;
}

//doing this function after CAviCreate();
//main process to comparing every 2 frames, and show the rate of  process.
BOOL CMyAvi::AviProcess(CWnd *pFrame)
{
	CDialog dlgError;
	long lResult;
	DWORD i;
	byte byFrameType,ZERO=0;
	
	//showing the file's name.
	pFrame->SetWindowText(this->m_AviStreamInfo.szName);

	InitCompare();  //creating inf file and recording AviFileInfo, 
					//the file type of I/P frame, as well as the first frame.

//////comparing every 2 adjecent pics
	int iFrameNum=0;
	for(i=0;i<m_pAviFileInfo->dwLength-1;i++)
	{
		// using Probe
		if(m_iProbeInterval>0&&(i%m_iProbeInterval)==0&&(i+m_iProbeInterval)<m_pAviFileInfo->dwLength)
		{

			m_byRunningProbeFlag=1;

			if(m_lpBMPInfoHeader2->biBitCount==24)
				lResult=Compare2Frame_24(i,i+m_iProbeInterval);
			else
				lResult=Compare2Frame(i,i+m_iProbeInterval);

			m_byRunningProbeFlag=0;

			if(lResult==0)			//there are no difference 
									//between current frame and the 10-later frame.
			{
				for(int j=0; j<m_iProbeInterval; j++)
					m_fileInf.Write(&ZERO, 1);			
											//consider these 10 frames are all 0-frame.
				i=i+m_iProbeInterval-1;		//because i++ will occure at circulation end.
				continue;
			}
			
		}

		//probe not used.   compare 2 adjecent frames.
		iFrameNum++;

		//if the frame number achieves max Iframe interval, it should return a I-frame.
		if(m_iMaxIFrameInterval > 0 && iFrameNum == m_iMaxIFrameInterval)
		{
			lResult=-1;
		}
		else
		{
			if(m_lpBMPInfoHeader2->biBitCount == 24)
				lResult=Compare2Frame_24(i,i+1);
			else
				lResult=Compare2Frame(i,i+1);
		}

		if(lResult>m_lIFrameThreshold || lResult==-1)   // the differenc is too large, that they are 2 different pics
		{
			if(this->m_byIFrameType==BMP)
				this->WriteBmpFile(i+1);
			if(this->m_byIFrameType==PNG)
				this->WritePngFile(i+1);
			if(this->m_byIFrameType==JPEG)
				this->WriteJpegFile(i+1);
			
			byFrameType=IFRAME;		//I-frame;

			iFrameNum=0;		//reset the counter of frame.
		}
		else if(lResult == 0)
			byFrameType=OFRAME;		//0-frame;
		else
			byFrameType=PFRAME;		//P-frame;

		m_fileInf.Write(&byFrameType, 1);		//recording the frame type for every one.

		//showing some information of the rate of the process.
		if (pFrame)
			pFrame->SendMessage(MYWM_PROGRESS, i*100/(m_pAviFileInfo->dwLength-1));  // message to the process bar
		CString strProcessInfo;
		strProcessInfo.Format("%s\t      %d%% is done",m_AviStreamInfo.szName,i*100/(m_pAviFileInfo->dwLength-1));
		pFrame->SetWindowText(strProcessInfo);
	}

	m_fileInf.Close();

	//showing some information of the rate of the process.
	CString strFinishInfo;
	strFinishInfo.Format("%s\t      %d%% is done",m_AviStreamInfo.szName,i*100/(m_pAviFileInfo->dwLength-1));
	pFrame->SetWindowText(strFinishInfo);

	pFrame->SendMessage(MYWM_PROGRESS,0);
	pFrame->Invalidate();

	return TRUE;
}

//open an avi file according to the name, and get the information of its stream
void CMyAvi::AviInit(CString strFileName)
{
	HRESULT hr;
	CDialog dlgError;

 	//open the avi file,  
	this->m_pAviFileInfo=new AVIFILEINFO;
	hr = AVIFileOpen(&m_pAviFile,
		strFileName,
		OF_READ,
		NULL);
	if(hr!=0)
		dlgError.MessageBox("error in AVIFileOpen");
	
	//get the information of avi file, 
	hr = AVIFileInfo(m_pAviFile,
		m_pAviFileInfo,
		sizeof(AVIFILEINFO)
		);
	if(hr!=0)
		dlgError.MessageBox("error in AVIFileInfo");
	
	m_wWidth=(unsigned short)m_pAviFileInfo->dwWidth;
	m_wHeight=(unsigned short)m_pAviFileInfo->dwHeight;

	//get the stream from avi file.
	hr = AVIFileGetStream(
		m_pAviFile,
		&m_pAviStream,
		streamtypeVIDEO,
		0);
	if(hr!=0)
		dlgError.MessageBox("error in AVIFileGetStream");

	//get the stream's infomation
	hr=AVIStreamInfo(m_pAviStream,
		&m_AviStreamInfo,
		sizeof(AVISTREAMINFO));
	if(hr!=0)
		dlgError.MessageBox("error in AVIStreamInfo");

	//get the Stream's poiter
	m_pGetFrame = ::AVIStreamGetFrameOpen(m_pAviStream,NULL);
	if(!m_pGetFrame)
		dlgError.MessageBox("error in AVIStreamGetFrameOpen");

	m_pGetFrame2 = ::AVIStreamGetFrameOpen(m_pAviStream,NULL);
	if(!m_pGetFrame2)
		dlgError.MessageBox("error in AVIStreamGetFrameOpen2");


	m_lpBMPInfoHeader = new BITMAPINFOHEADER;
	m_lpBMPInfoHeader2 = new BITMAPINFOHEADER;
	m_lpBMPInfoHeader = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_pGetFrame,0);

	//get the precise value of m_lIFrameThreshold: the threshold to determine 2 different I-frame. 
	this->m_lIFrameThreshold=(short)(m_wWidth*m_wHeight*m_fIFrameThresdRelative/100);
	m_XimageP=new CxImage(m_wWidth,m_wHeight,m_lpBMPInfoHeader2->biBitCount);

	m_pTempPixel=(MyPixel*)calloc(m_wPFrameThreshold,sizeof(MyPixel));

	//the following is just to test whether the format of BMP is acceptable.
	//we may just ignore it.

	//get the length of the format of the stream
	LONG lsize;
	hr=AVIStreamReadFormat(m_pAviStream,::AVIStreamStart(m_pAviStream),NULL,&lsize);
	if(hr!=0)
	{
		dlgError.MessageBox("error in AVIStreamReadFormat");
	}

	//get the format of the stream
	LPBYTE pChunk = new BYTE[lsize];
	if(!pChunk)
	{
		dlgError.MessageBox("error in pChunk");
	}

	hr=::AVIStreamReadFormat(m_pAviStream,::AVIStreamStart(m_pAviStream),pChunk,&lsize);
	if(hr!=0)
	{
		dlgError.MessageBox("error in AVIStreamReadFormat2");
	}

	//make the Streamformat into mitmap poiter
	LPBITMAPINFO pBmpInfo = (LPBITMAPINFO)pChunk;

	//determine the type of the bmp file, BITMAPV4HEADER or BITMAPINFOHEADER
 	DWORD dwSize = pBmpInfo->bmiHeader.biSize;
	switch(dwSize)
	{
	case sizeof(124):
		dlgError.MessageBox("BITMAPV5HEADER not supported now");
		break;
	case sizeof(BITMAPV4HEADER):
		dlgError.MessageBox("BITMAPV4HEADER not supported now");
		break;
	case sizeof(BITMAPINFOHEADER):
	//	dlgError.MessageBox("BITMAPINFOHEADER supported");
		break;
	}
}


//writing the I-frame using BMP format.
void CMyAvi::WriteBmpFile(int num)
{
	char filename[30];
	sprintf(filename,"picture\\data%d.bmp",num);
	
	if(m_lpBMPInfoHeader2->biBitCount<=8)
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER)+(WORD)pow(2,m_lpBMPInfoHeader2->biBitCount)*sizeof(RGBQUAD),CXIMAGE_FORMAT_BMP);
	else
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER),CXIMAGE_FORMAT_BMP);

	if (m_Ximage2.IsValid())
	{
		if(m_Ximage2.IsEnabled())
			m_Ximage2.Save(filename,CXIMAGE_FORMAT_BMP);
		else
		{		
			CDialog dlgError;
			dlgError.MessageBox("bmp is not printable");
		}
	}
	else
	{
		CDialog dlgError;
		dlgError.MessageBox("bmp is not ok");
	}
}


//writing the I-frame using PNG format.
void CMyAvi::WritePngFile(int num)
{
	char filename[30];
	sprintf(filename,"picture\\data%d.png",num);
	if(m_lpBMPInfoHeader2->biBitCount<=8)
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER)+(WORD)pow(2,m_lpBMPInfoHeader2->biBitCount)*sizeof(RGBQUAD),CXIMAGE_FORMAT_BMP);
	else
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER),CXIMAGE_FORMAT_BMP);
	

	if (m_Ximage2.IsValid())
	{
		if(m_Ximage2.IsEnabled())
			m_Ximage2.Save(filename,CXIMAGE_FORMAT_PNG);
		else
		{		
			CDialog dlgError;
			dlgError.MessageBox("png is not printable");
		}
	}
	else
	{
		CDialog dlgError;
		dlgError.MessageBox("png is not ok");
	}
//	m_Ximage2.Destroy();
}


//writing the I-frame using Jpeg format.
void CMyAvi::WriteJpegFile(int num)
{
	char filename[30];
	sprintf(filename,"picture\\data%d.jpg",num);

	if(m_lpBMPInfoHeader2->biBitCount<=8)
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER)+(WORD)pow(2,m_lpBMPInfoHeader2->biBitCount)*sizeof(RGBQUAD),CXIMAGE_FORMAT_BMP);
	else
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER),CXIMAGE_FORMAT_BMP);

	if (m_Ximage2.IsValid())
	{
		if(m_Ximage2.IsEnabled())
		{
		    if(!m_Ximage2.IsGrayScale()) 
				m_Ximage2.IncreaseBpp(24);
		    m_Ximage2.SetJpegQuality(99);
			m_Ximage2.Save(filename,CXIMAGE_FORMAT_JPG);
		}
		else
		{		
			CDialog dlgError;
			dlgError.MessageBox("png is not printable");
		}
	}
	else
	{
		CDialog dlgError;
		dlgError.MessageBox("png is not ok");
	}
//	m_Ximage2.Destroy();

}

//compare 2 frames, 
//return -1, when they are different; 
//return 0, when there are no changing between them; 
//return Diff, when they are based on the same image/(I-frame).
long CMyAvi::Compare2Frame(int lframe, int lframe2)
{
	//make the Streamformat into mitmap poiter
	m_lpBMPInfoHeader = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_pGetFrame,lframe);
	m_lpBMPInfoHeader2 = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_pGetFrame2,lframe2);

	//loading the 2 pics from memory into CxImage.
	if(m_lpBMPInfoHeader->biBitCount<=8)
		m_Ximage1.Decode((BYTE*)m_lpBMPInfoHeader,m_lpBMPInfoHeader->biSizeImage+sizeof(BITMAPINFOHEADER)+(WORD)pow(2,m_lpBMPInfoHeader->biBitCount)*sizeof(RGBQUAD),CXIMAGE_FORMAT_BMP);
	else
		m_Ximage1.Decode((BYTE*)m_lpBMPInfoHeader,m_lpBMPInfoHeader->biSizeImage+sizeof(BITMAPINFOHEADER),CXIMAGE_FORMAT_BMP);

	if(m_lpBMPInfoHeader2->biBitCount<=8)
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER)+(WORD)pow(2,m_lpBMPInfoHeader2->biBitCount)*sizeof(RGBQUAD),CXIMAGE_FORMAT_BMP);
	else
		m_Ximage2.Decode((BYTE*)m_lpBMPInfoHeader2,m_lpBMPInfoHeader2->biSizeImage+sizeof(BITMAPINFOHEADER),CXIMAGE_FORMAT_BMP);

	short x,y,i,j;
	short dr,dg,db;

	CString strBinFilename;
	CDialog dlgError;

	short nDistance;
	long lNumOfDiff=0;

//////////////////////////////////////////////////

	int zero=0,No_D_frame=1;

	RGBQUAD rgb1,rgb2;

	for(y=0; y<m_wHeight; y++)
	{
		for(x=0; x<m_wWidth; x++)
		{
			rgb1=m_Ximage1.GetPixelColor(x,y);
			rgb2=m_Ximage2.GetPixelColor(x,y);
			dr=DISTANCE(rgb1.rgbRed,rgb2.rgbRed);
			dg=DISTANCE(rgb1.rgbGreen,rgb2.rgbGreen);
			db=DISTANCE(rgb1.rgbBlue,rgb2.rgbBlue);
			
			//caculating the disstance of 2 pixel's colors.
			nDistance=dr+dg+db;
			
			
			//if there are some difference between 2 colors, the Mean filter are used.
			//and the border can not use filter.
			if(nDistance>=m_nPixelThreshold && m_byFilterType==1 && x>=m_byFilterRange && x<m_wWidth-m_byFilterRange && y>=m_byFilterRange && y<m_wHeight-m_byFilterRange)
			{
				short mean_r1=0,mean_g1=0,mean_b1=0,	mean_r2=0,mean_g2=0,mean_b2=0;
				BYTE num=0;
				for(j=y-m_byFilterRange;j<=y+m_byFilterRange;j++)
					for(i=x-m_byFilterRange;i<=x+m_byFilterRange;i++)
					{	
						rgb1=m_Ximage1.GetPixelColor(i,j);
						rgb2=m_Ximage2.GetPixelColor(i,j);

						mean_r1 += rgb1.rgbRed;
						mean_g1 += rgb1.rgbGreen;
						mean_b1 += rgb1.rgbBlue;
						mean_r2 += rgb2.rgbRed;
						mean_g2 += rgb2.rgbGreen;
						mean_b2 += rgb2.rgbBlue;

						num++;
					}
				mean_r1 /= num; mean_g1 /= num; mean_b1 /= num;
				mean_r2 /= num; mean_g2 /= num; mean_b2 /= num;
				nDistance=DISTANCE(mean_r1,mean_r2)+DISTANCE(mean_g1,mean_g2)+DISTANCE(mean_b1,mean_b2);

			}

			//if there are some difference between 2 colors, the Median filter are used.
			//and the border can not use filter.
			if(nDistance>=m_nPixelThreshold && m_byFilterType==2 && x>=m_byFilterRange && x<m_wWidth-m_byFilterRange && y>=m_byFilterRange && y<m_wHeight-m_byFilterRange)
			{
				BYTE array_r1[25],array_g1[25],array_b1[25],	array_r2[25],array_g2[25],array_b2[25];
				BYTE median_r1,median_g1,median_b1,	median_r2,median_g2,median_b2;

				BYTE num=0;
				for(j=y-m_byFilterRange;j<=y+m_byFilterRange;j++)
					for(i=x-m_byFilterRange;i<=x+m_byFilterRange;i++)
					{	
						rgb1=m_Ximage1.GetPixelColor(i,j);
						rgb2=m_Ximage2.GetPixelColor(i,j);

						array_r1[num]=rgb1.rgbRed;
						array_g1[num]=rgb1.rgbGreen;
						array_b1[num]=rgb1.rgbBlue;
						array_r2[num]=rgb2.rgbRed;
						array_g2[num]=rgb2.rgbGreen;
						array_b2[num]=rgb2.rgbBlue;

						num++;
					}
				median_r1=GetMedianValue(array_r1,num);
				median_g1=GetMedianValue(array_g1,num);
				median_b1=GetMedianValue(array_b1,num);
				median_r2=GetMedianValue(array_r2,num);
				median_g2=GetMedianValue(array_g2,num);
				median_b2=GetMedianValue(array_b2,num);


				nDistance=DISTANCE(median_r1,median_r2)+DISTANCE(median_g1,median_g2)+DISTANCE(median_b1,median_b2);

			}
			
			// if the difference between 2 pixels are less than m_nPixelThreshold, ignore it.
			if(nDistance < m_nPixelThreshold )
				nDistance=0;
			else  //there are differece of 2 pixels
			{
				lNumOfDiff++;

				//if this is some difference for the m_iProbeInterval, we neednot continue;
				if(m_byRunningProbeFlag)
				{
					if(lNumOfDiff>m_wPFrameThreshold)
						return -1;
				}
				else//the following txt file is used to recording D-frame.
				{
					
					if(lNumOfDiff<=m_wPFrameThreshold)
					{
						m_pTempPixel[lNumOfDiff-1].x=x;	
						m_pTempPixel[lNumOfDiff-1].y=y;
						m_pTempPixel[lNumOfDiff-1].r=rgb2.rgbRed;	
						m_pTempPixel[lNumOfDiff-1].g=rgb2.rgbGreen;	
						m_pTempPixel[lNumOfDiff-1].b=rgb2.rgbBlue;
					}
					else
					{
						if(No_D_frame)
						{
							if(!m_byPFrameType)
							{
								strBinFilename.Format("picture\\data%d.bin",lframe2);
								if(!m_fileBin.Open((LPCTSTR)strBinFilename,CFile::modeCreate|CFile::modeReadWrite))
								{
									dlgError.MessageBox("err in m_fileBin opening");
								}
								for(short k=0;k<m_wPFrameThreshold;k++)
									m_fileBin.Write(&m_pTempPixel[k], sizeof(MyPixel)-1);
							}
							else
							{
								m_XimageP->Clear(205);
								for(short k=0;k<m_wPFrameThreshold;k++)
									m_XimageP->SetPixelColor(m_pTempPixel[k].x, m_pTempPixel[k].y, rgb2, NULL);
							}

							No_D_frame=0;
						}
						if(!m_byPFrameType)
						{
							MyPixel pix;
							pix.x=x; pix.y=y; pix.r=rgb2.rgbRed; pix.g=rgb2.rgbGreen; pix.b=rgb2.rgbBlue;
							m_fileBin.Write(&pix,sizeof(MyPixel)-1);
						}
						else
							m_XimageP->SetPixelColor(x,y,rgb2,NULL);
						
					}
				}
			}

			// caculating the summary of all the difference of 2 pics.
			if(lNumOfDiff > m_lIFrameThreshold)
			{
				//if large enough, the 2nd pic is I-frame, we needn't write the m_fileBin,
				//instead we should break and copy the 2nd pics by returning -1. 
				if(!m_byPFrameType)
				{
					m_fileBin.Abort();
					::DeleteFile(strBinFilename);
				}
				return lNumOfDiff;
			}
		}//finish m_wHeightcle of x:	for(x=0; x<m_wWidth; x++)

	}//finish m_wHeightcle of y:	for(y=0; y<m_wHeight; y++)

	if(lNumOfDiff<=m_wPFrameThreshold)  //there are no difference between 2 pics.
	{
		lNumOfDiff=0;
	}
	else		//there are some differece, add the end-flag to the end of D-frame
	{	

		//writing the pixel's position and the color. 
		//using structure MyPixel
		if(!m_byRunningProbeFlag)
		{
			if(m_byPFrameType==BIN)
			{
				MyPixel pix;	
				pix.x=-1; pix.y=-1; pix.r=0; pix.g=0; pix.b=0;
				m_fileBin.Write(&pix,sizeof(MyPixel)-1);

				m_fileBin.Close();
			}
			else if(m_byPFrameType==PNG)
				WritePngFile_P(lframe2);
			else
				WriteJpegFile_P(lframe2);

		}
	}

	return lNumOfDiff;
}

//get the median value of the array
BYTE CMyAvi::GetMedianValue(BYTE *a, BYTE num)
{
	BYTE i,j,temp;
	for(i=0;i<num;i++)
	{
		temp=a[i];
		for(j=i;j<num;j++)
		{
			if(a[j]<temp)
			{
				a[i]=a[j];
				a[j]=temp;
			}
		}
	}
	return a[(num-1)/2];	
}


//compare 2 images which are 24-color, 
//return -1, when they are different; 
//return 0, when there are no changing between them; 
//return Diff, when they are based on the same image/(I-frame).
long CMyAvi::Compare2Frame_24(int lframe, int lframe2)
{
	//make the Streamformat into mitmap poiter
	m_lpBMPInfoHeader = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_pGetFrame,lframe);
	m_pBmpData = (BYTE*)m_lpBMPInfoHeader+m_lpBMPInfoHeader->biSize;
	m_lpBMPInfoHeader2 = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_pGetFrame2,lframe2);
	m_pBmpData2 = (BYTE*)m_lpBMPInfoHeader2+m_lpBMPInfoHeader2->biSize;

	short x,y,i,j;
	BYTE r1,r2,g1,g2,b1,b2,dr,dg,db;
	RGBQUAD color;

	CString strBinFilename;
	CDialog dlgError;
	
	int zero=0,No_D_frame=1;
	unsigned short nDistance,lNumOfDiff=0;

//////////////////////////////////////////////////

	BYTE *p1,*p2;				//point to the pixel's RGB value.
	
	p1=(BYTE*)m_pBmpData;p2=(BYTE*)m_pBmpData2;

	for(y=0; y<m_wHeight; y++)
	{
		for(x=0; x<m_wWidth; x++)
		{
			if(memcmp(p1,p2,3)==0)			//the RGB values of 2 pixels are same 
			{
				p1+=3;p2+=3;				//compare the next 2 pixels.
			}
			else
			{
				b1=*p1;b2=*p2;
				db=DISTANCE(b1,b2);
				p1++;p2++;

				g1=*p1;g2=*p2;
				dg=DISTANCE(g1,g2);
				p1++;p2++;

				r1=*p1;r2=*p2;
				dr=DISTANCE(r1,r2);
				p1++;p2++;
				
				//caculating the disstance of 2 pixel's colors.
				nDistance=dr+dg+db;
				
				//if there are some difference between 2 colors, the Mean filter are used.
				//and the border can not use filter.
				if(nDistance>=m_nPixelThreshold && m_byFilterType==1 && x>=m_byFilterRange && x<m_wWidth-m_byFilterRange && y>=m_byFilterRange && y<m_wHeight-m_byFilterRange)
				{
					short mean_r1=0,mean_g1=0,mean_b1=0,	mean_r2=0,mean_g2=0,mean_b2=0;
					BYTE num=0, *pp1,*pp2;		
					int temp;

					for(j=y-m_byFilterRange;j<=y+m_byFilterRange;j++)
						for(i=x-m_byFilterRange;i<=x+m_byFilterRange;i++)
						{	
							temp=(j*m_wWidth+i);			//offset to the current pixel	
							pp1=m_pBmpData+temp+temp+temp;		//note one pixel occure 3 BYTE
							pp2=m_pBmpData2+temp+temp+temp;	//it equals: pp2=m_pBmpData2+(j*m_wWidth+i)*3;

							mean_b1 += *pp1;
							mean_g1 += *(pp1+1);
							mean_r1 += *(pp1+2);
							mean_b2 += *pp2;
							mean_g2 += *(pp2+1);
							mean_r2 += *(pp2+2);

							num++;
						}
					mean_r1 /= num; mean_g1 /= num; mean_b1 /= num;
					mean_r2 /= num; mean_g2 /= num; mean_b2 /= num;
					nDistance=DISTANCE(mean_r1,mean_r2)+DISTANCE(mean_g1,mean_g2)+DISTANCE(mean_b1,mean_b2);

				}

				//if there are some difference between 2 colors, the Median filter are used.
				//and the border can not use filter.
				if(nDistance>=m_nPixelThreshold && m_byFilterType==2 && x>=m_byFilterRange && x<m_wWidth-m_byFilterRange && y>=m_byFilterRange && y<m_wHeight-m_byFilterRange)
				{
					BYTE array_r1[25],array_g1[25],array_b1[25],	array_r2[25],array_g2[25],array_b2[25];
					BYTE median_r1,median_g1,median_b1,	median_r2,median_g2,median_b2;
					BYTE num=0,	*pp1,*pp2;
					int temp;
					for(j=y-m_byFilterRange;j<=y+m_byFilterRange;j++)
						for(i=x-m_byFilterRange;i<=x+m_byFilterRange;i++)
						{	
							temp=(j*m_wWidth+i);		//find the pixel's point.
							pp1=m_pBmpData+temp+temp+temp;		//one pixel occur 3 BYTE.
							pp2=m_pBmpData2+temp+temp+temp;

							array_r1[num]=*pp1;
							array_g1[num]=*(pp1+1);
							array_b1[num]=*(pp1+2);
							array_r2[num]=*pp2;
							array_g2[num]=*(pp2+1);
							array_b2[num]=*(pp2+2);

							num++;
						}
					median_r1=GetMedianValue(array_r1,num);
					median_g1=GetMedianValue(array_g1,num);
					median_b1=GetMedianValue(array_b1,num);
					median_r2=GetMedianValue(array_r2,num);
					median_g2=GetMedianValue(array_g2,num);
					median_b2=GetMedianValue(array_b2,num);


					nDistance=DISTANCE(median_r1,median_r2)+DISTANCE(median_g1,median_g2)+DISTANCE(median_b1,median_b2);

				}
				
				// if the difference between 2 pixels are less than m_nPixelThreshold, ignore it.
				if(nDistance < m_nPixelThreshold )
					nDistance=0;
				else  //there are differece between 2 pixels
				{

					lNumOfDiff++;
					//if this is some difference for the m_iProbeInterval, we neednot continue;
					if(m_byRunningProbeFlag)
					{
						if(lNumOfDiff>50)
							return 50;
					}
					else//the following is used to recording P-frame.
					{
						if(lNumOfDiff<=m_wPFrameThreshold)
						{
							m_pTempPixel[lNumOfDiff-1].x=x;	m_pTempPixel[lNumOfDiff-1].y=y;
							m_pTempPixel[lNumOfDiff-1].r=r2;	m_pTempPixel[lNumOfDiff-1].g=g2;	m_pTempPixel[lNumOfDiff-1].b=b2;
						}
						else
						{
							if(No_D_frame)  //creat the file to record difference.
							{	
								if(!m_byPFrameType)	//use bin file
								{
									strBinFilename.Format("picture\\data%d.bin",lframe2);
									if(!m_fileBin.Open((LPCTSTR)strBinFilename,CFile::modeCreate|CFile::modeReadWrite))
									{
										dlgError.MessageBox("err in m_fileBin opening");
									}
									for(short k=0;k<m_wPFrameThreshold;k++)
										m_fileBin.Write(&m_pTempPixel[k],sizeof(MyPixel)-1);
								}
								else				//use PNG/Jpeg file
								{

									m_XimageP->Clear(205); 

									for(short k=0;k<m_wPFrameThreshold;k++)
									{
										color.rgbRed=r2;
										color.rgbBlue=b2;
										color.rgbGreen=g2;
										m_XimageP->SetPixelColor(m_pTempPixel[k].x,m_pTempPixel[k].y,color,NULL);
									}
									
								}
								
								No_D_frame=0;
							}

						
							//writing the pixel's position and the color. 
							//using structure MyPixel
							if(!m_byPFrameType)
							{
								MyPixel pix;
								pix.x=x; pix.y=y; pix.r=r2; pix.g=g2; pix.b=b2;
								m_fileBin.Write(&pix,sizeof(MyPixel)-1);
							}
							else
							{
								color.rgbRed=r2;
								color.rgbBlue=b2;
								color.rgbGreen=g2;
								m_XimageP->SetPixelColor(x,y,color,NULL);
							}	
						}
					}
				}

				// caculating the summary of all the difference of 2 pics.

				if(lNumOfDiff > m_lIFrameThreshold)
				{
					//if large enough, the 2nd pic is I-frame, we needn't write the P-frame: the m_fileBin,
					//instead we should break and copy the 2nd pics by returning -1. 
					if(!m_byPFrameType)
					{
						m_fileBin.Abort();
						::DeleteFile(strBinFilename);
					}
					else
					{
						//m_XimageP->Destroy();
					}
					return lNumOfDiff;
				}
			} // deal with 2 different pixel.

		} //finish m_wHeightcle of x:	for(x=0; x<m_wWidth; x++)

	}//finish m_wHeightcle of y:	for(y=0; y<m_wHeight; y++)

	if(lNumOfDiff<=m_wPFrameThreshold)
		lNumOfDiff=0;
	else	//there are some differece, add the end-flag to the end of P-frame
	{	

		//writing the end flag to the BIN-file. 
		//using structure MyPixel
		if(!m_byRunningProbeFlag)
		{
			if(m_byPFrameType==BIN)
			{
				WriteBinFile_P(lNumOfDiff);
			}
			else if(m_byPFrameType==PNG)
			{
				WritePngFile_P(lframe2);
			}
			else
				WriteJpegFile_P(lframe2);

		}
	}

	return lNumOfDiff;

}

//writing the P-frame using PNG format.
void CMyAvi::WritePngFile_P(int num)
{
	char filename[30];
	sprintf(filename,"picture\\data%d.png",num);

	if (m_XimageP->IsValid())
	{
		if(m_XimageP->IsEnabled())
		{
			m_XimageP->Save(filename,CXIMAGE_FORMAT_PNG);
		}
		else
		{		
			CDialog dlgError;
			dlgError.MessageBox("png is not printable");
		}
	}
	else
	{
		CDialog dlgError;
		dlgError.MessageBox("png_P is not ok");
	}

}


//writing the P-frame using Jpeg format.
void CMyAvi::WriteJpegFile_P(int num)
{
	char filename[30];
	sprintf(filename,"picture\\data%d.jpg",num);

	if (m_XimageP->IsValid())
	{
		if(m_XimageP->IsEnabled())
			m_XimageP->Save(filename,CXIMAGE_FORMAT_JPG);
		else
		{		
			CDialog dlgError;
			dlgError.MessageBox("jpg is not printable");
		}
	}
	else
	{
		CDialog dlgError;
		dlgError.MessageBox("jpg is not ok");
	}

}

unsigned short CMyAvi::GetWidth()
{
	return this->m_wWidth;
}

unsigned short CMyAvi::GetHeight()
{
	return this->m_wHeight;
}

void CMyAvi::SetIFrameThresdRelative(float value)
{
	this->m_fIFrameThresdRelative=value;
}

void CMyAvi::SetPFrameThreshold(unsigned short value)
{
	this->m_wPFrameThreshold=value;
}

void CMyAvi::SetProbeInterval(int value)
{
	this->m_iProbeInterval=value;
}

void CMyAvi::SetIFrameInterval(int value)
{
	this->m_iMaxIFrameInterval=value;
}

void CMyAvi::SetIFrameType(BYTE value)
{
	this->m_byIFrameType=value;
}

void CMyAvi::SetPFrameType(BYTE value)
{
	this->m_byPFrameType=value;
}

void CMyAvi::SetPixelThreshold(int value)
{
	this->m_nPixelThreshold=value;
}

void CMyAvi::SetFilterType(BYTE value)
{
	this->m_byFilterType=value;
}

void CMyAvi::SetFilterRange(BYTE value)
{
	this->m_byFilterRange=value;
}

AVIFILEINFO* CMyAvi::GetAviFileInfo()
{
	return this->m_pAviFileInfo;
}

BITMAPINFOHEADER* CMyAvi::GetBMPInfo()
{
	return this->m_lpBMPInfoHeader;
}

void CMyAvi::WriteBinFile_P(long lNumOfDiff)
{
	// add the over flage to the end of bin file.
	short MinusOne=-1;	

	m_fileBin.Write(&MinusOne,sizeof(short));
	m_fileBin.Write(&MinusOne,sizeof(short));

	m_fileBin.Write(&lNumOfDiff,sizeof(long));
	m_fileBin.Close();
}

void CMyAvi::InitCompare()
{
	//get the frame according to the time=0.
	long lframe = AVIStreamTimeToSample(m_pAviStream,0);

	//to get the data of the bitmap
	m_lpBMPInfoHeader2 = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_pGetFrame2,lframe);

	//INF file records all the infomation of the extraction

/*
	the following is writing into INF file the AviFileInfo, 
	the file type of I-frame and P-frame, and write the first frame as I-frame. 
*/	

	byte byFrameType=IFRAME;  //byFrameType=2 means I-frame, 1 meaning P-frame, 0 means 0-frame.

	if(m_fileInf.Open("picture\\begin.inf",CFile::modeCreate|CFile::modeReadWrite))
	{
		m_fileInf.Write(m_pAviFileInfo,sizeof(AVIFILEINFO));

		if(this->m_byIFrameType==BMP)		//writting the type of I-frame.
			m_fileInf.Write("bmp",4);
		if(this->m_byIFrameType==PNG)
			m_fileInf.Write("png",4);
		if(this->m_byIFrameType==JPEG)
			m_fileInf.Write("jpg",4);

		if(this->m_byPFrameType==BIN)
			m_fileInf.Write("bin",4);	//writting the type of P-frame.
		if(this->m_byPFrameType==PNG)
			m_fileInf.Write("png",4);	
		if(this->m_byPFrameType==JPEG)
			m_fileInf.Write("jpg",4);	

		m_fileInf.Write(&byFrameType,1);	//the first frame must be I-frame.
	}

	
	if(this->m_byIFrameType==BMP)		//writting the first frame as I-frame
		this->WriteBmpFile(0);
	if(this->m_byIFrameType==PNG)
		this->WritePngFile(0);
	if(this->m_byIFrameType==JPEG)
		this->WriteJpegFile(0);

	//the above is just to write into INF file that the first frame is I-frame. 
	//then write it as BMP/PNG/JPG format.
}
