www.gusucode.com > VC++远程视频监控系统源代码-源码程序 > VC++远程视频监控系统源代码-源码程序/code/接收端/接收端/revplaymdichildwnd.cpp

    // RevPlayMDIChildWnd.cpp : implementation file
//

#include "stdafx.h"
#include "RevPlayThread.h"
#include "RevPlayMDIChildWnd.h"
#include "ConnectDlg.h"
#include "resource.h"

#include "asyncio.h"
#include "asyncrdr.h"
#include "mainfrm.h"


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

//#define IDC_REVPLAY_WND 1
#define LISTEN_PORT 1500
#define BUFSIZE 32768
#define WSA_CONNECT WM_USER+200
#define WSA_READ WM_USER+300  //读取视频数据

//{ 36a5f771-fe4c-11ce-a8ed-00aa002feab5 }
const CLSID  CLSID_Stream = {
	0x36a5f771, 0xfe4c, 0x11ce, 0xa8, 0xed, 0x00, 0xaa, 0x00, 0x2f, 0xea, 0xb5
};

const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
    &MEDIATYPE_NULL,            // Major type
    &MEDIASUBTYPE_NULL          // Minor type
};

const AMOVIESETUP_PIN sudPins =
{
    L"Input",                   // Pin string name
    FALSE,                      // Is it rendered
    FALSE,                      // Is it an output
    FALSE,                      // Allowed none
    FALSE,                      // Likewise many
    &CLSID_NULL,                // Connects to filter
    L"Output",                  // Connects to pin
    1,                          // Number of types
    &sudPinTypes                // Pin information
};

const AMOVIESETUP_FILTER sudStream =
{
    &CLSID_Stream,                // Filter CLSID
    L"Stream",                    // String name
    MERIT_DO_NOT_USE,           // Filter merit
    1,                          // Number pins
    &sudPins                    // Pin details
};


//
//  Object creation stuff
//
CFactoryTemplate g_Templates[]= {
    L"Stream", &CLSID_Stream, NULL, NULL, &sudStream
};
int g_cTemplates = 1;


class CMemStream : public CAsyncStream
{
public:
    CRevPlayWnd* pWnd;  //接收播放窗口指针
public:
	BOOL PeekAndPump();
    CMemStream( LPBYTE pbData, LONGLONG llLength, DWORD dwKBPerSec = INFINITE) :
	m_pbData(pbData),
        m_llLength(llLength),
        m_llPosition(0),
        m_dwKBPerSec(dwKBPerSec)
    {
        m_dwTimeStart = timeGetTime();
    }
	//设置当前位置
	HRESULT SetPointer(LONGLONG llPos)
    {
        if (llPos < 0 || llPos > m_llLength) {
            return S_FALSE;
        } else {
            m_llPosition = llPos;
            return S_OK;
        }
    }
	//当MPEG1 Stream Splitter请求数据时,由Read函数提供
    HRESULT Read(PBYTE pbBuffer,
		DWORD dwBytesToRead,
		BOOL bAlign,
		LPDWORD pdwBytesRead)
    {
        CAutoLock lck(&m_csLock);
        DWORD dwReadLength, cbRet;
        DWORD dwTime = timeGetTime();
		//如果要求读取的字节数大于剩余的字节数,则只直接读取剩余的字节
        if (m_llPosition + dwBytesToRead > m_llLength) 
		{
            dwReadLength = (DWORD)(m_llLength - m_llPosition);
        } 
		else 
		{
            dwReadLength = dwBytesToRead;
        }
		
        DWORD dwTimeToArrive =
            ((DWORD)m_llPosition + dwReadLength) / m_dwKBPerSec;
        if (dwTime - m_dwTimeStart < dwTimeToArrive) {
            Sleep(dwTimeToArrive - dwTime + m_dwTimeStart);
        }
		static int rwIndex =0;
		static int Block = pWnd->Block;
       	int temp=pWnd->rIndex;
//		if (pWnd->m_RenderOk) 
//		{
		/*	while (rwIndex>temp) 
				PeekAndPump();*/
			
			//将存放接收的数据缓冲区数组中的数据拷贝到pbBuffer中,传给Splitter
			CopyMemory((PVOID)pbBuffer, (PVOID)(pWnd->pRevMem[rwIndex]), pWnd->RevLen);
			rwIndex = (rwIndex + 1) % 100;
			TRACE1("Read Addr = %d\n",rwIndex);
			cbRet=pWnd->RevLen;
	//	}
/*		else
		{
			if (Block == 0)
			{
				
				CopyMemory((PVOID)pbBuffer, (PVOID)(m_pbData),
					dwReadLength);
				Block ++;
			}
			else 
			{
				CopyMemory((PVOID)pbBuffer, (PVOID)(m_pbData + dwReadLength),
					dwReadLength);
				Block = 0;
			}
			cbRet = dwReadLength;
			
		}*/
		//当前位置向后移读出的字节数
        m_llPosition += cbRet;
        *pdwBytesRead = cbRet;
		if (cbRet != dwReadLength)
			m_llLength = m_llPosition;
		return S_OK;
	}
	//得到当前的数据总长度
    LONGLONG Size(LONGLONG *pSizeAvailable)
    {
        LONGLONG llCurrentAvailable =
            Int32x32To64((timeGetTime() - m_dwTimeStart),m_dwKBPerSec);
        *pSizeAvailable = min(m_llLength, llCurrentAvailable);
        return m_llLength;
    }
    DWORD Alignment()
    {
		//按1字节对齐
        return 1;
    }
    void Lock()
    {
        m_csLock.Lock();
    }
    void Unlock()
    {
        m_csLock.Unlock();
    }
	
private:
    CCritSec       m_csLock;     //数据操作的同步对象
    const PBYTE    m_pbData;     //读写的内存数据指针
    LONGLONG       m_llLength;   //数据总长度 
    LONGLONG       m_llPosition; //实际读写的内存数据位置指针
    DWORD          m_dwKBPerSec; //播放的的速率
    DWORD          m_dwTimeStart;//开始时间
};

