NHK FM Radioのライブストリームを聞くアプリ

libvlcwrapper.hを使えば3行で書けます

前記事の続き

の最後で、libvlcwrapper.h使えば数行で書けると言いましたが、実際は3行+1行でした。忘れないうちに掲載しておきます。まずフォームですが、何も無し。大きさも適当ですが、今後の拡張のために一応必要。

vlcwrapper.hを使うので、vclな64bitアプリにしておきましょう。vlcwrapper.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>


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

	
	}




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

	}


};

#endif

これをプロジェクトに追加しておきます。使う場合の前提条件等は、”らじる☆らじる聞き逃しサーチアプリ”と同様です。(64ビット版のVLC Playerのアプリがインストーラー経由でインストールされていることです。)Uni1.hは、

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

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	void __fastcall FormDestroy(TObject *Sender);
private:	// ユーザー宣言
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

なにもないですが、FormDestroy()のみ後始末でHookします。Unit1.cppは、

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

#include <vcl.h>
#pragma hdrstop
#include "vlcwrapper.h"
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
AnsiString playbackurl = "https://simul2.drdi.st.nhk/live/5/joined/audio/media.m3u8";

VLC* vlc;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	vlc = new VLC(playbackurl);
	vlc->SetHWND(Form1->Handle);
	vlc->Play();

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

これだけ。fmxの場合には、SetHWND(Form1->Handle)を削除しておけのはず。

[bcc64 致命的エラー] vlcwrapper.h(8): 'vlc/vlc.h' file not found

とかのエラーが出たら、インクルードパスにvlcのヘッダー群の在処を指定。

筆者の環境での一例です。さてbuild and runすると、

聞こえます。nhkラジオだとFM放送以外に、大昔からあるラジオ第一放送(R1)ないしラジオ第二放送(R2)も聞けます。それらは、

https://www.nhk.or.jp/radio/config/config_web.xml

を眺めるとurlがわかります。ちなみにVLCの用語でいえば、MRLですね。Media Resource Locatorの略。中身(一部東京)

<areajp>東京</areajp>
<area>tokyo</area>
<apikey>001</apikey>
<areakey>130</areakey>
<r1hls>
<![CDATA[ https://simul2.drdi.st.nhk/live/3/joined/master.m3u8 ]]>
</r1hls>
<r2hls>
<![CDATA[ https://simul.drdi.st.nhk/live/4/joined/master.m3u8 ]]>
</r2hls>
<fmhls>
<![CDATA[ https://simul2.drdi.st.nhk/live/5/joined/master.m3u8 ]]>
</fmhls>

MRLは、

R1
https://simul2.drdi.st.nhk/live/3/joined/master.m3u8

R2

https://simul.drdi.st.nhk/live/4/joined/master.m3u8
FM
https://simul2.drdi.st.nhk/live/5/joined/master.m3u8

プロトコルがhlsであることが示唆されているので、これをブラウザに食わせてても聴取できます。joinedの後にaudioが付いても付かなくてもよいですね。バンド切り替えできるようにしてもいいですね。あと再生レベルの調整も可です。フォームがすかすかなのて、VUメーター風の表示してもおけです。

コメント