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