www.pudn.com > SBDcode.rar > CutDetector.cpp


/* 
 *	Copyright (c) 2003, Jim Easterbrook 
 * 
 * 
 *	This file is part of shot-change. 
 * 
 *  shot-change is free software; you can redistribute it and/or modify 
 *  it under the terms of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation; either version 2.1 of the License, or 
 *  (at your option) any later version. 
 * 
 *  shot-change is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU Lesser General Public License for more details. 
 * 
 *  You should have received a copy of the GNU Lesser General Public License 
 *  along with shot-change; if not, write to the Free Software 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */ 
 
#pragma comment(exestr,"$Id: CutDetector.cpp,v 1.1.1.1 2003/03/20 11:49:01 easter Exp $") 
 
/* 
 * $Log: CutDetector.cpp,v $ 
 * Revision 1.1.1.1  2003/03/20 11:49:01  easter 
 * Initial import 
 * 
 */ 
 
#include 	// DirectShow (includes windows.h) 
#include 	// for VIDEOINFOHEADER2 
#include  
#include  
 
#include "CutDetector.h" 
 
// setup data for self-registration 
static const WCHAR g_wszName[] = L"Cut Detector"; 
 
const AMOVIESETUP_MEDIATYPE sudVideoTypes[] = 
{ 
	{ &MEDIATYPE_Video, &MEDIASUBTYPE_YUY2 }, 
}; 
const AMOVIESETUP_MEDIATYPE sudTextTypes[] = 
{ 
	{ &MEDIATYPE_Text, &MEDIASUBTYPE_NULL }, 
}; 
 
const AMOVIESETUP_PIN psudPins[] = 
{ 
	{ L"Video in",			// strName (obsolete) 
	  FALSE,				// bRendered 
	  FALSE,				// bOutput 
	  FALSE,				// bZero 
	  FALSE,				// bMany 
	  &CLSID_NULL,			// clsConnectsToFilter (obsolete) 
	  L"",					// strConnectsToPin (obsolete) 
	  sizeof(sudVideoTypes)/sizeof(sudVideoTypes[0]), 
	  sudVideoTypes 		// lpTypes 
	}, 
	{ L"~Video loop thru",	// strName (obsolete) 
	  FALSE,				// bRendered 
	  TRUE,					// bOutput 
	  FALSE,				// bZero 
	  FALSE,				// bMany 
	  &CLSID_NULL,			// clsConnectsToFilter (obsolete) 
	  L"",					// strConnectsToPin (obsolete) 
	  sizeof(sudVideoTypes)/sizeof(sudVideoTypes[0]), 
	  sudVideoTypes 		// lpTypes 
	}, 
	{ L"Text out",			// strName (obsolete) 
	  FALSE,				// bRendered 
	  TRUE, 				// bOutput 
	  FALSE,				// bZero 
	  FALSE,				// bMany 
	  &CLSID_NULL,			// clsConnectsToFilter (obsolete) 
	  L"",					// strConnectsToPin (obsolete) 
	  sizeof(sudTextTypes)/sizeof(sudTextTypes[0]), 
	  sudTextTypes			// lpTypes 
	}, 
}; 
 
const AMOVIESETUP_FILTER sudCutDetector = 
{ 
	&CLSID_CutDetector,		// clsID 
	g_wszName,				// strName 
	MERIT_DO_NOT_USE,		// dwMerit 
	sizeof(psudPins)/sizeof(psudPins[0]), 
	psudPins				// lpPin 
}; 
 
class VideoInPin : public CBaseInputPin 
{ 
public: 
	VideoInPin(CBaseFilter *pFilter, CCritSec *pLock, HRESULT *phr); 
private: 
	STDMETHODIMP EndOfStream(void); 
	STDMETHODIMP BeginFlush(void); 
	STDMETHODIMP EndFlush(void); 
	STDMETHODIMP Receive(IMediaSample *pSample); 
	HRESULT SetMediaType(const CMediaType *pmt); 
	HRESULT CheckMediaType(const CMediaType *pmt); 
	HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); 
	HRESULT CompleteConnect(IPin *pReceivePin); 
	STDMETHODIMP NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly); 
public: 
	IMemAllocator* PeekAllocator(void) const 
		{ return m_pAllocator; } 
	CMediaType CurrentMediaType(void) const 
		{ return m_mt; } 
private: 
	CCritSec	StreamLock; 
}; 
 
class QueuedOutputPin : public CBaseOutputPin 
{ 
public: 
	QueuedOutputPin(TCHAR *pObjectName, CBaseFilter *pFilter, CCritSec *pLock, 
		HRESULT *phr, LPCWSTR pName); 
private: 
	HRESULT Active(); 
	HRESULT Inactive(); 
public: 
	HRESULT Deliver(IMediaSample *pMediaSample); 
	HRESULT DeliverEndOfStream(); 
	HRESULT DeliverBeginFlush(); 
	HRESULT DeliverEndFlush(); 
private: 
	COutputQueue*	pOutputQueue; 
}; 
 
class VideoOutPin : public QueuedOutputPin 
{ 
public: 
	VideoOutPin(CBaseFilter *pFilter,CCritSec *pLock, HRESULT *phr); 
private: 
	HRESULT DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc); 
	HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); 
	HRESULT CheckMediaType(const CMediaType *pmt); 
	HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); 
	HRESULT CompleteConnect(IPin *pReceivePin); 
	STDMETHODIMP Notify(IBaseFilter *pSender, Quality q); 
public: 
	CMediaType CurrentMediaType(void) const 
		{ return m_mt; } 
}; 
 
class TextOutPin : public QueuedOutputPin 
{ 
public: 
	TextOutPin(CBaseFilter *pFilter,CCritSec *pLock, HRESULT *phr); 
private: 
	HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); 
	HRESULT CheckMediaType(const CMediaType *pmt); 
	HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); 
	STDMETHODIMP Notify(IBaseFilter *pSender, Quality q); 
}; 
 
// This class converts DirectShow sample times to frame numbers. This should be as easy as 
// dividing by the frame duration, but unfortunately the frame duration is not exactly as 
// reported by the AvgTimePerFrame video info header parameter. (Probably a consequence of 
// adjusting the video to fit the [free running] audio during capture.) This class attempts 
// to measure the actual frame time, and uses that to compute frame number. 
class ConvertSampleTime 
{ 
public: 
	ConvertSampleTime(); 
	void ReStart(); 
	void SetMediaType(const AM_MEDIA_TYPE *pmt); 
	int GetFrameNo(IMediaSample *pSample); 
private: 
	inline REFERENCE_TIME rdiv(const REFERENCE_TIME a, const REFERENCE_TIME b); 
private: 
	#define TimeScale	100000 
	REFERENCE_TIME	FrameDuration; 
	REFERENCE_TIME	LastStartTime; 
	REFERENCE_TIME	RefTime; 
	REFERENCE_TIME	RefFrame; 
	REFERENCE_TIME	FrameCount; 
	REFERENCE_TIME	TimeOffset; 
	REFERENCE_TIME	FDError; 
}; 
 
struct CDParams 
{ 
	CallBackFunc	*pCallBack; 
	float			Threshold; 
 
}; 
 
class CCutDetector : public CBaseFilter, public IAMFilterMiscFlags, public ICDControl 
{ 
public: 
	static CUnknown *WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr); 
private: 
	DECLARE_IUNKNOWN; 
	STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); 
	// CBaseFilter stuff 
	CCutDetector(LPUNKNOWN lpunk, HRESULT *phr); 
	~CCutDetector(); 
	CBasePin *GetPin(int n); 
	int GetPinCount(void); 
	// IAMFilterMiscFlags stuff 
	ULONG __stdcall GetMiscFlags(void); 
	// ICDControl stuff 
	STDMETHODIMP SetCallBack(CallBackFunc *pCallBack); 
	STDMETHODIMP SetThreshold(const float Threshold); 
	// My stuff 
public: 
	HRESULT EndOfStream(void); 
	HRESULT DeliverBeginFlush(void); 
	HRESULT DeliverEndFlush(void); 
	void ReleaseSamples(void); 
	HRESULT SetMediaType(const AM_MEDIA_TYPE *pmt); 
	HRESULT Receive(IMediaSample *pThisFrame); 
private: 
	//HRESULT SendResult(const int FrameNo, const float Confidence, const int Duration); 
    HRESULT SendResult(const int FrameNo, const int f1,const float f2,const float f3,const float f4,const float I1,const float I2,const float I3,const float I4); 
 
private: 
	CCritSec			StateLock; 
	TextOutPin			*pTextOutput; 
	VideoInPin			*pVideoInput; 
	VideoOutPin			*pVideoOutput; 
	IMediaSample		*pLastFrame; 
	ConvertSampleTime	CST; 
	CDParams			Params; 
	// Image dimensions 
	int		xLen, yLen; 
	int		BytesPerLine; 
	int		SampleOffset; 
 
	// Cut detector state 
	int			ValidFrames;	// frames since sequence or segment started 
	double      b0[2],b1[2],accum0[2],accum1[2],accum3[2],accum4[2]; 
//	double		Grate[10];			// raw "cut" signal 
//	double		MAD[10];		// mean absolute difference 
//	double		Thresh[10];		// threshold based on local activity 
	int			frameno[3]; 
	double		C1[10]; //一次帧差;; 
    double		Grate[10]; //平均灰度; 
	double      D_hist[256]; //直方图差; 
    double      D_hist_2[256]; 
	double		mono[256];//单色 
	long int    startNO[2],EndNO[2],signNO[2]; 
	long int    dowmNO[2],upNO[2] ,accum_mono[2]; 
	double      LHIST[256][10]; 
	int         cnt; 
    double      acc_hist; 
	double      level; 
	double		savec1[256],savedhist[256],savemono[256]; 
	double      SS1[10],SS2[10],SS3[10],SS[10],DS[10]; 
	int         a0,a1; // symbol bits; 
	 
}; 
 
