Write to file on a dedicated thread in VideoFileRenderer.

The disk cannot always keep up to with the frames produced. To solve
this, write to disk on a dedicated thread so we don't block rendering.

Bug: b/80409365
Change-Id: If9ef3eb6948d81deebb987420599fef446b082d6
Reviewed-on: https://webrtc-review.googlesource.com/79800
Reviewed-by: Paulina Hensman <phensman@webrtc.org>
Commit-Queue: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23483}
This commit is contained in:
Sami Kalliomäki 2018-05-30 09:24:19 +02:00 committed by Commit Bot
parent d45b345700
commit aa35aeaa66

View file

@ -29,6 +29,8 @@ public class VideoFileRenderer implements VideoSink {
private final HandlerThread renderThread; private final HandlerThread renderThread;
private final Handler renderThreadHandler; private final Handler renderThreadHandler;
private final HandlerThread fileThread;
private final Handler fileThreadHandler;
private final FileOutputStream videoOutFile; private final FileOutputStream videoOutFile;
private final String outputFileName; private final String outputFileName;
private final int outputFileWidth; private final int outputFileWidth;
@ -57,10 +59,14 @@ public class VideoFileRenderer implements VideoSink {
("YUV4MPEG2 C420 W" + outputFileWidth + " H" + outputFileHeight + " Ip F30:1 A1:1\n") ("YUV4MPEG2 C420 W" + outputFileWidth + " H" + outputFileHeight + " Ip F30:1 A1:1\n")
.getBytes(Charset.forName("US-ASCII"))); .getBytes(Charset.forName("US-ASCII")));
renderThread = new HandlerThread(TAG); renderThread = new HandlerThread(TAG + "RenderThread");
renderThread.start(); renderThread.start();
renderThreadHandler = new Handler(renderThread.getLooper()); renderThreadHandler = new Handler(renderThread.getLooper());
fileThread = new HandlerThread(TAG + "FileThread");
fileThread.start();
fileThreadHandler = new Handler(fileThread.getLooper());
ThreadUtils.invokeAtFrontUninterruptibly(renderThreadHandler, new Runnable() { ThreadUtils.invokeAtFrontUninterruptibly(renderThreadHandler, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -108,19 +114,21 @@ public class VideoFileRenderer implements VideoSink {
final VideoFrame.I420Buffer i420 = scaledBuffer.toI420(); final VideoFrame.I420Buffer i420 = scaledBuffer.toI420();
scaledBuffer.release(); scaledBuffer.release();
YuvHelper.I420Rotate(i420.getDataY(), i420.getStrideY(), i420.getDataU(), i420.getStrideU(), fileThreadHandler.post(() -> {
i420.getDataV(), i420.getStrideV(), outputFrameBuffer, i420.getWidth(), i420.getHeight(), YuvHelper.I420Rotate(i420.getDataY(), i420.getStrideY(), i420.getDataU(), i420.getStrideU(),
frame.getRotation()); i420.getDataV(), i420.getStrideV(), outputFrameBuffer, i420.getWidth(), i420.getHeight(),
i420.release(); frame.getRotation());
i420.release();
try { try {
videoOutFile.write("FRAME\n".getBytes(Charset.forName("US-ASCII"))); videoOutFile.write("FRAME\n".getBytes(Charset.forName("US-ASCII")));
videoOutFile.write( videoOutFile.write(
outputFrameBuffer.array(), outputFrameBuffer.arrayOffset(), outputFrameSize); outputFrameBuffer.array(), outputFrameBuffer.arrayOffset(), outputFrameSize);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error writing video to disk", e); throw new RuntimeException("Error writing video to disk", e);
} }
frameCount++; frameCount++;
});
} }
/** /**
@ -135,14 +143,23 @@ public class VideoFileRenderer implements VideoSink {
cleanupBarrier.countDown(); cleanupBarrier.countDown();
}); });
ThreadUtils.awaitUninterruptibly(cleanupBarrier); ThreadUtils.awaitUninterruptibly(cleanupBarrier);
fileThreadHandler.post(() -> {
try {
videoOutFile.close();
Logging.d(TAG,
"Video written to disk as " + outputFileName + ". The number of frames is " + frameCount
+ " and the dimensions of the frames are " + outputFileWidth + "x"
+ outputFileHeight + ".");
} catch (IOException e) {
throw new RuntimeException("Error closing output file", e);
}
fileThread.quit();
});
try { try {
videoOutFile.close(); fileThread.join();
Logging.d(TAG, } catch (InterruptedException e) {
"Video written to disk as " + outputFileName + ". The number of frames is " + frameCount Thread.currentThread().interrupt();
+ " and the dimensions of the frames are " + outputFileWidth + "x" + outputFileHeight Logging.e(TAG, "Interrupted while waiting for the write to disk to complete.", e);
+ ".");
} catch (IOException e) {
throw new RuntimeException("Error closing output file", e);
} }
} }
} }