asanovrus
asanovrus

Reputation: 1

how to move image processing to non-main thread

My app takes every frame from camera preview in yuv format and compresses to jpeg. it works on API8 but on Android >4 it says that too much work is done on main thread and frames skipped. everything other works but image processing is treated as too expensive. For me its more important then if it freezes UI. can i escalate priority or smth to stop frames skipping? I tried to move processing on other thread but how send yuv images from camera to other thread for processing. i sent byte array with bundle but it eat memory and worked only for a few seconds here's my code:

   public void surfaceCreated(SurfaceHolder holder){
    try{
        mCamera.setPreviewDisplay(holder);
        mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                                       @TargetApi(Build.VERSION_CODES.FROYO)
                                       @Override
                                       public void onPreviewFrame(byte[] data, Camera camera) {
                                           if (serverActivity.IPAddress != null) {
                                               Camera.Parameters parameters = camera.getParameters();
                                               int imageFormat = parameters.getPreviewFormat();
                                               if (imageFormat == ImageFormat.NV21) {
                                                   Rect rect = new Rect(0, 0, width, height);
                                                   //YuvImage appeared only in API8 - Froyo
                                                   YuvImage img = new YuvImage(data, ImageFormat.NV21, width, height, null);

                                                   bytearray = new ByteArrayOutputStream(20000);
                                                   try {
                                                       img.compressToJpeg(rect, 30, bytearray);
                                                       dataimage = bytearray.toByteArray();

                                                       serverActivity.send2thread(dataimage);
                                                    } catch (Exception e) {
                                                       e.printStackTrace();
                                                   }
                                               }
                                           }
                                       }
                                   }
        );
        mCamera.startPreview();
    } catch(IOException e){
        Toast.makeText(getContext(),"error setting camera preview: "+e.getMessage(),Toast.LENGTH_LONG).show();
    }
}

onPreviewFrame runs about 15 times per second and if i send data[] to other thread through bundle i get serious memory leaks. i have blur understanding of memory handling when working with threads.

Upvotes: 0

Views: 531

Answers (2)

Kevin
Kevin

Reputation: 1628

You have it right that it should be on a separate thread, but there may be a couple of things you could optimize.

  1. Make sure you only process one image at a time. Ie, don't process every image you get, only process once the previous task has ended. (I think this might be the issue, since the blocking of the UI thread would prevent you from processing concurrently and seeing the impact on mem and cpu)
  2. Recycle any bitmaps you no longer need.
  3. Are you sending an actual android.os.Bundle to the thread instead of byte[], or was that just phrasing? Either way, I'd expect raw byte[] to be faster.
  4. Depending on what processing you are doing on your image, it might be worth while to downscale it if quality isn't super important.

Upvotes: 0

Laurent Russier
Laurent Russier

Reputation: 658

You could do it with an AsynkTask http://developer.android.com/reference/android/os/AsyncTask.html

Upvotes: 1

Related Questions