// Global variables used by the class factory 
CFactoryTemplate g_Templates[]= 
{ 
	{ g_wszName, 
	  &CLSID_CutDetector, 
	  CCutDetector::CreateInstance, 
	  NULL, 
	  &sudCutDetector 
	} 
}; 
int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]); 
 
// Create and return an instance of the filter 
CUnknown *WINAPI 
CCutDetector::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) 
{ 
	CUnknown *punk = new CCutDetector(lpunk, phr); 
	if (punk == NULL) 
		*phr = E_OUTOFMEMORY; 
	return punk; 
} 
 
STDMETHODIMP 
CCutDetector::NonDelegatingQueryInterface(REFIID riid, void **ppv) 
{ 
	CheckPointer(ppv, E_POINTER); 
	if (riid == IID_IAMFilterMiscFlags) 
		return GetInterface((IAMFilterMiscFlags*)this, ppv); 
	if (riid == IID_ICDControl) 
		return GetInterface((ICDControl*)this, ppv); 
	return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); 
} 
 
CCutDetector::CCutDetector(LPUNKNOWN punk, HRESULT *phr) : 
	CBaseFilter(NAME("cut detector"), punk, &StateLock, CLSID_CutDetector) 
{ 
	pVideoInput = new VideoInPin(this, m_pLock, phr); 
	pVideoOutput = new VideoOutPin(this, m_pLock, phr); 
	pTextOutput = new TextOutPin(this, m_pLock, phr); 
	if (pVideoInput == NULL || pVideoOutput == NULL || pTextOutput == NULL) 
		*phr = E_OUTOFMEMORY; 
	pLastFrame = NULL; 
	Params.pCallBack = NULL; 
	Params.Threshold = 0.0; 
} 
 
// Destructor 
CCutDetector::~CCutDetector() 
{ 
	delete pVideoInput; 
	delete pVideoOutput; 
	delete pTextOutput; 
	// Release any left over samples 
	if (pLastFrame != NULL) 
	{ 
		pLastFrame->Release(); 
		pLastFrame = NULL; 
	} 
} 
 
#define VideoInputNo	0 
#define VideoOutputNo	1 
#define TextOutputNo	2 
 
CBasePin* 
CCutDetector::GetPin(int n) 
{ 
	if (n == VideoInputNo) 
		return pVideoInput; 
	if (n == VideoOutputNo) 
		return pVideoOutput; 
	if (n == TextOutputNo) 
		return pTextOutput; 
	return NULL; 
} 
 
int 
CCutDetector::GetPinCount(void) 
{ 
	return 3; 
} 
 
ULONG __stdcall 
CCutDetector::GetMiscFlags(void) 
{ 
	if (pVideoOutput->IsConnected() || 
		pTextOutput->IsConnected()) 
		return 0; 
	else 
		return AM_FILTER_MISC_FLAGS_IS_RENDERER; 
} 
 
STDMETHODIMP 
CCutDetector::SetCallBack(CallBackFunc *pCallBack) 
{ 
	Params.pCallBack = pCallBack; 
	return S_OK; 
} 
 
STDMETHODIMP 
CCutDetector::SetThreshold(const float Threshold) 
{ 
	Params.Threshold = Threshold; 
	return S_OK; 
} 
 
HRESULT 
CCutDetector::EndOfStream(void) 
{ 
	HRESULT		hr; 
 
	if (pVideoOutput->IsConnected()) 
	{ 
		hr = pVideoOutput->DeliverEndOfStream(); 
		if (FAILED(hr)) 
			return hr; 
	} 
	if (pTextOutput->IsConnected()) 
	{ 
		hr = pTextOutput->DeliverEndOfStream(); 
		if (FAILED(hr)) 
			return hr; 
	} 
	if ((GetMiscFlags() & AM_FILTER_MISC_FLAGS_IS_RENDERER) != 0) 
	{ 
		// Send an EC_COMPLETE event to stop the graph 
		hr = NotifyEvent(EC_COMPLETE, 0, 0); 
		if (FAILED(hr)) 
			return hr; 
	} 
	return S_OK; 
} 
 
HRESULT 
CCutDetector::DeliverBeginFlush(void) 
{ 
	HRESULT		hr; 
 
	if (pVideoOutput->IsConnected()) 
	{ 
		hr = pVideoOutput->DeliverBeginFlush(); 
		if (FAILED(hr)) 
			return hr; 
	} 
	if (pTextOutput->IsConnected()) 
	{ 
		hr = pTextOutput->DeliverBeginFlush(); 
		if (FAILED(hr)) 
			return hr; 
	} 
	return S_OK; 
} 
 
HRESULT 
CCutDetector::DeliverEndFlush(void) 
{ 
	HRESULT		hr; 
 
	if (pVideoOutput->IsConnected()) 
	{ 
		hr = pVideoOutput->DeliverEndFlush(); 
		if (FAILED(hr)) 
			return hr; 
	} 
	if (pTextOutput->IsConnected()) 
	{ 
		hr = pTextOutput->DeliverEndFlush(); 
		if (FAILED(hr)) 
			return hr; 
	} 
	return S_OK; 
} 
 
void 
CCutDetector::ReleaseSamples(void) 
{ 
	if (pLastFrame != NULL) 
	{ 
		pLastFrame->Release(); 
		pLastFrame = NULL; 
	} 
} 
 
HRESULT 
CCutDetector::SetMediaType(const AM_MEDIA_TYPE *pmt) 
{ 
	BITMAPINFOHEADER	*pBmi; 
	RECT				*pSrcRect; 
 
	CST.SetMediaType(pmt); 
	if (pmt->formattype == FORMAT_VideoInfo) 
	{ 
		pSrcRect = &((VIDEOINFOHEADER*)pmt->pbFormat)->rcSource; 
		pBmi = &((VIDEOINFOHEADER*)pmt->pbFormat)->bmiHeader; 
	} 
	else if (pmt->formattype == FORMAT_VideoInfo2) 
	{ 
		pSrcRect = &((VIDEOINFOHEADER2*)pmt->pbFormat)->rcSource; 
		pBmi = &((VIDEOINFOHEADER2*)pmt->pbFormat)->bmiHeader; 
	} 
	else 
		return E_UNEXPECTED; 
	BytesPerLine = (int)pBmi->biSizeImage / abs(pBmi->biHeight); 
	xLen = pSrcRect->right - pSrcRect->left; 
	if (xLen == 0) 
		xLen = pBmi->biWidth; 
	yLen = pSrcRect->bottom - pSrcRect->top; 
	if (yLen == 0) 
		yLen = abs(pBmi->biHeight); 
	SampleOffset = (pSrcRect->top * BytesPerLine) + (pSrcRect->left * 2); 
	return S_OK; 
} 
 
