3

I need to increase fps rate in my app. Now i have between 6 - 10 FPS which is very low imo because i have Nexus4. So i decided to switch from setPreviewCallback to setPreviewCallbackWithBuffer but i do not see ANY difference in framerate. In log i can see that addressess of buffers are changing circular but still i have only 6 - 10 fps (sometimes 12 but rarely)... Could you try to give me some advices? BTW. I have Android 4.4 and i tried OpenCV but there result is almost the same... My code is:

public class XPreview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {

        private SurfaceHolder mHolder;
        private Camera mCamera;
        long mTimer = 0;

        public XPreview(Context context, Camera camera) {
            super(context);
            mCamera = camera;

            mHolder = getHolder();
            mHolder.addCallback(this);
        }

        public void surfaceCreated(SurfaceHolder holder) {

        }

        public void surfaceDestroyed(SurfaceHolder holder) {

        }

        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            if (mHolder.getSurface() == null){
              // preview surface does not exist
              return;
            }

            // stop preview before making changes
            try {
                mCamera.stopPreview();
            } catch (Exception e){
              // ignore: tried to stop a non-existent preview
            }

            try {
                int formatt     = mCamera.getParameters().getPreviewFormat();
                int bytesPerPx  = ImageFormat.getBitsPerPixel( formatt );
                int width       = mCamera.getParameters().getPreviewSize().width;
                int height      = mCamera.getParameters().getPreviewSize().height;
                int size        = (int)( ( width * height * bytesPerPx ) / 8.0);

                Parameters params = mCamera.getParameters();
                mCamera.setParameters(params);

                Log.d(TAG, "Data: " + formatt + " " + bytesPerPx + " " + width + "x" + height + " " + size );

                mCamera.setPreviewDisplay(mHolder);
                mCamera.setPreviewCallbackWithBuffer(this);
                mCamera.addCallbackBuffer( new byte[size] );
                mCamera.addCallbackBuffer( new byte[size] );
                mCamera.addCallbackBuffer( new byte[size] );
                mCamera.addCallbackBuffer( new byte[size] );
                mCamera.addCallbackBuffer( new byte[size] );
                mCamera.startPreview();

            } catch (Exception e){
                Log.d(TAG, "Error starting camera preview: " + e.getMessage());
            }
        }


        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            long time = System.currentTimeMillis();
            Log.d( TAG, "Time between frames: " + ( time - mTimer ) + "ms, FPS: " + ( 1000.0 / (time - mTimer )) + ", data " + data );
            mTimer = time;
            camera.addCallbackBuffer(data);
        }
    }

Activity:

public class RTP extends Activity {

      private Camera mCamera;
        private XPreview mPreview; 

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            mCamera = Camera.open();

            mPreview = new XPreview(this, mCamera);
            FrameLayout preview = (FrameLayout) findViewById( R.id.frameLayout1 );
            preview.addView(mPreview); 
        } 


        @Override
        public void onPause(){
            super.onPause();
            if( mCamera != null ){
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        }
}

Edit:

Parameters params = mCamera.getParameters();
params.setRecordingHint(true);
mCamera.setParameters(params);

This decreased delay between frames to about ~30ms with version with buffers and decresed delay to about 60 with version without buffer. Anyway i'd be glad if someone could give me some more advices.

A bit deeper tests shows that now i have between 24 and 31 fps using version with buffering and two buffers and between 15 and 22 using default version.

Michal W
  • 793
  • 8
  • 24
  • So, you are OK at 24+ fps now? – Alex Cohn Nov 27 '13 at 23:59
  • You know, the more the better ;) Moreover trick with with redording hint has disadvantage in image quality. I think it does but maybe i am wrong? Even with this trick GC is called very often and he shouldn't i belive because i use preview with buffer. I'm not sure if this is it works or maybe i'm doing something wrong. – Michal W Nov 28 '13 at 11:55
  • 1
    One easy improvement could be to decouple `onPreveiwFrame()` from the main thread, see http://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes/19154438#19154438 – Alex Cohn Nov 29 '13 at 05:19
  • 1
    You should use analyze memory usage if you see more GC than expected: http://developer.android.com/tools/debugging/debugging-memory.html – Alex Cohn Nov 29 '13 at 05:25
  • Well... I have reset my Nexus4 to factory configuration, download ndk version 9b, switched to opencv 2.4.7 and now using opencv camera preview in Java version i have about 20fps instead of 8 so it's colossal difference! I believe that reset helped here coz i didn't noticed difference when switched to 2.4.7 and ndk version has nothing to do here, right? But i'm not sure... Oh, and i also switched target version for opencv library. I'm still fighting to achive native camera... – Michal W Nov 29 '13 at 20:39
  • 1
    You're right, NDK version cannot change the frame rate, while system reset and switch to OpenCV definitely can. – Alex Cohn Dec 01 '13 at 20:08
  • Really nice solution! thanks! I will suggest you to post your own solution as an answer... it's really good! – Sonhja Jul 22 '15 at 08:40

0 Answers0