Java Question ExoPlayer Wrapper Development

ronovar

Active Member
Licensed User
Longtime User
Hi...i im trying to develope library for B4A that i will use...

I have found ExoPlayer that suits my needs...so i installed Eclipse...see tutorial how to create B4A libraries, compile from sources ExoPlayer...got library.jar and now i need help how to write public functions to initialize player, add to view, add url file, and play file.

i im this way:

B4X:
package com.google.exoplayerb4a;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.objects.ViewWrapper;

import com.google.android.exoplayer.*;

@ShortName("ExoPlayerB4A")
@BA.Version(1.5F)

public class ExoPlayerB4A
  extends ViewWrapper<ExoPlayer>
{

}

Here is wrapper:

https://github.com/googleads/google...ork/exoplayerextensions/ExoplayerWrapper.java

So the question is how can i add exoplayer so that i can call from B4A:

B4X:
Dim ExoPlayer1 As ExoPlayerB4A

ExoPlayer1.Initialize("ExoPlayer1")
Activity.AddView(ExoPlayer1, 0, 0, 100%x, 100%y)

ExoPlayer1.SetURL("Http:\\myurl.com\file.mkv")
ExoPlayer1.Prepare
ExoPlayer1.Play

If someone can give me how can i add ExoPlayer to get thease functions it will be great...
 

ronovar

Active Member
Licensed User
Longtime User
As can i see i need first to add native ExoPlayer View to B4A View....

I try using this code but it error:

B4X:
public class ExoPlayerWrapper
  extends ViewWrapper<ExoPlayer> {
}
 

DonManfred

Expert
Licensed User
Longtime User

ronovar

Active Member
Licensed User
Longtime User
Thanks...i found that jar wrapper exists (and have videoview same api calls)...i added this in eclipse to build library:

B4X:
package google.b4a.exoplayer;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.objects.ViewWrapper;

import com.devbrackets.android.exomedia.EMVideoView;

@ShortName("ExoPlayer")
@BA.Version(1.0F)

public class ExoPlayerWrapper
  extends ViewWrapper<EMVideoView> {
   
    public static void LIBRARY_DOC() {}
   
    public void Initialize(BA paramBA, String paramString)
    {
        super.Initialize(paramBA, paramString);
    }

}

It compiles fine...B4A imports library fine...i added in B4A:

B4X:
'DEFINE - ExoPlayer
    Dim ExoPlayer1 As ExoPlayer

   ExoPlayer1.Initialize("ExoPlayer1")

And i im gettign in log:

B4X:
java.lang.RuntimeException: Object should first be initialized (ExoPlayer).

I did not get why public void Initialize does not initialize ExoPlayer?
 

ronovar

Active Member
Licensed User
Longtime User
Here is the updated code:

B4X:
package google.b4a.exoplayer;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.DependsOn;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.objects.ViewWrapper;

import com.devbrackets.android.exomedia.EMVideoView;

@ShortName("ExoPlayer")
@DependsOn(values={"emvideoview"})
@BA.Version(1.0F)

public class ExoPlayer extends ViewWrapper<EMVideoView> {
    public void Initialize(BA paramBA, String paramString)
    {
        super.Initialize(paramBA, paramString);
    }
   
    @BA.Hide
    public void innerInitialize(final BA pBA, final String pEventName, boolean pKeepOldObject)
    {
        if (!pKeepOldObject)
       {
          EMVideoView videoView = new EMVideoView(pBA.context);
          setObject(videoView);
       }
       super.innerInitialize(pBA, pEventName, true);
    }
}

I call in B4A:

B4X:
'DEFINE - ExoPlayer
    Dim ExoPlayer1 As ExoPlayer
    ExoPlayer1.Initialize("ExoPlayer1")


And I im getting this error:

B4X:
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
java.lang.NoClassDefFoundError: com.devbrackets.android.exomedia.EMVideoView
    at google.b4a.exoplayer.ExoPlayer.innerInitialize(ExoPlayer.java:25)
    at anywheresoftware.b4a.objects.ViewWrapper.Initialize(ViewWrapper.java:65)
    at google.b4a.exoplayer.ExoPlayer.Initialize(ExoPlayer.java:17)
    at b4a.example.main._activity_create(main.java:355)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:702)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:336)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:246)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:134)
    at b4a.example.main.afterFirstLayout(main.java:102)
    at b4a.example.main.access$000(main.java:17)
    at b4a.example.main$WaitForLayout.run(main.java:80)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5017)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:788)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:604)
    at dalvik.system.NativeStart.main(Native Method)
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Service (starter) Destroy **

