#34 video: auto play
This commit is contained in:
parent
9128380017
commit
a0f8b32440
12 changed files with 139 additions and 38 deletions
Binary file not shown.
|
@ -549,8 +549,10 @@
|
||||||
"@settingsSectionVideo": {},
|
"@settingsSectionVideo": {},
|
||||||
"settingsVideoShowVideos": "Show videos",
|
"settingsVideoShowVideos": "Show videos",
|
||||||
"@settingsVideoShowVideos": {},
|
"@settingsVideoShowVideos": {},
|
||||||
"settingsVideoEnableHardwareAcceleration": "Enable hardware acceleration",
|
"settingsVideoEnableHardwareAcceleration": "Hardware acceleration",
|
||||||
"@settingsVideoEnableHardwareAcceleration": {},
|
"@settingsVideoEnableHardwareAcceleration": {},
|
||||||
|
"settingsVideoEnableAutoPlay": "Auto play",
|
||||||
|
"@settingsVideoEnableAutoPlay": {},
|
||||||
"settingsVideoLoopModeTile": "Loop mode",
|
"settingsVideoLoopModeTile": "Loop mode",
|
||||||
"@settingsVideoLoopModeTile": {},
|
"@settingsVideoLoopModeTile": {},
|
||||||
"settingsVideoLoopModeTitle": "Loop Mode",
|
"settingsVideoLoopModeTitle": "Loop Mode",
|
||||||
|
|
|
@ -256,7 +256,8 @@
|
||||||
|
|
||||||
"settingsSectionVideo": "동영상",
|
"settingsSectionVideo": "동영상",
|
||||||
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
||||||
"settingsVideoEnableHardwareAcceleration": "하드웨어 가속 사용",
|
"settingsVideoEnableHardwareAcceleration": "하드웨어 가속",
|
||||||
|
"settingsVideoEnableAutoPlay": "자동 재생",
|
||||||
"settingsVideoLoopModeTile": "반복 모드",
|
"settingsVideoLoopModeTile": "반복 모드",
|
||||||
"settingsVideoLoopModeTitle": "반복 모드",
|
"settingsVideoLoopModeTitle": "반복 모드",
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,8 @@ class Settings extends ChangeNotifier {
|
||||||
static const viewerQuickActionsKey = 'viewer_quick_actions';
|
static const viewerQuickActionsKey = 'viewer_quick_actions';
|
||||||
|
|
||||||
// video
|
// video
|
||||||
static const isVideoHardwareAccelerationEnabledKey = 'video_hwaccel_mediacodec';
|
static const enableVideoHardwareAccelerationKey = 'video_hwaccel_mediacodec';
|
||||||
|
static const enableVideoAutoPlayKey = 'video_auto_play';
|
||||||
static const videoLoopModeKey = 'video_loop';
|
static const videoLoopModeKey = 'video_loop';
|
||||||
|
|
||||||
// info
|
// info
|
||||||
|
@ -229,9 +230,13 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
// video
|
// video
|
||||||
|
|
||||||
set isVideoHardwareAccelerationEnabled(bool newValue) => setAndNotify(isVideoHardwareAccelerationEnabledKey, newValue);
|
set enableVideoHardwareAcceleration(bool newValue) => setAndNotify(enableVideoHardwareAccelerationKey, newValue);
|
||||||
|
|
||||||
bool get isVideoHardwareAccelerationEnabled => getBoolOrDefault(isVideoHardwareAccelerationEnabledKey, true);
|
bool get enableVideoHardwareAcceleration => getBoolOrDefault(enableVideoHardwareAccelerationKey, true);
|
||||||
|
|
||||||
|
set enableVideoAutoPlay(bool newValue) => setAndNotify(enableVideoAutoPlayKey, newValue);
|
||||||
|
|
||||||
|
bool get enableVideoAutoPlay => getBoolOrDefault(enableVideoAutoPlayKey, false);
|
||||||
|
|
||||||
VideoLoopMode get videoLoopMode => getEnumOrDefault(videoLoopModeKey, VideoLoopMode.shortOnly, VideoLoopMode.values);
|
VideoLoopMode get videoLoopMode => getEnumOrDefault(videoLoopModeKey, VideoLoopMode.shortOnly, VideoLoopMode.values);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:aves/utils/file_utils.dart';
|
||||||
import 'package:aves/utils/math_utils.dart';
|
import 'package:aves/utils/math_utils.dart';
|
||||||
import 'package:aves/utils/string_utils.dart';
|
import 'package:aves/utils/string_utils.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
|
import 'package:aves/widgets/common/video/fijkplayer.dart';
|
||||||
import 'package:fijkplayer/fijkplayer.dart';
|
import 'package:fijkplayer/fijkplayer.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
@ -32,20 +33,7 @@ class VideoMetadataFormatter {
|
||||||
|
|
||||||
static Future<Map> getVideoMetadata(AvesEntry entry) async {
|
static Future<Map> getVideoMetadata(AvesEntry entry) async {
|
||||||
final player = FijkPlayer();
|
final player = FijkPlayer();
|
||||||
await player.setDataSource(entry.uri, autoPlay: false);
|
await player.setDataSourceUntilPrepared(entry.uri);
|
||||||
|
|
||||||
final completer = Completer();
|
|
||||||
void onChange() {
|
|
||||||
if ([FijkState.prepared, FijkState.error].contains(player.state)) {
|
|
||||||
completer.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player.addListener(onChange);
|
|
||||||
await player.prepareAsync();
|
|
||||||
await completer.future;
|
|
||||||
player.removeListener(onChange);
|
|
||||||
|
|
||||||
final info = await player.getInfo();
|
final info = await player.getInfo();
|
||||||
await player.release();
|
await player.release();
|
||||||
return info;
|
return info;
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Durations {
|
||||||
static const viewerOverlayChangeAnimation = Duration(milliseconds: 150);
|
static const viewerOverlayChangeAnimation = Duration(milliseconds: 150);
|
||||||
static const viewerOverlayPageScrollAnimation = Duration(milliseconds: 200);
|
static const viewerOverlayPageScrollAnimation = Duration(milliseconds: 200);
|
||||||
static const viewerOverlayPageShadeAnimation = Duration(milliseconds: 150);
|
static const viewerOverlayPageShadeAnimation = Duration(milliseconds: 150);
|
||||||
|
static const viewerVideoPlayerTransition = Duration(milliseconds: 500);
|
||||||
|
|
||||||
// info animations
|
// info animations
|
||||||
static const mapStyleSwitchAnimation = Duration(milliseconds: 300);
|
static const mapStyleSwitchAnimation = Duration(milliseconds: 300);
|
||||||
|
|
|
@ -24,9 +24,13 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
final ValueNotifier<StreamSummary> _selectedAudioStream = ValueNotifier(null);
|
final ValueNotifier<StreamSummary> _selectedAudioStream = ValueNotifier(null);
|
||||||
final ValueNotifier<StreamSummary> _selectedTextStream = ValueNotifier(null);
|
final ValueNotifier<StreamSummary> _selectedTextStream = ValueNotifier(null);
|
||||||
final ValueNotifier<Tuple2<int, int>> _sar = ValueNotifier(Tuple2(1, 1));
|
final ValueNotifier<Tuple2<int, int>> _sar = ValueNotifier(Tuple2(1, 1));
|
||||||
|
Timer _initialPlayTimer;
|
||||||
|
|
||||||
Stream<FijkValue> get _valueStream => _valueStreamController.stream;
|
Stream<FijkValue> get _valueStream => _valueStreamController.stream;
|
||||||
|
|
||||||
|
static const initialPlayDelay = Duration(milliseconds: 100);
|
||||||
|
static const gifLikeVideoDurationThreshold = Duration(seconds: 10);
|
||||||
|
|
||||||
IjkPlayerAvesVideoController(AvesEntry entry) {
|
IjkPlayerAvesVideoController(AvesEntry entry) {
|
||||||
FijkLog.setLevel(FijkLogLevel.Warn);
|
FijkLog.setLevel(FijkLogLevel.Warn);
|
||||||
_instance = FijkPlayer();
|
_instance = FijkPlayer();
|
||||||
|
@ -42,10 +46,14 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
// player cannot be dynamically set to use accurate seek only when playing
|
// player cannot be dynamically set to use accurate seek only when playing
|
||||||
const accurateSeekEnabled = false;
|
const accurateSeekEnabled = false;
|
||||||
|
|
||||||
// when HW acceleration is enabled, videos with dimensions that do not fit 16x macroblocks need cropping
|
// playing with HW acceleration seems to skip the last frames of some videos
|
||||||
|
// so HW acceleration is always disabled for gif-like videos where the last frames may be significant
|
||||||
|
final hwAccelerationEnabled = settings.enableVideoHardwareAcceleration && entry.durationMillis > gifLikeVideoDurationThreshold.inMilliseconds;
|
||||||
|
|
||||||
// TODO TLAD HW codecs sometimes fail when seek-starting some videos, e.g. MP2TS/h264(HDPR)
|
// TODO TLAD HW codecs sometimes fail when seek-starting some videos, e.g. MP2TS/h264(HDPR)
|
||||||
final hwAccelerationEnabled = settings.isVideoHardwareAccelerationEnabled;
|
|
||||||
if (hwAccelerationEnabled) {
|
if (hwAccelerationEnabled) {
|
||||||
|
// when HW acceleration is enabled, videos with dimensions that do not fit 16x macroblocks need cropping
|
||||||
|
// TODO TLAD not all formats/devices need this correction, e.g. 498x278 MP4 on S7, 408x244 WEBM on S10e do not
|
||||||
final s = entry.displaySize % 16 * -1 % 16;
|
final s = entry.displaySize % 16 * -1 % 16;
|
||||||
_macroBlockCrop = Offset(s.width, s.height);
|
_macroBlockCrop = Offset(s.width, s.height);
|
||||||
}
|
}
|
||||||
|
@ -83,6 +91,7 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_initialPlayTimer?.cancel();
|
||||||
_instance.removeListener(_onValueChanged);
|
_instance.removeListener(_onValueChanged);
|
||||||
_valueStreamController.close();
|
_valueStreamController.close();
|
||||||
_subscriptions
|
_subscriptions
|
||||||
|
@ -142,7 +151,7 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
_valueStreamController.add(_instance.value);
|
_valueStreamController.add(_instance.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable autoplay, even when seeking on uninitialized player, otherwise the texture is not updated
|
// always start playing, 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, {int startMillis = 0}) async {
|
Future<void> setDataSource(String uri, {int startMillis = 0}) async {
|
||||||
|
@ -150,14 +159,28 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
// `seek-at-start`: set offset of player should be seeked, default: 0, in [0, INT_MAX]
|
// `seek-at-start`: set offset of player should be seeked, default: 0, in [0, INT_MAX]
|
||||||
await _instance.setOption(FijkOption.playerCategory, 'seek-at-start', startMillis);
|
await _instance.setOption(FijkOption.playerCategory, 'seek-at-start', startMillis);
|
||||||
}
|
}
|
||||||
await _instance.setDataSource(uri, autoPlay: true);
|
// calling `setDataSource()` with `autoPlay` starts as soon as possible, but often yields initial artifacts
|
||||||
|
// so we introduce a small delay after the player is declared `prepared`, before playing
|
||||||
|
await _instance.setDataSourceUntilPrepared(uri);
|
||||||
|
_initialPlayTimer = Timer(initialPlayDelay, play);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> play() => _instance.start();
|
Future<void> play() {
|
||||||
|
if (_instance.isPlayable()) {
|
||||||
|
_instance.start();
|
||||||
|
}
|
||||||
|
return SynchronousFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> pause() => _instance.pause();
|
Future<void> pause() {
|
||||||
|
if (_instance.isPlayable()) {
|
||||||
|
_initialPlayTimer?.cancel();
|
||||||
|
_instance.pause();
|
||||||
|
}
|
||||||
|
return SynchronousFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> seekTo(int targetMillis) => _instance.seekTo(targetMillis);
|
Future<void> seekTo(int targetMillis) => _instance.seekTo(targetMillis);
|
||||||
|
@ -199,7 +222,7 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
fit: FijkFit(
|
fit: FijkFit(
|
||||||
sizeFactor: 1.0,
|
sizeFactor: 1.0,
|
||||||
aspectRatio: dar,
|
aspectRatio: dar,
|
||||||
alignment: Alignment.topLeft,
|
alignment: _alignmentForRotation(entry.rotationDegrees),
|
||||||
macroBlockCrop: _macroBlockCrop,
|
macroBlockCrop: _macroBlockCrop,
|
||||||
),
|
),
|
||||||
panelBuilder: (player, data, context, viewSize, texturePos) => SizedBox(),
|
panelBuilder: (player, data, context, viewSize, texturePos) => SizedBox(),
|
||||||
|
@ -207,6 +230,20 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Alignment _alignmentForRotation(int rotation) {
|
||||||
|
switch (rotation) {
|
||||||
|
case 90:
|
||||||
|
return Alignment.topRight;
|
||||||
|
case 180:
|
||||||
|
return Alignment.bottomRight;
|
||||||
|
case 270:
|
||||||
|
return Alignment.bottomLeft;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return Alignment.topLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraIjkStatus on FijkState {
|
extension ExtraIjkStatus on FijkState {
|
||||||
|
@ -233,6 +270,32 @@ extension ExtraIjkStatus on FijkState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ExtraFijkPlayer on FijkPlayer {
|
||||||
|
Future<void> setDataSourceUntilPrepared(String uri) async {
|
||||||
|
await setDataSource(uri, autoPlay: false);
|
||||||
|
|
||||||
|
final completer = Completer();
|
||||||
|
void onChange() {
|
||||||
|
switch (state) {
|
||||||
|
case FijkState.prepared:
|
||||||
|
removeListener(onChange);
|
||||||
|
completer.complete();
|
||||||
|
break;
|
||||||
|
case FijkState.error:
|
||||||
|
removeListener(onChange);
|
||||||
|
completer.completeError(value.exception);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addListener(onChange);
|
||||||
|
await prepareAsync();
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum StreamType { video, audio, text }
|
enum StreamType { video, audio, text }
|
||||||
|
|
||||||
extension ExtraStreamType on StreamType {
|
extension ExtraStreamType on StreamType {
|
||||||
|
|
|
@ -241,10 +241,15 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
title: Text(context.l10n.settingsVideoShowVideos),
|
title: Text(context.l10n.settingsVideoShowVideos),
|
||||||
),
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
value: settings.isVideoHardwareAccelerationEnabled,
|
value: settings.enableVideoHardwareAcceleration,
|
||||||
onChanged: (v) => settings.isVideoHardwareAccelerationEnabled = v,
|
onChanged: (v) => settings.enableVideoHardwareAcceleration = v,
|
||||||
title: Text(context.l10n.settingsVideoEnableHardwareAcceleration),
|
title: Text(context.l10n.settingsVideoEnableHardwareAcceleration),
|
||||||
),
|
),
|
||||||
|
SwitchListTile(
|
||||||
|
value: settings.enableVideoAutoPlay,
|
||||||
|
onChanged: (v) => settings.enableVideoAutoPlay = v,
|
||||||
|
title: Text(context.l10n.settingsVideoEnableAutoPlay),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(context.l10n.settingsVideoLoopModeTile),
|
title: Text(context.l10n.settingsVideoLoopModeTile),
|
||||||
subtitle: Text(settings.videoLoopMode.getName(context)),
|
subtitle: Text(settings.videoLoopMode.getName(context)),
|
||||||
|
|
|
@ -503,6 +503,9 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
() => IjkPlayerAvesVideoController(entry),
|
() => IjkPlayerAvesVideoController(entry),
|
||||||
(_) => _.dispose(),
|
(_) => _.dispose(),
|
||||||
);
|
);
|
||||||
|
if (settings.enableVideoAutoPlay) {
|
||||||
|
_playVideo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (entry.isMultipage) {
|
if (entry.isMultipage) {
|
||||||
_initViewSpecificController<MultiPageController>(
|
_initViewSpecificController<MultiPageController>(
|
||||||
|
@ -516,6 +519,22 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _playVideo() async {
|
||||||
|
await Future.delayed(Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
final entry = _entryNotifier.value;
|
||||||
|
if (entry == null) return;
|
||||||
|
|
||||||
|
final videoController = _videoControllers.firstWhere((kv) => kv.item1 == entry.uri, orElse: () => null)?.item2;
|
||||||
|
if (videoController != null) {
|
||||||
|
if (videoController.isPlayable) {
|
||||||
|
await videoController.play();
|
||||||
|
} else {
|
||||||
|
await videoController.setDataSource(entry.uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _initViewSpecificController<T>(String uri, List<Tuple2<String, T>> controllers, T Function() builder, void Function(T controller) disposer) {
|
void _initViewSpecificController<T>(String uri, List<Tuple2<String, T>> controllers, T Function() builder, void Function(T controller) disposer) {
|
||||||
var controller = controllers.firstWhere((kv) => kv.item1 == uri, orElse: () => null);
|
var controller = controllers.firstWhere((kv) => kv.item1 == uri, orElse: () => null);
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
|
|
|
@ -116,7 +116,7 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
icon: AnimatedIcons.play_pause,
|
icon: AnimatedIcons.play_pause,
|
||||||
progress: _playPauseAnimation,
|
progress: _playPauseAnimation,
|
||||||
),
|
),
|
||||||
onPressed: _playPause,
|
onPressed: _togglePlayPause,
|
||||||
tooltip: isPlaying ? context.l10n.viewerPauseTooltip : context.l10n.viewerPlayTooltip,
|
tooltip: isPlaying ? context.l10n.viewerPauseTooltip : context.l10n.viewerPlayTooltip,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -195,10 +195,16 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
_updatePlayPauseIcon();
|
_updatePlayPauseIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _playPause() async {
|
Future<void> _togglePlayPause() async {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
await controller.pause();
|
await controller.pause();
|
||||||
} else if (isPlayable) {
|
} else {
|
||||||
|
await _play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _play() async {
|
||||||
|
if (isPlayable) {
|
||||||
await controller.play();
|
await controller.play();
|
||||||
} else {
|
} else {
|
||||||
await controller.setDataSource(entry.uri);
|
await controller.setDataSource(entry.uri);
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:ui';
|
||||||
import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/entry_images.dart';
|
import 'package:aves/model/entry_images.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/collection/collection_page.dart';
|
import 'package:aves/widgets/collection/collection_page.dart';
|
||||||
import 'package:aves/widgets/common/video/controller.dart';
|
import 'package:aves/widgets/common/video/controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -57,14 +58,24 @@ class _VideoViewState extends State<VideoView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (controller == null) return SizedBox();
|
if (controller == null) return SizedBox();
|
||||||
return StreamBuilder<VideoStatus>(
|
return StreamBuilder<VideoStatus>(
|
||||||
stream: widget.controller.statusStream,
|
stream: controller.statusStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return controller?.isPlayable == true
|
return Stack(
|
||||||
? controller.buildPlayerWidget(context, entry)
|
fit: StackFit.expand,
|
||||||
: Image(
|
children: [
|
||||||
|
if (controller.isPlayable) controller.buildPlayerWidget(context, entry),
|
||||||
|
// fade out image to ease transition with the player as it starts with a black texture
|
||||||
|
AnimatedOpacity(
|
||||||
|
opacity: controller.isPlayable ? 0 : 1,
|
||||||
|
curve: Curves.easeInCirc,
|
||||||
|
duration: Durations.viewerVideoPlayerTransition,
|
||||||
|
child: Image(
|
||||||
image: entry.getBestThumbnail(settings.getTileExtent(CollectionPage.routeName)),
|
image: entry.getBestThumbnail(settings.getTileExtent(CollectionPage.routeName)),
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.fill,
|
||||||
);
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: aves
|
ref: aves
|
||||||
resolved-ref: "8fcf94a57e2a77a79d255f4499e26503ad411769"
|
resolved-ref: "0f25874db46d1af6fcfbeb8722915cbc211a10fb"
|
||||||
url: "git://github.com/deckerst/fijkplayer.git"
|
url: "git://github.com/deckerst/fijkplayer.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.8.7"
|
version: "0.8.7"
|
||||||
|
|
Loading…
Reference in a new issue