video_player: add ELinuxVideoPlayer (dartPluginClass) (#80)

This change fixes #78 issue of AndroidVideoPlayer being used on x64 host PC for some reason. To fix it, this change adds ELinuxVideoPlayer dart plugin class as a VideoPlayerPlatform for eLinux.

Signed-off-by: Hidenori Matsubayashi <Hidenori.Matsubayashi@gmail.com>
This commit is contained in:
Hidenori Matsubayashi
2023-08-25 22:27:20 +00:00
committed by GitHub
parent 582e6458f9
commit 96106f35e7
5 changed files with 677 additions and 1 deletions
+3
View File
@@ -1,3 +1,6 @@
## 0.9.9
* Add ELinuxVideoPlayer (VideoPlayerPlatform for eLinux) for flutter 3.13.
## 0.9.8
* Update flutter/dart-sdk versions in environment for flutter 3.13.0.
@@ -0,0 +1,195 @@
// Copyright 2023 Sony Group Corporation. All rights reserved.
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
import 'messages.g.dart';
/// An eLinux implementation of [VideoPlayerPlatform] that uses the
/// Pigeon-generated [VideoPlayerApi].
class ELinuxVideoPlayer extends VideoPlayerPlatform {
final ELinuxVideoPlayerApi _api = ELinuxVideoPlayerApi();
/// Registers this class as the default instance of [PathProviderPlatform].
static void registerWith() {
VideoPlayerPlatform.instance = ELinuxVideoPlayer();
}
@override
Future<void> init() {
return _api.initialize();
}
@override
Future<void> dispose(int textureId) {
return _api.dispose(TextureMessage(textureId: textureId));
}
@override
Future<int?> create(DataSource dataSource) async {
String? asset;
String? packageName;
String? uri;
String? formatHint;
Map<String, String> httpHeaders = <String, String>{};
switch (dataSource.sourceType) {
case DataSourceType.asset:
asset = dataSource.asset;
packageName = dataSource.package;
break;
case DataSourceType.network:
uri = dataSource.uri;
formatHint = _videoFormatStringMap[dataSource.formatHint];
httpHeaders = dataSource.httpHeaders;
break;
case DataSourceType.file:
uri = dataSource.uri;
httpHeaders = dataSource.httpHeaders;
break;
case DataSourceType.contentUri:
uri = dataSource.uri;
break;
}
final CreateMessage message = CreateMessage(
asset: asset,
packageName: packageName,
uri: uri,
httpHeaders: httpHeaders,
formatHint: formatHint,
);
final TextureMessage response = await _api.create(message);
return response.textureId;
}
@override
Future<void> setLooping(int textureId, bool looping) {
return _api.setLooping(LoopingMessage(
textureId: textureId,
isLooping: looping,
));
}
@override
Future<void> play(int textureId) {
return _api.play(TextureMessage(textureId: textureId));
}
@override
Future<void> pause(int textureId) {
return _api.pause(TextureMessage(textureId: textureId));
}
@override
Future<void> setVolume(int textureId, double volume) {
return _api.setVolume(VolumeMessage(
textureId: textureId,
volume: volume,
));
}
@override
Future<void> setPlaybackSpeed(int textureId, double speed) {
assert(speed > 0);
return _api.setPlaybackSpeed(PlaybackSpeedMessage(
textureId: textureId,
speed: speed,
));
}
@override
Future<void> seekTo(int textureId, Duration position) {
return _api.seekTo(PositionMessage(
textureId: textureId,
position: position.inMilliseconds,
));
}
@override
Future<Duration> getPosition(int textureId) async {
final PositionMessage response =
await _api.position(TextureMessage(textureId: textureId));
return Duration(milliseconds: response.position);
}
@override
Stream<VideoEvent> videoEventsFor(int textureId) {
return _eventChannelFor(textureId)
.receiveBroadcastStream()
.map((dynamic event) {
final Map<dynamic, dynamic> map = event as Map<dynamic, dynamic>;
switch (map['event']) {
case 'initialized':
return VideoEvent(
eventType: VideoEventType.initialized,
duration: Duration(milliseconds: map['duration'] as int),
size: Size((map['width'] as num?)?.toDouble() ?? 0.0,
(map['height'] as num?)?.toDouble() ?? 0.0),
rotationCorrection: map['rotationCorrection'] as int? ?? 0,
);
case 'completed':
return VideoEvent(
eventType: VideoEventType.completed,
);
case 'bufferingUpdate':
final List<dynamic> values = map['values'] as List<dynamic>;
return VideoEvent(
buffered: values.map<DurationRange>(_toDurationRange).toList(),
eventType: VideoEventType.bufferingUpdate,
);
case 'bufferingStart':
return VideoEvent(eventType: VideoEventType.bufferingStart);
case 'bufferingEnd':
return VideoEvent(eventType: VideoEventType.bufferingEnd);
/* TODO: need implementation
case 'isPlayingStateUpdate':
return VideoEvent(
eventType: VideoEventType.isPlayingStateUpdate,
isPlaying: map['isPlaying'] as bool,
);
*/
default:
return VideoEvent(eventType: VideoEventType.unknown);
}
});
}
@override
Widget buildView(int textureId) {
return Texture(textureId: textureId);
}
@override
Future<void> setMixWithOthers(bool mixWithOthers) {
return _api
.setMixWithOthers(MixWithOthersMessage(mixWithOthers: mixWithOthers));
}
EventChannel _eventChannelFor(int textureId) {
return EventChannel('flutter.io/videoPlayer/videoEvents$textureId');
}
static const Map<VideoFormat, String> _videoFormatStringMap =
<VideoFormat, String>{
VideoFormat.ss: 'ss',
VideoFormat.hls: 'hls',
VideoFormat.dash: 'dash',
VideoFormat.other: 'other',
};
DurationRange _toDurationRange(dynamic value) {
final List<dynamic> pair = value as List<dynamic>;
return DurationRange(
Duration(milliseconds: pair[0] as int),
Duration(milliseconds: pair[1] as int),
);
}
}
@@ -0,0 +1,471 @@
// Copyright 2023 Sony Group Corporation. All rights reserved.
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
import 'dart:async';
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
import 'package:flutter/services.dart';
class TextureMessage {
TextureMessage({
required this.textureId,
});
int textureId;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['textureId'] = textureId;
return pigeonMap;
}
static TextureMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return TextureMessage(
textureId: pigeonMap['textureId'] as int,
);
}
}
class CreateMessage {
CreateMessage({
this.asset,
this.uri,
this.packageName,
this.formatHint,
required this.httpHeaders,
});
String? asset;
String? uri;
String? packageName;
String? formatHint;
Map<String?, String?> httpHeaders;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['asset'] = asset;
pigeonMap['uri'] = uri;
pigeonMap['packageName'] = packageName;
pigeonMap['formatHint'] = formatHint;
pigeonMap['httpHeaders'] = httpHeaders;
return pigeonMap;
}
static CreateMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return CreateMessage(
asset: pigeonMap['asset'] as String?,
uri: pigeonMap['uri'] as String?,
packageName: pigeonMap['packageName'] as String?,
formatHint: pigeonMap['formatHint'] as String?,
httpHeaders: pigeonMap['httpHeaders'] as Map<String?, String?>,
);
}
}
class LoopingMessage {
LoopingMessage({
required this.textureId,
required this.isLooping,
});
int textureId;
bool isLooping;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['textureId'] = textureId;
pigeonMap['isLooping'] = isLooping;
return pigeonMap;
}
static LoopingMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return LoopingMessage(
textureId: pigeonMap['textureId'] as int,
isLooping: pigeonMap['isLooping'] as bool,
);
}
}
class VolumeMessage {
VolumeMessage({
required this.textureId,
required this.volume,
});
int textureId;
double volume;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['textureId'] = textureId;
pigeonMap['volume'] = volume;
return pigeonMap;
}
static VolumeMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return VolumeMessage(
textureId: pigeonMap['textureId'] as int,
volume: pigeonMap['volume'] as double,
);
}
}
class PlaybackSpeedMessage {
PlaybackSpeedMessage({
required this.textureId,
required this.speed,
});
int textureId;
double speed;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['textureId'] = textureId;
pigeonMap['speed'] = speed;
return pigeonMap;
}
static PlaybackSpeedMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return PlaybackSpeedMessage(
textureId: pigeonMap['textureId'] as int,
speed: pigeonMap['speed'] as double,
);
}
}
class PositionMessage {
PositionMessage({
required this.textureId,
required this.position,
});
int textureId;
int position;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['textureId'] = textureId;
pigeonMap['position'] = position;
return pigeonMap;
}
static PositionMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return PositionMessage(
textureId: pigeonMap['textureId'] as int,
position: pigeonMap['position'] as int,
);
}
}
class MixWithOthersMessage {
MixWithOthersMessage({
required this.mixWithOthers,
});
bool mixWithOthers;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['mixWithOthers'] = mixWithOthers;
return pigeonMap;
}
static MixWithOthersMessage decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
return MixWithOthersMessage(
mixWithOthers: pigeonMap['mixWithOthers'] as bool,
);
}
}
/// [VideoPlayerApi] in
class ELinuxVideoPlayerApi {
Future<void> initialize() async {
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(null) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<TextureMessage> create(CreateMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
return TextureMessage.decode(replyMap['result']!);
}
}
Future<void> dispose(TextureMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<void> setLooping(LoopingMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<void> setVolume(VolumeMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<void> setPlaybackSpeed(PlaybackSpeedMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed',
StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<void> play(TextureMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<PositionMessage> position(TextureMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
return PositionMessage.decode(replyMap['result']!);
}
}
Future<void> seekTo(PositionMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<void> pause(TextureMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
Future<void> setMixWithOthers(MixWithOthersMessage arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers',
StandardMessageCodec());
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null,
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
replyMap['error'] as Map<Object?, Object?>;
throw PlatformException(
code: error['code'] as String,
message: error['message'] as String?,
details: error['details'],
);
} else {
// noop
}
}
}
@@ -0,0 +1,6 @@
// Copyright 2023 Sony Group Corporation. All rights reserved.
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export 'src/elinux_video_player.dart';
+2 -1
View File
@@ -1,6 +1,6 @@
name: video_player_elinux
description: Flutter plugin for displaying inline video with other Flutter widgets on Embedded Linux.
version: 0.9.8
version: 0.9.9
homepage: https://github.com/sony/flutter-elinux-plugins
repository: https://github.com/sony/flutter-elinux-plugins/tree/main/packages/video_player
@@ -18,3 +18,4 @@ flutter:
platforms:
elinux:
pluginClass: VideoPlayerElinuxPlugin
dartPluginClass: ELinuxVideoPlayer