class CMemReader : public CAsyncReader
{
public:
    STDMETHODIMP Register()
    {
        return S_OK;
    }
    STDMETHODIMP Unregister()
    {
        return S_OK;
    }
    CMemReader(CMemStream *pStream, CMediaType *pmt, HRESULT *phr) :
	CAsyncReader(NAME("Mem Reader"), NULL, pStream, phr)
    {
        m_mt = *pmt;
    }
};




/////////////////////////////////////////////////////////////////////////////
// CRevPlayMDIChildWnd

CMenu CRevPlayMDIChildWnd::menu;   

IMPLEMENT_DYNCREATE(CRevPlayMDIChildWnd, CMDIChildWnd)

CRevPlayMDIChildWnd::CRevPlayMDIChildWnd()
{
}

CRevPlayMDIChildWnd::~CRevPlayMDIChildWnd()
{
}


BEGIN_MESSAGE_MAP(CRevPlayMDIChildWnd, CMDIChildWnd)
	//{{AFX_MSG_MAP(CRevPlayMDIChildWnd)
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_USER_PREPARE_TO_CLOSE, OnPrepareToClose)
   

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRevPlayMDIChildWnd message handlers

BOOL CRevPlayMDIChildWnd::Create(LPCTSTR szTitle, const RECT &rect, CMDIFrameWnd *parent)
{
    if (menu.m_hMenu == NULL)
		menu.LoadMenu(IDR_REVPLAY);
	m_hMenuShared = menu.m_hMenu;
	//创建子窗口
	if (!CMDIChildWnd::Create(NULL, szTitle, WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, rect, parent))
		return FALSE;
	//生成UI线程对象
	CRevPlayThread* pRevPlayThread = new CRevPlayThread(m_hWnd);
	//创建线程
	pRevPlayThread->CreateThread();

	return TRUE;
}

