DirectShowのRenderFileを2回呼び出すときにウインドウを再利用したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
墨汁

DirectShowのRenderFileを2回呼び出すときにウインドウを再利用したい

#1

投稿記事 by 墨汁 » 10年前

いつもお世話になっております
現在DirectShowとvc++ expressでmpegの動画ファイルを再生するプログラムを作っています
参考にしたページはこちらですhttp://www.geekpage.jp/programming/dire ... letion.php

今やりたいことは、用意した動画ファイルを再生して、その再生が終わったらすぐに次の動画ファイルを再生するということです

コード:

#include <stdio.h>

#include <dshow.h>

#define	FILENAME L"c:\\test1.mpeg"

int main()
{
 IGraphBuilder *pGraphBuilder;
 IMediaControl *pMediaControl;
 IMediaEvent *pMediaEvent;
 long eventCode;

 CoInitialize(NULL);

 CoCreateInstance(CLSID_FilterGraph,
	NULL,
	CLSCTX_INPROC,
	IID_IGraphBuilder,
	(LPVOID *)&pGraphBuilder);

 pGraphBuilder->QueryInterface(IID_IMediaControl,
	(LPVOID *)&pMediaControl);

 pGraphBuilder->QueryInterface(IID_IMediaEvent,
	(LPVOID *)&pMediaEvent);

MOVIE_START:
 pMediaControl->RenderFile(FILENAME);

 pMediaControl->Run();

 // 一つ目の引数はタイムアウトです。
 // 例えば、-1の部分を2にすると2秒でタイムアウト。
 pMediaEvent->WaitForCompletion(-1, &eventCode);
 switch (eventCode) {
 case 0:
	printf("timeout\n");
	break;
 case EC_COMPLETE:
	printf("complete\n");
	break;
 case EC_ERRORABORT:
	printf("errorabort\n");
	break;
 case EC_USERABORT:
	printf("userabort\n");
	break;
 }
 goto MOVIE_START;

 pMediaControl->Release();
 pGraphBuilder->Release();
 CoUninitialize();

 return 0;
}
(このプログラムだと、先頭に戻って同じ動画ファイルを再生していますが、そこは気にしないでください)


このプログラムを実行したら思い通りに動画が再生され、再生が終わり次第先頭からまた再生が始まるのかとおもっていたのですが、実際は「動画の再生が終わったら、そのウインドウは動画の最後のコマを表示したままになり、RenderFileに到達したところでまた新しいウインドウが生成され、そのウインドウ上で動画が再生される」といったことになりました。


MSDNのIGraphBuilder::RenderFileのページhttp://www.google.co.jp/url?url=http:// ... e82FFX9zMQには

>RenderFile メソッドは、グラフからフィルタを削除しない点に注意すること。
>RenderFile を 2 回呼び出すと、2 回目の呼び出しでは単純に追加のフィルタがグラフに追加される。
>グラフを実行すると、両方のソースが同時に再生される。


と書かれていました。
多分これが意味するところは、RenderFileを実行した時に、RenderFileの中でフィルタというものを作っているから、同じウインドウで違う動画を再生したいならRenderFileを自分で作って、その中でフィルタを再利用すればいい、ということだと思います。
ただ、どうにも私の知識ではRenderFileを自分で書いてみるということは出来ませんでした。


RenderFileを自分で書く以外にも同じウインドウで違う動画を再生する方法がありましたら教えて下さい。
よろしくお願いします。

墨汁

Re: DirectShowのRenderFileを2回呼び出すときにウインドウを再利用したい

#2

投稿記事 by 墨汁 » 10年前

「追記」
プログラムを少し書き換えてみました

コード:

#include <stdio.h>
 
#include <dshow.h>
 
#define FILENAME L"c:\\test1.mpeg"
 
int main()
{
 IGraphBuilder *pGraphBuilder;
 IMediaControl *pMediaControl;
 IMediaEvent *pMediaEvent;
 long eventCode;
 
 CoInitialize(NULL);
 
 CoCreateInstance(CLSID_FilterGraph,
    NULL,
    CLSCTX_INPROC,
    IID_IGraphBuilder,
    (LPVOID *)&pGraphBuilder);
 
 pGraphBuilder->QueryInterface(IID_IMediaControl,
    (LPVOID *)&pMediaControl);
 
 pGraphBuilder->QueryInterface(IID_IMediaEvent,
    (LPVOID *)&pMediaEvent);
 
MOVIE_START:
 pMediaControl->RenderFile(FILENAME);
 
 pMediaControl->Run();
 
 while(1){
  LONG v = 0;
  pMediaEvent->WaitForCompletion(1000, &v);
  if(v == EC_COMPLETE){  
    pMediaControl->Stop();
    IEnumFilters *pEnum;
    HRESULT hr = pGraphBuilder->EnumFilters(&pEnum);
    if(FAILED(hr)) return false;
    IBaseFilter *bf;
    while(pEnum->Next(1, &bf, NULL) == S_OK){
      hr = pGraphBuilder->RemoveFilter(bf);
      if(FAILED(hr)) return false;
      hr = pEnum->Reset();
      if(FAILED(hr)) return false;
      hr = bf->Release();
      if(FAILED(hr)) return false;
    }
    pEnum->Release();
  }
  goto MOVIE_START;
 }
 
 pMediaControl->Release();
 pGraphBuilder->Release();
 CoUninitialize();
 
 return 0;
}
このように書くと、再生が終わったウインドウを消すことが出来ました。
ここで取得しているIBaseFilter型のbfを使えば何かできるのでは……?というところまで来ました
引き続きよろしくお願いします

ISLe()

Re: DirectShowのRenderFileを2回呼び出すときにウインドウを再利用したい

#3

投稿記事 by ISLe() » 10年前

参考にしたというページと同じサイトにある情報を元に、サンプルコードを書いてみました。

こちらもエラー処理は省かれてますし、再生済みのフィルタグラフの除去もしてません。
動作確認中にウィンドウを閉じてもプロセスが残ってしまうことがありました。
再生中にプログラム終了するときのための後始末もきちんとする必要があるようです。
► スポイラーを表示

墨汁

Re: DirectShowのRenderFileを2回呼び出すときにウインドウを再利用したい

#4

投稿記事 by 墨汁 » 10年前

>ISLe様
まさしくこれです!思っていた通りの挙動を示してくれました。
自前でウインドウを作ってそれを使えるとは盲点でした。言われてみればその手が一番正しい気がして……コロンブスの卵ですね。
フィルタグラフの除去は調べてみてわかったのでそれを使って、再生中にbreak;した場合の処理も自分なりに書いて使います。
私の求めていたものはぴったりこれでした。本当にありがとうございました。これで解決にさせていただきます。

閉鎖

“C言語何でも質問掲示板” へ戻る