Skip to content

Commit 7c16d2f

Browse files
authored
Update param computation (#87)
* import sorter config * organize video types * ignore import sort for proto files * equality for video types * impl * adjust defaults * max
1 parent 7843e87 commit 7c16d2f

File tree

5 files changed

+112
-27
lines changed

5 files changed

+112
-27
lines changed

lib/src/options.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'track/options.dart';
66
import 'track/track.dart';
77
import 'types/other.dart';
88
import 'types/video_encoding.dart';
9+
import 'types/video_parameters.dart';
910

1011
/// Options used when connecting to the server.
1112
class ConnectOptions {
@@ -88,9 +89,15 @@ class VideoPublishOptions {
8889
/// Defaults to true.
8990
final bool simulcast;
9091

92+
final List<VideoParameters> videoSimulcastLayers;
93+
94+
final List<VideoParameters> screenShareSimulcastLayers;
95+
9196
const VideoPublishOptions({
9297
this.videoEncoding,
9398
this.simulcast = true,
99+
this.videoSimulcastLayers = const [],
100+
this.screenShareSimulcastLayers = const [],
94101
});
95102

96103
@override

lib/src/track/options.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class CameraCaptureOptions extends VideoCaptureOptions {
2323

2424
const CameraCaptureOptions({
2525
this.cameraPosition = CameraPosition.front,
26-
VideoParameters params = VideoParametersPresets.h720_169,
26+
VideoParameters params = VideoParametersPresets.h540_169,
2727
}) : super(params: params);
2828

2929
CameraCaptureOptions.from({required VideoCaptureOptions captureOptions})
@@ -51,7 +51,7 @@ class CameraCaptureOptions extends VideoCaptureOptions {
5151
/// Options used when creating a [LocalVideoTrack] that captures the screen.
5252
class ScreenShareCaptureOptions extends VideoCaptureOptions {
5353
const ScreenShareCaptureOptions({
54-
VideoParameters params = VideoParametersPresets.h720_169,
54+
VideoParameters params = VideoParametersPresets.screenShareH720FPS15,
5555
}) : super(params: params);
5656

5757
ScreenShareCaptureOptions.from({required VideoCaptureOptions captureOptions})
@@ -71,7 +71,7 @@ abstract class VideoCaptureOptions extends LocalTrackOptions {
7171
final VideoParameters params;
7272

7373
const VideoCaptureOptions({
74-
this.params = VideoParametersPresets.h720_169,
74+
this.params = VideoParametersPresets.h540_169,
7575
});
7676

7777
@override

lib/src/types/video_dimensions.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ class VideoDimensions {
4040
}
4141

4242
extension VideoDimensionsHelpers on VideoDimensions {
43+
// aspect ratios
44+
static const aspect169 = 16.0 / 9.0;
45+
static const aspect43 = 4.0 / 3.0;
46+
47+
double aspect() => width > height ? width / height : height / width;
48+
4349
/// Returns the larger value
4450
int max() => math.max(width, height);
4551

lib/src/types/video_parameters.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ class VideoParameters implements Comparable<VideoParameters> {
5656
}
5757

5858
extension VideoParametersPresets on VideoParameters {
59+
// 16:9 default
60+
static final List<VideoParameters> defaultSimulcast169 = [
61+
h180_169,
62+
h360_169,
63+
];
64+
65+
// 4:3 default
66+
static final List<VideoParameters> defaultSimulcast43 = [
67+
h180_43,
68+
h360_43,
69+
];
70+
5971
// all 16:9 presets
6072
static final List<VideoParameters> all169 = [
6173
h90_169,

lib/src/utils.dart

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:async';
2+
import 'dart:math' as math;
23

34
import 'package:flutter/foundation.dart';
45

@@ -34,6 +35,9 @@ typedef RetryCondition = bool Function(
3435

3536
// Collection of state-less static methods
3637
class Utils {
38+
// order of rids
39+
static final videoRids = ['q', 'h', 'f'];
40+
3741
/// Returns a [Future] that will retry [future] while it throws
3842
/// for a maximum of [tries] times with [delay] in between.
3943
/// If all the attempts throws, the future will throw a [List] of the
@@ -191,17 +195,62 @@ class Utils {
191195
required bool isScreenShare,
192196
required VideoDimensions dimensions,
193197
}) {
194-
if (isScreenShare) return VideoParametersPresets.allScreenShare;
198+
if (isScreenShare) {
199+
return VideoParametersPresets.allScreenShare;
200+
}
195201

196-
final double aspect = dimensions.width > dimensions.height
197-
? dimensions.width / dimensions.height
198-
: dimensions.height / dimensions.width;
199-
if ((aspect - 16.0 / 9.0).abs() < (aspect - 4.0 / 3.0).abs()) {
202+
final a = dimensions.aspect();
203+
if ((a - VideoDimensionsHelpers.aspect169).abs() <
204+
(a - VideoDimensionsHelpers.aspect43).abs()) {
200205
return VideoParametersPresets.all169;
201206
}
207+
202208
return VideoParametersPresets.all43;
203209
}
204210

211+
static List<VideoParameters> _computeDefaultScreenShareSimulcastParams({
212+
required VideoParameters original,
213+
}) {
214+
final layers = [
215+
rtc.RTCRtpEncoding(scaleResolutionDownBy: 2, maxFramerate: 3)
216+
];
217+
return layers.map((e) {
218+
final scale = e.scaleResolutionDownBy ?? 1;
219+
final fps = e.maxFramerate ?? 3;
220+
221+
return VideoParameters(
222+
dimensions: VideoDimensions((original.dimensions.width / scale).floor(),
223+
(original.dimensions.height / scale).floor()),
224+
encoding: VideoEncoding(
225+
maxBitrate: math.max(
226+
150 * 1000,
227+
(original.encoding.maxBitrate /
228+
(math.pow(scale, 2) *
229+
(original.encoding.maxFramerate / fps)))
230+
.floor(),
231+
),
232+
maxFramerate: fps,
233+
),
234+
);
235+
}).toList();
236+
}
237+
238+
static List<VideoParameters> _computeDefaultSimulcastParams({
239+
required bool isScreenShare,
240+
required VideoParameters original,
241+
}) {
242+
if (isScreenShare) {
243+
return _computeDefaultScreenShareSimulcastParams(original: original);
244+
}
245+
final a = original.dimensions.aspect();
246+
if ((a - VideoDimensionsHelpers.aspect169).abs() <
247+
(a - VideoDimensionsHelpers.aspect43).abs()) {
248+
return VideoParametersPresets.defaultSimulcast169;
249+
}
250+
251+
return VideoParametersPresets.defaultSimulcast43;
252+
}
253+
205254
static VideoEncoding _findAppropriateEncoding({
206255
required bool isScreenShare,
207256
required VideoDimensions dimensions,
@@ -221,8 +270,6 @@ class Utils {
221270
return result;
222271
}
223272

224-
static final videoRids = ['q', 'h', 'f'];
225-
226273
@internal
227274
static List<rtc.RTCRtpEncoding> encodingsFromPresets(
228275
VideoDimensions dimensions, {
@@ -233,11 +280,12 @@ class Utils {
233280
if (i >= videoRids.length) {
234281
return;
235282
}
283+
final size = dimensions.min();
236284
final rid = videoRids[i];
237285

238286
result.add(e.encoding.toRTCRtpEncoding(
239287
rid: rid,
240-
scaleResolutionDownBy: findEvenScaleDownBy(dimensions, e.dimensions),
288+
scaleResolutionDownBy: math.max(1, size / e.dimensions.min()),
241289
));
242290
});
243291
return result;
@@ -279,12 +327,10 @@ class Utils {
279327

280328
VideoEncoding? videoEncoding = options.videoEncoding;
281329

282-
final useSimulcast = !isScreenShare && options.simulcast;
283-
284-
if ((videoEncoding == null && !useSimulcast) || dimensions == null) {
330+
if ((videoEncoding == null && !options.simulcast) || dimensions == null) {
285331
// don't set encoding when we are not simulcasting and user isn't restricting
286332
// encoding parameters
287-
return null;
333+
return [rtc.RTCRtpEncoding()];
288334
}
289335

290336
final presets = _presetsForDimensions(
@@ -299,34 +345,48 @@ class Utils {
299345
dimensions: dimensions,
300346
presets: presets,
301347
);
348+
302349
logger.fine('using video encoding', videoEncoding);
303350
}
304351

305-
// Not simulcast
306-
if (!useSimulcast) return [videoEncoding.toRTCRtpEncoding()];
307-
308-
final VideoParameters lowPreset = presets.first;
309-
VideoParameters? midPreset;
310-
if (presets.length > 1) {
311-
midPreset = presets[1];
352+
if (!options.simulcast) {
353+
// not using simulcast
354+
return [videoEncoding.toRTCRtpEncoding()];
312355
}
356+
313357
final original = VideoParameters(
314358
dimensions: dimensions,
315359
encoding: videoEncoding,
316360
);
317361

362+
final userParams = isScreenShare
363+
? options.screenShareSimulcastLayers
364+
: options.videoSimulcastLayers;
365+
366+
final params = (userParams.isNotEmpty
367+
? userParams
368+
: _computeDefaultSimulcastParams(
369+
isScreenShare: isScreenShare, original: original))
370+
.sorted();
371+
372+
final VideoParameters lowPreset = params.first;
373+
VideoParameters? midPreset;
374+
if (params.length > 1) {
375+
midPreset = params[1];
376+
}
377+
318378
final size = dimensions.max();
319-
List<VideoParameters> computedPresets = [original];
379+
List<VideoParameters> computedParams = [original];
320380

321381
if (size >= 960 && midPreset != null) {
322-
computedPresets = [lowPreset, midPreset, original];
323-
} else if (size >= 500) {
324-
computedPresets = [lowPreset, original];
382+
computedParams = [lowPreset, midPreset, original];
383+
} else if (size >= 480) {
384+
computedParams = [lowPreset, original];
325385
}
326386

327387
return encodingsFromPresets(
328388
dimensions,
329-
presets: computedPresets,
389+
presets: computedParams,
330390
);
331391
}
332392

0 commit comments

Comments
 (0)