Natrafiłem na ten sam problem, a rozwiązaniem, którego używam, jest ustawienie znacznika czasu za pośrednictwem EGL, podobnego do RecordFBOActivity#doFrame. W tym celu pośrednia alokacja służy do wypełnienia luki między RenderScript i OpenGL/EGL.
Zobaczmy przepływ danych jako rurociąg przetwarzający ze stopniami.
Original Pipeline
[Camera]
--> [ImageAllocation]
--> [RenderScript]
--> [MediaCodecSurfaceAllocationForEncoder]
--> [MediaCodec]
W oryginalnym rurociągu wszystkie bufory są przydziały RS.
MediaCodecSurfaceAllocation
opiera się na powierzchni zwróconej z kodera, tj. MediaCodec#getSurface()
.
nowego rurociągu
[Camera]
--> [ImageAllocation]
--> [RenderScript]
--> [IntermediateAllocation]
--> [EglWindowSurfaceForEncoder]
--> [MediaCodec]
W nowym rurociągiem istnieją dwa duże zmiany, IntermediateAllocation
i EglWindowSurfaceForEncoder
IntermediateAllocation
jest przydział SurfaceTexture oparte, podobnie jak ful ekran tekstury blitter stosowanych w CameraCaptureActivity.
EglWindowSurfaceForEncoder
otacza powierzchnię wejścia enkodera, podobny do RecordFBOActivity#startEncoder
Kluczem tutaj jest, aby ustawić własny OnFrameAvailableListener.
Kod Konfiguracja
void setup() {
mEglWindowSurfaceForEncoder= new WindowSurface(mEglCore, encoderCore.getInputSurface(), true);
mFullScreen = new FullFrameRect(
new Texture2dProgram(Texture2dProgram.ProgramType.TEXTURE_EXT));
mTextureId = mFullScreen.createTextureObject();
mSurfaceTexture = new SurfaceTexture(mTextureId);
Type renderType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript))
.setX(width)
.setY(height)
.create();
mIntermediateAllocation = Allocation.createTyped(
renderScript,
renderType,
Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT);
mIntermediateAllocation .setSurface(surface);
mAllocationFromCamera = ...
}
OnNewCameraImage
mIntermediateAllocation.copyFrom(mAllocationFromCamera);
OnFrameAvailableListener
mSurfaceTexture.setOnFrameAvailableListener(
new SurfaceTexture.OnFrameAvailableListener() {
public void onFrameAvailableListener(SurfaceTexture) {
//latch the image data from camera
mSurfaceTexture.updateTexImage();
// Draw the frame.
mSurfaceTexture.getTransformMatrix(mSTMatrix);
mFullScreen.drawFrame(mTextureId, mSTMatrix);
// latch frame to encoder input
mEglWindowSurfaceForEncoder.setPresentationTimes(timestampNanos);
mEglWindowSurfaceForEncoder.swapBuffers();
}
}
}
Powyższy kod musi działać w kontekście EGL (tj. W wątku renderowania OpenGl).