;============================================================ ; iron_video.hsp — Media Foundation (MFPlay) 動画/音声再生ラッパ ; ; Windows 7 以降の Media Foundation MFPlay (IMFPMediaPlayer) を ; HSP の #comfunc で直接叩く動画・音声再生モジュール。 ; ; MCI と違って Windows 標準コーデックを Media Foundation 経由で ; 叩くため、MP4/MKV/H.264/AAC/MP3 等の現代フォーマットが ; 標準で再生可能。 ; ; API: ; iron_video_open path, hwnd ; ファイルを開いて hwnd に貼り付け ; ; (hwnd=0 で音声のみ) ; iron_video_play ; 再生開始 ; iron_video_pause ; 一時停止 ; iron_video_stop ; 停止 (頭に巻き戻る) ; iron_video_step ; 1 フレーム進める ; iron_video_set_rate rate ; 再生速度 (1.0=等速 / 2.0=2倍速) ; iron_video_set_volume vol ; 音量 (0.0〜1.0) ; iron_video_close ; 解放 ; ; 例: ; #include "iron_video.hsp" ; iron_video_open "movie.mp4", hwnd ; iron_video_play ; stop ; ボタン待ち等 ; ; 注意: ; - MFPlay は Win8 以降 deprecated 扱いだが現役で動作する ; - Position / Duration は PROPVARIANT 経由のため本ラッパでは未実装 ; (将来 iron_video_position / iron_video_length を追加予定) ; - hwnd を渡せば自動でアスペクト比保持して描画される ;============================================================ #ifndef __iron_video_hsp__ #define __iron_video_hsp__ #module iron_video ;------------------------------------------------------------ ; IMFPMediaPlayer インターフェース宣言 ; ; 空 CLSID "{}" を指定することで newcom が CoCreateInstance を ; 呼ばずに変数だけ確保 → MFPCreateMediaPlayer の var 引数で ; 受け取った生ポインタを COM ラップする HSP の慣用テク。 ;------------------------------------------------------------ #define IID_IMFPMediaPlayer "{A714590A-58AF-430a-85BF-44F5EC838D85}" #usecom IMFPMediaPlayer IID_IMFPMediaPlayer "{}" #comfunc IMFPMediaPlayer_Play 3 #comfunc IMFPMediaPlayer_Pause 4 #comfunc IMFPMediaPlayer_Stop 5 #comfunc IMFPMediaPlayer_FrameStep 6 #comfunc IMFPMediaPlayer_SetPosition 7 var, var #comfunc IMFPMediaPlayer_GetPosition 8 var, var #comfunc IMFPMediaPlayer_GetDuration 9 var, var #comfunc IMFPMediaPlayer_SetRate 10 float #comfunc IMFPMediaPlayer_GetState 13 var #comfunc IMFPMediaPlayer_SetVolume 20 float #comfunc IMFPMediaPlayer_UpdateVideo 32 #comfunc IMFPMediaPlayer_Shutdown 38 ;------------------------------------------------------------ ; mfplay.dll / mfplat.dll エクスポート ;------------------------------------------------------------ #uselib "Mfplay.dll" #func MFPCreateMediaPlayer "MFPCreateMediaPlayer" wstr, int, int, int, int, var #uselib "Mfplat.dll" #func MFStartup "MFStartup" int, int #func MFShutdown "MFShutdown" #define global MFSTARTUP_FULL 0 ;------------------------------------------------------------ ; 遅延初期化 (newcom + posguid 構築) ;------------------------------------------------------------ #deffunc _iv_init_once if _iv_inited : return _iv_inited = 1 newcom _iv_player, IMFPMediaPlayer _iv_loaded = 0 ; MFP_POSITIONTYPE_100NS GUID {c8e00d8d-1eae-4de7-99f4-5c2f8db5729a} sdim _iv_posguid, 16 lpoke _iv_posguid, 0, 0xc8e00d8d wpoke _iv_posguid, 4, 0x1eae wpoke _iv_posguid, 6, 0x4de7 poke _iv_posguid, 8, 0x99 poke _iv_posguid, 9, 0xf4 poke _iv_posguid, 10, 0x5c poke _iv_posguid, 11, 0x2f poke _iv_posguid, 12, 0x8d poke _iv_posguid, 13, 0xb5 poke _iv_posguid, 14, 0x72 poke _iv_posguid, 15, 0x9a return #deffunc iron_video_open str path, int hwnd _iv_init_once if _iv_loaded { IMFPMediaPlayer_Shutdown _iv_player delcom _iv_player MFShutdown newcom _iv_player, IMFPMediaPlayer _iv_loaded = 0 } MFStartup 0x00020070, MFSTARTUP_FULL MFPCreateMediaPlayer path, 1, 0, 0, hwnd, _iv_player _iv_loaded = 1 return #deffunc iron_video_play if _iv_loaded = 0 : return IMFPMediaPlayer_Play _iv_player return #deffunc iron_video_pause if _iv_loaded = 0 : return IMFPMediaPlayer_Pause _iv_player return #deffunc iron_video_stop if _iv_loaded = 0 : return IMFPMediaPlayer_Stop _iv_player return #deffunc iron_video_step if _iv_loaded = 0 : return IMFPMediaPlayer_FrameStep _iv_player return #deffunc iron_video_set_rate double rate if _iv_loaded = 0 : return IMFPMediaPlayer_SetRate _iv_player, rate return #deffunc iron_video_set_volume double vol if _iv_loaded = 0 : return IMFPMediaPlayer_SetVolume _iv_player, vol return #deffunc iron_video_update if _iv_loaded = 0 : return IMFPMediaPlayer_UpdateVideo _iv_player return #deffunc iron_video_close if _iv_loaded = 0 : return IMFPMediaPlayer_Shutdown _iv_player delcom _iv_player MFShutdown newcom _iv_player, IMFPMediaPlayer _iv_loaded = 0 return #defcfunc iron_video_state local _st if _iv_loaded = 0 : return -1 _st = -1 IMFPMediaPlayer_GetState _iv_player, _st return _st ;------------------------------------------------------------ ; Position / Duration 取得・設定 (PROPVARIANT 経由) ; ; PROPVARIANT layout (最小): ; offset 0: WORD vt (VT_I8 = 20 を使う) ; offset 2: WORD wReserved1 ; offset 4: WORD wReserved2 ; offset 6: WORD wReserved3 ; offset 8: LONGLONG hVal (100ns 単位の時刻) ; 24 byte 確保 (64bit ポインタ化された PROPVARIANT 互換サイズ) ;------------------------------------------------------------ ; 現在の再生位置を ms で取得 (defcfunc) #defcfunc iron_video_position_ms local _pv, local _lo, local _hi, local _hns if _iv_loaded = 0 : return 0 sdim _pv, 24 IMFPMediaPlayer_GetPosition _iv_player, _iv_posguid, _pv _lo = lpeek(_pv, 8) _hi = lpeek(_pv, 12) ; 100ns → ms: hns / 10000 ; 低 32bit を /10000 + 高 32bit 分を加算 (約 429497 ms/unit) return (_lo / 10000) + (_hi * 429497) ; 全長を ms で取得 (defcfunc) #defcfunc iron_video_duration_ms local _pv, local _lo, local _hi if _iv_loaded = 0 : return 0 sdim _pv, 24 IMFPMediaPlayer_GetDuration _iv_player, _iv_posguid, _pv _lo = lpeek(_pv, 8) _hi = lpeek(_pv, 12) return (_lo / 10000) + (_hi * 429497) ; 指定 ms 位置にシーク #deffunc iron_video_seek_ms int ms, local _pv, local _lo, local _hi, local _ms10k if _iv_loaded = 0 : return sdim _pv, 24 ; 0 クリア repeat 24 poke _pv, cnt, 0 loop ; vt = VT_I8 (20) wpoke _pv, 0, 20 ; hVal at offset 8: ms * 10000 (100ns 単位) ; ms が int32 なので hi は簡単計算 _ms10k = ms * 10000 _lo = _ms10k _hi = 0 if ms > 0 & (ms > 214748) { ; ms * 10000 が int32 範囲を超える ; hns = ms * 10000 を 64bit で計算 ; hi = (ms / 429497) (ざっくり近似) _hi = ms / 429497 _lo = (ms - _hi * 429497) * 10000 } lpoke _pv, 8, _lo lpoke _pv, 12, _hi IMFPMediaPlayer_SetPosition _iv_player, _iv_posguid, _pv return #global #endif