7

Czy w Jelly Bean możliwe jest utworzenie alokacji Rendercript z SurfaceTexture wypełnionej przez podgląd kamery? Buduję swoją aplikację z drzewa źródłowego Androida, więc dobrze się czuję używając interfejsów @hide API, takich jak Allocation.setSurfaceTexture(). Jednak chciałbym uniknąć używania wycofanych interfejsów API grafiki RS. Podobne pytanie: here nie uzyskało pełnej odpowiedzi i nie było specyficzne dla JB.Używanie Surface Texture wypełnionego przez podgląd kamery jako wejście Rendercript Allocation in Jelly Bean

mam następujące problemy podczas próby poniższy kod:

  • Dane wsiada do Renderscript jest zawsze zero
  • Dla onFrameAvailable zwrotna aby wielokrotnie wzywał, muszę updateTexImage() od kiedy zadzwoń do Allocation.ioReceive(), po raz pierwszy nie jest ona wywoływana, aw kodzie logcat jest "nieprawidłowa prezentacja EGL". Jednak myślałem, że ioReceive() jest drogą do zrobienia - to wewnętrznie również updateTexImage().
  • Obsługiwane typy przydziału obejmują RGBA8888, ale nie NV21 (który jest formatem podglądu kamery), w jaki sposób kod RS będzie w stanie adresować dane sformatowane w ten sposób?

(Wiem, że urządzenie, z którym pracuję, obsługuje żądaną rozdzielczość VGA).

public class SampleRSCPCActivity extends Activity implements SurfaceTexture.OnFrameAvailableListener { 
final static int DO_KERNEL = 0; 
private static final String TAG="SAMPLERSCP"; 
private static Camera mCamera; 
private Camera.Parameters mParams; 
private int mFrameWidth, mFrameHeight; 
private static SurfaceTexture mST; 
private RenderScript mRS; 
private Allocation mInAllocation; 
private Allocation mOutAllocation; 
private ScriptC_mono mScript; 

public void onCreate(Bundle savedInstanceState) { 

    super.onCreate(savedInstanceState); 

    Log.i(TAG, "onCreate()"); 
    createGUI(); 
    createCamera(); 
    createRSEnvironment(); 
} 

public void onPause() { 
    Log.i(TAG, "onPause"); 
    mCamera.stopPreview(); 
    mCamera.release(); 
    mCamera = null; 
    super.onPause(); 
} 

private void createCamera() { 
    mCamera = Camera.open(); 
    mParams = mCamera.getParameters(); 

    mFrameWidth = 640; 
    mFrameHeight = 480; 
    mParams.setPreviewSize(mFrameWidth, mFrameHeight); 
    mParams.setPreviewFormat(ImageFormat.NV21); 

    mCamera.setParameters(mParams); 
} 

private void createRSEnvironment() { 
    mRS = RenderScript.create(this); 
    mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono); 

    Type.Builder b = new Type.Builder(mRS, Element.U8(mRS)); 

    int usage = Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT; 
    mInAllocation = Allocation.createTyped(mRS, b.setX(mFrameWidth).setY(mFrameHeight).create(), usage); 
    mOutAllocation = Allocation.createTyped(mRS, b.setX(mFrameWidth).setY(mFrameHeight).create()); 

    Log.i(TAG, "Getting SurfaceTexture from input Allocation"); 
    mST = mInAllocation.getSurfaceTexture(); 

    mST.setOnFrameAvailableListener(this); 

    try { 
     Log.i(TAG, "Setting SurfaceTexture for camera preview"); 
     mCamera.setPreviewTexture(mST); 

     Log.i(TAG, "Starting preview"); 
     mCamera.startPreview(); 
     } catch (IOException e) { 
     Log.e(TAG, "Oops, something got wrong with setting the camera preview texture"); 
    } 
} 

private void createGUI() { 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
      WindowManager.LayoutParams.FLAG_FULLSCREEN); 

    setContentView(R.layout.main); 
} 

private Handler handler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     if (msg.what == DO_KERNEL) 
      Log.i(TAG, "Calling RS kernel"); 
      mST.updateTexImage(); 
      // mInAllocation.ioReceive(); 
      mScript.forEach_root(mInAllocation, mOutAllocation); 

      Log.i(TAG, "Finishing RS"); 
      mRS.finish(); 
      Log.i(TAG, "Ok"); 
    } 
}; 

public void onFrameAvailable(SurfaceTexture st) { 
    Log.i(TAG, "onFrameAvailable callback"); 
    handler.sendEmptyMessage(DO_KERNEL); 
} 

}

Kod RS jest dość prosta, po prostu staramy się wykryć niezerowym dane:

void root(const uchar *v_in, uchar *v_out, uint32_t x, uint32_t y) { 

if (*v_in != 0) 
    rsDebug("input data non null !", *v_in); 
*v_out = (x/640) * 255; 

}

Odpowiedz

6

following-up na moje własne pytanie:

Okazuje się, że odczyt buforów NV21 z obiektu SurfaceTexture wypełnionego przez aparat nie jest możliwy. Musiałem zmodyfikować kod źródłowy Androida, aby eksperymentować z tym (dla ekspertów: uzyskać obecny bufor SurfaceTexture, a następnie zablokować go, aby uzyskać prawdziwy wskaźnik bufora - zrobiłem to w RS rsdAllocationIoReceive()). Byłoby wspaniale, aby uniknąć wykonywania kopii bufora z kamery do RS.

Najnowsza wersja JB (MR1) ma aplikację testową o nazwie LivePreview, która wykonuje przetwarzanie RS w podglądzie kamery. Jednak używa on alokowanych pod kątem podglądu buforów wywołań zwrotnych, które następnie są skopiowane do alokacji wejściowej. Ciekawie wykorzystuje nową klasę ScriptIntrinsicRgbToYuv do konwersji kolorów. Większość konwersji jest kodowana ręcznie przez zespół Neon, więc prawdopodobnie dość szybko.

Może nawet być tak, że Nexus 10 (który ma sterownik RS oparty na Mali) robi to na GPU, chciałbym dostać się w swoje ręce na to urządzenie do zabawy. (Donatorzy witają ;-)!)

Powiązane problemy