BOOL CRevPlayMDIChildWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
	// TODO: Add your specialized code here and/or call the base class
	CWnd* pRevPlayWnd = (CRevPlayWnd*)GetDlgItem(IDC_REVPLAY_WND);
	if (pRevPlayWnd == NULL)
		return FALSE; 

	COnCmdMsg oncmdmsg;
	oncmdmsg.m_nID =    nID;
	oncmdmsg.m_nCode = nCode;
	oncmdmsg.m_pExtra = pExtra;
	oncmdmsg.m_pHandlerInfo = pHandlerInfo;
	return pRevPlayWnd->SendMessage(WM_USER_ONCMDMSG,
		0, (LPARAM)&oncmdmsg);

}

void CRevPlayMDIChildWnd::OnSize(UINT nType, int cx, int cy) 
{
	CMDIChildWnd::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	CWnd* pRevPlayWnd = GetDlgItem(IDC_REVPLAY_WND);
	if (pRevPlayWnd == NULL)
		return; // child CBounceWnd not created yet
	CRect rect;
	GetClientRect(&rect);
	pRevPlayWnd->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
		SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);

}

BOOL CRevPlayMDIChildWnd::DestroyWindow() 
{
	// TODO: Add your specialized code here and/or call the base class
	OnPrepareToClose();
	return CMDIChildWnd::DestroyWindow();
}


LRESULT CRevPlayMDIChildWnd::OnPrepareToClose(WPARAM wParam, LPARAM lParam)
{
 	CWnd* pRevPlayWnd = (CRevPlayWnd*)GetDlgItem(IDC_REVPLAY_WND);
	pRevPlayWnd->SendMessage(WM_USER_PREPARE_TO_CLOSE);

	WaitForSingleObject(CRevPlayThread::m_hEventRevPlayThreadKilled, INFINITE);
	return 0;
}


/////////////////////////////////////////////////////////////////////////////
// CRevPlayWnd


CRevPlayWnd::CRevPlayWnd()
{
	m_LostBlock=0;
	
	m_Receive=FALSE;
	m_Save=FALSE;
	m_FirstRead=TRUE;
	m_RenderOk=FALSE;
	m_Stop=FALSE;
	rIndex=0;   //pRevMem数组的标记
	g_rwIndex=0;
	m_pStream=NULL;
	m_rdr=NULL;
	
	m_pifg = NULL;
	m_pigb = NULL;
	m_pimc = NULL;
	m_pivw = NULL;
	m_ppos = NULL;
	
	hmmioSave = NULL;

}

CRevPlayWnd::~CRevPlayWnd()
{
 
}


BEGIN_MESSAGE_MAP(CRevPlayWnd, CWnd)
	//{{AFX_MSG_MAP(CRevPlayWnd)
	ON_WM_CREATE()
	ON_COMMAND(IDR_SAVE, OnSave)
	ON_WM_CONTEXTMENU()
	ON_COMMAND(ID_STOP_RECEIVE, OnStopReceive)
	ON_COMMAND(IDR_REV_PLAY, OnRevPlay)
	ON_UPDATE_COMMAND_UI(IDR_SAVE, OnUpdateSave)
	ON_UPDATE_COMMAND_UI(ID_STOP_RECEIVE, OnUpdateStopReceive)
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_USER_ONCMDMSG, OnDelegatedCmdMsg)
	ON_MESSAGE(WM_USER_PREPARE_TO_CLOSE, OnPrepareToClose)
	ON_MESSAGE(WSA_CONNECT,OnConnect)
	ON_MESSAGE(WSA_READ,OnRead)

END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CRevPlayWnd message handlers