I copy ExoPlayer.jar and ExoPlayer.xml and emvideoview.jar to B4A libraries folder (emvideoview.jar is native EMVideoView compiled jar from github)

I included @DependsOn(values={"emvideoview"}) but errors is stil that it does not finc classdef why?
 

ronovar

Active Member
Licensed User
Longtime User
Here is Project using SLC library compiler..if someone can look (it compiles fine...but B4A get error: java.lang.NoClassDefFoundError: com.devbrackets.android.exomedia.EMVideoView)

Here is SLC project...just look at ExoPlayer folder...
 

Attachments

  • SimpleLibraryCompiler.zip
    392.7 KB · Views: 353

ronovar

Active Member
Licensed User
Longtime User
Thanks...now it compiles without error ( i im just adding ExoPlayerWrapper.jar and forget to include ExoPlayer.jar from google...now when i call ExoPlayer1.Initialize("ExoPlayer1") in B4A it run program....now i need to wrap others api calls to eclipse so that i can test if is working)

Thanks Erel
 

ronovar

Active Member
Licensed User
Longtime User
I got another problem..i need to get Sub ExoPlayer1_Prepared Event...i setup this in java:

B4X:
public class ExoPlayer extends ViewWrapper<EMVideoView> {
    /*
    * XML wrapper
    * Extract funtions in xml file
    */
    public static void LIBRARY_DOC() {}
   
    /*
    * Initialize the ExoPlayer object to B4A
    */
    @Override
    public void Initialize(BA paramBA, String paramString)
    {
        super.Initialize(paramBA, paramString);
    }
   
    /*
    * Wrap the ExoPlayer view to B4A view
    */
    @Override
    @BA.Hide
    public void innerInitialize(final BA pBA, final String pEventName, boolean pKeepOldObject)
    {
        if (!pKeepOldObject)
       {
          EMVideoView VideoView = new EMVideoView(pBA.context);

          if (pBA.subExists(pEventName + "_Prepared")) {
              VideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
              {
                  public void onPrepared(android.media.MediaPlayer arg0)
                 {
                     pBA.raiseEvent(ExoPlayer.this, pEventName + "_Prepared", new Object[0]);
                 }
              });
          } else {
              Log.e("B4A", "Sub Does Not Exists..." +(pEventName + "_Prepared"));
          }
          setObject(VideoView);
       }
       super.innerInitialize(pBA, pEventName, true);
    }
   
    /*
    * Sets the path to the video
    * This path can be a web address (e.g. http://) or an absolute local path (e.g. file://)
    * @param: path - The path to the video
    */
    public void SetVideoPath(String VideoPath) {
        ((EMVideoView)getObject()).setVideoPath(VideoPath);
    }
   
    /*
    * Starts or resumes playback
    */
    public void Start() {
        ((EMVideoView)getObject()).start();
    }
   
    /*
     * Enables and disables the media control overlay for the video view
     * @param: enabled - Weather the default video controls are enabled (default: false)
     */
    public void SetDefaultControlsEnabled(boolean Enabled) {
        ((EMVideoView)getObject()).setDefaultControlsEnabled(Enabled);
    }
   
}

All compiles fine and in B4A i added this:

B4X:
'DEFINE - ExoPlayer
    Dim ExoPlayer1 As ExoPlayer

'INITILIZE - ExoPlayer
    ExoPlayer1.Initialize("ExoPlayer1")

'URL - ExoPlayer
    ExoPlayer1.SetVideoPath("http://myurl.com/file.mp4")
   
    'PLAY - ExoPlayer
    ExoPlayer1.Start
   
    'ADDVIEW - ExoPlayer
    Activity.AddView(ExoPlayer1, 0, 0, 100%x, 100%y)

And in B4A Log i see:

B4X:
Sub Does Not Exists...exoplayer1_Prepared
[email protected]

