Chromium Code Reviews| Index: webrtc/api/android/java/src/org/webrtc/GlVideoFileRenderer.java |
| diff --git a/webrtc/api/android/java/src/org/webrtc/GlVideoFileRenderer.java b/webrtc/api/android/java/src/org/webrtc/GlVideoFileRenderer.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a5084f5c07dda8ddd4e89a57402f20f427670395 |
| --- /dev/null |
| +++ b/webrtc/api/android/java/src/org/webrtc/GlVideoFileRenderer.java |
| @@ -0,0 +1,131 @@ |
| +/* |
| + * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
| + * |
| + * Use of this source code is governed by a BSD-style license |
| + * that can be found in the LICENSE file in the root of the source |
| + * tree. An additional intellectual property rights grant can be found |
| + * in the file PATENTS. All contributing project authors may |
| + * be found in the AUTHORS file in the root of the source tree. |
| + */ |
| +package org.webrtc; |
| + |
| +import android.os.Handler; |
| +import android.os.HandlerThread; |
| + |
| +import java.nio.ByteBuffer; |
| +import java.io.FileOutputStream; |
| +import java.io.IOException; |
| + |
| +/** |
| + * Can be used to saves the video frames to file. |
| + */ |
| +public class GlVideoFileRenderer implements VideoRenderer.Callbacks { |
| + private static final String TAG = "GlVideoFileRenderer"; |
| + |
| + private SurfaceTextureHelper.YuvConverter yuvConverter; |
| + |
| + private HandlerThread renderThread; |
| + |
| + private Handler renderThreadHandler; |
| + |
| + private FileOutputStream videoOutFile; |
| + private int outputFileWidth; |
| + private int outputFileHeight; |
| + |
| + public GlVideoFileRenderer( |
| + String outputFile, int outputFileWidth, int outputFileHeight, |
| + EglBase.Context sharedContext) { |
| + yuvConverter = new SurfaceTextureHelper.YuvConverter( |
| + sharedContext); |
| + |
| + this.outputFileWidth = outputFileWidth; |
| + this.outputFileHeight = outputFileHeight; |
| + try { |
| + videoOutFile = new FileOutputStream(outputFile); |
| + videoOutFile.write(( |
| + "YUV4MPEG2 C420 W" + outputFileWidth + |
| + " H" + outputFileHeight + " Ip F30:1 A1:1\n").getBytes()); |
| + } |
| + catch (IOException e) { |
| + Logging.d(TAG, "Failed to open file to print video out"); |
|
magjed_webrtc
2016/09/16 13:46:25
I guess we don't want to continue here.
|
| + } |
| + |
| + renderThread = new HandlerThread(TAG); |
| + renderThread.start(); |
| + renderThreadHandler = new Handler(renderThread.getLooper()); |
| + } |
| + |
| + @Override |
| + public void renderFrame(final VideoRenderer.I420Frame frame) { |
| + renderThreadHandler.post(new Runnable() { |
| + @Override |
| + public void run() { |
| + renderFrameOnRenderThread(frame); |
| + } |
| + }); |
| + } |
| + |
| + private void renderFrameOnRenderThread(VideoRenderer.I420Frame frame) { |
| + int oesTextureId = frame.textureId; |
|
magjed_webrtc
2016/09/16 13:46:25
We need to be able to handle ByteBuffer frames as
|
| + if (videoOutFile == null) { |
| + return; |
| + } |
| + float frameAspectRatio = (frame.rotationDegree % 180 == 0) ? |
| + (float) frame.width / frame.height |
| + : (float) frame.height / frame.width; |
| + |
| + final float[] rotatedSamplingMatrix = |
| + RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationDegree); |
| + final float[] layoutMatrix = RendererCommon.getLayoutMatrix( |
| + false, frameAspectRatio, (float) outputFileWidth / outputFileHeight); |
| + final float[] texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix); |
| + |
| + int frameSize = outputFileWidth*outputFileHeight*3/2; |
| + ByteBuffer frameBytes = ByteBuffer.allocateDirect(frameSize); |
| + |
| + yuvConverter.convert( |
| + frameBytes, outputFileWidth, outputFileHeight, outputFileWidth, |
| + oesTextureId, texMatrix); |
| + |
| + VideoRenderer.renderFrameDone(frame); |
| + |
| + try { |
| + videoOutFile.write("FRAME\n".getBytes()); |
| + |
| + int width = outputFileWidth; |
| + int height = outputFileHeight; |
| + int stride = width; |
| + byte[] data = frameBytes.array(); |
| + int offset = frameBytes.arrayOffset(); |
| + |
| + Logging.d(TAG, |
| + "arrayOffset(): " + frameBytes.arrayOffset() + |
| + " hasArray: " + frameBytes.hasArray()); |
| + // Write Y |
| + videoOutFile.write(data, offset, width*height); |
| + |
| + // Write U |
| + for (int r = height; r<height*3/2; ++r) { |
| + videoOutFile.write(data, offset + r * stride, stride / 2); |
| + } |
| + |
| + // Write V |
| + for (int r = height; r<height*3/2; ++r) { |
| + videoOutFile.write(data, offset + r * stride + stride / 2, stride / 2); |
| + } |
| + } |
| + catch (IOException e) { |
| + Logging.d(TAG, "Failed to write to file for video out"); |
| + } |
| + } |
| + |
| + public void release() { |
| + try { |
| + videoOutFile.close(); |
| + } |
| + catch (IOException e) { |
| + Logging.d(TAG, "Error closing output video file"); |
| + } |
| + } |
| +} |
| + |