首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

DirectShow Editing Services (DES) 非線性編輯技術詳解

     編輯:關於VC++

摘要

本文詳細闡述基於 DirectShow 核心框架的非線性編輯服務(DES)原理,並提供範例程式碼演示如何拼接兩個音視頻檔案、實現視頻轉場效果與預覽。

技術背景:為何需要 DES?

DirectShow Filter 架構雖強大,但對非線性編輯支援先天不足。若需動態調整剪輯順序、加入背景音樂、套用轉場特效,直接操作 Filter Graph 會極其複雜。DES 作為 DirectShow Filter 的增強應用層,提供高階編輯介面:開發者僅需以 DES 介面描述編輯決策(時間線、軌道、來源、轉場),其餘 Graph 建構與控制全權交由 DES 處理。

DES 核心優勢

  • 基於 時間線 與 軌道 的直觀結構,多媒體組織編輯高效。
  • 支援即時預覽。
  • 專案可儲存為 XML 格式。
  • 內建視頻/音頻特效與轉場處理,支援 100+ 種 SMPTE 轉場、IE Transform/Transition 元件。
  • 支援色調、亮度、RGB、Alpha 合成。
  • 自動調整源檔幀率、採樣率,支援視頻縮放。

DES 物件模型:時間線樹狀結構

Timeline (根節點)
├── Group (輸出單一媒體流,典型為 Audio Group、Video Group)
│   ├── Composition (可包裝多 Track 為 Virtual Track)
│   │   └── Track (優先級遞增,高優先級輸出優先)
│   │       └── Source (葉節點,對應音視頻檔案片段)

關鍵規則:Group 中 Track 有優先級,運行時輸出高優先級 Track 的內容;無內容時回落至低優先級。Audio Group 所有 Track 內容混合輸出。Transition 置於高優先級 Track,預設從低優先級向高優先級過渡,方向可改變。

Transition 與 Effect 技術細節

DES 使用 DirectX Transform Object 實現 Transition(雙輸入單輸出)與 Effect(單輸入單輸出)。可惜 Microsoft 已停止支援此類元件開發,僅能使用 DES 內建效果與 IE 自帶元件。Composition 採用 Composite 設計模式,可將多 Track 封裝為 Virtual Track,支援更複雜的巢狀編輯。

範例程式碼:拼接兩個 WMV 檔案並加入 JPEG 轉場

編譯環境:Windows XP + VC6.0 SP5 + DX9 SDK。需連結 strmiids.lib。

