連載2 画像転送システム その6
先ずはネットワーク処理からですが特別な処理は必要ないので省略して、コーデックの処理から始めます。
構造体やグローバル変数はサーバー側と同じモノを使い、最初にサーバー側で使ったコーデックの情報をネットワークから受信します。
受信は2回に分けて行い、一回目はコーデックのFourCCとサーバー側glpbiOutのバイト数を取得。次にバイト数分のバッファをglpbiInに確保してから二回目の通信でサーバー側のglpbiOutの内容をglpbiInへ受信します。
コレによりサーバー側のglpbiOutとクライアント側のglpbiInが同じ内容となりクライアントの入力フォーマットとします。
次に出力フォーマットglpbiOutです。基本的にはサーバー側のglpbiInと同じ設定になりますが完全に一致させる必要は無いのでネットワークは使わずに独自に設定しましょう。このとき画像サイズの設定だけ注意が必要です。画像サイズはコーデックにより変更される場合がありまして、例えばAMV3ビデオコーデックのハーフサイズオプションにより画像サイズが変更されます。こう言ったケースに対応するためにglpbiOutの画像サイズはキャプチャー時の画像サイズではなくglpbiInに設定されている画像サイズを使います。
入力/出力フォーマットが用意できたら、コーデックのデコンプレッサーのハンドルを取得します。このときコーデックのFourCCが必要になりますがこのFourCCはサーバー側から受信したFourCCを使います。
次にデコンプレッサーを初期化してデコンプレッサーの準備は完了です。
最後に圧縮されたデータを格納するためのバッファglpCompressBuffを確保して終わり。
#include <vfw.h> #include <aviriff.h> #pragma comment(lib,"vfw32") // コーデック情報の送信につけるヘッダー struct NETWORK_CODEC_HEADER { DWORD dwbiSize; // コーデック情報のバイト数 DWORD dwFcc; // コーデックのFourCC DWORD dwReserve[2]; // 未使用 }; // コーデック処理で使う変数 HIC ghIC = NULL; // コーデックのハンドル LPVOID glpCompressBuff = NULL; // 圧縮された画像を格納するバッファへのポインタ BITMAPINFO *glpbiIn = NULL; // 圧縮された画像フォーマット(実態はコーデックにより異なる) BITMAPINFO *glpbiOut = NULL; // 復元された画像フォーマット(ビットマップインフォで確定) // コーデック処理の初期化 BOOL CodecInit(SOCKET sock) { DWORD size; // コーデック情報のヘッダーを取得(コーデック情報のバイト数とFourCC) NETWORK_CODEC_HEADER network_codec_header; size = recv_all(sock, (char*)&network_codec_header, sizeof(network_codec_header), 0 ); if (size == SOCKET_ERROR) return FALSE; // コーデック情報(可変長)を格納する為のバッファを確保 glpbiIn = (BITMAPINFO*)malloc( network_codec_header.dwbiSize ); if (glpbiIn == NULL) return FALSE; // コーデック情報を取得(最終的な画像サイズや、どの様に圧縮したか等が記録されています) size = recv_all(sock, (char*)glpbiIn, network_codec_header.dwbiSize, 0 ); if (size == SOCKET_ERROR) return FALSE; // 復元に使うフォーマットを作成 glpbiOut = (BITMAPINFO*)malloc( sizeof(BITMAPINFO) ); if (glpbiOut == NULL) return FALSE; ZeroMemory(glpbiOut, sizeof(BITMAPINFO) ); glpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); glpbiOut->bmiHeader.biBitCount = 32; glpbiOut->bmiHeader.biPlanes = 1; glpbiOut->bmiHeader.biWidth = glpbiIn->bmiHeader.biWidth; glpbiOut->bmiHeader.biHeight = glpbiIn->bmiHeader.biHeight; glpbiOut->bmiHeader.biSizeImage = glpbiIn->bmiHeader.biWidth* glpbiIn->bmiHeader.biHeight*4; glpbiOut->bmiHeader.biCompression = BI_RGB; // コーデックのデコンプレッサーのハンドルを取得 ghIC = ICOpen( ICTYPE_VIDEO, network_codec_header.dwFcc, // glpbiIn->biCompressionを使ってはダメ。 // 必ず、圧縮の時に使ったFourCCを使いましょう。 ICMODE_DECOMPRESS // ICMODE_DECOMPRESSとなります。圧縮時とは異なるので注意。 ); if (ghIC == NULL) return FALSE; // デコンプレッサーの初期化 if (ICERR_OK != ICDecompressBegin( ghIC, glpbiIn, // 圧縮された画像データのフォーマット(サーバー側のICCompressGetFormatで取得したlpbiOutをそのまま使う) glpbiOut // 復元する画像データのフォーマット(クライアント側で用意する) )) return FALSE; // 圧縮された画像データを格納するバッファを確保する。 // 確保するバイト数はサーバー側の初期化処理でICCompressGetSize等を使って取得する // 未圧縮よりもサイズが大きくなるコーデックも有りです。必ずコーデックから // 最大データサイズを取得しましょう。 glpCompressBuff = malloc(glpbiIn->bmiHeader.biSizeImage ); if (glpCompressBuff == NULL) return FALSE; return TRUE; } |
サーバー側のコンプレッサーの準備に比べると、クライアント側のデコンプレッサーの準備はその殆どをサーバ側から受信して済ませるので楽ですね。
レアなケースですが画像サイズが変更される可能性があることだけ注意しておけば大丈夫だと思います。次回は実際にデコンプレッサーを使って圧縮された画像の復元処理を紹介します。
- 関連記事
trackback
コメントの投稿