HRESULT 
CCutDetector::Receive(IMediaSample *pThisFrame) 
{ 
	HRESULT			hr; 
	int		        ThisFrameNo; 
	int             sk2,sk0,Xn,Yn,p0,p1; 
    double		    p_this,p_last,p_diff,Tn;	 
	double          danse; 
	int             tabs[710],tab0[710],tabn[710]; 
	int             CycNO; 
	double          n0,np,nn,p_0,p_n,p_p; 
	 
    danse=0.0; 
	p_diff=0.0;	 
	CycNO=0; 
	 
	 
	AM_MEDIA_TYPE	*NewMT; 
 
	if (pLastFrame == NULL) 
		ValidFrames = 0; 
 
	if (pThisFrame->GetMediaType(&NewMT) == S_OK) 
	{ 
		ValidFrames = 0; 
		hr = SetMediaType(NewMT); 
		DeleteMediaType(NewMT); 
		if (FAILED(hr)) 
			return hr; 
	} 
 
	if (pThisFrame->IsDiscontinuity() == S_OK) 
	{ 
		ValidFrames = 0; 
		CST.ReStart(); 
	} 
 
	ThisFrameNo = CST.GetFrameNo(pThisFrame); 
	ValidFrames = min(ValidFrames + 1, 100000); 
 
	// Shift results from previous frame 
 
//	memmove(&C0[1], &C0[0], sizeof(C0) - sizeof(C0[0])); 
	memmove(&C1[1], &C1[0], sizeof(C1) - sizeof(C1[0])); 
//	memmove(&MAD[1], &MAD[0], sizeof(MAD) - sizeof(MAD[0])); 
//	memmove(&Gdiff[1], &Gdiff[0], sizeof(Gdiff) - sizeof(Gdiff[0])); 
	memmove(&Grate[1], &Grate[0], sizeof(Grate) - sizeof(Grate[0])); 
//	memmove(&Thresh[1], &Thresh[0], sizeof(Thresh) - sizeof(Thresh[0])); 
	memmove(&D_hist[1], &D_hist[0], sizeof(D_hist) - sizeof(D_hist[0]));  
	memmove(&D_hist_2[1], &D_hist_2[0], sizeof(D_hist_2) - sizeof(D_hist_2[0]));  
	memmove(&mono[1], &mono[0], sizeof(mono) - sizeof(mono[0]));  
	memmove(&startNO[1], &startNO[0], sizeof(startNO) - sizeof(startNO[0])); 
	memmove(&EndNO[1], &EndNO[0], sizeof(EndNO) - sizeof(EndNO[0])); 
	memmove(&signNO[1], &signNO[0], sizeof(signNO) - sizeof(signNO[0])); 
	memmove(&SS1[1], &SS1[0], sizeof(SS1) - sizeof(SS1[0])); 
	memmove(&SS2[1], &SS2[0], sizeof(SS2) - sizeof(SS2[0])); 
	memmove(&SS3[1], &SS3[0], sizeof(SS3) - sizeof(SS3[0]));    
	memmove(&SS[1], &SS[0], sizeof(SS) - sizeof(SS[0])); 
	memmove(&DS[1], &DS[0], sizeof(DS) - sizeof(DS[0])); 
 
	for(int i = 0; i <= 255; i++) 
	{ 
	   memmove(& LHIST[i][1], & LHIST[i][0], sizeof( LHIST[i]) - sizeof( LHIST[i][0]));   
	}  
 
 
 
	if (ValidFrames >= 2) 
	{ 
		// Compute mean absolute interframe difference 
		BYTE	*pThisLine, *pLastLine,*pThisLine0, *pLastLine0; 
		BYTE	*pThisSample, *pLastSample; 
		int		Total; 
 
		hr = pThisFrame->GetPointer(&pThisLine); 
		if (FAILED(hr)) 
			return hr; 
		hr = pLastFrame->GetPointer(&pLastLine); 
		if (FAILED(hr)) 
			return hr; 
		pThisLine0 = pThisLine + SampleOffset; 
		pLastLine0 = pLastLine + SampleOffset; 
 
		Total = 0;  
		D_hist[0] = 0; 
		D_hist_2[0] = 0; 
		 
        n0=np=nn=p_0=p_n=p_p=0.0; 
 
	    p_this=p_last=p_diff=0.0; 
	    sk0=1; 
	    sk2=2*sk0; 
	    Xn=int(xLen /sk0);	   
        Yn=int((yLen)/(sk0)); 
        Tn=double(Yn*Xn);	 
	    pThisLine=pThisLine0; 
        pLastLine=pLastLine0; 
 
 
		for (int y = 0; y < Yn; y++) 
		{ 
			pThisSample = pThisLine; 
			pLastSample = pLastLine; 
			for (int x = 0; x < Xn; x++) 
			{ 
				p0 = (*pLastSample); 
				p1 = (*pThisSample); 
				 
				LHIST[p1][0] += 1;			 
                
			    p_this=p_this+ double (p1); 
             
				if (p0==p1)          //不变; 
			   { 
					p_0 += 1.0; 
				//	n0=n0+1.0; 
				} 
		 	   else					 
			   {  
				   if (p1>p0)     //减小; 
					{ 
                        p_p +=(double) p0/(double)p1; 
					//	np=np+1.0; 
					}     
					else          //增大;					 
					 { 
                        p_n += (double)p1/(double)p0; 
					//	nn=nn+1.0; 
					 }			                 
			   } 
       
           
 
				pThisSample = pThisSample + sk2;	// Skip U or V sample 
				pLastSample = pLastSample + sk2; 
			} 
 
			pThisLine = pThisLine + BytesPerLine; 
			pLastLine = pLastLine + BytesPerLine; 
		} 
             
			Grate[0]=p_this/Tn;   //平均灰度; 
			 
 
        for( int j = 0; j <= 255;j++)        //灰度直方图;	 
        {  			  
             LHIST[j][0] =  LHIST[j][0]/Tn;							 
		}	 
          
		for( int k = 0; k <= 255; k++)      //帧间差(1); 
		{ 
            D_hist[0] +=   fabs( LHIST[k][0] - LHIST[k][1]); 
		    D_hist_2[0] +=   fabs( LHIST[k][0] - LHIST[k][3]);	 
		} 
 
		if(D_hist_2[0] < 0.2 && D_hist_2[1] > 0.5 &&  D_hist_2[2] < 0.2) 
		{ 
		    D_hist[0] = 0.01; 
            D_hist[1] = 0.01; 
		} 
 
	         SS1[0]= p_0/(Tn); 
		              
			 SS2[0]= p_p/(Tn);  
		             
			 SS3[0]= p_n/(Tn);	 
			    
			 SS[0] =  SS1[0] +SS2[0] + SS3[0]; //总的相似度; 
 
			 DS[0] = (1-exp(-10*(1-SS[0])));   //差异度; 
      
 
	    
		pThisLine=pThisLine0; 
        pLastLine=pLastLine0; 
 
	// 
		for (y = 0; y < Yn; y++) 
		{ 
			pThisSample = pThisLine; 
			pLastSample = pLastLine; 
			for (int x = 0; x < Xn; x++) 
			{ 
 
				p0=(*pLastSample); 
				p1=(*pThisSample);	 
 
 
				//求单色帧 
				danse=danse+fabs((p1)-Grate[0]); 
                
 
                p_diff=p_diff+fabs(p1-Grate[0]-p0+Grate[1]); 
 
                
				pThisSample = pThisSample + sk2;	// Skip U or V sample 
				pLastSample = pLastSample + sk2; 
			} 
 
			pThisLine = pThisLine + BytesPerLine; 
			pLastLine = pLastLine + BytesPerLine; 
		} 
 
        
 
		   mono[0]=danse/Tn; //"方差"; 
          
		   C1[0]=p_diff/Tn;  //一次帧差;       
 
	 
    } 
 
 
#pragma warning(push) 
#pragma warning(disable:4244)	// turn off conversion from double to float warning 
		// Convert to "confidence" and output result 
 
/********************打印镜头变化处数据 ********************/	 
 
 // for ( int y = 1; y <=480; y++) 
 /* 
  for ( int y =124; y <=325; y++)  //打印DISSOLVE; 
	 {		 
         if (ThisFrameNo >= tab0[y] - 2 && ThisFrameNo <= tab0[y]+tabn[y] + 3 && tabn[y]==2) 
		  { 
	         hr=SendResult(ThisFrameNo,0, Grate[0],C1[0], mono[0],D_hist[0],D_hist_2[0],SS1[0],DS[0]);  
			   break; 
		  }	  
		   
	 } 
*/	 
 
/*************** FADE DETECTION *******************/ 
// 
/* 
 if(ThisFrameNo >5 && mono[5] < 6.5 
	  &&  (Grate[5] < 55.0 || Grate[5] > 177.0 ))   //黑色,灰色; 
{ 
 
       accum_mono[0] += 1;	  //单色帧持续的周长; 
	    
 
   //找cut+fade in类型的OTHS起始位置; 
	 if ( mono[6] > 6.5 && C1[5] >= 17.0) 
	 {     
         startNO[0] =  ThisFrameNo-6; 
		 a0 = 1; 
	 } 
  // FADE OUT 找起始位置; 
     if (( mono[6] > 6.5 
		 ||(mono[6] < 6.5 && Grate[6] > 55.0  && Grate[6] < 100.0) 
		 ||(mono[6] < 6.5 && Grate[6] > 155.0 && Grate[6] < 177.0)) 
		 && C1[5] < 17.0) 
	{ 
      accum0[0]  = accum1[0]=0; 
 
	  dowmNO[0] =   upNO[0] = 0; 
 
      for(int i=0 ; ;i++) 
	  { 
	     if(  mono[5+i] <= mono[6+i]  
			 && (mono[6+i]-mono[5+i]) < 5.0 && (mono[6+i]-mono[5+i]) >= 0.3 //momo分布曲线单调递减,没有突变。 
			 ) 
		 {  
			 accum1[0] += 1; 
 
			 if(accum0[0]==1) 
			 { 
				 accum0[0] =0; 
			 } 
			  
		 } 
 
		  if( (mono[5+i] > mono[6+i]) ||((mono[6+i]-mono[5+i]) < 0.3 && (mono[6+i]-mono[5+i]) >= 0 )) //累计奇异点的个数; 
		  { 
			  accum0[0] +=1;  
		  } 
		   
		 CycNO += 1; //循环次数;  
 
		  if(accum0[0] >=2) //连续出现两个奇异点就终止搜索起始边界; 
			  break; 
			   
	  } 
 
      startNO[0] =  ThisFrameNo-5-(CycNO-2); 
	  
 
	} 
 
      //背景很暗的FADE 
 
    if(mono[6] < 6.5 && mono[5] < 6.5 && mono[4] < 6.5) 
	{ 
 
     if( mono[5] <= mono[4] )  //递增; 
	 { 
 
         dowmNO[0] = 0 ; 
 
		 upNO[0] += 1; 
 
		 if(upNO[0] >= 7 ) 
		 { 
		     
			 if(mono[3] < mono[4] && mono[3] < 6.5 && accum_mono[0] >= 12) 
			 { 
			    EndNO[0] = ThisFrameNo - 5; 
			   
			    if((EndNO[0] - startNO[0]) > 2 &&  (EndNO[0] - startNO[0])  <=128) 
				{ 
                     hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0); 
 
			          dowmNO[0] =   upNO[0] = 0; 
 
					  EndNO[0] = startNO[0] = 0; 
            
				}			   
 
			 } 
		 } 
 
		 	 
	 } 
 
	   
	  if( mono[5] > mono[4])  //递减; 
	 { 
         upNO[0] = 0 ; 
 
		 dowmNO[0] += 1; 
 
		 if(dowmNO[0] == 7 && accum_mono[0] >= 12) 
		 { 
		    startNO[0] = ThisFrameNo - 12; 
		 } 
		  
	 } 
	  
	} 
    
} 
 
 
 
// 
   //fade out  + cut  类型的OTHS的终止边界; 
   if( mono[5] < 6.5  
	   && mono[4] > 6.5  &&  (Grate[5] < 55.0 || Grate[5] > 180.0)  
	   && C1[4] >= 17.0) 
   { 
      EndNO[0] =  ThisFrameNo-4; 
	  a1 = 1; 
 
	  if((EndNO[0] - startNO[0]) > 2 &&  (EndNO[0] - startNO[0])  <=128) 
		{ 
		  if(a0==1 && a1 ==1 
			  && accum_mono[0] >= 2) 
		  { 
		    hr=SendResult(startNO[0] ,startNO[0]+1,0,0,0,0,0,0,0); 
			hr=SendResult(EndNO[0]-1 ,EndNO[0],0,0,0,0,0,0,0); 
		  } 
		  else 
          hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0);		 
		} 
 
	  a0 = 0; 
	  a1 = 0; 
   } 
    
//  
    //找fade in 的终止边界; 
   if( mono[5] < 6.5  
	   &&( mono[4] > 6.5  && (Grate[5] < 55.0 || Grate[5] > 177.0)  
	   ||( mono[4] < 6.5  &&  Grate[4] > 55.0 && Grate[4] < 100.0) 
	   ||( mono[4] < 6.5  && Grate[4] > 155.0 && Grate[4] < 177.0)) 
	   && C1[4] < 17.0) 
	{     
		  accum_mono[0] =0;  
		   
		  b0[0] = mono[5]; 
		  b1[0] = mono[4]; 
 
		  accum0[0]=accum1[0]=0; 
		   
	} 
         
 
   if( ThisFrameNo >7 && b0[0] < 6.5 && b1[0] > 6.5  ) 
   { 
	      if(  mono[5] <= mono[4] && (mono[4]-mono[5]) < 5.0 && (mono[4]-mono[5]) >= 0.3) 
		 {  
			 accum1[0] += 1; 
 
			 if(accum0[0] ==1) 
			 { 
				 accum0[0] =0; 
			 } 
		 }   
	      if((mono[5] > mono[4]) ||((mono[4]-mono[5]) < 0.3 && (mono[4]-mono[5]) >= 0 ))//|| ((mono[4]-mono[5]) > 10.0)) 
		 { 
			  accum0[0] +=1;  
		 } 
 
 
		  if(accum0[0] >=2) 
		  { 
			  EndNO[0] =  ThisFrameNo-7;			   
 
			  b0[0] =b1[0] = 0.0;  //fade 结束时清零; 
 
            if((EndNO[0] - startNO[0]) > 2 &&  (EndNO[0] - startNO[0])  <=128) 
			{ 
             hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0);		 
			} 
		  }   
    }  
*/ 
 
/*************  CUT  DETECTION*****************/ 
//特征:相异度DS; 
 
 
if(   ThisFrameNo >7 
   && mono[3] > 6.5 &&  mono[4] >= 6.5 // eliminate 单色帧 
   && DS[3] == max(max(max(max(max(max(DS[0],DS[1]),DS[2]),DS[3]),DS[4]),DS[5]),DS[6]) 
   ) 
{ 
	// 
   if(DS[3] >= 0.90 && max(max(max(DS[1],DS[2]),DS[4]),DS[5]) <= 0.7 
   && DS[3] >= 1.40* max(DS[4],DS[2]) 
   ) 
   { 
      hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,DS[6],DS[5],DS[4],DS[3],DS[2],DS[1],DS[0]); 
	  //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34); 
   } 
 
// 
   else if( DS[3] >= 0.80  && DS[3] < 0.90 && max(max(max(DS[1],DS[2]),DS[4]),DS[5]) <= 0.50 
         && DS[3] >= 2.10* max(DS[4],DS[2]) 
   ) 
   { 
      hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,DS[6],DS[5],DS[4],DS[3],DS[2],DS[1],DS[0]); 
	  //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34); 
   } 
 
