diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 0da6b35..660fd4c 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'dart:typed_data'; +import 'package:flutter/widgets.dart'; import 'package:video_player/video_player.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; @@ -211,4 +212,13 @@ extension FVPControllerExtensions on VideoPlayerController { void setExternalSubtitle(String uri) { _platform.setExternalSubtitle(_getId(this), uri); } + + /// Set video box fit mode + void setBoxFitToVideo( + {required BoxFit fit, + required double width, + required double height}) { + _platform.setBoxFitToVideo(_getId(this), + fit: fit, width: width, height: height); + } } diff --git a/lib/src/player.dart b/lib/src/player.dart index dc25371..a7ef026 100644 --- a/lib/src/player.dart +++ b/lib/src/player.dart @@ -10,6 +10,7 @@ import 'dart:ui' as ui; import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; import 'fvp_platform_interface.dart'; @@ -611,6 +612,64 @@ class Player { .asFunction, int, Pointer)>()( _player.ref.object, degree, _getVid()); + + void setBoxFitToVideo({ + required BoxFit fit, + required double width, + required double height, + }) async { + var x = await textureSize; + if (x == null) { + return; + } + var videoWidth = x.width; + var videoHeight = x.height; + if (videoWidth == 0 || + videoHeight == 0 || + width == 0 || + height == 0) { + return; + } + + var fittedHeight = width * videoHeight / videoWidth; + var heightScale = fittedHeight / height; + + var fittedWidth = height * videoWidth / videoHeight; + var widthScale = fittedWidth / width; + + switch (fit) { + case BoxFit.fill: + scale(1, 1); + break; + case BoxFit.contain: + case BoxFit.scaleDown: + if (fittedWidth < width) { + scale(1 * widthScale, 1); + } else if (fittedHeight < height) { + scale(1, 1 * heightScale); + } + break; + case BoxFit.cover: + if (fittedWidth > width) { + scale(1 * widthScale, 1); + } else if (fittedHeight > height) { + scale(1, 1 * heightScale); + } + break; + case BoxFit.fitWidth: + scale(1, 1 * heightScale); + break; + case BoxFit.fitHeight: + scale(1 * widthScale, 1); + break; + case BoxFit.none: + var originalWidthScale = videoWidth / width; + var originalHeightScale = videoHeight / height; + scale(originalWidthScale, originalHeightScale); + break; + } + } + /// scale video content. 1.0 is no scale. /// https://github.com/wang-bin/mdk-sdk/wiki/Player-APIs#void-scalefloat-x-float-y-void-vo_opaque--nullptr void scale(double x, double y) => _player.ref.scale.asFunction< @@ -736,7 +795,16 @@ class Player { // we don't support dynamic texture size change, so use the max video codec width if (v != null) { for (final i in mediaInfo.video!) { - if (i.codec.width > v!.codec.width) { + // 跳过明显是封面/缩略图的流 + if (i.codec.codec.toLowerCase() == "mjpeg" && (i.codec.bitRate == 0 || i.codec.frameRate > 1000)) { + continue; + } + if (v!.codec.codec.toLowerCase() == "mjpeg" && (i.codec.bitRate == 0 || i.codec.frameRate > 1000)) { + // 如果当前 v 本身是 mjpeg/无效流,则直接替换 + v = i; + continue; + } + if (i.codec.width > v.codec.width) { v = i; } } diff --git a/lib/src/video_player_mdk.dart b/lib/src/video_player_mdk.dart index e6bf871..d9d7ef0 100644 --- a/lib/src/video_player_mdk.dart +++ b/lib/src/video_player_mdk.dart @@ -548,4 +548,11 @@ class MdkVideoPlayerPlatform extends VideoPlayerPlatform { return dataSource.uri!; } } + void setBoxFitToVideo(int textureId, {required BoxFit fit, required double width, required double height}) { + final player = _players[textureId]; + if (player == null) { + return; + } + player.setBoxFitToVideo(fit: fit, width: width, height: height); + } }