Microsoft DirectX 8.0

タイムラインの構築

ここでは、Microsoft® DirectShow® 編集サービス (DES) でタイムラインを構築する方法を説明している。タイムラインを作成してレンダリングするコンソール アプリケーションの例を紹介する。作成するタイムラインは、ソース クリップ 1 つだけの単一のビデオ グループからなる最小規模のものだが、より複雑なタイムラインの作成に必要な概念のほとんどが示されている。

ここには、以下のトピックが含まれる。

タイムライン オブジェクトの作成

ここで紹介するサンプル コードは空のタイムラインで始まるが、既存のプロジェクトをロードしてオブジェクトを追加する場合も、同じ手順が適用される。

タイムライン内に何らかの型のオブジェクトを作成するには、IAMTimeline::CreateEmptyNode メソッドを呼び出し、合成、グループ、またはトラックなど、作成するメジャー タイプを指定する。たとえば、次のコードは新しいグループを作成する。

IAMTimelineObj *pGroupObj = NULL;
pTL->CreateEmptyNode(&pGroupObj, TIMELINE_MAJOR_TYPE_GROUP);

CreateEmptyNode メソッドは、オブジェクトを作成して、そのオブジェクトの IAMTimelineObj インターフェイスを指すポインタを返す。このメソッドは、IAMTimelineObj インターフェイスの参照カウントもインクリメントするので、使用を終えたときには、このインターフェイスも解放しなければならない。CoCreateInstance 関数を呼び出してはならない。そうではなく、必ず CreateEmptyNode を使ってタイムライン オブジェクトを作成する。これは、このメソッドが、タイムラインで使用できるように新しいオブジェクトを初期化するためである。

IAMTimelineObj インターフェイスは、汎用インターフェイスである。これは、タイムライン オブジェクトのすべてのタイプに共通のメソッドを提供する。オブジェクトの各タイプは、他のインターフェイスも公開する。たとえば、グループは IAMTimelineGroup インターフェイスを公開する。他のインターフェイスを指すポインタは、QueryInterface を呼び出して取得できる。

オブジェクトを作成した段階では、まだそれはタイムラインの一部にはなっていない。オブジェクトをタイムラインに追加するメソッドは、オブジェクトのタイプによって異なる。次のセクションでは、グループ、合成、およびトラックをタイムラインに追加する方法を説明する。

グループ、合成、およびトラックの作成

グループ、合成、およびトラックは、タイムラインとソース クリップとの間の中間レイヤである。これらは、その中に入るオブジェクトのタイプによって区別される。

以下のインターフェイスは、これらのオブジェクトによって公開される。

インターフェイスインターフェイスを公開するオブジェクト
IAMTimelineTrackトラック
IAMTimelineVirtualTrackトラック、合成
IAMTimelineComp合成、グループ
IAMTimelineGroupグループ

これらのインターフェイスには、オブジェクトをタイムラインに追加するメソッドが含まれている。

たとえば、次のコードは新しいトラックをグループに挿入する。前の表に示したように、グループは合成の一種と考えられ、トラックは仮想トラックの一種と考えられる。したがって、トラックをグループに挿入するには、グループにその IAMTimelineComp インターフェイスについて照会し、IAMTimelineComp::VTrackInsBefore メソッドを呼び出さなければならない。

IAMTimelineGroup    *pGroup;
// 新しいグループを作成する (ここには示されていない)。

IAMTimelineComp     *pComp = NULL;
IAMTimelineObj      *pTrackObj = NULL;

pTL->CreateEmptyNode(&pTrackObj, TIMELINE_MAJOR_TYPE_TRACK);
pGroup->QueryInterface(IID_IAMTimelineComp, (void **)&pComp);
pComp->VTrackInsBefore(pTrackObj, 0);

VTrackInsBefore の 2 番目のパラメータは、仮想トラックの優先順位を指定する。優先順位レベルはゼロから始まる。-1 を指定した場合、仮想トラックは優先順位リストの最後に挿入される。既に仮想トラックが存在するレベルの値を指定した場合、その位置以下のすべてのオブジェクトの優先順位レベルが 1 ずつ下げられる。仮想トラックの個数より大きい優先順位レベルの仮想トラックを挿入してはならない。それを行った場合の動作は未定義となる。

タイムラインからオブジェクトを完全に削除するには、そのオブジェクトの IAMTimelineObj::RemoveAll メソッドを呼び出す。このメソッドは、オブジェクトとその子をすべて削除する。オブジェクトをタイムラインの別の場所に再挿入する目的で削除するには、代わりに IAMTimelineObj::Remove を呼び出す。RemoveAll と異なり、このメソッドはオブジェクトの子は削除しない。タイムラインからすべてを削除するには、IAMTimeline::ClearAllGroups を呼び出す。

グループ メディア タイプの設定

すべてのグループは、非圧縮のメディア タイプとしてオーディオまたはビデオを定義しなければならない。非圧縮メディア タイプは、再生時にビューアが見る、または聴くフォーマットである。通常、最終出力は非圧縮フォーマットである。詳細については、「プロジェクトのレンダリング」を参照すること。

非圧縮フォーマットを設定するには、AM_MEDIA_TYPE 構造体を作成し、そのメンバとして適切なメジャー タイプ、サブタイプ、およびフォーマット ヘッダーを設定する。ビデオの場合は、フォーマット ヘッダーに幅、高さ、およびビット深度を設定する。オーディオの場合は、フォーマット ヘッダーにサンプリング レートを設定する。メジャー タイプのみを設定した場合、DES は他の値に適切なデフォルトを設定する。実際には、出力を明示的に制御する場合には値を設定する必要がある。CMediaType 基底クラスは、AM_MEDIA_TYPE 構造体を管理する便利な方法を提供する。そうしたければ、AM_MEDIA_TYPE 構造体を直接操作することもできる。

メディア タイプ構造体を初期化した後、IAMTimelineGroup::SetMediaType メソッドを呼び出してグループのメディア タイプを設定する。

次の例は、幅 320 ピクセル、高さ 240 ピクセルの 16 ビット RGB ビデオを指定している。

AM_MEDIA_TYPE mtGroup;  
mtGroup.majortype = MEDIATYPE_Video;
mtGroup.subtype = MEDIASUBTYPE_RGB555;

// フォーマット ヘッダーを設定する。
mtGroup.pbFormat = (BYTE*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)mtGroup.pbFormat;
ZeroMemory(pVideoHeader, sizeof(VIDEOINFOHEADER));
pVideoHeader->bmiHeader.biBitCount = 16;
pVideoHeader->bmiHeader.biWidth = 320;
pVideoHeader->bmiHeader.biHeight = 240;
pVideoHeader->bmiHeader.biPlanes = 1;
pVideoHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pVideoHeader->bmiHeader.biSizeImage = DIBSIZE(pVideoHeader->bmiHeader);

mtGroup.formattype = FORMAT_VideoInfo;
mtGroup.bFixedSizeSamples = TRUE;
mtGroup.lSampleSize = DIBSIZE(pVideoHeader->bmiHeader);

// グループのメディア タイプを設定する。
pGroup->SetMediaType( &mtGroup );

ソースの追加

ソース オブジェクトは、他のタイムライン オブジェクトと同じ方法で作成する。ただし、タイムラインに挿入する前に、少なくともソース上の以下のプロパティを指定しなければならない。

次の例では、ソース クリップはファイル内の 4 秒の位置から始まる。メディアの時間幅は 10 秒で、タイムラインの長さの 2 倍であり、これはソースが通常の 2 倍の速度で再生されることを意味する。定数 UNITS は、10000000 (107) として定義され、これは 1 秒に等しい。

pSourceObj->SetStartStop(0, 50000000)
pSource->SetMediaName(L"C:\\Example.avi");
pSource->SetMediaTimes(40000000, 140000000);

注 :  現在 DES は、ビデオ圧縮マネージャ (VCM) CODEC で圧縮されたソースは、同時に 75 個までしかレンダリングできない。また、そのようなソースがプロジェクト全体で 75 個を超える場合は、動的な再接続を使わなければ、DES はプロジェクトをプレビューできない。詳細については、「IRenderEngine::SetDynamicReconnectLevel」を参照すること。

ソースの詳細については、「ソースの操作」を参照すること。

サンプル コード

以下は、ここで説明したサンプル アプリケーション全体のコードである。

注 :  簡潔にするために、サンプル コードではエラー チェックを行っていない。実際のアプリケーションでは、メソッド呼び出しの戻り値をチェックして、失敗がないようにする必要がある。

#include <dshow.h>
#include <qedit.h>

// タイムラインをプレビューする。
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();
}

void main( void )
{
    // 最初に空のタイムラインを作成する。

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

    // グループ :  タイムラインにビデオ グループを追加する。
    IAMTimelineGroup    *pGroup = NULL;
    IAMTimelineObj      *pGroupObj = NULL;

    pTL->CreateEmptyNode(&pGroupObj, TIMELINE_MAJOR_TYPE_GROUP);
    pGroupObj->QueryInterface(IID_IAMTimelineGroup, (void **)&pGroup);

    // グループのメディア タイプを設定する。
    AM_MEDIA_TYPE mtGroup;  
    ZeroMemory(&mtGroup, sizeof(AM_MEDIA_TYPE));
    mtGroup.majortype = MEDIATYPE_Video;
    pGroup->SetMediaType(&mtGroup);
    pTL->AddGroup(pGroupObj);
    pGroupObj->Release();

    // トラック :  グループにトラックを追加する。
    IAMTimelineObj      *pTrackObj;
    IAMTimelineTrack    *pTrack;
    IAMTimelineComp     *pComp = NULL;

    pTL->CreateEmptyNode(&pTrackObj, TIMELINE_MAJOR_TYPE_TRACK);
    pGroup->QueryInterface(IID_IAMTimelineComp, (void **)&pComp);
    pComp->VTrackInsBefore(pTrackObj, 0);
    pTrackObj->QueryInterface(IID_IAMTimelineTrack, (void **)&pTrack);

    pTrackObj->Release();
    pComp->Release();    
    pGroup->Release();

    // ソース :  トラックにソースを追加する。
    IAMTimelineSrc      *pSource = NULL;
    IAMTimelineObj      *pSourceObj;
    pTL->CreateEmptyNode(&pSourceObj, TIMELINE_MAJOR_TYPE_SOURCE);
    pSourceObj->QueryInterface(IID_IAMTimelineSrc, (void **)&pSource);

    // タイムとファイル名を設定する。
    pSourceObj->SetStartStop(0, 50000000);
    pSource->SetMediaName(L"C:\\Example.avi");
    pSource->SetMediaTimes(40000000, 140000000);
    pTrack->SrcAdd(pSourceObj);

    pSourceObj->Release();
    pSource->Release();
    pTrack->Release();

    // タイムラインをプレビューする。
    IRenderEngine       *pRenderEngine = NULL;
    CoCreateInstance(CLSID_RenderEngine, NULL, CLSCTX_INPROC_SERVER,
            IID_IRenderEngine, (void**) &pRenderEngine);
    PreviewTL(pTL, pRenderEngine);

    // クリーン アップする。
    pRenderEngine->ScrapIt();
    pTL->ClearAllGroups();
    pRenderEngine->Release();
    pTL->Release();
    CoUninitialize();
}