<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      文心公司

      文心公司

      導航

      Directshow開發(fā)的基本技巧(轉(zhuǎn))

      摘要:本篇文檔主要講述了Directshow開發(fā)的一些基本概念和技巧

       

       

      1視頻播放(Video Rendering

       

       

       

       

       

       

      dshow的視頻提交過濾器可以在窗口模式和無窗口模式下工作。在窗口模式下,過濾器創(chuàng)建一個自己的窗口,在里面播放視頻。在無窗口模式下,過濾器直接將視頻在應用程序提供的窗口上顯示,過濾器本身不創(chuàng)建窗口。

      窗口模式

       

       

       

       

      在窗口模式下,視頻提交過濾器創(chuàng)建一個窗口,然后將視頻禎帖到窗口上,你可以將這個窗口帖到你的應用程序的窗口。

       Video Renderer只支持窗口模式,VMR-7 and VMR-9缺省的是窗口模式,也支持無窗口模式。

      為了在你的應用程序中顯示視頻,你可以將視頻窗口設置成應用程序的子窗口。你可以通過

      IVideoWindow *pVidWin = NULL;

      pGraph->QueryInterface(IID_IVideoWindow, (void **)&g_pVidWin);

      pVidWin->put_Owner((OAHWND)hwnd);

      pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

      RECT grc;

      GetClientRect(hwnd, &grc);

      pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);

      結(jié)束時一定要清理現(xiàn)場

      pControl->Stop();
      

       

      pVidWin->put_Visible(OAFALSE);
      

       

      pVidWin->put_Owner(NULL); 
      

       

      
      

       

      無窗口模式

       

       

       

       

      當采用無窗口的模式時,就沒有必要暴露IVideoWindow接口了。

      為了能夠使用VMR的缺省行為,在構(gòu)建Graph圖之前必須要調(diào)整VMR

      1 創(chuàng)建一個過慮器圖表管理器,

      2創(chuàng)建一個VMR,加入到graph中,

      3 調(diào)用VMRIVMRFilterConfig::SetRenderingMode方法設置VMRMode_Windowless標志。

      4調(diào)用IVMRWindowlessControl::SetVideoClippingWindow 給視頻指定一個顯示窗口。

      然后調(diào)用IGraphBuilder::RenderFile或者其他的方法來創(chuàng)建其他的Graph

      下面的代碼顯示了如何創(chuàng)建一個VMR,將其添加到Graph,如何設置無窗口模式

       

       

       

       

      HRESULT InitWindowlessVMR(

          HWND hwndApp,                  // Window to hold the video.

          IGraphBuilder* pGraph,         // Pointer to the Filter Graph Manager.

          IVMRWindowlessControl** ppWc, // Receives a pointer to the VMR.   )

      {

          if (!pGraph || !ppWc) return E_POINTER;

          IBaseFilter* pVmr = NULL;

          IVMRWindowlessControl* pWc = NULL;

          // Create the VMR.

          HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,

              CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);

          if (FAILED(hr))

          {

              return hr;

          }

         

          // Add the VMR to the filter graph.

          hr = pGraph->AddFilter(pVmr, L"Video Mixing Renderer");

          if (FAILED(hr))

          {

              pVmr->Release();

              return hr;

          }

          // Set the rendering mode. 

          IVMRFilterConfig* pConfig;

          hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);

          if (SUCCEEDED(hr))

          {

              hr = pConfig->SetRenderingMode(VMRMode_Windowless);

              pConfig->Release();

          }

          if (SUCCEEDED(hr))

          {

              // Set the window.

              hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);

              if( SUCCEEDED(hr))

              {

                  hr = pWc->SetVideoClippingWindow(hwndApp);

                  if (SUCCEEDED(hr))

                  {

                      *ppWc = pWc; // Return this as an AddRef'd pointer.

                  }

                  else

                  {

                      // An error occurred, so release the interface.

                      pWc->Release();

                  }

              }

          }

          pVmr->Release();

          return hr;

      }

      你也可以調(diào)用下面的函數(shù)

      IVMRWindowlessControl *pWc = NULL;

      hr = InitWindowlessVMR(hwnd, pGraph, &g_pWc);

      if (SUCCEEDED(hr))

      {

          // Build the graph. For example:

          pGraph->RenderFile(wszMyFileName, 0);

          // Release the VMR interface when you are done.

          pWc->Release();

      }

      下面看看如何設置視頻的位置

       

       

       

       

      有兩個矩形需要考慮,一個是源矩形,一個是目的矩形。源矩形決定開始播放視頻的位置,目的矩形決定在窗口顯示視頻的區(qū)域。VMR將源矩形按照目的矩形的大小進行擴展。

      IVMRWindowlessControl::SetVideoPosition可以設置兩個矩形的大小,源矩形必須小于等于本地視頻大小。你可以通過IVMRWindowlessControl::GetNativeVideoSize獲取本地的視頻區(qū)域大小。

      // Find the native video size.

      long lWidth, lHeight;

      HRESULT hr = g_pWc->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);

      if (SUCCEEDED(hr))

      {

          RECT rcSrc, rcDest;

          // Set the source rectangle.

          SetRect(&rcSrc, 0, 0, lWidth/2, lHeight/2);

         

          // Get the window client area.

          GetClientRect(hwnd, &rcDest);

          // Set the destination rectangle.

          SetRect(&rcDest, 0, 0, rcDest.right/2, rcDest.bottom/2);

         

          // Set the video position.

          hr = g_pWc->SetVideoPosition(&rcSrc, &rcDest);

      }

      處理窗口消息

      因為VMR沒有自己的窗口,所以當視頻需要重畫或者改變的時候你要通知它。

      1 當你接到一個WM_PAINT消息,你就要調(diào)用IVMRWindowlessControl::RepaintVideo來重畫視頻

      2 當你接到一個WM_DISPLAYCHANGE消息,你就要調(diào)用IVMRWindowlessControl::DisplayModeChanged.

      3 當你接到一個WM_SIZE消息時,重新計算視頻的位置,然后調(diào)用SetVideoPostion

      下面的代碼演示了WM_PAINT消息的處理

      void OnPaint(HWND hwnd)

      {

          PAINTSTRUCT ps;

          HDC         hdc;

          RECT        rcClient;

          GetClientRect(hwnd, &rcClient);

          hdc = BeginPaint(hwnd, &ps);

          if (g_pWc != NULL)

          {

              // Find the region where the application can paint by subtracting

              // the video destination rectangle from the client area.

              // (Assume that g_rcDest was calculated previously.)

              HRGN rgnClient = CreateRectRgnIndirect(&rcClient);

              HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest); 

              CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF); 

             

              // Paint on window.

              HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);

              FillRgn(hdc, rgnClient, hbr);

       

       

       

       

              // Clean up.

              DeleteObject(hbr);

              DeleteObject(rgnClient);

              DeleteObject(rgnVideo);

       

       

       

       

              // Request the VMR to paint the video.

              HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc); 

          }

          else // There is no video, so paint the whole client area.

          {

              FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1));

          }

          EndPaint(hwnd, &ps);

      }

      盡管我們要自己處理onpaint消息,但是已經(jīng)非常簡單了。

      2 如何處理事件通知(Event Notification

       

        當一個Directshow的應用程序運行的時候,在 filter Graph內(nèi)部就會發(fā)生各種各樣的事件,例如,一個filter也許發(fā)生數(shù)據(jù)流錯誤。Filter通過給graph mangaer發(fā)送事件通知來和graph通信,這個事件通知包括一個事件碼和兩個事件參數(shù)。事件碼表示發(fā)生事件的類型,兩個參數(shù)用來傳遞信息。

       

       

       

       

      Filter發(fā)送的這些事件,其中的一部分可以被Manager直接處理,不通知應用程序,但有一部分事件,Manager將事件放入到一個隊列中,等待應用程序處理。這里我們主要討論在應用程序中經(jīng)常遇到的三種事件

       

       

       

       

      EC_COMPLETE表明回放已經(jīng)結(jié)束

       

       

       

       

      EC_USERABORT表明用戶中斷了回放。用戶關閉視頻播放窗口時,視頻Render會發(fā)生這個事件

       

       

       

       

      EC_ERRORABORT表明出現(xiàn)了一個錯誤。

       

       

       

       

      應用程序可以通知filter graph manager,在某個指定的事件發(fā)生時,向指定的窗口發(fā)生一個指定的消息。這樣應用程序就可以在消息循環(huán)中對發(fā)生的事件產(chǎn)生反應。

       

       

       

       

        首先定義消息,

      #define WM_GRAPHNOTIFY WM_APP + 1

       

       

       

       

        然后向filter graph manager請求IMediaEventEx接口,然后調(diào)用IMediaEventEx::SetNotifyWindow方法來設置消息通知窗口

      IMediaEventEx *g_pEvent = NULL;

      g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);

      g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

      然后在WindowProc函數(shù)增加一個處理WM_GRAPHNOTIFY消息的函數(shù)

      case WM_GRAPHNOTIFY:

          HandleGraphEvent();

          break;

      HandleGraphEvent()函數(shù)具體定義如下

      void HandleGraphEvent()

      {

          // Disregard if we don't have an IMediaEventEx pointer.

          if (g_pEvent == NULL)

          {

              return;

          }

          // Get all the events

          long evCode;

          LONG_PTR param1, param2;

          HRESULT hr;

          while (SUCCEEDED(g_pEvent->GetEvent(&evCode, &param1, &param2, 0)))

          {

              g_pEvent->FreeEventParams(evCode, param1, param2);

              switch (evCode)

              {

              case EC_COMPLETE: // Fall through.

              case EC_USERABORT: // Fall through.

              case EC_ERRORABORT:

                  CleanUp();

                  PostQuitMessage(0);

                  return;

              }

          }

      }

      在釋放IMediaEventEx指針前,要取消事件通知消息,代碼如下

      // Disable event notification before releasing the graph.

      g_pEvent->SetNotifyWindow(NULL, 0, 0);

      g_pEvent->Release();

      g_pEvent = NULL;

       

       

       

       

       

       

       

       

      3如何枚舉系統(tǒng)的設備和過慮器

       

        有時,應用程序需要查看系統(tǒng)中所有的filter。例如,視頻應用程序需要列出系統(tǒng)中可用的捕捉設備。因為dshow基于com結(jié)構(gòu)的,你在設計程序的時候是沒法知道系統(tǒng)中正在使用的過濾器。Directshow提供了兩種方法來枚舉系統(tǒng)中注冊的過慮器。

      1 系統(tǒng)設備枚舉器

       

       

       

       

      系統(tǒng)設備枚舉器提供了一個很好的方法根據(jù)種類來枚舉系統(tǒng)中注冊的過慮器。也許枚一種不同的硬件都會有自己的過慮器,或許所有的硬件設備共用同一個filter。這個對于采用WDM驅(qū)動程序的硬件很有用。

      系統(tǒng)設備枚舉器根據(jù)不同的種類創(chuàng)建了一個枚舉器,例如,音頻壓縮,視頻捕捉。不同種類的枚舉器對于每一種設備返回一個獨立的名稱(moniker)。種類枚舉器自動將相關的即插即用,演播設備包括進來。

      按照下面的步驟使用設備枚舉器

      1 創(chuàng)建枚舉器組件,CLSIDCLSID_SystemDeviceEnum

      2 指定某一種類型設備,參數(shù)CLSID,通過ICreateDevEnum::CreateClassEnumerator獲取某一種類的枚舉器,這個函數(shù)返回一個IEnumMoniker接口指針,如果該種類的空或者不存在,這個方法就返回S_FALSE。因此,當你調(diào)用這個函數(shù)時一定要檢查返回值是否為S_OK,而不要用SUCCEEDED宏。

       

       

       

       

      3 然后IEnumMoniker::Next枚舉每一個moniker。這個方法返回一個IMoniker接口指針。

       

       

       

       

      4 要想知道設備的名稱,可以通過下面的函數(shù)IMoniker::BindToStorage

       

       

       

       

      5 然后利用IMoniker::BindToObject生成綁定道設備上的filter。調(diào)用IFilterGraph::AddFilterfilter添加到Graph圖中。

             1

      // Create the System Device Enumerator.

      HRESULT hr;

      ICreateDevEnum *pSysDevEnum = NULL;

      hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,

       

       

       

       

          IID_ICreateDevEnum, (void **)&pSysDevEnum);

       

       

       

       

      if (FAILED(hr))

      {

          return hr;

      }

       

       

       

       

      // Obtain a class enumerator for the video compressor category.

      IEnumMoniker *pEnumCat = NULL;

      hr=pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);

       

       

       

       

       

       

       

       

      if (hr == S_OK)

      {

          // Enumerate the monikers.

          IMoniker *pMoniker = NULL;

          ULONG cFetched;

          while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)

          {

              IPropertyBag *pPropBag;

              hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,

       

       

       

       

                  (void **)&pPropBag);//知道設備的名稱

              if (SUCCEEDED(hr))

              {

                  // To retrieve the filter's friendly name, do the following:

                  VARIANT varName;

                  VariantInit(&varName);

                  hr = pPropBag->Read(L"FriendlyName", &varName, 0);

                  if (SUCCEEDED(hr))

                  {

                      // Display the name in your UI somehow.

                  }

                  VariantClear(&varName);

       

       

       

       

                  // To create an instance of the filter, do the following:

                  IBaseFilter *pFilter;

                  hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,

       

       

       

       

                      (void**)&pFilter); //生成一個filter綁定到設備上。

                  // Now add the filter to the graph.

                  //Remember to release pFilter later.

                  pPropBag->Release();

              }

              pMoniker->Release();

          }

          pEnumCat->Release();

      }

      pSysDevEnum->Release();

      在上面我們IMoniker::BindToObject生成綁定道設備上的filter,當然我們還可以用另外的一種方法來生成綁定到設備上的filter

       

       

       

       

      利用IMoniker::GetDisplayName得到moniker的名字。然后你把moniker的名字做參數(shù)傳遞給IFilterGraph2::AddSourceFilterForMoniker,就可以創(chuàng)建一個綁定到設備的filter了。在上面我們是調(diào)用IMoniker::BindToObject生成filter的,還是上面的簡單些。看看代碼吧。

       

       

       

       

      LPOLESTR strName = NULL;

      IBaseFilter pSrc = NULL;

      hr = pMoniker->GetDisplayName(NULL, NULL, &strName);

      if (SUCCEEDED(hr))

      {

          // Query the Filter Graph Manager for IFilterGraph2.

          IFilterGraph2 *pFG2 = NULL;

          hr = pGraph->QueryInterface(IID_IFilterGraph2, (void**)&pFG2);

          if (SUCCEEDED(hr))

          {

              hr = pFG2->AddSourceFilterForMoniker(pMoniker, 0, L"Source", &pSrc);

              pFG2->Release();

          }

          CoTaskMemFree(strName);

      }

      // If successful, remember to release pSrc.

      2 Filter Mapper

       

       

       

       

        搜索系統(tǒng)中的filter的另一個方法就是采用Filer MapperFilter mapper是一個com對象,它按照一定的條件來搜索系統(tǒng)的filer,它比系統(tǒng)設備枚舉器(System Device Enumerator)的效率要低一些。所以當你要枚舉某特定種類的filter時,你應該使用系統(tǒng)設備枚舉器,但是當你搜索支持某種媒體類型的filter時,同時也找不到清晰的filter,你應該使用filter mapper

      Filter Mapper 暴露一個IFilerMapper2接口,要想搜索一個接口,你可以調(diào)用該接口的IFilterMapper2::EnumMatchingFilters方法,這個方法需要傳遞一些參數(shù)來定義搜索條件,同時該方法返回一個適合條件的filter的枚舉器,這個枚舉器提供一個IEnumMoniker接口,并且對于每個適合的filter都提供一個單獨的moniker

      下面的例子演示了,枚舉所有的支持DV,并且至少有一個輸出pinfilter,這個filter支持任何媒體類型。

      IFilterMapper2 *pMapper = NULL;

      IEnumMoniker *pEnum = NULL;

       

       

       

       

      hr =CoCreateInstance( CLSID_FilterMapper2,NULL, CLSCTX_INPROC, IID_IFilterMapper2,

                          (void **) &pMapper);

      if (FAILED(hr))

      {

          // Error handling omitted for clarity.

      }

       

       

       

       

      GUID arrayInTypes[2];

      arrayInTypes[0] = MEDIATYPE_Video;

      arrayInTypes[1] = MEDIASUBTYPE_dvsd;

       

       

       

       

      hr = pMapper->EnumMatchingFilters(

              &pEnum,

              0,                  // Reserved.

              TRUE,               // Use exact match?

              MERIT_DO_NOT_USE+1, // Minimum merit.

              TRUE,               // At least one input pin?

       

       

       

       

              1,                  // Number of major type/subtype pairs for input.

              arrayInTypes,       // Array of major type/subtype pairs for input.

              NULL,               // Input medium.

              NULL,               // Input pin category.

              FALSE,              // Must be a renderer?

              TRUE,               // At least one output pin?

              0,                  // Number of major type/subtype pairs for output.

              NULL,               // Array of major type/subtype pairs for output.

              NULL,               // Output medium.

              NULL);              // Output pin category.

       

       

       

       

      // Enumerate the monikers.

      IMoniker *pMoniker;

      ULONG cFetched; 

      //////////下面就是枚舉filter了,就是系統(tǒng)枚舉設備filter

      while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)

      {

          IPropertyBag *pPropBag = NULL;

          hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,

             (void **)&pPropBag);

       

       

       

       

          if (SUCCEEDED(hr))

          {

              // To retrieve the friendly name of the filter, do the following:

              VARIANT varName;

              VariantInit(&varName);

              hr = pPropBag->Read(L"FriendlyName", &varName, 0);

              if (SUCCEEDED(hr))

              {

                  // Display the name in your UI somehow.

              }

              VariantClear(&varName);

       

       

       

       

              // To create an instance of the filter, do the following:

              IBaseFilter *pFilter;

              hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter);

              // Now add the filter to the graph. Remember to release pFilter later.

         

              // Clean up.

              pPropBag->Release();

          }

          pMoniker->Release();

      }

      // Clean up.

      pMapper->Release();

      pEnum->Release();

      4如何枚舉Graph圖中的對象(filterpin

       

      有些時候,應用程序需要枚舉graph中的filter或者是枚舉filter所支持的pin。因此directshow提供了枚舉graph filter中的com組件方法。

      1 枚舉filter

       

       

       

       

      Filter圖表管理器支持IFilterGraph::EnumFilters方法,來枚舉graph圖中的所有的filter。他返回一個IEnumFilters接口,利用這個接口就可以遍歷graph中的所有的filter

      下面的代碼演示了,如何遍歷graph中的filter,并且顯示filter的名字。

      HRESULT EnumFilters (IFilterGraph *pGraph)

      {

          IEnumFilters *pEnum = NULL;

          IBaseFilter *pFilter;

          ULONG cFetched;

          HRESULT hr = pGraph->EnumFilters(&pEnum);

          if (FAILED(hr)) return hr;

          while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)

          {

              FILTER_INFO FilterInfo;

              hr = pFilter->QueryFilterInfo(&FilterInfo);

              if (FAILED(hr))

              {

                  MessageBox(NULL, TEXT("Could not get the filter info"),

                      TEXT("Error"), MB_OK | MB_ICONERROR);

                  continue; // Maybe the next one will work.

              }

       

       

       

       

      #ifdef UNICODE

              MessageBox(NULL, FilterInfo.achName, TEXT("Filter Name"), MB_OK);

      #else

              char szName[MAX_FILTER_NAME];

              int cch = WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName,

                  MAX_FILTER_NAME, szName, MAX_FILTER_NAME, 0, 0);

              if (chh > 0)

                  MessageBox(NULL, szName, TEXT("Filter Name"), MB_OK);

      #endif

              // The FILTER_INFO structure holds a pointer to the Filter Graph

              // Manager, with a reference count that must be released.

              if (FilterInfo.pGraph != NULL)

              {

                  FilterInfo.pGraph->Release();

              }

              pFilter->Release();

          }

          pEnum->Release();

          return S_OK;

      }

      2 枚舉pin

       

       

       

       

      Filter支持IBaseFilter::EnumPins方法,這個方法可以可以枚舉filter所有的pin。它返回一個IEnumPins接口,IEnumPins::Next可以遍歷pin的接口。

      下面的代碼演示了如何如何查找一個輸出和輸入pin。利用PIN_DIRECTION參數(shù)來制定pin的類型(輸入還是輸出)。

      HRESULT GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)

      {

          IEnumPins *pEnum = NULL;

          IPin       *pPin = NULL;

          HRESULT    hr;

       

       

       

       

          if (ppPin == NULL)

          {

              return E_POINTER;

          }

       

       

       

       

          hr = pFilter->EnumPins(&pEnum);

          if (FAILED(hr))

          {

              return hr;

          }

          while(pEnum->Next(1, &pPin, 0) == S_OK)

          {

              PIN_DIRECTION PinDirThis;

              hr = pPin->QueryDirection(&PinDirThis);

              if (FAILED(hr))

              {

                  pPin->Release();

                  pEnum->Release();

                  return hr;

              }

              if (PinDir == PinDirThis) //如果類型符合

              {

                  // Found a match. Return the IPin pointer to the caller.

                  **ppPin = pPin;

                  pEnum->Release();

                  return S_OK;

              }

              // Release the pin for the next time through the loop.

              pPin->Release();

          }

          // No more pins. We did not find a match.

          pEnum->Release();

          return E_FAIL; 

      }

      利用這個方法可以很容易的就查找一個pin,然后調(diào)用IPin::ConnectedTo方法確定這個pin是否被連接,可以查找一個空閑的pin

      3 查找媒體類型

       

       

       

       

      每個pin都支持一個IPin::EnumMediaTypes方法,可以來枚舉pin支持的媒體類型。它返回一個IEnumMediaTypes接口,這個接口的方法IEnumMediaTypes::Next返回一個指向AM_MEDIA_TYPE類型的指針。可以參考上面的代碼來遍歷pin所支持的媒體類型。

      5 Seeking Filter graph

       

      主要講述了如何在一個媒體數(shù)據(jù)流中定位,任意指定開始播放的位置。

      1 檢查是否支持seek

      Directshow通過IMediaSeeking接口支持seekingFilter graph管理器支持這個接口,但是實際seeking的功能是有graph中的filter來實現(xiàn)的。

      有一些數(shù)據(jù)是不能seek的,例如,你不可能seek從照相機中采集的活動的視頻流。如果一個數(shù)據(jù)流可以被seek,但是,seek的類型還分以下幾種類型,可以給你的數(shù)據(jù)流選擇一種

      1 定位到數(shù)據(jù)流中的一個絕對位置

      2 返回數(shù)據(jù)流的持續(xù)時間

      3返回數(shù)據(jù)流中的當前播放位置

      4回放。

      IMediaSeeking接口定義了一套標志AM_SEEKING_SEEKING_CAPABILITIES,用來描述可能支持的seek功能。

      typedef enum AM_SEEKING_SeekingCapabilities {
      

       

          AM_SEEKING_CanSeekAbsolute        = 0x1,
      

       

          AM_SEEKING_CanSeekForwards        = 0x2,
      

       

          AM_SEEKING_CanSeekBackwards       = 0x4,
      

       

          AM_SEEKING_CanGetCurrentPos       = 0x8,
      

       

          AM_SEEKING_CanGetStopPos          = 0x10,
      

       

          AM_SEEKING_CanGetDuration         = 0x20,
      

       

          AM_SEEKING_CanPlayBackwards       = 0x40,
      

       

          AM_SEEKING_CanDoSegments          = 0x80,
      

       

          AM_SEEKING_Source                 = 0x100
      

       

      }   AM_SEEKING_SEEKING_CAPABILITIES;
      

       

       

       

       

       

      可以通過IMediaSeeking::GetCapabilities查看數(shù)據(jù)流支持的seek能力都有哪些。應用程序可以采取 &測試每一項。例如,下面的代碼檢查了graph是否可以seek 一個任意的位置

       DWORD dwCap = 0;

       

       

       

       

      HRESULT hr = pSeek->GetCapabilities(&dwCap);

       

       

       

       

      if (AM_SEEKING_CanSeekAbsolute & dwCap)

       

       

       

       

      {

       

       

       

       

          // Graph can seek to absolute positions.

       

       

       

       

      }

       

       

       

       

      2Setting and Retrieving the Position

       

       

       

       

       Filter graph包含兩個位置,當前位置和停止位置,定義如下:

       1當前位置,當一個graph正處于運行的時候,當前位置就是當前的回放位置,相對于開始的位置而言。如果graph處于停止或者暫停狀態(tài)的時候,當前位置就是數(shù)據(jù)流下次開始播放的位置點。

       2 停止位置,停止位置就是數(shù)據(jù)流將要停止的位置,當一個graph到達一個停止位置時,將沒有數(shù)據(jù)流,filter graph管理器將會發(fā)送一個EC_COMPLETE事件。

       可以通過IMediaSeeking::GetPositions方法可以獲取這些位置值。返回值都是相對于原始的開始位置。

       通過IMediaSeeking::SetPositions方法可以seek一個新的位置,見下面:

      #define ONE_SECOND 10000000

       

       

       

       

      REFERENCE_TIME rtNow = 2 * ONE_SECOND,

       

       

       

       

                     rtStop = 5 * ONE_SECOND;

       

       

       

       

       

       

       

       

      hr = pSeek->SetPositions(

       

       

       

       

          &rtNow, AM_SEEKING_AbsolutePositioning,

       

       

       

       

          &rtStop, AM_SEEKING_AbsolutePositioning

       

       

       

       

          );

       

       

       

       

      注:1秒是10,000,000參考時間單位。為了方便,這個例子將這個值定義為ONE_SECOND,如果你使用的dshow的基類,常量CUITS的值和這個值相等。

       RtNow參數(shù)指定新的當前位置,第二個參數(shù)用來標示如何來定位rtNow參數(shù)。在這個例子中,AM_SEEKING_AbsolutePositioning 標志表示rtNow指定的位置是一個絕對的位置。RtStop參數(shù)指定了停止時間,最后一個參數(shù)也指定了絕對位置。

        如果想指定一個相對的位置,可以指定一個AM_SEEKING_RelativePositioning參數(shù),

      為了設置這個位置不能改變,可以指定一個AM_SEEKING_NoPositioning參數(shù)。此時,參考時間應該設置為NULL。下面的例子將位置向前seek 10秒,然后停止位置不變。

      REFERENCE_TIME rtNow = 10 * ONE_SECOND;
      

       

      hr = pSeek->SetPositions(

       

       

       

       

          &rtNow, AM_SEEKING_RelativePositioning,

       

       

       

       

          NULL, AM_SEEKING_NoPositioning

       

       

       

       

          );

       

       

       

       

       

       

       

       

      3Setting the Playback Rate

       

       

       

       

      調(diào)用IMediaSeeking::SetRate方法可以改變回放的速率。通過將新的速率設置成原來速率的倍數(shù)就可以設置新的速率,例如,pSeek->SetRate(2.0)
      

       

      將新的速率設置為原來速率的兩倍。比率大于1說明回放的速度比原來的大,如果介于01之間,就比正常的速度慢。

       如果我們不考慮回放速率,當前位置和停止位置相對于開始位置都是不變的。舉個例子,如果我們有一個可以播放20秒的文件,將當前時間設置為10秒就會將播放位置設置到中間,如果播放的速率提高要原來的2倍,如果停止時間是20秒,你將播放位置設置到原來的10秒處,結(jié)果現(xiàn)在只能播放5秒了,因為速度提高了兩倍。

       

       

       

       

      4Time Formats For Seek Commands

       

       

       

       

       IMediaSeeking接口中的許多函數(shù)的參數(shù)都要求指定一個位置值,比如當前位置,或者停止位置,缺省的情況下這些參數(shù)是以of 100 nanoseconds為時間單位的,稱為參考時間,任何支持seekfilter必須支持按參考時間來進行定位。一些filter也支持采取其他時間單位進行定位。例如,根據(jù)指定的楨的數(shù)量,或在數(shù)據(jù)流偏移的字節(jié)數(shù)進行定位。

        這種用來定位的時間單位稱為時間格式,采用一個GUID來標示。Directshow定義了一系列的時間格式,詳細地可以參考SDK。第三方也可以定義自己的時間格式。

        為了確定graph中的當前的filter是否支持特定的時間格式,可以調(diào)用

      IMediaSeeking::IsFormatSupported方法,如果filter支持該時間格式,該函數(shù)返回ok否則返回false或者一個錯誤碼。如果filter支持某種指定的時間格式,可以調(diào)用IMediaSeeking::SetTimeFormat方法切換到其他的時間格式。如果SetTimeFormat方法成功,下面的seek命令就要使用新的時間格式。

        下面的代碼檢查graph是否支持用楨的數(shù)量進行定位,如果支持,定位到第20楨。

      hr = pSeek->IsFormatSupported(&TIME_FORMAT_FRAME);

       

       

       

       

      if (hr == S_OK)

       

       

       

       

      {

       

       

       

       

          hr = pSeek->SetTimeFormat(&TIME_FORMAT_FRAME);

       

       

       

       

          if (SUCCEEDED(hr))

       

       

       

       

          {

       

       

       

       

              // Seek to frame number 20.

       

       

       

       

              LONGLONG rtNow = 20;

       

       

       

       

              hr = pSeek->SetPositions(

       

       

       

       

                  &rtNow, AM_SEEKING_AbsolutePositioning,

       

       

       

       

                  0, AM_SEEKING_NoPositioning);

       

       

       

       

          }

       

       

       

       

      }

       

       

       

       

       

       

       

       

      6 如何設置Graph時鐘(Setting Graph Clock

       

      當你構(gòu)建了一個graph后,graph管理器會自動地給你的graph選擇一個參考時鐘的。Graph中的所有filter都同步于時鐘。特別的,Renderer filter還要根據(jù)參考時鐘的時間來決定每一個samplePresentation 時間。

        通常的情況下,應用程序是沒有必要重新設置graph管理器選擇好的參考時鐘的。但是,如果你想修改參考時鐘,你可以通過graph管理器提供的IMediaFilter::SetSyncSource方法來重新設置參考時鐘。這個方法的參數(shù)是一個時鐘的IReferenceClock接口指針。可以在graph停止的時候調(diào)用這個函數(shù),下面的例子演示了如何指定一個時鐘

       

       

       

       

      IGraphBuilder *pGraph = 0;

       

       

       

       

      IReferenceClock *pClock = 0;

       

       

       

       

       

       

       

       

      CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,

       

       

       

       

          IID_IGraphBuilder, (void **)&pGraph);

       

       

       

       

       

       

       

       

      // Build the graph.

       

       

       

       

      pGraph->RenderFile(L"C:\\Example.avi", 0);

       

       

       

       

       

       

       

       

      // Create your clock.

       

       

       

       

      hr = CreateMyPrivateClock(&pClock);

       

       

       

       

      if (SUCCEEDED(hr))

       

       

       

       

      {

       

       

       

       

          // Set the graph clock.

       

       

       

       

          IMediaFilter *pMediaFilter = 0;

       

       

       

       

          pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);

       

       

       

       

          pMediaFilter->SetSyncSource(pClock);

       

       

       

       

          pClock->Release();

       

       

       

       

          pMediaFilter->Release();

       

       

       

       

      }

       

       

       

       

       這段代碼假定CreateMyPrivateClock 是應用程序定義的一個函數(shù),用來創(chuàng)建一個時鐘,然后返回一個IReferenceClock接口。

        你也可以在graph沒有設置時鐘的情況下運行graph。當SetSyncSource 函數(shù)的參數(shù)為NULL的時候就給graph設置了一個空的參考時鐘。如果graph沒有時鐘,graph將運行的快許多。因為renderer 不用再按照samplepresentation 時間了,只要sample到達了renderer filter,就可以立即被提交。所以,當你想處理數(shù)據(jù)盡可能快,而不是還要考慮預覽的實際時間,你就可以給graph設置一個空的時間。

      posted on 2006-08-22 12:54  文心  閱讀(1448)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 国产又色又爽无遮挡免费动态图 | 性XXXX视频播放免费直播| 成人网站免费观看永久视频下载| 日韩中文字幕av有码| 97欧美精品系列一区二区| 午夜不卡欧美AAAAAA在线观看| 久久香蕉国产线看观看猫咪av | 国产精品中文字幕av| 久久青草国产精品一区| 亚洲国产精品一区二区久| 99精品视频在线观看免费蜜桃| 亚洲av一本二本三本| 欧美一区二区三区欧美日韩亚洲 | 久久亚洲中文无码咪咪爱| 国产精品久久久久9999高清| 欧美激情一区二区| 免费观看日本污污ww网站| 日韩美少妇大胆一区二区| 一区二区三区不卡国产| 丁香五月亚洲综合在线国内自拍| 亚洲国产日韩a在线播放| 一区二区三区在线色视频| 国产午夜精品一区理论片| 日韩大片看一区二区三区| 国产伦一区二区三区久久| 亚洲真人无码永久在线| 国内精品久久久久影院日本| 乱人伦无码中文视频在线| 国产大尺度一区二区视频| 精品国产亚洲一区二区三区在线观看| 欧洲亚洲色一区二区色99| 无码专区—va亚洲v天堂麻豆| 日本韩国日韩少妇熟女少妇| 狠狠做五月深爱婷婷天天综合| 精品超清无码视频在线观看| 中文字幕精品人妻丝袜| 中文字幕国产精品资源| 在线日韩日本国产亚洲| 欧美乱妇狂野欧美在线视频| 精品无码人妻一区二区三区| 国产日产亚洲系列最新|