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
で、検索したトップ。
から“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を文字通りロードして使う方法について述べます。
コメント
[…] 前編C++ Builder CE ネットワークプログラミングと同様にLibVLCの力を借りるのであるけど、DLLを直接ロードして使います。ついでにVLCの簡単なwrapperを作って、使いやすくしていきます。要するにVLCを扱うクラスを作るのですが、結果を示します。ファイル名が、vlcwarpper.hで。ヘッダオンリーのクラスです。これは、 […]