Basic Question: Capturing the FrameBuffer

Started by Babu, June 22, 2011, 09:02:15 AM

Previous topic - Next topic

Babu

Hi,

Is it possible to capture the FrameBuffer(i.e. a snapshot of what user sees) and save it as JPG/PNG?

Regards

EgonOlsen

Yes, you can get the rendered image by calling FrameBuffer.getOutputBuffer(); and save it using the normal ImageIO ways.

Babu

thanks, Egon. 
But I forgot to mention that I am using jpct-ae and I don't find that API in the ae version  :(.  Is there any workaround that I can use for capturing the snapshot in ae?

P.S. sorry for not posting this query in the 'ae' forum  :-[


Babu

thanks, Egon.  I will check that out and get back to you.

Nemetz

Quote from: EgonOlsen on June 22, 2011, 06:05:34 PM
Have a look here: http://www.jpct.net/forum2/index.php/topic,2088.0.html
Good, but it's to slow method, as i saw it in API description of this method.
Maybe  native methods with ndk will be much faster?

EgonOlsen


Nemetz

Quote from: EgonOlsen on June 24, 2011, 08:41:11 AM
Too slow for what?
I mean what getPixels(); method to slow, for example, for a taking snapshot in real game process, or smth like that.
In emulator it works ~ 2800 ms(

EgonOlsen

You might want to profile which operation (getPixels(), updating the int[]-array or creating the new image) is actually slow.

Consider that:

  • the emulator is slower than any current device anyway
  • getting pixels from the gl framebuffer isn't very fast and the NDK can't help there
  • maybe getting the pixels from the buffer isn't the right solution for the problem (...which is?)



Babu

hi Egon,

I tried the solution mentioned in the forum topic that you pointed me to.  I did this.
I introduced a new method called getBitmap() in my Renderer.

public Bitmap getBitmap()
{
int[] tmpPixels = mFrameBuffer.getPixels();
        for (int i = 0; i < tmpPixels.length; i++){
            int tmpInt = tmpPixels[i] + 0xff000000;
            int red = (tmpInt & 0x00ff0000)>>16;
            int blue = (tmpInt & 0x000000ff)<<16;
            tmpInt &= 0xff00ff00;
            tmpInt += red + blue;
            tmpPixels[i] = tmpInt;
        }
        Bitmap lastImage = Bitmap.createBitmap(tmpPixels,
        mFrameBufferWidth, mFrameBufferHeight, Bitmap.Config.ARGB_8888);
       
        return lastImage;
}


Then called this method from my Activity's onButtonClickListener.

mBtnDone.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v)
    {
        Bitmap bmp = mRenderer.getBitmap();
        ...............
        ................
     }
});


Then when the button is clicked... i got the following exception.  :(

06-26 12:23:39.069: ERROR/AndroidRuntime(340): FATAL EXCEPTION: main
06-26 12:23:39.069: ERROR/AndroidRuntime(340): java.lang.ClassCastException: com.threed.jpct.World
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at com.threed.jpct.GLRenderer.execute(GLRenderer.java:1721)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at com.threed.jpct.FrameBuffer.getPixels(FrameBuffer.java:449)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at com.goora.ams.model.AMSRenderer.getBitmap(FMSRenderer.java:438)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at com.goora.ams.ui.ModelMain$11.onClick(AvatarMain.java:634)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at android.view.View.performClick(View.java:2485)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at android.view.View$PerformClick.run(View.java:9080)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at android.os.Handler.handleCallback(Handler.java:587)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at android.os.Handler.dispatchMessage(Handler.java:92)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at android.os.Looper.loop(Looper.java:123)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at android.app.ActivityThread.main(ActivityThread.java:3683)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at java.lang.reflect.Method.invokeNative(Native Method)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at java.lang.reflect.Method.invoke(Method.java:507)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-26 12:23:39.069: ERROR/AndroidRuntime(340):     at dalvik.system.NativeStart.main(Native Method)


I am not sure if it has got anything to do with the communication between the UI thread (Activity) and the Renderer thread  ::).  Any idea what's going wrong?  Meanwhile I'll do more analysis in parallel.

- Thanks...

EgonOlsen

You can't call gl related stuff from inside the ui thread without asking for trouble. I'm not sure why it throws a class cast in this particular case, but its not supposed to work anyway.  Let the ui thread set a flag instead and do the actual call in the gl thread.

raft

alternatively you can use GLSurfaceView.queueEvent(..) method to run code in GL thread.

Babu

thanks, raft. That's exactly how I resolved it.   8)

Also, I needed to save the bitmap as a png file.  I didn't want to do file operations in my renderer and so needed to pass the bitmap back to UI thread (activity) and also I needed the UI-Thread to have complete knowledge on the completion of file operations. 

So I created a 'Handler' in my UI-Thread and passed it to the renderer (constructor parameter). 
Once Renderer completes the queued operation, i.e. creation of the bitmap, it will post a 'Message' back to the UI-Thread, using the 'Handler'.  The bitmap goes back to the UI-Thread as 'Message.obj'

Sorry, I wanted to share this with the community, but got sucked into pose animation issues.... and you know that  ;D