From 8fc1c846ec0a769e3d7f408f3d60d1c6a9eb7fb0 Mon Sep 17 00:00:00 2001 From: Tobias Ollmann Date: Wed, 22 Jan 2025 12:12:17 +0100 Subject: [PATCH] fix: tighten VideoTrackRenderer Widget This allows external users to e.g. apply rounded edges. Without this patch, VideoTrackRenderer will expand to its available space with no way for parent widgets to know how large the video actually is --- lib/src/widgets/video_track_renderer.dart | 62 ++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/lib/src/widgets/video_track_renderer.dart b/lib/src/widgets/video_track_renderer.dart index 61e353603..eb7ccc277 100644 --- a/lib/src/widgets/video_track_renderer.dart +++ b/lib/src/widgets/video_track_renderer.dart @@ -65,6 +65,9 @@ class VideoTrackRenderer extends StatefulWidget { final rtc.RTCVideoRenderer? cachedRenderer; final bool autoDisposeRenderer; + /// wrap the video view in a Center widget (if [fit] is [VideoViewFit.contain]) + final bool autoCenter; + const VideoTrackRenderer( this.track, { this.fit = VideoViewFit.contain, @@ -72,6 +75,7 @@ class VideoTrackRenderer extends StatefulWidget { this.renderMode = VideoRenderMode.texture, this.autoDisposeRenderer = true, this.cachedRenderer, + this.autoCenter = true, Key? key, }) : super(key: key); @@ -83,6 +87,7 @@ class _VideoTrackRendererState extends State { rtc.VideoRenderer? _renderer; // for flutter web only. bool _rendererReadyForWeb = false; + double? _aspectRatio; EventsListener? _listener; // Used to compute visibility information late GlobalKey _internalKey; @@ -121,6 +126,7 @@ class _VideoTrackRendererState extends State { void disposeRenderer() { try { + _renderer?.onResize = null; _renderer?.srcObject = null; _renderer?.dispose(); _renderer = null; @@ -167,6 +173,14 @@ class _VideoTrackRendererState extends State { // force recompute of mirror mode setState(() {}); }); + _renderer?.onResize = () { + if (mounted) { + setState(() { + _aspectRatio = + (_renderer as rtc.RTCVideoRenderer?)?.videoValue.aspectRatio; + }); + } + }; } @override @@ -268,8 +282,52 @@ class _VideoTrackRendererState extends State { // FutureBuilder will cause flickering for flutter web. so using // different rendering methods for web and native. @override - Widget build(BuildContext context) => - kIsWeb ? _videoViewForWeb() : _videoViewForNative(); + Widget build(BuildContext context) { + final child = kIsWeb ? _videoViewForWeb() : _videoViewForNative(); + + if (widget.fit == VideoViewFit.cover) { + return child; + } + + final videoView = LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (!constraints.hasBoundedWidth && !constraints.hasBoundedHeight) { + return child; + } + if (_aspectRatio == null) { + return child; + } + + bool fixHeight; + if (!constraints.hasBoundedWidth) { + fixHeight = true; + } else if (!constraints.hasBoundedHeight) { + fixHeight = false; + } else { + // both width and height are bound, figure out which to fix based on aspect ratios + final constraintsAspectRatio = + constraints.maxWidth / constraints.maxHeight; + fixHeight = constraintsAspectRatio > _aspectRatio!; + } + final double width; + final double height; + if (fixHeight) { + height = constraints.maxHeight; + width = height * _aspectRatio!; + } else { + width = constraints.maxWidth; + height = width / _aspectRatio!; + } + return SizedBox(width: width, height: height, child: child); + }, + ); + + if (widget.autoCenter) { + return Center(child: videoView); + } else { + return videoView; + } + } bool _shouldMirror() { // off for screen share