// 
   else if(DS[3] >= 0.95   
   && max(max(max(DS[1],DS[2]),DS[4]),DS[5]) >  0.70 
   && max(max(max(DS[1],DS[2]),DS[4]),DS[5]) <= 0.80 
   && DS[3] >= 1.23*max(DS[4],DS[2]) 
   ) 
   { 
      hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,DS[6],DS[5],DS[4],DS[3],DS[2],DS[1],DS[0]); 
	  //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34); 
   } 
 
// 
    else if(DS[3] >= 0.95   
   && max(max(max(DS[1],DS[2]),DS[4]),DS[5]) >  0.80 
   && max(max(max(DS[1],DS[2]),DS[4]),DS[5]) <= 0.90 
   && DS[3] >= 1.12*max(DS[4],DS[2]) 
   ) 
   { 
      hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,DS[6],DS[5],DS[4],DS[3],DS[2],DS[1],DS[0]); 
	  //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34); 
   } 
 
 
} 
 
 
//特征:一次帧差C1; 
/* 
double Mean_0,Mean_1,Mean_2; 
       Mean_0 = (C1[0]+C1[1]+C1[2]+C1[4]+C1[5]+C1[6])/6.0; 
       Mean_1 = (C1[1]+C1[2]+C1[4]+C1[5])/4.0; 
       Mean_2 = (C1[2]+C1[4])/2.0; 
 
 if(     ThisFrameNo >7 
	  && Grate[3] >= 35.0 &&  Grate[4] >= 35.0 // eliminate 单色帧 
   ) 
 { 
   // 
   if(C1[3] >= 35.0) 
   { 
	   if(     Mean_0 <= 10.5 
            && Mean_1 <= 10.5 
            && Mean_2 <= 10.5 
            && C1[3] >= 5.0*Mean_0 
            && C1[3] >= 5.1*Mean_1 
            && C1[3] >= 4.9*Mean_2 
            && C1[3] >= 3.9*max(C1[2],C1[4])//3.9 
         ) 
	   { 
            hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,	D_hist[6],D_hist[5],D_hist[4],D_hist[3],D_hist[2],D_hist[1],D_hist[0]); 
	   //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34); 
	   } 
   } 
   
    
   // 
   else if(C1[3] >= 20.0 &&  C1[3] < 35.0) 
   { 
        if(   Mean_0 <= 4.5 
           && Mean_1 <= 4.9 
           && Mean_2 <= 6.1 
           && C1[3] >= 5.4*Mean_0 
           && C1[3] >= 4.4*Mean_1 
           && C1[3] >= 5.3*Mean_2 
           && C1[3] >= 3.4*max(C1[2],C1[4]) 
           ) 
		{               
              hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,D_hist[6],D_hist[5],D_hist[4],D_hist[3],D_hist[2],D_hist[1],D_hist[0]); 
		     //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34);   
		} 
   }  
    
 
   // 
   else if( C1[3] >= 10.0 &&  C1[3] < 20.0) 
   { 
      if( 
		    Mean_0 <= 3.4 
         && Mean_1 <= 3.8  
         && Mean_2 <= 4.3 
		 && C1[3] >= 4.8*Mean_0 
         && C1[3] >= 4.5*Mean_1 
         && C1[3] >= 4.0*Mean_2 
         && C1[3] >= 3.3*max(C1[2],C1[4])//5.2 
		 ) 
	     { 
            hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
	   //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34); 
	     } 
   } 
} 
 */ 
 