LRESULT CRevPlayWnd::OnConnect(WPARAM wParam,LPARAM lParam) 
{
	int status;
	int SendLen;
	int socket;
	char szRev[80];
	char szBuff[80];
	char Msg[]="请发送数据";
	u_long block=0;
	socket=(SOCKET)wParam; 
	if (WSAGETSELECTERROR(lParam))
	{//建立连接失败
		
		MessageBox("不能连接服务器", "连接失败", MB_OK);
		if(WaitDlg)
			WaitDlg.EndDialog(IDCANCEL);
		//关闭socket
		closesocket(socket); 
		return -1;
	}
	if (WSAGETSELECTEVENT(lParam) == FD_CONNECT)
	{//成功建立连接
		
		if(WaitDlg)
			WaitDlg.EndDialog(IDCANCEL);
		//发送请求发送数据命令给发送端
		SendLen=send(socket,Msg,sizeof(Msg),0);
		if(SendLen!=sizeof(Msg))
		{//请求数据发送失败
			MessageBox("请求错误" "Send");
			closesocket(socket); 
			return -1;
		}
		if(SendLen==sizeof(Msg))
		{
			WSAAsyncSelect(socket,m_hWnd, 0, 0 ); 
			status=ioctlsocket(socket,FIONBIO,&block);
			if(status==SOCKET_ERROR)
			{
				sprintf(szBuff,"Err: %d",WSAGetLastError());
				MessageBox(szBuff);
				return -1;
			}
			//接收数据
			status =recv(socket, szRev,sizeof(szRev),0);
			if (status) 
			{
				//得到组播IP地址和端口
				sscanf(szRev,"%s%d",strDestAddr,&DestPort);    
				sprintf(szBuff,"请加入组:%s,端口:%d",strDestAddr,DestPort);
				MessageBox(szBuff,"接收请求");            
				sprintf(szBuff,"接收播放:组:%s,端口:%d",strDestAddr,DestPort);
				::SetWindowText(GetParent()->m_hWnd,szBuff);
				//关闭socket
				closesocket(socket);
			}
			if(status==0)
			{
				MessageBox("对方关闭连接");
				closesocket(socket);
				return -1;
			}	 
		}
	}
	return 0;
}


LRESULT CRevPlayWnd::OnRead(WPARAM wParam,LPARAM lParam) 
{
	DWORD dwRet;
	REFTIME		fTime;
	REFERENCE_TIME	llClock; 
	HRESULT hr;
	RECT rect;
	//接收组播数据,存放到缓冲区stWSABuf中
	RevLen=ReceiveData();
	//将缓冲区stWSABuf中的数据拷贝到存放接收的数据的数组pRevMem中,
	//以供DirectShow读取
	CopyMemory((PVOID)pRevMem[rIndex],(PVOID)stWSABuf.buf,RevLen);
	rIndex=(rIndex+1)%100;
	//将接收到的数据保存到文件中
	if(hmmioSave)
		mmioWrite(hmmioSave,stWSABuf.buf,RevLen);
	
	if(m_FirstRead)   
	{//如果是第一次接收到数据,启动DirectShow
		fTime = 0.0;
		dwRet = Parse ((PBYTE)stWSABuf.buf, stWSABuf.len, &llClock);
		fTime = llClock / 90000.0;
		if(dwRet == 0)
			return -1;
		
		if(InitGraph()==-1)
			return -1;
		
		if (abs (dwRet - 2048000) <= 16000) {
			RenderFrom ((PBYTE)achInBuf, "2mpal.dat");
		} 
		
		if (abs (dwRet - 1152000) <= 16000) {
			RenderFrom ((PBYTE)achInBuf, "1mpal.dat");
		} 
		
		if (abs (dwRet - 512000)  <= 16000) {
			RenderFrom ((PBYTE)achInBuf, "512pal.dat");
		}
		
		if (abs (dwRet - 256000)  <= 16000) {
			RenderFrom ((PBYTE)achInBuf, "256pal.dat");
		}
		
		Block = 0;
		
		//使用智能连接,将Source Filter的输出Pin连出去
		if (FAILED(hr = m_pigb -> Render(m_rdr -> GetPin(0)))) 
		{
			if (hr != VFW_S_AUDIO_NOT_RENDERED && hr != VFW_E_NO_AUDIO_HARDWARE )
			{
				MessageBox ("Render Error");
				WSAAsyncSelect(MultiSock,m_hWnd,WSA_READ,0); 
				HELPER_RELEASE(m_pifg);
				HELPER_RELEASE(m_pigb);
				HELPER_RELEASE(m_pimc);
				HELPER_RELEASE(m_pivw);
				HELPER_RELEASE(m_ppos);
				return -1;
			}
		}
		
		m_RenderOk = true;
		//设置视频窗口属性
		m_pivw -> put_Owner((OAHWND)m_hWnd);
		m_pivw -> put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
		GetClientRect(&rect);
		m_pivw -> SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom);
		//开始播放
		m_pimc -> Run();	
		m_ppos->put_CurrentPosition(fTime + 0.4);
		m_Stop = TRUE;
	}
	
	m_FirstRead=FALSE;
	return 0;
}




