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

原创 2003年09月17日 08:55:00

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

 

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

 

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

直播技术学习笔记(一)

播放器相关技术: 1、开源项目jjdxm_ijkplayer是基于ijkplayer简单的UI界面; ijkplayer是一个基于 FFmpeg n2.6 的开源 Android/iOS ...
  • zhaodecang
  • zhaodecang
  • 2016年11月23日 00:06
  • 15371

《流媒体技术入门与提高》读书笔记

公司是搞视频类的互联网公司,本人虽为开发人员,但因为业务相关,因此也要懂得视频和流媒体方面的知识,于是把公司图书阁里的《流媒体技术入门与提高》借回来看。我手上的是第二版。 流式技术解决方案 所谓流...
  • zhangxin09
  • zhangxin09
  • 2013年01月23日 23:16
  • 5493

学习流媒体之前需要了解的基本知识

在学习流媒体之前最重要的是先了解媒体,然后再了解流。在没有学习多媒体之前总是把多媒体的包装形式和视频的编解码方式混淆,这也是普通人容易混淆的地方,尤其是当谈到mp4和mpeg4时,最开始本人一脸懵逼,...
  • superjaingchao
  • superjaingchao
  • 2016年09月28日 14:06
  • 830

流媒体学习笔记

1,[总结]FFMPEG视音频编解码零基础学习方法 http://blog.csdn.net/leixiaohua1020/article/details/15811977 2海狗哥的流媒体空间  ...
  • xuwentao37x
  • xuwentao37x
  • 2014年03月17日 21:11
  • 588

流媒体的各种流知识点

一 从TS流开始         最近开始学习数字电视机顶盒的开发,从MPEG-2到DVB,看着看着突然就出现了一大堆表格,什么PAT、PMT、CAT……如此多的表该怎样深入了解呢?   ...
  • dafeng5455
  • dafeng5455
  • 2016年07月29日 10:47
  • 592

流媒体的一些基本概念

码率(比特率): 一般单位 bps 即位每秒。单位时间传送或处理的数据量。带宽需求看这个参数就OK了。 帧率: 在1秒钟时间里传输的图片数量,单位FPS 或Hz...
  • qq_32609385
  • qq_32609385
  • 2016年10月12日 15:00
  • 185

流媒体各种环境搭建方法

http://blog.csdn.net/funkri/article/category/1314184
  • chenchong_219
  • chenchong_219
  • 2014年07月13日 09:33
  • 1625

流媒体技术原理与应用

流媒体技术原理与应用   ...
  • tanliyoung
  • tanliyoung
  • 2007年08月10日 00:01
  • 4287

对于流媒体的一些认识

流媒体,rtmp ,rtsp,音视频,编码,解码,视频压缩
  • wf021017
  • wf021017
  • 2017年10月12日 10:32
  • 141

网络流媒体下载的 10 种方法(以下载 Echo 音乐为例)

Echo是一款基于声音/音乐内容的社交媒体型产品。最早接触Echo,是同学分享的一首 3D 音乐,不过第一次使用便发现, Echo 似乎并不支持音乐下载。 其实Echo 上的音乐都是常规的流媒体...
  • lhorse003
  • lhorse003
  • 2017年06月20日 14:20
  • 1463
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:流媒体学习笔记---------编码视频的预览
举报原因:
原因补充:

(最多只允许输入30个字)