📄 capture.cpp
字号:
/*
* Openmysee
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "stdafx.h"
#include <atlbase.h>
#include <dmodshow.h>
#include <qedit.h>
#include "capture.h"
#include "utilities.h"
#include "audiocompressselectordlg.h"
#include "GVCaptureDlg.h"
#include "audiochangeddlg.h"
#include "videochanged.h"
#include "SysConfig.h"
#include "wmcodecconst.h"
#include "VideoEncParams.h"
#include "macros.h"
#include "videoenc.h"
#include "streams.h"
#pragma comment(lib,"Dmoguids")
#pragma comment(lib,"Winmm")
//static const GUID CLSID_TVStreamSink =
//{ 0x1860c8d5, 0x370b, 0x4334, { 0x99, 0xf1, 0xb7, 0xc, 0x37, 0x9f, 0xac, 0x67 } };
// {C2B146BB-C61D-4673-AF41-5079E6855401}
static const GUID CLSID_TVStreamSink =
{ 0xc2b146bb, 0xc61d, 0x4673, { 0xaf, 0x41, 0x50, 0x79, 0xe6, 0x85, 0x54, 0x1 } };
static const GUID CLSID_FVideoOverlay =
{0xae1c4226, 0xb8ec, 0x4204, { 0xbf, 0x15, 0x92, 0x56, 0x63, 0xde, 0x51, 0x68} };
//用于WM9的外部变量
extern CVideoEncParams g_VideoEncodingParams;
//////////////////////////////////////////////////////////////////////////
//以下是构造和析构函数
//////////////////////////////////////////////////////////////////////////
CCaptureGraph::CCaptureGraph()
{
m_config = FALSE;
state = NULL;
sstate = 0;
m_RefCount = 0;
m_pGB = NULL; // capture graph
m_pVW = NULL; // video window
m_pMC = NULL; // media control
m_pTVConfig = NULL; // tv sink config
// filters in graph
m_pVideoCapture = NULL;
m_pVideoEncoder = NULL;
m_pAudioEncoder = NULL;
m_pAudioCapture = NULL;
m_pTVStreamSink = NULL;
m_pVideoSmartTee = NULL;
m_pAudioSmartTee = NULL;
m_pAVIMuxer = NULL;
m_pFileWriter = NULL;
m_pftrDVSpliter = NULL;
m_pDVDecoder = NULL;
//xiezhouwei 05-08-17添加
m_pVideoOverlay = NULL;
m_arrayOtherFilter.RemoveAll();
m_bGraphBuiled = FALSE;
m_bIsPreview = TRUE;
m_bIsOnlyAudio = FALSE;
m_bSave = FALSE; // added by zk for saving 2004-04-16
m_bNeedOverlay = TRUE;
mbIsDV = FALSE; //added by xiezhouwei 2005-09-01
m_bISCrossBar = FALSE; //默认不选择CrossBar
m_strCurVideoEncoder.Empty();
m_pCurAudioAMT = NULL;
m_hWndOwner = NULL;
ZeroMemory(m_szAVIFile,sizeof(m_szAVIFile));
}
CCaptureGraph::~CCaptureGraph()
{
Uninitialize();
}
STDMETHODIMP_(ULONG) CCaptureGraph::AddRef()
{
return ++m_RefCount;
}
STDMETHODIMP_(ULONG) CCaptureGraph::Release()
{
m_RefCount--;
if(m_RefCount == 0)
delete this;
return m_RefCount;
}
STDMETHODIMP CCaptureGraph::QueryInterface(REFIID iid, void** ppInter)
{
// we need not to implement this now
// it only for late_use
return E_NOTIMPL;
}
STDMETHODIMP CCaptureGraph::Initialize()
{
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
TRACE0("ERROR - Could not initialize COM library");
return hr;
}
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void **)&m_pGB);
if (FAILED(hr))
{
TRACE0("ERROR - Could not create the Filter Graph Manager.");
return hr;
}
hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
if (FAILED(hr))
{
TRACE0("ERROR - Could not Get IMediaControl");
return hr;
}
// for DEBUG
#ifdef _DEBUG
AddGraphToRot(m_pGB, &g_dwRegister);
#endif //_DEBUG
return S_OK;
}
STDMETHODIMP CCaptureGraph::Uninitialize()
{
// first unDEBUG
#ifdef _DEBUG
RemoveGraphFromRot(g_dwRegister);
#endif //_DEBUG
RemoveFilter(m_pVideoCapture);
RemoveFilter(m_pAudioCapture);
RemoveFilter(m_pVideoEncoder);
RemoveFilter(m_pAudioEncoder);
RemoveFilter(m_pVideoSmartTee);
RemoveFilter(m_pAudioSmartTee);
RemoveFilter(m_pTVStreamSink);
RemoveFilter(m_pVideoOverlay);
RemoveFilter(m_pAVIMuxer);
RemoveFilter(m_pFileWriter);
RemoveFilter(m_pDVDecoder);
state = NULL;
SAFE_RELEASE(m_pGB);
SAFE_RELEASE(m_pVW);
SAFE_RELEASE(m_pMC);
// SAFE_RELEASE(m_pTVConfig);
// filters in graph
SAFE_RELEASE(m_pVideoCapture);
SAFE_RELEASE(m_pVideoEncoder);
SAFE_RELEASE(m_pAudioEncoder);
SAFE_RELEASE(m_pAudioCapture);
// SAFE_RELEASE(m_pTVStreamSink);
SAFE_RELEASE(m_pVideoSmartTee);
SAFE_RELEASE(m_pAudioSmartTee);
SAFE_RELEASE(m_pAVIMuxer);
SAFE_RELEASE(m_pFileWriter);
SAFE_RELEASE(m_pVideoOverlay);
SAFE_RELEASE(m_pDVDecoder);
m_hWndOwner = NULL;
CoUninitialize();
return S_OK;
}
// controls
STDMETHODIMP CCaptureGraph::Run()
{
HRESULT hr;
if(!m_bGraphBuiled)
{
if(FAILED(BuildGraph()))
{
DisassembleGraph();
return E_FAIL;
}
}
CComPtr <IVideoWindow> lpVideoWindow;
hr = m_pGB->QueryInterface(IID_IVideoWindow, (void**)&lpVideoWindow);
if (FAILED(hr))
{
return hr;
}
hr = lpVideoWindow->put_Visible(OATRUE);
ASSERT(m_pMC);
return m_pMC->Run();
}
STDMETHODIMP CCaptureGraph::Stop()
{
HRESULT hr;
ASSERT(m_pMC);
CComPtr <IVideoWindow> lpVideoWindow;
hr = m_pGB->QueryInterface(IID_IVideoWindow, (void**)&lpVideoWindow);
if (FAILED(hr))
{
return hr;
}
hr = lpVideoWindow->put_AutoShow(OAFALSE);
hr = lpVideoWindow->put_Visible(OAFALSE);
return m_pMC->Stop();
}
STDMETHODIMP CCaptureGraph::Pause()
{
ASSERT(m_pMC);
return m_pMC->Pause();
}
// enums,it respectively call EnumSpeciFilters
// with diffrent specification
STDMETHODIMP CCaptureGraph::EnumVideoCapDevices(CStringArray &strArrayType)
{
return EnumSpeciFilters(VIDEO_CAP, strArrayType);
}
STDMETHODIMP CCaptureGraph::EnumAudioCapDevices(CStringArray &strArrayType)
{
return EnumSpeciFilters(AUDIO_CAP, strArrayType);
}
STDMETHODIMP CCaptureGraph::EnumVideoEncoders(CStringArray &strArrayType)
{
return EnumSpeciFilters(VIDEO_COMPRESS, strArrayType);
}
STDMETHODIMP CCaptureGraph::EnumAudioEncoders(CStringArray &strArrayType)
{
return EnumSpeciFilters(AUDIO_COMPRESS, strArrayType);
}
// configs
STDMETHODIMP CCaptureGraph::ConfigVideoCapDeviceByName(HWND hParent)
{
if (NULL == m_pVideoCapture)
{
AfxMessageBox("视频采集设备未找到");
return S_OK;
}
// must be added in the graph this time
m_pGB->AddFilter(m_pVideoCapture, NULL);
/*
* FIRST: prompt user to set filter configuration
*/
// Get property page interface
HRESULT hr;
IAMVfwCaptureDialogs* pDlg;
hr = m_pVideoCapture->QueryInterface(IID_IAMVfwCaptureDialogs, (void**)(&pDlg));
if(!FAILED(hr))
{
if ( !FAILED(pDlg->HasDialog(VfwCaptureDialog_Format)))
{
hr = pDlg->ShowDialog(VfwCaptureDialog_Format, hParent);
}
if ( !FAILED(pDlg->HasDialog(VfwCaptureDialog_Source)))
{
hr = pDlg->ShowDialog(VfwCaptureDialog_Source, hParent);
}
if ( !FAILED(pDlg->HasDialog(VfwCaptureDialog_Display)))
{
hr = pDlg->ShowDialog(VfwCaptureDialog_Display, hParent);
}
return hr;
}
ISpecifyPropertyPages *pSpec;
hr = m_pVideoCapture->QueryInterface(IID_ISpecifyPropertyPages, (void**)(&pSpec));
if(FAILED(hr))
{
return E_FAIL;
}
// Popup page
CString str(_T("Video Capture Configuration 1")); // dlg caption
WCHAR wstrCaption[256];
CAUUID cauuid;
pSpec->GetPages(&cauuid);
pSpec->Release();
if(cauuid.cElems >= 1)
{
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
str.GetBuffer(str.GetLength()), -1,
wstrCaption, sizeof(wstrCaption) / sizeof(WCHAR));
hr = OleCreatePropertyFrame(hParent, 30, 30, wstrCaption, 1,
(IUnknown **)&m_pVideoCapture, cauuid.cElems,
(GUID *)cauuid.pElems, 0, 0, NULL);
if(FAILED(hr))
{
CoTaskMemFree(cauuid.pElems);
pSpec->Release();
return E_FAIL;
}
}
// Destructor
CoTaskMemFree(cauuid.pElems);
return S_OK;
}
// configs
STDMETHODIMP CCaptureGraph::ConfigAudioCapDeviceByName(HWND hParent)
{
if (NULL == m_pAudioCapture)
{
AfxMessageBox("视频采集设备未找到");
return S_OK;
}
// must be added in the graph this time
m_pGB->AddFilter(m_pAudioCapture, NULL);
/*
* FIRST: prompt user to set filter configuration
*/
// Get property page interface
HRESULT hr;
IAMVfwCaptureDialogs* pDlg;
hr = m_pAudioCapture->QueryInterface(IID_IAMVfwCaptureDialogs, (void**)(&pDlg));
if(!FAILED(hr))
{
if ( !FAILED(pDlg->HasDialog(VfwCaptureDialog_Format)))
{
hr = pDlg->ShowDialog(VfwCaptureDialog_Format, hParent);
}
if ( !FAILED(pDlg->HasDialog(VfwCaptureDialog_Source)))
{
hr = pDlg->ShowDialog(VfwCaptureDialog_Source, hParent);
}
if ( !FAILED(pDlg->HasDialog(VfwCaptureDialog_Display)))
{
hr = pDlg->ShowDialog(VfwCaptureDialog_Display, hParent);
}
return hr;
}
ISpecifyPropertyPages *pSpec;
hr = m_pAudioCapture->QueryInterface(IID_ISpecifyPropertyPages, (void**)(&pSpec));
if(FAILED(hr))
{
return E_FAIL;
}
// Popup page
CString str(_T("Audio Capture Configuration 1")); // dlg caption
WCHAR wstrCaption[256];
CAUUID cauuid;
pSpec->GetPages(&cauuid);
pSpec->Release();
if(cauuid.cElems >= 1)
{
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
str.GetBuffer(str.GetLength()), -1,
wstrCaption, sizeof(wstrCaption) / sizeof(WCHAR));
hr = OleCreatePropertyFrame(hParent, 30, 30, wstrCaption, 1,
(IUnknown **)&m_pAudioCapture, cauuid.cElems,
(GUID *)cauuid.pElems, 0, 0, NULL);
if(FAILED(hr))
{
CoTaskMemFree(cauuid.pElems);
pSpec->Release();
return E_FAIL;
}
}
// Destructor
CoTaskMemFree(cauuid.pElems);
return S_OK;
}
//Arthur?
bool isEqualFOURCC(FOURCC fccA, FOURCC fccB) {
int i;
for(i=0; i<4; i++) {
if (tolower((unsigned char)fccA) != tolower((unsigned char)fccB))
return false;
fccA>>=8;
fccB>>=8;
}
return true;
}
////////////////
HIC hic=0;
BYTE *pState = NULL;
int size = 0;
ICINFO in;
STDMETHODIMP CCaptureGraph::ConfigVideoEncoderByName(HWND hParent)
{
HRESULT hr;
if (NULL == m_pVideoEncoder)
{
return E_FAIL;
}
if (NULL == hParent)
{
AfxMessageBox("hParent不能为空");
}
hr = m_pGB->AddFilter(m_pVideoEncoder, NULL);
if (FAILED(hr))
{
return E_FAIL;
}
if (TRUE == IsDMOFilter())
{
return S_OK;
}
//ASSERT(m_pVideoEncoder);
if(hic)
{
ICClose(hic);
TRACE("hic值为:%d",hic);
}
//Arthur:?将压缩信息中ICTYPE_VIDEO进行枚举。若能打开则取出他的信息。
//判断它的描述信息是否和当前的m_strCurVideoEncoder一致。一致则显示配置
//配置信息框。(若pState中有可设置的值。则将之,设入。?是否会将上次的
//pState设置到这次的hic中去。)再用ICGetState得到信息。再将之设回去??
//何必呢?并将之保存在state变量中。
//一切连接好后,若用户选择马上中断则会,将全部filter移出。若不是则将之
//移出后再立刻接上会不会有问题,是否执行了重定位操作。
ICINFO info;
for(int i=0; ICInfo(ICTYPE_VIDEO, i, &info); i++)//Arthur:该函数的用法逐步取出i个ICINFO结构。
{
hic = ICOpen(info.fccType, info.fccHandler, ICMODE_COMPRESS);//Arthur:打开该压缩器。
if(hic == NULL)
continue;
ICINFO ici = { sizeof(ICINFO) };
CHAR* lpszDes;
if (ICGetInfo(hic, &ici, sizeof(ICINFO)))//Arthur:得到该压缩器。并将描述信息放入
//lpszDes中
{
int cch = lstrlenW(ici.szDescription) + 1;
lpszDes = new char[cch * 2];
if (!lpszDes)
{
AfxMessageBox("开辟描述名buf失败");
return E_OUTOFMEMORY;
}
WideCharToMultiByte(GetACP(), 0, ici.szDescription,
-1,lpszDes, cch, NULL, NULL);
}
if(CString(lpszDes) == m_strCurVideoEncoder)//若取出的,是自己要的
{
if(ICQueryConfigure(hic))
{
if (state)
ICSetState(hic, state, sstate);
if (NULL == hParent || 0 == hic)
{
AfxMessageBox("父窗口指针为空,无法显示");
return E_FAIL;
}
ICConfigure(hic, hParent);//Arthur:显示该压缩码的对话框。
if(pState)
delete [] pState;
size = ICGetStateSize(hic);
pState = new BYTE[size];
if (0 == hic || NULL == pState)
{
AfxMessageBox("pState为零");
return E_FAIL;
}
int nt = ICGetState(hic, pState, size);//Arthur:得到hic此时的状态信息
if(nt > 0)
{
m_config = TRUE;
if (NULL == state)
{
state=new BYTE[size + 1];
if (NULL == state)
{
AfxMessageBox("State为零");
return E_FAIL;
}
}
ICSetState(hic, pState, size);//为什么要重新设置一次,此时pState的信息已经是完善了的。
memcpy(state,pState,size);
sstate=size;
}
}
if (lpszDes)
{
delete [] lpszDes;
}
break;
}
ICClose(hic);
hic = 0;
if (lpszDes)
{
delete [] lpszDes;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -