1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

日本語プログラミング言語「なでしこ」Advent Calendar 2020

Day 11

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

Last updated at Posted at 2020-12-10

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

発端

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

スマホのカメラをパソコンのwebカメラとして使う術

 ググッと検索すれば色々ヒットすると思いますが、わたしはコレを使いました。

iVCam

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

なでしこv1でwebカメラを使う術

 基本的には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)  # カメラが1台ならNoは0でOK

●カメラ切断(ハンドルから)
  メッセージ送信(ハンドル,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(CW,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,CW,"UINT,UINT,BOOL,BOOL,BOOL,long,BOOL,BOOL,BOOL,DWORD,DWORD,DWORD,DWORD,HPALETTE,BOOL,DWORD,UINT,UINT")

■CW
 ・幅
 ・高さ
 ・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("",CWスタイル,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
!CWスタイルとは整数=WS_VISIBLE||WS_CHILD  #キャプチャーウィンドウのスタイル
#-----------------------------------------------------------
●枠固定中央表示(母艦ハンドルとCWハンドルを)
  母艦ハンドルを枠固定に窓ハンドルスタイル設定。
  母艦のクライアント幅はCWの幅。母艦のクライアント高さはCWの高さ。
  母艦ハンドルを(デスクトップW-母艦の幅)/2,(デスクトップH-母艦の高さ)/2,母艦の幅,母艦の高さに窓ハンドル位置サイズ設定。
  CWハンドルを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を指定して反映させる必要がある。
#-----------------------------------------------------------

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

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

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

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

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

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

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

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

*終了処理
  CWハンドルからカメラ切断。
  CWハンドルをウィンドウ破棄。
  終わる。
#-----------------------------------------------------------

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

ファイル置き場

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

https://github.com/snowdrops89/VFW_nako

※Githubのリポジトリを変更しました(2023/07/08)

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

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

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

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

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

おわります

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

参考

 英語ページ。よめない……(x_x)

https://msdn.microsoft.com/en-us/library/windows/desktop/dd757696(v=vs.85).aspx

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

1
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?