From d0cf68ee376cf9416c588d00207f34c78a926223 Mon Sep 17 00:00:00 2001 From: "glaznev@webrtc.org" Date: Thu, 30 Oct 2014 18:38:26 +0000 Subject: [PATCH] Add 15 fps support for Android devices with missing 15 fps camera mode. Some latest Android devices support only 30 fps for front camera, but HW VP8 encoder performance is not enough for 720p 30 fps encoding. Add 15 fps support for these devices by allowing frame drop in Android camera wrapper. BUG= R=tkchin@webrtc.org Review URL: https://webrtc-codereview.appspot.com/24149004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7571 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../videoengine/VideoCaptureAndroid.java | 43 ++++++++++++++++++- .../VideoCaptureDeviceInfoAndroid.java | 30 +++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java index 926b350e19..801edbf911 100644 --- a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java +++ b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java @@ -11,11 +11,13 @@ package org.webrtc.videoengine; import java.io.IOException; +import java.util.List; import java.util.concurrent.Exchanger; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; +import android.hardware.Camera.Parameters; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera; import android.opengl.GLES11Ext; @@ -58,6 +60,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback { private double averageDurationMs; private long lastCaptureTimeMs; private int frameCount; + private int frameDropRatio; // Requests future capturers to send their frames to |localPreview| directly. public static void setLocalPreview(SurfaceHolder localPreview) { @@ -170,7 +173,38 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback { parameters.setVideoStabilization(true); } parameters.setPreviewSize(width, height); + + // Check if requested fps range is supported by camera, + // otherwise calculate frame drop ratio. + List supportedFpsRanges = parameters.getSupportedPreviewFpsRange(); + frameDropRatio = Integer.MAX_VALUE; + for (int i = 0; i < supportedFpsRanges.size(); i++) { + int[] range = supportedFpsRanges.get(i); + if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == min_mfps && + range[Parameters.PREVIEW_FPS_MAX_INDEX] == max_mfps) { + frameDropRatio = 1; + break; + } + if (range[Parameters.PREVIEW_FPS_MIN_INDEX] % min_mfps == 0 && + range[Parameters.PREVIEW_FPS_MAX_INDEX] % max_mfps == 0) { + int dropRatio = range[Parameters.PREVIEW_FPS_MAX_INDEX] / max_mfps; + frameDropRatio = Math.min(dropRatio, frameDropRatio); + } + } + if (frameDropRatio == Integer.MAX_VALUE) { + Log.e(TAG, "Can not find camera fps range"); + error = new RuntimeException("Can not find camera fps range"); + exchange(result, false); + return; + } + if (frameDropRatio > 1) { + Log.d(TAG, "Frame dropper is enabled. Ratio: " + frameDropRatio); + } + min_mfps *= frameDropRatio; + max_mfps *= frameDropRatio; + Log.d(TAG, "Camera preview mfps range: " + min_mfps + " - " + max_mfps); parameters.setPreviewFpsRange(min_mfps, max_mfps); + int format = ImageFormat.NV21; parameters.setPreviewFormat(format); camera.setParameters(parameters); @@ -180,7 +214,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback { } camera.setPreviewCallbackWithBuffer(this); frameCount = 0; - averageDurationMs = 1000 / max_mfps; + averageDurationMs = 1000000.0f / (max_mfps / frameDropRatio); camera.startPreview(); exchange(result, true); return; @@ -296,8 +330,13 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback { throw new RuntimeException("Unexpected camera in callback!"); } frameCount++; + // Check if frame needs to be dropped. + if ((frameDropRatio > 1) && (frameCount % frameDropRatio) > 0) { + camera.addCallbackBuffer(data); + return; + } long captureTimeMs = SystemClock.elapsedRealtime(); - if (frameCount > 1) { + if (frameCount > frameDropRatio) { double durationMs = captureTimeMs - lastCaptureTimeMs; averageDurationMs = 0.9 * averageDurationMs + 0.1 * durationMs; if ((frameCount % 30) == 0) { diff --git a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java index fe207ca3e9..4b0089b19c 100644 --- a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java +++ b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java @@ -75,6 +75,36 @@ public class VideoCaptureDeviceInfoAndroid { sizes.put(size); } + boolean is30fpsRange = false; + boolean is15fpsRange = false; + // If there is constant 30 fps mode, but no 15 fps - add 15 fps + // mode to the list of supported ranges. Frame drop will be done + // in software. + for (int[] range : supportedFpsRanges) { + if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == 30000 && + range[Parameters.PREVIEW_FPS_MAX_INDEX] == 30000) { + is30fpsRange = true; + } + if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == 15000 && + range[Parameters.PREVIEW_FPS_MAX_INDEX] == 15000) { + is15fpsRange = true; + } + } + if (is30fpsRange && !is15fpsRange) { + Log.d(TAG, "Adding 15 fps support"); + int[] newRange = new int [Parameters.PREVIEW_FPS_MAX_INDEX + 1]; + newRange[Parameters.PREVIEW_FPS_MIN_INDEX] = 15000; + newRange[Parameters.PREVIEW_FPS_MAX_INDEX] = 15000; + for (int j = 0; j < supportedFpsRanges.size(); j++ ) { + int[] range = supportedFpsRanges.get(j); + if (range[Parameters.PREVIEW_FPS_MAX_INDEX] > + newRange[Parameters.PREVIEW_FPS_MAX_INDEX]) { + supportedFpsRanges.add(j, newRange); + break; + } + } + } + JSONArray mfpsRanges = new JSONArray(); for (int[] range : supportedFpsRanges) { JSONObject mfpsRange = new JSONObject();