Microsoft DirectX 8.0

エフェクトとトランジションの操作

ここでは、Microsoft® DirectShow® 編集サービス (DES) におけるエフェクトとトランジションの使い方を説明している。以下のセクションが含まれる。

エフェクトおよびトランジション オブジェクトの追加

エフェクト オブジェクトまたはトランジション オブジェクトを追加するには、以下の手順を実行する。

  1. エフェクト オブジェクトまたはトランジション オブジェクトを作成する。

    IAMTimeline::CreateEmptyNode メソッドを、メジャー タイプ TIMELINE_MAJOR_TYPE_EFFECT または TIMELINE_MAJOR_TYPE_TRANSITION によって呼び出す。エフェクトは IAMTimelineEffect インターフェイスを公開し、トランジションは IAMTimelineTrans インターフェイスを公開する。詳細については、「タイムライン オブジェクトの作成」を参照すること。

  2. サブオブジェクトを設定する。

    エフェクト オブジェクトとトランジション オブジェクトは、サブオブジェクトのためのラッパーである。データ変換を実装することにより、サブオブジェクトが実際の機能を果たす。エフェクト オブジェクトまたはトランジション オブジェクトは、サブオブジェクトを使ってオーディオまたはビデオ ストリームを変換する。任意の単一入力 Microsoft® DirectX® 変換オブジェクトをエフェクトとして使用でき、任意の双入力 DirectX 変換オブジェクトをトランジションとして使用できる。DirectShow オーディオ エフェクト フィルタは、オーディオ グループ内のエフェクトとして機能できる。DES は、ボリュームの設定を行う、ボリューム エンベロープと呼ばれる特殊なオーディオ エフェクトも提供している。タイムライン内の各オブジェクトが持つことができるボリューム エンベロープ エフェクトは、最大で 1 つである。他のエフェクトについては、このような制限はない。

    エフェクトまたはトランジション オブジェクトを作成したら、サブオブジェクトのクラス識別子 (CLSID) を使って IAMTimelineObj::SetSubObjectGUID を呼び出す。ユーザーのシステム上で使用可能なエフェクトとトランジションを列挙する方法については、「エフェクトおよびトランジションの列挙」を参照すること。

  3. 開始タイムと終了タイムを設定する。

    IAMTimelineObj::SetStartStop メソッドを呼び出して、親オブジェクト相対の開始タイムと終了タイムを設定する。

  4. プロパティを設定する。

    多数のエフェクトとトランジションが、カスタム プロパティをサポートしている。これらのプロパティの設定方法については、「エフェクトおよびトランジションのプロパティの設定」を参照すること。

  5. エフェクト オブジェクトまたはトランジション オブジェクトをタイムラインに挿入する。

    親オブジェクトの、次のいずれかのメソッドを呼び出す。

    親オブジェクトは、複数のエフェクトおよびトランジションを持つことができる。エフェクトは同じオブジェクトに重ねて使用できるが、トランジションはそのような使い方はできない。各オブジェクトごとに、そのエフェクトが、優先順位に従って、優先順位ゼロから順にレンダリングされる (優先順位レベルは、EffectInsBefore を呼び出すときに指定する)。

次のサンプル コードでは、SMPTE ワイプトランジションをトラックに追加している。ここでは、トラックはすでに作成されているものとする。

// IAMTimeline *pTL;
// IAMTimelineTrack *pTrack;

// トランジション オブジェクトを作成する。
IAMTimelineObj *pTransObj = NULL;
hr = pTL->CreateEmptyNode(&pTransObj, TIMELINE_MAJOR_TYPE_TRANSITION);

// サブオブジェクトを設定する。
hr = pTransObj->SetSubObjectGUID(CLSID_DxtJpeg);  // SMPTE ワイプ

// 開始タイムと終了タイムを設定する。
hr = pTransObj->SetStartStop(0000000, 100000000);

// トランジション オブジェクトをタイムラインに挿入する。
IAMTimelineTransable *pTransable = NULL;
hr = pTrack->QueryInterface(IID_IAMTimelineTransable, (void **)&pTransable);
hr = pTransable->TransAdd(pTransObj);  
hr = pTransObj->Release();

エフェクトおよびトランジションのプレビュー

一部のエフェクトおよびトランジションは、他と比べてレンダリングに時間がかかる。プレビュー中に、これが原因でビデオが乱れたり、オーディオとの同期がくずれることがある。エフェクトまたはトランジションを無効にすることにより、プレビューの速度を上げることができる。

エフェクトが無効になると、プレビュー時にエフェクトはレンダリングされない。トランジションが無効になると、トランジションは直接切り替えとしてレンダリングされる。それでもトラック間の切り替えは行われるが、ビジュアル エフェクトはレンダリングされない。

エフェクトまたはトランジションがレンダリングできない場合、レンダリング エンジンはデフォルトのエフェクトまたはトランジションに置き換える。デフォルト エフェクトの設定は IAMTimeline::SetDefaultEffect メソッドを呼び出して行い、デフォルトのトランジションの設定は IAMTimeline::SetDefaultTransition メソッドを呼び出して行う。デフォルトを指定していない場合、または指定した内容でエラーが発生した場合は、DES 自体のデフォルトが使用される。

注 :  フレーム バッファの容量を大きくすることによっても、プレビューの品質を高めることができる。詳細については、「IAMTimelineGroup::SetOutputBuffering」を参照すること。

エフェクトおよびトランジションの列挙

DirectShow は、デバイスを列挙するためのシステム デバイス列挙子を提供している。これを使って、ユーザーのシステムにインストールされているエフェクトまたはトランジションのためのモニカを取得できる。

システム デバイス列挙子は、ICreateDevEnum インターフェイスを公開する。これは、指定されたデバイス カテゴリのためのカテゴリ列挙子を返す。カテゴリ列挙子は、IEnumMoniker インターフェイスを公開し、カテゴリ内の各デバイスのモニカを返す。ICreateDevEnem の使い方の詳細については、「デバイスとフィルタの列挙」を参照すること。以下に、DirectShow 編集サービスでの使い方の要約を示す。

エフェクトまたはトランジションを列挙するには、以下の手順を実行する。

  1. システム デバイス列挙子のインスタンスを作成する。
  2. ICreateDevEnum::CreateClassEnumerator メソッドを呼び出して、カテゴリ列挙子を取得する。カテゴリは、クラス識別子 (CLSID) によって定義されている。エフェクトの場合は CLSID_VideoEffects1Category、トランジションの場合は CLSID_VideoEffects2Category を使用する。
  3. IEnumMoniker::Next を呼び出して、列挙内の各モニカを取得する。
  4. 各モニカごとに IMoniker::BindToStorage を呼び出して、関連付けられているプロパティ バッグを取得する。
  5. プロパティ バッグには、そのエフェクトまたはトランジションのフレンドリ名とグローバル ユニーク識別子 (GUID) が入っている。アプリケーションでは、フレンドリ名のリストを表示でき、対応する GUID を取得できる。

次のサンプル コードは、以上の手順を示している。

ICreateDevEnum *pCreateDevEnum;
IEnumMoniker *pEm;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
        IID_ICreateDevEnum, (void**)&pCreateDevEnum);

pCreateDevEnum->CreateClassEnumerator(
        CLSID_VideoEffects1Category,  // エフェクトのカテゴリ。
        &pEnumMoniker, 0);            // トランジションに CLSID_VideoEffects2Category を使用する。  

ULONG cFetched;
IMoniker *pMoniker;
while(S_OK == pEnumMoniker->Next(1, &pMoniker, &cFetched))
{
    HRESULT hr;
    IPropertyBag *pBag;
    hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
    if(SUCCEEDED(hr))
    {
        VARIANT var;
        var.vt = VT_BSTR;
        hr = pBag->Read(L"FriendlyName", &var, NULL);
        if (SUCCEEDED(hr))
        {
            if ( ... )  // var.bstrVal が目的の名前かどうかチェックする。
            {
                VARIANT var2;
                GUID guid;
                pBag->Read(L"guid", &var2, NULL);
                GuidFromString(var2.bstrVal, &guid);
                SysFreeString(var2.bstrVal);		        
                // これで GUID はエフェクトの CLSID となる。
                break;
            }
            SysFreeString(var.bstrVal);
        }
        pBag->Release();
    }
    pMoniker->Release();
}
pEnumMoniker->Release();
pCreateDevEnum->Release();

エフェクトおよびトランジションのプロパティの設定

多数のエフェクトとトランジションで、その外観を制御するプロパティがサポートされている。たとえば、ボリューム エンベロープ エフェクトには、ボリューム レベルを指定するプロパティがある。アプリケーションでは、IPropertySetter インターフェイスを使用して、時間の範囲を越えてプロパティの値を設定できる。

プロパティを設定するには、以下の手順を実行する。

  1. プロパティ セッター (CLSID_PropertySetter) のインスタンスを作成する。
  2. DEXTER_PARAM および DEXTER_VALUE 構造体に、プロパティ データを設定する。この 2 つの構造体については後で説明する。
  3. DEXTER_PARAM および DEXTER_VALUE 構造体を IPropertySetter::AddProp メソッドに渡す。
  4. 設定する各プロパティごとに、手順 2 と 3 を繰り返す。
  5. IPropertySetter インターフェイス ポインタを IAMTimelineObj::SetPropertySetter メソッドに渡す。

DEXTER_PARAM 構造体は、設定対象のプロパティを指定する。以下のメンバがある。

プロパティの DISPID がわかっている場合は、dispID メンバに設定する。通常、このメンバはゼロに設定し、Name メンバにプロパティの名前を設定する。

DEXTER_VALUE 構造体は、所定の時点でのプロパティの値を指定する。以下のメンバがある。

vt メンバを VT_BSTR に設定した場合、プロパティ セッターは必要な変換をすべて行う。浮動小数点値の場合には、小数点の前にゼロが含まれる。たとえば、.3 ではなく 0.3 となる。

プロパティの値は時間の経過に従って変化できるので、IPropertySetter::AddProp メソッドは単一の DEXTER_PARAM 構造体と、DEXTER_VALUE 構造体の配列へのポインタをパラメータにとる。この配列は、プロパティの時間に基づく値のセットを定義する。配列のメンバは、昇順の時系列に沿っていなければならず、DEXTER_PARAM 構造体の nValues メンバは配列の長さに等しくなければならない。

次のサンプル コードは、SMPTE ワイプトランジションのプロパティ データを作成する。ここではワイプ コードを 120 に設定し、これは長円ワイプを作成する。基準タイムは、トランジションの開始時を示すゼロに設定される。

IPropertySetter     *pProp;   // プロパティ セッター
IAMTimelineObj      *pTransObj;  // トランジション オブジェクト
// SMPTE ワイプトランジション オブジェクトを作成する  (ここには示されていない)

CoCreateInstance(CLSID_PropertySetter, 
    NULL, CLSCTX_INPROC_SERVER, 
    IID_IPropertySetter, (void**) &pProp);

DEXTER_PARAM param;
DEXTER_VALUE *pValue = (DEXTER_VALUE *)CoTaskMemAlloc(sizeof(DEXTER_VALUE));

// パラメータを初期化する。
param.Name = SysAllocString(L"MaskNum");
param.dispID = 0;
param.nValues = 1;

// 値を初期化する。
pValue->v.vt = VT_BSTR;
pValue->v.bstrVal = SysAllocString(L"120"); // 長円
pValue->rt = 0;
pValue->dwInterp = DEXTERF_JUMP;

pProp->AddProp(param, pValue);

// 割り当てられていたリソースを解放する。
SysFreeString(param.Name);
VariantClear(&(pValue->v));
CoTaskMemFree(pValue);

// トランジションのプロパティを設定する。
pTransObj->SetPropertySetter(pProp);
pProp->Release();

トランジションの方向

トランジションは入力 A から入力 B に向かって、タイム t0 から t1 までの間に行われる。したがって、トランジションの方向は、次の 2 つのいずれかを意味する。

前者は入力方向であり、後者は進行方向である。この両方の方向を制御できる。

次の図は、入力方向と進行方向の違いを示している。ここでは、標準の SMPTE ワイプトランジションの 4 つのバリエーションが示されている。

ワイプの方向

トランジションはトラック 1 にある。デフォルトでは、ワイプは左から右に、トラック 0 から 1 に向かって行われる。入力を切り替えると、ワイプはトラック 1 から 0 に向かって行われるが、進行方向は左から右のままである。進行方向を逆にすると、トランジションは右から左へ向かって行われる。一番左に示されているように、この両方を組み合わせることができる。

DES がトランジションをレンダリングする方法については、「タイムライン モデル」を参照すること。