Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2340)

Unified Diff: webrtc/api/android/java/src/org/webrtc/FileVideoCapturer.java

Issue 2273573003: Support for video file instead of camera and output video out to file (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added file to start automated loopback run Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/api/android/java/src/org/webrtc/FileVideoCapturer.java
diff --git a/webrtc/api/android/java/src/org/webrtc/FileVideoCapturer.java b/webrtc/api/android/java/src/org/webrtc/FileVideoCapturer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9953960c83d73049b7e30b14728171e145437ccf
--- /dev/null
+++ b/webrtc/api/android/java/src/org/webrtc/FileVideoCapturer.java
@@ -0,0 +1,280 @@
+/*
+ * 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.content.Context;
+
+import java.util.List;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+
+interface VideoReader {
+ int getFrameWidth();
+ int getFrameHeight();
+ byte[] getNextFrame();
+ void close();
+}
+
+class VideoReaderYuv implements VideoReader {
magjed_webrtc 2016/08/31 13:08:03 Make this a private class in FileVideoCapturer ins
mandermo 2016/09/16 12:32:30 Done.
+ private final static String TAG = "VideoReaderYuv";
+ private int frameWidth;
+ private int frameHeight;
+ private int frameSize;
+ private RandomAccessFile mediaFileStream;
+
+ public int getFrameWidth() {
+ return frameWidth;
+ }
magjed_webrtc 2016/08/31 13:08:03 You should have an empty line between functions.
mandermo 2016/09/16 12:32:29 Done. Does it apply to interfaces?
magjed_webrtc 2016/09/16 13:46:25 No.
+ public int getFrameHeight() {
+ return frameHeight;
+ }
+
+ VideoReaderYuv(File file, int width, int height) throws IOException {
+ mediaFileStream = new RandomAccessFile(file, "r");
+ this.frameWidth = width;
+ this.frameHeight = height;
+ this.frameSize = width*height*3/2;
magjed_webrtc 2016/08/31 13:08:03 You need to insert spaces here.
mandermo 2016/09/16 12:32:30 Done.
+ }
+ public byte[] getNextFrame() {
+ byte[] frame = new byte[frameSize];
+ try {
+ if (mediaFileStream.length() - mediaFileStream.getFilePointer() < frameSize) {
+ mediaFileStream.seek(0);
+ }
+ mediaFileStream.readFully(frame);
+
+ return frame;
+ }
+ catch (IOException e) {
+ Logging.d(TAG, "Problem reading file");
+ return null;
+ }
+ }
+ public void close() {
+ try {
+ mediaFileStream.close();
+ }
+ catch (IOException e) {
+ Logging.d(TAG, "Problem closing file");
+ }
+ }
+}
+
+class VideoReaderY4M implements VideoReader {
magjed_webrtc 2016/08/31 13:08:03 Is this class unused?
mandermo 2016/09/16 12:32:30 Used earlier, removed now.
+ private final static String TAG = "VideoReaderY4M";
+ private int frameWidth;
+ private int frameHeight;
+ private int frameSize;
+ // First char after header
+ private int videoStart;
+ final String Y4M_FRAME_DELIMETER = "FRAME";
+ private RandomAccessFile mediaFileStream;
+
+ public int getFrameWidth() {
+ return frameWidth;
+ }
+ public int getFrameHeight() {
+ return frameHeight;
+ }
+
+ VideoReaderY4M(File file) throws IOException {
+ mediaFileStream = new RandomAccessFile(file, "r");
+ byte[] startData = new byte[1000];
+ mediaFileStream.read(startData);
+
+ String headerAndMore = new String(startData);
+ videoStart = headerAndMore.indexOf(Y4M_FRAME_DELIMETER);
+ if (videoStart == -1) {
+ //throw new RuntimeException("Error reading file");
+ return;
+ }
+ String header = headerAndMore.substring(0, videoStart);
+ mediaFileStream.seek(videoStart);
+ String[] headerTokens = header.split("[\n ]");
+ Logging.d(TAG, "header: " + header + ", headerTokens" + headerTokens);
+ int w = 0;
+ int h = 0;
+ for (String tok : headerTokens) {
+ char c = tok.charAt(0);
+ switch (c) {
+ case 'W':
+ w = Integer.parseInt(tok.substring(1));
+ break;
+ case 'H':
+ h = Integer.parseInt(tok.substring(1));
+ break;
+ }
+ }
+ frameWidth = w;
+ frameHeight = h;
+ frameSize = w*h*3/2;
+ Logging.d(TAG, "frame dim: (" + w + ", " + h + ") frameSize: " + frameSize);
+ }
+ public byte[] getNextFrame() {
+ byte[] frame = new byte[frameSize];
+ try {
+ if (mediaFileStream.skipBytes(Y4M_FRAME_DELIMETER.length()+1) <
+ Y4M_FRAME_DELIMETER.length()+1)
+ {
+ // We reach end of file, loop
+ mediaFileStream.seek(videoStart + Y4M_FRAME_DELIMETER.length()+1);
+ }
+ mediaFileStream.readFully(frame);
+ return frame;
+ }
+ catch (IOException e) {
+ return null;
+ }
+ }
+ public void close() {
+ try {
+ mediaFileStream.close();
+ }
+ catch (IOException e) {
+ Logging.d(TAG, "Problem closing file");
+ }
+ }
+}
+public class FileVideoCapturer implements CameraVideoCapturer {
magjed_webrtc 2016/08/31 13:08:03 Implement VideoCapturer instead of CameraVideoCapt
mandermo 2016/09/16 12:32:30 PeerConnectionClient uses switchCamera(), which is
magjed_webrtc 2016/09/16 13:46:25 We talked about it offline, but I think the right
mandermo 2016/09/23 15:12:03 Done.
+ private final static String TAG = "FileVideoCapturer";
+
+ private VideoReader videoReader;
+
+ private CameraVideoCapturer physicalCameraCapturer;
magjed_webrtc 2016/08/31 13:08:03 This is strange, why does the File capturer need a
mandermo 2016/09/16 12:32:30 Refactored with a timer thread controlling when to
+
+ private int getFrameWidth() {
+ return videoReader.getFrameWidth();
+ }
+
+ private int getFrameHeight() {
+ return videoReader.getFrameHeight();
+ }
+
+ class CapturerObserverHijacker implements CapturerObserver {
+ private CapturerObserver sink;
+
+ CapturerObserverHijacker(CapturerObserver sink) {
+ this.sink = sink;
+ }
+
+ @Override
+ public void onCapturerStarted(boolean success) {
+ sink.onCapturerStarted(success);
+ }
+
+ @Override
+ public void onCapturerStopped() {
+ sink.onCapturerStopped();
+ }
+
+ @Override
+ public void onByteBufferFrameCaptured(byte[] data, int width, int height, int rotation,
+ long timeStamp) {
+ // Hijack and send our frame instead
+ byte[] frameData = getNextFrame();
+ sink.onByteBufferFrameCaptured(frameData, getFrameWidth(), getFrameHeight(), 0, timeStamp);
+ }
+
+ @Override
+ public void onTextureFrameCaptured(
+ int width, int height, int oesTextureId, float[] transformMatrix, int rotation,
+ long timestamp)
+ {
+ sink.onTextureFrameCaptured(
+ width, height, oesTextureId, transformMatrix, rotation, timestamp);
+ }
+
+ @Override
+ public void onOutputFormatRequest(int width, int height, int framerate) {
+ sink.onOutputFormatRequest(width, height, framerate);
+ }
+ }
+
+ public FileVideoCapturer(File inputFile, int fileVideoWidth, int fileVideoHeight,
+ CameraVideoCapturer physicalCameraCapturer) throws IOException {
+ this.physicalCameraCapturer = physicalCameraCapturer;
+ openMediaFile(inputFile, fileVideoWidth, fileVideoHeight);
+ }
+
+ public static FileVideoCapturer create(File inputFile, int fileVideoWidth,
+ int fileVideoHeight, CameraVideoCapturer physicalCameraCapturer) {
+ try {
+ return new FileVideoCapturer(
+ inputFile, fileVideoWidth, fileVideoHeight, physicalCameraCapturer);
+ } catch (IOException e) {
+ Logging.e(TAG, "Error opening input file.", e);
+ return null;
+ }
+ }
+
+ @Override
+ public List<CameraEnumerationAndroid.CaptureFormat> getSupportedFormats() {
+ return physicalCameraCapturer.getSupportedFormats();
+ }
+
+ @Override
+ public void initialize(SurfaceTextureHelper surfaceTextureHelper, Context applicationContext,
+ CapturerObserver capturerObserver) {
+ CapturerObserverHijacker hijacker = new CapturerObserverHijacker(capturerObserver);
+ // Decorate with own frameObserver and call parent
+ // The decorated frame observer throws away the frame it got and takes from file
+ physicalCameraCapturer.initialize(surfaceTextureHelper, applicationContext, hijacker);
+ }
+
+ @Override
+ public void startCapture(
+ int width, int height, int framerate) {
+ physicalCameraCapturer.startCapture(width, height, framerate);
+ }
+
+ @Override
+ public void stopCapture() throws InterruptedException {
+ physicalCameraCapturer.stopCapture();
+ }
+
+ @Override
+ public void onOutputFormatRequest(int width, int height, int framerate) {
+ physicalCameraCapturer.onOutputFormatRequest(width, height, framerate);
+ }
+
+ @Override
+ public void changeCaptureFormat(int width, int height, int framerate) {
+ physicalCameraCapturer.changeCaptureFormat(width, height, framerate);
+ }
+
+ @Override
+ public void dispose() {
+ physicalCameraCapturer.dispose();
+ videoReader.close();
+ }
+
+ @Override
+ public void switchCamera(CameraSwitchHandler switchEventsHandler) {
+ physicalCameraCapturer.switchCamera(switchEventsHandler);
+ }
+
+ private void openMediaFile(File file, int fileVideoWidth, int fileVideoHeight)
+ throws IOException
+ {
+ try {
+ videoReader = new VideoReaderYuv(file, fileVideoWidth, fileVideoHeight);
+ }
+ catch (IOException e) {
+ Logging.d(TAG, "Could not open video file: " + file);
+ }
+ }
+
+ private byte[] getNextFrame() {
+ return videoReader.getNextFrame();
+ }
+}
+

Powered by Google App Engine
This is Rietveld 408576698