C++ Builder CE ネットワークプログラミング

5. rtspのサポート TS-WLCEやEZVIZ CP1の動画をモニターする 続編

前編C++ Builder CE ネットワークプログラミングと同様にLibVLCの力を借りるのであるけど、DLLを直接ロードして使います。ついでにVLCの簡単なwrapperを作って、使いやすくしていきます。要するにVLCを扱うクラスを作るのですが、結果を示します。ファイル名が、vlcwarpper.hで。ヘッダオンリーのクラスです。これは、

#ifndef vlcwrapper
#define vlcwrapper

#ifndef _WIN64
#error compile 64bit mode
#endif
#include <vcl.h>
#include <vlc/vlc.h>
#include <windows.h>
#include <Registry.hpp>


AnsiString GetVLCLibPath()
{
	AnsiString S;
	AnsiString KeyName = "Software\\VideoLAN\\VLC";

	TRegistry *Registry = new TRegistry(KEY_READ);
	try {
		Registry->RootKey = HKEY_LOCAL_MACHINE;
	 // 存在しない場合は作成しないので、False
		Registry->OpenKey(KeyName, false);
		S = Registry->ReadString("InstallDir");
	 }
	 __finally {
		delete Registry;
	 }
	 return S;

}


class VLC {
	private:

   //	typedef void WINAPI (*plibvlcmediaaddoption)(libvlc_instance_t*,const char*);

	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;
	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;


	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());
		//	avlccore = LoadLibraryA(p2.c_str());

		if( !avlc )
			ShowMessage("libvlc.dll loading error");

		if( !avlccore )
			ShowMessage("libvlccore.dll loading error");


		FARPROC proc = GetProcAddress(avlc,"libvlc_new");
		if(proc == NULL ){
			ShowMessage("getting libvlc_new is failed");
		}
	//plibvlcmediaplayerisplaying glibvlc_media_player_is_playing;

		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);


	}

	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 Stop(void){

		if(!media_player)
			return;

		libvlc_media_player_stop(media_player);

		libvlc_media_player_release(media_player);



		libvlc_release(instance);
	}

};

#endif

これを使いたいプログラムでインクルードします。具体的な使い方は、

void __fastcall TForm1::WatchClick(TObject *Sender)
{
	vlc = new VLC(playbackurl);
        vlc->SetHWND(Panel1->Handle);
	vlc->Play();

}

という風に使えますので、前の記事でのWatchClick()

void __fastcall TForm1::WatchClick(TObject *Sender)
{
	instance = libvlc_new(0, NULL);
	libvlc_media_t* VlcMedia;
	VlcMedia = libvlc_media_new_location(instance,playbackurl.c_str());
      media_player = libvlc_media_player_new_from_media(VlcMedia);
	libvlc_media_release(VlcMedia);
	libvlc_media_player_set_hwnd(media_player,Panel1->Handle);
	libvlc_media_player_play(media_player);
}

に比べると、だいぶすっきりしますよね。StopClick()はもっと短く、

void __fastcall TForm1::StopClick(TObject *Sender)
{
	vlc->Stop();
}

です。前の記事では、

oid __fastcall TForm1::StopClick(TObject *Sender)
{
	if(!media_player)
		return;
	libvlc_media_player_stop(media_player);
	while( libvlc_media_player_is_playing(media_player) )
		Sleep(100);
	libvlc_media_player_release(media_player);
	libvlc_release(instance);
}

でした。前の記事のように、フォームをデザインして、プロジェクトに忘れずにvlcwrapper.hを足して。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 で管理されるコンポーネント
	TButton *Watch;
	TPanel *Panel1;
	TButton *Stop;
	void __fastcall WatchClick(TObject *Sender);
	void __fastcall StopClick(TObject *Sender);
private:	// ユーザー宣言
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit1.cppは、

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "vlcwrapper.h"


#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
String playbackurl = "rtsp://192.168.0.112:38912/ipcam_h264.sdp";

VLC* vlc;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{

	if(GetVLCLibPath() == "" ){
		ShowMessage("このプログラムはVLCPlayer 64bit版がインストールされていることが動作のために必要です。インストール後に起動してください");
		Application->Terminate();

	}

}
//---------------------------------------------------------------------------
void __fastcall TForm1::WatchClick(TObject *Sender)
{
		vlc = new VLC(playbackurl);
        vlc->SetHWND(Panel1->Handle);
		vlc->Play();

}
//---------------------------------------------------------------------------
void __fastcall TForm1::StopClick(TObject *Sender)
{
	vlc->Stop();
}
//---------------------------------------------------------------------------

一応64bitでbuildすることが必要なので、そうでない場合はコンパイルできません。実行時にVLC Playerがインストールされているかどうかをレジストリを見て調べて、インストールされていない場合は、アラートを出して、実行を中止します。

さて、前回と今回はVCL(紛らわしいことこの上ない 笑)でのプログラミングでしたが、FMXの時はどうするんだい?上記にあるように、VCLでは動画再生画面をちょうどコンポーネント(TPanel)”はめ込む”ことができました。

この場合は、TPanelだったのですが、Handleが引けるものならば他のものでも表示可能です。上記は一応Panelのサイズと再生画面のサイズ(640×480)を合わせていますので、余計な枠が出なくて良い案配です。

FMXの場合は、フォームやらその上に載っているコンポーネントの有効なHandleが得られないので、

vlc->SetHWND(Panel1->Handle);

ができません。ではどうするか?無視しておけです。LibVLC側が適当にフォームとは別にウィンドウを形成してそこで動画を表示してくれます。フォームの一部にうまいことはめ込むことは筆者が調べた範囲では、簡単にはできないようです。何かうまい方法があれば教えてください。強行すると下図のようになります。

手前に見えている、動画再生フォームは元のフォームとは独立なので、タイトルバーを掴んで移動とかもできます。VCL版との差は、Watchで。

void __fastcall TForm1::WatchClick(TObject *Sender)
{
	vlc = new VLC(playbackurl);
        //vlc->SetHWND(Panel1->Handle);
	vlc->Play();

}

と、vlc->SetHWND()をコメントアウトしただけです。簡単なのはいいんだけど、画面デザインとかやりにくいかな。

コメント