2000/2/24 Ver 1.00 MpegTransfer(MPEG2プログラム・ストリーム転送ライブラリ)について カノープス株式会社 1 概要 (1) MpegTransferは、MPEG2プログラム・ストリームのネットワーク経由での転送機能を実現する、C++クラス・ライブラリである。 (2) MpegTransferは、C++ソース・ファイルで提供される。 (3) ネットワーク・プロトコルとしては、UDP/IPを用いる。 (4) ネットワーク・プロトコルへのアクセスは、Windows Socket 2経由で実行される。 (5) MVR-D2000の制御は、MVR-D2000 SDK(以下、SDKと略記)が提供するAPIを用いて実行される。 (5) プログラムは、Microsoft VC++ 6.0(with service pack 3)を用いて開発されている。 2 ファイル一覧 .\MpegTransfer.txt このファイル自身 .\MpegTransfer\ MpegTransfer C++クラスのソース・ファイル群 .\Encode_cEx\ MpegTransferを用いた送信サンプル・プログラムEncode_cEx.exeのソース・ファイル群 .\Decode_cEx\ MpegTransferを用いた受信サンプル・プログラムDecode_cEx.exeのソース・ファイル群 .\bin\ Debug\ デバッグ版Encode_cEx.exe、Decode_cEx.exe Release\ リリース版Encode_cEx.exe、Decode_cEx.exe 3 MpegTransfer C++クラス 3-1 クラス階層 CObject MFC 基底クラス | +--CMpegTransfer CMpegSender/CMpegTransferのための基底クラス | +--CMpegSender 送信クラス | +--CMpegReceiver 受信クラス 3-2 CMpegTransfer CMpegSender/CMpegReceiverの基底クラス。アプリが直接CMpegTransferのインスタンスを生成することはない。 以下に、公開(public)メンバを列挙する。 static const DWORD m_cbBuffDefault; 32KB。SDKメモリ転送バッファ・サイズ(ENC_BSS_PARAMETER.cbBuff/DEC_BSR_PARAMETER.cbBuff)であり、 同時に、(ネットワーク経由での)1回の送信/受信サイズのディフォルト値。 static const DWORD m_cBuffDefault; 16。SDKメモリ転送バッファ数(ENC_BSS_PARAMETER.cBuff/DEC_BSR_PARAMETER.cBuff)のディフォルト値。 CMpegTransfer(UINT nId = 1); 入力 nId SDKエンコーダ/デコーダ識別子 static BOOL StartUp(); Ws2_32.dllにWinSock2の使用を開始することを通知する。 アプリの起動直後に1回だけ呼び出さなければならない。 static BOOL CleanUp(); Ws2_32.dllにWinSock2の使用を終了することを通知する。 アプリの終了直前に1回だけ呼び出さなければならない。 static BOOL SetSockAddrIn(LPCTSTR pszAddress, WORD nPort, LPSOCKADDR_IN pAddr); インターネット・アドレス文字列とポート#からソケット・アドレス(SOCKADDR_IN)を生成する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 pszAddress インターネット・アドレス文字列 nPort ポート# 出力 pAddr static int SendOverlapped(SOCKET hSocket, int fSocketType, LPVOID pBuff, DWORD cbBuff, LPDWORD pcbSent, LPSOCKADDR_IN pAddr = NULL); 1回分の送信をWin32 overlapped IOで実行する。 返値 成功すると、0を返す。失敗すると、0以外の値を返す。 入力 hSocket Win32 ソケット・ハンドル fSocketType TCP(SOCK_STREAM)またはUDP(SOCK_DGRAM)を指定する。 pBuff 送信バッファ cbBuff 送信サイズ pAddr UDPの場合の、相手先のソケット・アドレスを指定する。TCPの場合は不要。 出力 pcbSent 実際に送信したバイト数 static int ReceiveOverlapped(SOCKET hSocket, int fSocketType, LPVOID pBuff, DWORD cbBuff, LPDWORD pcbReceived, LPSOCKADDR_IN pAddr = NULL); 1回分の受信をWin32 overlapped IOで実行する。 返値 成功すると、0を返す。失敗すると、0以外の値を返す。 入力 hSocket Win32 ソケット・ハンドル fSocketType TCP(SOCK_STREAM)またはUDP(SOCK_DGRAM)を指定する。 pBuff 受信バッファ cbBuff 受信サイズ pAddr UDPの場合の、相手先のソケット・アドレスを指定する。TCPの場合は不要。 出力 pcbReceived 実際に受信したバイト数 operator SOCKET(); 返値 Win32 ソケット・ハンドルを返す。 LPSOCKADDR_IN Addr(); 返値 ローカル・マシンのソケット・アドレスを返す。 LPSOCKADDR_IN AddrOpposite(); 返値 相手先のマシンののソケット・アドレスを返す。 virtual BOOL Connect(LPCTSTR pszAddress, WORD nPort, LPCTSTR pszAddressOpposite); ソケットを生成する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 pszAddress ローカル・マシンのインターネット・アドレス文字列 nPort ポート# pszAddressOpposite 相手先のマシンのインターネット・アドレス文字列 virtual BOOL Disconnect(); ソケットをクローズする。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 3-3 CMpegSender エンコード及びエンコード結果の送信を実行するクラス。 使用例としては、Encode_cExのソース・ファイル参照。 以下に、公開(public)メンバを列挙する。 CMpegSender(UINT nEncId); 入力 nEncId SDKエンコーダ識別子 static BOOL Init(UINT nEncId, CMpegSender* pSender = NULL, ENC_CB_STATUS pfnStatus = NULL, ENC_CB_ERROR pfnError = NULL, ENC_CB_VOBU_ENT pfnVobuEnt = NULL); エンコーダを初期化する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 nEncId SDKエンコーダ識別子 pSender CMpegSenderのインスタンス。CMpegSenderのインスタンスがまだ生成されていない場合は、NULLを指定する。 pfnStatus pfnError pfnVobuEnt SDK ENC_Set_Callback APIに渡す引数と同一。詳細は、SDKマニュアル参照。 備考 通常は、CMpegSenderのインスタンスがまだ生成されていない段階でエンコーダを初期化したい場合に使用する。 CMpegSenderのインスタンスにエンコーダを初期化したい場合は、下記の(staticでない)Initメンバを使用する。 static BOOL Exit(UINT nEncId); エンコーダの使用を終了する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 nEncId SDKエンコーダ識別子 備考 通常は、CMpegSenderのインスタンスの削除後にエンコーダの使用を終了したい場合に使用する。 CMpegSenderのインスタンスがまだ存在する間にエンコーダの使用を終了したい場合は、 下記の(staticでない)Exitメンバを使用する。 BOOL Init(ENC_CB_STATUS pfnStatus = NULL, ENC_CB_ERROR pfnError = NULL, ENC_CB_VOBU_ENT pfnVobuEnt = NULL); エンコーダを初期化する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 pfnStatus pfnError pfnVobuEnt SDK ENC_Set_Callback APIに渡す引数と同一。詳細は、SDKマニュアル参照。 備考 通常は、CMpegSenderのインスタンスにエンコーダを初期化したい場合に使用する。 CMpegSenderのインスタンスがまだ生成されていない段階でエンコーダを初期化したい場合は、 上記の(static)Initメンバを使用する。 BOOL Exit(); エンコーダの使用を終了する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 備考 通常は、CMpegSenderのインスタンスがまだ存在する間にエンコーダの使用を終了したい場合に使用する。 CMpegSenderのインスタンスの削除後にエンコーダの使用を終了したい場合は、上記の(static)Exitメンバを使用する。 BOOL SendStart(DWORD cbBssBuff = m_cbBuffDefault, DWORD cBssBuff = m_cBuffDefault); エンコード及びエンコード結果の送信を開始する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 cbBssBuff SDKメモリ転送バッファ・サイズ(ENC_BSS_PARAMETER.cbBuff)であり、 同時に、(ネットワーク経由での)1回の送信サイズ。ディフォルトは、32KB。 cBuff SDKメモリ転送バッファ数(ENC_BSS_PARAMETER.cBuff)。ディフォルトは、16。 BOOL SendStop(); エンコード及びエンコード結果の送信を終了する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 3-4 CMpegReceiver MPEG2プログラム・ストリームの受信、及び、受信結果のデコードを実行するクラス。 デコーダとしてMPL-D2000(改)が使用されている場合は、CMpegReceiver内部の受信バッファ及びSDK内部のデコーダ・バッファの 空き具合に応じてデコーダ・マスター・クロックを切り替える。 使用例としては、Decode_cExのソース・ファイル参照。 以下に、公開(public)メンバを列挙する。 CMpegReceiver(UINT nDecId); 入力 nDecId SDKデコーダ識別子 static BOOL Init(UINT nDecId, CMpegReceiver* pReceiver = NULL, DEC_CB_STATUS pfnStatus = NULL, DEC_CB_ERROR pfnError = NULL); デコーダを初期化する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 nDecId SDKデコーダ識別子 pSender CMpegReceiverのインスタンス。CMpegSenderのインスタンスがまだ生成されていない場合は、NULLを指定する。 pfnStatus pfnError SDK DEC_Set_Callback APIに渡す引数と同一。詳細は、SDKマニュアル参照。 備考 通常は、CMpegReceiverのインスタンスがまだ生成されていない段階でデコーダを初期化したい場合に使用する。 CMpegReceiverのインスタンスにデコーダを初期化したい場合は、下記の(staticでない)Initメンバを使用する。 static BOOL Exit(UINT nDecId); デコーダの使用を終了する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 nDecId SDKデコーダ識別子 備考 通常は、CMpegReceiveのインスタンスの削除後にデコーダの使用を終了したい場合に使用する。 CMpegReceiveのインスタンスがまだ存在する間にデコーダの使用を終了したい場合は、 下記の(staticでない)Exitメンバを使用する。 BOOL Init(DEC_CB_STATUS pfnStatus = NULL, DEC_CB_ERROR pfnError = NULL); デコーダを初期化する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 pfnStatus pfnError SDK DEC_Set_Callback APIに渡す引数と同一。詳細は、SDKマニュアル参照。 備考 通常は、CMpegReceiveのインスタンスにデコーダを初期化したい場合に使用する。 CMpegReceiverのインスタンスがまだ生成されていない段階でデコーダを初期化したい場合は、 上記の(static)Initメンバを使用する。 BOOL Exit(); デコーダの使用を終了する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 備考 通常は、CMpegReceiverのインスタンスがまだ存在する間にデコーダの使用を終了したい場合に使用する。 CMpegReceiverのインスタンスの削除後にデコーダの使用を終了したい場合は、上記の(static)Exitメンバを使用する。 BOOL ReceiveStart(DWORD cbBssBuff = m_cbBuffDefault, DWORD cBssBuff = m_cBuffDefault); MPEG2プログラム・ストリームの受信、及び、受信結果のデコードを開始する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 入力 cbBssBuff SDKメモリ転送バッファ・サイズ(ENC_BSR_PARAMETER.cbBuff)であり、 同時に、(ネットワーク経由での)1回の受信サイズ。ディフォルトは、32KB。 cBuff SDKメモリ転送バッファ数(ENC_BSR_PARAMETER.cBuff)。ディフォルトは、16。 BOOL ReceiveStop(); MPEG2プログラム・ストリームの受信、及び、受信結果のデコードを終了する。 返値 成功すると、0以外の値を返す。失敗すると、0を返す。 4 サンプル・プログラム(Encode_cEx.exe/Decode_cEx.exe)の使用方法 4-1 一回の実行毎に、下記を繰り返す。 (1) 接続オプションの設定 ローカル・アドレス、ポート#、相手先のアドレスを入力する。 (2) 接続 接続は、Encode_cEx.exe、Decode_cEx.exeのどちらで先に実行してもかまわないl。 (3) 送信/受信オプションの設定 バッファ・サイズは、Encode_cEx.exeとDecode_cEx.exeで同じ値を設定しなければならない。 (4) 送信/受信開始 Decode_cEx.exeで受信を開始した後、Encode_cEx.exeで送信を開始する。 Decode_cEx.exeは、受信を開始すると、受信待ちで待機する。 Encode_cEx.exe〜Decode_cEx.exe間でのハンド・シェーク(例えば、Deocode_cEx.exeから送信開始要求を送る等)は実装していない。 (5) 送信/受信終了 先にEncode_cEx.exeで送信終了を実行すると、Decode_cEx.exeの受信も自動的に終了する。 先にDecode_cEx.exeで受信を終了した場合は、Encode_cEx.exeは自動的には送信終了しないので、コマンド・メニューから 明示的に送信終了を実行しなければならない。 通常は、先にEncode_cEx.exeで送信終了を実行する。 Encode_cEx.exe〜Decode_cEx.exe間でのハンド・シェーク(例えば、Deocode_cEx.exeから送信終了要求を送る等)は実装していない。 (6) 切断 切断は、Encode_cEx.exe、Decode_cEx.exeのどちらで先に実行してもかまわない。 4-2 Encode_cEx.exe/Decode_cEx.exeは、プロセス(Encode_cEx.exe/Decode_cEx.exeの実行中のインスタンス)1個当たり、 1枚のMVR-D2000カードを使用する。 複数枚のMVR-D2000カードを装着したPC上で、同時に複数のEncode_cEx.exeを動作させたい場合は、 2個め以降のEncode_cEx.exeに対し、下記の様に、起動オプションとしてエンコーダID(SDKのエンコーダID)を指定する。 Encode_cEx.exe /id:n (n = 2, 3, ...) 例えば、2個めのEncode_cEx.exeに対しては、下記の様に指定する。 Encode_cEx.exe /id:2 /idオプションが省略された場合、Encode_cEx.exeはエンコーダID = 1で実行される。 同様に、同時に複数のDecode_cEx.exeを動作させたい場合は、 2個め以降のDecode_cEx.exeに対し、下記の様に、起動オプションとしてデコーダID(SDKのデコーダID)を指定する。 Decode_cEx.exe /id:n (n = 2, 3, ...) /idオプションが省略された場合、Decode_cEx.exeはデコーダID = 1で実行される。 5 実績 (1) 10Mbpsのイーサネット回線で接続したPC間で、Encode_cEx.exe及びDecode_cEx.exeを用いて、 ビデオ=6Mbpsまで、オーディオ=224kbpsのMPEG2プログラム・ストリームの転送動作を確認している。 但し、Windows 98ではWindows NTに比べて受信が遅いので、薦められない。 (2) エンコード〜デコード間の遅延時間 以下では、ビデオ=6Mbpsの場合を例として、ビデオのビット・レートから遅延時間を概算する。 実際のビット・レートでは、オーディオのビット・レート、及び、プログラム・ストリームとしての付加情報 (パック・ヘッダ、PESヘッダ等)によるビット・レートの増加分が含まれるが、これらの値はビデオのビット・レート と比較すると小さいので、概算では無視しても問題ない。 (a) MVR-D2000のエンコーダが実行を開始してからデータを出力し始めるまでの遅延時間は、ビット・レートに無関係に 一定であり、通常、約0.06〜0.1秒である。 (b) MVR-D2000のドライバ(MvrAvc.dll)は、内部のデコーダ・バッファが一杯になるまではデコードを開始しない。 このことによる遅延時間は、 32KB × 16 ÷ (6Mbps ÷ 8) = 0.70秒 となる。 (c) MPEGデータには、デコード開始時の初期遅延が設定されている。MP@MLの場合の初期遅延は、 1835008bits ÷ 6Mbps = 0.31秒 以上から、遅延時間の合計は、1.11秒(0.1 + 0.70 + 0.31)となる。 (a)〜(c)のうち、(b)は、バッファ・サイズの変更で小さくすることができる。バッファ・サイズを16KBにすると、 (b)は0.35秒になり、遅延時間の合計は、0.76秒に短縮される。 Encode_cEx.exe/Decode_cEx.exeを動作させて元の映像と再生映像との時間差を計った結果は、上記の時間に一致している。 即ち、現在の実装では無駄なオーバーヘッドはないと言える。 以上から、遅延時間を短くするにはバッファ・サイズを小さくすれば良いことになるが、逆に、小さくし過ぎると 転送が間に合わなくなる。 下表に、ビデオのビット・レートとバッファ・サイズの下限値(目安)を示す。 ビデオ(Mbps) バッファ・サイズ(KB) 遅延時間(秒) ---------------------------------------------------- 6 16 × 16 0.76 4 16 × 16 1.08 2 8 × 16 1.53 6 備考 (1) Window Socket 2の実装では、APIが失敗しても、WSAGetLastError APIがエラー・コードを返さない(代わりに、0を返す) 場合がよくある。 (2) 当初のMpegTransferではネットワーク・プロトコルとしてTCP/IPを用いた転送も実装していたが、実験の結果、TCP/IPでの 安定した転送はビデオ=2Mbpsまでであったため、TCP/IPを用いた実は装削除した。