B4J Question Can I do more than MediaView.dispose to make MediaView ready again?

bdunkleysmith

Active Member
Licensed User
Longtime User
I have an app which displays up to 12 short (~ 6 second) mp4 videos sequentially, however despite seemingly overcoming the problem as reported in this thread, again I'm having some of the videos randomly not showing. The watchdog timer (Timer5) I implemented ensures the display continues to the next video, but I'd like to fix this "random" problem so all videos show.

Here's an extract of the code which includes the relevant subs:

B4X:
Private MediaView0, MediaView1 As MediaView

Sub PlayerIntros
    ' Show videos or images of players in that preferential order
    ' Players
    For Each k As Object In mapHomeTeam.Keys
        Dim playerId As String = mapHomeTeam.Get(k)
        For a = 0 To mapHomeTeam.Size - 1
        If playerId = arrayHome(a, 0) Then  
                Dim mediaFile As String = arrayHome(a, 1).SubString(arrayHome(a, 1).IndexOf(" ") + 2)                                  
                If IntroVideos(mediaFile & ".mp4", arrayHome(a, 1).SubString2(0, 2).Trim) = True Then
                    Timer5.Enabled = True
                    wait For video_Complete
                    Display.playernumber.As(B4XView).SendToBack
                    MediaView1.Dispose
                    Timer5.Enabled = False
                Else if IntroImages(mediaFile & ".png", arrayHome(a, 1).SubString2(0, 2).Trim) = True Then
                    Sleep(txtIntrosDelay.text * 1000)
                    Display.ivGraphics.visible = False
                Else
                    IntroImages("noImageFile.png", arrayHome(a, 1).SubString2(0, 2).Trim)
                    Sleep(txtIntrosDelay.text * 1000)
                    Display.ivGraphics.visible = False
                End If
        End If
        Next
    Next
End Sub

Sub mpp_Complete
    CallSubDelayed(Me, "video_Complete")
End Sub

Sub IntroVideos(videoFile As String, pNum As String ) As Boolean    'Player - first initial dot space secondname dot MP4, player singlet number / Coaches & Team Managers - firstname dot space secondname dot MP4, ""
    Display.playerNumber.text = pNum
    Display.playerNumber.visible = True
    If File.Exists(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile) = True Then
        MediaView1.Initialize(Me, "mpp")
        MediaView1.DesignerCreateView(Display.fullPane, Null, Null)
        MediaView1.Source = File.GetUri(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile)
        MediaView1.play
        MediaView1.Volume = 0        'Mute player intro video clips
        Display.playernumber.As(B4XView).BringToFront
'        Log (pNum & " | " & videoFile & " | True")
        Return True
    Else
        Display.playernumber.As(B4XView).BringToFront
'        Log (pNum & " | " & videoFile & " | False")
        Return False
    End If
End Sub

As can be seen, I repeatedly use Mediaview1 and issue a
B4X:
MediaView1.Dispose
command prior to initializing MediaView1 ready to display the next video. The error which occurs causing a random video in the sequence not to show is captured by
B4X:
Sub mpp_Error (Message As String)
    Log("Intro videos error: " & Message)
End Sub
and this is an example:
B4X:
Intro videos error: MediaException: UNKNOWN : [com.sun.media.jfxmediaimpl.platform.gstreamer.GSTMediaPlayer@260da058] ERROR_MEDIA_INVALID: ERROR_MEDIA_INVALID
but the media is valid because most times all videos display in sequence.

I wonder whether
B4X:
MediaView1.Dispose
is sufficient to truly dispose of all resources ready for the initialization again and so perhaps Mediaview1 is not completely ready to be initialized or perhaps memory is not completely cleared leading to these random errors. Although I'm yet to find a video file size that never throws an error, it does seem reducing the size of the video files is beneficial, eg. 2mb files appear to error less than 5mb files.

Because it's random, I'm finding it hard to systematically diagnose the cause and so any ideas ideas/suggestions would be warmly received.
 

TILogistic

Expert
Licensed User
Longtime User
see code:

I don't remember if it's the buffer and playlist management version.

you can watch video in full screen

The video view is responsive
 
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Thanks for your reply @TILogistic but are you suggesting I can just install the jMediaView library and select that library in lieu of the MediaView library in the Libraries Manager?

Do you believe use of jMediaView in lieu of MediaView will eliminate my random MediaException errors?

I note in your example code that there is no initialilization of MediaView1 like I have in my code:
B4X:
MediaView1.Initialize(Me, "mpp")
Is initialization not required?
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
Dear, it is the same library with some display modifications and others.
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
I modified it to use it in B4x with SMM in this app

 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
If you want, unzip it and see the code. I don't remember if it's the one that handles playlists and fluid video display (buffer).
 
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Thank you @TILogistic for your clarification and further information.

As I noted in the this thread when I first encountered this problem, I did not pursue implementation of the pre-loading technique used in this post Media exception error because its implementation in my situation would be rather difficult in my situation. However I will revisit this because I'm making no progress determining the cause of the current random error and so I need to try something different.

Incidentally, this app involves use of the UI on one screen and the video on a second screen. My development and testing is done on a PC with a standard 21" external monitor. Inexplicably I've encountered another fatal error only when connected to a large 6m video screen where the app is used. The error in this case was that the first video in the sequence just kept looping, something I've never seen in my testing with a small external monitor and should not happen according to my code. I'm struggling to understand both the random non-playing of some videos and this looping problem which only occurs when using a large video screen given the app has worked reliably in the past. I keep coming back to the thought that it's to do with the format/content of the new short videos produced for use this year. This year's videos are larger and so I tried compressing them with no noticeable improvement, but I'm wondering if the compression actually reduces the underlying makeup of the video and so demand on the PC processing.
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
see:
1744346624701.png


Prebuffering

B4X:
Sub PlayWithPrebuffering
    If CurrentIndex < FileList.Size Then
        Dim FilePath As String = FileList.Get(CurrentIndex)
        MediaJO.InitializeNewInstance("javafx.scene.media.Media", Array(FilePath))
        MediaPlayerJO.InitializeNewInstance("javafx.scene.media.MediaPlayer", Array(MediaJO))
        MediaViewJO.RunMethod("setMediaPlayer", Array(MediaPlayerJO))
        Dim PlayerJO As JavaObject = MediaPlayerJO
        Do While PlayerJO.RunMethod("getBufferProgressTime", Null).RunMethod("toSeconds", Null) < 5
            Log("Esperando más datos en el buffer... " & PlayerJO.RunMethod("getBufferProgressTime", Null).RunMethod("toSeconds", Null) & " segundos acumulados.")
            Sleep(500)
        Loop
        Log("Buffer suficiente acumulado. Iniciando reproducción.")
        PlayerJO.RunMethod("play", Null)
    Else
        Log("Todos los videos han sido reproducidos.")
    End If
End Sub
 
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Again thank you @TILogistic for your input.

Rather than use setOnEndOfMedia, I am waiting for the MediaView _Complete event before using Dispose to release the instance resources.

In regard to prebuffering, I'm not skilled enough to work out how I add/insert that into my code. I presume this code:

B4X:
        MediaJO.InitializeNewInstance("javafx.scene.media.Media", Array(FilePath))
        MediaPlayerJO.InitializeNewInstance("javafx.scene.media.MediaPlayer", Array(MediaJO))
        MediaViewJO.RunMethod("setMediaPlayer", Array(MediaPlayerJO))
        Dim PlayerJO As JavaObject = MediaPlayerJO
        Do While PlayerJO.RunMethod("getBufferProgressTime", Null).RunMethod("toSeconds", Null) < 5
            Sleep(500)
        Loop
        PlayerJO.RunMethod("play", Null)

would somehow replace this part of my code shown in post #1:

B4X:
        MediaView1.Initialize(Me, "mpp")
        MediaView1.DesignerCreateView(Display.fullPane, Null, Null)
        MediaView1.Source = File.GetUri(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile)
        MediaView1.play

I think I need to put this problem aside and come back to it later with a fresh mind!
 
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Thought I'd use this as a learning exercise and try to include the getBufferProgressTime method in a customised version of MediaView so that I could try the prebuffering suggestion.

I have added in my customised MediaView:

B4X:
'Returns BufferProgressTime.
Public Sub getBufferProgressTime as Double
    Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).As(JavaObject).RunMethod("toMillis", Null)
End Sub

Then I have created a PreBuffer sub which will delay playing the video until at least 5 seconds of video is loaded in the buffer:

B4X:
Sub IntroVideos(videoFile As String, pNum As String ) As Boolean    'Player - first initial dot space secondname dot MP4, player singlet number / Coaches & Team Managers - firstname dot space secondname dot MP4, ""
    Display.playerNumber.text = pNum
    Display.playerNumber.visible = True
    If File.Exists(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile) = True Then
        MediaView1.Initialize(Me, "mpp")
        MediaView1.DesignerCreateView(Display.fullPane, Null, Null)
        MediaView1.Source = File.GetUri(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile)
        
        PreBuffer
        
        MediaView1.play
        MediaView1.Volume = 0        'Mute player intro video clips
        Display.playernumber.As(B4XView).BringToFront
        Return True
    Else
        Display.playernumber.As(B4XView).BringToFront
        Return False
    End If
End Sub

Sub PreBuffer
    Do While MediaView1.BufferProgressTime < 5000
        Log("Waiting for more data in the buffer... " & MediaView1.BufferProgressTime & " accumulated milliseconds.")
        Sleep(500)
    Loop
    Log("Sufficient buffer accumulated. Starting playback.")
End Sub

When my app is run and the code tries to run the PreBuffer sub, this error is thrown:

mediaview._getbufferprogresstime (java line: 168)
java.lang.RuntimeException: Object should first be initialized (JavaObject).
at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:49)
at anywheresoftware.b4j.object.JavaObject.getCurrentClass(JavaObject.java:259)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:119)
at b4j.example.mediaview._getbufferprogresstime(mediaview.java:168)
at b4j.example.main$ResumableSub_PreBuffer.resume(main.java:6783)
at b4j.example.main._prebuffer(main.java:6758)
at b4j.example.main._introvideos(main.java:4200)
at b4j.example.main$ResumableSub_PlayerIntros.resume(main.java:6359)
at b4j.example.main._playerintros(main.java:6248)
at b4j.example.main._mp_complete(main.java:5569)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:514)
at anywheresoftware.b4a.keywords.Common.access$0(Common.java:494)
at anywheresoftware.b4a.keywords.Common$CallSubDelayedHelper.run(Common.java:568)
at javafx.graphics@18.0.1/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics@18.0.1/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at javafx.graphics@18.0.1/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics@18.0.1/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics@18.0.1/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)

If instead of the line:
B4X:
Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).As(JavaObject).RunMethod("toMillis", Null)
I remove .As(JavaObject) so it becomes:
B4X:
Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).RunMethod("toMillis", Null)
then a compilation error is thrown:
Compiling code. Error
Error compiling program.
Error description: Unknown type: Object
Are you missing a library reference?
Error occurred on line: 102
Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).RunMethod("toMillis", Null)
Word: runmethod

Any suggestions/guidance would be appreciated.
 
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Just researching further https://docs.oracle.com/javase/8/ja...a/MediaPlayer.html#bufferProgressTimeProperty I note it says "This is applicable to buffered streams such as those reading from network connections as opposed for example to local files."

So perhaps the bufferProgressTime property is not set when the media player source is a local file and not a remote stream, and that why it's not initialized, thus throwing the error.

Thoughts?
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
Thought I'd use this as a learning exercise and try to include the getBufferProgressTime method in a customised version of MediaView so that I could try the prebuffering suggestion.

I have added in my customised MediaView:

B4X:
'Returns BufferProgressTime.
Public Sub getBufferProgressTime as Double
    Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).As(JavaObject).RunMethod("toMillis", Null)
End Sub

Then I have created a PreBuffer sub which will delay playing the video until at least 5 seconds of video is loaded in the buffer:

B4X:
Sub IntroVideos(videoFile As String, pNum As String ) As Boolean    'Player - first initial dot space secondname dot MP4, player singlet number / Coaches & Team Managers - firstname dot space secondname dot MP4, ""
    Display.playerNumber.text = pNum
    Display.playerNumber.visible = True
    If File.Exists(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile) = True Then
        MediaView1.Initialize(Me, "mpp")
        MediaView1.DesignerCreateView(Display.fullPane, Null, Null)
        MediaView1.Source = File.GetUri(PublicApplicationDataFolder & "\Intros\" & cmbOrganisationID.Value, videoFile)
       
        PreBuffer
       
        MediaView1.play
        MediaView1.Volume = 0        'Mute player intro video clips
        Display.playernumber.As(B4XView).BringToFront
        Return True
    Else
        Display.playernumber.As(B4XView).BringToFront
        Return False
    End If
End Sub

Sub PreBuffer
    Do While MediaView1.BufferProgressTime < 5000
        Log("Waiting for more data in the buffer... " & MediaView1.BufferProgressTime & " accumulated milliseconds.")
        Sleep(500)
    Loop
    Log("Sufficient buffer accumulated. Starting playback.")
End Sub

When my app is run and the code tries to run the PreBuffer sub, this error is thrown:



If instead of the line:
B4X:
Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).As(JavaObject).RunMethod("toMillis", Null)
I remove .As(JavaObject) so it becomes:
B4X:
Return jMediaPlayer.RunMethod("getBufferProgressTime", Null).RunMethod("toMillis", Null)
then a compilation error is thrown:


Any suggestions/guidance would be appreciated.
see:
 
Upvote 0
Top