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

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

 

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

 

要想显示压缩前的和压缩后的视频流要用到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);  //CStringCComBSTR的转化

              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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值