LRESULT CRevPlayWnd::OnDelegatedCmdMsg(WPARAM, LPARAM lParam)
{
	COnCmdMsg* pOnCmdMsg = (COnCmdMsg*)lParam;
	return CWnd::OnCmdMsg(pOnCmdMsg->m_nID, pOnCmdMsg->m_nCode, pOnCmdMsg->m_pExtra,
		pOnCmdMsg->m_pHandlerInfo);
}

LRESULT CRevPlayWnd::OnPrepareToClose(WPARAM, LPARAM)
{
	
    StopReceive();
	if( stWSABuf.buf)
	{
		delete  stWSABuf.buf;
		stWSABuf.buf=NULL;
	}
	if(achInBuf)
	{
		delete achInBuf;
		achInBuf=NULL;
	}
	DestroyWindow();
	return 0;
}

BOOL CRevPlayWnd::Create(LPCTSTR szTitle, LONG style, const RECT& rect, CWnd* parent)
{
	// Register a custom WndClass and create a window.
	// This must be done because CBounceWnd has a custom cursor, and
	//  no icon.
	LPCTSTR lpszRevPlayClass =
		AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
		LoadCursor(NULL, IDC_UPARROW),
		(HBRUSH)(COLOR_WINDOW+1),
		NULL);
	
	return CWnd::Create(lpszRevPlayClass, szTitle, style, rect, parent,
		IDC_REVPLAY_WND);
}


int CRevPlayWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here
	int status;
	int sock;
	CConnectDlg ConnectDlg;
	
	stWSABuf.buf = new char[BUFSIZE];
	stWSABuf.len = BUFSIZE;
	achInBuf = new BYTE [BUFSIZE*2];
	
	if(ConnectDlg.DoModal()==IDOK)
	{
		status=Connect(m_hWnd,AddressIp,LISTEN_PORT,sock);
		if(status<0)
			return -1;
	}
	
	return 0;
}

int CRevPlayWnd::Connect(HWND hwnd, const char *Addr, short Port, int &sock)
{
	SOCKADDR_IN send_sin;
	int status;
	//创建一个socket
	sock = socket(AF_INET,SOCK_STREAM,0);
	if (sock == INVALID_SOCKET)
	{
       	MessageBox("Socket Error");
        closesocket(sock);   
		return -1;
	} 
	else
	{
		send_sin.sin_family=AF_INET;
		send_sin.sin_addr.s_addr=inet_addr(Addr);
		send_sin.sin_port=htons(Port);
		//设置响应的网络事件为FD_CONNECT,即建立连接
		//发送WSA_CONNECT消息给窗口
		status=WSAAsyncSelect(sock,hwnd,WSA_CONNECT,FD_CONNECT); 
		if(status<0)	
		{//连接建立失败,关闭socket
			MessageBox("Error on WSAAsyncSelect()");
			WSAAsyncSelect(sock, hwnd, 0, 0);
			closesocket(sock);
			return -1;
		} 
	}
	//连接发送端
	connect(sock,(struct sockaddr FAR *)&send_sin, sizeof(send_sin));
	int error=WSAGetLastError();
	//有阻塞,弹出等待对话框
	if (error==WSAEWOULDBLOCK)
		WaitDlg.DoModal(); 
	return 0;
}



void CRevPlayWnd::InitMultiSock()
{
    int RevBuf;
    int status;
    BOOL  bFlag;
	CString ErrMsg;
	SOCKADDR_IN stLocalAddr;
	SOCKADDR_IN stDestAddr;
	SOCKET hNewSock;
    int RevLen=sizeof(RevBuf);
	//创建一个IP组播套接字
    MultiSock = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
		  (LPWSAPROTOCOL_INFO)NULL, 0, 
		  WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF);
	if (MultiSock == INVALID_SOCKET) 
	{
		MessageBox("WSASocket() failed");
		return;
    } 
	
    //允许对同一地址bind多次
	bFlag = TRUE;
	status = setsockopt(
		MultiSock,					/* socket */
    	SOL_SOCKET,				/* socket level */
		SO_REUSEADDR,			/* socket option */
	    (char *)&bFlag,			/* option value */
	 	sizeof (bFlag));	/* size of value */

	if (status == SOCKET_ERROR) 
	{
	  ErrMsg.Format ("set SO_REUSEADDR failed, Err: %d",WSAGetLastError());
      MessageBox(ErrMsg);
	  return;
	}
	// 将套接字绑定到用户指定端口
	stLocalAddr.sin_family = AF_INET;
  //  stLocalAddr.sin_port = htons (DestPort);
    stLocalAddr.sin_port = htons (201);
	stLocalAddr.sin_addr.s_addr = INADDR_ANY;
    status = bind (
        MultiSock, 
        (struct sockaddr FAR *)&stLocalAddr, 
        sizeof(struct sockaddr));

    if (status == SOCKET_ERROR) 
	{
		ErrMsg.Format ("Bind(socket: %d, port: %d) failed, Err: %d",
			MultiSock, DestPort, WSAGetLastError());
		MessageBox(ErrMsg);
			
    }
	//设定接收缓冲区为64k
 	RevBuf=65536;
	status = setsockopt(
		MultiSock,					/* socket */
    	SOL_SOCKET,				/* socket level */
	    SO_RCVBUF,			/* socket option */
	    (char *)&RevBuf,			/* option value */
	    sizeof(RevBuf));	/* size of value */
	if (status == SOCKET_ERROR) 
	{
		MessageBox("set SO_REVBUF error");
		return;
	}
    
	//加入组播组
	stDestAddr.sin_family = PF_INET;
	stDestAddr.sin_port = htons (201);
    stDestAddr.sin_addr.s_addr = inet_addr("234.5.6.7");
    hNewSock = WSAJoinLeaf (MultiSock, /* socket */
        (PSOCKADDR)&stDestAddr, /* multicast address */
        sizeof (stDestAddr),    /* length of addr struct */	
        NULL,                   /* caller data buffer */
        NULL,                   /* callee data buffer */
        NULL,                   /* socket QOS setting */
        NULL,                   /* socket group QOS */
        JL_RECEIVER_ONLY);               /* do both: send *and* receive */

    if (hNewSock == INVALID_SOCKET) 
	{
	  ErrMsg.Format ("WSAJoinLeaf() failed, Err: %d",WSAGetLastError());
      MessageBox(ErrMsg);
	} 	
}


int CRevPlayWnd::ReceiveData()
{//接收组播数据
    CString msg;
    int status;
    DWORD cbRet;
    DWORD dFlag;
	int iLen;
	SOCKADDR_IN stSrcAddr;
	cbRet = 0;
	iLen = sizeof (stSrcAddr);
	dFlag = 0;
	//接收组播数据,存放到缓冲区stWSABuf中
	status = WSARecvFrom (MultiSock, /* socket */
		&stWSABuf,               /* input buffer structure */
		1,                       /* buffer count */
		&cbRet,                  /* number of bytes recv'd */
		&dFlag,                 /* flags */
		(struct sockaddr *)&stSrcAddr,/* source address */
		&iLen,                   /* size of addr structure */
		NULL,                    /* overlapped structure */
		NULL);                   /* overlapped callback function */
	
	if (status == SOCKET_ERROR) 
	{
		//数据丢失,丢失的块数计数加1
		m_LostBlock++;
		msg.Format ("WSARecvFrom() failed, Err:%d", WSAGetLastError());
		MessageBox (msg);
		return -1;
	} 
	return cbRet;
}



void CRevPlayWnd::OnSave() 
{
	// TODO: Add your command handler code here
	m_Save=!m_Save;
	DWORD dwFlags;
	CString SaveFileName;
	CString strSave;
	TCHAR Driver;
    CFileDialog dlg(TRUE,NULL,"temp.mpg",NULL,"mpeg文件(*.mpg)|*.mpg|AVI文件(*.avi)|*.avi");
    dlg.m_ofn.lpstrTitle="保存到...";
    if(dlg.DoModal()==IDOK)
	{
		
		SaveFileName=dlg.GetPathName();
        Driver=SaveFileName.GetAt(0);
       	CWnd* pParent = GetOwner();
		strSave.Format("保存到:%s",SaveFileName);
		CMainFrame* pFrame=(CMainFrame*)pParent->GetOwner();
		//   pFrame->m_wndStatusBar.SetPaneText(1,strSave);
		
	}
    dwFlags = MMIO_CREATE | MMIO_WRITE;
    hmmioSave = mmioOpen(SaveFileName.GetBuffer(_MAX_PATH), (LPMMIOINFO)NULL, dwFlags);
    SaveFileName.ReleaseBuffer();
}

void CRevPlayWnd::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	// TODO: Add your message handler code here
	CMenu menu;
	menu.LoadMenu(IDR_POP_MENU);
	menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
}

void CRevPlayWnd::OnStopReceive() 
{
	// TODO: Add your command handler code here
	StopReceive();
	m_Save=FALSE;
    m_FirstRead=TRUE;
    m_RenderOk=FALSE;
    m_Stop=FALSE;
    rIndex=0;
}

int  CRevPlayWnd::InitGraph()
{//构建Filter Graph
    HRESULT hr;
	hr = S_OK;
	//设置媒体类型,为MPEG1数据流
    mt.majortype = MEDIATYPE_Stream;
    mt.subtype = MEDIASUBTYPE_MPEG1System;
	//创建Source Filter
	m_pStream = new CMemStream(achInBuf, 0x80000000, INFINITE);
    m_pStream->pWnd=this;
    m_rdr = new CMemReader(m_pStream, &mt, &hr);
	
    if(FAILED(hr) || m_rdr == NULL)
	{
		MessageBox("CMemReader Error");
		return -1;
	}
    
	m_rdr -> AddRef();
	//创建Filter Graph
	CHECK_ERROR(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IFilterGraph, (void**)&m_pifg),"CoCreateInstance Error") ;
	//将Source Filter加入到Filter Graph中    
	CHECK_ERROR(m_pifg -> AddFilter(m_rdr, NULL), "AddFilter Error");
	//查询IGraphBuilder接口
	CHECK_ERROR(m_pifg -> QueryInterface(IID_IGraphBuilder, (void **)&m_pigb),"QueryInterface(IGraphBuilder) Error");
    m_pigb->AddRef ();
	//查询IMediaControl接口
	CHECK_ERROR(m_pigb -> QueryInterface(IID_IMediaControl, (void **)&m_pimc),"QueryInterface(IMediaControl) Error");
    m_pimc->AddRef ();
	//查询IVideoWindow接口
    CHECK_ERROR(m_pigb -> QueryInterface(IID_IVideoWindow, (void **)&m_pivw),"QueryInterface(IVideoWindow) Error");
    m_pivw->AddRef ();
    //查询IMediaPosition接口
    CHECK_ERROR(m_pigb -> QueryInterface(IID_IMediaPosition, (void **)&m_ppos),"QueryInterface(IMediaPosition) Error");
    m_ppos->AddRef ();
	return 0;
}

void CRevPlayWnd::OnRevPlay() 
{
	// TODO: Add your command handler code here
	int status;
	//建立组播socket,加入组播组
  	InitMultiSock();
	//设置响应的网络事件为FD_READ,即读数据
	//发送WSA_READ消息给窗口
	status=WSAAsyncSelect(MultiSock,m_hWnd,WSA_READ,FD_READ);
	if(status<0)	
	{
       MessageBox("Error on WSAAsyncSelect()");
       closesocket(MultiSock);
	   return;
	}
	//初始化存放接收数据的缓冲区
	for (int i = 0; i< 100; i++ )
		pRevMem[i] =new BYTE[BUFSIZE]; //32k
	m_Receive=TRUE;
	
}

BOOL CMemStream::PeekAndPump()
{
	static MSG msg;
	
	while (::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) {
		if (!AfxGetApp()->PumpMessage()) {
			::PostQuitMessage(0);
			return FALSE;
		}	
	}
	
	return TRUE;
}

