1

I'm working on a video streaming app. It's a particularly case and I need to process each frame manually (from network access to decode and other treatments). At the end of all my process, for each frame, I have a byte[] containing ARGB_8888 encoded image.

For now, I draw each frame this way (assuming width = 1280 and height = 720, and data is my byte[] containing the frame, and imageView is my ImageView container)

// Step 1: reception and treatments
// After that, data contains the frame bytes;

// Step 2: bitmap creation
Bitmap toDraw = Bitmap.createBitmap(1280, 720, Bitmap.Config.ARGB_8888);
toDraw.copyPixelsFromBuffer(ByteBuffer.wrap(data));

// Step 3: draw the bitmap
imageView.post(new Runnable() {

    @Override
    public void run()
    {
        imageView.setImageBitmap(toDraw);
    }
});

All works fine, no problem with that. But I have a lot of GC and I really don't like creating a new Bitmap each time for each same-size frame! So I need to know how can I optimize my frames render? I know that I can call createBitmap only the first time then only use copyPixelsFromBuffer to fill it (even if it makes a copy and I don't like it but it's better). An intuitive solution comes to me but I don't know if it's possible or not:

What if I create and draw a Bitmap only the first time, and then I retrieve reference to pixels from imageView and modify it or directly or give my data as reference? I searched about DrawingCache but found no solution.

Otherwise, any idea to do better than this code (by better I mean memory-friendly and faster)? Question is: what is the best way to quickly update my imageView providing my already decoded byte[] data (for each frame).


EDIT: I just see that. I'll test and continue to investigate.

Community
  • 1
  • 1
N0un
  • 868
  • 8
  • 31

1 Answers1

1

you can create the bitmap only if needed, if it's null or if it's size is not ok

Bitmap mBitmap;

private void someMethod(){

    if(mBitmap == null || !isBitmapSizeOk(mBitmap)){
        if(mBitmap != null) mBitmap.recycle();

        mBitmap = Bitmap.createBitmap(1280, 720, Bitmap.Config.ARGB_8888);
        // call it only when the Bitmap instance changes
        imageView.setImageBitmap(mBitmap); 
    }

    mBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(data));

    // Step 3: draw the bitmap
    imageView.post(new Runnable() {

        @Override
        public void run(){    
            imageView.invalidate();       
        }
    });
}

you can call setImageBitmap(mBitmap) only when creating the Bitmap and avoid to call it every time, however, the ImageView needs to know that it has to redraw itself, you can do that by calling invalidate()

lelloman
  • 13,883
  • 5
  • 63
  • 85
  • Thanks for your answer but I knew that and I write it just at the bottom of my code sample > "I know that I can call createBitmap only the first time then only use copyPixelsFromBuffer" – N0un Aug 31 '16 at 12:15
  • oh i see, then i'm afraid i don't understand what's the problem – lelloman Aug 31 '16 at 12:19
  • I want to know if it is possible to avoid the call of `setImageBitmap()` for each frame and access to the currently shown bitmap's buffer to modify it. – N0un Aug 31 '16 at 12:30
  • sure, you don't need to call it every time but you still need to notify the ImageView that it has to redraw itself, please see update answer :) – lelloman Aug 31 '16 at 12:48
  • Ok thanks! A bitmap is persitent by default and only a call to `recycle()` allow us to remove it? – N0un Aug 31 '16 at 13:00
  • you don't need to call recycle(), its purpose is to release the memory occupied by the Bitmap since it's usually a lot without waiting for GC, however you must not use a bitmap after it's been recycled. bottom line is, if you don't call recycle() nothing bad will happen but it's good if you do – lelloman Aug 31 '16 at 13:03
  • Well, you answer my question I'll test it as soon as possible. Do you think there is an other way to show successive bitmap more efficiently? Call `recycle()` each time I create a Bitmap is better than let the GC doing its work? – N0un Aug 31 '16 at 13:06
  • well, if you're doing this just for fun it's ok, but if you need to implement video streaming you should not be using an image view, go with [ExoPlayer](https://github.com/google/ExoPlayer) – lelloman Aug 31 '16 at 13:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122303/discussion-between-n0un-and-lelloman). – N0un Aug 31 '16 at 13:13