/**********2_LEN  dissolve detection  *****************/ 
//特征:相异度,灰度直方图差,一次帧差;  
 
 
/* 
double    Mean_DS,Mean_Dhist,Mean_C1; 
          Mean_DS = (DS[0] + DS[1] + DS[2] + DS[5] + DS[6] + DS[7] )/6; 
          Mean_Dhist = (D_hist[0] + D_hist[1] + D_hist[2] + D_hist[5] + D_hist[6] + D_hist[7] )/6; 
          Mean_C1 = (C1[0] + C1[1] + C1[2] + C1[5] + C1[6] + C1[7] )/6; 
 
 if(   ThisFrameNo >7  
   // 
   && Grate[2] > 35.0 && Grate[3] > 35.0 && Grate[4] > 35.0 && Grate[5] > 35.0 && Grate[6] > 35.0   
   // 
   && min(DS[4],DS[3]) >= 0.45 
   && DS[3] == max(max(max(DS[0],DS[1]),DS[2]),DS[3]) 
   && DS[4] == max(max(max(DS[4],DS[5]),DS[6]),DS[7]) 
   && max(DS[4],DS[3]) <= 3.0 * min(DS[4],DS[3]) 
   && min(DS[4],DS[3]) >= 1.5 * Mean_DS 
   // 
   && Mean_Dhist <= 0.2 
   && D_hist[3] == max(max(max(D_hist[0],D_hist[1]),D_hist[2]),D_hist[3]) 
   && D_hist[4] == max(max(max(D_hist[4],D_hist[5]),D_hist[6]),D_hist[7]) 
   && max(D_hist[4],D_hist[3]) <= 5.0 * min(D_hist[4],D_hist[3])  //系数2.0,3.5 
   && min(D_hist[4],D_hist[3]) >= 2.6 * Mean_Dhist      //2.2 
   && (D_hist[3]+D_hist[4]) >= 0.68  //0.45 
   &&min(min(min( D_hist_2[1],D_hist_2[2]),D_hist_2[3]),D_hist_2[4]) >= 0.20 // eliminate  Flash; 
   // 
//   && Mean_C1 <= 7.0  //5.0 
//   && C1[3] == max(max(max(C1[0],C1[1]),C1[2]),C1[3]) 
//   && C1[4] == max(max(max(C1[4],C1[5]),C1[6]),C1[7]) 
//   && max(C1[4],C1[3]) <= 4.8 * min(C1[4],C1[3]) //系数4.0 
//   && min(C1[4],C1[3]) >= 1.7 * Mean_C1 
  ) 
{     
	 if(Grate[4]-Grate[5] > 9.0 && Grate[4]-Grate[3] > 9.0)  // eliminate  Flash; 
	 { 
	     if(    D_hist_2[2] >= 0.85 
			 && D_hist_2[3] >= 0.85 
			 && D_hist_2[4] >= 0.85 
			 && D_hist_2[5] <= 0.1)  //flash occurs during a cut; 
		 { 
		      hr=SendResult(ThisFrameNo-5,ThisFrameNo-4,C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
	   //   hr=SendResult(34,67,34,34,ThisFrameNo-5,34,34,ThisFrameNo-4,34); 
		 } 
		 else  //flash; 
			 ; 
	 } 
 
	else  
	{ 
	     hr=SendResult(ThisFrameNo-5,ThisFrameNo-3,	C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
    //   hr=SendResult(34,68,34,34,ThisFrameNo-5,34,34,ThisFrameNo-3,34); 
	}  
    		    
} 
 
else if (  D_hist[4] >= 0.2 && D_hist[3] >= 0.2 && D_hist[4] + D_hist[3] >= 0.85 
		 && D_hist[0] <= 0.1  
		 && D_hist[1] <= 0.1  
		// && D_hist[2] <= 0.1 
		// && D_hist[5] <= 0.1  
		 && D_hist[6] <= 0.1  
		 && D_hist[7] <= 0.1 
		 && Mean_Dhist <= 0.1 
		 ) 
{   
	if(Grate[4]-Grate[5] > 9.0 && Grate[4]-Grate[3] > 9.0)  // eliminate  Flash; 
	{ 
	    if(    D_hist_2[2] >= 0.85 
			 && D_hist_2[3] >= 0.85 
			 && D_hist_2[4] >= 0.85 
			 && D_hist_2[5] <= 0.1)  //flash occurs during a cut; 
		 { 
		      hr=SendResult(ThisFrameNo-5,ThisFrameNo-4,C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
	   //   hr=SendResult(34,67,34,34,ThisFrameNo-5,34,34,ThisFrameNo-4,34); 
		 } 
		 else  //flash; 
			 ; 
	 }  
	// 
	else if( (max(C1[3],C1[4]) >= 9.0*min(C1[3],C1[4]) && max(C1[5],C1[4]) >= 9.0*min(C1[5],C1[4])) 
		  ||(max(C1[3],C1[2]) >= 9.0*min(C1[3],C1[2]) && max(C1[3],C1[4]) >= 9.0*min(C1[3],C1[4])) 
		   ) //  eliminate  cut;  
	{ 
	    if(max(C1[3],C1[4]) ==  C1[4]) 
		 { 
             hr=SendResult(ThisFrameNo-5,ThisFrameNo-4,C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
	   //   hr=SendResult(34,67,34,34,ThisFrameNo-5,34,34,ThisFrameNo-4,34);  
		 } 
		 else 
		 { 
              hr=SendResult(ThisFrameNo-4,ThisFrameNo-3,C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
	   //   hr=SendResult(34,67,34,34,ThisFrameNo-4,34,34,ThisFrameNo-3,34);  
		 } 
 
	}  
	// 
	else 
     	hr=SendResult(ThisFrameNo-5,ThisFrameNo-3,	C1[6],C1[5],C1[4],C1[3],C1[2],C1[1],C1[0]); 
} 
 
*/ 
/* 
//afanty's code: 
			if ( C1[5]>=20.0&& C1[4]>=20.0 && C1[3]<=4.1&& C1[2]<=4.8 && C1[6]<=2.77 && C1[7]<=3.8 
				 && fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				 && C1[5]>C1[6] && C1[4]>C1[3]  
				 && mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 ) 
	         hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);   
	 
			else if (   C1[5]<20.0 && C1[5]>10.0  
				&& C1[4]<20.0 && C1[4]>10.0  
				&& C1[3]<=3.5 
				&& (C1[2]<=2.9 || fabs(Grate[1]-Grate[3])<2.0)//防止闪光 
				&& C1[6]<=6.1  
				&& (C1[7]<=6.64|| fabs(Grate[6]-Grate[8])<2.0) 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& C1[5]>C1[6] && C1[4]>C1[3]  
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 ) 
	         hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0);	 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
 
			else if (   C1[5]<10.0 && C1[5]>4.3 
				&& C1[4]<10.0 && C1[4]>4.3 
				&& C1[3]<=2.76 
				&& (C1[2]<=2.5 || fabs(Grate[1]-Grate[3])<2.0)//防止闪光 
				&& C1[6]<=2.76  
				&& (C1[7]<=3.3|| fabs(Grate[6]-Grate[8])<2.0) 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& C1[5]>C1[6] && C1[4]>C1[3]  
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 ) 
	         hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
			 			  
			else if (   C1[5]>20.0  
				&& C1[4]<20.0 && C1[4]>10.0  
				&& C1[5]>C1[6] && C1[4]>C1[3]  
				&& (C1[3]<6.1||fabs(C1[3]-C1[2])<2.0)//防止晃动  
				&& (C1[6]<5.2||fabs(C1[6]-C1[7])<2.0)//防止晃动 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 ) 
	         hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
			  
			 else if (   C1[4]>20.0  
				&& C1[5]<20.0 && C1[5]>10.0  
				&& C1[5]>C1[6] && C1[4]>C1[3]  
				&& (C1[6]<6.1||fabs(C1[6]-C1[7])<2.0)//防止晃动 
				&& (C1[3]<5.2||fabs(C1[3]-C1[2])<2.0)//防止晃动 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 ) 
	         hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0);	 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
			 
			else if (   C1[5]<20.0 && C1[5]>10.0 
				&& C1[5]-C1[6]>5.0 && C1[4]>C1[3]  
				&& C1[4]<10.0 && C1[4]>4.0  
				&& (C1[3]<4.4||fabs(C1[3]-C1[2])<2.0)//防止晃动 
				&& (C1[6]<2.8||fabs(C1[6]-C1[7])<2.0)//防止晃动 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 )			 
			 hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
 
			  
 
			else if (   C1[4]<20.0 && C1[4]>10.0 
				&& C1[4]-C1[3]>5.0 && C1[5]>C1[6]  
				&& C1[5]<10.0 && C1[5]>4.0  
				&& (C1[6]<4.4||fabs(C1[6]-C1[7])<2.0)//防止晃动 
				&& (C1[3]<2.8||fabs(C1[3]-C1[2])<2.0)//防止晃动 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 )			 
			 hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
		//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
 
 
			 
			else if (   C1[5]>20.0 
				&& C1[4]<10.0 && C1[4]>4.0  
				&& C1[5]-C1[6]>5.0 && C1[4]>C1[3]  
				&& (C1[6]<6.7||fabs(C1[6]-C1[7])<2.0)//防止晃动 
				&& (C1[3]<4.2||fabs(C1[3]-C1[2])<2.0)//防止晃动 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 )			 
				 hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
			//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
 
			 
			else if (   C1[4]>20.0 
				&& C1[5]<10.0 && C1[5]>4.0  
				&& C1[4]-C1[3]>5.0 && fabs(C1[5]-C1[6])>1.5  
				&& (C1[3]<6.7||fabs(C1[3]-C1[2])<2.0)//防止晃动 
				&& (C1[6]<4.2||fabs(C1[6]-C1[7])<2.0)//防止晃动 
				&& fabs(Grate[7]-Grate[2])>2.2//防止闪光 
				&& mono[6]>6.5 &&mono[5]>6.5&&mono[4]>6.5&&mono[3]>6.5 
				 )			 
				 hr=SendResult(ThisFrameNo-5-1,ThisFrameNo-5+1,0,0,0,0,0,0,0); 
			//   hr=SendResult(34,68,34,34,ThisFrameNo-6,34,34,ThisFrameNo-4,34);  
 
			 
*/ 
 /******  short gradual transition detection **********/ 
   //用的特征是灰度直方图差  D_hist[0]; 
 /*  
if( D_hist[5] >= 0.1 && D_hist[5] < 0.85 
   && C1[5] >= 4.0     
   &&  D_hist[6] < 0.08 
   &&  D_hist[5] / D_hist[6] >= 2.3  
   &&  mono[5] > 10.0  
   && cnt == 0 ) 
  { 
     cnt += 1; 
     acc_hist += D_hist[5]; 
  } 
else if (   D_hist[5] >= 0.1 && D_hist[5] < 0.85 
		 && D_hist[6] >= 0.1 && D_hist[6] < 0.85 
		 && C1[5] >= 4.0  
		 && (max(C1[5],C1[6])/min(C1[5],C1[6])) <= 4.0  
		 && (max(D_hist[5],D_hist[6])/min(D_hist[5],D_hist[6])) <= 3.0		      
         && mono[5] > 10.0  
		 && cnt >= 1 ) 
 {  
     cnt += 1; 
     acc_hist += D_hist[5]; 
  } 
else 
{      
	  if(D_hist[5] >= 0.85) 
		  ; 
	  else if( cnt > 2 && cnt < 8 && acc_hist >= 0.85  && mono[5] > 10.0) //检测部分短渐变; 
      {      
		 for ( int i = 0; i < cnt; i++)						 
		 {		 
		  savemono[i]= mono[cnt + 5 - i];           
		 }  
 
	      double  MINMONO;	 
			   MINMONO=100.0; 
		  int     SignNO;  
 
	      for( i = 0; i < cnt; i++) 
		  {			   
	       MINMONO =min(MINMONO,savemono[i]);	 
		  } 
 
		  for(i = 0; i < cnt; i++) 
		  { 
			if(savemono[i] == MINMONO) 
			 { 
				  SignNO = i; 
				  break; 
			 }			  
		  } 
 
		  int acc_odd; 
		      acc_odd=0; 
 
		  for( i = 0;i < SignNO; i++) 
		  { 
             if(savemono [i] < savemono[i+1]) 
			 { 
			   acc_odd += 1; 
			 } 
		  } 
 
		  for( i = SignNO+1;i < cnt; i++) 
		  { 
            if(savemono [i-1] > savemono[i]) 
			 { 
			   acc_odd += 1; 
			 } 
		  } 
		   
 
       if(acc_odd == 0  && mono[7] < mono[6] ) 
	   { 
		     if(mono[5] < mono[4] && mono[4] < mono[3]  
				 && fabs(mono[5]-mono[6]) < 0.3  
				 ) 
			 ; 
		else if(mono[5] > mono[4] && mono[4] > mono[3] 
		        && fabs(mono[5]-mono[6]) < 0.3  
			    ) 
			 ; 
		else if(mono[5+cnt+2] > mono[5+cnt+1] && mono[5+cnt+1] > mono[5+cnt] 
		    	&& fabs(mono[5+cnt+1]-mono[5+cnt]) < 0.3 
		     	) 			 
			 ; 
		else if(mono[5+cnt+2] < mono[5+cnt+1] && mono[5+cnt+1] < mono[5+cnt]  
			    && fabs(mono[5+cnt+1]-mono[5+cnt]) < 0.3 
			) 
			 ; 
        else	 
         
		 hr=SendResult(ThisFrameNo-5-cnt-1,ThisFrameNo-5-1,0,0,0,0,0,0,0); 
				 
	   } 
 
      } 
       cnt = 0; 
       acc_hist = 0; 
}   
*/ 
 
