Android: Change camera fps range selection

This CL changes the logic in
CameraEnumerationAndroid.getClosestSupportedFramerateRange() to prefer
fps ranges with a low lower bound so the camera can adjust for
brightness conditions.

To test the functionality of the fps range selection, JUnit tests are
added. This required a new target in api_tests.gyp. JUnit tests are
preferable over instrumentation tests
(libjingle_peerconnection_android_unittest) because they are faster and
simpler.

R=kjellander@webrtc.org, sakal@webrtc.org

Review URL: https://codereview.webrtc.org/2013413002 .

Cr-Commit-Position: refs/heads/master@{#12964}
This commit is contained in:
Magnus Jedvert
2016-05-31 10:18:53 +02:00
parent 92379de5c6
commit b4ddb5c3d3
4 changed files with 103 additions and 2 deletions

View File

@ -0,0 +1,2 @@
magjed@webrtc.org
sakal@webrtc.org

View File

@ -0,0 +1,55 @@
/*
* 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 static org.junit.Assert.assertEquals;
import static org.webrtc.CameraEnumerationAndroid.getClosestSupportedFramerateRange;
import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
import org.webrtc.CameraEnumerationAndroid.CaptureFormat.FramerateRange;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.Arrays;
/**
* Tests for CameraEnumerationAndroid.
*/
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class CameraEnumerationTest {
@Test
public void testGetClosestSupportedFramerateRange() {
assertEquals(new FramerateRange(10000, 30000),
getClosestSupportedFramerateRange(
Arrays.asList(new FramerateRange(10000, 30000),
new FramerateRange(30000, 30000)),
30 /* requestedFps */));
assertEquals(new FramerateRange(10000, 20000),
getClosestSupportedFramerateRange(
Arrays.asList(new FramerateRange(0, 30000),
new FramerateRange(10000, 20000),
new FramerateRange(14000, 16000),
new FramerateRange(15000, 15000)),
15 /* requestedFps */));
assertEquals(new FramerateRange(10000, 20000),
getClosestSupportedFramerateRange(
Arrays.asList(new FramerateRange(15000, 15000),
new FramerateRange(10000, 20000),
new FramerateRange(10000, 30000)),
10 /* requestedFps */));
}
}

View File

@ -181,15 +181,37 @@ public class CameraEnumerationAndroid {
}
}
// Prefer a fps range with an upper bound close to |framerate|. Also prefer a fps range with a low
// lower bound, to allow the framerate to fluctuate based on lightning conditions.
public static CaptureFormat.FramerateRange getClosestSupportedFramerateRange(
List<CaptureFormat.FramerateRange> supportedFramerates, final int requestedFps) {
return Collections.min(supportedFramerates,
new ClosestComparator<CaptureFormat.FramerateRange>() {
private static final int MAX_FPS_WEIGHT = 10;
// Progressive penalty if the upper bound is further away than |MAX_FPS_DIFF_THRESHOLD|
// from requested.
private static final int MAX_FPS_DIFF_THRESHOLD = 5000;
private static final int MAX_FPS_LOW_DIFF_WEIGHT = 1;
private static final int MAX_FPS_HIGH_DIFF_WEIGHT = 3;
// Progressive penalty if the lower bound is bigger than |MIN_FPS_THRESHOLD|.
private static final int MIN_FPS_THRESHOLD = 8000;
private static final int MIN_FPS_LOW_VALUE_WEIGHT = 1;
private static final int MIN_FPS_HIGH_VALUE_WEIGHT = 4;
// Use one weight for small |value| less than |threshold|, and another weight above.
private int progressivePenalty(int value, int threshold, int lowWeight, int highWeight) {
return (value < threshold)
? value * lowWeight
: threshold * lowWeight + (value - threshold) * highWeight;
}
@Override
int diff(CaptureFormat.FramerateRange range) {
return range.min + MAX_FPS_WEIGHT * abs(requestedFps * 1000 - range.max);
final int minFpsError = progressivePenalty(range.min,
MIN_FPS_THRESHOLD, MIN_FPS_LOW_VALUE_WEIGHT, MIN_FPS_HIGH_VALUE_WEIGHT);
final int maxFpsError = progressivePenalty(Math.abs(requestedFps * 1000 - range.max),
MAX_FPS_DIFF_THRESHOLD, MAX_FPS_LOW_DIFF_WEIGHT, MAX_FPS_HIGH_DIFF_WEIGHT);
return minFpsError + maxFpsError;
}
});
}

View File

@ -353,6 +353,28 @@
'<(apk_tests_path):webrtc_nonparallel_tests_apk',
],
},
{
'target_name': 'android_junit_tests',
'type': 'none',
'dependencies': [
'<(webrtc_root)/api/api.gyp:libjingle_peerconnection_java',
'<(DEPTH)/base/base.gyp:base_java',
'<(DEPTH)/base/base.gyp:base_java_test_support',
'<(DEPTH)/base/base.gyp:base_junit_test_support',
],
'variables': {
'main_class': 'org.chromium.testing.local.JunitTestMain',
'src_paths': [
'androidjunit/',
],
'test_type': 'junit',
'wrapper_script_name': 'helper/<(_target_name)',
},
'includes': [
'../build/android/test_runner.gypi',
'../build/host_jar.gypi',
],
},
],
'conditions': [
['test_isolation_mode != "noop"',