OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 package org.appspot.apprtc; | 11 package org.appspot.apprtc; |
12 | 12 |
13 import android.widget.SeekBar; | 13 import android.widget.SeekBar; |
14 import android.widget.TextView; | 14 import android.widget.TextView; |
15 | 15 |
16 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; | 16 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; |
17 | 17 |
18 import java.util.Arrays; | 18 import java.util.Arrays; |
19 import java.util.Collections; | 19 import java.util.Collections; |
20 import java.util.Comparator; | 20 import java.util.Comparator; |
21 import java.util.List; | 21 import java.util.List; |
22 | 22 |
23 /** | 23 /** |
24 * Control capture format based on a seekbar listener. | 24 * Control capture format based on a seekbar listener. |
25 */ | 25 */ |
26 public class CaptureQualityController implements SeekBar.OnSeekBarChangeListener
{ | 26 public class CaptureQualityController implements SeekBar.OnSeekBarChangeListener
{ |
27 private final List<CaptureFormat> formats = Arrays.asList( | 27 private final List<CaptureFormat> formats = |
28 new CaptureFormat(1280, 720, 0, 30000), | 28 Arrays.asList(new CaptureFormat(1280, 720, 0, 30000), new CaptureFormat(96
0, 540, 0, 30000), |
29 new CaptureFormat(960, 540, 0, 30000), | 29 new CaptureFormat(640, 480, 0, 30000), new CaptureFormat(480, 360, 0,
30000), |
30 new CaptureFormat(640, 480, 0, 30000), | 30 new CaptureFormat(320, 240, 0, 30000), new CaptureFormat(256, 144, 0,
30000)); |
31 new CaptureFormat(480, 360, 0, 30000), | |
32 new CaptureFormat(320, 240, 0, 30000), | |
33 new CaptureFormat(256, 144, 0, 30000)); | |
34 // Prioritize framerate below this threshold and resolution above the threshol
d. | 31 // Prioritize framerate below this threshold and resolution above the threshol
d. |
35 private static final int FRAMERATE_THRESHOLD = 15; | 32 private static final int FRAMERATE_THRESHOLD = 15; |
36 private TextView captureFormatText; | 33 private TextView captureFormatText; |
37 private CallFragment.OnCallEvents callEvents; | 34 private CallFragment.OnCallEvents callEvents; |
38 private int width = 0; | 35 private int width = 0; |
39 private int height = 0; | 36 private int height = 0; |
40 private int framerate = 0; | 37 private int framerate = 0; |
41 private double targetBandwidth = 0; | 38 private double targetBandwidth = 0; |
42 | 39 |
43 public CaptureQualityController( | 40 public CaptureQualityController( |
44 TextView captureFormatText, CallFragment.OnCallEvents callEvents) { | 41 TextView captureFormatText, CallFragment.OnCallEvents callEvents) { |
45 this.captureFormatText = captureFormatText; | 42 this.captureFormatText = captureFormatText; |
46 this.callEvents = callEvents; | 43 this.callEvents = callEvents; |
47 } | 44 } |
48 | 45 |
49 private final Comparator<CaptureFormat> compareFormats = new Comparator<Captur
eFormat>() { | 46 private final Comparator<CaptureFormat> compareFormats = new Comparator<Captur
eFormat>() { |
50 @Override | 47 @Override |
51 public int compare(CaptureFormat first, CaptureFormat second) { | 48 public int compare(CaptureFormat first, CaptureFormat second) { |
52 int firstFps = calculateFramerate(targetBandwidth, first); | 49 int firstFps = calculateFramerate(targetBandwidth, first); |
53 int secondFps = calculateFramerate(targetBandwidth, second); | 50 int secondFps = calculateFramerate(targetBandwidth, second); |
54 | 51 |
55 if (firstFps >= FRAMERATE_THRESHOLD && secondFps >= FRAMERATE_THRESHOLD | 52 if (firstFps >= FRAMERATE_THRESHOLD && secondFps >= FRAMERATE_THRESHOLD |
56 || firstFps == secondFps) { | 53 || firstFps == secondFps) { |
57 // Compare resolution. | 54 // Compare resolution. |
58 return first.width * first.height - second.width * second.height; | 55 return first.width * first.height - second.width * second.height; |
59 } else { | 56 } else { |
60 // Compare fps. | 57 // Compare fps. |
61 return firstFps - secondFps; | 58 return firstFps - secondFps; |
62 } | 59 } |
63 } | 60 } |
64 }; | 61 }; |
65 | 62 |
66 @Override | 63 @Override |
67 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{ | 64 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{ |
68 if (progress == 0) { | 65 if (progress == 0) { |
69 width = 0; | 66 width = 0; |
70 height = 0; | 67 height = 0; |
71 framerate = 0; | 68 framerate = 0; |
72 captureFormatText.setText(R.string.muted); | 69 captureFormatText.setText(R.string.muted); |
73 return; | 70 return; |
74 } | 71 } |
75 | 72 |
76 // Extract max bandwidth (in millipixels / second). | 73 // Extract max bandwidth (in millipixels / second). |
77 long maxCaptureBandwidth = java.lang.Long.MIN_VALUE; | 74 long maxCaptureBandwidth = java.lang.Long.MIN_VALUE; |
78 for (CaptureFormat format : formats) { | 75 for (CaptureFormat format : formats) { |
79 maxCaptureBandwidth = Math.max(maxCaptureBandwidth, | 76 maxCaptureBandwidth = |
80 (long) format.width * format.height * format.framerate.max); | 77 Math.max(maxCaptureBandwidth, (long) format.width * format.height * fo
rmat.framerate.max); |
81 } | 78 } |
82 | 79 |
83 // Fraction between 0 and 1. | 80 // Fraction between 0 and 1. |
84 double bandwidthFraction = (double) progress / 100.0; | 81 double bandwidthFraction = (double) progress / 100.0; |
85 // Make a log-scale transformation, still between 0 and 1. | 82 // Make a log-scale transformation, still between 0 and 1. |
86 final double kExpConstant = 3.0; | 83 final double kExpConstant = 3.0; |
87 bandwidthFraction = | 84 bandwidthFraction = |
88 (Math.exp(kExpConstant * bandwidthFraction) - 1) / (Math.exp(kExpConstan
t) - 1); | 85 (Math.exp(kExpConstant * bandwidthFraction) - 1) / (Math.exp(kExpConstan
t) - 1); |
89 targetBandwidth = bandwidthFraction * maxCaptureBandwidth; | 86 targetBandwidth = bandwidthFraction * maxCaptureBandwidth; |
90 | 87 |
91 // Choose the best format given a target bandwidth. | 88 // Choose the best format given a target bandwidth. |
92 final CaptureFormat bestFormat = Collections.max(formats, compareFormats); | 89 final CaptureFormat bestFormat = Collections.max(formats, compareFormats); |
93 width = bestFormat.width; | 90 width = bestFormat.width; |
94 height = bestFormat.height; | 91 height = bestFormat.height; |
95 framerate = calculateFramerate(targetBandwidth, bestFormat); | 92 framerate = calculateFramerate(targetBandwidth, bestFormat); |
96 captureFormatText.setText(width + "x" + height + " @ " + framerate + "fps"); | 93 captureFormatText.setText(width + "x" + height + " @ " + framerate + "fps"); |
97 } | 94 } |
98 | 95 |
99 @Override | 96 @Override |
100 public void onStartTrackingTouch(SeekBar seekBar) { | 97 public void onStartTrackingTouch(SeekBar seekBar) {} |
101 } | |
102 | 98 |
103 @Override | 99 @Override |
104 public void onStopTrackingTouch(SeekBar seekBar) { | 100 public void onStopTrackingTouch(SeekBar seekBar) { |
105 callEvents.onCaptureFormatChange(width, height, framerate); | 101 callEvents.onCaptureFormatChange(width, height, framerate); |
106 } | 102 } |
107 | 103 |
108 // Return the highest frame rate possible based on bandwidth and format. | 104 // Return the highest frame rate possible based on bandwidth and format. |
109 private int calculateFramerate(double bandwidth, CaptureFormat format) { | 105 private int calculateFramerate(double bandwidth, CaptureFormat format) { |
110 return (int) Math.round(Math.min(format.framerate.max, | 106 return (int) Math.round( |
111 (int) Math.round(bandwidth / (format.width * format.height))) / 1000.0); | 107 Math.min(format.framerate.max, (int) Math.round(bandwidth / (format.widt
h * format.height))) |
| 108 / 1000.0); |
112 } | 109 } |
113 } | 110 } |
114 | |
OLD | NEW |