/****************   DISSOLVE DETECTION *****************/ 
 /* 
int SignNO; 
 double threshold; 
        threshold = 0.07; 
  
  //start; 
  if( C1[5] <= 20.0  && D_hist[5] >= threshold && cnt == 0 ) 
  { 
     if( fabs( mono[6]- mono[5]) >= 0.3 ) 
	  cnt = 1; 
	 else  
	  cnt = 0; 
  } 
  // 
  else if( C1[5] <= 20.0 && D_hist[6] >= threshold && D_hist[5] >= threshold && cnt >= 1) 
  { 
      cnt += 1;  
  } 
 //tolerance one singular point; 
  else if(  C1[5] <= 20.0 && D_hist[6] >= threshold && D_hist[5] < threshold  && D_hist[4] >= threshold && D_hist[3] >= threshold && cnt >= 1) 
  {  
      cnt += 1;  
  } 
  // 
  else if( C1[5] <= 20.0 && D_hist[7] >= threshold && D_hist[6] < threshold  && D_hist[5] >= threshold && D_hist[4] >= threshold && cnt >= 1) 
  {  
      cnt += 1;  
  } 
  //end; 
  else if(  (  C1[5] <= 20.0 && D_hist[7] >= threshold && D_hist[6] >= threshold && D_hist[5] < threshold && D_hist[4] < threshold  && cnt >= 1 )	       
		  ||(  C1[5] <= 20.0 && D_hist[6] >= threshold && D_hist[5] < threshold && D_hist[4] >= threshold && D_hist[3] < threshold  && cnt >= 1 ) 
		  ||(  C1[5] > 20.0 && cnt >= 1 )		   
		  ) 
  {   
    // if(cnt >=8 && cnt <= 250) 
	 //  hr=SendResult(ThisFrameNo-6-cnt,ThisFrameNo-5,0,0,0,0,0,0,0); 
	 //  cnt = 0 ; 
       
    if(cnt >=8 && cnt <= 250)	 
	{  
 
	  for ( int i = 0; i < cnt; i++)						 
	  {		 
		  savemono[i]= mono[cnt + 5 - i]; 
           
	  }  
 
	   double  MINMONO;	 
			   MINMONO=100.0; 
 
	       for( i = 0; i < cnt; i++) 
			 {			   
	            MINMONO =min(MINMONO,savemono[i]);	 
			 } 
 
			for(i = 0; i < cnt; i++) 
			{ 
			  if(savemono[i] == MINMONO) 
			  { 
				  SignNO = i; 
				  break; 
			  } 
			  
			}            
             
        if( SignNO <= 1) //单增; 
		{  
		  startNO[0] =  ThisFrameNo-6-cnt; 
 
		  for(i = 2; i < cnt-2; i++) 
		  {   
			// if(savemono[i] >savemono[i+1] && savemono[i+1] < savemono[i+2]) 
			// { 
			//    ac_odd += 1; 
		//	 } 
		     if(savemono[i] >= savemono[i+1] && savemono[i+1] >= savemono[i+2]) 
			  { 
                  EndNO[0] = ThisFrameNo-5-cnt + i;  
				  break; 
			  } 			 
		  } 
 
		  if(EndNO[0]==0) 
            EndNO[0] =  ThisFrameNo-5; 
             
		  hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0); 
			   
		  EndNO[0] = startNO[0]  = 0; 
		   
		  cnt = 0; 
 
		} 
 
		else if(SignNO >=  cnt-2) //单减; 
		{ 
		    EndNO[0] = ThisFrameNo - 5; 
			 
			for(i = cnt-2; i > 1; i--) 
			{ 
			  if(savemono[i] >= savemono[i-1] && savemono[i-1] >= savemono[i-2]) 
			  { 
                  startNO[0] = ThisFrameNo-6-cnt + i;  
				  break; 
			  }			  
			} 
 
			if(startNO[0]==0) 
               startNO[0] =  ThisFrameNo-6-cnt; 
 
			 hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0); 
			   
		     EndNO[0] = startNO[0]  = 0; 
 
			 cnt = 0; 
 
 
		} 
 
		else  
		{ 
			for(i = SignNO; i > 1; i--)       
			{ 
			   
			  if(savemono[i] >= savemono[i-1] && savemono[i-1] >= savemono[i-2]) 
			  { 
                  startNO[0] = ThisFrameNo-6-cnt + i;  
				  break; 
			  }			  
			} 
 
			if(startNO[0]==0) 
               startNO[0] =  ThisFrameNo-6-cnt; 
 
 
			for(i = SignNO; i < cnt-2;i++) 
			{ 
			  if(savemono[i] >= savemono[i+1] && savemono[i+1] >= savemono[i+2]) 
			  { 
                  EndNO[0] =  ThisFrameNo-5-cnt + i;  
				  break; 
			  }			  
			} 
 
			if(EndNO[0]==0) 
              EndNO[0] =  ThisFrameNo-5; 
             
			 hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0); 
			   
			 EndNO[0] = startNO[0]  = 0; 
 
			 cnt = 0; 
 
		} 
           
	} 
	else 
	{ 
	   cnt = 0; 
	} 
	 
  } 
  // 
  else 
  { 
	 cnt = 0;  
  } 
*/  
/* 
 if( Grate[5] >= 45.0 && C1[5] <= 20.0  && D_hist[5] >= 0.1) 
  {      
      if( mono[6] > mono[5]// && mono[5] > mono[4]) 
		 // ||(mono[6] < mono[5] && fabs(mono[6] - mono[5]) < 0.2 && mono[5] > mono[4]) 
		  ) //递减; 
	  {    		 
		   upNO[0] =  0 ; 		    
 
		   dowmNO[0] += 1; 
 
		   if( mono[5] < mono[4]// && mono[4] < mono[3]  
			   && D_hist[4] >= 0.1)  
		   {			 
			   startNO[0] = (ThisFrameNo -5) - (dowmNO[0]) ; 
			    
			   signNO[0]  = ThisFrameNo -5;			   
		   } 
		    
	  } 
 
	  if(mono[6] <= mono[5]  
		  //&& mono[5] <= mono[4]) 
	//	 ||(mono[6] > mono[5] && fabs(mono[6] - mono[5]) < 0.2 && mono[5] < mono[4])  
		 ) //递增; 
	  {  
		   dowmNO[0] =  0 ; 	 
 
		   upNO[0] += 1;  
 
		   if( mono[5] >= mono[4] //&& mono[4] >= mono[3]) 
			   || D_hist[4] < 0.1 ) 
		   {			 
			   EndNO[0] = ThisFrameNo - 5; 
		   }  
 
	  } 
	    
  } 
 
  else  
  {     	    
	     EndNO[0] = startNO[0]  = 0; 
			   
	     upNO[0] = dowmNO[0] = 0;      
  } 
        
   
  if( (EndNO[0] - startNO[0]) >= 8 && (EndNO[0] - startNO[0]) <= 128 && EndNO[0] - signNO[0] == upNO[0]) 
	{ 
             hr=SendResult(startNO[0] ,EndNO[0],0,0,0,0,0,0,0); 
			   
			 EndNO[0] = startNO[0]  = 0; 
			   
			 upNO[0] = dowmNO[0] = 0;				 
			 
	} 
*/ 
 
 
 
 
/* 
  //   中间只出现一帧单色帧的OTH 检测(mono) 
 if( mono[5] < 5.0 
   && mono[4] > 20.0 &&  mono[6] > 20.0 
   && (mono[4] > mono[3] || mono[6] > mono[7] ) //单色帧两侧 mono不满足单调性(区分FADE); 
   ) 
    hr=SendResult(ThisFrameNo-6,ThisFrameNo-4,0,0,0,0,0,0,0);	 
 // 中间只出现两帧单色帧的OTH 检测(mono) 
 if( mono[5] < 5.0 && mono[4] < 5.0 
   && mono[3] > 20.0 &&  mono[6] > 20.0 
   && (mono[3] > mono[2] || mono[6] > mono[7] ) //单色帧两侧 mono不满足单调性(区分FADE); 
   ) 
    hr=SendResult(ThisFrameNo-6,ThisFrameNo-3,0,0,0,0,0,0,0); 
*/ 
 
				if (FAILED(hr)) 
					return hr; 
 