void CDesTestDlg::OnStart() {
    CoInitialize(NULL);
    IAMTimeline *pTL = NULL;
    CoCreateInstance(CLSID_AMTimeline, NULL, CLSCTX_INPROC_SERVER, 
                     IID_IAMTimeline, (void**)&pTL);

    // 建立 Video Group
    IAMTimelineGroup *pGroup = NULL;
    IAMTimelineObj *pGroupObj = NULL;
    pTL->CreateEmptyNode(&pGroupObj, TIMELINE_MAJOR_TYPE_GROUP);
    pGroupObj->QueryInterface(IID_IAMTimelineGroup, (void**)&pGroup);
    AM_MEDIA_TYPE mtGroup = {0};
    mtGroup.majortype = MEDIATYPE_Video;
    pGroup->SetMediaType(&mtGroup);
    pTL->AddGroup(pGroupObj);
    pGroupObj->Release();

    // 加入兩個 Track
    IAMTimelineTrack *pTrack1, *pTrack2;
    IAMTimelineObj *pTrackObj1, *pTrackObj2;
    IAMTimelineComp *pComp1 = NULL;
    pTL->CreateEmptyNode(&pTrackObj1, TIMELINE_MAJOR_TYPE_TRACK);
    pGroup->QueryInterface(IID_IAMTimelineComp, (void**)&pComp1);
    pComp1->VTrackInsBefore(pTrackObj1, -1);
    pTrackObj1->QueryInterface(IID_IAMTimelineTrack, (void**)&pTrack1);
    pTL->CreateEmptyNode(&pTrackObj2, TIMELINE_MAJOR_TYPE_TRACK);
    pGroup->QueryInterface(IID_IAMTimelineComp, (void**)&pComp1);
    pComp1->VTrackInsBefore(pTrackObj2, -1);
    pTrackObj2->QueryInterface(IID_IAMTimelineTrack, (void**)&pTrack2);
    pTrackObj1->Release(); pTrackObj2->Release(); pComp1->Release(); pGroup->Release();

    // 加入兩個 Source
    IAMTimelineSrc *pSource1, *pSource2;
    IAMTimelineObj *pSourceObj1, *pSourceObj2;
    pTL->CreateEmptyNode(&pSourceObj1, TIMELINE_MAJOR_TYPE_SOURCE);
    pSourceObj1->QueryInterface(IID_IAMTimelineSrc, (void**)&pSource1);
    pTL->CreateEmptyNode(&pSourceObj2, TIMELINE_MAJOR_TYPE_SOURCE);
    pSourceObj2->QueryInterface(IID_IAMTimelineSrc, (void**)&pSource2);

    pSourceObj1->SetStartStop(0, 100000000);
    pSourceObj2->SetStartStop(50000000, 100000000);
    BSTR bstr1 = SysAllocString(OLESTR("news.WMV"));
    BSTR bstr2 = SysAllocString(OLESTR("vos.wmv"));
    pSource1->SetMediaName(bstr1);
    pSource2->SetMediaName(bstr2);
    SysFreeString(bstr1); SysFreeString(bstr2);
    pSource1->SetMediaTimes(0, 100000000);
    pSource2->SetMediaTimes(50000000, 100000000);
    pTrack1->SrcAdd(pSourceObj1);
    pTrack2->SrcAdd(pSourceObj2);
    // Release sources...

    // 建立 Transition (SMPTE Wipe - 六角星)
    IAMTimelineObj *pTransObj = NULL;
    pTL->CreateEmptyNode(&pTransObj, TIMELINE_MAJOR_TYPE_TRANSITION);
    pTransObj->SetSubObjectGUID(CLSID_DxtJpeg);
    pTransObj->SetStartStop(50000000, 100000000);
    IAMTimelineTransable *pTransable = NULL;
    pTrack2->QueryInterface(IID_IAMTimelineTransable, (void**)&pTransable);
    pTransable->TransAdd(pTransObj);

    // 設定 Transition 參數
    IPropertySetter *pProp = NULL;
    CoCreateInstance(CLSID_PropertySetter, NULL, CLSCTX_INPROC_SERVER,
                     IID_IPropertySetter, (void**)&pProp);
    DEXTER_PARAM param; param.Name = SysAllocString(L"MaskNum");
    param.dispID = 0; param.nValues = 1;
    DEXTER_VALUE *pVal = (DEXTER_VALUE*)CoTaskMemAlloc(sizeof(DEXTER_VALUE));
    pVal->v.vt = VT_BSTR; pVal->v.bstrVal = SysAllocString(L"129"); // 六角星
    pVal->rt = 0; pVal->dwInterp = DEXTERF_JUMP;
    pProp->AddProp(param, pVal);
    SysFreeString(param.Name); VariantClear(&pVal->v); CoTaskMemFree(pVal);
    pTransObj->SetPropertySetter(pProp);
    pProp->Release(); pTransable->Release(); pTransObj->Release();

    // 預覽
    IRenderEngine *pRender = NULL;
    CoCreateInstance(CLSID_RenderEngine, NULL, CLSCTX_INPROC_SERVER,
                     IID_IRenderEngine, (void**)&pRender);
    PreviewTL(pTL, pRender);
    pRender->ScrapIt(); pRender->Release(); pTL->Release();
    CoUninitialize();
}

void PreviewTL(IAMTimeline *pTL, IRenderEngine *pRender) {
    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEvent *pEvent = NULL;
    pRender->SetTimelineObject(pTL);
    pRender->ConnectFrontEnd();
    pRender->RenderOutputPins();
    pRender->GetFilterGraph(&pGraph);
    pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
    pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent);
    pControl->Run();
    long evCode; pEvent->WaitForCompletion(INFINITE, &evCode);
    pControl->Stop();
    pEvent->Release(); pControl->Release(); pGraph->Release();
}

總結

DES 以時間線模型極大簡化了非線性編輯開發,讓開發者專注於編輯邏輯而非 Filter Graph 細節。本文範例展示了核心 API 使用流程,可作為進一步開發視頻編輯應用的基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved