Android Question Optimisation question

freedom2000

Well-Known Member
Licensed User
Longtime User
HI all,

I have this code that I would like to run as fast as possible :
B4X:
For i= 0 To list_files.Size -1
        ImageView1.Bitmap = LoadBitmap(Dir,list_files.Get(i))
        Sleep(0)
    Next

If I remove the Sleep(0) then the UI freezes.
Is there a way to optimize it ?
Threading library ? Something else ?

Thanks for your help
 

XbNnX_507

Active Member
Licensed User
Longtime User
B4X:
LoadBitmap( Dir, Path )
may take some time, it depends of file size, image quality and android specific hardware performance etc...
be aware it can cause OutOfMemory exception.
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
B4X:
LoadBitmap( Dir, Path )
may take some time, it depends of file size, image quality and android specific hardware performance etc...
Yes sure, I know that all this depends on hardware and file size.
But I was thinking at a way to "prefetch" the bitmaps in a kind of circular buffer to hide access time to the image ?
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
yep good idea.

But What I still didn't say is that I could have an "unlimited" number of images on my disk...
Basically my app would use the screen recorder library to encode a movie of the images.
This is to make a timelapse video of a serie of photos acquired by the Camera.
The App fully works but the video is a little too slow. Thus I would like to speed up the "frame rate"
The constraints of my solution are :
- screen must be on...
- imageView must be full size of the screen
- imageVew should be loaded as fast as possible

For now the bottle neck is bitmap loading...
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
Service code runs in the main Thread. This won't help much.

I recommend you reference the CollectionsExtra library and use a LinkedList as a Queue. You will be loading the Bitmaps into the Queue from another Thread using LoadBitmapSample. This will keep memory usage down and you can do this since you can programmatically get the dimensions of the ImageView. Then, in the Main Thread, you will be getting the 0th element from the Queue and loading into the ImageView. Then you remove it from the Queue. Then you call Sleep(20) for a 50 frames/sec frame rate (or you can adjust accordingly for the desired frame rate). Bitmaps removed from the Queue will have no more references to them so they will be garbage collected, keeping memory usage down. You can control the frame rate in a hardware-independent manner. And this will allow you to display an indefinite number of Bitmaps without having to have them all loaded into memory at once.

Technically, you could just use a normal List for this, but the LinkedList has some nice methods for this kind of usage.
 
Upvote 0

eps

Expert
Licensed User
Longtime User
What are you attempting to achieve?

Ideally you would load only those that you can see and possibly some more, for a page down or across... Then repeat as necessary, bump scrolling etc..
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
Service code runs in the main Thread. This won't help much.

I recommend you reference the CollectionsExtra library and use a LinkedList as a Queue. You will be loading the Bitmaps into the Queue from another Thread using LoadBitmapSample. This will keep memory usage down and you can do this since you can programmatically get the dimensions of the ImageView. Then, in the Main Thread, you will be getting the 0th element from the Queue and loading into the ImageView. Then you remove it from the Queue. Then you call Sleep(20) for a 50 frames/sec frame rate (or you can adjust accordingly for the desired frame rate). Bitmaps removed from the Queue will have no more references to them so they will be garbage collected, keeping memory usage down. You can control the frame rate in a hardware-independent manner. And this will allow you to display an indefinite number of Bitmaps without having to have them all loaded into memory at once.

Technically, you could just use a normal List for this, but the LinkedList has some nice methods for this kind of usage.
Thanks for this clear explaination.
So i will use threading lib to preload the linkedlist.

I will try and post the code if if works !
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
What are you attempting to achieve?

Ideally you would load only those that you can see and possibly some more, for a page down or across... Then repeat as necessary, bump scrolling etc..
As i said i take pictures to make a Time lapse. Then i display the pictures and I encode the video with a screenrecorder.
That's it !
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
Just thinking loud of other approaches in case it may help,

I think that with @moster67 ffmpeg library you could encode directly from the camera with the desired framerate, giving to the ffmpeg one picture (one preview converted to bitmap, no need to take snapshot) each X seconds/minutes. I don't know the ffmpeg config parameters for this, but I think it should be possible.

If this is not the case, with my OpenCV lib you can also convert preview to bitmap in real time and encode in MJPEG at the speed that you want (this is the only one directly supported in the lib). The only limitation is that this format won't be directly recognized by the default android video player, but works on any other or on a PC.
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
Just thinking loud of other approaches in case it may help,

I think that with @moster67 ffmpeg library you could encode directly from the camera with the desired framerate, giving to the ffmpeg one picture (one preview converted to bitmap, no need to take snapshot) each X seconds/minutes. I don't know the ffmpeg config parameters for this, but I think it should be possible.

If this is not the case, with my OpenCV lib you can also convert preview to bitmap in real time and encode in MJPEG at the speed that you want (this is the only one directly supported in the lib). The only limitation is that this format won't be directly recognized by the default android video player, but works on any other or on a PC.
Hi Jordi,
Thanks for your help !
My first idea was to go to ffmepg but seems quite complex and a little expensive for hobby purpose.
I will give a try to your option as i am indeed capturing previews from the camera. I will show you the results with moviemakers tonight as i am currently at the airport going to Madrid :)
The only limitation I see with your option is that I wouldn't be able to suppress bad images before encoding. But of course real time encoding is also a must (Always a matter of trade off !)
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
Ok to clarify what I am currently doing, here is a first video showing my 3D printer triggering , via the jack interface, the camera of my Android.
Picture is taken any time a layer is finished on the 3D printed object.
Then the second video is the final result after video rendering with WIndowsMovieMaker (not the same object...)



I can achieve the same result with screen recorder lib but with slower frame rate.
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
Hi All,

I have modified my code to run it with a different thread to PreLoad the images.
As promized, here is the code :

B4X:
'screen recorder
    Dim rec As ScreenRecorder
    Dim Record As Thread
    Dim LL As LinkedList

B4X:
Sub MakeMovie
    rec.GetPermission
End Sub

Sub rec_Result(Grant As Boolean)
    'here we check if user granted permission to record the screen
    If Grant = True Then
        'in this sample-app, I am using the same file-name for all recordings and therefore
        'I delete the previous video-file. Here you will need to implement your own solution
        'in order to make sure the video file-name does not already exist....
        If File.Exists(File.DirRootExternal,"mytest1.mp4") Then
            File.Delete(File.DirRootExternal,"mytest1.mp4")
        End If
        LL.Initialize
        Record.Start(Record, "PreLoad", Null)    'this will pre load the images in another thread and into LL list
       
        Dim list_files As List
        list_files.Initialize
        list_files=File.ListFiles(ExtSDCard & "/TimeLapse/")

        Do While (LL.Size < Min(20, list_files.Size)) 'allows the PreLoad thread to start and read a few images
            Sleep(0)
        Loop
   
        Try
            ImageView1.Bitmap = LL.first
            ImageView1.Visible = True
            rec.StartRecording(GetDeviceLayoutValues.Width,GetDeviceLayoutValues.Height,File.DirRootExternal,"mytest1") 'starts the screnrecording
           
            Do While LL.Size > 0                    'while there are images into the list, record them
                ImageView1.Bitmap = LL.RemoveFirst
                Log( LL.Size)
                Sleep(0)
            Loop
        Catch
            Log(LastException)
        End Try
        rec.StopRecording                        'now stop screen recording
        If Record.Running Then Record.Interrupt    'and stop the PreLoad thread if running
        ImageView1.Visible = False
    Else
        ToastMessageShow("User did not grant permission to record.", True)
    End If

End Sub

Sub PreLoad
    Log("PreLoad thread launched") 
    Dim list_files As List
    Dim i As Int = 0
    list_files.Initialize
    list_files=File.ListFiles(ExtSDCard & "/TimeLapse/")
    Do While True
        Dim img As Bitmap
        If LL.Size < 20 Then
            img = LoadBitmap(ExtSDCard & "/TimeLapse/",list_files.Get(i))
            LL.Add(img)
            i = i+1
        End If
        'Log( LL.Size)
        If Record.IsInterrupted Then Exit
        If i= list_files.Size Then Exit
    Loop
End Sub

With this solution I win 30% of speed compared to my original solution. Thank you @Roycefer and @moster67 for his excellent screen recorder
 
Last edited:
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
Here is the result with the above code.

As you can see it is still much slower than with WindowsMovieMaker... (27s versus 13s)
But pretty decent speed however !

Now I will try Jordi's OpenCV :)

 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
Why not use a "man in the middle" approach?
I was thinking of a raspi with camera doing all the hard work (timelapse picture taking and conversion to mpeg) and then accessing it by server/client...
There are already solutions based on this out there, like octaprint
 
Upvote 0
Top