VideoDimensions instead of width height

This commit is contained in:
Hiroshi Horie
2021-12-13 21:49:42 +07:00
parent 3384bc6c6e
commit a82c5a7a50
7 changed files with 60 additions and 60 deletions
+6 -8
View File
@@ -101,8 +101,7 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
publishOptions ?? room.roomOptions?.defaultVideoPublishOptions; publishOptions ?? room.roomOptions?.defaultVideoPublishOptions;
// use constraints passed to getUserMedia by default // use constraints passed to getUserMedia by default
int width = track.currentOptions.params.width; VideoDimensions dimensions = track.currentOptions.params.dimensions;
int height = track.currentOptions.params.height;
if (kIsWeb) { if (kIsWeb) {
// getSettings() is only implemented for Web // getSettings() is only implemented for Web
@@ -110,10 +109,10 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
// try to use getSettings for more accurate resolution // try to use getSettings for more accurate resolution
final settings = track.mediaStreamTrack.getSettings(); final settings = track.mediaStreamTrack.getSettings();
if (settings['width'] is int) { if (settings['width'] is int) {
width = settings['width'] as int; dimensions = dimensions.copyWith(width: settings['width'] as int);
} }
if (settings['height'] is int) { if (settings['height'] is int) {
height = settings['height'] as int; dimensions = dimensions.copyWith(height: settings['height'] as int);
} }
} catch (_) { } catch (_) {
logger.warning('Failed to call `mediaStreamTrack.getSettings()`'); logger.warning('Failed to call `mediaStreamTrack.getSettings()`');
@@ -125,7 +124,7 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
name: track.name, name: track.name,
kind: track.kind, kind: track.kind,
source: track.source.toPBType(), source: track.source.toPBType(),
dimension: TrackDimension(width, height), dimensions: dimensions,
); );
logger.fine('publishVideoTrack addTrack response: ${trackInfo}'); logger.fine('publishVideoTrack addTrack response: ${trackInfo}');
@@ -133,12 +132,11 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
await track.start(); await track.start();
logger.fine( logger.fine(
'Compute encodings with resolution: ${width}x${height}, options: ${publishOptions}'); 'Compute encodings with resolution: ${dimensions}, options: ${publishOptions}');
// Video encodings and simulcasts // Video encodings and simulcasts
final encodings = Utils.computeVideoEncodings( final encodings = Utils.computeVideoEncodings(
width: width, dimensions: dimensions,
height: height,
options: publishOptions, options: publishOptions,
); );
+2 -2
View File
@@ -32,7 +32,7 @@ abstract class TrackPublication<T extends Track> extends Disposable {
bool get muted => track?.muted ?? false; bool get muted => track?.muted ?? false;
bool simulcasted = false; bool simulcasted = false;
TrackDimension? dimension; VideoDimensions? dimension;
bool get subscribed => track != null; bool get subscribed => track != null;
@@ -52,7 +52,7 @@ abstract class TrackPublication<T extends Track> extends Disposable {
void updateFromInfo(lk_models.TrackInfo info) { void updateFromInfo(lk_models.TrackInfo info) {
simulcasted = info.simulcast; simulcasted = info.simulcast;
if (info.type == lk_models.TrackType.VIDEO) { if (info.type == lk_models.TrackType.VIDEO) {
dimension = TrackDimension(info.width, info.height); dimension = VideoDimensions(info.width, info.height);
} }
} }
+2 -2
View File
@@ -147,7 +147,7 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
required String name, required String name,
required lk_models.TrackType kind, required lk_models.TrackType kind,
required lk_models.TrackSource source, required lk_models.TrackSource source,
TrackDimension? dimension, VideoDimensions? dimensions,
bool? dtx, bool? dtx,
}) async { }) async {
// TODO: Check if cid already published // TODO: Check if cid already published
@@ -158,7 +158,7 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
name: name, name: name,
type: kind, type: kind,
source: source, source: source,
dimension: dimension, dimensions: dimensions,
dtx: dtx, dtx: dtx,
); );
+4 -4
View File
@@ -148,7 +148,7 @@ class SignalClient extends Disposable with EventsEmittable<SignalEvent> {
required String name, required String name,
required lk_models.TrackType type, required lk_models.TrackType type,
required lk_models.TrackSource source, required lk_models.TrackSource source,
TrackDimension? dimension, VideoDimensions? dimensions,
bool? dtx, bool? dtx,
}) { }) {
final req = lk_rtc.AddTrackRequest( final req = lk_rtc.AddTrackRequest(
@@ -158,10 +158,10 @@ class SignalClient extends Disposable with EventsEmittable<SignalEvent> {
source: source, source: source,
); );
if (type == lk_models.TrackType.VIDEO && dimension != null) { if (type == lk_models.TrackType.VIDEO && dimensions != null) {
// video specific // video specific
req.width = dimension.width; req.width = dimensions.width;
req.height = dimension.height; req.height = dimensions.height;
} }
if (type == lk_models.TrackType.AUDIO && dtx != null) { if (type == lk_models.TrackType.AUDIO && dtx != null) {
+15 -26
View File
@@ -1,6 +1,7 @@
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import '../track/local/video.dart'; import '../track/local/video.dart';
import '../track/local/audio.dart'; import '../track/local/audio.dart';
import '../types.dart';
/// A type that represents front or back of the camera. /// A type that represents front or back of the camera.
enum CameraPosition { enum CameraPosition {
@@ -112,14 +113,12 @@ extension VideoEncodingExt on VideoEncoding {
class VideoParameters { class VideoParameters {
final String description; final String description;
final int width; final VideoDimensions dimensions;
final int height;
final VideoEncoding encoding; final VideoEncoding encoding;
const VideoParameters({ const VideoParameters({
required this.description, required this.description,
required this.width, required this.dimensions,
required this.height,
required this.encoding, required this.encoding,
}); });
@@ -129,8 +128,7 @@ class VideoParameters {
static const presetQVGA169 = VideoParameters( static const presetQVGA169 = VideoParameters(
description: 'QVGA(320x180) 16:9', description: 'QVGA(320x180) 16:9',
width: 320, dimensions: VideoDimensions(320, 180),
height: 180,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 125000, maxBitrate: 125000,
maxFramerate: 15, maxFramerate: 15,
@@ -139,8 +137,7 @@ class VideoParameters {
static const presetVGA169 = VideoParameters( static const presetVGA169 = VideoParameters(
description: 'VGA(640x360) 16:9', description: 'VGA(640x360) 16:9',
width: 640, dimensions: VideoDimensions(640, 360),
height: 360,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 400000, maxBitrate: 400000,
maxFramerate: 30, maxFramerate: 30,
@@ -149,8 +146,7 @@ class VideoParameters {
static const presetQHD169 = VideoParameters( static const presetQHD169 = VideoParameters(
description: 'QHD(960x540) 16:9', description: 'QHD(960x540) 16:9',
width: 960, dimensions: VideoDimensions(960, 540),
height: 540,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 800000, maxBitrate: 800000,
maxFramerate: 30, maxFramerate: 30,
@@ -159,8 +155,7 @@ class VideoParameters {
static const presetHD169 = VideoParameters( static const presetHD169 = VideoParameters(
description: 'HD(1280x720) 16:9', description: 'HD(1280x720) 16:9',
width: 1280, dimensions: VideoDimensions(1280, 720),
height: 720,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 2500000, maxBitrate: 2500000,
maxFramerate: 30, maxFramerate: 30,
@@ -169,8 +164,7 @@ class VideoParameters {
static const presetFHD169 = VideoParameters( static const presetFHD169 = VideoParameters(
description: 'FHD(1920x1080) 16:9', description: 'FHD(1920x1080) 16:9',
width: 1920, dimensions: VideoDimensions(1920, 1080),
height: 1080,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 4000000, maxBitrate: 4000000,
maxFramerate: 30, maxFramerate: 30,
@@ -179,8 +173,7 @@ class VideoParameters {
static const presetQVGA43 = VideoParameters( static const presetQVGA43 = VideoParameters(
description: 'QVGA(240x180) 4:3', description: 'QVGA(240x180) 4:3',
width: 240, dimensions: VideoDimensions(240, 180),
height: 180,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 100000, maxBitrate: 100000,
maxFramerate: 15, maxFramerate: 15,
@@ -189,8 +182,7 @@ class VideoParameters {
static const presetVGA43 = VideoParameters( static const presetVGA43 = VideoParameters(
description: 'VGA(480x360) 4:3', description: 'VGA(480x360) 4:3',
width: 480, dimensions: VideoDimensions(480, 360),
height: 360,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 320000, maxBitrate: 320000,
maxFramerate: 30, maxFramerate: 30,
@@ -199,8 +191,7 @@ class VideoParameters {
static const presetQHD43 = VideoParameters( static const presetQHD43 = VideoParameters(
description: 'QHD(720x540) 4:3', description: 'QHD(720x540) 4:3',
width: 720, dimensions: VideoDimensions(720, 540),
height: 540,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 640000, maxBitrate: 640000,
maxFramerate: 30, maxFramerate: 30,
@@ -209,8 +200,7 @@ class VideoParameters {
static const presetHD43 = VideoParameters( static const presetHD43 = VideoParameters(
description: 'HD(960x720) 4:3', description: 'HD(960x720) 4:3',
width: 960, dimensions: VideoDimensions(960, 720),
height: 720,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 2000000, maxBitrate: 2000000,
maxFramerate: 30, maxFramerate: 30,
@@ -219,8 +209,7 @@ class VideoParameters {
static const presetFHD43 = VideoParameters( static const presetFHD43 = VideoParameters(
description: 'FHD(1440x1080) 4:3', description: 'FHD(1440x1080) 4:3',
width: 1440, dimensions: VideoDimensions(1440, 1080),
height: 1080,
encoding: VideoEncoding( encoding: VideoEncoding(
maxBitrate: 3200000, maxBitrate: 3200000,
maxFramerate: 30, maxFramerate: 30,
@@ -248,8 +237,8 @@ class VideoParameters {
// https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
// //
Map<String, dynamic> toMediaConstraintsMap() => <String, dynamic>{ Map<String, dynamic> toMediaConstraintsMap() => <String, dynamic>{
'width': width, 'width': dimensions.width,
'height': height, 'height': dimensions.height,
'frameRate': encoding.maxFramerate, 'frameRate': encoding.maxFramerate,
}; };
} }
+18 -2
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'extensions.dart'; import 'extensions.dart';
import 'dart:math' as math;
typedef CancelListenFunc = Function(); typedef CancelListenFunc = Function();
@@ -134,12 +135,27 @@ class RTCIceServer {
} }
@immutable @immutable
class TrackDimension { class VideoDimensions {
final int width; final int width;
final int height; final int height;
const TrackDimension( const VideoDimensions(
this.width, this.width,
this.height, this.height,
); );
@override
String toString() => 'VideoDimensions(${width}×${height})';
/// Returns the larger value
int max() => math.max(width, height);
VideoDimensions copyWith({
int? width,
int? height,
}) =>
VideoDimensions(
width ?? this.width,
height ?? this.height,
);
} }
+13 -16
View File
@@ -6,6 +6,7 @@ import 'extensions.dart';
import 'livekit.dart'; import 'livekit.dart';
import 'options.dart'; import 'options.dart';
import 'track/options.dart'; import 'track/options.dart';
import 'types.dart';
extension UriExt on Uri { extension UriExt on Uri {
bool get isSecureScheme => ['https', 'wss'].contains(scheme); bool get isSecureScheme => ['https', 'wss'].contains(scheme);
@@ -54,53 +55,49 @@ class Utils {
); );
} }
static List<VideoParameters> _presetsForResolution( static List<VideoParameters> _presetsForDimensions(
int width, VideoDimensions dimensions,
int height,
) { ) {
final double aspect = width / height; final double aspect = dimensions.width / dimensions.height;
if ((aspect - 16.0 / 9.0).abs() < (aspect - 4.0 / 3.0).abs()) { if ((aspect - 16.0 / 9.0).abs() < (aspect - 4.0 / 3.0).abs()) {
return VideoParameters.presets169; return VideoParameters.presets169;
} }
return VideoParameters.presets43; return VideoParameters.presets43;
} }
static VideoParameters _findPresetForResolution( static VideoParameters _findPresetForDimensions(
int width, VideoDimensions dimensions, {
int height, {
required List<VideoParameters> presets, required List<VideoParameters> presets,
}) { }) {
assert(presets.isNotEmpty, 'presets should not be empty'); assert(presets.isNotEmpty, 'presets should not be empty');
VideoParameters result = presets.first; VideoParameters result = presets.first;
for (final preset in presets) { for (final preset in presets) {
if (width >= preset.width && height >= preset.height) result = preset; if (dimensions.width >= preset.dimensions.width &&
dimensions.height >= preset.dimensions.height) result = preset;
} }
return result; return result;
} }
static List<rtc.RTCRtpEncoding>? computeVideoEncodings({ static List<rtc.RTCRtpEncoding>? computeVideoEncodings({
int? width, VideoDimensions? dimensions,
int? height,
VideoPublishOptions? options, VideoPublishOptions? options,
}) { }) {
options ??= const VideoPublishOptions(); options ??= const VideoPublishOptions();
VideoEncoding? videoEncoding = options.videoEncoding; VideoEncoding? videoEncoding = options.videoEncoding;
if ((videoEncoding == null && !options.simulcast) || if ((videoEncoding == null && !options.simulcast) || dimensions == null) {
width == null ||
height == 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 null;
} }
final presets = _presetsForResolution(width, height); final presets = _presetsForDimensions(dimensions);
if (videoEncoding == null) { if (videoEncoding == null) {
// find the right encoding based on width/height // find the right encoding based on width/height
final preset = _findPresetForResolution(width, height, presets: presets); final preset = _findPresetForDimensions(dimensions, presets: presets);
// print('Using preset: ${preset.id}'); // print('Using preset: ${preset.id}');
videoEncoding = preset.encoding; videoEncoding = preset.encoding;
// log.debug('using video encoding', videoEncoding); // log.debug('using video encoding', videoEncoding);
@@ -118,7 +115,7 @@ class Utils {
), ),
// if resolution is high enough, we would send both h and q res.. // if resolution is high enough, we would send both h and q res..
// otherwise only send h // otherwise only send h
if (width >= 960) ...[ if (dimensions.max() >= 960) ...[
midPreset.encoding.toRTCRtpEncoding( midPreset.encoding.toRTCRtpEncoding(
rid: 'h', rid: 'h',
// passing decimals to hardware encoder of android devices // passing decimals to hardware encoder of android devices