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