Why above function does not trigger _Prepared event? I Defined it correctly (using example in VideoView.class wrapper and event is not fired when video start playing why?

Using this wrapper ExoPlayer sucessfully start playing video....i added setvideopath and start api, so i need to add events so that i then port all library to b4a library
 

ronovar

Active Member
Licensed User
Longtime User
Thanks Erel for replay...but i don't understand what you say.

I have:

B4X:
if (pBA.subExists(pEventName + "_Prepared")) {
 
} else {
 Log.e("B4A", "Sub Does Not Exists..." +(pEventName + "_Prepared"));
 }

And when i run in B4A this library using above example code i always get:

B4X:
Sub Does Not Exists...exoplayer1_Prepared

So the problem is that ExoPlayer1 is initialized in above public void Initialize(BA paramBA, String paramString) and when function pBA.subExists(pEventName + "_Prepared") checks (function cheks if pBA.subExists("ExoPlayer1_Prepared") exists) and it not find it....and i don't figure it why could it not find it?

in B4A i have this code:

B4X:
'PREPARED - Event
Sub ExoPlayer1_Prepared
    Log("ExoPlayer1_Prepared")   
End Sub
 

DonManfred

Expert
Licensed User
Longtime User
Erel said you should use LOWERCASED eventnames...
pBA.raiseEvent(ExoPlayer.this, pEventName + "_Prepared", new Object[0]);
->
pBA.raiseEvent(ExoPlayer.this, pEventName + "_prepared", new Object[0]);
Make sure pEventName is LOWERCASED TOO (the content, not the variablename)

B4X:
    public void Initialize(final BA ba, String EventName) {
        this.pEventName = EventName.toLowerCase(BA.cul);
 

ronovar

Active Member
Licensed User
Longtime User
Yesss...that's true....i forget that java Prepare and prepare is not the same...now i just change to _prepare...and i see in B4A that event is called...thanks:)

Now i will add the other 5 events so that events is complete...will replay here when i get into problem.

(Wrapping library is very nice job when you know what do you doing :))
 

ronovar

Active Member
Licensed User
Longtime User
I just use this:

B4X:
@Events(values={"prepared"})

And it works...will add to this events 5 more...
 

ronovar

Active Member
Licensed User
Longtime User
Ok..i have now succesfully added Event: onCompleted, onError, onPrepared...all this three events in B4A works perfectly.

I could not get onInfo event to return values in B4A...all compile fine in Eclipse...in B4A i only see log from onInfo that i write in Eclipse...but onInfo from B4A is not called....why?

here is eclipse code:

B4X:
/*
          * OnInfo
          * Called to indicate an info or a warning
          */
          if (pBA.subExists(pEventName + "_oninfo")) {
Log.e("B4A", pEventName + "_oninfo1");
              VideoView.setOnInfoListener(new MediaPlayer.OnInfoListener()
              {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra)
                    {
                        String What = null;
                      switch(what) {
                          case MediaPlayer.MEDIA_INFO_UNKNOWN:
                              What = "Unspecified MediaPlayer Info";
                              break;
                          case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
                              What = "The Video Is Too Complex For The Decoder";
                              break;
                          case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                              What = "The Player Just Pushed The Very First Video Frame For Rendering";
                              break;
                          case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                              What = "MediaPlayer Is Temporarily Pausing Playback Internally In Order To Buffer More Data";
                              break;
                          case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                              What = "MediaPlayer Is Resuming Playback After Filling Buffers";
                              break;
                          case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
                              What = "Media Has Been Improperly Interleaved Or Not Interleaved At All";
                              break;
                          case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
                              What = "The Media Cannot Be Seeked";
                              break;
                          case MediaPlayer.MEDIA_INFO_METADATA_UPDATE:
                              What = "A New Set Of Metadata Is Available";
                              break;
                          case MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:
                              What = "Subtitle Track Was Not Supported By The Media Framework";
                              break;
                          case MediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:
                              What = "Reading The Subtitle Track Takes Too Long";
                              break;
                          default:
                              What = "OK";
                              break;
                      }                  
                      String Extra = null;
                        pBA.raiseEvent(ExoPlayer.this, pEventName + "_oninfo", new Object[] {What, Extra});
                        return false;
                    }
                });
          }

in B4A i defined onInfo event:

B4X:
'OnInfo - Event
Sub ExoPlayer1_OnInfo(What As String, Extra As String) As Boolean
    Log("ExoPlayer1_OnInfo")
    Log(What)
    Log(Extra)
    'LIBRARY - handle event
    Return False   
End Sub

But event is not fired....i could not figure why?
 

ronovar

Active Member
Licensed User
Longtime User
I set this

B4X:
Log.e("B4A", pEventName + "_oninfo1");

To check event name if is called...and event name is called i get this in B4A log:

B4X:
exoplayer1_oninfo1

So Event _oninfo is called but does not execute next code after this Log.e("B4A", pEventName + "_oninfo1"); _oninfo is all lowercase letters and in B4A in only OnInfo Event. Could you get idea why code is not executing after Log.e?
 

moster67

Expert
Licensed User
Longtime User
I don't know if it related but if ExoPlayer is using the standard onInfoListener from MediaPlayer, then beware of the fact that it requires at least API level 13
 
Top