libvlc_video_take_snapshot()を追加
libvlcwrapperでライブ動画を再生中にスナップショットをセーブする必要が生じました。CS-CP1等のAPIを叩いてスナップショットを撮ることを考えましたが、どうも実現できません。ということでUSB直結のwebcameraを使うことにしました。前の記事でも何回か取り上げましたが、WindowsシステムないしVLC界隈からはCapture Deviceで扱えます。VLCでいうところのMRLとしては、“dshow://”ですね。
フォームは、

今はこれだけ。TPanelx1,TButtonx1,TLabelx1ですね。Unit1.hは、
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TPanel *Panel1;
TButton *Still;
TLabel *Label1;
void __fastcall FormDestroy(TObject *Sender);
void __fastcall StillClick(TObject *Sender);
private: // ユーザー宣言
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endifUnit1.cppは、
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "vlcwrapper.h"
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
VLC* vlc;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
AnsiString mrl = "dshow://";
vlc = new VLC(mrl);
vlc->Option(":dshow-aspect-ratio=16\\:9");
vlc->SetHWND(Form1->Panel1->Handle);
vlc->Play();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
vlc->Stop();
delete vlc;
}
void __fastcall TForm1::StillClick(TObject *Sender)
{
AnsiString output_path = "webcam_snapshot.png";
int result = vlc->SnapShot(output_path.c_str());
if (result == 0) {
Label1->Caption = "File saved";
} else {
Label1->Caption = "save error";
}
}
//---------------------------------------------------------------------------
/*
vlc = new VLC("dshow://");
vlc->Option(":dshow-vdev=" + dlist[Form1->ComboBox1->ItemIndex].dname);
String resolution = dlist[Form1->ComboBox1->ItemIndex].resolutions[Form1->ComboBox2->ItemIndex];
TStringDynArray array = SplitString(resolution, "x");
vlc->Option(":dshow-size=" + dlist[Form1->ComboBox1->ItemIndex].resolutions[Form1->ComboBox2->ItemIndex]);
//vlc->Option(":dshow-aspect-ratio=4\\:3");
Edit1->Text = array[0];
Edit2->Text = array[1];
vlc->Option(":dshow-aspect-ratio="+Edit1->Text+"\\:"+Edit2->Text);
if( !Floating->Checked )
vlc->SetHWND(Panel1->Handle);
vlc->SetVolume(25);
vlc->Play();
*/
忘れずにプロジェクトにvlcwrapper.hを追加し、ターゲットプラットフォームは64bitで、

