Androidのカメラ映像をWifi経由でWindowsに表示 ~Delphiソースコード集
0.作成するもの
同じLANに接続されている(同じWifiアクセスポイントに接続している)android端末とwindows端末で、 android端末のカメラで撮影した映像を1秒に1回windows端末にjpg形式で画像を転送して、 windows端末に表示します。
1.プロジェクトの作成とファイルの保存
ファイル⇒新規作成⇒マルチデバイス アプリケーション -Delphiをクリックします。
「空のアプリケーション」を選択してOKを押します。
「すべて保存」ボタンを押して、
ドキュメント\Embarcadero\Studio\Projects\AppTether\windows
フォルダにプロジェクト(Project1.dproj)とユニット(Unit1.pas)をデフォルトのまま保存します。
右ペイン(Project1.dproj - プロジェクト)の「ProjectGroup1」を右クリックし、 「新規プロジェクトを追加」を左クリックします。
「マルチデバイス アプリケーション」を選択してOKを左クリックします。
「空のアプリケーション」を選択してOKを左クリックします。
「すべて保存」ボタンを押して、
ドキュメント\Embarcadero\Studio\Projects\AppTether\android
フォルダにプロジェクト(Project2.dproj)とユニット(Unit2.pas)をデフォルトのまま保存します。
プロジェクトグループ「ProjectGroup1.groupproj」ファイルは
ドキュメント\Embarcadero\Studio\Projects\AppTether
フォルダに保存します。
右上ペインのProject2のターゲットプラットフォームを展開して「Android」をダブルクリックして切り替えます。
| ・・・\Projects\AppTether | |
| ProjectGroup1.groupproj | |
| ・・・\Projects\AppTether\windows | |
| Project1.dproj | |
| Unit1.pas | |
| ・・・\Projects\AppTether\android | |
| Project2.dproj | |
| Unit2.pas | |
2.画面の作成
Unit1(Windowsアプリの画面)にTButton、TEdit、TImage、TTetheringManager、TTetheringAppProfile、TTimerをドラッグ&ドロップします。
Unit2(Androidアプリの画面)に
TButton、TEdit、TTetheringManager、TTetheringAppProfile、TTimer、TCameraComponentをドラッグ&ドロップします。
3.プロパティの設定
Unit1(Windowsアプリの画面)のTetheringAppProfile1.ManagerプロパティをTetheringManager1に設定します。Unit1(Windowsアプリの画面)のTetheringAppProfile1.Groupプロパティを MyGroup に設定します。
Unit1(Windowsアプリの画面)のTetheringAppProfile1.Resourcesプロパティの[...]ボタンをクリックします。
新規追加ボタンをクリックすると「リソース0」が追加され、プロパティを以下に設定します。
Kind:Mirror Name:img ResType:Stream
Unit2(Androidアプリの画面)のTetheringAppProfile1.ManagerプロパティをTetheringManager1に設定します。
Unit2(Androidアプリの画面)のTetheringAppProfile1.Groupプロパティを MyGroup に設定します。
Unit2(Androidアプリの画面)のTetheringAppProfile1.Resourcesプロパティの[...]ボタンをクリックします。
新規追加ボタンをクリックすると「リソース0」が追加され、プロパティを以下に設定します。
Kind:Shared Name:img ResType:Stream
4.プロジェクトオプションの設定
右上ペインの「libProject2.so」をダブルクリックしてプロジェクトを切り替えます。プロジェクト⇒オプション をクリックします。
左ペインの アプリケーション⇒使用する権限 をクリックします。
ターゲットを、「すべての構成 - Androidプラットフォーム」に切り替えます。
カメラの使用にチェックをいれて「保存」をクリックします。
5.Unit1(Windowsアプリ)ソースコードの記述
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, IPPeerClient,
IPPeerServer, FMX.StdCtrls, FMX.Controls.Presentation, FMX.Edit, FMX.Objects,
System.Tether.Manager, System.Tether.AppProfile;
type
TForm1 = class(TForm)
TetheringManager1: TTetheringManager;
TetheringAppProfile1: TTetheringAppProfile;
Image1: TImage;
Timer1: TTimer;
Edit1: TEdit;
Button1: TButton;
procedure TetheringAppProfile1Resources0ResourceReceived(
const Sender: TObject; const AResource: TRemoteResource);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure TetheringAppProfile1AcceptResource(const Sender: TObject;
const AProfileId: string; const AResource: TCustomRemoteItem;
var AcceptResource: Boolean);
private
{ private 宣言 }
public
{ public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
begin
TetheringManager1.AutoConnect();
end;
procedure TForm1.TetheringAppProfile1AcceptResource(const Sender: TObject;
const AProfileId: string; const AResource: TCustomRemoteItem;
var AcceptResource: Boolean);
begin
AcceptResource:=True;
end;
procedure TForm1.TetheringAppProfile1Resources0ResourceReceived(
const Sender: TObject; const AResource: TRemoteResource);
begin
TThread.Synchronize(nil,procedure
begin
Image1.Bitmap.LoadFromStream(AResource.Value.AsStream);
end);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if TetheringManager1.RemoteProfiles.Count>0 then
Edit1.Text:='接続中'
else
Edit1.Text:='未接続';
end;
end.
6.Unit2(Androidアプリ)ソースコードの記述
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, IPPeerClient,
IPPeerServer, FMX.Edit, FMX.Controls.Presentation, FMX.StdCtrls, FMX.Media,
System.Tether.Manager, System.Tether.AppProfile,
FMX.platform, FMX.surfaces, System.Permissions ;
type
TForm2 = class(TForm)
TetheringManager1: TTetheringManager;
TetheringAppProfile1: TTetheringAppProfile;
Timer1: TTimer;
CameraComponent1: TCameraComponent;
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure CameraComponent1SampleBufferReady(Sender: TObject;
const ATime: TMediaTime);
private
{ private 宣言 }
img_flag:boolean;
Fstrm:TMemoryStream;
function AppEvent(iAppEvent:TApplicationEvent;iContext:TObject):Boolean;
procedure PermissionRequestResult(
Sender: TObject; const APermissions: TArray;
const AGrantResults: TArray);
procedure RequestPermissions();
public
{ public 宣言 }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
uses
Androidapi.Helpers, Androidapi.JNI.Os,
//Androidapi.JNI.JavaTypes,
Androidapi.Jni.Support, FMX.DialogService ;
function TForm2.AppEvent(iAppEvent: TApplicationEvent;
iContext: TObject): Boolean;
begin
Result:=False;
case iAppEvent of
TApplicationEvent.BecameActive:
begin
//focus取得時
CameraComponent1.Active:=true;
Sleep(100);
CameraComponent1.Active:=False;
Sleep(400);
//オートフォーカスモードに設定する
CameraComponent1.FocusMode:=TFocusMode.ContinuousAutoFocus;
CameraComponent1.Active:=True;
end;
TApplicationEvent.WillBecomeInactive:
begin
//focus喪失時
CameraComponent1.Active:=False;
end;
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
TetheringManager1.AutoConnect();
end;
procedure TForm2.CameraComponent1SampleBufferReady(Sender: TObject;
const ATime: TMediaTime);
var bmp :TBitmap;
bmps :TBitmapSurface;
pm :TBitmapCodecSaveParams;
begin
if img_flag then
TThread.Synchronize(
TThread.CurrentThread,
procedure
begin
bmp:=TBitmap.Create;
bmps := TBitmapSurface.Create;
CameraComponent1.SampleBufferToBitmap(bmp,true);
bmps.Assign(bmp);
if Fstrm<>nil then fstrm.DisposeOf;
Fstrm:=TMemoryStream.Create;
//品質80で保存(0-100)
pm.Quality:=80;
TBitmapCodecManager.SaveToStream(fstrm,bmps,'.jpg',@pm);
fstrm.Position:=0;
TetheringAppProfile1.Resources.FindByName('img').Value:=fstrm;
img_flag:=false;
bmp.DisposeOf;
bmps.DisposeOf;
end
);
end;
procedure TForm2.FormCreate(Sender: TObject);
var APPEventService:IFMXApplicationEventService;
begin
img_flag:=false;
CameraComponent1.Kind:=TCameraKind.BackCamera;
if TPlatformServices.Current.SupportsPlatformService(
IFMXApplicationEventService) then
begin
APPEventService:=IFMXApplicationEventService(
TPlatformServices.Current.GetPlatformService(
IFMXApplicationEventService)
);
end;
if (APPEventService<>nil) then
APPEventService.SetApplicationEventHandler(AppEvent);
RequestPermissions();
end;
procedure TForm2.PermissionRequestResult(Sender: TObject;
const APermissions: TArray;
const AGrantResults: TArray);
begin
//カメラとストレージの権限があるか
if (AGrantResults[0]<>TPermissionStatus.Granted) then
begin
//権限がない場合
//「□今後は表示しない」チェックボックスにチェックが入っているか
if (TJActivityCompat.JavaClass.shouldShowRequestPermissionRationale(
TAndroidHelper.Activity,TJManifest_permission.JavaClass.CAMERA)) then
begin
//「□今後は表示しない」チェックボックスにチェックが入っていない場合
// 非同期でダイアログを表示して説明と許可を要求
TDialogService.MessageDialog(
'許可しないとアプリが動作しません。',TMsgDlgType.mtInformation,
[TMsgDlgBtn.mbOK],TMsgDlgBtn.mbOk,0,
procedure (const AResult: TModalResult)
begin
//2回目以降は「□今後は表示しない」チェックボックスが表示される
RequestPermissions();
end);
end
else
begin
//「□今後は表示しない」チェックボックスにチェックが入っている
TDialogService.MessageDialog(
'権限が無いため終了します。「設定⇒アプリと通知」から権限を設定してください。',
TMsgDlgType.mtError,[TMsgDlgBtn.mbOK],TMsgDlgBtn.mbOK,0,
procedure(const AResult:TModalResult)
begin
Application.Terminate;
end
);
end;
end;
end;
procedure TForm2.RequestPermissions;
var FPmsCamera: string;
begin
FPmsCamera :=
JStringToString(TJManifest_permission.JavaClass.CAMERA);
PermissionsService.RequestPermissions(
[FPmsCamera],PermissionRequestResult);
end;
procedure TForm2.Timer1Timer(Sender: TObject);
begin
if TetheringManager1.RemoteProfiles.Count>0 then
begin
Edit1.Text:='接続中';
img_flag:=true;
end
else
begin
Edit1.Text:='未接続';
img_flag:=false;
end;
end;
end.
7.完成したアプリケーションを起動する
(1)Windowsアプリの実行
右上ペインのProject1.exeをダブルクリックします。実行⇒実行 又はツールバーの「右三角」ボタンを押して実行します。
(2)Androidアプリの実行
右上ペインのlibProject2.soをダブルクリックします。実行⇒実行 又はツールバーの「右三角」ボタンを押して実行します。
以下ダイアログが表示されたら「許可」をタップします。
(3)Windowsアプリの操作
起動したらButton1をクリックします。以下ダイアログが表示されたら「アクセスを許可する」をクリックします。
(4)Androidアプリの操作
Button1をクリックします。(5)WindowsアプリとAndroidアプリがアプリケーションテザリングでネットワーク接続され、Androidアプリのカメラ映像がWindowsアプリに送信され表示される
