video: switched to fijkplayer, optional HW acceleration [WIP]
This commit is contained in:
parent
8d90d6c698
commit
3ddf44b6cc
11 changed files with 328 additions and 313 deletions
BIN
android/app/libs/fijkplayer-full-release.aar
Normal file
BIN
android/app/libs/fijkplayer-full-release.aar
Normal file
Binary file not shown.
|
@ -542,6 +542,8 @@
|
||||||
"@settingsSectionVideo": {},
|
"@settingsSectionVideo": {},
|
||||||
"settingsVideoShowVideos": "Show videos",
|
"settingsVideoShowVideos": "Show videos",
|
||||||
"@settingsVideoShowVideos": {},
|
"@settingsVideoShowVideos": {},
|
||||||
|
"settingsVideoEnableHardwareAcceleration": "Enable hardware acceleration",
|
||||||
|
"@settingsVideoEnableHardwareAcceleration": {},
|
||||||
|
|
||||||
"settingsSectionPrivacy": "Privacy",
|
"settingsSectionPrivacy": "Privacy",
|
||||||
"@settingsSectionPrivacy": {},
|
"@settingsSectionPrivacy": {},
|
||||||
|
|
|
@ -252,6 +252,7 @@
|
||||||
|
|
||||||
"settingsSectionVideo": "동영상",
|
"settingsSectionVideo": "동영상",
|
||||||
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
||||||
|
"settingsVideoEnableHardwareAcceleration": "하드웨어 가속 사용",
|
||||||
|
|
||||||
"settingsSectionPrivacy": "개인정보 보호",
|
"settingsSectionPrivacy": "개인정보 보호",
|
||||||
"settingsEnableAnalytics": "진단 데이터 보내기",
|
"settingsEnableAnalytics": "진단 데이터 보내기",
|
||||||
|
|
|
@ -49,6 +49,9 @@ class Settings extends ChangeNotifier {
|
||||||
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
|
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
|
||||||
static const viewerQuickActionsKey = 'viewer_quick_actions';
|
static const viewerQuickActionsKey = 'viewer_quick_actions';
|
||||||
|
|
||||||
|
// video
|
||||||
|
static const isVideoHardwareAccelerationEnabledKey = 'video_hwaccel_mediacodec';
|
||||||
|
|
||||||
// info
|
// info
|
||||||
static const infoMapStyleKey = 'info_map_style';
|
static const infoMapStyleKey = 'info_map_style';
|
||||||
static const infoMapZoomKey = 'info_map_zoom';
|
static const infoMapZoomKey = 'info_map_zoom';
|
||||||
|
@ -223,6 +226,12 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set viewerQuickActions(List<EntryAction> newValue) => setAndNotify(viewerQuickActionsKey, newValue.map((v) => v.toString()).toList());
|
set viewerQuickActions(List<EntryAction> newValue) => setAndNotify(viewerQuickActionsKey, newValue.map((v) => v.toString()).toList());
|
||||||
|
|
||||||
|
// video
|
||||||
|
|
||||||
|
set isVideoHardwareAccelerationEnabled(bool newValue) => setAndNotify(isVideoHardwareAccelerationEnabledKey, newValue);
|
||||||
|
|
||||||
|
bool get isVideoHardwareAccelerationEnabled => getBoolOrDefault(isVideoHardwareAccelerationEnabledKey, true);
|
||||||
|
|
||||||
// info
|
// info
|
||||||
|
|
||||||
EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, EntryMapStyle.stamenWatercolor, EntryMapStyle.values);
|
EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, EntryMapStyle.stamenWatercolor, EntryMapStyle.values);
|
||||||
|
|
|
@ -1,119 +1,147 @@
|
||||||
// import 'dart:async';
|
import 'dart:async';
|
||||||
//
|
|
||||||
// import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
// import 'package:aves/utils/change_notifier.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
// import 'package:aves/widgets/common/video/video.dart';
|
import 'package:aves/utils/change_notifier.dart';
|
||||||
// import 'package:fijkplayer/fijkplayer.dart';
|
import 'package:aves/widgets/common/video/video.dart';
|
||||||
// import 'package:flutter/material.dart';
|
import 'package:fijkplayer/fijkplayer.dart';
|
||||||
//
|
import 'package:flutter/material.dart';
|
||||||
// class FijkPlayerAvesVideoController extends AvesVideoController {
|
|
||||||
// FijkPlayer _instance;
|
class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
// final List<StreamSubscription> _subscriptions = [];
|
FijkPlayer _instance;
|
||||||
// final StreamController<FijkValue> _valueStreamController = StreamController.broadcast();
|
final List<StreamSubscription> _subscriptions = [];
|
||||||
// final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
final StreamController<FijkValue> _valueStreamController = StreamController.broadcast();
|
||||||
//
|
final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||||
// Stream<FijkValue> get _valueStream => _valueStreamController.stream;
|
|
||||||
//
|
Stream<FijkValue> get _valueStream => _valueStreamController.stream;
|
||||||
// FijkPlayerAvesVideoController() {
|
|
||||||
// _instance = FijkPlayer();
|
IjkPlayerAvesVideoController() {
|
||||||
// _instance.addListener(_onValueChanged);
|
_instance = FijkPlayer();
|
||||||
// _subscriptions.add(_valueStream.where((value) => value.completed).listen((_) => _playFinishNotifier.notifyListeners()));
|
|
||||||
// }
|
// FFmpeg options
|
||||||
//
|
// cf https://github.com/Bilibili/ijkplayer/blob/master/ijkmedia/ijkplayer/ff_ffplay_options.h
|
||||||
// @override
|
// cf https://www.jianshu.com/p/843c86a9e9ad
|
||||||
// void dispose() {
|
|
||||||
// _instance.removeListener(_onValueChanged);
|
final option = FijkOption();
|
||||||
// _valueStreamController.close();
|
// `fastseek`: enable fast, but inaccurate seeks for some formats
|
||||||
// _subscriptions
|
option.setFormatOption('fflags', 'fastseek');
|
||||||
// ..forEach((sub) => sub.cancel())
|
// `enable-accurate-seek`: enable accurate seek, default: 0, in [0, 1]
|
||||||
// ..clear();
|
option.setPlayerOption('enable-accurate-seek', 1);
|
||||||
// _instance.release();
|
// `framedrop`: drop frames when cpu is too slow, default: 0, in [-1, 120]
|
||||||
// }
|
option.setPlayerOption('framedrop', 5);
|
||||||
//
|
|
||||||
// void _onValueChanged() => _valueStreamController.add(_instance.value);
|
final hwAccel = settings.isVideoHardwareAccelerationEnabled ? 1 : 0;
|
||||||
//
|
// `mediacodec-all-videos`: MediaCodec: enable all videos, default: 0, in [0, 1]
|
||||||
// // enable autoplay, even when seeking on uninitialized player, otherwise the texture is not updated
|
// TODO TLAD enabling `mediacodec-all-videos` randomly fails to render some videos, e.g. MP2TS/h264(HDPR)
|
||||||
// // as a workaround, pausing after a brief duration is possible, but fiddly
|
option.setPlayerOption('mediacodec-all-videos', hwAccel);
|
||||||
// @override
|
|
||||||
// Future<void> setDataSource(String uri) => _instance.setDataSource(uri, autoPlay: true);
|
// option.setPlayerOption('analyzemaxduration', 200 * 1024);
|
||||||
//
|
// option.setPlayerOption('analyzeduration', 200 * 1024);
|
||||||
// @override
|
// option.setPlayerOption('probesize', 1024 * 1024);
|
||||||
// Future<void> refreshVideoInfo() => null;
|
|
||||||
//
|
// TODO TLAD check looping
|
||||||
// @override
|
// option.setPlayerOption('loop', 42);
|
||||||
// Future<void> play() => _instance.start();
|
|
||||||
//
|
_instance.applyOptions(option);
|
||||||
// @override
|
|
||||||
// Future<void> pause() => _instance.pause();
|
_instance.addListener(_onValueChanged);
|
||||||
//
|
_subscriptions.add(_valueStream.where((value) => value.completed).listen((_) => _playFinishNotifier.notifyListeners()));
|
||||||
// @override
|
}
|
||||||
// Future<void> seekTo(int targetMillis) => _instance.seekTo(targetMillis);
|
|
||||||
//
|
@override
|
||||||
// @override
|
void dispose() {
|
||||||
// Future<void> seekToProgress(double progress) => _instance.seekTo((duration * progress).toInt());
|
_instance.removeListener(_onValueChanged);
|
||||||
//
|
_valueStreamController.close();
|
||||||
// @override
|
_subscriptions
|
||||||
// Listenable get playCompletedListenable => _playFinishNotifier;
|
..forEach((sub) => sub.cancel())
|
||||||
//
|
..clear();
|
||||||
// @override
|
_instance.release();
|
||||||
// VideoStatus get status => _instance.state.toAves;
|
}
|
||||||
//
|
|
||||||
// @override
|
void _onValueChanged() => _valueStreamController.add(_instance.value);
|
||||||
// Stream<VideoStatus> get statusStream => _valueStream.map((value) => value.state.toAves);
|
|
||||||
//
|
// enable autoplay, even when seeking on uninitialized player, otherwise the texture is not updated
|
||||||
// @override
|
// as a workaround, pausing after a brief duration is possible, but fiddly
|
||||||
// bool get isVideoReady => _instance.value.videoRenderStart;
|
@override
|
||||||
//
|
Future<void> setDataSource(String uri) => _instance.setDataSource(uri, autoPlay: true);
|
||||||
// @override
|
|
||||||
// Stream<bool> get isVideoReadyStream => _valueStream.map((value) => value.videoRenderStart);
|
@override
|
||||||
//
|
Future<void> refreshVideoInfo() => null;
|
||||||
// // we check whether video info is ready instead of checking for `noDatasource` status,
|
|
||||||
// // as the controller could also be uninitialized with the `pause` status
|
@override
|
||||||
// // (e.g. when switching between video entries without playing them the first time)
|
Future<void> play() => _instance.start();
|
||||||
// @override
|
|
||||||
// bool get isPlayable => _instance.isPlayable();
|
@override
|
||||||
//
|
Future<void> pause() => _instance.pause();
|
||||||
// @override
|
|
||||||
// int get duration => _instance.value.duration.inMilliseconds;
|
@override
|
||||||
//
|
Future<void> seekTo(int targetMillis) => _instance.seekTo(targetMillis);
|
||||||
// @override
|
|
||||||
// int get currentPosition => _instance.currentPos.inMilliseconds;
|
@override
|
||||||
//
|
Future<void> seekToProgress(double progress) => _instance.seekTo((duration * progress).toInt());
|
||||||
// @override
|
|
||||||
// Stream<int> get positionStream => _instance.onCurrentPosUpdate.map((pos) => pos.inMilliseconds);
|
@override
|
||||||
//
|
Listenable get playCompletedListenable => _playFinishNotifier;
|
||||||
// @override
|
|
||||||
// Widget buildPlayerWidget(AvesEntry entry) => FijkView(
|
@override
|
||||||
// player: _instance,
|
VideoStatus get status => _instance.state.toAves;
|
||||||
// panelBuilder: (player, data, context, viewSize, texturePos) => SizedBox(),
|
|
||||||
// color: Colors.transparent,
|
@override
|
||||||
// );
|
Stream<VideoStatus> get statusStream => _valueStream.map((value) => value.state.toAves);
|
||||||
// }
|
|
||||||
//
|
@override
|
||||||
// extension ExtraIjkStatus on FijkState {
|
bool get isVideoReady => _instance.value.videoRenderStart;
|
||||||
// VideoStatus get toAves {
|
|
||||||
// switch (this) {
|
@override
|
||||||
// case FijkState.idle:
|
Stream<bool> get isVideoReadyStream => _valueStream.map((value) => value.videoRenderStart);
|
||||||
// return VideoStatus.idle;
|
|
||||||
// case FijkState.initialized:
|
// we check whether video info is ready instead of checking for `noDatasource` status,
|
||||||
// return VideoStatus.initialized;
|
// as the controller could also be uninitialized with the `pause` status
|
||||||
// case FijkState.asyncPreparing:
|
// (e.g. when switching between video entries without playing them the first time)
|
||||||
// return VideoStatus.preparing;
|
@override
|
||||||
// case FijkState.prepared:
|
bool get isPlayable => _instance.isPlayable();
|
||||||
// return VideoStatus.prepared;
|
|
||||||
// case FijkState.started:
|
@override
|
||||||
// return VideoStatus.playing;
|
int get duration => _instance.value.duration.inMilliseconds;
|
||||||
// case FijkState.paused:
|
|
||||||
// return VideoStatus.paused;
|
@override
|
||||||
// case FijkState.completed:
|
int get currentPosition => _instance.currentPos.inMilliseconds;
|
||||||
// return VideoStatus.completed;
|
|
||||||
// case FijkState.stopped:
|
@override
|
||||||
// return VideoStatus.stopped;
|
Stream<int> get positionStream => _instance.onCurrentPosUpdate.map((pos) => pos.inMilliseconds);
|
||||||
// case FijkState.end:
|
|
||||||
// return VideoStatus.disposed;
|
@override
|
||||||
// case FijkState.error:
|
Widget buildPlayerWidget(AvesEntry entry) => FijkView(
|
||||||
// return VideoStatus.error;
|
player: _instance,
|
||||||
// }
|
panelBuilder: (player, data, context, viewSize, texturePos) => SizedBox(),
|
||||||
// return VideoStatus.idle;
|
color: Colors.transparent,
|
||||||
// }
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
extension ExtraIjkStatus on FijkState {
|
||||||
|
VideoStatus get toAves {
|
||||||
|
switch (this) {
|
||||||
|
case FijkState.idle:
|
||||||
|
return VideoStatus.idle;
|
||||||
|
case FijkState.initialized:
|
||||||
|
return VideoStatus.initialized;
|
||||||
|
case FijkState.asyncPreparing:
|
||||||
|
return VideoStatus.preparing;
|
||||||
|
case FijkState.prepared:
|
||||||
|
return VideoStatus.prepared;
|
||||||
|
case FijkState.started:
|
||||||
|
return VideoStatus.playing;
|
||||||
|
case FijkState.paused:
|
||||||
|
return VideoStatus.paused;
|
||||||
|
case FijkState.completed:
|
||||||
|
return VideoStatus.completed;
|
||||||
|
case FijkState.stopped:
|
||||||
|
return VideoStatus.stopped;
|
||||||
|
case FijkState.end:
|
||||||
|
return VideoStatus.disposed;
|
||||||
|
case FijkState.error:
|
||||||
|
return VideoStatus.error;
|
||||||
|
}
|
||||||
|
return VideoStatus.idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,144 +1,144 @@
|
||||||
import 'dart:async';
|
// import 'dart:async';
|
||||||
|
//
|
||||||
import 'package:aves/model/entry.dart';
|
// import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/utils/change_notifier.dart';
|
// import 'package:aves/utils/change_notifier.dart';
|
||||||
import 'package:aves/widgets/common/video/video.dart';
|
// import 'package:aves/widgets/common/video/video.dart';
|
||||||
import 'package:flutter/material.dart';
|
// import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
|
// import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
|
||||||
|
//
|
||||||
class FlutterIjkPlayerAvesVideoController extends AvesVideoController {
|
// class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
IjkMediaController _instance;
|
// IjkMediaController _instance;
|
||||||
final List<StreamSubscription> _subscriptions = [];
|
// final List<StreamSubscription> _subscriptions = [];
|
||||||
final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
// final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||||
|
//
|
||||||
FlutterIjkPlayerAvesVideoController() {
|
// IjkPlayerAvesVideoController() {
|
||||||
_instance = IjkMediaController();
|
// _instance = IjkMediaController();
|
||||||
_subscriptions.add(_instance.playFinishStream.listen((_) => _playFinishNotifier.notifyListeners()));
|
// _subscriptions.add(_instance.playFinishStream.listen((_) => _playFinishNotifier.notifyListeners()));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
void dispose() {
|
// void dispose() {
|
||||||
_subscriptions
|
// _subscriptions
|
||||||
..forEach((sub) => sub.cancel())
|
// ..forEach((sub) => sub.cancel())
|
||||||
..clear();
|
// ..clear();
|
||||||
_instance?.dispose();
|
// _instance?.dispose();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// enable autoplay, even when seeking on uninitialized player, otherwise the texture is not updated
|
// // enable autoplay, even when seeking on uninitialized player, otherwise the texture is not updated
|
||||||
// as a workaround, pausing after a brief duration is possible, but fiddly
|
// // as a workaround, pausing after a brief duration is possible, but fiddly
|
||||||
@override
|
// @override
|
||||||
Future<void> setDataSource(String uri) => _instance.setDataSource(DataSource.photoManagerUrl(uri), autoPlay: true);
|
// Future<void> setDataSource(String uri) => _instance.setDataSource(DataSource.photoManagerUrl(uri), autoPlay: true);
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Future<void> refreshVideoInfo() => _instance.refreshVideoInfo();
|
// Future<void> refreshVideoInfo() => _instance.refreshVideoInfo();
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Future<void> play() => _instance.play();
|
// Future<void> play() => _instance.play();
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Future<void> pause() => _instance.pause();
|
// Future<void> pause() => _instance.pause();
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Future<void> seekTo(int targetMillis) => _instance.seekTo(targetMillis / 1000.0);
|
// Future<void> seekTo(int targetMillis) => _instance.seekTo(targetMillis / 1000.0);
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Future<void> seekToProgress(double progress) => _instance.seekToProgress(progress);
|
// Future<void> seekToProgress(double progress) => _instance.seekToProgress(progress);
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Listenable get playCompletedListenable => _playFinishNotifier;
|
// Listenable get playCompletedListenable => _playFinishNotifier;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
VideoStatus get status => _instance.ijkStatus.toAves;
|
// VideoStatus get status => _instance.ijkStatus.toAves;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Stream<VideoStatus> get statusStream => _instance.ijkStatusStream.map((status) => status.toAves);
|
// Stream<VideoStatus> get statusStream => _instance.ijkStatusStream.map((status) => status.toAves);
|
||||||
|
//
|
||||||
// we check whether video info is ready instead of checking for `noDatasource` status,
|
// // we check whether video info is ready instead of checking for `noDatasource` status,
|
||||||
// as the controller could also be uninitialized with the `pause` 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)
|
// // (e.g. when switching between video entries without playing them the first time)
|
||||||
@override
|
// @override
|
||||||
bool get isPlayable => _videoInfo.hasData;
|
// bool get isPlayable => _videoInfo.hasData;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
bool get isVideoReady => _instance.textureId != null;
|
// bool get isVideoReady => _instance.textureId != null;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Stream<bool> get isVideoReadyStream => _instance.textureIdStream.map((id) => id != null);
|
// Stream<bool> get isVideoReadyStream => _instance.textureIdStream.map((id) => id != null);
|
||||||
|
//
|
||||||
// `videoInfo` is never null (even if `toString` prints `null`)
|
// // `videoInfo` is never null (even if `toString` prints `null`)
|
||||||
// check presence with `hasData` instead
|
// // check presence with `hasData` instead
|
||||||
VideoInfo get _videoInfo => _instance.videoInfo;
|
// VideoInfo get _videoInfo => _instance.videoInfo;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
int get duration => _videoInfo.durationMillis;
|
// int get duration => _videoInfo.durationMillis;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
int get currentPosition => _videoInfo.currentPositionMillis;
|
// int get currentPosition => _videoInfo.currentPositionMillis;
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Stream<int> get positionStream => _instance.videoInfoStream.map((info) => info.currentPositionMillis);
|
// Stream<int> get positionStream => _instance.videoInfoStream.map((info) => info.currentPositionMillis);
|
||||||
|
//
|
||||||
@override
|
// @override
|
||||||
Widget buildPlayerWidget(AvesEntry entry) => IjkPlayer(
|
// Widget buildPlayerWidget(AvesEntry entry) => IjkPlayer(
|
||||||
mediaController: _instance,
|
// mediaController: _instance,
|
||||||
controllerWidgetBuilder: (controller) => SizedBox.shrink(),
|
// controllerWidgetBuilder: (controller) => SizedBox.shrink(),
|
||||||
statusWidgetBuilder: (context, controller, status) => SizedBox.shrink(),
|
// statusWidgetBuilder: (context, controller, status) => SizedBox.shrink(),
|
||||||
textureBuilder: (context, controller, info) {
|
// textureBuilder: (context, controller, info) {
|
||||||
var id = controller.textureId;
|
// var id = controller.textureId;
|
||||||
var child = id != null
|
// var child = id != null
|
||||||
? Texture(
|
// ? Texture(
|
||||||
textureId: id,
|
// textureId: id,
|
||||||
)
|
// )
|
||||||
: Container(
|
// : Container(
|
||||||
color: Colors.black,
|
// color: Colors.black,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
final degree = entry.rotationDegrees ?? 0;
|
// final degree = entry.rotationDegrees ?? 0;
|
||||||
if (degree != 0) {
|
// if (degree != 0) {
|
||||||
child = RotatedBox(
|
// child = RotatedBox(
|
||||||
quarterTurns: degree ~/ 90,
|
// quarterTurns: degree ~/ 90,
|
||||||
child: child,
|
// child: child,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return Center(
|
// return Center(
|
||||||
child: AspectRatio(
|
// child: AspectRatio(
|
||||||
aspectRatio: entry.displayAspectRatio,
|
// aspectRatio: entry.displayAspectRatio,
|
||||||
child: child,
|
// child: child,
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
backgroundColor: Colors.transparent,
|
// backgroundColor: Colors.transparent,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
extension ExtraVideoInfo on VideoInfo {
|
// extension ExtraVideoInfo on VideoInfo {
|
||||||
int get durationMillis => duration == null ? null : (duration * 1000).toInt();
|
// int get durationMillis => duration == null ? null : (duration * 1000).toInt();
|
||||||
|
//
|
||||||
int get currentPositionMillis => currentPosition == null ? null : (currentPosition * 1000).toInt();
|
// int get currentPositionMillis => currentPosition == null ? null : (currentPosition * 1000).toInt();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
extension ExtraIjkStatus on IjkStatus {
|
// extension ExtraIjkStatus on IjkStatus {
|
||||||
VideoStatus get toAves {
|
// VideoStatus get toAves {
|
||||||
switch (this) {
|
// switch (this) {
|
||||||
case IjkStatus.noDatasource:
|
// case IjkStatus.noDatasource:
|
||||||
return VideoStatus.idle;
|
// return VideoStatus.idle;
|
||||||
case IjkStatus.preparing:
|
// case IjkStatus.preparing:
|
||||||
return VideoStatus.preparing;
|
// return VideoStatus.preparing;
|
||||||
case IjkStatus.prepared:
|
// case IjkStatus.prepared:
|
||||||
return VideoStatus.prepared;
|
// return VideoStatus.prepared;
|
||||||
case IjkStatus.playing:
|
// case IjkStatus.playing:
|
||||||
return VideoStatus.playing;
|
// return VideoStatus.playing;
|
||||||
case IjkStatus.pause:
|
// case IjkStatus.pause:
|
||||||
return VideoStatus.paused;
|
// return VideoStatus.paused;
|
||||||
case IjkStatus.complete:
|
// case IjkStatus.complete:
|
||||||
return VideoStatus.completed;
|
// return VideoStatus.completed;
|
||||||
case IjkStatus.disposed:
|
// case IjkStatus.disposed:
|
||||||
return VideoStatus.disposed;
|
// return VideoStatus.disposed;
|
||||||
case IjkStatus.setDatasourceFail:
|
// case IjkStatus.setDatasourceFail:
|
||||||
case IjkStatus.error:
|
// case IjkStatus.error:
|
||||||
return VideoStatus.error;
|
// return VideoStatus.error;
|
||||||
}
|
// }
|
||||||
return VideoStatus.idle;
|
// return VideoStatus.idle;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
// import 'package:aves/widgets/common/video/fijkplayer.dart';
|
import 'package:aves/widgets/common/video/fijkplayer.dart';
|
||||||
import 'package:aves/widgets/common/video/flutter_ijkplayer.dart';
|
// import 'package:aves/widgets/common/video/flutter_ijkplayer.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
abstract class AvesVideoController {
|
abstract class AvesVideoController {
|
||||||
AvesVideoController();
|
AvesVideoController();
|
||||||
|
|
||||||
factory AvesVideoController.flutterIjkPlayer() => FlutterIjkPlayerAvesVideoController();
|
factory AvesVideoController.ijkPlayer() => IjkPlayerAvesVideoController();
|
||||||
|
|
||||||
// factory AvesVideoController.fijkPlayer() => FijkPlayerAvesVideoController();
|
|
||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,11 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
onChanged: (v) => context.read<CollectionSource>().changeFilterVisibility(MimeFilter.video, v),
|
onChanged: (v) => context.read<CollectionSource>().changeFilterVisibility(MimeFilter.video, v),
|
||||||
title: Text(context.l10n.settingsVideoShowVideos),
|
title: Text(context.l10n.settingsVideoShowVideos),
|
||||||
),
|
),
|
||||||
|
SwitchListTile(
|
||||||
|
value: settings.isVideoHardwareAccelerationEnabled,
|
||||||
|
onChanged: (v) => settings.isVideoHardwareAccelerationEnabled = v,
|
||||||
|
title: Text(context.l10n.settingsVideoEnableHardwareAcceleration),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,7 +499,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
_initViewSpecificController<AvesVideoController>(
|
_initViewSpecificController<AvesVideoController>(
|
||||||
uri,
|
uri,
|
||||||
_videoControllers,
|
_videoControllers,
|
||||||
() => AvesVideoController.flutterIjkPlayer(),
|
() => AvesVideoController.ijkPlayer(),
|
||||||
(_) => _.dispose(),
|
(_) => _.dispose(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
18
pubspec.lock
18
pubspec.lock
|
@ -206,6 +206,15 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
fijkplayer:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: aves
|
||||||
|
resolved-ref: c48e515a98851e55c857308d5482cd7bf5c9faad
|
||||||
|
url: "git://github.com/deckerst/fijkplayer.git"
|
||||||
|
source: git
|
||||||
|
version: "0.8.7"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -300,15 +309,6 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.0"
|
||||||
flutter_ijkplayer:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: HEAD
|
|
||||||
resolved-ref: d4e079404ba8e4f82a7e053ffdc47af787a61c3b
|
|
||||||
url: "git://github.com/deckerst/flutter_ijkplayer.git"
|
|
||||||
source: git
|
|
||||||
version: "0.3.7"
|
|
||||||
flutter_image:
|
flutter_image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
42
pubspec.yaml
42
pubspec.yaml
|
@ -15,7 +15,7 @@ environment:
|
||||||
|
|
||||||
# not null safe, as of 2021/03/13
|
# not null safe, as of 2021/03/13
|
||||||
# `charts_flutter` - https://github.com/google/charts/issues/579
|
# `charts_flutter` - https://github.com/google/charts/issues/579
|
||||||
# `flutter_ijkplayer` - unmaintained?
|
# `fijkplayer` - https://github.com/befovy/fijkplayer/issues/381
|
||||||
# `flutter_map` - https://github.com/fleaflet/flutter_map/issues/829
|
# `flutter_map` - https://github.com/fleaflet/flutter_map/issues/829
|
||||||
# `latlong` - archived - migrate to maps_toolkit? cf https://github.com/fleaflet/flutter_map/pull/750
|
# `latlong` - archived - migrate to maps_toolkit? cf https://github.com/fleaflet/flutter_map/pull/750
|
||||||
# `streams_channel` - unmaintained? - no issue/PR
|
# `streams_channel` - unmaintained? - no issue/PR
|
||||||
|
@ -32,21 +32,19 @@ dependencies:
|
||||||
decorated_icon:
|
decorated_icon:
|
||||||
event_bus:
|
event_bus:
|
||||||
expansion_tile_card:
|
expansion_tile_card:
|
||||||
# path: ../expansion_tile_card
|
|
||||||
git:
|
git:
|
||||||
url: git://github.com/deckerst/expansion_tile_card.git
|
url: git://github.com/deckerst/expansion_tile_card.git
|
||||||
|
fijkplayer:
|
||||||
|
git:
|
||||||
|
url: git://github.com/deckerst/fijkplayer.git
|
||||||
|
ref: aves
|
||||||
firebase_core:
|
firebase_core:
|
||||||
firebase_analytics:
|
firebase_analytics:
|
||||||
firebase_crashlytics:
|
firebase_crashlytics:
|
||||||
flutter_highlight:
|
flutter_highlight:
|
||||||
# fijkplayer:
|
# flutter_ijkplayer:
|
||||||
## path: ../fijkplayer
|
|
||||||
# git:
|
# git:
|
||||||
# url: git://github.com/deckerst/fijkplayer.git
|
# url: git://github.com/deckerst/flutter_ijkplayer.git
|
||||||
# ref: aves-config
|
|
||||||
flutter_ijkplayer:
|
|
||||||
git:
|
|
||||||
url: git://github.com/deckerst/flutter_ijkplayer.git
|
|
||||||
flutter_localized_locales:
|
flutter_localized_locales:
|
||||||
flutter_map:
|
flutter_map:
|
||||||
flutter_markdown:
|
flutter_markdown:
|
||||||
|
@ -125,29 +123,3 @@ flutter:
|
||||||
|
|
||||||
# capture shaders in profile mode (real device only):
|
# capture shaders in profile mode (real device only):
|
||||||
# % flutter drive -t test_driver/app.dart --profile --cache-sksl --write-sksl-on-exit shaders.sksl.json
|
# % flutter drive -t test_driver/app.dart --profile --cache-sksl --write-sksl-on-exit shaders.sksl.json
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Package study
|
|
||||||
|
|
||||||
# brendan-duncan/image (as of v2.1.19):
|
|
||||||
# - does not support TIFF with JPEG compression (issue #184)
|
|
||||||
# - TIFF tile decoding is not public (issue #258)
|
|
||||||
|
|
||||||
# video_player (as of v0.10.8+2, backed by ExoPlayer):
|
|
||||||
# - does not support content URIs (by default, but trivial by fork)
|
|
||||||
# - does not support AVI/XVID, AC3
|
|
||||||
# - cannot play if only the video or audio stream is supported
|
|
||||||
|
|
||||||
# flutter_ijkplayer (as of v0.3.5+1, backed by IJKPlayer & ffmpeg):
|
|
||||||
# ~ support content URIs (`DataSource.photoManagerUrl` from v0.3.6, but need fork to support content URIs on Android <Q)
|
|
||||||
# + does not support AC3 (by default, but possible by custom build)
|
|
||||||
# + can play if only the video or audio stream is supported
|
|
||||||
# - edge smear on some videos, depending on dimensions (dimension not multiple of 16?)
|
|
||||||
# - unmaintained
|
|
||||||
|
|
||||||
# fijkplayer (as of v0.8.7, backed by IJKPlayer & ffmpeg):
|
|
||||||
# + support content URIs
|
|
||||||
# + does not support XVID, AC3 (by default, but possible by custom build)
|
|
||||||
# + can play if only the video or audio stream is supported
|
|
||||||
# + no edge smear (with default build)
|
|
||||||
# - crash when calling `seekTo` for some files, cf https://github.com/befovy/fijkplayer/issues/360
|
|
||||||
|
|
Loading…
Reference in a new issue