这篇文章是对以前写过的《显示压缩前的和压缩后的视频》的补充和完善
《显示压缩前的和压缩后的视频》原文如下:
要想显示压缩前的和压缩后的视频流要用到IWMEncDataView 接口。要使用IWMEncDataViewCollection::Add方法增加一个IWMEncDataView 接口。
显示编码前的窗口
代码如下://一些基本设定省略。
IWMEncDataView* pPreview;
IWMEncDataViewCollection* pPreviewColl;
hr = CoCreateInstance( CLSID_WMEncPreview,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWMEncDataView,
(void**)&pPreview);
// Retrieve the preview collection.
hr = pVidSrc->get_PreviewCollection( &pPreviewColl );
long lCookie = -1;//设定为-1,则编码则自动给你加一个唯一的cookie。
hr = pPreviewColl->Add( pPreview, &lCookie);
HWND hWnd;//一个窗口句柄,如果没有设定,则会自动调用一个系统的窗口。
hr = pPreview->SetViewSetting((DWORD) lCookie, sizeof(hWnd),
(BYTE*)&hWnd);
hr = pEncoder->Start();
// Start viewing the stream in a pop-up window.
hr = pPreview->Start(lCookie); //开始编码后,显示窗口。
显示编码后的窗口
IWMEncDataView* pPostview;
IWMEncDataViewCollection* pPostviewColl;
hr = CoCreateInstance( CLSID_WMEncPreview,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWMEncDataView,
(void**)&p
Postview);
// Retrieve the preview collection.
hr = pVidSrc->get_
PostviewCollection( &p
PostviewColl );
long lCookie = -1;//设定为-1,则编码则自动给你加一个唯一的cookie。
hr = p
PostviewColl->Add( p
Postview, &lCookie);
HWND hWnd;//一个窗口句柄,如果没有设定,则会自动调用一个系统的窗口。
hr = p
Postview->SetViewSetting((DWORD) lCookie, sizeof(hWnd),
(BYTE*)&hWnd);
hr = pEncoder->Start();
// Start viewing the stream in a pop-up window.
hr = p
Postview->Start(lCookie); //开始编码后,显示窗口。
上文只是说明了显示窗口的设置,没有文件输入和格式选择等操作,因此每次都要改源码来控制打开文件、存储路径、编码格式,改进了的程序运行界面如下:
其中的两个文件路径分别用Cstring m_path, m_path1
浏览按钮的实现分别如下:
CFileDialog file(true);//true为打开一个文件,false为保存一个文件
file.DoModal(); //响应点击事件
m_path=file.GetPathName(); //得到文件的完整路径
this->UpdateData(false); //更新数据
GetDlgItem(IDC_SCREEN) //使屏幕捕获和视频设备的按钮无效,因为已经选择了文件编码。这样会使程序更健壮一些,否则无意中点了这两个按钮会出现意外的错误。
->EnableWindow(FALSE);
GetDlgItem(IDC_DEVICE)
->EnableWindow(FALSE);
CFileDialog file1(false,".wmv",NULL,OFN_HIDEREADONLY, //保存一个文件,而且以.wmv为扩展名
"WMV Files (*.wmv)|*.wmv|");
file1.DoModal();
if(m_path1=file1.GetPathName())
GetDlgItem(IDC_COMBO)
->EnableWindow(TRUE);
this->UpdateData(false);
其中得到编码格式是通过在窗口初始化的时候加入的,通过CPreviewsDlg::Choice();调用自定义的函数,Choice()函数的具体实现如下:
void CPreviewsDlg::Choice()
{
HRESULT hr;
IWMEncoder* pEncoder;
IWMEncProfileCollection* pProColl;
IWMEncProfile* pPro;
long lCount;
int i;
// Initialize the COM library and retrieve a pointer
// to an IWMEncoder interface.
hr = CoInitialize(NULL);
hr = CoCreateInstance(CLSID_WMEncoder,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWMEncoder,
(void**) &pEncoder);
// Retrieve a pointer to an IWMEncProfileCollection interface.
hr = pEncoder->get_ProfileCollection(&pProColl);
// Loop through the profile collection and retrieve a specific
// profile.
CString str;
CComBSTR bstrName(L"");
hr = pProColl->get_Count(&lCount);
for (i=0; i<lCount; i++)
{
hr = pProColl->Item(i, &pPro);
hr = pPro->get_Name(&bstrName);
str=bstrName.Copy();
m_choice.InsertString(i,str);
}
pEncoder->Release();
}
并使用CcomboBox类的OnSelchangeCombo()来得到选择编码的格式
void CPreviewsDlg::OnSelchangeCombo()
{
j=m_choice.GetCurSel(); //把当前的选择赋值给j
if(j!=100) //j的初值为100,如果不等于100说明已经选择了格式
GetDlgItem(IDC_START) //使开始编码按钮有效
->EnableWindow(TRUE);
}
关于屏幕和设备的区别是通过全局变量h来标志的,h=1是屏幕捕获, h=2是从设备得到视频。程序如下:
void CPreviewsDlg::OnScreen()
{
h=1;
GetDlgItem(IDC_DEVICE)
->EnableWindow(FALSE);
GetDlgItem(IDC_BROWER)
->EnableWindow(FALSE);
}
void CPreviewsDlg::OnDevice()
{
h=2;
GetDlgItem(IDC_SCREEN)
->EnableWindow(FALSE);
GetDlgItem(IDC_BROWER)
->EnableWindow(FALSE);
}
当配置好后,就可以开始编码了,程序如下:
void CPreviewsDlg::OnStart()
{
hwnd=::GetDlgItem(this->GetSafeHwnd(),IDC_VIEW); //得到预览编码前窗口的句柄
phwnd=::GetDlgItem(this->GetSafeHwnd(),IDC_POSTVIEW); //得到预览编码后窗口的句柄
// g_MyThread->SetParentWnd(hwnd); //可以去掉
g_MyThread->PostThreadMessage(WM_START,0,0 ); //给线程发送消息,开始编码
GetDlgItem(IDC_WATCH)
->EnableWindow(TRUE);
GetDlgItem(IDC_STOP)
->EnableWindow(TRUE);
GetDlgItem(IDC_START)
->EnableWindow(FALSE);
}
线程中的开始函数如下:
void CMyThread::OnStart( WPARAM wParam, LPARAM lParam)
{
IWMEncSourceGroupCollection* pSrcGrpColl;
IWMEncSourceGroup* pSrcGrp;
IWMEncSource* pAudSrc1;
IWMEncSource* pSrc1;
IWMEncVideoSource* pVidSrc1;
// IWMEncDataView* pPreview;
IWMEncDataViewCollection* pPostviewColl;
IWMEncDataViewCollection* pPreviewColl;
IWMEncProfileCollection* pProColl;
IWMEncSourcePluginInfoManager* pSrcPlugMgr;
IWMEncPluginInfo* pPlugInfo;
IWMEncProfile* pPro;
IWMEncDisplayInfo* pDispInfo;
IWMEncAttributes* pAttr;
IWMEncBroadcast* pBrdcast;
IWMEncFile* pFile;
WMENC_ENCODER_STATE enumEncoderState;
CComBSTR bstrResource(L"");
long lCount;
short i;
hr = CoInitialize(NULL);
hr = CoCreateInstance(CLSID_WMEncoder, //初始化com库
NULL,
CLSCTX_INPROC_SERVER,
IID_IWMEncoder,
(void**) &pEncoder);
// Retrieve a pointer to an IWMEncSourceGroupCollection
// interface.
hr = pEncoder->get_SourceGroupCollection(&pSrcGrpColl);
// Add a source group to the collection. named "SG_1"
hr = pSrcGrpColl->Add(L"SG_1", &pSrcGrp);
// Add a video and audio source to the source group.
hr = pSrcGrp->AddSource(WMENC_VIDEO, &pSrc1);
hr = pSrcGrp->AddSource(WMENC_AUDIO, &pAudSrc1);
// Retrieve a pointer to an IWMEncVideoSource interface.
hr = pSrc1->QueryInterface(IID_IWMEncVideoSource,
(void**)&pVidSrc1);
if(h==0) //h=0说明是编码文件
{
CComBSTR bstrInFile("");
bstrInFile.Append(pThread->m_path); //CString和CComBSTR的转化
hr = pAudSrc1->SetInput(bstrInFile);
hr = pVidSrc1->SetInput(bstrInFile);
}
else
{
hr = pEncoder->get_SourcePluginInfoManager(&pSrcPlugMgr);
hr = pSrcPlugMgr->Item(0, &pPlugInfo);
hr = pPlugInfo->Item(1, &bstrResource); //设置声音的输入
CComBSTR Aud(L"DEVICE://");
Aud.Append(bstrResource);
hr=pAudSrc1->SetInput(Aud);
if(h==1)
hr=pVidSrc1->SetInput(L"ScreenCap://Screen Capture"); //如果h=1,视频来源为屏幕
else
{
hr = pSrcPlugMgr->Item(1, &pPlugInfo);
hr = pPlugInfo->Item(1, &bstrResource);
CComBSTR Vid(L"DEVICE://"); //得到视频设备的输入
Vid.Append(bstrResource);
hr=pVidSrc1->SetInput(Vid);
}
}
// Choose a profile from the collection.
CComBSTR bstrName = NULL;
CComVariant varProfile;
varProfile.vt = VT_DISPATCH;
hr = pEncoder->get_ProfileCollection(&pProColl);
hr = pProColl->get_Count(&lCount);
for (i=0; i<lCount; i++)
{
hr = pProColl->Item(i, &pPro);
hr = pPro->get_Name(&bstrName);
if(i==j) //选择编码格式
{
// Set the profile in the source group.
varProfile.pdispVal = pPro;
hr = pSrcGrp->put_Profile(varProfile);
break;
}
}
// Retrieve a pointer to an IWMEncDisplayInfo interface.
hr = pEncoder->get_DisplayInfo(&pDispInfo);
// Describe the encoded content.
CComBSTR bstrAuthor("Let5fly");
CComBSTR bstrCopyright("Copyright 2000. All rights reserved.");
CComBSTR bstrDescription("Description of the encoded content.");
CComBSTR bstrRating("Content rating.");
CComBSTR bstrTitle("Test the Encoder");
hr = pDispInfo->put_Author(bstrAuthor); //描述信息
hr = pDispInfo->put_Copyright(bstrCopyright);
hr = pDispInfo->put_Description(bstrDescription);
hr = pDispInfo->put_Rating(bstrRating);
hr = pDispInfo->put_Title(bstrTitle);
// Retrieve a pointer to an IWMEncAttributes interface.
hr = pEncoder->get_Attributes(&pAttr);<