⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 revplaymdichildwnd.cpp

📁 VC++视频开发实例集锦(包括“远程视频监控”"语音识别系统"等13个经典例子)
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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;
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -