Revert of Android: Add FramerateRange class (patchset #2 id:60001 of https://codereview.webrtc.org/2010763003/ )

Reason for revert:
Breaks downstream Android tests:
java.lang.NoSuchFieldError: no field with name='framerate' signature='org/webrtc/CameraEnumerationAndroid$CaptureFormat$FramerateRange' in class Lorg/webrtc/CameraEnumerationAndroid$CaptureFormat;

We should have a similar test in WebRTC so we can catch such errors pre-commit.

Original issue's description:
> Android: Add FramerateRange class
>
> The Camera1 and Camera2 API use different framerate range types. Camera1
> uses int[2] and Camera2 uses Range<Integer>. Range<Integer> is
> unfortunately only available on Lollipop and later, so this CL adds a
> similar FramerateRange class in CaptureFormat.
>
> The purpose with this CL is to have a common framerate range type that can
> be reused from both Camera1 and Camera2 in helper functions such as
> CameraEnumerationAndroid.getClosestSupportedFramerateRange().
>
> BUG=webrtc:5519
> R=sakal@webrtc.org
>
> Committed: https://crrev.com/94cb67d6df1a78e7fa25e469f719c1a8809dc583
> Cr-Commit-Position: refs/heads/master@{#12942}

TBR=sakal@webrtc.org,magjed@webrtc.org
NOTRY=True
BUG=webrtc:5519

Review-Url: https://codereview.webrtc.org/2024573002
Cr-Commit-Position: refs/heads/master@{#12956}
This commit is contained in:
kjellander
2016-05-29 23:06:27 -07:00
committed by Commit bot
parent 2a3a93783e
commit bd5621f065
6 changed files with 47 additions and 101 deletions

View File

@ -286,7 +286,7 @@ public class VideoCapturerAndroidTestFixtures {
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(
"SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
final FakeCapturerObserver observer = new FakeCapturerObserver(); final FakeCapturerObserver observer = new FakeCapturerObserver();
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
// Make sure camera is started and first frame is received and then stop it. // Make sure camera is started and first frame is received and then stop it.
assertTrue(observer.WaitForCapturerToStart()); assertTrue(observer.WaitForCapturerToStart());
@ -310,7 +310,7 @@ public class VideoCapturerAndroidTestFixtures {
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(
"SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
final FakeCapturerObserver observer = new FakeCapturerObserver(); final FakeCapturerObserver observer = new FakeCapturerObserver();
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
// Make sure camera is started and then stop it. // Make sure camera is started and then stop it.
assertTrue(observer.WaitForCapturerToStart()); assertTrue(observer.WaitForCapturerToStart());
@ -359,7 +359,7 @@ public class VideoCapturerAndroidTestFixtures {
for(int i = 0; i < 3 ; ++i) { for(int i = 0; i < 3 ; ++i) {
CameraEnumerationAndroid.CaptureFormat format = formats.get(i); CameraEnumerationAndroid.CaptureFormat format = formats.get(i);
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
assertTrue(observer.WaitForCapturerToStart()); assertTrue(observer.WaitForCapturerToStart());
observer.WaitForNextCapturedFrame(); observer.WaitForNextCapturedFrame();
@ -408,7 +408,7 @@ public class VideoCapturerAndroidTestFixtures {
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(
"SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
final FakeCapturerObserver observer = new FakeCapturerObserver(); final FakeCapturerObserver observer = new FakeCapturerObserver();
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
@ -433,7 +433,7 @@ public class VideoCapturerAndroidTestFixtures {
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(
"SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
final FakeCapturerObserver observer = new FakeCapturerObserver(); final FakeCapturerObserver observer = new FakeCapturerObserver();
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
waitUntilIdle(capturer); waitUntilIdle(capturer);
@ -459,7 +459,7 @@ public class VideoCapturerAndroidTestFixtures {
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(
"SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
final FakeCapturerObserver observer = new FakeCapturerObserver(); final FakeCapturerObserver observer = new FakeCapturerObserver();
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
capturer.stopCapture(); capturer.stopCapture();
release(capturer); release(capturer);
@ -475,7 +475,7 @@ public class VideoCapturerAndroidTestFixtures {
List<CaptureFormat> formats = capturer.getSupportedFormats(); List<CaptureFormat> formats = capturer.getSupportedFormats();
CameraEnumerationAndroid.CaptureFormat format = formats.get(0); CameraEnumerationAndroid.CaptureFormat format = formats.get(0);
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
assertTrue(observer.WaitForCapturerToStart()); assertTrue(observer.WaitForCapturerToStart());
@ -485,7 +485,7 @@ public class VideoCapturerAndroidTestFixtures {
assertTrue(listOftimestamps.size() >= 1); assertTrue(listOftimestamps.size() >= 1);
format = formats.get(1); format = formats.get(1);
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
observer.WaitForCapturerToStart(); observer.WaitForCapturerToStart();
if (capturer.isCapturingToTexture()) { if (capturer.isCapturingToTexture()) {
@ -548,7 +548,7 @@ public class VideoCapturerAndroidTestFixtures {
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(
"SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
final FakeCapturerObserver observer = new FakeCapturerObserver(); final FakeCapturerObserver observer = new FakeCapturerObserver();
capturer.startCapture(format.width, format.height, format.framerate.max, capturer.startCapture(format.width, format.height, format.maxFramerate,
surfaceTextureHelper, appContext, observer); surfaceTextureHelper, appContext, observer);
// Make sure camera is started. // Make sure camera is started.
assertTrue(observer.WaitForCapturerToStart()); assertTrue(observer.WaitForCapturerToStart());

View File

@ -43,56 +43,21 @@ public class CameraEnumerationAndroid {
} }
public static class CaptureFormat { public static class CaptureFormat {
// Class to represent a framerate range. The framerate varies because of lightning conditions.
// The values are multiplied by 1000, so 1000 represents one frame per second.
public static class FramerateRange {
public int min;
public int max;
public FramerateRange(int min, int max) {
this.min = min;
this.max = max;
}
@Override
public String toString() {
return "[" + (min / 1000.0f) + ":" + (max / 1000.0f) + "]";
}
@Override
public boolean equals(Object other) {
if (!(other instanceof FramerateRange)) {
return false;
}
final FramerateRange otherFramerate = (FramerateRange) other;
return min == otherFramerate.min && max == otherFramerate.max;
}
@Override
public int hashCode() {
// Use prime close to 2^16 to avoid collisions for normal values less than 2^16.
return 1 + 65537 * min + max;
}
}
public final int width; public final int width;
public final int height; public final int height;
public final FramerateRange framerate; public final int maxFramerate;
public final int minFramerate;
// TODO(hbos): If VideoCapturer.startCapture is updated to support other image formats then this // TODO(hbos): If VideoCapturer.startCapture is updated to support other image formats then this
// needs to be updated and VideoCapturer.getSupportedFormats need to return CaptureFormats of // needs to be updated and VideoCapturer.getSupportedFormats need to return CaptureFormats of
// all imageFormats. // all imageFormats.
public final int imageFormat = ImageFormat.NV21; public final int imageFormat = ImageFormat.NV21;
public CaptureFormat(int width, int height, int minFramerate, int maxFramerate) { public CaptureFormat(int width, int height, int minFramerate,
int maxFramerate) {
this.width = width; this.width = width;
this.height = height; this.height = height;
this.framerate = new FramerateRange(minFramerate, maxFramerate); this.minFramerate = minFramerate;
} this.maxFramerate = maxFramerate;
public CaptureFormat(int width, int height, FramerateRange framerate) {
this.width = width;
this.height = height;
this.framerate = framerate;
} }
// Calculates the frame size of this capture format. // Calculates the frame size of this capture format.
@ -114,14 +79,15 @@ public class CameraEnumerationAndroid {
@Override @Override
public String toString() { public String toString() {
return width + "x" + height + "@" + framerate; return width + "x" + height + "@[" + minFramerate + ":" + maxFramerate + "]";
} }
public boolean isSameFormat(final CaptureFormat that) { public boolean isSameFormat(final CaptureFormat that) {
if (that == null) { if (that == null) {
return false; return false;
} }
return width == that.width && height == that.height && framerate.equals(that.framerate); return width == that.width && height == that.height && maxFramerate == that.maxFramerate
&& minFramerate == that.minFramerate;
} }
} }
@ -168,9 +134,7 @@ public class CameraEnumerationAndroid {
return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK); return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
} }
// Helper class for finding the closest supported format for the two functions below. It creates a // Helper class for finding the closest supported format for the two functions below.
// comparator based on the difference to some requested parameters, where the element with the
// minimum difference is the element that is closest to the requested parameters.
private static abstract class ClosestComparator<T> implements Comparator<T> { private static abstract class ClosestComparator<T> implements Comparator<T> {
// Difference between supported and requested parameter. // Difference between supported and requested parameter.
abstract int diff(T supportedParameter); abstract int diff(T supportedParameter);
@ -181,15 +145,20 @@ public class CameraEnumerationAndroid {
} }
} }
public static CaptureFormat.FramerateRange getClosestSupportedFramerateRange( public static int[] getFramerateRange(android.hardware.Camera.Parameters parameters,
List<CaptureFormat.FramerateRange> supportedFramerates, final int requestedFps) { final int framerate) {
return Collections.min(supportedFramerates, List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
new ClosestComparator<CaptureFormat.FramerateRange>() { if (listFpsRange.isEmpty()) {
private static final int MAX_FPS_WEIGHT = 10; Logging.w(TAG, "No supported preview fps range");
return new int[]{0, 0};
@Override }
int diff(CaptureFormat.FramerateRange range) { return Collections.min(listFpsRange,
return range.min + MAX_FPS_WEIGHT * abs(requestedFps * 1000 - range.max); new ClosestComparator<int[]>() {
@Override int diff(int[] range) {
final int maxFpsWeight = 10;
return range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX]
+ maxFpsWeight * abs(framerate
- range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
} }
}); });
} }

View File

@ -81,16 +81,4 @@ public class CameraEnumerator implements CameraEnumerationAndroid.Enumerator {
+ " Time spent: " + (endTimeMs - startTimeMs) + " ms."); + " Time spent: " + (endTimeMs - startTimeMs) + " ms.");
return formatList; return formatList;
} }
// Convert from int[2] to CaptureFormat.FramerateRange.
public static List<CaptureFormat.FramerateRange> convertFramerates(
List<int[]> arrayRanges) {
final List<CaptureFormat.FramerateRange> ranges = new ArrayList<CaptureFormat.FramerateRange>();
for (int[] range : arrayRanges) {
ranges.add(new CaptureFormat.FramerateRange(
range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
}
return ranges;
}
} }

View File

@ -401,24 +401,19 @@ public class VideoCapturerAndroid implements
// Find closest supported format for |width| x |height| @ |framerate|. // Find closest supported format for |width| x |height| @ |framerate|.
final android.hardware.Camera.Parameters parameters = camera.getParameters(); final android.hardware.Camera.Parameters parameters = camera.getParameters();
final List<CaptureFormat.FramerateRange> supportedFramerates = for (int[] fpsRange : parameters.getSupportedPreviewFpsRange()) {
CameraEnumerator.convertFramerates(parameters.getSupportedPreviewFpsRange()); Logging.d(TAG, "Available fps range: " +
Logging.d(TAG, "Available fps ranges: " + supportedFramerates); fpsRange[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + ":" +
fpsRange[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
final CaptureFormat.FramerateRange bestFpsRange;
if (supportedFramerates.isEmpty()) {
Logging.w(TAG, "No supported preview fps range");
bestFpsRange = new CaptureFormat.FramerateRange(0, 0);
} else {
bestFpsRange = CameraEnumerationAndroid.getClosestSupportedFramerateRange(
supportedFramerates, framerate);
} }
final int[] range = CameraEnumerationAndroid.getFramerateRange(parameters, framerate * 1000);
final android.hardware.Camera.Size previewSize = final android.hardware.Camera.Size previewSize =
CameraEnumerationAndroid.getClosestSupportedSize( CameraEnumerationAndroid.getClosestSupportedSize(
parameters.getSupportedPreviewSizes(), width, height); parameters.getSupportedPreviewSizes(), width, height);
final CaptureFormat captureFormat = new CaptureFormat( final CaptureFormat captureFormat = new CaptureFormat(
previewSize.width, previewSize.height, bestFpsRange); previewSize.width, previewSize.height,
range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
// Check if we are already using this capture format, then we don't need to do anything. // Check if we are already using this capture format, then we don't need to do anything.
if (captureFormat.isSameFormat(this.captureFormat)) { if (captureFormat.isSameFormat(this.captureFormat)) {
@ -433,8 +428,8 @@ public class VideoCapturerAndroid implements
} }
// Note: setRecordingHint(true) actually decrease frame rate on N5. // Note: setRecordingHint(true) actually decrease frame rate on N5.
// parameters.setRecordingHint(true); // parameters.setRecordingHint(true);
if (captureFormat.framerate.max > 0) { if (captureFormat.maxFramerate > 0) {
parameters.setPreviewFpsRange(captureFormat.framerate.min, captureFormat.framerate.max); parameters.setPreviewFpsRange(captureFormat.minFramerate, captureFormat.maxFramerate);
} }
parameters.setPreviewSize(captureFormat.width, captureFormat.height); parameters.setPreviewSize(captureFormat.width, captureFormat.height);

View File

@ -127,27 +127,21 @@ AndroidVideoCapturerJni::GetSupportedFormats() {
jclass j_list_class = jni->FindClass("java/util/List"); jclass j_list_class = jni->FindClass("java/util/List");
jclass j_format_class = jclass j_format_class =
jni->FindClass("org/webrtc/CameraEnumerationAndroid$CaptureFormat"); jni->FindClass("org/webrtc/CameraEnumerationAndroid$CaptureFormat");
jclass j_framerate_class = jni->FindClass(
"org/webrtc/CameraEnumerationAndroid$CaptureFormat$FramerateRange");
const int size = jni->CallIntMethod( const int size = jni->CallIntMethod(
j_list_of_formats, GetMethodID(jni, j_list_class, "size", "()I")); j_list_of_formats, GetMethodID(jni, j_list_class, "size", "()I"));
jmethodID j_get = jmethodID j_get =
GetMethodID(jni, j_list_class, "get", "(I)Ljava/lang/Object;"); GetMethodID(jni, j_list_class, "get", "(I)Ljava/lang/Object;");
jfieldID j_framerate_field = GetFieldID(
jni, j_format_class, "framerate",
"org/webrtc/CameraEnumerationAndroid$CaptureFormat$FramerateRange");
jfieldID j_width_field = GetFieldID(jni, j_format_class, "width", "I"); jfieldID j_width_field = GetFieldID(jni, j_format_class, "width", "I");
jfieldID j_height_field = GetFieldID(jni, j_format_class, "height", "I"); jfieldID j_height_field = GetFieldID(jni, j_format_class, "height", "I");
jfieldID j_max_framerate_field = jfieldID j_max_framerate_field =
GetFieldID(jni, j_framerate_class, "max", "I"); GetFieldID(jni, j_format_class, "maxFramerate", "I");
std::vector<cricket::VideoFormat> formats; std::vector<cricket::VideoFormat> formats;
formats.reserve(size); formats.reserve(size);
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
jobject j_format = jni->CallObjectMethod(j_list_of_formats, j_get, i); jobject j_format = jni->CallObjectMethod(j_list_of_formats, j_get, i);
jobject j_framerate = GetObjectField(jni, j_format, j_framerate_field);
const int frame_interval = cricket::VideoFormat::FpsToInterval( const int frame_interval = cricket::VideoFormat::FpsToInterval(
(GetIntField(jni, j_framerate, j_max_framerate_field) + 999) / 1000); (GetIntField(jni, j_format, j_max_framerate_field) + 999) / 1000);
formats.emplace_back(GetIntField(jni, j_format, j_width_field), formats.emplace_back(GetIntField(jni, j_format, j_width_field),
GetIntField(jni, j_format, j_height_field), GetIntField(jni, j_format, j_height_field),
frame_interval, cricket::FOURCC_NV21); frame_interval, cricket::FOURCC_NV21);

View File

@ -77,7 +77,7 @@ public class CaptureQualityController implements SeekBar.OnSeekBarChangeListener
long maxCaptureBandwidth = java.lang.Long.MIN_VALUE; long maxCaptureBandwidth = java.lang.Long.MIN_VALUE;
for (CaptureFormat format : formats) { for (CaptureFormat format : formats) {
maxCaptureBandwidth = Math.max(maxCaptureBandwidth, maxCaptureBandwidth = Math.max(maxCaptureBandwidth,
(long) format.width * format.height * format.framerate.max); (long) format.width * format.height * format.maxFramerate);
} }
// Fraction between 0 and 1. // Fraction between 0 and 1.
@ -107,7 +107,7 @@ public class CaptureQualityController implements SeekBar.OnSeekBarChangeListener
// Return the highest frame rate possible based on bandwidth and format. // Return the highest frame rate possible based on bandwidth and format.
private int calculateFramerate(double bandwidth, CaptureFormat format) { private int calculateFramerate(double bandwidth, CaptureFormat format) {
return (int) Math.round(Math.min(format.framerate.max, return (int) Math.round(Math.min(format.maxFramerate,
(int) Math.round(bandwidth / (format.width * format.height))) / 1000.0); (int) Math.round(bandwidth / (format.width * format.height))) / 1000.0);
} }
} }