なでしこｖ１でパソコンのカメラを使うやつ

　書ける事が無くてピンチなので、失われた過去ブログからの蔵出し。
　なでしこ１でVFW(Video for Windows)をどうこうして、ｗｅｂカメラを使うヤツです。

# 発端
　数年前になでしこでこんなこと出来ないかと言われて、たまたま参考になるところがあって（今は無い）その通りにやってみたら出来ちゃって、私自身が面白くなったのでしばらくそれで遊んでいたんですけれどね。
　その後、パソコンが~~壊れて~~壊して（自業自得の水損；）、しょーがないから安いノーパソ買ったらカメラ付いて無くて（哀）
　そのまま中途で放置となっていたんだけど、このコロナ禍で、在宅ワーク用のｗｅｂカメラが足りない！→スマホで出来るアプリあるよ☆　というような記事が沢山出ました。
　ま、マジか！　そんなコトが出来たのか！！　というわけで、久々にちょっとやってみたんです。
　別に大したことはしていないんだけど、一応ちゃんとして動作確認したものをここに書き残しておくことにする。

# スマホのカメラをパソコンのｗｅｂカメラとして使う術
　ググッと検索すれば色々ヒットすると思いますが、わたしはコレを使いました。

> [iVCam](https://www.e2esoft.com/ivcam/)

　英語だけど負けません！＞＜
　読みもせずに「Download for Windows」のボタンをクリックして、ポチポチとインストール。完了して起動すると、スマホ側のアプリダウンロード用のQRコードが表示されるという親切設計。
　一旦認識されたら、他のソフトからもスマホがｗｅｂカメラとして使えるということでやってみたら動きました。やったね！

# なでしこｖ１でｗｅｂカメラを使う術
　基本的にはWindowsAPIでキャプチャーウィンドウを作成して、そのハンドルにVFWのメッセージを送ってやる感じです。

## なでしこで Video for Windows を使うやつ

　取りあえずコレをlibに放り込む（またはプログラムと同じトコに置く）

```VFW.nako
#---VFW定数-----
!WM_CAP_DRIVER_CONNECTとは整数＝$400+10           # キャプチャウィンドウをキャプチャドライバに接続します。
!WM_CAP_DRIVER_DISCONNECTとは整数＝$400+11        # キャプチャウィンドウからキャプチャドライバを切断します。
!WM_CAP_FILE_SET_CAPTURE_FILEとは整数＝$400+20    # ビデオキャプチャに使用されるファイルの名前を指定します。
!WM_CAP_EDIT_COPYとは＝$400+30                    # 画面をクリップボードにコピー。
!WM_CAP_DLG_VIDEOFORMATとは整数＝$400+41          # ビデオ形式を選択できるダイアログボックスが表示されます。
!WM_CAP_DLG_VIDEOSOURCEとは整数＝$400+42          # ビデオソースを制御できるダイアログボックスが表示されます。
!WM_CAP_DLG_VIDEODISPLAYとは整数＝$400+43         # ビデオ出力を設定または調整できるダイアログボックスを表示します。
!WM_CAP_DLG_VIDEOCOMPRESSIONとは整数＝$400+46     # キャプチャ処理中に使用する圧縮器を選択できるダイアログボックスを表示します。
!WM_CAP_SET_PREVIEWとは整数＝$400+50              # プレビューモード（オン／オフ）
!WM_CAP_SET_PREVIEWRATEとは整数＝$400+52          # プレビューモードのフレーム表示レート（ミリ秒）
!WM_CAP_SET_SCALEとは整数＝$400+53                # 画像をキャプチャーウィンドウに合わせて拡縮（オン／オフ）
!WM_CAP_GET_STATUSとは整数＝$400+54               # キャプチャウィンドウのステータスを取得します。
!WM_CAP_SEQUENCEとは整数＝$400+62                 # ストリーミングビデオおよびオーディオキャプチャをファイルに開始します。
#-----------------------------------------------------------
●カメラ接続（ハンドルに{数値=0}Noの）
　　メッセージ送信(ハンドル,WM_CAP_DRIVER_CONNECT,No,0)　　# カメラが１台ならNoは０でＯＫ

●カメラ切断（ハンドルから）
　　メッセージ送信(ハンドル,WM_CAP_DRIVER_DISCONNECT,0,0)

●プレビューレート設定（ハンドルをmsに）
　　メッセージ送信(ハンドル,WM_CAP_SET_PREVIEWRATE,ms,0)　　# ms＝ミリ秒単位

●プレビューモード設定（ハンドルをfに）
　　メッセージ送信(ハンドル,WM_CAP_SET_PREVIEW,f,0)　　　　 # f＝オン／オフ

●キャプチャ開始（ハンドルを）
　　メッセージ送信(ハンドル,WM_CAP_SEQUENCE,0,0)

●キャプチャファイル設定（ハンドルをaviファイル名に）
　　メッセージ送信(ハンドル,WM_CAP_FILE_SET_CAPTURE_FILE,0,aviファイル名)

●スケーリングフラグ設定（ハンドルをfに）
　　メッセージ送信(ハンドル,WM_CAP_SET_SCALE,f,0)　　　　　 # f＝オン／オフ

●クリップボードコピー（ハンドルを）
　　メッセージ送信(ハンドル,WM_CAP_EDIT_COPY,0,0)
#-----------------------------------------------------------
●ビデオ形式ダイアログ（ハンドルの）
　　メッセージ送信(ハンドル,WM_CAP_DLG_VIDEOFORMAT,0,0)

●ビデオソースダイアログ（ハンドルの）
　　メッセージ送信(ハンドル,WM_CAP_DLG_VIDEOSOURCE,0,0)

●ビデオ出力設定ダイアログ（ハンドルの）
　　メッセージ送信(ハンドル,WM_CAP_DLG_VIDEODISPLAY,0,0)　　# 出ない

●圧縮器選択ダイアログ（ハンドルの）
　　メッセージ送信(ハンドル,WM_CAP_DLG_VIDEOCOMPRESSION,0,0)
#-----------------------------------------------------------
●ステータス取得（ハンドルの）
　　PACK(ＣＷ,S,"UINT,UINT,BOOL,BOOL,BOOL,long,BOOL,BOOL,BOOL,DWORD,DWORD,DWORD,DWORD,HPALETTE,BOOL,DWORD,UINT,UINT")
　　メッセージ送信(ハンドル,WM_CAP_GET_STATUS,76,POINTER(S))　　　 # Size＝バイト単位。S＝CAPSTATUS構造体へのポインタ。
　　UNPACK(S,ＣＷ,"UINT,UINT,BOOL,BOOL,BOOL,long,BOOL,BOOL,BOOL,DWORD,DWORD,DWORD,DWORD,HPALETTE,BOOL,DWORD,UINT,UINT")

■ＣＷ
　・幅
　・高さ
　・fLiveWindow
　・fOverlayWindow
　・fScale
　・ptScroll
　・fUsingDefaultPalette
　・fAudioHardware
　・fCapFileExists
　・dwCurrentVideoFrame
　・dwCurrentVideoFramesDropped
　・dwCurrentWaveSamples
　・dwCurrentTimeElapsedMS
　・hPalCurrent
　・fCapturingNow
　・dwReturn
　・wNumVideoAllocated
　・wNumAudioAllocated
#-----------------------------------------------------------
#-----API---------------------------------------------------
#https://msdn.microsoft.com/ja-jp/library/cc428606.aspx
●capCreateCaptureWindowA(lpszWindowName,dwStyle,x,y,nWidth,nHeight,hWnd,nID) =DLL("avicap32.dll",
"HWND capCreateCaptureWindowA(
LPCSTR lpszWindowName,  // ウィンドウ名
DWORD dwStyle,          // ウィンドウスタイル
int x,                  // X
int y,                  // Y
int nWidth,             // W
int nHeight,            // H
HWND hWnd,              // 親ウィンドウのハンドル
int nID                 // ウィンドウ識別子…ってなんすか；
)")
●キャプチャーウィンドウ作成（母艦ハンドルに）
　capCreateCaptureWindowA（"",ＣＷスタイル,0,0,0,0,母艦ハンドル,0）
#-----------------------------------------------------------
#https://msdn.microsoft.com/ja-jp/library/cc411022.aspx
●メッセージ送信(hWnd,Msg,wParam,lParam) =DLL("user32.dll",
"LRESULT SendMessageA(
HWND hWnd,      // 送信先ウィンドウのハンドル
UINT Msg,       // メッセージ
SHORT wParam,  // メッセージの最初のパラメータ
LPCSTR lParam   // メッセージの 2 番目のパラメータ
)")
#-----------------------------------------------------------
#https://msdn.microsoft.com/ja-jp/library/cc410763.aspx
●ウィンドウ破棄(hWndを) =DLL("user32.dll",
"BOOL DestroyWindow(
HWND hWnd   // 破棄するウィンドウのハンドル
)")
#-----------------------------------------------------------

#---ウィンドウスタイル定数-----
!WS_VISIBLEとは整数＝$10000000    # 初期状態（枠なし）で表示。
!WS_CHILDとは整数＝$40000000      # 子ウィンドウ。
!WS_CAPTIONとは整数＝$C00000      # タイトルバーを持つ。
!WS_SYSMENUとは整数＝$80000       # システムメニューボタン。
!枠なしとは整数＝WS_VISIBLE
!枠固定とは整数＝WS_VISIBLE||WS_CAPTION||WS_SYSMENU
!枠固定非表示とは整数＝WS_DISABLED||WS_CAPTION||WS_SYSMENU
!ＣＷスタイルとは整数＝WS_VISIBLE||WS_CHILD　　＃キャプチャーウィンドウのスタイル
#-----------------------------------------------------------
●枠固定中央表示（母艦ハンドルとＣＷハンドルを）
　　母艦ハンドルを枠固定に窓ハンドルスタイル設定。
　　母艦のクライアント幅はＣＷの幅。母艦のクライアント高さはＣＷの高さ。
　　母艦ハンドルを(デスクトップW-母艦の幅)/2,(デスクトップH-母艦の高さ)/2,母艦の幅,母艦の高さに窓ハンドル位置サイズ設定。
　　ＣＷハンドルを0,0,母艦のクライアント幅,母艦のクライアント高さに窓ハンドル位置サイズ設定。
　　母艦の可視はオン。　　#オンにしなくてもウィンドウは表示されるけど、タスクバーには表示されなくなる！

●枠無全画面表示（母艦ハンドルを）
　　母艦ハンドルを0,0,デスクトップW,デスクトップHで枠なしに窓ハンドルスタイル設定。
　　母艦の可視はオン。
#-----------------------------------------------------------
#-----API---------------------------------------------------
#https://msdn.microsoft.com/ja-jp/library/cc411206.aspx
●SetWindowPos(hWnd,hWndInsertAfter,X,Y,cx,cy,uFlags) =DLL("user32.dll",
"BOOL SetWindowPos(
HWND hWnd,             // ウィンドウのハンドル
HWND hWndInsertAfter,  // 配置順序のハンドル…？
int X,                 // 横方向の位置
int Y,                 // 縦方向の位置
int cx,                // 幅
int cy,                // 高さ
UINT uFlags            // ウィンドウ位置のオプション
)")

●窓ハンドル位置サイズ設定（ハンドルをX,Y,W,Hに）
　　SetWindowPos（ハンドル,0,X,Y,W,H,0）
#-----------------------------------------------------------
#https://msdn.microsoft.com/ja-jp/library/cc411203.aspx
●SetWindowLong(hWnd,nIndex,dwNewLong) =DLL("user32.dll",
"LONG SetWindowLongA(
  HWND hWnd,       // ウィンドウのハンドル
  int nIndex,      // 設定する値のオフセット
  LONG dwNewLong   // 新しい値
)")

!GWL_STYLEとは整数＝-16　　　　　# ウィンドウスタイル
!SWP_FRAMECHANGEDとは整数＝$20　 # SetWindowLong関数を使用後に新しいフレームスタイルの設定を適用
●窓ハンドルスタイル設定（ハンドルを{数値=0}X,{数値=0}Y,{数値=0}W,{数値=0}Hでスタイルに）
　　SetWindowLong（ハンドル,GWL_STYLE,スタイル）
　　SetWindowPos（ハンドル,0,X,Y,W,H,SWP_FRAMECHANGED）
　　#SetWindowLongでウィンドウスタイルを変更した後は、SetWindowPosでSWP_FRAMECHANGEDを指定して反映させる必要がある。
#-----------------------------------------------------------
```

## なでしこでｗｅｂカメラを起動して表示するだけのやつ

```VFW_サンプル１.nako
！『VFW.nako』を取り込む。
！母艦設計=「母艦の可視はオフ」

#-----宣言--------------------------------------------------
ＣＷハンドルとは整数＝-1　　＃キャプチャーウィンドウのハンドル。
カメラ接続状態とは整数＝オフ。
フレームレートとは整数＝60　　　　　 #ミリ秒単位

#-----------------------------------------------------------

#-----母艦設計----------------------------------------------
#---母艦-----
母艦について
　　タイトルは「ｗｅｂカメラ」
　　閉じた時は～終了処理。
母艦を黒色で画面クリア。
#-----------------------------------------------------------

#-----メイン------------------------------------------------
カメラ起動。
ウィンドウサイズ設定。

#-----------------------------------------------------------
＊カメラ起動
　　母艦のハンドルにキャプチャーウィンドウ作成。
　　ＣＷハンドルはそれ。１秒待つ。
　　５回
　　　　ＣＷハンドルに0のカメラ接続。
　　　　１秒待つ。
　　　　もし、それがはいならば、カメラ接続状態はオン。抜ける。
　　もし、カメラ接続状態がオフならば、
　　　　ＣＷハンドルをウィンドウ破棄。
　　　　「カメラに接続出来ませんでした」と言う。
　　　　終わる。
　　ＣＷハンドルをフレームレートにプレビューレート設定。
　　ＣＷハンドルをオンにプレビューモード設定。

＊ウィンドウサイズ設定
　　ＣＷハンドルのステータス取得。
　　母艦ハンドルとＣＷハンドルを枠固定中央表示。

＊終了処理
　　ＣＷハンドルからカメラ切断。
　　ＣＷハンドルをウィンドウ破棄。
　　終わる。
#-----------------------------------------------------------
```
　まずは、キャプチャーウィンドウを作成。枠なしで母艦の子ウィンドウにしています。
　関数が成功すると、作成されたキャプチャーウィンドウのハンドルが返るので、それにカメラ接続。
　カメラが準備できるまで少し待つ必要がある……ラシイので、リトライしながら最大５秒待ちます。
　キャプチャーウィンドウのステータスを取得すると、ＣＷの幅、ＣＷの高さ（ＣＷはキャプチャーウィンドウてことです；）が分かるんで、それに母艦のサイズを合わせます。
　……的な？
　あまり、説明にもなっていない；；；
　終了する時には、作ったキャプチャーウィンドウを破棄するのを忘れず。

## ファイル置き場
　上記２ファイルと、今出来る命令が大体お試しできるサンプル２があります。
　一応、静止画を保存したり、動画を保存したり、何かしらのダイアログ出したり出来ます。

> https://github.com/snowdrops89/VFW_nako
>
>※Githubのリポジトリを変更しました(2023/07/08)

　VFWのメッセージは他にも沢山あって、もっと色々なことが出来るっぽいのだけど、なにしろドキュメントが英語のページしかない（？）のでよく分からない～(´・д・｀)
　取りあえずは、こんなとこかなという感じ。

- CAPSTATUS構造体が……というより、こーぞーたい自体があんまり分からないので、ステータス取得は幅と高さを得るためだけにあります。それ以下の項目がちゃんと取れているかは不明；

- ダイアログは、環境（カメラ？）によって出るヤツ出ないヤツがあるようなことがどっかに書いてあったけど、うちではビデオ出力設定ダイアログは出ません。（ビデオ出力設定ダイアログのメッセージがタイポしてたので、でないのそのせいか？！　と思ったけど直しても出ませんでした；）

- ビデオ形式ダイアログの解像度以外は、基本出るだけです（何するもんだかよく分からないので）

- ビデオ形式ダイアログで設定出来る解像度は、どうやら640×480が最大となるようです。（前のパソコンの内蔵カメラは640×480だったので気にしてなかったけど、スマホは1280×720なんだけど出ない。VFWはHDには対応してないのであろうか……？）


# おわります
　アドベントカレンダーになんか書かなきゃなのと、当時結構頑張ってたので救済したいのと、一度掲示板の質問に出たことがあるのでもしかして需要ある……？　と思い、ここに書き残しておく～。
　今となってはむしろ、v3でこうゆうことやりたい気も。

# 参考
　~~英語ページ。よめない……（ｘ＿ｘ）~~
> https://msdn.microsoft.com/en-us/library/windows/desktop/dd757696(v=vs.85).aspx

　いつの間にか日本語化されてた！