#pragma warning(pop) 
 
	// Release last sample 
	if (pLastFrame != NULL) 
	{ 
		pLastFrame->Release(); 
		pLastFrame = NULL; 
	} 
 
	// Hold on to this sample 
	pLastFrame = pThisFrame; 
	pLastFrame->AddRef(); 
	 
	// Pass on video frame 
	if (pVideoOutput->IsConnected()) 
	{ 
		hr = pVideoOutput->Deliver(pThisFrame); 
		if (FAILED(hr)) 
			return hr; 
	} 
 
	return S_OK; 
} 
 
 
 
 
// HRESULT CCutDetector::SendResult(const int FrameNo, const float Confidence, const int Duration) 
HRESULT 
CCutDetector::SendResult(const int FrameNo, const int f1,const float f2,const float f3,const float f4,const float I1,const float  I2,const float I3,const float I4) 
{ 
	IMediaSample			*pOutput; 
	char					*pOutData; 
	HRESULT					hr = S_OK; 
 
	if (pTextOutput->IsConnected()) 
	{ 
		// Get a buffer from the cut detector output pin's allocator 
		hr = pTextOutput->GetDeliveryBuffer(&pOutput, NULL, NULL, 0); 
		if (FAILED(hr)) 
			return hr; 
 
		// Set sample properties 
		pOutput->SetTime(NULL, NULL); 
		pOutput->SetSyncPoint(FALSE); 
		pOutput->SetDiscontinuity(TRUE); 
		pOutput->SetPreroll(FALSE); 
		pOutput->SetMediaTime(NULL, NULL); 
 
		// Copy message to buffer 
		hr = pOutput->GetPointer((BYTE**)&pOutData); 
		if (FAILED(hr)) 
			return hr; 
		sprintf(pOutData, "%9d\t%9d\t%9g\t%9g\t%9g\t%9g\t%9g\t%9g\t%9g\n",FrameNo,f1,f2,f3,f4,I1,I2,I3,I4); 
		//sprintf(pOutData, "%8d %14g %4d", FrameNo, Confidence, Duration); 
		hr = pOutput->SetActualDataLength(1 + strlen(pOutData)); 
		if (FAILED(hr)) 
			return hr; 
 
		// Deliver the output 
		hr = pTextOutput->Deliver(pOutput); 
		pOutput->Release(); 
		if (FAILED(hr)) 
			return hr; 
	} 
 
	if (Params.pCallBack != NULL) 
	{ 
		 
			if (Params.pCallBack(FrameNo,f1,f2,f3,f4,I1,I2,I3,I4) != 0) 
		//if (Params.pCallBack(FrameNo,f1,f2,f3,f4,I1,I2) != 0) 
			// Application wants to abort - what can we do if we aren't a renderer? 
			if ((GetMiscFlags() & AM_FILTER_MISC_FLAGS_IS_RENDERER) != 0) 
			{ 
				// Send an EC_COMPLETE event to stop the graph 
				hr = NotifyEvent(EC_COMPLETE, 0, 0); 
				if (FAILED(hr)) 
					return hr; 
			} 
	} 
 
	return hr; 
} 
 
 
VideoInPin::VideoInPin(CBaseFilter *pFilter, CCritSec *pLock, HRESULT *phr) : 
	CBaseInputPin(NAME("cut detector input"), pFilter, pLock, phr, 
		psudPins[VideoInputNo].strName) 
{ 
} 
 
STDMETHODIMP 
VideoInPin::EndOfStream(void) 
{ 
    CAutoLock	LockStream(&StreamLock); 
	HRESULT		hr; 
 
	hr = ((CCutDetector*)m_pFilter)->EndOfStream(); 
	if (FAILED(hr)) 
		return hr; 
 
	return CBaseInputPin::EndOfStream(); 
} 
 
STDMETHODIMP 
VideoInPin::BeginFlush(void) 
{ 
    CAutoLock	LockFilter(m_pLock); 
	HRESULT		hr; 
 
	// First, make sure any VideoInPin::Receive that starts from now on will terminate immediately 
	hr = CBaseInputPin::BeginFlush(); 
	if (FAILED(hr)) 
		return hr; 
 
	// Deliver BeginFlush to all the filter's output pins 
	hr = ((CCutDetector*)m_pFilter)->DeliverBeginFlush(); 
	if (FAILED(hr)) 
		return hr; 
 
	// Lock the stream here to wait for any running VideoInPin::Receive to finish 
    CAutoLock		LockStream(&StreamLock); 
 
	// Release any samples we're holding 
	((CCutDetector*)m_pFilter)->ReleaseSamples(); 
 
	return hr; 
} 
 
STDMETHODIMP 
VideoInPin::EndFlush(void) 
{ 
    CAutoLock	LockFilter(m_pLock); 
	HRESULT		hr; 
 
	hr = ((CCutDetector*)m_pFilter)->DeliverEndFlush(); 
	if (FAILED(hr)) 
		return hr; 
 
	return CBaseInputPin::EndFlush(); 
} 
 
STDMETHODIMP 
VideoInPin::Receive(IMediaSample *pSample) 
{ 
    CAutoLock		LockStream(&StreamLock); 
	HRESULT			hr; 
 
	// Check that all is well (implemented in the base class) 
	hr = CBaseInputPin::Receive(pSample); 
	if (hr != S_OK) 
		return hr; 
 
	// Main filter class does all the work 
	return ((CCutDetector*)m_pFilter)->Receive(pSample); 
} 
 
HRESULT 
VideoInPin::SetMediaType(const CMediaType *pmt) 
{ 
	HRESULT		hr; 
 
	hr = CBasePin::SetMediaType(pmt); 
	if (FAILED(hr)) 
		return hr; 
	return ((CCutDetector*)m_pFilter)->SetMediaType(pmt); 
} 
 
HRESULT 
VideoInPin::CheckMediaType(const CMediaType *pmt) 
{ 
	if (*pmt->Type() != MEDIATYPE_Video || 
		*pmt->Subtype() != MEDIASUBTYPE_YUY2) 
		return VFW_E_TYPE_NOT_ACCEPTED; 
 
	// is downstream filter happy with this type? 
	if (m_pFilter->GetPin(VideoOutputNo)->IsConnected()) 
		return m_pFilter->GetPin(VideoOutputNo)->GetConnected()->QueryAccept(pmt); 
 
	return S_OK; 
} 
 
HRESULT 
VideoInPin::GetMediaType(int iPosition, CMediaType *pMediaType) 
{ 
    CAutoLock	LockFilter(m_pLock); 
	HRESULT		hr; 
 
	if (iPosition < 0) 
		return E_INVALIDARG; 
	if (iPosition > 0) 
		return VFW_S_NO_MORE_ITEMS; 
	if (m_pFilter->GetPin(VideoOutputNo)->IsConnected()) 
	{ 
		// Can only accept connections of the same type 
		hr = pMediaType->Set(((VideoOutPin*)m_pFilter->GetPin(VideoOutputNo))->CurrentMediaType()); 
		if (FAILED(hr)) 
			return hr; 
	} 
	else 
	{ 
		// Specify our preferred media type 
		pMediaType->InitMediaType(); 
		pMediaType->SetType(&MEDIATYPE_Video); 
		pMediaType->SetSubtype(&MEDIASUBTYPE_YUY2); 
	} 
	return S_OK; 
} 
 
HRESULT 
VideoInPin::CompleteConnect(IPin *pReceivePin) 
{ 
	HRESULT					hr; 
 
	if (m_pFilter->GetPin(VideoOutputNo)->IsConnected()) 
	{ 
		// Reconnect output pin to make sure it uses the input's allocator and media type 
		hr = m_pFilter->ReconnectPin(m_pFilter->GetPin(VideoOutputNo), &m_mt); 
		if (FAILED(hr)) 
			return hr; 
	} 
 
	// Pass the call on to the base class 
	return CBaseInputPin::CompleteConnect(pReceivePin); 
} 
 
// NotifyAllocator is overridden as we can't trust the upstream filter to allocate an extra 
// buffer if we had reqested it with GetAllocatorRequirements. 
STDMETHODIMP 
VideoInPin::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly) 
{ 
	CAutoLock				LockFilter(m_pLock); 
	ALLOCATOR_PROPERTIES	Actual, Request; 
	HRESULT					hr; 
 
	// Get allocator properties set by upstream filter 
	hr = pAllocator->GetProperties(&Actual); 
	if (FAILED(hr)) 
		return hr; 
 
	// Set our requirements (one extra buffer) 
	Request = Actual; 
	Request.cBuffers = Request.cBuffers + 1; 
 
	hr = pAllocator->SetProperties(&Request, &Actual); 
	if (FAILED(hr)) 
		return hr; 
 
	// Check that our request has been met 
	if (Actual.cBuffers < Request.cBuffers || 
		Actual.cbBuffer < Request.cbBuffer || 
		Actual.cbAlign  < Request.cbAlign  || 
		Actual.cbPrefix < Request.cbPrefix) 
		return E_FAIL; 
 
	// Notify the base class about the allocator 
	return CBaseInputPin::NotifyAllocator(pAllocator, bReadOnly); 
} 
 
ConvertSampleTime::ConvertSampleTime() 
{ 
	FrameDuration = 400000; 
	LastStartTime = 0; 
	RefTime = 0; 
	RefFrame = 0; 
	FrameCount = 0; 
	TimeOffset = 0; 
	FDError = 0; 
} 
 
void 
ConvertSampleTime::ReStart() 
{ 
	LastStartTime = 0; 
	RefTime = 0; 
	RefFrame = 0; 
	FrameCount = 0; 
	TimeOffset = 0; 
	FDError = 0; 
} 
 
