MediaFoundationを使う (2) MediaFoundation管理クラスの宣言

2020年のオリンピック開催が東京に決まったというニュースが景気よく流れています。

そうなると東京ビックサイトで開催場所がかぶるコミケはいったいどうなるのでしょうかね。

それはさておき。

前回は特徴と使用するライブラリなどについて書きました。

二回目は宣言部です。管理するクラスの宣言を見ていきたいと思います。

宣言部

#ifndef __mfsession_h__
#define __mfsession_h__
#define WM_MFSNOTIFY					(WM_USER + 0x1001)
#define MFS_VOLUMEMAX					1000
#define MFS_VOLUMEMIN					0
#define MFS_PANLEFT					-(MFS_VOLUMEMAX)
#define MFS_PANCENTER					MFS_VOLUMEMIN
#define MFS_PANRIGHT					MFS_VOLUMEMAX
typedef int int32_t;
typedef __int64 int64_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
//メディアセッション管理
class CMFSession : public CUnknownBase, public IMFAsyncCallback{
public:
	CMFSession(HWND hWnd); //コンストラクタ
	virtual ~CMFSession(); //デストラクタ
	//IUnknownの機能を実装する
	DECLARE_IUNKNOWN;
	STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); //インターフェイスの要求
	//IMFAsyncCallbackの実装
	STDMETHODIMP GetParameters(DWORD *pdwFlags,DWORD *pdwQueue); //内部パラメータを取得する
	STDMETHODIMP Invoke(IMFAsyncResult *pAsyncResult); //非同期処理が行われたときのコールバック
	virtual HRESULT LoadMovie(const TCHAR *lpFileName); //メディアを読み込む
	virtual BOOL ReleaseMovie(void); //解放処理
	virtual BOOL PlayMovie(BOOL bIsLoop = FALSE); //再生
	virtual BOOL StopMovie(void); //停止
	virtual BOOL IsPlayMovie(void) const; //再生中かどうか
	virtual BOOL PauseMovie(void); //一時停止
	virtual BOOL ForwardMovie(uint32_t nTime); //早送り(ms)
	virtual BOOL BackwardMovie(uint32_t nTime); //巻き戻し(ms)
	virtual BOOL SeekMovie(uint32_t nTime); //再生位置の移動(ms)
	virtual BOOL SeekMovieRel(int64_t llTime); //再生位置の相対移動(100ns)
	virtual BOOL SeekMovieAbs(uint64_t ullTime); //再生位置の絶対移動(100ns)
	virtual BOOL SetSpeed(double dSpeed); //スピードの変更
	virtual BOOL SetPan(int nAbsolutePan); //パンの変化を設定する
	virtual BOOL SetVolume(int nAbsoluteVolume); //音量の設定をする
	virtual uint32_t GetMovieTime(void) const; //メディアの再生時間を取得
	virtual uint64_t GetMediaTime(void) const; //メディア時間で再生時間を取得
	virtual BOOL GetMovieSize(int32_t *lpnWidth,int32_t *lpnHeight) const; //メディアの画像のサイズを取得
	virtual BOOL HasMediaVideo(void) const; //メディアが映像ラインを保持しているかどうか
	virtual BOOL HasMediaAudio(void) const; //メディアが音声ラインを保持しているかどうか
	virtual BOOL SetPlayWindow(const POINT *lpPlayPos = NULL,const SIZE *lpPlaySize = NULL); //再生ウィンドウの設定
	virtual BOOL Repaint(void); //再描画を行う
	virtual BOOL HandleEvent(LPARAM lParam); //イベント処理発行
protected:
	HRESULT SetByteStreamContentType(const TCHAR *lpFileName,const TCHAR *lpContentType); //ByteStreamにContentTypeを設定する
	HRESULT CreateSourceNode(IMFPresentationDescriptor *lpPresentDesc,IMFStreamDescriptor *lpStreamDesc,IMFTopologyNode **lplpNode); //ソース部のトポロジーノードを作成する
	HRESULT CreateOutputNode(IMFStreamDescriptor *lpStreamDesc,IMFTopologyNode **lplpNode); //出力部のトポロジーノードを作成する
	HRESULT InnerSeekTime(MFTIME nTime); //再生位置を設定する
	HRESULT InnerSetVolume(void); //ボリュームを設定する
	inline bool IsEnableVideo(void) const; //ビデオ有効テスト
	inline bool IsEnableAudio(void) const; //サウンド有効テスト
	inline bool InnerTestStatus(uint32_t nStatus) const; //内部的なステータステスト
	static inline uint64_t MilliSecondToMediaTime(uint32_t t); //ミリ秒をメディアタイムに変換する
	static inline uint32_t MediaTimeToMilliSecond(uint64_t t); //メディアタイムをミリ秒に変換する
	
