2013-02-19 16 views
6

Używam OpenCV, aby spróbować trochę przetwarzać wideo na żywo. Ponieważ przetwarzanie jest dość ciężkie, znacznie opóźnia ramki wyjściowe, przez co strumień na żywo wygląda na wzburzony.Android Asynctask do przetwarzania klatek wideo na żywo

Chciałbym odciążyć niektóre przetwarzanie w AsyncTask. Wypróbowałem to i to sprawia, że ​​wideo jest znacznie płynniejsze. Jednak kończy się uruchamianie dużej ilości zadań na raz, a następnie powoli zaczną powracać z niektórymi wynikami.

Czy istnieje sposób na spowolnienie tego procesu i oczekiwanie na wynik za pomocą instrukcji Synchronizuj lub innej metody?

Na każdej ramie aparatu uruchamiam jedno z tych zadań. DoImgProcessing wykonuje długie przetwarzanie i zwraca wynik ciągu.

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

Używałbym pojedynczego wątku z blokującą sekwencją do wstawiania ramek. – njzk2

+0

Nigdy nie napisałem jednej z nich. Byłbym szczęśliwy, gdyby mogłem zaakceptować twoją odpowiedź, gdybyś mógł podać trochę przykładowego kodu. – Jameo

Odpowiedz

3

chciałbym zrobić coś takiego:

// 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; 
} 

onCameraFrame stawia ramkę na kolejce, sondażach pracownik wątku z kolejki.

To dekorelacja odbioru i leczenia ramki. Możesz monitorować wzrost kolejki za pomocą frames.size().

Jest to typowy przykład producent-konsument.

+0

Niesamowity przykład. Dwa pytania, po pierwsze, ta zmienna bieżąca boolean, powinna teoretycznie być uruchomiona przez całą aktywność? Czy sugerujesz, że dodając ramki do kolejki, powiem coś takiego, jeśli (frames.size() <4) {frames.put (inputFrame);} ?? – Jameo

+1

Zazwyczaj musisz zdecydować się na warunek zatrzymania. 'running = false' jest szybkim i prostym sposobem obsługi, ale oznacza to, że upuścisz resztę kolejki (która może być lub może nie być oczekiwanym zachowaniem). – njzk2

+1

Jeśli chodzi o rozmiar kolejki, możesz użyć kolejki o stałej wydajności (dodaj limit w konstruktorze) i użyj 'offer (inputFrame)', która spróbuje umieścić obiekt i zwróci wartość false, jeśli nie ma wolnego miejsca. Oznacza to, że możesz upuścić klatki, ale będziesz miał coś zbliżonego do leczenia w czasie rzeczywistym. – njzk2

1

Jeśli robisz to na każdej ramce, to brzmi jak trzeba wątku zamiast. AsyncTask służy do wykonywania jednorazowych czynności w innym wątku. Tutaj chcesz zrobić to wielokrotnie. Po prostu utwórz wątek, a gdy skończy się ramka, wyślij wiadomość do programu obsługi, aby uruchomić krok postu w wątku interfejsu użytkownika. Może czekać na semafor w górnej części pętli, aby następna ramka była gotowa.

+0

Widziałem, jak to może działać . Ale czy AsyncTask naprawdę nie jest tak naprawdę wątkiem? – Jameo

+0

Czy sądzisz, że istnieje przewaga pozwalająca systemowi na rozpoczęcie przetwarzania więcej niż jednej klatki na raz? – Jameo

+0

Działa na wątku, ale wątek wychodzi. Jeśli robisz coś w sposób ciągły, jest to sprzeczne z tym, czego chcesz. Jeśli chodzi o więcej niż 1-krotnie, uzyskanie więcej niż 1 asynchronicznego zadania na raz jest trudne, wymaga specjalnego kodu w niektórych wersjach Androida. Byłoby użyteczne tylko wtedy, gdyby system operacyjny był inteligentny, aby uruchomić je na różnych rdzeniach, w co wątpię. –

Powiązane problemy