Android Mediaprojection api from delphi

685 Views Asked by At

I have written something with delphi for testing android mediaprojection api. ( https://developer.android.com/reference/android/media/projection/MediaProjection )

I tried to convert some of the java codes to delphi.

java example: https://github.com/mtsahakis/MediaProjectionDemo/blob/master/src/com/mtsahakis/mediaprojectiondemo/ScreenCaptureImageActivity.java

When you click the button it will ask to authorize the user to capture the screen.

When the user accept, it will register one procedure to mediaprojection api.

So when the screen changed, the api will call our procedure with picture data and we will show any text on the screen for testing.

i tested my code below.

When you accept the screen asking for permission the app crash and closes instantly.

On Android 8.1:

raised exception class Senmentation fault(11) ----> System ---> procedure _InstCopy() ----> Source.__ObjAddRef

or

raised exception class Illegal instruction(4) ----> System.Internal.Excutils.SignalConverter

On Android 6.0:

raised exception class EInvalidCast with message 'Invalid class typecast' ----> System.Rtti ---> System._DbgExcNotify

unit frmuMediaProjectionTest;

    interface

    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
      FMX.Controls.Presentation, FMX.StdCtrls,

      System.Messaging, Androidapi.JNI.GraphicsContentViewText,
      Androidapi.JNI.Media, Androidapi.JNIBridge;

    type
      TonImageAvailable = procedure (reader: JImageReader) of object;

      TImageAvailableListener = class( TJavaLocal, JImageReader_OnImageAvailableListener )
       private
         FonImageAvailable: TonImageAvailable;
       public
        procedure onImageAvailable(reader: JImageReader);cdecl;

        property onIAvailable: TonImageAvailable read FonImageAvailable write FonImageAvailable;
      end;

      TfrmMediaProjectionTest = class(TForm)
        Button1: TButton;
        Label1: TLabel;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        MPManager: JMediaProjectionManager;
        FMessageSubscriptionID: integer;

        procedure HandleActivityMessage(const Sender: TObject; const M: TMessage);
        function OnActivityResult(RequestCode, ResultCode: Integer; Data: JIntent): Boolean;

        procedure onImageAvailable(reader: JImageReader);
      public

      end;

    var
      frmMediaProjectionTest: TfrmMediaProjectionTest;

    implementation

    {$R *.fmx}

    Uses //Androidapi.JNI.Media,
         AndroidApi.Jni.JavaTypes,
         Androidapi.Helpers,
         //Androidapi.JNI.GRaphicsContentViewText,
         //Androidapi.JNIBridge,
         Androidapi.JNI.os,
         Androidapi.JNI.App;


    procedure TfrmMediaProjectionTest.FormCreate(Sender: TObject);
    begin
      MPManager := nil;
    end;


    procedure TfrmMediaProjectionTest.Button1Click(Sender: TObject);
     var MPObj: JObject;
    begin
      FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage( TMessageResultNotification, HandleActivityMessage );

      MPObj := TAndroidHelper.Context.getSystemService( TJContext.JavaClass.MEDIA_PROJECTION_SERVICE );
      MPManager := TJMediaProjectionManager.Wrap( ( MPObj as ILocalObject ).GetObjectID );
      TAndroidHelper.Activity.startActivityForResult( MPManager.createScreenCaptureIntent, 100 );
    end;


    procedure TfrmMediaProjectionTest.HandleActivityMessage(const Sender: TObject; const M: TMessage);
     begin
       if M is TMessageResultNotification then
           OnActivityResult( TMessageResultNotification( M ).RequestCode, TMessageResultNotification( M ).ResultCode,
                             TMessageResultNotification( M ).Value );
     end;


    //ResultCode: iptal: 0   kabul: -1
    function TfrmMediaProjectionTest.OnActivityResult( RequestCode, ResultCode: Integer; Data: JIntent ): Boolean;
     const RGBA_8888: integer = 1;
           mDencity: integer = 160;
           VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY: integer = 8;
           VIRTUAL_DISPLAY_FLAG_PUBLIC: integer = 1;
     var mp: JMediaProjection;
         imageReader: JImageReader;
         handler: JHandler;
         ImageAvailableListener: TImageAvailableListener;
     begin
       TMessageManager.DefaultManager.Unsubscribe( TMessageResultNotification, FMessageSubscriptionID );

       if ResultCode = -1 then
       begin
         mp := MpManager.getMediaProjection( ResultCode, Data );
         if mp <> nil then
         begin
           imageReader := TJImageReader.JavaClass.newInstance( screen.Width, screen.Height, RGBA_8888, 2 );

           handler := TJHandler.JavaClass.init();

           mp.createVirtualDisplay( StringToJString( 'Test' ), screen.Width, screen.Height, mDencity,
                                    VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY or VIRTUAL_DISPLAY_FLAG_PUBLIC,
                                    imageReader.getSurface, nil, handler );

           ImageAvailableListener := TImageAvailableListener.Create;
           ImageAvailableListener.onIAvailable := onImageAvailable;
           imageReader.setOnImageAvailableListener( ImageAvailableListener, handler );
         end;
       end
       else
       if ResultCode = 0 then showmessage( 'Canceled' );

       result := true;
     end;


    procedure TfrmMediaProjectionTest.onImageAvailable(reader: JImageReader);
    begin
       Label1.Text := 'Called from api';
    end;

    { TImageAvailableListener }

    procedure TImageAvailableListener.onImageAvailable(reader: JImageReader);cdecl;
    begin
      if assigned( FonImageAvailable ) then
      begin
        FonImageAvailable( reader );
      end;
    end;

    end.
0

There are 0 best solutions below