分享
 
 
 

流媒体学习笔记---------编码视频的预览

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

这篇文章是对以前写过的《显示压缩前的和压缩后的视频》的补充和完善

《显示压缩前的和压缩后的视频》原文如下:

要想显示压缩前的和压缩后的视频流要用到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**)&pPostview);

// Retrieve the preview collection.

hr = pVidSrc->get_PostviewCollection( &pPostviewColl );

long lCookie = -1;//设定为-1,则编码则自动给你加一个唯一的cookie。

hr = pPostviewColl->Add( pPostview, &lCookie);

HWND hWnd;//一个窗口句柄,如果没有设定,则会自动调用一个系统的窗口。

hr = pPostview->SetViewSetting((DWORD) lCookie, sizeof(hWnd),

(BYTE*)&hWnd);

hr = pEncoder->Start();

// Start viewing the stream in a pop-up window.

hr = pPostview->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);

// Add an attribute to the attributes collection.

CComBSTR bstrAttrName(L"DateCreated: ");

CComVariant varValue;

varValue.vt = VT_BSTR;

varValue.bstrVal = L"02/15/2000";

hr = pAttr->Add(bstrAttrName,varValue);

// Retrieve a pointer to an IWMEncBroadcast interface.

hr = pEncoder->get_Broadcast(&pBrdcast);

// Specify a port number and a protocol.

hr = pBrdcast->put_PortNumber(WMENC_PROTOCOL_HTTP, 527); //设定广播端口为527

// Retrieve a pointer to an IWMEncFile interface.

hr = pEncoder->get_File(&pFile);

// Specify a file in which to save encoded content.

CComBSTR bstrSaveFile("");

bstrSaveFile.Append(pThread->m_path1); //存储编码后的文件

hr = pFile->put_LocalFileName(bstrSaveFile);

// Retrieve a pointer to a preview object.

hr = CoCreateInstance( CLSID_WMEncPreview,

NULL,

CLSCTX_INPROC_SERVER,

IID_IWMEncDataView,

(void**)&pPreview);

hr = CoCreateInstance( CLSID_WMEncPreview, //分别初始化预览窗口

NULL,

CLSCTX_INPROC_SERVER,

IID_IWMEncDataView,

(void**)&pPostview);

// Retrieve the preview collection.

hr = pSrc1->get_PreviewCollection( &pPreviewColl );

hr = pSrc1->get_PostviewCollection(&pPostviewColl);

// Add the postiew object to the data view collection. If you set the

// cookie to -1, the encoder engine automatically generates a unique

// cookie.

hr = pPreviewColl->Add( pPreview, &lCookie);

hr = pPostviewColl->Add( pPostview, &lCookiePostview);

// Continue configuring the encoder engine.

hr = pEncoder->PrepareToEncode(VARIANT_TRUE);

hr = pPreview->SetViewSetting((DWORD) lCookie,

sizeof(hwnd),

(BYTE*)&hwnd);

hr = pPostview->SetViewSetting((DWORD)lCookiePostview, //设置视频输入

sizeof(phwnd),

(BYTE*)&phwnd);

hr = pEncoder->Start();

AfxMessageBox("Encoder have start!");

// hr = pPreview->Start(lCookie);

// Wait until the engoder engine stops before exiting the application.

// You can do this by using the _IWMEncoderEvents object to create an

// event sink.

hr = pEncoder->get_RunState(&enumEncoderState); //得到运行状态

}

其中

HRESULT hr;

IWMEncoder* pEncoder;

IWMEncDataView* pPreview;

IWMEncDataView* pPostview;

long lCookie = -1;

long lCookiePostview =2;

均定义成了全局变量,因为在其他的函数中也要用到。

当要观看视频时就向线程中的watch()函数发送消息

void CPreviewsDlg::OnWatch()

{

// w=2;

g_MyThread->PostThreadMessage(WM_WATCH,0,0);

}

watch()函数通过全局变量w的值判断是显示编码前的还是编码后的视频,程序如下:

void CMyThread::Watch( WPARAM wParam, LPARAM lParam)

{

if(w==1)

hr = pPreview->Start(lCookie);

else

hr = pPostview->Start(lCookiePostview);

AfxMessageBox("Have previwe!");

}

最后要说明的一点是:线程在窗口初始的时候就创建了,并通过Gethwnd()得到窗口句柄。(因为要在CmyThread类中使用它的变量和函数)

g_MyThread = (CMyThread*)AfxBeginThread( RUNTIME_CLASS(CMyThread),0,0);

g_MyThread->Gethwnd(this);

Gethwnd()的实现如下:

CPreviewsDlg* pThread;

bool Gethwnd(CPreviewsDlg* pMain)

{

pThread=pMain;

return 1;

}

关于编码视频的预览程序介绍完了,可能说的有点乱,如果想要程序请和我联系 let5fly@msn.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有