private:
	HWND m_hWnd; //ウィンドウハンドル
	uint32_t m_nStatusCode; //ステータスコード
	MFTIME m_mtMediaLength; //メディア長(100ns)
	float m_fAudioVolume; //オーディオボリューム
	float m_fAudioBalance; //オーディオバランス
	IMFMediaSession *m_lpMediaSession; //メディアセッション
	IMFByteStream *m_lpByteStream; //バイトストリーム
	IMFMediaSource *m_lpMediaSource; //メディアソース
	IMFPresentationClock *m_lpPresentationClock; //プレゼンテーションクロック
	IMFVideoDisplayControl *m_lpVideoDisplay; //ビデオディスプレイ
	IMFAudioStreamVolume *m_lpAudioVolume; //オーディオボリューム
};
#endif //__mfsession_h__

管理クラスにはIMFAsyncCallbackの実装が必要なんですね

ちなみにIMFAsyncCallbackはMediaFoundation側から使用側にコールバックがあるときに渡されるインターフェイスで、この場合はイベント管理(再生終了など)の通知を受け取るために実装する必要があります。

で、面倒なのはこのIMFAsyncCallbackはIUnknownを継承しているため、IUnknownを実装しなければならない、というところです。

このために番外編でIUnknownの実装を行ったというわけです。

これがあるおかげで参照カウントの管理などが外に出ているため見通しが良くなります。

使用するインターフェイスは?

今回再生で使用するMediaFoundationのインターフェイスは以下の通りになります。

インターフェイス名 役割
IMFMediaSession メディア全体の状態を管理する。DirectShowのIGraphBuider(IFilterGraph)に近い役割
IMFByteStream MediaFoundation内でバイト単位のデータをやりとりするときに使うインターフェイス。今回はメディアの読み込みを管理
IMFMediaSource メディアのソース部(ByteStreamも含む)を管理する
IMFPresentationClock メディア再生時の基準時間の管理を行う。DirectShowのIReferenceClockの拡張に近い
IMFVideoDisplayControl ビデオ状態の管理を行う。DirectShowのIBasicVideoやIVideoWindowに近い役割
IMFAudioStreamVolume オーディオの音量管理を行う。DirectShowのIBasicAudioの拡張

そのほかにもこの宣言内でIMFPresentationDescriptorやらIMFStreamDescriptorやらIMFTopologyNodeやら出てきていますが、これらは使うときに説明します。

見てわかるとおり、MediaFoundationのインターフェイスは基本的にIMF~で始まります。だれも国際機関の名前ではありません。

使うインターフェイスがわからないと管理の仕方もわからないですよね。このあたりはDirectShowと同じです。

あと、時間管理はMFTIMEを使います。といってもDirectShowのREFERENCE_TIMEと同じ定義で意味も100nsを1とする単位系なので意味もほぼ同じです。

また、先頭にWM_MFSNOTIFYがあるようにウィンドウプロシージャにメッセージを飛ばしますのでそれを受ける部分も必要になることを覚えておいてください。

一応動画再生の基本要素を宣言している

動画再生に必要な機能は一通りあると思います。

ちなみにビデオが有効の時の出力先はコンストラクタで渡されるウィンドウハンドルのウィンドウです。

このあたりもDirectShowの基本形と同じです。

次回からいよいよ実装

まずはコンストラクタとデストラクタ、データの読み込みと解放ですか・・・。

One thought on “MediaFoundationを使う (2) MediaFoundation管理クラスの宣言

  1. ピンバック: MediaFoundationでの音量操作 - c# - 質問と回答

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

この記事のトラックバック用URL