void 
ConvertSampleTime::SetMediaType(const AM_MEDIA_TYPE *pmt) 
{ 
	if (pmt->formattype == FORMAT_VideoInfo) 
		FrameDuration = ((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame; 
	else if (pmt->formattype == FORMAT_VideoInfo2) 
		FrameDuration = ((VIDEOINFOHEADER2*)pmt->pbFormat)->AvgTimePerFrame; 
} 
 
inline REFERENCE_TIME 
ConvertSampleTime::rdiv(const REFERENCE_TIME a, const REFERENCE_TIME b) 
{ 
	if (a > 0) 
		return (a + (b / 2)) / b; 
	else 
		return (a - (b / 2)) / b; 
} 
 
int 
ConvertSampleTime::GetFrameNo(IMediaSample *pSample) 
{ 
	REFERENCE_TIME	ThisFrameNo; 
	REFERENCE_TIME	TimeError; 
	REFERENCE_TIME	CorrDuration; 
	REFERENCE_TIME	StartTime, StopTime; 
 
	if (pSample->GetMediaTime(&StartTime, &StopTime) != S_OK) 
		if (pSample->GetTime(&StartTime, &StopTime) != S_OK) 
			return -1; 
 
	CorrDuration = FrameDuration + rdiv(FDError, TimeScale); 
	ThisFrameNo = rdiv(StartTime - TimeOffset, CorrDuration); 
 
	TimeError = (StartTime - LastStartTime) - FrameDuration; 
	if (TimeError < -2000 || TimeError > 2000) 
		// Major glitch in frame duration - reset reference point after more frames have arrived 
		FrameCount = -20; 
 
	if (FrameCount == 0) 
	{ 
		RefTime = StartTime; 
		RefFrame = ThisFrameNo; 
	} 
	 
	if (FrameCount > 500) 
	{ 
		// Have large enough time interval to compute slope 
		TimeError = (StartTime - RefTime) - (FrameDuration * (ThisFrameNo - RefFrame)); 
		TimeError = rdiv(TimeError * TimeScale, ThisFrameNo - RefFrame); 
		FDError = FDError + rdiv(TimeError - FDError, 1000); 
		// Adjust offset 
		CorrDuration = FrameDuration + rdiv(FDError, TimeScale); 
		TimeOffset = RefTime - (CorrDuration * RefFrame); 
	} 
 
	LastStartTime = StartTime; 
	FrameCount = FrameCount + 1; 
 
	return (int)ThisFrameNo; 
} 
 
QueuedOutputPin::QueuedOutputPin(TCHAR *pObjectName, CBaseFilter *pFilter, CCritSec *pLock, 
								 HRESULT *phr, LPCWSTR pName) : 
	pOutputQueue(NULL), 
	CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName) 
{ 
} 
 
HRESULT 
QueuedOutputPin::Active() 
{ 
	HRESULT		hr = S_OK; 
 
	// Create the output queue 
	if (pOutputQueue == NULL) 
	{ 
		pOutputQueue = new COutputQueue(GetConnected(), &hr, TRUE, FALSE); 
		if (pOutputQueue == NULL) 
			return E_OUTOFMEMORY; 
		if (FAILED(hr)) 
		{ 
			delete pOutputQueue; 
			pOutputQueue = NULL; 
			return hr; 
		} 
	} 
 
	// Pass the call on to the base class 
	return CBaseOutputPin::Active(); 
} 
 
HRESULT 
QueuedOutputPin::Inactive() 
{ 
	// Delete the output queue 
	if (pOutputQueue != NULL) 
	{ 
		delete pOutputQueue; 
		pOutputQueue = NULL; 
	} 
 
	// Pass the call on to the base class 
	return CBaseOutputPin::Inactive(); 
} 
 
HRESULT 
QueuedOutputPin::Deliver(IMediaSample *pMediaSample) 
{ 
	if (pOutputQueue == NULL) 
		return S_OK; 
	pMediaSample->AddRef(); 
	return pOutputQueue->Receive(pMediaSample); 
} 
 
HRESULT 
QueuedOutputPin::DeliverEndOfStream() 
{ 
	if (pOutputQueue != NULL) 
		pOutputQueue->EOS(); 
	return S_OK; 
} 
 
HRESULT 
QueuedOutputPin::DeliverBeginFlush() 
{ 
	if (pOutputQueue != NULL) 
		pOutputQueue->BeginFlush(); 
	return S_OK; 
} 
 
HRESULT 
QueuedOutputPin::DeliverEndFlush() 
{ 
	if (pOutputQueue != NULL) 
		pOutputQueue->EndFlush(); 
	return S_OK; 
} 
 
VideoOutPin::VideoOutPin(CBaseFilter *pFilter,CCritSec *pLock, HRESULT *phr) : 
	QueuedOutputPin(NAME("cut detector video output"), pFilter, pLock, phr, 
		psudPins[VideoOutputNo].strName) 
{ 
} 
 
// Instead of the video output pin choosing an allocator, it just uses whatever the 
// upstream filter has chosen. 
HRESULT 
VideoOutPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc) 
{ 
	HRESULT		hr = S_OK; 
 
	// Get the allocator from the video input pin 
	*ppAlloc = ((VideoInPin*)m_pFilter->GetPin(VideoInputNo))->PeekAllocator(); 
 
	// Tell the downstream filter about the allocator set by the upstream filter, but read only. 
	hr = pPin->NotifyAllocator(*ppAlloc,TRUE); 
	if (FAILED(hr)) 
	{ 
		*ppAlloc = NULL; 
		return hr; 
	} 
 
	(*ppAlloc)->AddRef(); 
	return S_OK; 
} 
 
// DecideBufferSize is pure virtual in the base class, so must be implemented. 
// It is never called because we've overridden DecideAllocator. 
HRESULT 
VideoOutPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) 
{ 
	return S_OK; 
} 
 
HRESULT 
VideoOutPin::CheckMediaType(const CMediaType *pmt) 
{ 
	// reject some media types straight away 
	if (*pmt->Type() != MEDIATYPE_Video || *pmt->Subtype() != MEDIASUBTYPE_YUY2) 
		return VFW_E_TYPE_NOT_ACCEPTED; 
 
	// is upstream filter happy with this type? 
	if (m_pFilter->GetPin(VideoInputNo)->IsConnected()) 
		return m_pFilter->GetPin(VideoInputNo)->GetConnected()->QueryAccept(pmt); 
 
	return S_OK; 
} 
 
HRESULT 
VideoOutPin::GetMediaType(int iPosition, CMediaType *pMediaType) 
{ 
    CAutoLock			LockFilter(m_pLock); 
	HRESULT				hr; 
	IEnumMediaTypes*	pEnum; 
	AM_MEDIA_TYPE*		PartnerMT[100]; 
	ULONG				Fetched; 
	int					ValidCount; 
 
	if (iPosition < 0) 
		return E_INVALIDARG; 
	if (m_pFilter->GetPin(VideoInputNo)->IsConnected()) 
	{ 
		// pass on all preferred media types from upstream filter that are OK with us 
		hr = m_pFilter->GetPin(VideoInputNo)->GetConnected()->EnumMediaTypes(&pEnum); 
		if (FAILED(hr)) 
			return hr; 
		hr = pEnum->Next(sizeof(PartnerMT) / sizeof(PartnerMT[0]), PartnerMT, &Fetched); 
		if (FAILED(hr)) 
			return hr; 
		pEnum->Release(); 
		ValidCount = 0; 
		for (ULONG i = 0; i < Fetched; i++) 
		{ 
			if (PartnerMT[i]->majortype == MEDIATYPE_Video && 
				PartnerMT[i]->subtype == MEDIASUBTYPE_YUY2) 
			{ 
				if (ValidCount == iPosition) 
					hr = pMediaType->Set(*PartnerMT[i]); 
				ValidCount = ValidCount + 1; 
			} 
			DeleteMediaType(PartnerMT[i]); 
		} 
		if (FAILED(hr)) 
			return hr; 
		if (iPosition >= ValidCount) 
			return VFW_S_NO_MORE_ITEMS; 
	} 
	else 
	{ 
		// specify our preferred media type 
		if (iPosition > 0) 
			return VFW_S_NO_MORE_ITEMS; 
		pMediaType->InitMediaType(); 
		pMediaType->SetType(&MEDIATYPE_Video); 
		pMediaType->SetSubtype(&MEDIASUBTYPE_YUY2); 
	} 
	return S_OK; 
} 
 
HRESULT 
VideoOutPin::CompleteConnect(IPin *pReceivePin) 
{ 
	HRESULT			hr; 
 
	if (m_pFilter->GetPin(VideoInputNo)->IsConnected() && 
		m_mt != ((VideoInPin*)m_pFilter->GetPin(VideoInputNo))->CurrentMediaType()) 
	{ 
		// Reconnect input pin to make it use the output's media type 
		hr = m_pFilter->ReconnectPin(m_pFilter->GetPin(VideoInputNo), &m_mt); 
		if (FAILED(hr)) 
			return hr; 
	} 
 
	// Pass the call on to the base class 
	return CBaseOutputPin::CompleteConnect(pReceivePin); 
} 
 
// We ignore quality control messages, as we do not want to skip frames! 
STDMETHODIMP 
VideoOutPin::Notify(IBaseFilter *pSender, Quality q) 
{ 
	return E_NOTIMPL; 
} 
 
TextOutPin::TextOutPin(CBaseFilter *pFilter,CCritSec *pLock, HRESULT *phr) : 
	QueuedOutputPin(NAME("cut detector output"), pFilter, pLock, phr, 
		psudPins[TextOutputNo].strName) 
{ 
} 
 
HRESULT 
TextOutPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) 
{ 
	HRESULT					hr; 
	ALLOCATOR_PROPERTIES	Actual; 
 
	// One buffer to hold a string of up to 127 chars 
	ppropInputRequest->cBuffers = max(ppropInputRequest->cBuffers, 1); 
	ppropInputRequest->cbBuffer = max(ppropInputRequest->cbBuffer, 128); 
 
	hr = pAlloc->SetProperties(ppropInputRequest, &Actual); 
	if (FAILED(hr)) 
		return hr; 
	if (Actual.cBuffers < ppropInputRequest->cBuffers || 
		Actual.cbBuffer < ppropInputRequest->cbBuffer || 
		Actual.cbAlign  < ppropInputRequest->cbAlign  || 
		Actual.cbPrefix < ppropInputRequest->cbPrefix) 
		return E_FAIL; 
 
	return S_OK; 
} 
 
HRESULT 
TextOutPin::CheckMediaType(const CMediaType *pmt) 
{ 
	if (*pmt->Type() != MEDIATYPE_Text) 
		return VFW_E_TYPE_NOT_ACCEPTED; 
	return S_OK; 
} 
 
HRESULT 
TextOutPin::GetMediaType(int iPosition, CMediaType *pMediaType) 
{ 
	if (iPosition < 0) 
		return E_INVALIDARG; 
	if (iPosition > 0) 
		return VFW_S_NO_MORE_ITEMS; 
	pMediaType->InitMediaType(); 
	pMediaType->SetType(&MEDIATYPE_Text); 
	pMediaType->SetSubtype(&MEDIASUBTYPE_NULL); 
	return S_OK; 
} 
 
// We ignore quality control messages, as we do not want to skip frames! 
STDMETHODIMP 
TextOutPin::Notify(IBaseFilter *pSender, Quality q) 
{ 
	return E_NOTIMPL; 
} 
 
STDAPI DllRegisterServer() 
{ 
	return AMovieDllRegisterServer2(TRUE); 
} 
 
STDAPI DllUnregisterServer() 
{ 
	return AMovieDllRegisterServer2(FALSE); 
}