| 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..b0822d93f4c9b71e2bc48964222d358679a1fda0
|
| --- /dev/null
|
| +++ b/webrtc/api/android/java/src/org/webrtc/GlVideoFileRenderer.java
|
| @@ -0,0 +1,124 @@
|
| +/*
|
| + * 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) throws IOException {
|
| + yuvConverter = new SurfaceTextureHelper.YuvConverter(
|
| + sharedContext);
|
| +
|
| + this.outputFileWidth = outputFileWidth;
|
| + this.outputFileHeight = outputFileHeight;
|
| +
|
| + videoOutFile = new FileOutputStream(outputFile);
|
| + videoOutFile.write((
|
| + "YUV4MPEG2 C420 W" + outputFileWidth +
|
| + " H" + outputFileHeight + " Ip F30:1 A1:1\n").getBytes());
|
| +
|
| + 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;
|
| + 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");
|
| + }
|
| + }
|
| +}
|
| +
|
|
|