void CRevPlayWnd::RenderFrom(PBYTE Buf, LPCTSTR File)
{
    CFile f;
	CString MyPath;
	char path[MAX_PATH];
	
	GetModuleFileName (AfxGetInstanceHandle(), path, _MAX_PATH);
	MyPath = path;
	int index = MyPath.ReverseFind ('\\');
	MyPath = MyPath.Left (index+1);
	MyPath += File;
	
	int r = f.Open (MyPath, CFile::modeRead);
    if(r>0)	   
		r = f.Read (Buf, BUFSIZE*2);
    else
		return;
	f.Close ();
}

DWORD CRevPlayWnd::Parse(PBYTE Ptr, DWORD dwSize, LONGLONG *llTime)
{
	DWORD	RetV;
	DWORD LeftBytes = dwSize;
	while ((LONGLONG)LeftBytes >= 4 ) {
		if (!NextStartCode ((const BYTE **)&Ptr, &LeftBytes))
			break;
		DWORD Code = DWORD_SWAP(*(UNALIGNED DWORD *)Ptr);
		
		if (VALID_PACKET(Code)) {
			PBYTE PcktPtr;
			DWORD  Remain;
			DWORD PtsPos;
			RetV = ParseMPEG1Packet(Ptr, LeftBytes, &PacketData, &PtsPos);
			
			PcktPtr = Ptr+4;
			Remain = RetV;
			while ((LONG)Remain > 4) {
				if (!NextStartCode ((const BYTE **)&PcktPtr, &Remain))
					break;
				DWORD PcktCode = DWORD_SWAP(*(UNALIGNED DWORD *)PcktPtr);
				switch (PcktCode) {
				case SEQUENCE_HEADER_CODE:
					ParseSequenceHeader(PcktPtr, 0, &SeqInfo);
					return (SeqInfo.dwBitRate);
				}
				PcktPtr += 4;
				Remain -=4 ;
			}
			
		} else {
			switch (Code) {
			case PACK_START_CODE:
				GetClock (Ptr+4, llTime);
				RetV = PACK_HEADER_LENGTH;
				break;
			case SYSTEM_HEADER_START_CODE:
				RetV = ParseSystemHeader(Ptr, LeftBytes);
				break;
			default:
				RetV = 4;
				break;
			}
		}
		
		Ptr += RetV;
		LeftBytes -= RetV;
		if (RetV <=0)
			break;
	} 
	return 0;
}

void CRevPlayWnd::OnUpdateSave(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable (!m_Stop);
	pCmdUI->SetCheck (m_Save);
}

void CRevPlayWnd::OnUpdateStopReceive(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable (m_Stop);
}

void CRevPlayWnd::StopReceive()
{
    WSAAsyncSelect(MultiSock,m_hWnd,WSA_READ,0);
	closesocket(MultiSock);
	if (hmmioSave)
	{
		mmioClose(hmmioSave, NULL);
		hmmioSave = NULL;
	}
	if(m_pimc)
	{
		m_pimc -> Pause ();
		m_pimc ->StopWhenReady();
		m_pimc -> Stop();
	}
	if(m_pivw)
	{
		m_pivw -> put_Visible(OAFALSE);
		m_pivw -> put_Owner(NULL);
	}
	HELPER_RELEASE(m_pifg);
	HELPER_RELEASE(m_pigb);
	HELPER_RELEASE(m_pimc);
	HELPER_RELEASE(m_pivw);
	HELPER_RELEASE(m_ppos);
	
	if(m_pStream)
	{
		delete m_pStream;
		m_pStream = NULL;
	}
	
	if(m_rdr)
	{
		delete m_rdr;
		m_rdr = NULL;
	}
	for (int i = 0; i< 100; i++) 
	{
		
		if (m_Receive) //表示按了Receive菜单
			if(pRevMem[i])
				delete pRevMem[i];
			pRevMem[i] = NULL;
	}
}

void CRevPlayWnd::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	CRect rect;
	GetClientRect(&rect);
	if(m_pivw)
		m_pivw -> SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom);

}