1

I need to keep running a thread which does image processing using the frames from the camera of an android device.

I've tried the simplest way

new Thread() {

    @Override
    public void run() {
        while (true) {
            /* Processing frames here */
        }
    }
}.start();

Buts this hogs the CPU too much and the UI starts lagging. Also, added Thread.sleep(300) after processing the frame so that the UI thread can get some CPU time but although it does help to some extent, it doesn't feel like the right way to do it.

I would like to have some ideas about a good approach to handle this.

EDIT: Using AsyncTask

private DetectionTask detectionTask;

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    /* Doing some stuff here */

    camera.addCallbackBuffer(data);

    if (detectionTask != null && detectionTask.getStatus() != AsyncTask.Status.FINISHED)
        return;

    detectionTask = new DetectionTask();
    detectionTask.execute();
}

private class DetectionTask extends AsyncTask<Void, Void, float[]> {

    @Override
    protected float[] doInBackground(Void... params) {
        /* Processing frames here */
        return result;
    }

    @Override
    protected void onPostExecute(float[] result) {
        if (result != null) {
           /* Update UI */
        }
    };
};
timemanx
  • 4,493
  • 6
  • 34
  • 43
  • Use `Service` as Maxim recommended, but also learn about `Thread#yield`. – chrylis -cautiouslyoptimistic- Sep 26 '13 at 04:23
  • while(true) is busy waiting, if you need to do some processing in background you have to use Thread.sleep method no matter where u put this code it will take CPU time whether a service or task etc. – Pulkit Sethi Sep 26 '13 at 04:24
  • @chrylis In Oracle's [documentation](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#yield%28%29) for `Thread.yield()`: "It is rarely appropriate to use this method." It's use would seem to indicate poor design, like active waiting. – Dave Sep 26 '13 at 04:38
  • Check the change of behavior in `AsyncTask`'s implementation starting from Honeycomb http://www.techrepublic.com/blog/android-app-builder/android-asynctask-behavior-changes-you-should-know/ – ecle Sep 26 '13 at 08:28
  • http://stackoverflow.com/questions/11168925/how-to-keep-a-method-running-continuously-in-background-until-the-program-ends – Antony Joslin Nov 17 '16 at 08:39

4 Answers4

1

Consider using Service instead of Thread. It's a common tool for long-running processes which must do some work time to time on another thread.

Maxim Efimov
  • 2,747
  • 1
  • 19
  • 25
  • I need to be always doing the work as long as the application is running. Since I also need to update the UI on each iteration of the loop, would using `Service` be a good fit here? – timemanx Sep 26 '13 at 04:29
  • @TimeManx I think it depends on the case of usage. Do you have only one Activity which is a host for the Thread or not. Service may be accessed from any Context, while Thread is obviously not. In general it's easier to communicate with service rather than with thread and there is nearly no cost of service usage. – Maxim Efimov Sep 26 '13 at 04:37
  • @MaximEfimov In a situation like this, using a `Service` isn't "nearly no cost". At best, all communication will go through a `Binder`, which has noticeable latency in real-time applications. With the `MediaPlayer`, I typically see 50-100ms (or more) between a native call to `notify` and the resultant `handleMessage` call in the Java `Handler`, and that only passes through the JNI layer in one direction. Personally, I don't see this as an option for him. – Dave Sep 26 '13 at 06:39
  • @Dave there is no need in binder-based communication, just return a `Service` in `Binder` sub-class method of the service and then call services' method with 0ms latency, so it's exaclty "nearly no cost" – Maxim Efimov Sep 26 '13 at 06:42
  • 1
    In that manner, your calls to the `Service` methods are going to run on the same thread and you haven't gained any benefit of parallelism. – Dave Sep 26 '13 at 06:58
1

If you know exactly when a frame is ready to be processed, you can use the Object.wait() and Object.notify() methods as a simple mechanism to signal your processor thread that a frame is ready.

Object mLock = new Object();
Thread mProcessor = new Thread() {
    @Override
    public void run() {
        while (true) {
            mLock.wait();
            // do processing
        }
    }
};

Then call mLock.notify() when a frame or batch of frames is ready.

Dave
  • 4,282
  • 2
  • 19
  • 24
  • The delivery time of a frame is half the time it takes to complete a single iteration of the loop. So, there is no point in waiting. – timemanx Sep 26 '13 at 04:43
  • Then there is likewise no point in sleeping. Your process is simply going to hog the CPU. If hogging the CPU is unacceptable, you are left with making the processing algorithm more efficient or simply processing less frames. Also, using a Service as others have suggested will increase your overhead, which is likely something you don't care to do. – Dave Sep 26 '13 at 05:20
  • Another idea... have you considered finding a way to do your processing in native code? I obviously haven't seen all your code, but dragging data through the JNI layer is a huge bottleneck in this type of application. At the very least you should be using NIO buffers to avoid that where possible. – Dave Sep 26 '13 at 06:42
  • Yes, the processing is already in native code. Like you said, the overhead when using a `Service` is noticeable. I guess I'd be better off with having a sampling rate and do the processing a fixed number of times in a second. – timemanx Sep 27 '13 at 02:01
1

Have you considered AsyncTask?
It is specially designed just to deal with heavy loads in the background.
It will do the heavy process in the background and update your UI when done.

Lazy Ninja
  • 22,342
  • 9
  • 83
  • 103
  • Yea, but I get the same result. The problem is that I'm having to execute an `AsyncTask` as soon as the previous one ends. So, I guess it's more or less the same as what I've posted in the question. – timemanx Sep 26 '13 at 04:38
  • Could you post the relevant source code? Using AsyncTask, the UI should not lag in my understanding. – Lazy Ninja Sep 26 '13 at 04:48
  • Hmmm! Your AsyncTask looks fine to me. Try using an handler like here http://ibuzzlog.blogspot.jp/2012/08/how-to-do-real-time-image-processing-in.html . But I doubt it will make some difference, but it is worth trying. – Lazy Ninja Sep 26 '13 at 05:13
0

usually I use Thread. If you are using a device with multi-core processors, the system will automatically dispatch threads to different cores. This means running UI thread and assistant thread simultaneously will be no problem. generally, I save data from Preview callback to a buffer queue in memory, which will not block UI. Then create another thread to read and process the data from the buffer. The buffer queue has to be synchronized. If your data processing takes too much time, you have two options: 1. skip some frames strategically 2. write data to cache file for post-processing. I've done this for my own app.

yushulx
  • 11,695
  • 8
  • 37
  • 64