Index: webrtc/sdk/android/api/org/webrtc/VideoFileRenderer.java |
diff --git a/webrtc/sdk/android/api/org/webrtc/VideoFileRenderer.java b/webrtc/sdk/android/api/org/webrtc/VideoFileRenderer.java |
index f4ffbcace8b6b7c7f90b7fc8f38d47505088657a..02a4a3fd0f37488434935c966d18b1b2f7158628 100644 |
--- a/webrtc/sdk/android/api/org/webrtc/VideoFileRenderer.java |
+++ b/webrtc/sdk/android/api/org/webrtc/VideoFileRenderer.java |
@@ -16,6 +16,7 @@ import java.io.FileOutputStream; |
import java.io.IOException; |
import java.nio.ByteBuffer; |
import java.util.concurrent.CountDownLatch; |
+import java.util.ArrayList; |
/** |
* Can be used to save the video frames to file. |
@@ -27,12 +28,14 @@ public class VideoFileRenderer implements VideoRenderer.Callbacks { |
private final Object handlerLock = new Object(); |
private final Handler renderThreadHandler; |
private final FileOutputStream videoOutFile; |
+ private final String outputFileName; |
private final int outputFileWidth; |
private final int outputFileHeight; |
private final int outputFrameSize; |
private final ByteBuffer outputFrameBuffer; |
private EglBase eglBase; |
private YuvConverter yuvConverter; |
+ private ArrayList<ByteBuffer> rawFrames = new ArrayList<>(); |
public VideoFileRenderer(String outputFile, int outputFileWidth, int outputFileHeight, |
final EglBase.Context sharedContext) throws IOException { |
@@ -40,6 +43,7 @@ public class VideoFileRenderer implements VideoRenderer.Callbacks { |
throw new IllegalArgumentException("Does not support uneven width or height"); |
} |
+ this.outputFileName = outputFile; |
this.outputFileWidth = outputFileWidth; |
this.outputFileHeight = outputFileHeight; |
@@ -86,7 +90,7 @@ public class VideoFileRenderer implements VideoRenderer.Callbacks { |
final float[] texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix); |
try { |
- videoOutFile.write("FRAME\n".getBytes()); |
+ ByteBuffer buffer = nativeCreateNativeByteBuffer(outputFrameSize); |
if (!frame.yuvFrame) { |
yuvConverter.convert(outputFrameBuffer, outputFileWidth, outputFileHeight, outputFileWidth, |
frame.textureId, texMatrix); |
@@ -96,27 +100,26 @@ public class VideoFileRenderer implements VideoRenderer.Callbacks { |
int offset = outputFrameBuffer.arrayOffset(); |
// Write Y |
- videoOutFile.write(data, offset, outputFileWidth * outputFileHeight); |
+ buffer.put(data, offset, outputFileWidth * outputFileHeight); |
// Write U |
for (int r = outputFileHeight; r < outputFileHeight * 3 / 2; ++r) { |
- videoOutFile.write(data, offset + r * stride, stride / 2); |
+ buffer.put(data, offset + r * stride, stride / 2); |
} |
// Write V |
for (int r = outputFileHeight; r < outputFileHeight * 3 / 2; ++r) { |
- videoOutFile.write(data, offset + r * stride + stride / 2, stride / 2); |
+ buffer.put(data, offset + r * stride + stride / 2, stride / 2); |
} |
} else { |
nativeI420Scale(frame.yuvPlanes[0], frame.yuvStrides[0], frame.yuvPlanes[1], |
frame.yuvStrides[1], frame.yuvPlanes[2], frame.yuvStrides[2], frame.width, frame.height, |
outputFrameBuffer, outputFileWidth, outputFileHeight); |
- videoOutFile.write( |
- outputFrameBuffer.array(), outputFrameBuffer.arrayOffset(), outputFrameSize); |
+ |
+ buffer.put(outputFrameBuffer.array(), outputFrameBuffer.arrayOffset(), outputFrameSize); |
} |
- } catch (IOException e) { |
- Logging.e(TAG, "Failed to write to file for video out"); |
- throw new RuntimeException(e); |
+ buffer.rewind(); |
+ rawFrames.add(buffer); |
} finally { |
VideoRenderer.renderFrameDone(frame); |
} |
@@ -130,11 +133,6 @@ public class VideoFileRenderer implements VideoRenderer.Callbacks { |
renderThreadHandler.post(new Runnable() { |
@Override |
public void run() { |
- try { |
- videoOutFile.close(); |
- } catch (IOException e) { |
- Logging.d(TAG, "Error closing output video file"); |
- } |
yuvConverter.release(); |
eglBase.release(); |
renderThread.quit(); |
@@ -142,9 +140,31 @@ public class VideoFileRenderer implements VideoRenderer.Callbacks { |
} |
}); |
ThreadUtils.awaitUninterruptibly(cleanupBarrier); |
+ try { |
+ for (ByteBuffer buffer : rawFrames) { |
+ videoOutFile.write("FRAME\n".getBytes()); |
+ |
+ byte[] data = new byte[outputFrameSize]; |
+ buffer.get(data); |
+ |
+ videoOutFile.write(data); |
+ |
+ nativeFreeNativeByteBuffer(buffer); |
+ } |
+ videoOutFile.close(); |
+ Logging.d(TAG, "Video written to disk as " + outputFileName + ". Number frames are " |
+ + rawFrames.size() + " and the dimension of the frames are " + outputFileWidth + "x" |
+ + outputFileHeight + "."); |
+ } catch (IOException e) { |
+ Logging.e(TAG, "Error writing video to disk", e); |
+ } |
} |
public static native void nativeI420Scale(ByteBuffer srcY, int strideY, ByteBuffer srcU, |
int strideU, ByteBuffer srcV, int strideV, int width, int height, ByteBuffer dst, |
int dstWidth, int dstHeight); |
+ |
+ public static native ByteBuffer nativeCreateNativeByteBuffer(int size); |
+ |
+ public static native void nativeFreeNativeByteBuffer(ByteBuffer buffer); |
} |