video: package study, HW acceleration macroblock fix for fijk
This commit is contained in:
parent
3ddf44b6cc
commit
37dde5cb38
15 changed files with 275 additions and 43 deletions
|
@ -58,6 +58,7 @@ android {
|
|||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
manifestPlaceholders = [googleApiKey: keystoreProperties['googleApiKey']]
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
@ -106,6 +107,7 @@ dependencies {
|
|||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
|
||||
implementation 'androidx.core:core-ktx:1.5.0-rc01' // v1.5.0-alpha02+ for ShortcutManagerCompat.setDynamicShortcuts
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.2'
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
implementation 'com.commonsware.cwac:document:0.4.1'
|
||||
implementation 'com.drewnoakes:metadata-extractor:2.15.0'
|
||||
implementation 'com.github.deckerst:Android-TiffBitmapFactory:876e53870a' // forked, built by JitPack
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/widgets/common/video/fijkplayer.dart';
|
||||
// import 'package:aves/widgets/common/video/flutter_ijkplayer.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
abstract class AvesVideoController {
|
||||
AvesVideoController();
|
||||
|
||||
factory AvesVideoController.ijkPlayer() => IjkPlayerAvesVideoController();
|
||||
|
||||
void dispose();
|
||||
|
||||
Future<void> setDataSource(String uri);
|
||||
|
@ -44,7 +40,7 @@ abstract class AvesVideoController {
|
|||
|
||||
Stream<int> get positionStream;
|
||||
|
||||
Widget buildPlayerWidget(AvesEntry entry);
|
||||
Widget buildPlayerWidget(BuildContext context, AvesEntry entry);
|
||||
}
|
||||
|
||||
class AvesVideoInfo {
|
|
@ -1,9 +1,10 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/utils/change_notifier.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:fijkplayer/fijkplayer.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -12,10 +13,11 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
final List<StreamSubscription> _subscriptions = [];
|
||||
final StreamController<FijkValue> _valueStreamController = StreamController.broadcast();
|
||||
final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||
Offset _macroBlockCrop = Offset.zero;
|
||||
|
||||
Stream<FijkValue> get _valueStream => _valueStreamController.stream;
|
||||
|
||||
IjkPlayerAvesVideoController() {
|
||||
IjkPlayerAvesVideoController(AvesEntry entry) {
|
||||
_instance = FijkPlayer();
|
||||
|
||||
// FFmpeg options
|
||||
|
@ -30,15 +32,27 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
// `framedrop`: drop frames when cpu is too slow, default: 0, in [-1, 120]
|
||||
option.setPlayerOption('framedrop', 5);
|
||||
|
||||
final hwAccel = settings.isVideoHardwareAccelerationEnabled ? 1 : 0;
|
||||
final _hwAccelerationEnabled = settings.isVideoHardwareAccelerationEnabled;
|
||||
if (_hwAccelerationEnabled) {
|
||||
// crop HW acceleration macroblock misalignment for videos with dimensions that do not fit 16x
|
||||
final s = entry.displaySize % 16 * -1 % 16;
|
||||
_macroBlockCrop = Offset(s.width, s.height);
|
||||
}
|
||||
// `mediacodec-all-videos`: MediaCodec: enable all videos, default: 0, in [0, 1]
|
||||
// TODO TLAD enabling `mediacodec-all-videos` randomly fails to render some videos, e.g. MP2TS/h264(HDPR)
|
||||
option.setPlayerOption('mediacodec-all-videos', hwAccel);
|
||||
option.setPlayerOption('mediacodec-all-videos', _hwAccelerationEnabled ? 1 : 0);
|
||||
|
||||
// option.setPlayerOption('analyzemaxduration', 200 * 1024);
|
||||
// option.setPlayerOption('analyzeduration', 200 * 1024);
|
||||
// option.setPlayerOption('probesize', 1024 * 1024);
|
||||
|
||||
// CJL options
|
||||
// option.setPlayerOption('reconnect', 5);
|
||||
// option.setPlayerOption('mediacodec', 1);
|
||||
// option.setPlayerOption('packet-buffering', 1);
|
||||
// option.setPlayerOption('soundtouch', 1);
|
||||
// option.setPlayerOption('start-on-prepared', 1);
|
||||
|
||||
// TODO TLAD check looping
|
||||
// option.setPlayerOption('loop', 42);
|
||||
|
||||
|
@ -95,9 +109,6 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
@override
|
||||
Stream<bool> get isVideoReadyStream => _valueStream.map((value) => value.videoRenderStart);
|
||||
|
||||
// we check whether video info is ready instead of checking for `noDatasource` status,
|
||||
// as the controller could also be uninitialized with the `pause` status
|
||||
// (e.g. when switching between video entries without playing them the first time)
|
||||
@override
|
||||
bool get isPlayable => _instance.isPlayable();
|
||||
|
||||
|
@ -111,11 +122,19 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
Stream<int> get positionStream => _instance.onCurrentPosUpdate.map((pos) => pos.inMilliseconds);
|
||||
|
||||
@override
|
||||
Widget buildPlayerWidget(AvesEntry entry) => FijkView(
|
||||
player: _instance,
|
||||
panelBuilder: (player, data, context, viewSize, texturePos) => SizedBox(),
|
||||
color: Colors.transparent,
|
||||
);
|
||||
Widget buildPlayerWidget(BuildContext context, AvesEntry entry) {
|
||||
return FijkView(
|
||||
player: _instance,
|
||||
fit: FijkFit(
|
||||
sizeFactor: 1.0,
|
||||
aspectRatio: -1,
|
||||
alignment: Alignment.topLeft,
|
||||
macroBlockCrop: _macroBlockCrop,
|
||||
),
|
||||
panelBuilder: (player, data, context, viewSize, texturePos) => SizedBox(),
|
||||
color: Colors.transparent,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtraIjkStatus on FijkState {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// import 'package:aves/model/entry.dart';
|
||||
// import 'package:aves/utils/change_notifier.dart';
|
||||
// import 'package:aves/widgets/common/video/video.dart';
|
||||
// import 'package:aves/widgets/common/video/controller.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
|
||||
//
|
||||
|
@ -57,7 +57,7 @@
|
|||
// // as the controller could also be uninitialized with the `pause` status
|
||||
// // (e.g. when switching between video entries without playing them the first time)
|
||||
// @override
|
||||
// bool get isPlayable => _videoInfo.hasData;
|
||||
// bool get isPlayable => _videoInfo.hasData && [VideoStatus.prepared, VideoStatus.playing, VideoStatus.paused, VideoStatus.completed].contains(status);
|
||||
//
|
||||
// @override
|
||||
// bool get isVideoReady => _instance.textureId != null;
|
||||
|
@ -79,7 +79,7 @@
|
|||
// Stream<int> get positionStream => _instance.videoInfoStream.map((info) => info.currentPositionMillis);
|
||||
//
|
||||
// @override
|
||||
// Widget buildPlayerWidget(AvesEntry entry) => IjkPlayer(
|
||||
// Widget buildPlayerWidget(BuildContext context, AvesEntry entry) => IjkPlayer(
|
||||
// mediaController: _instance,
|
||||
// controllerWidgetBuilder: (controller) => SizedBox.shrink(),
|
||||
// statusWidgetBuilder: (context, controller, status) => SizedBox.shrink(),
|
||||
|
|
119
lib/widgets/common/video/flutter_vlc_player.dart
Normal file
119
lib/widgets/common/video/flutter_vlc_player.dart
Normal file
|
@ -0,0 +1,119 @@
|
|||
// import 'dart:async';
|
||||
// import 'dart:io';
|
||||
//
|
||||
// import 'package:aves/model/entry.dart';
|
||||
// import 'package:aves/utils/change_notifier.dart';
|
||||
// import 'package:aves/widgets/common/video/controller.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/src/foundation/change_notifier.dart';
|
||||
// import 'package:flutter/src/widgets/framework.dart';
|
||||
// import 'package:flutter_vlc_player/flutter_vlc_player.dart';
|
||||
// import 'package:provider/provider.dart';
|
||||
//
|
||||
// class VlcAvesVideoController extends AvesVideoController {
|
||||
// VlcPlayerController _instance;
|
||||
// final List<StreamSubscription> _subscriptions = [];
|
||||
// final StreamController<VlcPlayerValue> _valueStreamController = StreamController.broadcast();
|
||||
// final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||
//
|
||||
// Stream<VlcPlayerValue> get _valueStream => _valueStreamController.stream;
|
||||
//
|
||||
// VlcAvesVideoController();
|
||||
//
|
||||
// @override
|
||||
// Future<void> setDataSource(String uri) async {
|
||||
// _instance = VlcPlayerController.file(
|
||||
// File(uri),
|
||||
// );
|
||||
// _instance.addListener(_onValueChanged);
|
||||
// _subscriptions.add(_valueStream.where((value) => value.isEnded).listen((_) => _playFinishNotifier.notifyListeners()));
|
||||
//
|
||||
// // update value stream to:
|
||||
// // 1) trigger playability check
|
||||
// // 2) show the `VlcPlayer` widget
|
||||
// // 3) initialize its `PlatformView`
|
||||
// // 4) complete `VlcPlayerController` initialization
|
||||
// _valueStreamController.add(_instance.value);
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _instance?.removeListener(_onValueChanged);
|
||||
// _valueStreamController.close();
|
||||
// _subscriptions
|
||||
// ..forEach((sub) => sub.cancel())
|
||||
// ..clear();
|
||||
// _instance?.dispose();
|
||||
// }
|
||||
//
|
||||
// void _onValueChanged() => _valueStreamController.add(_instance.value);
|
||||
//
|
||||
// @override
|
||||
// Future<void> refreshVideoInfo() => null;
|
||||
//
|
||||
// @override
|
||||
// Future<void> play() => _instance.play();
|
||||
//
|
||||
// @override
|
||||
// Future<void> pause() => _instance?.pause();
|
||||
//
|
||||
// @override
|
||||
// Future<void> seekTo(int targetMillis) => _instance.seekTo(Duration(milliseconds: targetMillis));
|
||||
//
|
||||
// @override
|
||||
// Future<void> seekToProgress(double progress) => _instance.seekTo(Duration(milliseconds: (duration * progress).toInt()));
|
||||
//
|
||||
// @override
|
||||
// Listenable get playCompletedListenable => _playFinishNotifier;
|
||||
//
|
||||
// @override
|
||||
// VideoStatus get status => _instance?.value?.toAves ?? VideoStatus.idle;
|
||||
//
|
||||
// @override
|
||||
// Stream<VideoStatus> get statusStream => _valueStream.map((value) => value.toAves);
|
||||
//
|
||||
// @override
|
||||
// bool get isVideoReady => _instance != null && _instance.value.isInitialized && !_instance.value.hasError;
|
||||
//
|
||||
// @override
|
||||
// Stream<bool> get isVideoReadyStream => _valueStream.map((value) => value.isInitialized && !value.hasError);
|
||||
//
|
||||
// @override
|
||||
// bool get isPlayable => _instance != null;
|
||||
//
|
||||
// @override
|
||||
// int get duration => _instance?.value?.duration?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// int get currentPosition => _instance?.value?.position?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// Stream<int> get positionStream => _valueStream.map((value) => value.position.inMilliseconds);
|
||||
//
|
||||
// @override
|
||||
// Widget buildPlayerWidget(BuildContext context, AvesEntry entry) {
|
||||
// // do not use `Magnifier` with `applyScale` enabled when using this widget,
|
||||
// // as the original video size will be used to create the `PlatformView`
|
||||
// // and a virtual display larger than the device screen may crash the app
|
||||
// final mqWidth = context.select<MediaQueryData, double>((mq) => mq.size.width);
|
||||
// final displaySize = entry.displaySize;
|
||||
// final ratio = mqWidth / displaySize.width;
|
||||
// return SizedBox.fromSize(
|
||||
// size: displaySize * ratio,
|
||||
// child: VlcPlayer(
|
||||
// controller: _instance,
|
||||
// aspectRatio: entry.displayAspectRatio,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// extension ExtraVlcPlayerValue on VlcPlayerValue {
|
||||
// VideoStatus get toAves {
|
||||
// if (hasError) return VideoStatus.error;
|
||||
// if (!isInitialized) return VideoStatus.idle;
|
||||
// if (isEnded) return VideoStatus.completed;
|
||||
// if (isPlaying) return VideoStatus.playing;
|
||||
// return VideoStatus.paused;
|
||||
// }
|
||||
// }
|
95
lib/widgets/common/video/video_player.dart
Normal file
95
lib/widgets/common/video/video_player.dart
Normal file
|
@ -0,0 +1,95 @@
|
|||
// import 'dart:async';
|
||||
//
|
||||
// import 'package:aves/model/entry.dart';
|
||||
// import 'package:aves/utils/change_notifier.dart';
|
||||
// import 'package:aves/widgets/common/video/controller.dart';
|
||||
// import 'package:flutter/src/foundation/change_notifier.dart';
|
||||
// import 'package:flutter/src/widgets/framework.dart';
|
||||
// import 'package:video_player/video_player.dart';
|
||||
//
|
||||
// class VideoPlayerAvesVideoController extends AvesVideoController {
|
||||
// VideoPlayerController _instance;
|
||||
// final List<StreamSubscription> _subscriptions = [];
|
||||
// final StreamController<VideoPlayerValue> _valueStreamController = StreamController.broadcast();
|
||||
// final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||
//
|
||||
// Stream<VideoPlayerValue> get _valueStream => _valueStreamController.stream;
|
||||
//
|
||||
// VideoPlayerAvesVideoController();
|
||||
//
|
||||
// @override
|
||||
// Future<void> setDataSource(String uri) async {
|
||||
// _instance = VideoPlayerController.network(uri);
|
||||
// _instance.addListener(_onValueChanged);
|
||||
// _subscriptions.add(_valueStream.where((value) => value.position > value.duration).listen((_) => _playFinishNotifier.notifyListeners()));
|
||||
//
|
||||
// await _instance.initialize();
|
||||
// await play();
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _instance?.removeListener(_onValueChanged);
|
||||
// _valueStreamController.close();
|
||||
// _subscriptions
|
||||
// ..forEach((sub) => sub.cancel())
|
||||
// ..clear();
|
||||
// _instance?.dispose();
|
||||
// }
|
||||
//
|
||||
// void _onValueChanged() => _valueStreamController.add(_instance.value);
|
||||
//
|
||||
// @override
|
||||
// Future<void> refreshVideoInfo() => null;
|
||||
//
|
||||
// @override
|
||||
// Future<void> play() => _instance.play();
|
||||
//
|
||||
// @override
|
||||
// Future<void> pause() => _instance?.pause();
|
||||
//
|
||||
// @override
|
||||
// Future<void> seekTo(int targetMillis) => _instance.seekTo(Duration(milliseconds: targetMillis));
|
||||
//
|
||||
// @override
|
||||
// Future<void> seekToProgress(double progress) => _instance.seekTo(Duration(milliseconds: (duration * progress).toInt()));
|
||||
//
|
||||
// @override
|
||||
// Listenable get playCompletedListenable => _playFinishNotifier;
|
||||
//
|
||||
// @override
|
||||
// VideoStatus get status => _instance?.value?.toAves ?? VideoStatus.idle;
|
||||
//
|
||||
// @override
|
||||
// Stream<VideoStatus> get statusStream => _valueStream.map((value) => value.toAves);
|
||||
//
|
||||
// @override
|
||||
// bool get isVideoReady => _instance != null && _instance.value.isInitialized && !_instance.value.hasError;
|
||||
//
|
||||
// @override
|
||||
// Stream<bool> get isVideoReadyStream => _valueStream.map((value) => value.isInitialized && !value.hasError);
|
||||
//
|
||||
// @override
|
||||
// bool get isPlayable => _instance != null && _instance.value.isInitialized && !_instance.value.hasError;
|
||||
//
|
||||
// @override
|
||||
// int get duration => _instance?.value?.duration?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// int get currentPosition => _instance?.value?.position?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// Stream<int> get positionStream => _valueStream.map((value) => value.position.inMilliseconds);
|
||||
//
|
||||
// @override
|
||||
// Widget buildPlayerWidget(BuildContext context, AvesEntry entry) => VideoPlayer(_instance);
|
||||
// }
|
||||
//
|
||||
// extension ExtraVideoPlayerValue on VideoPlayerValue {
|
||||
// VideoStatus get toAves {
|
||||
// if (hasError) return VideoStatus.error;
|
||||
// if (!isInitialized) return VideoStatus.idle;
|
||||
// if (isPlaying) return VideoStatus.playing;
|
||||
// return VideoStatus.paused;
|
||||
// }
|
||||
// }
|
|
@ -3,7 +3,7 @@ import 'package:aves/model/multipage.dart';
|
|||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/widgets/common/magnifier/pan/gesture_detector_scope.dart';
|
||||
import 'package:aves/widgets/common/magnifier/pan/scroll_physics.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:aves/widgets/viewer/multipage.dart';
|
||||
import 'package:aves/widgets/viewer/visual/entry_page_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/widgets/common/magnifier/pan/scroll_physics.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:aves/widgets/viewer/entry_horizontal_pager.dart';
|
||||
import 'package:aves/widgets/viewer/info/info_page.dart';
|
||||
import 'package:aves/widgets/viewer/info/notifications.dart';
|
||||
|
|
|
@ -11,7 +11,8 @@ import 'package:aves/theme/durations.dart';
|
|||
import 'package:aves/utils/change_notifier.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:aves/widgets/common/basic/insets.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:aves/widgets/common/video/fijkplayer.dart';
|
||||
import 'package:aves/widgets/viewer/entry_action_delegate.dart';
|
||||
import 'package:aves/widgets/viewer/entry_vertical_pager.dart';
|
||||
import 'package:aves/widgets/viewer/hero.dart';
|
||||
|
@ -499,7 +500,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
_initViewSpecificController<AvesVideoController>(
|
||||
uri,
|
||||
_videoControllers,
|
||||
() => AvesVideoController.ijkPlayer(),
|
||||
() => IjkPlayerAvesVideoController(entry),
|
||||
(_) => _.dispose(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
|
@ -9,6 +8,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:latlong/latlong.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class EntryLeafletMap extends StatefulWidget {
|
||||
|
|
|
@ -6,8 +6,8 @@ import 'package:aves/services/svg_metadata_service.dart';
|
|||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/color_utils.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
||||
import 'package:aves/widgets/viewer/info/common.dart';
|
||||
import 'package:aves/widgets/viewer/info/metadata/metadata_section.dart';
|
||||
import 'package:aves/widgets/viewer/info/metadata/metadata_thumbnail.dart';
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:aves/utils/time_utils.dart';
|
|||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||
import 'package:aves/widgets/common/fx/borders.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:aves/widgets/viewer/overlay/common.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -175,14 +175,17 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
|||
Text(entry.durationText),
|
||||
],
|
||||
),
|
||||
StreamBuilder<int>(
|
||||
stream: controller.positionStream,
|
||||
builder: (context, snapshot) {
|
||||
// do not use stream snapshot because it is obsolete when switching between videos
|
||||
var progress = controller.progress;
|
||||
if (!progress.isFinite) progress = 0.0;
|
||||
return LinearProgressIndicator(value: progress);
|
||||
}),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: StreamBuilder<int>(
|
||||
stream: controller.positionStream,
|
||||
builder: (context, snapshot) {
|
||||
// do not use stream snapshot because it is obsolete when switching between videos
|
||||
var progress = controller.progress;
|
||||
if (!progress.isFinite) progress = 0.0;
|
||||
return LinearProgressIndicator(value: progress);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'package:aves/widgets/common/magnifier/magnifier.dart';
|
|||
import 'package:aves/widgets/common/magnifier/scale/scale_boundaries.dart';
|
||||
import 'package:aves/widgets/common/magnifier/scale/scale_level.dart';
|
||||
import 'package:aves/widgets/common/magnifier/scale/state.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:aves/widgets/viewer/hero.dart';
|
||||
import 'package:aves/widgets/viewer/visual/error.dart';
|
||||
import 'package:aves/widgets/viewer/visual/raster.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:aves/model/entry.dart';
|
|||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:aves/widgets/common/video/video.dart';
|
||||
import 'package:aves/widgets/common/video/controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class VideoView extends StatefulWidget {
|
||||
|
@ -53,17 +53,14 @@ class _VideoViewState extends State<VideoView> {
|
|||
widget.controller.playCompletedListenable.removeListener(_onPlayCompleted);
|
||||
}
|
||||
|
||||
bool isPlayable(VideoStatus status) => controller != null && [VideoStatus.prepared, VideoStatus.playing, VideoStatus.paused, VideoStatus.completed].contains(status);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (controller == null) return SizedBox();
|
||||
return StreamBuilder<VideoStatus>(
|
||||
stream: widget.controller.statusStream,
|
||||
builder: (context, snapshot) {
|
||||
final status = snapshot.data;
|
||||
return isPlayable(status)
|
||||
? controller.buildPlayerWidget(entry)
|
||||
return controller?.isPlayable == true
|
||||
? controller.buildPlayerWidget(context, entry)
|
||||
: Image(
|
||||
image: entry.getBestThumbnail(settings.getTileExtent(CollectionPage.routeName)),
|
||||
fit: BoxFit.contain,
|
||||
|
|
|
@ -211,7 +211,7 @@ packages:
|
|||
description:
|
||||
path: "."
|
||||
ref: aves
|
||||
resolved-ref: c48e515a98851e55c857308d5482cd7bf5c9faad
|
||||
resolved-ref: "7171c3ede20f407b523c18692572cbcd12acc169"
|
||||
url: "git://github.com/deckerst/fijkplayer.git"
|
||||
source: git
|
||||
version: "0.8.7"
|
||||
|
|
Loading…
Reference in a new issue