Update param computation (#87)
* import sorter config * organize video types * ignore import sort for proto files * equality for video types * impl * adjust defaults * max
This commit is contained in:
@@ -6,6 +6,7 @@ import 'track/options.dart';
|
||||
import 'track/track.dart';
|
||||
import 'types/other.dart';
|
||||
import 'types/video_encoding.dart';
|
||||
import 'types/video_parameters.dart';
|
||||
|
||||
/// Options used when connecting to the server.
|
||||
class ConnectOptions {
|
||||
@@ -88,9 +89,15 @@ class VideoPublishOptions {
|
||||
/// Defaults to true.
|
||||
final bool simulcast;
|
||||
|
||||
final List<VideoParameters> videoSimulcastLayers;
|
||||
|
||||
final List<VideoParameters> screenShareSimulcastLayers;
|
||||
|
||||
const VideoPublishOptions({
|
||||
this.videoEncoding,
|
||||
this.simulcast = true,
|
||||
this.videoSimulcastLayers = const [],
|
||||
this.screenShareSimulcastLayers = const [],
|
||||
});
|
||||
|
||||
@override
|
||||
|
||||
@@ -23,7 +23,7 @@ class CameraCaptureOptions extends VideoCaptureOptions {
|
||||
|
||||
const CameraCaptureOptions({
|
||||
this.cameraPosition = CameraPosition.front,
|
||||
VideoParameters params = VideoParametersPresets.h720_169,
|
||||
VideoParameters params = VideoParametersPresets.h540_169,
|
||||
}) : super(params: params);
|
||||
|
||||
CameraCaptureOptions.from({required VideoCaptureOptions captureOptions})
|
||||
@@ -51,7 +51,7 @@ class CameraCaptureOptions extends VideoCaptureOptions {
|
||||
/// Options used when creating a [LocalVideoTrack] that captures the screen.
|
||||
class ScreenShareCaptureOptions extends VideoCaptureOptions {
|
||||
const ScreenShareCaptureOptions({
|
||||
VideoParameters params = VideoParametersPresets.h720_169,
|
||||
VideoParameters params = VideoParametersPresets.screenShareH720FPS15,
|
||||
}) : super(params: params);
|
||||
|
||||
ScreenShareCaptureOptions.from({required VideoCaptureOptions captureOptions})
|
||||
@@ -71,7 +71,7 @@ abstract class VideoCaptureOptions extends LocalTrackOptions {
|
||||
final VideoParameters params;
|
||||
|
||||
const VideoCaptureOptions({
|
||||
this.params = VideoParametersPresets.h720_169,
|
||||
this.params = VideoParametersPresets.h540_169,
|
||||
});
|
||||
|
||||
@override
|
||||
|
||||
@@ -40,6 +40,12 @@ class VideoDimensions {
|
||||
}
|
||||
|
||||
extension VideoDimensionsHelpers on VideoDimensions {
|
||||
// aspect ratios
|
||||
static const aspect169 = 16.0 / 9.0;
|
||||
static const aspect43 = 4.0 / 3.0;
|
||||
|
||||
double aspect() => width > height ? width / height : height / width;
|
||||
|
||||
/// Returns the larger value
|
||||
int max() => math.max(width, height);
|
||||
|
||||
|
||||
@@ -56,6 +56,18 @@ class VideoParameters implements Comparable<VideoParameters> {
|
||||
}
|
||||
|
||||
extension VideoParametersPresets on VideoParameters {
|
||||
// 16:9 default
|
||||
static final List<VideoParameters> defaultSimulcast169 = [
|
||||
h180_169,
|
||||
h360_169,
|
||||
];
|
||||
|
||||
// 4:3 default
|
||||
static final List<VideoParameters> defaultSimulcast43 = [
|
||||
h180_43,
|
||||
h360_43,
|
||||
];
|
||||
|
||||
// all 16:9 presets
|
||||
static final List<VideoParameters> all169 = [
|
||||
h90_169,
|
||||
|
||||
+84
-24
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
@@ -34,6 +35,9 @@ typedef RetryCondition = bool Function(
|
||||
|
||||
// Collection of state-less static methods
|
||||
class Utils {
|
||||
// order of rids
|
||||
static final videoRids = ['q', 'h', 'f'];
|
||||
|
||||
/// Returns a [Future] that will retry [future] while it throws
|
||||
/// for a maximum of [tries] times with [delay] in between.
|
||||
/// If all the attempts throws, the future will throw a [List] of the
|
||||
@@ -191,17 +195,62 @@ class Utils {
|
||||
required bool isScreenShare,
|
||||
required VideoDimensions dimensions,
|
||||
}) {
|
||||
if (isScreenShare) return VideoParametersPresets.allScreenShare;
|
||||
if (isScreenShare) {
|
||||
return VideoParametersPresets.allScreenShare;
|
||||
}
|
||||
|
||||
final double aspect = dimensions.width > dimensions.height
|
||||
? dimensions.width / dimensions.height
|
||||
: dimensions.height / dimensions.width;
|
||||
if ((aspect - 16.0 / 9.0).abs() < (aspect - 4.0 / 3.0).abs()) {
|
||||
final a = dimensions.aspect();
|
||||
if ((a - VideoDimensionsHelpers.aspect169).abs() <
|
||||
(a - VideoDimensionsHelpers.aspect43).abs()) {
|
||||
return VideoParametersPresets.all169;
|
||||
}
|
||||
|
||||
return VideoParametersPresets.all43;
|
||||
}
|
||||
|
||||
static List<VideoParameters> _computeDefaultScreenShareSimulcastParams({
|
||||
required VideoParameters original,
|
||||
}) {
|
||||
final layers = [
|
||||
rtc.RTCRtpEncoding(scaleResolutionDownBy: 2, maxFramerate: 3)
|
||||
];
|
||||
return layers.map((e) {
|
||||
final scale = e.scaleResolutionDownBy ?? 1;
|
||||
final fps = e.maxFramerate ?? 3;
|
||||
|
||||
return VideoParameters(
|
||||
dimensions: VideoDimensions((original.dimensions.width / scale).floor(),
|
||||
(original.dimensions.height / scale).floor()),
|
||||
encoding: VideoEncoding(
|
||||
maxBitrate: math.max(
|
||||
150 * 1000,
|
||||
(original.encoding.maxBitrate /
|
||||
(math.pow(scale, 2) *
|
||||
(original.encoding.maxFramerate / fps)))
|
||||
.floor(),
|
||||
),
|
||||
maxFramerate: fps,
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
static List<VideoParameters> _computeDefaultSimulcastParams({
|
||||
required bool isScreenShare,
|
||||
required VideoParameters original,
|
||||
}) {
|
||||
if (isScreenShare) {
|
||||
return _computeDefaultScreenShareSimulcastParams(original: original);
|
||||
}
|
||||
final a = original.dimensions.aspect();
|
||||
if ((a - VideoDimensionsHelpers.aspect169).abs() <
|
||||
(a - VideoDimensionsHelpers.aspect43).abs()) {
|
||||
return VideoParametersPresets.defaultSimulcast169;
|
||||
}
|
||||
|
||||
return VideoParametersPresets.defaultSimulcast43;
|
||||
}
|
||||
|
||||
static VideoEncoding _findAppropriateEncoding({
|
||||
required bool isScreenShare,
|
||||
required VideoDimensions dimensions,
|
||||
@@ -221,8 +270,6 @@ class Utils {
|
||||
return result;
|
||||
}
|
||||
|
||||
static final videoRids = ['q', 'h', 'f'];
|
||||
|
||||
@internal
|
||||
static List<rtc.RTCRtpEncoding> encodingsFromPresets(
|
||||
VideoDimensions dimensions, {
|
||||
@@ -233,11 +280,12 @@ class Utils {
|
||||
if (i >= videoRids.length) {
|
||||
return;
|
||||
}
|
||||
final size = dimensions.min();
|
||||
final rid = videoRids[i];
|
||||
|
||||
result.add(e.encoding.toRTCRtpEncoding(
|
||||
rid: rid,
|
||||
scaleResolutionDownBy: findEvenScaleDownBy(dimensions, e.dimensions),
|
||||
scaleResolutionDownBy: math.max(1, size / e.dimensions.min()),
|
||||
));
|
||||
});
|
||||
return result;
|
||||
@@ -279,12 +327,10 @@ class Utils {
|
||||
|
||||
VideoEncoding? videoEncoding = options.videoEncoding;
|
||||
|
||||
final useSimulcast = !isScreenShare && options.simulcast;
|
||||
|
||||
if ((videoEncoding == null && !useSimulcast) || dimensions == null) {
|
||||
if ((videoEncoding == null && !options.simulcast) || dimensions == null) {
|
||||
// don't set encoding when we are not simulcasting and user isn't restricting
|
||||
// encoding parameters
|
||||
return null;
|
||||
return [rtc.RTCRtpEncoding()];
|
||||
}
|
||||
|
||||
final presets = _presetsForDimensions(
|
||||
@@ -299,34 +345,48 @@ class Utils {
|
||||
dimensions: dimensions,
|
||||
presets: presets,
|
||||
);
|
||||
|
||||
logger.fine('using video encoding', videoEncoding);
|
||||
}
|
||||
|
||||
// Not simulcast
|
||||
if (!useSimulcast) return [videoEncoding.toRTCRtpEncoding()];
|
||||
|
||||
final VideoParameters lowPreset = presets.first;
|
||||
VideoParameters? midPreset;
|
||||
if (presets.length > 1) {
|
||||
midPreset = presets[1];
|
||||
if (!options.simulcast) {
|
||||
// not using simulcast
|
||||
return [videoEncoding.toRTCRtpEncoding()];
|
||||
}
|
||||
|
||||
final original = VideoParameters(
|
||||
dimensions: dimensions,
|
||||
encoding: videoEncoding,
|
||||
);
|
||||
|
||||
final userParams = isScreenShare
|
||||
? options.screenShareSimulcastLayers
|
||||
: options.videoSimulcastLayers;
|
||||
|
||||
final params = (userParams.isNotEmpty
|
||||
? userParams
|
||||
: _computeDefaultSimulcastParams(
|
||||
isScreenShare: isScreenShare, original: original))
|
||||
.sorted();
|
||||
|
||||
final VideoParameters lowPreset = params.first;
|
||||
VideoParameters? midPreset;
|
||||
if (params.length > 1) {
|
||||
midPreset = params[1];
|
||||
}
|
||||
|
||||
final size = dimensions.max();
|
||||
List<VideoParameters> computedPresets = [original];
|
||||
List<VideoParameters> computedParams = [original];
|
||||
|
||||
if (size >= 960 && midPreset != null) {
|
||||
computedPresets = [lowPreset, midPreset, original];
|
||||
} else if (size >= 500) {
|
||||
computedPresets = [lowPreset, original];
|
||||
computedParams = [lowPreset, midPreset, original];
|
||||
} else if (size >= 480) {
|
||||
computedParams = [lowPreset, original];
|
||||
}
|
||||
|
||||
return encodingsFromPresets(
|
||||
dimensions,
|
||||
presets: computedPresets,
|
||||
presets: computedParams,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user