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

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

IO-DATAのTS-WLCEの画像をrtsp経由でモニターする話を書いていましたけど、C++ Builder CEで作ったアプリからアクセスする件は初めてですかね。VLC Playerやらffplayからアクセスするのは書いていましたね。

さて、C++ Builder CEで使える“Indy”は偉大なライブラリであり、普通のプロトコルであればほぼ網羅しています。前に書いた“http”やら“https”やらを筆頭に大抵のものはサポートしているのですが、さすがに“rtsp”は現時点のIndyではサポートされていません。そういう時には、ライブラリを使えば良いのです。rtspについては何度か出てきているVLCの中核を構成してるVLCのライブラリLibVLCを使えば良いのです。形式としてはDynamic Link Library経由で使うことになります。頭文字を取って、DLLと呼ばれますし、拡張子もDLLです。在処は、64ビット版のVLC Playerがインストールされていれば、インストールされているディレクトリ内部のlibvlc.dllがそのものです。とりあえず、このファイルを見つけ出して、コピーを新しく作ったディレクトリに置きましょうかね。ありかが分からないって?64ビット版のVLC Playerをインストール済みであれば、普通は、

にあります。このファイルを置いたディレクトリで

何もないところで右クリックして出てくる上図のメニューで”Open Git Bash here”です。

これから普通のDLLで供給されているライブラリをC++ Builder CE で使える形に変換します。そのために使用するユーティリティーは、64ビット版ならばmkexpです。32ビット版の時は、implibを使います。とりあえずmkexpと入力してリターンを打ちましょうか。

$ mkexp
mkexp.exe: Copyright (c) 2013 Embarcadero Technologies, Inc.
All rights reserved.

usage: mkexp [-f] [-d] [-o] [-p] outputfile inputfile
     Creates an import archive from an input file.
     Valid input files are OMF object files that contain only
     EXPDEF COMENT records, PE files, and DEF files.

     -f: prefer to link by ordinal (dangerous)
     -d: assume input is a DEF file
     -o: assume input is an OMF object file
     -p: assume input is a PE file

     File type is by default based on extension:
     OMF: .obj
     DEF: .def
     PE:  .dll, .exe

C++ Builder CEがインストールされていて、Git for Windowsがインストールされていれば上記のようになるはずです。続いて、

$ mkexp libvlc.a libvlc.dll

できたlibvlc.aが64ビット版のライブラリファイルです。インポートライブラリなので、中身はエントリーだけですが、このファイルをプロジェクトに追加します。

他にコンパイルのためには、libvlcのヘッダーファイルが必要ですので、LibVLCのソースコードをなんとかして手に入れる必要があります。ヒントは、ファイル名が“vlc-3.0.2.tar.xz”なファイルをインターネットの大海から探します。まともに辿ってVideo LAN Playerのサイトからソースとして探すと、壊れたファイルに行き着きますので注意してください。googleで検索キーワードを

vlc-3.0.2.tar.xz download

で、検索したトップ。

Index of /pub/vlc/3.0.2/

から“vlc-3.0.2.tar.xz”をダウンロードします。解凍はtar.xzが扱えるもので。(Winrarなら可能です。)IDEを立ち上げて、新規VCLプログラムからの、デザインを下記のような感じに、

TPanelがミソです。あとボタンを2個貼り付けます。ここまで作ったら、プロジェクトオプションからインクルードディレクトリを指定します。

上図の”インクルードファイルの検索パス”の…をクリックして、

フォルダーアイコンをクリックして、先ほど解凍したソースを辿って、“include”ディレクトリを指定します。

上図でフォルダーの選択をクリックします。

上図で“追加”の後“OK”です。

ここで保存

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);
	void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private:	// ユーザー宣言
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Button1のNameをWatchにButton2のNameをStopに変更しているのに注意願います。

こうするとフックしたルーチンが分かりやすくなります。Nameとして許される”名前”には制限があるので、変更できる場合はプログラムの見通しがよくなります。

Unit1.cppは、

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

#include <vcl.h>
#pragma hdrstop

#include <vlc/vlc.h>

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

libvlc_media_player_t* media_player;
libvlc_instance_t* instance;

//VLC* vlc;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
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);
}
//---------------------------------------------------------------------------
void __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);
}
//---------------------------------------------------------------------------

ここまで入力したら、一旦プロジェクトをセーブしておきましょう。忘れずに先ほど述べたlibvlc.aプロジェクトに追加する作業をしておきましょうかね。忘れると、

[ilink64 エラー] Error: Unresolved external 'libvlc_new' referenced from C:\USERS\JAKEB\ONEDRIVE\DOCUMENTS\EMBARCADERO\STUDIO\PROJECTS\RTSP-SIMPLE-A\WIN64\DEBUG\UNIT1.O
[ilink64 エラー] Error: Unresolved external 'libvlc_media_new_location' referenced from C:\USERS\JAKEB\ONEDRIVE\DOCUMENTS\EMBARCADERO\STUDIO\PROJECTS\RTSP-SIMPLE-A\WIN64\DEBUG\UNIT1.O
[ilink64 エラー] Error: Unresolved external 'libvlc_media_player_new_from_media' referenced from C:\USERS\JAKEB\ONEDRIVE\DOCUMENTS\EMBARCADERO\STUDIO\PROJECTS\RTSP-SIMPLE-A\WIN64\DEBUG\UNIT1.O
[ilink64 エラー] Error: Unresolved external 'libvlc_media_release' referenced from C:\USERS\JAKEB\ONEDRIVE\DOCUMENTS\EMBARCADERO\STUDIO\PROJECTS\RTSP-SIMPLE-A\WIN64\DEBUG\UNIT1.O

等と盛大に文句言われますよ。で、具体的には、libvlc.aをプロジェクトディレクトリに置いて、IDEからProject1.exeを右クリックして出てくる下記で、

追加から、

ここで右下の種類を

デフォルトの*.cppから“静的ライブラリファイル(*.a)”に切り替えて、

libvlc.aを選択

“shift-F9”とかでエラーが出なければ、最後のステップです。あと少しです。VLC Playerのインストールディレクトリから、拡張子dllのファイル4個と”plugin”という名前のフォルダーはそのまま全部できてるはずの”Project1.exe”と同じ階層にコピーします。結果は、

このようになっているはずです。ここで“F9”

こんなダイアログが出てきたら、ほぼ成功です。同時に所望の画面が見えていることが多いですが、”許可”します。

watchで再生stopでstopです。プログラムの終了は右上の×をクリック。次は、libvlcをwrapしつつ、dllを文字通りロードして使う方法について述べます。

コメント

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