こんな感じです。vlcwrapper.hにはlibvlc_video_take_snapshot()を追加しています。追加部分だけ示してもいいのですが、3カ所追加するので間違いやすいということで、全部掲載しておきます。
#ifndef vlcwrapper
#define vlcwrapper
#ifndef _WIN64
#error compile 64bit mode
#endif
#include <vcl.h>
#include <vlc/vlc.h>
#include <windows.h>
#include <Registry.hpp>
class VLC {
private:
// typedef void WINAPI (*plibvlcmediaaddoption)(libvlc_instance_t*,const char*);
// LIBVLC_API void libvlc_media_player_pause (libvlc_media_player_t *p_mi)
typedef int WINAPI (*plibvlcvideotakesnapshot)(libvlc_media_player_t *,int,const char*,int,int);
typedef void WINAPI (*plibvlcmediaplayerpause)(libvlc_media_player_t *);
typedef int WINAPI (*plibvlc_audio_set_volume)(libvlc_media_player_t*,int);
typedef libvlc_instance_t* WINAPI (*plibvlcnew)(int , const char*);
typedef libvlc_media_t* WINAPI (*plibvlcmedianewlocation)(libvlc_instance_t* , const char*);
typedef libvlc_media_player_t* WINAPI (*plibvlcmediaplayernewfrommedia)(libvlc_media_t*);
typedef void WINAPI (*plibvlcmediarelease)(libvlc_media_t*);
typedef void WINAPI (*plibvlcvideosetscale)(libvlc_media_player_t*,float);
typedef void WINAPI (*plibvlcmediaplayerplay)(libvlc_media_player_t*);
typedef void WINAPI (*plibvlcmediaaddoption)(libvlc_media_t*,const char*);
typedef bool WINAPI (*plibvlcmediaplayerisplaying)(libvlc_media_player_t *);
typedef void WINAPI (*plibvlcmediaplayersethwnd)(libvlc_media_player_t *,HWND);
typedef void WINAPI (*plibvlcmediaplayerstop)(libvlc_media_player_t*);
typedef void WINAPI (*plibvlcmediaplayerrelease)(libvlc_media_player_t*);
typedef void WINAPI (*plibvlcrelease)(libvlc_instance_t*);
HMODULE avlccore;
HMODULE avlc;
//plibvlcmediaaddoption libvlc_media_add_option;
plibvlcvideotakesnapshot libvlc_video_take_snapshot;
plibvlcmediaplayerpause libvlc_media_player_pause;
plibvlc_audio_set_volume libvlc_audio_set_volume;
plibvlcnew libvlc_new;
plibvlcmedianewlocation libvlc_media_new_location;
plibvlcmediaplayernewfrommedia libvlc_media_player_new_from_media;
plibvlcmediarelease libvlc_media_release;
plibvlcmediaplayerplay libvlc_media_player_play;
plibvlcmediaplayersethwnd libvlc_media_player_set_hwnd;
plibvlcvideosetscale libvlc_video_set_scale;
plibvlcmediaaddoption libvlc_media_add_option;
plibvlcmediaplayerisplaying libvlc_media_player_is_playing;
plibvlcmediaplayerstop libvlc_media_player_stop;
plibvlcmediaplayerrelease libvlc_media_player_release;
plibvlcrelease libvlc_release;
libvlc_media_player_t* media_player;
libvlc_instance_t* instance;
libvlc_media_t* VlcMedia;
AnsiString GetVLCLibPath()
{
AnsiString S;
AnsiString KeyName = "Software\\VideoLAN\\VLC";
TRegistry *Registry = new TRegistry(KEY_READ);
try {
Registry->RootKey = HKEY_LOCAL_MACHINE;
Registry->OpenKey(KeyName, false);
S = Registry->ReadString("InstallDir");
}
__finally {
delete Registry;
}
return S;
}
void initaddress(){
AnsiString path;
char buf[100];
path = GetVLCLibPath();
//ShowMessage(path);
path += "\\";
AnsiString p1 = path + "libvlc.dll";
AnsiString p2 = path + "libvlccore.dll";
avlccore = LoadLibraryA(p2.c_str());
avlc = LoadLibraryA(p1.c_str());
if( !avlc )
ShowMessage("libvlc.dll loading error");
if( !avlccore )
ShowMessage("libvlccore.dll loading error");
FARPROC proc0 = GetProcAddress(avlc,"libvlc_media_player_pause");
if(proc0 == NULL ){
ShowMessage("getting libvlc_media_player_pause is failed");
}
libvlc_media_player_pause = reinterpret_cast <plibvlcmediaplayerpause>(proc0);
FARPROC proc2xy = GetProcAddress(avlc,"libvlc_audio_set_volume");
if(proc2xy == NULL ){
ShowMessage("getting libvlc_autio_set_volume is failed");
}
libvlc_audio_set_volume = reinterpret_cast <plibvlc_audio_set_volume>(proc2xy);
FARPROC proc = GetProcAddress(avlc,"libvlc_new");
if(proc == NULL ){
ShowMessage("getting libvlc_new is failed");
}
libvlc_new = reinterpret_cast <plibvlcnew>(proc);
FARPROC proc2 = GetProcAddress(avlc,"libvlc_media_new_location");
if(proc2 == NULL ){
ShowMessage("getting libvlc_media_new_location is failed");
}
libvlc_media_new_location = reinterpret_cast <plibvlcmedianewlocation>(proc2);
FARPROC proc3 = GetProcAddress(avlc,"libvlc_media_player_new_from_media");
if(proc3 == NULL ){
ShowMessage("getting libvlc_player_new_from_media is failed");
}
libvlc_media_player_new_from_media = reinterpret_cast <plibvlcmediaplayernewfrommedia>(proc3);
FARPROC proc4 = GetProcAddress(avlc,"libvlc_media_release");
if( proc4 == NULL ){
ShowMessage("getting libvlc_media_release is failed");
}
libvlc_media_release = reinterpret_cast <plibvlcmediarelease>(proc4);
FARPROC proc5 = GetProcAddress(avlc,"libvlc_video_set_scale");
if(proc5 == NULL ){
ShowMessage("getting libvlc_video_set_scale is failed");
}
libvlc_video_set_scale = reinterpret_cast <plibvlcvideosetscale>(proc5);
FARPROC proc6 = GetProcAddress(avlc,"libvlc_media_player_play");
if(proc6 == NULL ){
ShowMessage("getting libvlc_media_player_play is failed");
}
libvlc_media_player_play = reinterpret_cast <plibvlcmediaplayerplay>(proc6);
FARPROC proc7 = GetProcAddress(avlc,"libvlc_media_add_option");
if(proc7 == NULL ){
ShowMessage("getting libvlc_media_add_option is failed");
}
libvlc_media_add_option = reinterpret_cast <plibvlcmediaaddoption>(proc7);
FARPROC proc8 = GetProcAddress(avlc,"libvlc_media_add_option");
if(proc8 == NULL ){
ShowMessage("getting libvlc_media_player_is_playing is failed");
}
libvlc_media_player_is_playing = reinterpret_cast <plibvlcmediaplayerisplaying>(proc8);
FARPROC proc9 = GetProcAddress(avlc,"libvlc_media_player_set_hwnd");
if(proc9 == NULL ){
ShowMessage("getting libvlc_media_player_set_hwnd is failed");
}
libvlc_media_player_set_hwnd = reinterpret_cast <plibvlcmediaplayersethwnd>(proc9);
FARPROC proc10 = GetProcAddress(avlc,"libvlc_media_player_stop");
if(proc10 == NULL ){
ShowMessage("getting libvlc_media_player_stop is failed");
}
libvlc_media_player_stop = reinterpret_cast <plibvlcmediaplayerstop>(proc10);
FARPROC proc11 = GetProcAddress(avlc,"libvlc_media_player_release");
if(proc11 == NULL ){
ShowMessage("getting libvlc_media_player_release is failed");
}
libvlc_media_player_release = reinterpret_cast <plibvlcmediaplayerrelease>(proc11);
FARPROC proc12 = GetProcAddress(avlc,"libvlc_release");
if(proc12 == NULL ){
ShowMessage("getting libvlc_release is failed");
}
libvlc_release = reinterpret_cast <plibvlcrelease>(proc12);
FARPROC proc13 = GetProcAddress(avlc,"libvlc_video_take_snapshot");
if(proc13 == NULL ){
ShowMessage("getting libvlc_video_take_snapshot is failed");
}
libvlc_video_take_snapshot = reinterpret_cast <plibvlcvideotakesnapshot>(proc13);
}
public:
VLC(AnsiString location){
initaddress();
instance = libvlc_new(0, NULL);
VlcMedia = libvlc_media_new_location(instance,location.c_str());
media_player = libvlc_media_player_new_from_media(VlcMedia);
libvlc_media_release(VlcMedia);
}
void SetHWND(HWND Handle){
libvlc_media_player_set_hwnd(media_player,Handle);
}
void Option(AnsiString option){
libvlc_media_add_option(VlcMedia,option.c_str());
}
void Play(void){
libvlc_media_player_play(media_player);
}
void Pause(void){
libvlc_media_player_pause(media_player);
}
void Stop(void){
if(!media_player)
return;
libvlc_media_player_stop(media_player);
libvlc_media_player_release(media_player);
libvlc_release(instance);
}
void SetVolume(int vol){
libvlc_audio_set_volume(media_player,vol);
}
int SnapShot(AnsiString fname){
int ret;
ret = libvlc_video_take_snapshot(media_player,0,fname.c_str(),0,0);
return ret;
}
};
#endif引数並びを間違えずに宣言して、
typedef int WINAPI (*plibvlcvideotakesnapshot)(libvlc_media_player_t *,int,const char*,int,int);
plibvlcvideotakesnapshot libvlc_video_take_snapshot;
FARPROC proc13 = GetProcAddress(avlc,"libvlc_video_take_snapshot");
if(proc13 == NULL ){
ShowMessage("getting libvlc_video_take_snapshot is failed");
}
libvlc_video_take_snapshot = reinterpret_cast <plibvlcvideotakesnapshot>(proc13);
が追加分です。aspect ratioの設定も関数呼び出しでできますが、面倒なのでオプション文字列で設定しています。本当はUnit1.cppの末尾のコメント部分内部のように、デバイス名、スクリーン分解能(横x縦)、アスペクト比を設定すべきですが、面倒なのでデフォルトで…..。さて起動すると、

ここで“Still”ボタンをクリックすると、ファイルセーブされます。アスペクト比が間違っていると、左右に黒い部分がでてきます。

ファイルは、

live画像のスナップショットなので、寸分違いませんね。たまたま横に映り込んでいるのが、EZVIZ CS-CP1ですが、こちらで静止画撮る(といっても動画キャプチャー中のスクリーンダンプ経由)と、

この距離だとこの画像で、歪みが大きくて認識率低くなりそうなので使いません。現時点で、APIわからないしね。
ライブカメラからの静止画も撮れるようになりましたから、最終目標に向かってじわじわ進んでいます。


コメント