2013-02-19 3 views
6

Ich verwende OpenCV, um einige Live-Video-Verarbeitung zu versuchen. Da die Verarbeitung ziemlich umfangreich ist, werden die Ausgangsframes erheblich verzögert, wodurch der Live-Stream unruhig wirkt.Android Asynctask, um Live-Video-Frames zu verarbeiten

Ich möchte einige der Verarbeitung in eine AsyncTask entladen. Ich habe es ausprobiert und es macht das Video tatsächlich viel glatter. Es beginnt jedoch eine große Menge von Aufgaben auf einmal, und dann werden sie langsam mit einigen Ergebnissen zurückkehren.

Gibt es eine Möglichkeit, dies zu verlangsamen, und warten auf ein Ergebnis, entweder mithilfe von Synchronize-Anweisungen oder eine andere Methode?

Auf jedem Kamerarahmen starte ich eine dieser Aufgaben. DoImgProcessing führt die lange Verarbeitung durch und gibt ein Zeichenfolgenresultat zurück.

private class LongOperation extends AsyncTask<Mat, Void, String> { 

    @Override 
    protected String doInBackground(Mat... params) { 
     Mat inputFrame = params[0]; 
     cropToCenter(inputFrame); 
     return doImgProcessing(inputFrame); 
    }  

    @Override 
    protected void onPostExecute(String result) { 
     Log.d(TAG, "on post execute: "+result); 

    } 

    @Override 
    protected void onPreExecute() { 
     Log.d(TAG, "on pre execute"); 
    } 
} 

public Mat onCameraFrame(Mat inputFrame) { 
    inputFrame.copyTo(mRgba);//this will be used for the live stream 
    LongOperation op = new LongOperation(); 
    op.execute(inputFrame); 
    return mRgba; 
} 
+0

Ich würde einen einzelnen Thread mit einem Blockingqueue verwenden, um Frames einzufügen. – njzk2

+0

Ich habe nie eine von diesen geschrieben, ich bin glücklich, Ihre Antwort zu akzeptieren, wenn Sie ein wenig Beispielcode geben könnten – Jameo

Antwort

3

Ich würde so etwas tun:

// Example value for a timeout. 
private static final long TIMEOUT = 1000L; 

private BlockingQueue<Mat> frames = new LinkedBlockingQueue<Mat>(); 

Thread worker = new Thread() { 
    @Override 
    public void run() { 
     while (running) { 
      Mat inputFrame = frames.poll(TIMEOUT, TimeUnit.MILLISECONDS); 
      if (inputFrame == null) { 
       // timeout. Also, with a try {} catch block poll can be interrupted via Thread.interrupt() so not to wait for the timeout. 
       continue; 
      } 
      cropToCenter(inputFrame); 
      String result = doImgProcessing(inputFrame); 
     } 
    } 
}; 
worker.start(); 

public Mat onCameraFrame(Mat inputFrame) { 
    inputFrame.copyTo(mRgba);//this will be used for the live stream 
    frames.put(inputFrame); 
    return mRgba; 
} 

Der onCameraFrame den Rahmen auf der Warteschlange, die Arbeiter-Thread Umfragen aus der Warteschlange stellt.

Diese Dekorieren den Empfang und die Behandlung des Rahmens. Sie können das Wachstum der Warteschlange mit frames.size() überwachen.

Dies ist ein typisches Beispiel eines Produzenten-Konsumenten.

+0

Super Beispiel. Zwei Fragen, diese boolesche laufende Variable, sollte diese theoretisch während der gesamten Aktivität laufen? Schlagen Sie vor, dass wenn ich die Frames der Warteschlange hinzufüge, ich etwas sage, wenn (frames.size() <4) {frames.put (inputFrame);} ?? – Jameo

+1

Normalerweise müssen Sie sich für eine Stoppbedingung entscheiden. 'running = false' ist eine schnelle und einfache Art, es zu handhaben, aber es bedeutet, dass Sie den Rest der Warteschlange löschen würden (was das erwartete Verhalten sein könnte oder nicht). – njzk2

+1

Wie bei der Warteschlangengröße können Sie eine Warteschlange mit fester Kapazität verwenden (Limit im Konstruktor hinzufügen) und "offerFrame" verwenden, die versucht, das Objekt zu platzieren, und false zurückgibt, wenn kein Platz mehr verfügbar ist. Das bedeutet, dass Sie Frames löschen können, aber Sie haben etwas in der Nähe von Echtzeit-Behandlung. – njzk2

1

Wenn Sie dies für jeden Frame tun, klingt es, als ob Sie stattdessen einen Thread benötigen. Eine AsyncTask ist für, wenn Sie eine einmalige Aktivität für einen anderen Thread ausführen möchten. Hier möchten Sie es wiederholt tun. Erstellen Sie einfach einen Thread, und wenn ein Frame fertig ist, wird eine Nachricht an einen Handler gesendet, um den Post-Schritt im UI-Thread auszuführen. Es kann auf einem Semaphor oben in der Schleife warten, bis das nächste Frame bereit ist.

+0

Ich könnte sehen, wie das funktionieren könnte . Aber ist eine AsyncTask nicht wirklich nur ein Thread? – Jameo

+0

Glauben Sie, dass es von Vorteil ist, wenn das System mehr als eine Frame-Verarbeitung gleichzeitig startet? – Jameo

+0

Es läuft auf einem Thread, aber der Thread wird beendet. Wenn Sie etwas ständig machen, widerspricht das Ihrem Wunsch. Wie für mehr als 1- tatsächlich mehr als 1 async Aufgabe zu einer Zeit ist schwierig, erfordert es speziellen Code auf einigen Android-Versionen. Und es wäre nur nützlich, wenn das Betriebssystem schlau wäre, sie auf verschiedenen Kernen laufen zu lassen, was ich bezweifle. –