diff --git a/packages/video_player_videohole/CHANGELOG.md b/packages/video_player_videohole/CHANGELOG.md index 2e0cecd94..c82ca3ef6 100644 --- a/packages/video_player_videohole/CHANGELOG.md +++ b/packages/video_player_videohole/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.0 + +* Merge media player code from avplay. + ## 0.3.0 * Implement `httpHeaders` of `VideoPlayerController.network`. diff --git a/packages/video_player_videohole/README.md b/packages/video_player_videohole/README.md index 0f79a937c..c80a76d13 100644 --- a/packages/video_player_videohole/README.md +++ b/packages/video_player_videohole/README.md @@ -12,7 +12,7 @@ To use this package, add `video_player_videohole` as a dependency in your `pubsp ```yaml dependencies: - video_player_videohole: ^0.3.0 + video_player_videohole: ^0.4.0 ``` Then you can import `video_player_videohole` in your Dart code: diff --git a/packages/video_player_videohole/lib/src/messages.g.dart b/packages/video_player_videohole/lib/src/messages.g.dart index ea6b377ce..d20dddefc 100644 --- a/packages/video_player_videohole/lib/src/messages.g.dart +++ b/packages/video_player_videohole/lib/src/messages.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), 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 @@ -141,7 +141,7 @@ class TrackTypeMessage { int playerId; - int trackType; + String trackType; Object encode() { return [ @@ -154,7 +154,7 @@ class TrackTypeMessage { result as List; return TrackTypeMessage( playerId: result[0]! as int, - trackType: result[1]! as int, + trackType: result[1]! as String, ); } } @@ -170,7 +170,7 @@ class SelectedTracksMessage { int trackId; - int trackType; + String trackType; Object encode() { return [ @@ -185,7 +185,7 @@ class SelectedTracksMessage { return SelectedTracksMessage( playerId: result[0]! as int, trackId: result[1]! as int, - trackType: result[2]! as int, + trackType: result[2]! as String, ); } } @@ -224,6 +224,7 @@ class CreateMessage { this.formatHint, this.httpHeaders, this.drmConfigs, + this.playerOptions, }); String? asset; @@ -238,6 +239,8 @@ class CreateMessage { Map? drmConfigs; + Map? playerOptions; + Object encode() { return [ asset, @@ -246,6 +249,7 @@ class CreateMessage { formatHint, httpHeaders, drmConfigs, + playerOptions, ]; } @@ -260,6 +264,8 @@ class CreateMessage { (result[4] as Map?)?.cast(), drmConfigs: (result[5] as Map?)?.cast(), + playerOptions: + (result[6] as Map?)?.cast(), ); } } @@ -411,7 +417,8 @@ class VideoPlayerVideoholeApi { Future initialize() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.initialize', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.initialize', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; if (replyList == null) { @@ -432,7 +439,8 @@ class VideoPlayerVideoholeApi { Future create(CreateMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.create', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.create', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -459,7 +467,8 @@ class VideoPlayerVideoholeApi { Future dispose(PlayerMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.dispose', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.dispose', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -481,7 +490,8 @@ class VideoPlayerVideoholeApi { Future setLooping(LoopingMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.setLooping', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setLooping', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -503,7 +513,8 @@ class VideoPlayerVideoholeApi { Future setVolume(VolumeMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.setVolume', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setVolume', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -525,7 +536,8 @@ class VideoPlayerVideoholeApi { Future setPlaybackSpeed(PlaybackSpeedMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.setPlaybackSpeed', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setPlaybackSpeed', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -547,7 +559,8 @@ class VideoPlayerVideoholeApi { Future play(PlayerMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.play', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.play', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -567,9 +580,10 @@ class VideoPlayerVideoholeApi { } } - Future position(PlayerMessage arg_msg) async { + Future setDeactivate(PlayerMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.position', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setDeactivate', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -590,13 +604,14 @@ class VideoPlayerVideoholeApi { message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as PositionMessage?)!; + return (replyList[0] as bool?)!; } } - Future seekTo(PositionMessage arg_msg) async { + Future setActivate(PlayerMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.seekTo', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setActivate', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -611,14 +626,20 @@ class VideoPlayerVideoholeApi { message: replyList[1] as String?, details: replyList[2], ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); } else { - return; + return (replyList[0] as bool?)!; } } Future track(TrackTypeMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.track', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.track', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -643,9 +664,66 @@ class VideoPlayerVideoholeApi { } } - Future setTrackSelection(SelectedTracksMessage arg_msg) async { + Future setTrackSelection(SelectedTracksMessage arg_msg) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setTrackSelection', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_msg]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as bool?)!; + } + } + + Future position(PlayerMessage arg_msg) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.position', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_msg]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as PositionMessage?)!; + } + } + + Future seekTo(PositionMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.setTrackSelection', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.seekTo', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -667,7 +745,8 @@ class VideoPlayerVideoholeApi { Future pause(PlayerMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.pause', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.pause', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -689,7 +768,8 @@ class VideoPlayerVideoholeApi { Future setMixWithOthers(MixWithOthersMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.setMixWithOthers', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setMixWithOthers', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; @@ -711,7 +791,8 @@ class VideoPlayerVideoholeApi { Future setDisplayGeometry(GeometryMessage arg_msg) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerVideoholeApi.setDisplayGeometry', codec, + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.setDisplayGeometry', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_msg]) as List?; diff --git a/packages/video_player_videohole/lib/src/register_drm_callback_real.dart b/packages/video_player_videohole/lib/src/register_drm_callback_real.dart deleted file mode 100644 index e184b6f8c..000000000 --- a/packages/video_player_videohole/lib/src/register_drm_callback_real.dart +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2023 Samsung Electronics Co., Ltd. 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:ffi'; -import 'dart:isolate'; - -import 'package:flutter/foundation.dart'; - -import 'drm_configs.dart'; - -typedef _InitDartApi = int Function(Pointer); -typedef _InitDartApiNative = IntPtr Function(Pointer); - -typedef _RegisterSendPort = void Function(int, int); -typedef _RegisterSendPortNative = Void Function(Int64, Int64); - -class _CppRequest { - _CppRequest.fromList(List message) - : replyPort = message[0]! as SendPort, - pendingCall = message[1]! as int, - method = message[2]! as String, - data = message[3]! as Uint8List; - - final SendPort replyPort; - final int pendingCall; - final String method; - final Uint8List data; -} - -class _CppResponse { - _CppResponse(this.pendingCall, this.data); - - final int pendingCall; - final Uint8List data; - - List toList() => [pendingCall, data]; -} - -/// Registers the DRM callback and communication channel for handling license challenges. -/// -/// This function is used to register the necessary callback and communication channel -/// to handle DRM-related operations and license challenges for the video playback. -/// It establishes communication with native code using DynamicLibrary, and handles -/// incoming requests for license challenges from the platform side. -/// -/// The [drmConfigs] parameter contains configuration details for DRM operations, -/// including a [licenseCallback] function that is responsible for acquiring licenses -/// based on the provided challenges. -/// -/// It is important to call this function within the [initialize] method of the video -/// player to enable DRM capabilities and communicate with the native side properly. -/// -/// Example usage: -/// ```dart -/// registerDrmCallback(licenseCallback, _playerId); -/// ``` -/// -/// Note: This function should not be called directly outside the [initialize] method, -/// and it requires proper configuration and setup of the native C/C++ code to handle -/// DRM operations. -void registerDrmCallback(LicenseCallback licenseCallback, int playerId) { - final DynamicLibrary process = DynamicLibrary.process(); - final _InitDartApi initDartApi = - process.lookupFunction<_InitDartApiNative, _InitDartApi>( - 'VideoPlayerTizenPluginInitDartApi'); - initDartApi(NativeApi.initializeApiDLData); - - final ReceivePort receivePort = ReceivePort(); - receivePort.listen((dynamic message) async { - final _CppRequest request = _CppRequest.fromList(message as List); - - if (request.method == 'onLicenseChallenge') { - final Uint8List challenge = request.data; - final Uint8List result = await licenseCallback(challenge); - - final _CppResponse response = _CppResponse(request.pendingCall, result); - request.replyPort.send(response.toList()); - } - }); - - final _RegisterSendPort registerSendPort = - process.lookupFunction<_RegisterSendPortNative, _RegisterSendPort>( - 'VideoPlayerTizenPluginRegisterSendPort'); - registerSendPort(playerId, receivePort.sendPort.nativePort); -} diff --git a/packages/video_player_videohole/lib/src/register_drm_callback_stub.dart b/packages/video_player_videohole/lib/src/register_drm_callback_stub.dart deleted file mode 100644 index 3f57daa9c..000000000 --- a/packages/video_player_videohole/lib/src/register_drm_callback_stub.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'drm_configs.dart'; - -/// Register DRM callback function (No-op implementation). -/// -/// This function is a no-op (no-operation) implementation for registering the DRM callback -/// and communication channel to handle license challenges for video playback. It does not -/// perform any actual DRM operations but serves as a placeholder to maintain consistency -/// in the codebase when DRM functionality is not required. -/// -/// This function does not perform any communication with the native side or any DRM-related -/// operations. It can be used when DRM functionality is not required, or when a specific DRM -/// plugin or platform support is not available. -/// -/// Example usage: -/// ```dart -/// registerDrmCallback(drmConfigs, _playerId); -/// ``` -/// -/// Note: This function does not have any DRM functionality and should only be used in cases -/// where DRM support is not necessary or when using a DRM plugin that does not require native -/// communication for license handling. -void registerDrmCallback(LicenseCallback licenseCallback, int playerId) {} diff --git a/packages/video_player_videohole/lib/src/tracks.dart b/packages/video_player_videohole/lib/src/tracks.dart index fe68ab1df..923b9c200 100644 --- a/packages/video_player_videohole/lib/src/tracks.dart +++ b/packages/video_player_videohole/lib/src/tracks.dart @@ -109,19 +109,15 @@ class AudioTrack extends Track { class TextTrack extends Track { /// Creates an instance of [TextTrack]. /// - /// The [language] and [subtitleType] arguments are required. + /// The [language] arguments are required. /// /// [trackType] is [TrackType.text]. TextTrack({ required super.trackId, super.trackType = TrackType.text, required this.language, - required this.subtitleType, }); /// The language of text track. final String language; - - /// The subtitle type of track. - final TextTrackSubtitleType subtitleType; } diff --git a/packages/video_player_videohole/lib/src/video_player_tizen.dart b/packages/video_player_videohole/lib/src/video_player_tizen.dart index 94dc871af..6520d7e4b 100644 --- a/packages/video_player_videohole/lib/src/video_player_tizen.dart +++ b/packages/video_player_videohole/lib/src/video_player_tizen.dart @@ -13,7 +13,7 @@ import 'messages.g.dart'; import 'tracks.dart'; /// An implementation of [VideoPlayerPlatform] that uses the -/// Pigeon-generated [TizenVideoPlayerApi]. +/// Pigeon-generated [VideoPlayerVideoholeApi]. class VideoPlayerTizen extends VideoPlayerPlatform { final VideoPlayerVideoholeApi _api = VideoPlayerVideoholeApi(); @@ -41,6 +41,7 @@ class VideoPlayerTizen extends VideoPlayerPlatform { message.formatHint = _videoFormatStringMap[dataSource.formatHint]; message.httpHeaders = dataSource.httpHeaders; message.drmConfigs = dataSource.drmConfigs?.toMap(); + message.playerOptions = dataSource.playerOptions; break; case DataSourceType.file: message.uri = dataSource.uri; @@ -65,6 +66,16 @@ class VideoPlayerTizen extends VideoPlayerPlatform { return _api.play(PlayerMessage(playerId: playerId)); } + @override + Future setActivate(int playerId) { + return _api.setActivate(PlayerMessage(playerId: playerId)); + } + + @override + Future setDeactivate(int playerId) { + return _api.setDeactivate(PlayerMessage(playerId: playerId)); + } + @override Future pause(int playerId) { return _api.pause(PlayerMessage(playerId: playerId)); @@ -93,9 +104,7 @@ class VideoPlayerTizen extends VideoPlayerPlatform { Future> getVideoTracks(int playerId) async { final TrackMessage response = await _api.track(TrackTypeMessage( playerId: playerId, - trackType: _intTrackTypeMap.keys.firstWhere( - (int key) => _intTrackTypeMap[key] == TrackType.video, - orElse: () => -1), + trackType: TrackType.video.name, )); final List videoTracks = []; @@ -120,9 +129,7 @@ class VideoPlayerTizen extends VideoPlayerPlatform { Future> getAudioTracks(int playerId) async { final TrackMessage response = await _api.track(TrackTypeMessage( playerId: playerId, - trackType: _intTrackTypeMap.keys.firstWhere( - (int key) => _intTrackTypeMap[key] == TrackType.audio, - orElse: () => -1), + trackType: TrackType.audio.name, )); final List audioTracks = []; @@ -148,22 +155,17 @@ class VideoPlayerTizen extends VideoPlayerPlatform { Future> getTextTracks(int playerId) async { final TrackMessage response = await _api.track(TrackTypeMessage( playerId: playerId, - trackType: _intTrackTypeMap.keys.firstWhere( - (int key) => _intTrackTypeMap[key] == TrackType.text, - orElse: () => -1), + trackType: TrackType.text.name, )); final List textTracks = []; for (final Map? trackMap in response.tracks) { final int trackId = trackMap!['trackId']! as int; final String language = trackMap['language']! as String; - final TextTrackSubtitleType subtitleType = - _intSubtitleTypeMap[trackMap['subtitleType']]!; textTracks.add(TextTrack( trackId: trackId, language: language, - subtitleType: subtitleType, )); } @@ -171,13 +173,11 @@ class VideoPlayerTizen extends VideoPlayerPlatform { } @override - Future setTrackSelection(int playerId, Track track) { + Future setTrackSelection(int playerId, Track track) { return _api.setTrackSelection(SelectedTracksMessage( playerId: playerId, trackId: track.trackId, - trackType: _intTrackTypeMap.keys.firstWhere( - (int key) => _intTrackTypeMap[key] == track.trackType, - orElse: () => -1), + trackType: track.trackType.name, )); } @@ -268,22 +268,10 @@ class VideoPlayerTizen extends VideoPlayerPlatform { VideoFormat.other: 'other', }; - static const Map _intTrackTypeMap = { - 1: TrackType.audio, - 2: TrackType.video, - 3: TrackType.text, - }; - static const Map _intChannelTypeMap = { 1: AudioTrackChannelType.mono, 2: AudioTrackChannelType.stereo, 3: AudioTrackChannelType.surround, }; - - static const Map _intSubtitleTypeMap = - { - 0: TextTrackSubtitleType.text, - 1: TextTrackSubtitleType.picture, - }; } diff --git a/packages/video_player_videohole/lib/video_player.dart b/packages/video_player_videohole/lib/video_player.dart index 5f8d7beaf..86548d7bf 100644 --- a/packages/video_player_videohole/lib/video_player.dart +++ b/packages/video_player_videohole/lib/video_player.dart @@ -13,8 +13,6 @@ import 'package:flutter/services.dart'; import 'src/closed_caption_file.dart'; import 'src/drm_configs.dart'; import 'src/hole.dart'; -import 'src/register_drm_callback_stub.dart' - if (dart.library.ffi) 'src/register_drm_callback_real.dart'; import 'src/tracks.dart'; import 'video_player_platform_interface.dart'; @@ -218,12 +216,16 @@ class VideoPlayerController extends ValueNotifier { /// The name of the asset is given by the [dataSource] argument and must not be /// null. The [package] argument must be non-null when the asset comes from a /// package and null otherwise. - VideoPlayerController.asset(this.dataSource, - {this.package, this.closedCaptionFile, this.videoPlayerOptions}) - : dataSourceType = DataSourceType.asset, + VideoPlayerController.asset( + this.dataSource, { + this.package, + this.closedCaptionFile, + this.videoPlayerOptions, + }) : dataSourceType = DataSourceType.asset, formatHint = null, httpHeaders = const {}, drmConfigs = null, + playerOptions = const {}, super(VideoPlayerValue(duration: Duration.zero)); /// Constructs a [VideoPlayerController] playing a video from obtained from @@ -242,6 +244,7 @@ class VideoPlayerController extends ValueNotifier { this.videoPlayerOptions, this.httpHeaders = const {}, this.drmConfigs, + this.playerOptions, }) : dataSourceType = DataSourceType.network, package = null, super(VideoPlayerValue(duration: Duration.zero)); @@ -250,23 +253,28 @@ class VideoPlayerController extends ValueNotifier { /// /// This will load the file from the file-URI given by: /// `'file://${file.path}'`. - VideoPlayerController.file(File file, - {this.closedCaptionFile, this.videoPlayerOptions}) - : dataSource = 'file://${file.path}', + VideoPlayerController.file( + File file, { + this.closedCaptionFile, + this.videoPlayerOptions, + }) : dataSource = 'file://${file.path}', dataSourceType = DataSourceType.file, package = null, formatHint = null, httpHeaders = const {}, drmConfigs = null, + playerOptions = const {}, super(VideoPlayerValue(duration: Duration.zero)); /// Constructs a [VideoPlayerController] playing a video from a contentUri. /// /// This will load the video from the input content-URI. /// This is supported on Android only. - VideoPlayerController.contentUri(Uri contentUri, - {this.closedCaptionFile, this.videoPlayerOptions}) - : assert(defaultTargetPlatform == TargetPlatform.android, + VideoPlayerController.contentUri( + Uri contentUri, { + this.closedCaptionFile, + this.videoPlayerOptions, + }) : assert(defaultTargetPlatform == TargetPlatform.android, 'VideoPlayerController.contentUri is only supported on Android.'), dataSource = contentUri.toString(), dataSourceType = DataSourceType.contentUri, @@ -274,6 +282,7 @@ class VideoPlayerController extends ValueNotifier { formatHint = null, httpHeaders = const {}, drmConfigs = null, + playerOptions = const {}, super(VideoPlayerValue(duration: Duration.zero)); /// The URI to the video file. This will be in different formats depending on @@ -289,6 +298,10 @@ class VideoPlayerController extends ValueNotifier { /// Only for [VideoPlayerController.network]. final DrmConfigs? drmConfigs; + /// Player Options used for add additional parameters. + /// Only for [VideoPlayerController.network]. + final Map? playerOptions; + /// **Android only**. Will override the platform's generic file format /// detection with whatever is set here. final VideoFormat? formatHint; @@ -327,6 +340,9 @@ class VideoPlayerController extends ValueNotifier { @visibleForTesting int get playerId => _playerId; + final MethodChannel _channel = + const MethodChannel('dev.flutter.videoplayer.drm'); + /// Attempts to open the given [dataSource] and load metadata about the video. Future initialize() async { final bool allowBackgroundPlayback = @@ -353,6 +369,7 @@ class VideoPlayerController extends ValueNotifier { formatHint: formatHint, httpHeaders: httpHeaders, drmConfigs: drmConfigs, + playerOptions: playerOptions, ); break; case DataSourceType.file: @@ -433,7 +450,16 @@ class VideoPlayerController extends ValueNotifier { } if (drmConfigs?.licenseCallback != null) { - registerDrmCallback(drmConfigs!.licenseCallback!, _playerId); + _channel.setMethodCallHandler((MethodCall call) async { + if (call.method == 'requestLicense') { + final Map argumentsMap = + call.arguments as Map; + final Uint8List message = argumentsMap['message']! as Uint8List; + return drmConfigs!.licenseCallback!(message); + } else { + throw Exception('not implemented ${call.method}'); + } + }); } void errorListener(Object obj) { @@ -482,6 +508,16 @@ class VideoPlayerController extends ValueNotifier { await _applyPlayPause(); } + /// Sets the video activated. Use it if create two native players. + Future activate() async { + return _applyActivate(); + } + + /// Sets the video deactivated. Use it if create two native players. + Future deactivate() async { + return _applyDeactivate(); + } + /// Sets whether or not the video should loop after playing once. See also /// [VideoPlayerValue.isLooping]. Future setLooping(bool looping) async { @@ -502,6 +538,20 @@ class VideoPlayerController extends ValueNotifier { await _videoPlayerPlatform.setLooping(_playerId, value.isLooping); } + Future _applyActivate() async { + if (_isDisposedOrNotInitialized) { + return false; + } + return _videoPlayerPlatform.setActivate(_playerId); + } + + Future _applyDeactivate() async { + if (_isDisposedOrNotInitialized) { + return false; + } + return _videoPlayerPlatform.setDeactivate(_playerId); + } + Future _applyPlayPause() async { if (_isDisposedOrNotInitialized) { return; @@ -611,11 +661,11 @@ class VideoPlayerController extends ValueNotifier { } /// Sets the selected tracks. - Future setTrackSelection(Track track) async { + Future setTrackSelection(Track track) async { if (!value.isInitialized || _isDisposed) { - return; + return false; } - await _videoPlayerPlatform.setTrackSelection(_playerId, track); + return _videoPlayerPlatform.setTrackSelection(_playerId, track); } /// Sets the audio volume of [this]. diff --git a/packages/video_player_videohole/lib/video_player_platform_interface.dart b/packages/video_player_videohole/lib/video_player_platform_interface.dart index e8e63ce21..db56b9a3f 100644 --- a/packages/video_player_videohole/lib/video_player_platform_interface.dart +++ b/packages/video_player_videohole/lib/video_player_platform_interface.dart @@ -77,6 +77,16 @@ abstract class VideoPlayerPlatform extends PlatformInterface { throw UnimplementedError('pause() has not been implemented.'); } + /// Set the video activated. + Future setActivate(int playerId) { + throw UnimplementedError('setActivate() has not been implemented.'); + } + + /// Set the video deactivated. + Future setDeactivate(int playerId) { + throw UnimplementedError('setDeactivate() has not been implemented.'); + } + /// Sets the volume to a range between 0.0 and 1.0. Future setVolume(int playerId, double volume) { throw UnimplementedError('setVolume() has not been implemented.'); @@ -103,7 +113,7 @@ abstract class VideoPlayerPlatform extends PlatformInterface { } /// Sets the selected track. - Future setTrackSelection(int playerId, Track track) { + Future setTrackSelection(int playerId, Track track) { throw UnimplementedError('setTrackSelection() has not been implemented.'); } @@ -163,6 +173,7 @@ class DataSource { this.package, this.httpHeaders = const {}, this.drmConfigs, + this.playerOptions, }); /// The way in which the video was originally loaded. @@ -195,6 +206,9 @@ class DataSource { /// Configurations for playing DRM content. DrmConfigs? drmConfigs; + + /// Set additional optional player settings. + Map? playerOptions; } /// The way in which the video was originally loaded. diff --git a/packages/video_player_videohole/pigeons/messages.dart b/packages/video_player_videohole/pigeons/messages.dart index 25bf8173b..89dbbb011 100644 --- a/packages/video_player_videohole/pigeons/messages.dart +++ b/packages/video_player_videohole/pigeons/messages.dart @@ -41,14 +41,14 @@ class TrackMessage { class TrackTypeMessage { TrackTypeMessage(this.playerId, this.trackType); int playerId; - int trackType; + String trackType; } class SelectedTracksMessage { SelectedTracksMessage(this.playerId, this.trackId, this.trackType); int playerId; int trackId; - int trackType; + String trackType; } class PositionMessage { @@ -65,6 +65,7 @@ class CreateMessage { String? formatHint; Map? httpHeaders; Map? drmConfigs; + Map? playerOptions; } class MixWithOthersMessage { @@ -90,11 +91,13 @@ abstract class VideoPlayerVideoholeApi { void setVolume(VolumeMessage msg); void setPlaybackSpeed(PlaybackSpeedMessage msg); void play(PlayerMessage msg); + bool setDeactivate(PlayerMessage msg); + bool setActivate(PlayerMessage msg); + TrackMessage track(TrackTypeMessage msg); + bool setTrackSelection(SelectedTracksMessage msg); PositionMessage position(PlayerMessage msg); @async void seekTo(PositionMessage msg); - TrackMessage track(TrackTypeMessage msg); - void setTrackSelection(SelectedTracksMessage msg); void pause(PlayerMessage msg); void setMixWithOthers(MixWithOthersMessage msg); void setDisplayGeometry(GeometryMessage msg); diff --git a/packages/video_player_videohole/pubspec.yaml b/packages/video_player_videohole/pubspec.yaml index 2f0d09a89..bfd9edd4f 100644 --- a/packages/video_player_videohole/pubspec.yaml +++ b/packages/video_player_videohole/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_videohole description: Flutter plugin for displaying inline video on Tizen TV devices. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/video_player_videohole -version: 0.3.0 +version: 0.4.0 environment: sdk: ">=2.18.0 <4.0.0" @@ -16,7 +16,6 @@ flutter: fileName: video_player_tizen_plugin.h dependencies: - ffi: ^2.0.1 flutter: sdk: flutter html: ^0.15.0 diff --git a/packages/video_player_videohole/tizen/inc/video_player_tizen_plugin.h b/packages/video_player_videohole/tizen/inc/video_player_tizen_plugin.h index ff405ea7d..ab68b2f19 100644 --- a/packages/video_player_videohole/tizen/inc/video_player_tizen_plugin.h +++ b/packages/video_player_videohole/tizen/inc/video_player_tizen_plugin.h @@ -1,7 +1,6 @@ #ifndef FLUTTER_PLUGIN_VIDEO_PLAYER_TIZEN_PLUGIN_H_ #define FLUTTER_PLUGIN_VIDEO_PLAYER_TIZEN_PLUGIN_H_ -#include #include #include @@ -19,11 +18,6 @@ extern "C" { FLUTTER_PLUGIN_EXPORT void VideoPlayerTizenPluginRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar); -FLUTTER_PLUGIN_EXPORT intptr_t VideoPlayerTizenPluginInitDartApi(void *data); - -FLUTTER_PLUGIN_EXPORT void VideoPlayerTizenPluginRegisterSendPort( - int64_t player_id, Dart_Port send_port); - #if defined(__cplusplus) } // extern "C" #endif diff --git a/packages/video_player_videohole/tizen/src/drm_license_helper.cc b/packages/video_player_videohole/tizen/src/drm_license_helper.cc index 56d789b62..b4517cf70 100644 --- a/packages/video_player_videohole/tizen/src/drm_license_helper.cc +++ b/packages/video_player_videohole/tizen/src/drm_license_helper.cc @@ -408,7 +408,7 @@ int CbCurlProgress(void* ptr, double total_to_download, double now_downloaded, *http_cancel_request); if (*http_cancel_request) { - LOG_INFO("[DrmLicenseHelper] %s:%d curl works canceled."); + LOG_INFO("[DrmLicenseHelper] curl works canceled."); return 1; } } diff --git a/packages/video_player_videohole/tizen/src/drm_manager.cc b/packages/video_player_videohole/tizen/src/drm_manager.cc index f2ad971b6..3d695b01e 100644 --- a/packages/video_player_videohole/tizen/src/drm_manager.cc +++ b/packages/video_player_videohole/tizen/src/drm_manager.cc @@ -4,248 +4,337 @@ #include "drm_manager.h" +#include +#include + #include "drm_license_helper.h" +#include "drm_manager_proxy.h" #include "log.h" static std::string GetDrmSubType(int drm_type) { switch (drm_type) { - case DRM_TYPE_PLAYREADAY: + case DrmManager::DRM_TYPE_PLAYREADAY: return "com.microsoft.playready"; - case DRM_TYPE_WIDEVINECDM: + case DrmManager::DRM_TYPE_WIDEVINECDM: default: return "com.widevine.alpha"; } } -DrmManager::DrmManager(int drm_type, const std::string &license_server_url, - player_h player) - : drm_type_(drm_type), - license_server_url_(license_server_url), - player_(player) {} - -DrmManager::~DrmManager() {} - -bool DrmManager::InitializeDrmSession(const std::string &url) { - drm_manager_handle_ = OpenDrmManager(); - if (!drm_manager_handle_) { - LOG_ERROR("[DrmManager] Failed to dlopen libdrmmanager."); - return false; - } - int ret = InitDrmManager(drm_manager_handle_); - if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Failed to initialize DRM manager: %s", - get_error_message(ret)); - return false; +DrmManager::DrmManager() : drm_type_(DM_TYPE_NONE) { + drm_manager_proxy_ = OpenDrmManagerProxy(); + if (drm_manager_proxy_) { + int ret = InitDrmManagerProxy(drm_manager_proxy_); + if (ret != DM_ERROR_NONE) { + LOG_ERROR("[DrmManager] Fail to initialize DRM manager: %s", + get_error_message(ret)); + CloseDrmManagerProxy(drm_manager_proxy_); + drm_manager_proxy_ = nullptr; + } + } else { + LOG_ERROR("[DrmManager] Fail to dlopen libdrmmanager."); } + license_request_pipe_ = ecore_pipe_add( + [](void *data, void *buffer, unsigned int nbyte) -> void { + auto *self = static_cast(data); + self->ExecuteRequest(); + }, + this); +} - media_player_handle_ = OpenMediaPlayer(); - if (!media_player_handle_) { - LOG_ERROR("[DrmManager] Failed to dlopen libcapi-media-player."); - return false; +DrmManager::~DrmManager() { + ReleaseDrmSession(); + if (license_request_pipe_) { + ecore_pipe_del(license_request_pipe_); } - ret = InitMediaPlayer(media_player_handle_); - if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Failed to initialize Media Player: %s", - get_error_message(ret)); - return false; + if (drm_manager_proxy_) { + CloseDrmManagerProxy(drm_manager_proxy_); + drm_manager_proxy_ = nullptr; } +} - if (!CreateDrmSession()) { - LOG_ERROR("[DrmManager] Failed to create a DRM session."); +bool DrmManager::CreateDrmSession(int drm_type, bool local_mode) { + if (!drm_manager_proxy_) { + LOG_ERROR("[DrmManager] Invalid handle of libdrmmanager."); return false; } - if (!SetPlayerDrm(url)) { - LOG_ERROR("[DrmManager] Failed to set player DRM handle."); - return false; + if (local_mode) { + DMGRSetDRMLocalMode(); } - if (!SetChallengeCondition()) { - LOG_ERROR("[DrmManager] Failed to set challenge condition."); + drm_type_ = drm_type; + std::string sub_type = GetDrmSubType(drm_type); + LOG_INFO("[DrmManager] drm type is %s", sub_type.c_str()); + drm_session_ = DMGRCreateDRMSession(DM_TYPE_EME, sub_type.c_str()); + if (!drm_session_) { + LOG_ERROR("[DrmManager] Fail to create drm session."); return false; } + LOG_INFO("[DrmManager] Drm session is created, drm_session: %p", + drm_session_); - ret = DMGRSetData(drm_session_, "Initialize", nullptr); + SetDataParam_t configure_param = {}; + configure_param.param1 = reinterpret_cast(OnDrmManagerError); + configure_param.param2 = drm_session_; + int ret = DMGRSetData(drm_session_, "error_event_callback", &configure_param); if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Failed to initialize DRM session."); + LOG_ERROR( + "[DrmManager] Fail to set error_event_callback to drm session: %s", + get_error_message(ret)); + ReleaseDrmSession(); return false; } + return true; } -bool DrmManager::CreateDrmSession() { - std::string sub_type = GetDrmSubType(drm_type_); - LOG_INFO("[DrmManager] drm_sub_type: %s", sub_type.c_str()); - - drm_session_ = DMGRCreateDRMSession(DM_TYPE_EME, sub_type.c_str()); - if (!drm_session_) { - LOG_ERROR("[DrmManager] DMGRCreateDRMSession failed."); - return false; - } - LOG_INFO("[DrmManager] drm_session: %p", drm_session_); +bool DrmManager::SetChallenge(const std::string &media_url, + flutter::BinaryMessenger *binary_messenger) { + request_license_channel_ = + std::make_unique>( + binary_messenger, "dev.flutter.videoplayer.drm", + &flutter::StandardMethodCodec::GetInstance()); + return DM_ERROR_NONE == SetChallenge(media_url); +} - return true; +bool DrmManager::SetChallenge(const std::string &media_url, + const std::string &license_server_url) { + license_server_url_ = license_server_url; + return DM_ERROR_NONE == SetChallenge(media_url); } -bool DrmManager::SetPlayerDrm(const std::string &url) { - int ret = DMGRSetData(drm_session_, "set_playready_manifest", - static_cast(const_cast(url.c_str()))); +void DrmManager::ReleaseDrmSession() { + if (drm_session_ == nullptr) { + LOG_ERROR("[DrmManager] Already released."); + return; + } + + SetDataParam_t challenge_data_param = {}; + challenge_data_param.param1 = nullptr; + challenge_data_param.param2 = nullptr; + int ret = DMGRSetData(drm_session_, "eme_request_key_callback", + &challenge_data_param); if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Setting set_playready_manifest failed: %s", + LOG_ERROR("[DrmManager] Fail to unset eme_request_key_callback: %s", get_error_message(ret)); - return false; } - SetDataParam_t configure_param = {}; - configure_param.param1 = reinterpret_cast(OnDrmManagerError); - configure_param.param2 = drm_session_; - ret = DMGRSetData(drm_session_, "error_event_callback", &configure_param); + ret = DMGRSetData(drm_session_, "Finalize", nullptr); + if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Setting error_event_callback failed: %s", + LOG_ERROR("[DrmManager] Fail to set finalize to drm session: %s", get_error_message(ret)); - return false; } - int drm_handle = 0; - ret = DMGRGetData(drm_session_, "drm_handle", &drm_handle); + ret = DMGRReleaseDRMSession(drm_session_); if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Getting drm_handle failed: %s", + LOG_ERROR("[DrmManager] Fail to release drm session: %s", get_error_message(ret)); + } + drm_session_ = nullptr; +} + +bool DrmManager::GetDrmHandle(int *handle) { + if (drm_session_) { + *handle = 0; + int ret = DMGRGetData(drm_session_, "drm_handle", handle); + if (ret != DM_ERROR_NONE) { + LOG_ERROR("[DrmManager] Fail to get drm_handle from drm session: %s", + get_error_message(ret)); + return false; + } + LOG_INFO("[DrmManager] Get drm handle: %d", *handle); + return true; + } else { + LOG_ERROR("[DrmManager] Invalid drm session."); return false; } - LOG_INFO("[DrmManager] drm_handle: %d", drm_handle); +} + +int DrmManager::UpdatePsshData(const void *data, int length) { + if (!drm_session_) { + LOG_ERROR("[DrmManager] Invalid drm session."); + return DM_ERROR_INVALID_SESSION; + } - ret = player_set_drm_handle(player_, PLAYER_DRM_TYPE_EME, drm_handle); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[DrmManager] player_set_drm_handle failed: %s", + SetDataParam_t pssh_data_param = {}; + pssh_data_param.param1 = const_cast(data); + pssh_data_param.param2 = reinterpret_cast(length); + int ret = DMGRSetData(drm_session_, "update_pssh_data", &pssh_data_param); + if (DM_ERROR_NONE != ret) { + LOG_ERROR("[DrmManager] Fail to set update_pssh_data to drm session: %s", get_error_message(ret)); - return false; } + return ret; +} +bool DrmManager::SecurityInitCompleteCB(int *drm_handle, unsigned int len, + unsigned char *pssh_data, + void *user_data) { // IMPORTANT: SetDataParam_t cannot be stack allocated because // DMGRSecurityInitCompleteCB is called multiple times during video playback // and the parameter should always be available. - security_param_ = {}; - security_param_.param1 = player_; - security_param_.param2 = drm_session_; - ret = player_set_drm_init_complete_cb(player_, DMGRSecurityInitCompleteCB, - &security_param_); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[DrmManager] player_set_drm_init_complete_cb failed: %s", - get_error_message(ret)); - return false; + SetDataParam_t security_param = {}; + if (user_data) { + security_param.param1 = user_data; } + security_param.param2 = drm_session_; - ret = player_set_drm_init_data_cb(player_, UpdatePsshDataCB, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[DrmManager] player_set_drm_init_data_cb failed: %s", - get_error_message(ret)); - return false; - } - return true; + return DMGRSecurityInitCompleteCB(drm_handle, len, pssh_data, + &security_param); } -bool DrmManager::SetChallengeCondition() { +int DrmManager::SetChallenge(const std::string &media_url) { + if (!drm_session_) { + LOG_ERROR("[DrmManager] Invalid drm session."); + return DM_ERROR_INVALID_SESSION; + } + SetDataParam_t challenge_data_param = {}; challenge_data_param.param1 = reinterpret_cast(OnChallengeData); challenge_data_param.param2 = this; int ret = DMGRSetData(drm_session_, "eme_request_key_callback", &challenge_data_param); if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Setting eme_request_key_callback failed: %s", + LOG_ERROR( + "[DrmManager] Fail to set eme_request_key_callback to drm session: " + "%s", + get_error_message(ret)); + return ret; + } + + ret = DMGRSetData(drm_session_, "set_playready_manifest", + static_cast(const_cast(media_url.c_str()))); + if (ret != DM_ERROR_NONE) { + LOG_ERROR( + "[DrmManager] Fail to set set_playready_manifest to drm session: %s", + get_error_message(ret)); + return ret; + } + + ret = DMGRSetData(drm_session_, "Initialize", nullptr); + if (ret != DM_ERROR_NONE) { + LOG_ERROR("[DrmManager] Fail to set initialize to drm session: %s", get_error_message(ret)); - return false; + return ret; } - return true; + initialized_ = true; + return ret; } int DrmManager::OnChallengeData(void *session_id, int message_type, void *message, int message_length, void *user_data) { - LOG_INFO("[DrmManager] session_id: %s", session_id); + LOG_INFO("[DrmManager] challenge data: %s, challenge length: %d", message, + message_length); DrmManager *self = static_cast(user_data); - - LOG_INFO("[DrmManager] drm_type: %d", self->drm_type_); - LOG_INFO("[DrmManager] license_server_url: %s", + LOG_INFO("[DrmManager] drm_type: %d, license server: %s", self->drm_type_, self->license_server_url_.c_str()); - LOG_INFO("[DrmManager] Challenge length: %d", message_length); + DataForLicenseProcess process_message(session_id, message, message_length); + self->PushLicenseRequestData(process_message); + return DM_ERROR_NONE; +} + +void DrmManager::OnDrmManagerError(long error_code, char *error_message, + void *user_data) { + LOG_ERROR("[DrmManager] DRM manager had an error: [%ld][%s]", error_code, + error_message); +} - std::vector response; - if (!self->license_server_url_.empty()) { +bool DrmManager::ProcessLicense(DataForLicenseProcess &data) { + LOG_INFO("[DrmManager] Start process license."); + + if (!license_server_url_.empty()) { // Get license via the license server. unsigned char *response_data = nullptr; - unsigned long response_length = 0; + unsigned long response_len = 0; DRM_RESULT ret = DrmLicenseHelper::DoTransactionTZ( - self->license_server_url_.c_str(), message, message_length, - &response_data, &response_length, - static_cast(self->drm_type_), nullptr, - nullptr); - LOG_INFO("[DrmManager] Transaction result: 0x%lx", ret); - response = - std::vector(response_data, response_data + response_length); - free(response_data); - } else { + license_server_url_.c_str(), data.message.c_str(), data.message.size(), + &response_data, &response_len, + static_cast(drm_type_), nullptr, nullptr); + if (DRM_SUCCESS != ret || nullptr == response_data || 0 == response_len) { + LOG_ERROR("[DrmManager] Fail to get respone by license server url."); + return false; + } + LOG_INFO("[DrmManager] Response length : %lu", response_len); + InstallKey(const_cast( + reinterpret_cast(data.session_id.c_str())), + static_cast(response_data), + reinterpret_cast(response_len)); + } else if (request_license_channel_) { // Get license via the Dart callback. - std::vector challenge( - static_cast(message), - static_cast(message) + message_length); - response = self->challenge_callback_(challenge); + RequestLicense(data.session_id, data.message); + } else { + LOG_ERROR("[DrmManager] No way to request license."); } - LOG_INFO("[DrmManager] Response length: %d", response.size()); + return false; +} + +void DrmManager::InstallKey(void *session_id, void *response_data, + void *response_len) { + LOG_INFO("[DrmManager] Start install license."); SetDataParam_t license_param = {}; license_param.param1 = session_id; - license_param.param2 = response.data(); - license_param.param3 = reinterpret_cast(response.size()); - int ret = DMGRSetData(self->drm_session_, "install_eme_key", &license_param); + license_param.param2 = response_data; + license_param.param3 = response_len; + int ret = DMGRSetData(drm_session_, "install_eme_key", &license_param); if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Setting install_eme_key failed: %s", + LOG_ERROR("[DrmManager] Fail to install eme key: %s", get_error_message(ret)); } - return 0; } -int DrmManager::UpdatePsshDataCB(drm_init_data_type type, void *data, - int length, void *user_data) { - DrmManager *self = static_cast(user_data); - LOG_INFO("[DrmManager] drm_session: %p", self->drm_session_); +void DrmManager::RequestLicense(std::string &session_id, std::string &message) { + LOG_INFO("[DrmManager] Start request license."); - SetDataParam_t pssh_data_param = {}; - pssh_data_param.param1 = data; - pssh_data_param.param2 = reinterpret_cast(length); - int ret = - DMGRSetData(self->drm_session_, "update_pssh_data", &pssh_data_param); - if (DM_ERROR_NONE != ret) { - LOG_ERROR("[DrmManager] Setting update_pssh_data failed: %s", - get_error_message(ret)); - return 0; + if (request_license_channel_ == nullptr) { + LOG_ERROR("[DrmManager] request license channel is null."); + return; } - return 1; -} -void DrmManager::ReleaseDrmSession() { - if (drm_session_) { - int ret = DMGRSetData(drm_session_, "Finalize", nullptr); - if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Finalize failed: %s", get_error_message(ret)); - } - ret = DMGRReleaseDRMSession(drm_session_); - if (ret != DM_ERROR_NONE) { - LOG_ERROR("[DrmManager] Releasing DRM session failed: %s", - get_error_message(ret)); - } - drm_session_ = nullptr; - } + std::vector message_vec(message.begin(), message.end()); + flutter::EncodableMap args_map = { + {flutter::EncodableValue("message"), + flutter::EncodableValue(message_vec)}, + }; + auto result_handler = + std::make_unique>( - // Close dlopen handles. - CloseDrmManager(drm_manager_handle_); - drm_manager_handle_ = nullptr; - CloseMediaPlayer(media_player_handle_); - media_player_handle_ = nullptr; + [session_id, this](const flutter::EncodableValue *success_value) { + std::vector response; + if (std::holds_alternative>(*success_value)) { + response = std::get>(*success_value); + } else { + LOG_ERROR("[DrmManager] Fail to get response."); + return; + } + LOG_INFO("[DrmManager] Response length : %d", response.size()); + InstallKey(const_cast( + reinterpret_cast(session_id.c_str())), + reinterpret_cast(response.data()), + reinterpret_cast(response.size())); + }, + nullptr, nullptr); + request_license_channel_->InvokeMethod( + "requestLicense", + std::make_unique( + flutter::EncodableValue(args_map)), + std::move(result_handler)); } -void DrmManager::OnDrmManagerError(long error_code, char *error_message, - void *user_data) { - LOG_ERROR("[DrmManager] DRM manager had error: [%ld][%s]", error_code, - error_message); +void DrmManager::PushLicenseRequestData(DataForLicenseProcess &data) { + std::lock_guard lock(queue_mutex_); + license_request_queue_.push(data); + ecore_pipe_write(license_request_pipe_, nullptr, 0); +} + +void DrmManager::ExecuteRequest() { + std::lock_guard lock(queue_mutex_); + while (!license_request_queue_.empty()) { + DataForLicenseProcess data = license_request_queue_.front(); + ProcessLicense(data); + license_request_queue_.pop(); + } } diff --git a/packages/video_player_videohole/tizen/src/drm_manager.h b/packages/video_player_videohole/tizen/src/drm_manager.h index 924b3e044..c8113d96f 100644 --- a/packages/video_player_videohole/tizen/src/drm_manager.h +++ b/packages/video_player_videohole/tizen/src/drm_manager.h @@ -5,55 +5,69 @@ #ifndef FLUTTER_PLUGIN_DRM_MANAGER_H_ #define FLUTTER_PLUGIN_DRM_MANAGER_H_ -#include +#include +#include -#include -#include -#include -#include -#include +#include +#include -#include "drm_manager_service_proxy.h" - -typedef std::function( - const std::vector &challenge)> - ChallengeCallback; +#include "drm_manager_proxy.h" class DrmManager { public: - explicit DrmManager(int drm_type, const std::string &license_server_url, - player_h player); + typedef enum { + DRM_TYPE_NONE, + DRM_TYPE_PLAYREADAY, + DRM_TYPE_WIDEVINECDM, + } DrmType; + + explicit DrmManager(); ~DrmManager(); - bool InitializeDrmSession(const std::string &url); + bool CreateDrmSession(int drm_type, bool local_mode); + bool SetChallenge(const std::string &media_url, + const std::string &license_server_url); + bool SetChallenge(const std::string &media_url, + flutter::BinaryMessenger *binary_messenger); + bool GetDrmHandle(int *handle); + bool SecurityInitCompleteCB(int *drm_handle, unsigned int len, + unsigned char *pssh_data, void *user_data); + int UpdatePsshData(const void *data, int length); void ReleaseDrmSession(); - void SetChallengeCallback(ChallengeCallback callback) { - challenge_callback_ = callback; - } - private: - bool CreateDrmSession(); - bool SetPlayerDrm(const std::string &url); - bool SetChallengeCondition(); + struct DataForLicenseProcess { + DataForLicenseProcess(void *session_id, void *message, int message_length) + : session_id(static_cast(session_id)), + message(static_cast(message), message_length) {} + std::string session_id; + std::string message; + }; + + void RequestLicense(std::string &session_id, std::string &message); + void InstallKey(void *session_id, void *response_data, void *response_len); + int SetChallenge(const std::string &media_url); static int OnChallengeData(void *session_id, int message_type, void *message, int message_length, void *user_data); - static int UpdatePsshDataCB(drm_init_data_type type, void *data, int length, - void *user_data); static void OnDrmManagerError(long error_code, char *error_message, void *user_data); + bool ProcessLicense(DataForLicenseProcess &data); + void PushLicenseRequestData(DataForLicenseProcess &data); + void ExecuteRequest(); + + std::unique_ptr> + request_license_channel_; - SetDataParam_t security_param_; - DRMSessionHandle_t drm_session_ = nullptr; - void *drm_manager_handle_ = nullptr; - void *media_player_handle_ = nullptr; + void *drm_session_ = nullptr; + void *drm_manager_proxy_ = nullptr; int drm_type_; std::string license_server_url_; - player_h player_; - - ChallengeCallback challenge_callback_; + bool initialized_ = false; + std::mutex queue_mutex_; + Ecore_Pipe *license_request_pipe_ = nullptr; + std::queue license_request_queue_; }; #endif // FLUTTER_PLUGIN_DRM_MANAGER_H_ diff --git a/packages/video_player_videohole/tizen/src/drm_manager_service_proxy.cc b/packages/video_player_videohole/tizen/src/drm_manager_proxy.cc similarity index 54% rename from packages/video_player_videohole/tizen/src/drm_manager_service_proxy.cc rename to packages/video_player_videohole/tizen/src/drm_manager_proxy.cc index df855918b..5a59c9c14 100644 --- a/packages/video_player_videohole/tizen/src/drm_manager_service_proxy.cc +++ b/packages/video_player_videohole/tizen/src/drm_manager_proxy.cc @@ -2,26 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "drm_manager_service_proxy.h" +#include "drm_manager_proxy.h" #include FuncDMGRSetData DMGRSetData = nullptr; FuncDMGRGetData DMGRGetData = nullptr; +FuncDMGRSetDRMLocalMode DMGRSetDRMLocalMode = nullptr; FuncDMGRCreateDRMSession DMGRCreateDRMSession = nullptr; FuncDMGRSecurityInitCompleteCB DMGRSecurityInitCompleteCB = nullptr; FuncDMGRReleaseDRMSession DMGRReleaseDRMSession = nullptr; -FuncPlayerSetDrmHandle player_set_drm_handle = nullptr; -FuncPlayerSetDrmInitCompleteCB player_set_drm_init_complete_cb = nullptr; -FuncPlayerSetDrmInitDataCB player_set_drm_init_data_cb = nullptr; -void* OpenDrmManager() { return dlopen("libdrmmanager.so.0", RTLD_LAZY); } +void* OpenDrmManagerProxy() { return dlopen("libdrmmanager.so.0", RTLD_LAZY); } -void* OpenMediaPlayer() { - return dlopen("libcapi-media-player.so.0", RTLD_LAZY); -} - -int InitDrmManager(void* handle) { +int InitDrmManagerProxy(void* handle) { if (!handle) { return DM_ERROR_INVALID_PARAM; } @@ -36,6 +30,12 @@ int InitDrmManager(void* handle) { return DM_ERROR_DL; } + DMGRSetDRMLocalMode = reinterpret_cast( + dlsym(handle, "DMGRSetDRMLocalMode")); + if (!DMGRSetDRMLocalMode) { + return DM_ERROR_DL; + } + DMGRCreateDRMSession = reinterpret_cast( dlsym(handle, "DMGRCreateDRMSession")); if (!DMGRCreateDRMSession) { @@ -57,36 +57,7 @@ int InitDrmManager(void* handle) { return DM_ERROR_NONE; } -int InitMediaPlayer(void* handle) { - player_set_drm_handle = reinterpret_cast( - dlsym(handle, "player_set_drm_handle")); - if (!player_set_drm_handle) { - return DM_ERROR_DL; - } - - player_set_drm_init_complete_cb = - reinterpret_cast( - dlsym(handle, "player_set_drm_init_complete_cb")); - if (!player_set_drm_init_complete_cb) { - return DM_ERROR_DL; - } - - player_set_drm_init_data_cb = reinterpret_cast( - dlsym(handle, "player_set_drm_init_data_cb")); - if (!player_set_drm_init_data_cb) { - return DM_ERROR_DL; - } - - return DM_ERROR_NONE; -} - -void CloseDrmManager(void* handle) { - if (handle) { - dlclose(handle); - } -} - -void CloseMediaPlayer(void* handle) { +void CloseDrmManagerProxy(void* handle) { if (handle) { dlclose(handle); } diff --git a/packages/video_player_videohole/tizen/src/drm_manager_service_proxy.h b/packages/video_player_videohole/tizen/src/drm_manager_proxy.h similarity index 72% rename from packages/video_player_videohole/tizen/src/drm_manager_service_proxy.h rename to packages/video_player_videohole/tizen/src/drm_manager_proxy.h index 4583a9462..02261d1b1 100644 --- a/packages/video_player_videohole/tizen/src/drm_manager_service_proxy.h +++ b/packages/video_player_videohole/tizen/src/drm_manager_proxy.h @@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_PLUGIN_DRM_MANAGER_SERVICE_PROXY_H_ -#define FLUTTER_PLUGIN_DRM_MANAGER_SERVICE_PROXY_H_ - -#include +#ifndef FLUTTER_PLUGIN_DRM_MANAGER_PROXY_H_ +#define FLUTTER_PLUGIN_DRM_MANAGER_PROXY_H_ typedef enum { DM_ERROR_NONE = 0, /**< Success */ @@ -70,25 +68,6 @@ typedef enum { DM_ERROR_UNKOWN, } dm_error_e; -typedef enum { - PLAYER_DRM_TYPE_NONE = 0, - PLAYER_DRM_TYPE_PLAYREADY, - PLAYER_DRM_TYPE_MARLIN, - PLAYER_DRM_TYPE_VERIMATRIX, - PLAYER_DRM_TYPE_WIDEVINE_CLASSIC, - PLAYER_DRM_TYPE_SECUREMEDIA, - PLAYER_DRM_TYPE_SDRM, - PLAYER_DRM_TYPE_VUDU, - PLAYER_DRM_TYPE_WIDEVINE_CDM, - PLAYER_DRM_TYPE_AES128, - PLAYER_DRM_TYPE_HDCP, - PLAYER_DRM_TYPE_DTCP, - PLAYER_DRM_TYPE_SCSA, - PLAYER_DRM_TYPE_CLEARKEY, - PLAYER_DRM_TYPE_EME, - PLAYER_DRM_TYPE_MAX_COUNT, -} player_drm_type_e; - typedef enum { DM_TYPE_NONE = 0, /**< None */ DM_TYPE_PLAYREADY = 1, /**< Playready */ @@ -113,29 +92,13 @@ typedef struct SetDataParam_s { void* param4; /**< Parameter 4 */ } SetDataParam_t; -typedef enum { - DRM_TYPE_NONE, - DRM_TYPE_PLAYREADAY, - DRM_TYPE_WIDEVINECDM, -} DRMTYPE; - -typedef enum { - CENC = 0, - KEYIDS = 1, - WEBM = 2, -} drm_init_data_type; - typedef void* DRMSessionHandle_t; -typedef bool (*security_init_complete_cb)(int* drmhandle, unsigned int length, - unsigned char* psshdata, - void* user_data); -typedef int (*set_drm_init_data_cb)(drm_init_data_type init_type, void* data, - int data_length, void* user_data); typedef int (*FuncDMGRSetData)(DRMSessionHandle_t drm_session, const char* data_type, void* input_data); typedef int (*FuncDMGRGetData)(DRMSessionHandle_t drm_session, const char* data_type, void* output_data); +typedef void (*FuncDMGRSetDRMLocalMode)(); typedef DRMSessionHandle_t (*FuncDMGRCreateDRMSession)( dm_type_e type, const char* drm_sub_type); typedef bool (*FuncDMGRSecurityInitCompleteCB)(int* drm_handle, @@ -143,29 +106,16 @@ typedef bool (*FuncDMGRSecurityInitCompleteCB)(int* drm_handle, unsigned char* pssh_data, void* user_data); typedef int (*FuncDMGRReleaseDRMSession)(DRMSessionHandle_t drm_session); -typedef int (*FuncPlayerSetDrmHandle)(player_h player, - player_drm_type_e drm_type, - int drm_handle); -typedef int (*FuncPlayerSetDrmInitCompleteCB)( - player_h player, security_init_complete_cb callback, void* user_data); -typedef int (*FuncPlayerSetDrmInitDataCB)(player_h player, - set_drm_init_data_cb callback, - void* user_data); - -void* OpenDrmManager(); -void* OpenMediaPlayer(); -int InitDrmManager(void* handle); -int InitMediaPlayer(void* handle); -void CloseDrmManager(void* handle); -void CloseMediaPlayer(void* handle); + +void* OpenDrmManagerProxy(); +int InitDrmManagerProxy(void* handle); +void CloseDrmManagerProxy(void* handle); extern FuncDMGRSetData DMGRSetData; extern FuncDMGRGetData DMGRGetData; +extern FuncDMGRSetDRMLocalMode DMGRSetDRMLocalMode; extern FuncDMGRCreateDRMSession DMGRCreateDRMSession; extern FuncDMGRSecurityInitCompleteCB DMGRSecurityInitCompleteCB; extern FuncDMGRReleaseDRMSession DMGRReleaseDRMSession; -extern FuncPlayerSetDrmHandle player_set_drm_handle; -extern FuncPlayerSetDrmInitCompleteCB player_set_drm_init_complete_cb; -extern FuncPlayerSetDrmInitDataCB player_set_drm_init_data_cb; -#endif // FLUTTER_PLUGIN_DRM_MANAGER_SERVICE_PROXY_H_ +#endif // FLUTTER_PLUGIN_DRM_MANAGER_PROXY_H_ diff --git a/packages/video_player_videohole/tizen/src/ecore_wl2_window_proxy.cc b/packages/video_player_videohole/tizen/src/ecore_wl2_window_proxy.cc new file mode 100644 index 000000000..0e8891ffb --- /dev/null +++ b/packages/video_player_videohole/tizen/src/ecore_wl2_window_proxy.cc @@ -0,0 +1,60 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ecore_wl2_window_proxy.h" + +#include + +#include "log.h" + +typedef void (*FuncEcoreWl2WindowGeometryGet)(void *window, int *x, int *y, + int *width, int *height); +typedef int (*FuncEcoreWl2WindowSurfaceIdGet)(void *window); + +EcoreWl2WindowProxy::EcoreWl2WindowProxy() { + ecore_wl2_window_handle_ = dlopen("libecore_wl2.so.1", RTLD_LAZY); + if (ecore_wl2_window_handle_ == nullptr) { + LOG_ERROR("Failed to open ecore wl2."); + } +} + +void EcoreWl2WindowProxy::ecore_wl2_window_geometry_get(void *window, int *x, + int *y, int *width, + int *height) { + if (!ecore_wl2_window_handle_) { + LOG_ERROR("ecore_wl2_window_handle_ not valid"); + return; + } + + FuncEcoreWl2WindowGeometryGet ecore_wl2_window_geometry_get = + reinterpret_cast( + dlsym(ecore_wl2_window_handle_, "ecore_wl2_window_geometry_get")); + if (!ecore_wl2_window_geometry_get) { + LOG_ERROR("Fail to find ecore_wl2_window_geometry_get."); + return; + } + ecore_wl2_window_geometry_get(window, x, y, width, height); +} + +int EcoreWl2WindowProxy::ecore_wl2_window_surface_id_get(void *window) { + if (!ecore_wl2_window_handle_) { + LOG_ERROR("ecore_wl2_window_handle_ not valid"); + return -1; + } + FuncEcoreWl2WindowSurfaceIdGet ecore_wl2_window_surface_id_get = + reinterpret_cast( + dlsym(ecore_wl2_window_handle_, "ecore_wl2_window_surface_id_get")); + if (!ecore_wl2_window_surface_id_get) { + LOG_ERROR("Fail to find ecore_wl2_window_surface_id_get."); + return -1; + } + return ecore_wl2_window_surface_id_get(window); +} + +EcoreWl2WindowProxy::~EcoreWl2WindowProxy() { + if (ecore_wl2_window_handle_) { + dlclose(ecore_wl2_window_handle_); + ecore_wl2_window_handle_ = nullptr; + } +} diff --git a/packages/video_player_videohole/tizen/src/ecore_wl2_window_proxy.h b/packages/video_player_videohole/tizen/src/ecore_wl2_window_proxy.h new file mode 100644 index 000000000..66c4aa3cc --- /dev/null +++ b/packages/video_player_videohole/tizen/src/ecore_wl2_window_proxy.h @@ -0,0 +1,20 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_PLUGIN_ECORE_WL2_WINDOW_PROXY_H_ +#define FLUTTER_PLUGIN_ECORE_WL2_WINDOW_PROXY_H_ + +class EcoreWl2WindowProxy { + public: + EcoreWl2WindowProxy(); + ~EcoreWl2WindowProxy(); + void ecore_wl2_window_geometry_get(void *window, int *x, int *y, int *width, + int *height); + int ecore_wl2_window_surface_id_get(void *window); + + private: + void *ecore_wl2_window_handle_ = nullptr; +}; + +#endif // FLUTTER_PLUGIN_ECORE_WL2_WINDOW_PROXY_H_ diff --git a/packages/video_player_videohole/tizen/src/media_player.cc b/packages/video_player_videohole/tizen/src/media_player.cc new file mode 100644 index 000000000..5d25041a2 --- /dev/null +++ b/packages/video_player_videohole/tizen/src/media_player.cc @@ -0,0 +1,677 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media_player.h" + +#include + +#include "log.h" + +static std::string RotationToString(player_display_rotation_e rotation) { + switch (rotation) { + case PLAYER_DISPLAY_ROTATION_NONE: + return "PLAYER_DISPLAY_ROTATION_NONE"; + case PLAYER_DISPLAY_ROTATION_90: + return "PLAYER_DISPLAY_ROTATION_90"; + case PLAYER_DISPLAY_ROTATION_180: + return "PLAYER_DISPLAY_ROTATION_180"; + case PLAYER_DISPLAY_ROTATION_270: + return "PLAYER_DISPLAY_ROTATION_270"; + } + return std::string(); +} + +static player_stream_type_e ConvertTrackType(std::string track_type) { + if (track_type == "video") { + return PLAYER_STREAM_TYPE_VIDEO; + } + if (track_type == "audio") { + return PLAYER_STREAM_TYPE_AUDIO; + } + if (track_type == "text") { + return PLAYER_STREAM_TYPE_TEXT; + } + return PLAYER_STREAM_TYPE_DEFAULT; +} + +MediaPlayer::MediaPlayer(flutter::BinaryMessenger *messenger, + FlutterDesktopViewRef flutter_view) + : VideoPlayer(messenger, flutter_view) { + media_player_proxy_ = std::make_unique(); +} + +MediaPlayer::~MediaPlayer() { + if (player_) { + player_stop(player_); + player_unprepare(player_); + player_unset_buffering_cb(player_); + player_unset_completed_cb(player_); + player_unset_interrupted_cb(player_); + player_unset_error_cb(player_); + player_unset_subtitle_updated_cb(player_); + player_destroy(player_); + player_ = nullptr; + } + if (drm_manager_) { + drm_manager_->ReleaseDrmSession(); + } +} + +int64_t MediaPlayer::Create(const std::string &uri, int drm_type, + const std::string &license_server_url, + bool is_prebuffer_mode, + flutter::EncodableMap &http_headers) { + LOG_INFO("[MediaPlayer] uri: %s, drm_type: %d.", uri.c_str(), drm_type); + + if (uri.empty()) { + LOG_ERROR("[MediaPlayer] The uri must not be empty."); + return -1; + } + + int ret = player_create(&player_); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_create failed: %s.", + get_error_message(ret)); + return -1; + } + + if (!http_headers.empty()) { + auto iter = http_headers.find(flutter::EncodableValue("Cookie")); + if (iter != http_headers.end()) { + if (std::holds_alternative(iter->second)) { + std::string cookie = std::get(iter->second); + ret = + player_set_streaming_cookie(player_, cookie.c_str(), cookie.size()); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_streaming_cookie failed: %s.", + get_error_message(ret)); + } + } + } + + iter = http_headers.find(flutter::EncodableValue("User-Agent")); + if (iter != http_headers.end()) { + if (std::holds_alternative(iter->second)) { + std::string user_agent = std::get(iter->second); + ret = player_set_streaming_user_agent(player_, user_agent.c_str(), + user_agent.size()); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_streaming_user_agent failed: %s.", + get_error_message(ret)); + } + } + } + } + + if (drm_type != 0) { + if (!SetDrm(uri, drm_type, license_server_url)) { + LOG_ERROR("[MediaPlayer] Failed to set drm."); + return -1; + } + } + + if (!SetDisplay()) { + LOG_ERROR("[MediaPlayer] Failed to set display."); + return -1; + } + + SetDisplayRoi(0, 0, 1, 1); + + ret = player_set_uri(player_, uri.c_str()); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_uri failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_set_display_visible(player_, true); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_display_visible failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_set_buffering_cb(player_, OnBuffering, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_buffering_cb failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_set_completed_cb(player_, OnPlayCompleted, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_completed_cb failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_set_interrupted_cb(player_, OnInterrupted, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_interrupted_cb failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_set_error_cb(player_, OnError, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_error_cb failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_set_subtitle_updated_cb(player_, OnSubtitleUpdated, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_subtitle_updated_cb failed : %s.", + get_error_message(ret)); + return -1; + } + + ret = player_prepare_async(player_, OnPrepared, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_prepare_async failed : %s.", + get_error_message(ret)); + return -1; + } + + return SetUpEventChannel(); +} + +void MediaPlayer::Dispose() { + LOG_INFO("[MediaPlayer] Disposing."); + ClearUpEventChannel(); +} + +void MediaPlayer::SetDisplayRoi(int32_t x, int32_t y, int32_t width, + int32_t height) { + int ret = player_set_display_roi_area(player_, x, y, width, height); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_display_roi_area failed: %s.", + get_error_message(ret)); + } +} + +bool MediaPlayer::Play() { + LOG_INFO("[MediaPlayer] Player starting."); + + player_state_e state = PLAYER_STATE_NONE; + int ret = player_get_state(player_, &state); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] Unable to get player state."); + } + if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { + LOG_ERROR("[MediaPlayer] Player not ready."); + return false; + } + if (state == PLAYER_STATE_PLAYING) { + LOG_INFO("[MediaPlayer] Player already playing."); + return false; + } + ret = player_start(player_); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_start failed: %s.", get_error_message(ret)); + return false; + } + return true; +} + +bool MediaPlayer::Pause() { + LOG_INFO("[MediaPlayer] Player pausing."); + + player_state_e state = PLAYER_STATE_NONE; + int ret = player_get_state(player_, &state); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] Unable to get player state."); + } + if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { + LOG_ERROR("[MediaPlayer] Player not ready."); + return false; + } + if (state != PLAYER_STATE_PLAYING) { + LOG_INFO("[MediaPlayer] Player not playing."); + return false; + } + ret = player_pause(player_); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_pause failed: %s.", get_error_message(ret)); + return false; + } + return true; +} + +bool MediaPlayer::SetLooping(bool is_looping) { + LOG_INFO("[MediaPlayer] is_looping: %d.", is_looping); + + int ret = player_set_looping(player_, is_looping); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_looping failed: %s.", + get_error_message(ret)); + return false; + } + return true; +} + +bool MediaPlayer::SetVolume(double volume) { + LOG_INFO("[MediaPlayer] volume: %f.", volume); + + int ret = player_set_volume(player_, volume, volume); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_volume failed: %s.", + get_error_message(ret)); + return false; + } + return true; +} + +bool MediaPlayer::SetPlaybackSpeed(double speed) { + LOG_INFO("[MediaPlayer] speed: %f.", speed); + + int ret = player_set_playback_rate(player_, speed); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_playback_rate failed: %s.", + get_error_message(ret)); + return false; + } + return true; +} + +bool MediaPlayer::SeekTo(int64_t position, SeekCompletedCallback callback) { + LOG_INFO("[MediaPlayer] position: %lld.", position); + + on_seek_completed_ = std::move(callback); + int ret = + player_set_play_position(player_, position, true, OnSeekCompleted, this); + if (ret != PLAYER_ERROR_NONE) { + on_seek_completed_ = nullptr; + LOG_ERROR("[MediaPlayer] player_set_play_position failed: %s.", + get_error_message(ret)); + return false; + } + return true; +} + +int64_t MediaPlayer::GetPosition() { + int position = 0; + int ret = player_get_play_position(player_, &position); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_play_position failed: %s.", + get_error_message(ret)); + } + LOG_DEBUG("[MediaPlayer] Video current position : %d.", position); + return position; +} + +int64_t MediaPlayer::GetDuration() { + int duration = 0; + int ret = player_get_duration(player_, &duration); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_duration failed: %s.", + get_error_message(ret)); + } + LOG_INFO("[MediaPlayer] Video duration: %d.", duration); + return duration; +} + +void MediaPlayer::GetVideoSize(int32_t *width, int32_t *height) { + int w = 0, h = 0; + int ret = player_get_video_size(player_, &w, &h); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_video_size failed: %s.", + get_error_message(ret)); + } + LOG_INFO("[MediaPlayer] Video width: %d, height: %d.", w, h); + + player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE; + ret = player_get_display_rotation(player_, &rotation); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_display_rotation failed: %s.", + get_error_message(ret)); + } + LOG_DEBUG("[MediaPlayer] Video rotation: %s.", + RotationToString(rotation).c_str()); + if (rotation == PLAYER_DISPLAY_ROTATION_90 || + rotation == PLAYER_DISPLAY_ROTATION_270) { + std::swap(w, h); + } + + *width = w; + *height = h; +} + +bool MediaPlayer::IsReady() { + player_state_e state = PLAYER_STATE_NONE; + int ret = player_get_state(player_, &state); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_state failed: %s.", + get_error_message(ret)); + return false; + } + + LOG_INFO("[MediaPlayer] Player state : %d.", state); + return PLAYER_STATE_READY == state; +} + +bool MediaPlayer::SetDisplay() { + void *native_window = GetWindowHandle(); + if (!native_window) { + LOG_ERROR("[MediaPlayer] Could not get a native window handle."); + return false; + } + + int x = 0, y = 0, width = 0, height = 0; + ecore_wl2_window_proxy_->ecore_wl2_window_geometry_get(native_window, &x, &y, + &width, &height); + int ret = media_player_proxy_->player_set_ecore_wl_display( + player_, PLAYER_DISPLAY_TYPE_OVERLAY, native_window, x, y, width, height); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_ecore_wl_display failed: %s.", + get_error_message(ret)); + return false; + } + + ret = player_set_display_mode(player_, PLAYER_DISPLAY_MODE_DST_ROI); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_display_mode failed: %s.", + get_error_message(ret)); + return false; + } + return true; +} + +flutter::EncodableList MediaPlayer::GetTrackInfo(std::string track_type) { + player_state_e state = PLAYER_STATE_NONE; + int ret = player_get_state(player_, &state); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_state failed: %s", + get_error_message(ret)); + return {}; + } + if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { + LOG_ERROR("[MediaPlayer] Player not ready."); + return {}; + } + + player_stream_type_e type = ConvertTrackType(track_type); + int track_count = 0; + ret = media_player_proxy_->player_get_track_count_v2(player_, type, + &track_count); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_track_count_v2 failed: %s", + get_error_message(ret)); + return {}; + } + if (track_count <= 0) { + return {}; + } + + flutter::EncodableList trackSelections = {}; + flutter::EncodableMap trackSelection = {}; + trackSelection.insert( + {flutter::EncodableValue("trackType"), flutter::EncodableValue(type)}); + if (type == PLAYER_STREAM_TYPE_VIDEO) { + LOG_INFO("[MediaPlayer] video_count: %d", track_count); + + for (int video_index = 0; video_index < track_count; video_index++) { + player_video_track_info_v2 *video_track_info = nullptr; + + ret = media_player_proxy_->player_get_video_track_info_v2( + player_, video_index, &video_track_info); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_video_track_info_v2 failed: %s", + get_error_message(ret)); + return {}; + } + LOG_INFO( + "[MediaPlayer] video track info: width[%d], height[%d], " + "bitrate[%d]", + video_track_info->width, video_track_info->height, + video_track_info->bit_rate); + + trackSelection.insert_or_assign(flutter::EncodableValue("trackId"), + flutter::EncodableValue(video_index)); + trackSelection.insert_or_assign( + flutter::EncodableValue("width"), + flutter::EncodableValue(video_track_info->width)); + trackSelection.insert_or_assign( + flutter::EncodableValue("height"), + flutter::EncodableValue(video_track_info->height)); + trackSelection.insert_or_assign( + flutter::EncodableValue("bitrate"), + flutter::EncodableValue(video_track_info->bit_rate)); + + trackSelections.push_back(flutter::EncodableValue(trackSelection)); + } + + } else if (type == PLAYER_STREAM_TYPE_AUDIO) { + LOG_INFO("[MediaPlayer] audio_count: %d", track_count); + + for (int audio_index = 0; audio_index < track_count; audio_index++) { + player_audio_track_info_v2 *audio_track_info = nullptr; + + ret = media_player_proxy_->player_get_audio_track_info_v2( + player_, audio_index, &audio_track_info); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_audio_track_info_v2 failed: %s", + get_error_message(ret)); + return {}; + } + LOG_INFO( + "[MediaPlayer] audio track info: language[%s], channel[%d], " + "sample_rate[%d], bitrate[%d]", + audio_track_info->language, audio_track_info->channel, + audio_track_info->sample_rate, audio_track_info->bit_rate); + + trackSelection.insert_or_assign(flutter::EncodableValue("trackId"), + flutter::EncodableValue(audio_index)); + trackSelection.insert_or_assign( + flutter::EncodableValue("language"), + flutter::EncodableValue(std::string(audio_track_info->language))); + trackSelection.insert_or_assign( + flutter::EncodableValue("channel"), + flutter::EncodableValue(audio_track_info->channel)); + trackSelection.insert_or_assign( + flutter::EncodableValue("bitrate"), + flutter::EncodableValue(audio_track_info->bit_rate)); + + trackSelections.push_back(flutter::EncodableValue(trackSelection)); + } + + } else if (type == PLAYER_STREAM_TYPE_TEXT) { + LOG_INFO("[MediaPlayer] subtitle_count: %d", track_count); + + for (int sub_index = 0; sub_index < track_count; sub_index++) { + player_subtitle_track_info_v2 *sub_track_info = nullptr; + + ret = media_player_proxy_->player_get_subtitle_track_info_v2( + player_, sub_index, &sub_track_info); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_subtitle_track_info_v2 failed: %s", + get_error_message(ret)); + return {}; + } + LOG_INFO("[MediaPlayer] subtitle track info: language[%s]", + sub_track_info->language); + + trackSelection.insert_or_assign(flutter::EncodableValue("trackId"), + flutter::EncodableValue(sub_index)); + trackSelection.insert_or_assign( + flutter::EncodableValue("language"), + flutter::EncodableValue(std::string(sub_track_info->language))); + + trackSelections.push_back(flutter::EncodableValue(trackSelection)); + } + } + + return trackSelections; +} + +bool MediaPlayer::SetTrackSelection(int32_t track_id, std::string track_type) { + LOG_INFO("[MediaPlayer] track_id: %d,track_type: %s", track_id, + track_type.c_str()); + + player_state_e state = PLAYER_STATE_NONE; + int ret = player_get_state(player_, &state); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_state failed: %s", + get_error_message(ret)); + return false; + } + if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { + LOG_ERROR("[MediaPlayer] Player not ready."); + return false; + } + + ret = player_select_track(player_, ConvertTrackType(track_type), track_id); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_select_track failed: %s", + get_error_message(ret)); + return false; + } + + return true; +} + +bool MediaPlayer::SetDrm(const std::string &uri, int drm_type, + const std::string &license_server_url) { + drm_manager_ = std::make_unique(); + if (!drm_manager_->CreateDrmSession(drm_type, false)) { + LOG_ERROR("[MediaPlayer] Failed to create drm session."); + return false; + } + + int drm_handle = 0; + if (!drm_manager_->GetDrmHandle(&drm_handle)) { + LOG_ERROR("[MediaPlayer] Failed to get drm handle."); + return false; + } + + int ret = media_player_proxy_->player_set_drm_handle( + player_, PLAYER_DRM_TYPE_EME, drm_handle); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_drm_handle failed : %s.", + get_error_message(ret)); + return false; + } + + ret = media_player_proxy_->player_set_drm_init_complete_cb( + player_, OnDrmSecurityInitComplete, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_drm_init_complete_cb failed : %s.", + get_error_message(ret)); + return false; + } + + ret = media_player_proxy_->player_set_drm_init_data_cb( + player_, OnDrmUpdatePsshData, this); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_set_drm_init_complete_cb failed : %s.", + get_error_message(ret)); + return false; + } + + if (license_server_url.empty()) { + bool success = drm_manager_->SetChallenge(uri, binary_messenger_); + if (!success) { + LOG_ERROR("[MediaPlayer] Failed to set challenge."); + return false; + } + } else { + if (!drm_manager_->SetChallenge(uri, license_server_url)) { + LOG_ERROR("[MediaPlayer] Failed to set challenge."); + return false; + } + } + return true; +} + +void MediaPlayer::OnPrepared(void *user_data) { + LOG_INFO("[MediaPlayer] Player prepared."); + + MediaPlayer *self = static_cast(user_data); + if (!self->is_initialized_) { + self->SendInitialized(); + } +} + +void MediaPlayer::OnBuffering(int percent, void *user_data) { + LOG_INFO("[MediaPlayer] Buffering percent: %d.", percent); + + MediaPlayer *self = static_cast(user_data); + if (percent == 100) { + self->SendBufferingEnd(); + self->is_buffering_ = false; + } else if (!self->is_buffering_ && percent <= 5) { + self->SendBufferingStart(); + self->is_buffering_ = true; + } else { + self->SendBufferingUpdate(percent); + } +} + +void MediaPlayer::OnSeekCompleted(void *user_data) { + LOG_INFO("[MediaPlayer] Seek completed."); + + MediaPlayer *self = static_cast(user_data); + if (self->on_seek_completed_) { + self->on_seek_completed_(); + self->on_seek_completed_ = nullptr; + } +} + +void MediaPlayer::OnPlayCompleted(void *user_data) { + LOG_INFO("[MediaPlayer] Play completed."); + + MediaPlayer *self = static_cast(user_data); + self->SendPlayCompleted(); + self->Pause(); +} + +void MediaPlayer::OnInterrupted(player_interrupted_code_e code, + void *user_data) { + LOG_ERROR("[MediaPlayer] Interrupt code: %d.", code); + + MediaPlayer *self = static_cast(user_data); + self->SendError("Interrupted error", "Media player has been interrupted."); +} + +void MediaPlayer::OnError(int error_code, void *user_data) { + LOG_ERROR("An error occurred for media player, error: %d (%s).", error_code, + get_error_message(error_code)); + + MediaPlayer *self = static_cast(user_data); + self->SendError("Media Player error", get_error_message(error_code)); +} + +void MediaPlayer::OnSubtitleUpdated(unsigned long duration, char *text, + void *user_data) { + LOG_INFO("[MediaPlayer] Subtitle updated, duration: %ld, text: %s.", duration, + text); + + MediaPlayer *self = static_cast(user_data); + self->SendSubtitleUpdate(duration, std::string(text)); +} + +bool MediaPlayer::OnDrmSecurityInitComplete(int *drm_handle, + unsigned int length, + unsigned char *pssh_data, + void *user_data) { + LOG_INFO("[MediaPlayer] Drm init completed."); + + MediaPlayer *self = static_cast(user_data); + if (self->drm_manager_) { + return self->drm_manager_->SecurityInitCompleteCB(drm_handle, length, + pssh_data, self->player_); + } + return false; +} + +int MediaPlayer::OnDrmUpdatePsshData(drm_init_data_type init_type, void *data, + int data_length, void *user_data) { + LOG_INFO("[MediaPlayer] Drm update pssh data."); + + MediaPlayer *self = static_cast(user_data); + if (self->drm_manager_) { + return self->drm_manager_->UpdatePsshData(data, data_length); + } + return 0; +} diff --git a/packages/video_player_videohole/tizen/src/media_player.h b/packages/video_player_videohole/tizen/src/media_player.h new file mode 100644 index 000000000..01e0e91c6 --- /dev/null +++ b/packages/video_player_videohole/tizen/src/media_player.h @@ -0,0 +1,70 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_PLUGIN_MEDIA_PLAYER_H_ +#define FLUTTER_PLUGIN_MEDIA_PLAYER_H_ + +#include + +#include +#include +#include + +#include "drm_manager.h" +#include "media_player_proxy.h" +#include "video_player.h" + +class MediaPlayer : public VideoPlayer { + public: + explicit MediaPlayer(flutter::BinaryMessenger *messenger, + FlutterDesktopViewRef flutter_view); + ~MediaPlayer(); + + int64_t Create(const std::string &uri, int drm_type, + const std::string &license_server_url, bool is_prebuffer_mode, + flutter::EncodableMap &http_headers) override; + void Dispose() override; + + void SetDisplayRoi(int32_t x, int32_t y, int32_t width, + int32_t height) override; + bool Play() override; + bool Pause() override; + bool SetLooping(bool is_looping) override; + bool SetVolume(double volume) override; + bool SetPlaybackSpeed(double speed) override; + bool SeekTo(int64_t position, SeekCompletedCallback callback) override; + int64_t GetPosition() override; + int64_t GetDuration() override; + void GetVideoSize(int32_t *width, int32_t *height) override; + bool IsReady() override; + flutter::EncodableList GetTrackInfo(std::string track_type) override; + bool SetTrackSelection(int32_t track_id, std::string track_type) override; + + private: + bool SetDisplay(); + bool SetDrm(const std::string &uri, int drm_type, + const std::string &license_server_url); + + static void OnPrepared(void *user_data); + static void OnBuffering(int percent, void *user_data); + static void OnSeekCompleted(void *user_data); + static void OnPlayCompleted(void *user_data); + static void OnInterrupted(player_interrupted_code_e code, void *user_data); + static void OnError(int error_code, void *user_data); + static void OnSubtitleUpdated(unsigned long duration, char *text, + void *user_data); + static bool OnDrmSecurityInitComplete(int *drm_handle, unsigned int length, + unsigned char *pssh_data, + void *user_data); + static int OnDrmUpdatePsshData(drm_init_data_type init_type, void *data, + int data_length, void *user_data); + + player_h player_ = nullptr; + std::unique_ptr media_player_proxy_ = nullptr; + std::unique_ptr drm_manager_; + bool is_buffering_ = false; + SeekCompletedCallback on_seek_completed_; +}; + +#endif // FLUTTER_PLUGIN_MEDIA_PLAYER_H_ diff --git a/packages/video_player_videohole/tizen/src/media_player_proxy.cc b/packages/video_player_videohole/tizen/src/media_player_proxy.cc new file mode 100644 index 000000000..06adafac1 --- /dev/null +++ b/packages/video_player_videohole/tizen/src/media_player_proxy.cc @@ -0,0 +1,181 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media_player_proxy.h" + +#include + +#include "log.h" + +typedef int (*FuncPlayerSetEcoreWlDisplay)(player_h player, + player_display_type_e type, + void* ecore_wl_window, int x, int y, + int width, int height); + +typedef int (*FuncPlayerSetDrmHandle)(player_h player, + player_drm_type_e drm_type, + int drm_handle); +typedef int (*FuncPlayerSetDrmInitCompleteCB)( + player_h player, security_init_complete_cb callback, void* user_data); +typedef int (*FuncPlayerSetDrmInitDataCB)(player_h player, + set_drm_init_data_cb callback, + void* user_data); +typedef int (*FuncPlayerGetTrackCountV2)(player_h player, + player_stream_type_e type, + int* pcount); +typedef int (*FuncPlayerGetVideoTrackInfoV2)( + player_h player, int index, player_video_track_info_v2** track_info); +typedef int (*FuncPlayerGetAudioTrackInfoV2)( + player_h player, int index, player_audio_track_info_v2** track_info); +typedef int (*FuncPlayerGetSubtitleTrackInfoV2)( + player_h player, int index, player_subtitle_track_info_v2** track_info); + +MediaPlayerProxy::MediaPlayerProxy() { + media_player_handle_ = dlopen("libcapi-media-player.so.0", RTLD_LAZY); + if (media_player_handle_ == nullptr) { + LOG_ERROR("Failed to open media player."); + } +} + +MediaPlayerProxy::~MediaPlayerProxy() { + if (media_player_handle_) { + dlclose(media_player_handle_); + media_player_handle_ = nullptr; + } +} + +int MediaPlayerProxy::player_set_ecore_wl_display(player_h player, + player_display_type_e type, + void* ecore_wl_window, int x, + int y, int width, + int height) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerSetEcoreWlDisplay player_set_ecore_wl_display = + reinterpret_cast( + dlsym(media_player_handle_, "player_set_ecore_wl_display")); + if (!player_set_ecore_wl_display) { + LOG_ERROR("Fail to find player_set_ecore_wl_display."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_set_ecore_wl_display(player, type, ecore_wl_window, x, y, width, + height); +} + +int MediaPlayerProxy::player_set_drm_handle(player_h player, + player_drm_type_e drm_type, + int drm_handle) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerSetDrmHandle player_set_drm_handle = + reinterpret_cast( + dlsym(media_player_handle_, "player_set_drm_handle")); + if (!player_set_drm_handle) { + LOG_ERROR("Fail to find player_set_ecore_wl_display."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_set_drm_handle(player, drm_type, drm_handle); +} + +int MediaPlayerProxy::player_set_drm_init_complete_cb( + player_h player, security_init_complete_cb callback, void* user_data) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerSetDrmInitCompleteCB player_set_drm_init_complete_cb = + reinterpret_cast( + dlsym(media_player_handle_, "player_set_drm_init_complete_cb")); + if (!player_set_drm_init_complete_cb) { + LOG_ERROR("Fail to find player_set_drm_init_complete_cb."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_set_drm_init_complete_cb(player, callback, user_data); +} + +int MediaPlayerProxy::player_set_drm_init_data_cb(player_h player, + set_drm_init_data_cb callback, + void* user_data) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerSetDrmInitDataCB player_set_drm_init_data_cb = + reinterpret_cast( + dlsym(media_player_handle_, "player_set_drm_init_data_cb")); + if (!player_set_drm_init_data_cb) { + LOG_ERROR("Fail to find player_set_drm_init_data_cb."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_set_drm_init_data_cb(player, callback, user_data); +} + +int MediaPlayerProxy::player_get_track_count_v2(player_h player, + player_stream_type_e type, + int* pcount) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerGetTrackCountV2 player_get_track_count_v2 = + reinterpret_cast( + dlsym(media_player_handle_, "player_get_track_count_v2")); + if (!player_get_track_count_v2) { + LOG_ERROR("Fail to find player_get_track_count_v2."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_get_track_count_v2(player, type, pcount); +} + +int MediaPlayerProxy::player_get_video_track_info_v2( + player_h player, int index, player_video_track_info_v2** track_info) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerGetVideoTrackInfoV2 player_get_video_track_info_v2 = + reinterpret_cast( + dlsym(media_player_handle_, "player_get_video_track_info_v2")); + if (!player_get_video_track_info_v2) { + LOG_ERROR("Fail to find player_get_video_track_info_v2."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_get_video_track_info_v2(player, index, track_info); +} + +int MediaPlayerProxy::player_get_audio_track_info_v2( + player_h player, int index, player_audio_track_info_v2** track_info) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerGetAudioTrackInfoV2 player_get_audio_track_info_v2 = + reinterpret_cast( + dlsym(media_player_handle_, "player_get_audio_track_info_v2")); + if (!player_get_audio_track_info_v2) { + LOG_ERROR("Fail to find player_get_audio_track_info_v2."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_get_audio_track_info_v2(player, index, track_info); +} + +int MediaPlayerProxy::player_get_subtitle_track_info_v2( + player_h player, int index, player_subtitle_track_info_v2** track_info) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerGetSubtitleTrackInfoV2 player_get_subtitle_track_info_v2 = + reinterpret_cast( + dlsym(media_player_handle_, "player_get_subtitle_track_info_v2")); + if (!player_get_subtitle_track_info_v2) { + LOG_ERROR("Fail to find player_get_subtitle_track_info_v2."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_get_subtitle_track_info_v2(player, index, track_info); +} diff --git a/packages/video_player_videohole/tizen/src/media_player_proxy.h b/packages/video_player_videohole/tizen/src/media_player_proxy.h new file mode 100644 index 000000000..6e9e94d90 --- /dev/null +++ b/packages/video_player_videohole/tizen/src/media_player_proxy.h @@ -0,0 +1,98 @@ +// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_PLUGIN_MEDIA_PLAYER_PROXY_H_ +#define FLUTTER_PLUGIN_MEDIA_PLAYER_PROXY_H_ + +#include + +#define MAX_STRING_NAME_LEN 255 +#define MMPLAYER_FOUR_CC_LEN 14 +#define PLAYER_LANG_NAME_SIZE 10 + +typedef struct { + char fourCC[MMPLAYER_FOUR_CC_LEN + 1]; /**< codec fourcc */ + char name[MAX_STRING_NAME_LEN]; /**< name: video/audio, it maybe not exit in + some track*/ + /*dynamic infos in hls,ss,dash streams*/ + int width; /**< resolution width */ + int height; /**< resolution height */ + int bit_rate; /**< bitrate in bps */ +} player_video_track_info_v2; + +typedef struct { + char fourCC[MMPLAYER_FOUR_CC_LEN + 1]; /**< codec fourcc */ + char language[PLAYER_LANG_NAME_SIZE]; /**< language info*/ + /*dynamic infos in hls,ss,dash streams*/ + int sample_rate; /**< sample rate in this track*/ + int channel; /**< channel in this track*/ + int bit_rate; /**< bitrate in this track*/ +} player_audio_track_info_v2; + +typedef struct { + char fourCC[MMPLAYER_FOUR_CC_LEN + 1]; /**< codec fourcc */ + char language[PLAYER_LANG_NAME_SIZE]; /**< language info*/ + int subtitle_type; /**< text subtitle = 0, picture subtitle = 1 */ +} player_subtitle_track_info_v2; + +typedef enum { + PLAYER_DRM_TYPE_NONE = 0, + PLAYER_DRM_TYPE_PLAYREADY, + PLAYER_DRM_TYPE_MARLIN, + PLAYER_DRM_TYPE_VERIMATRIX, + PLAYER_DRM_TYPE_WIDEVINE_CLASSIC, + PLAYER_DRM_TYPE_SECUREMEDIA, + PLAYER_DRM_TYPE_SDRM, + PLAYER_DRM_TYPE_VUDU, + PLAYER_DRM_TYPE_WIDEVINE_CDM, + PLAYER_DRM_TYPE_AES128, + PLAYER_DRM_TYPE_HDCP, + PLAYER_DRM_TYPE_DTCP, + PLAYER_DRM_TYPE_SCSA, + PLAYER_DRM_TYPE_CLEARKEY, + PLAYER_DRM_TYPE_EME, + PLAYER_DRM_TYPE_MAX_COUNT, +} player_drm_type_e; + +typedef enum { + CENC = 0, + KEYIDS = 1, + WEBM = 2, +} drm_init_data_type; + +typedef bool (*security_init_complete_cb)(int* drmhandle, unsigned int length, + unsigned char* psshdata, + void* user_data); +typedef int (*set_drm_init_data_cb)(drm_init_data_type init_type, void* data, + int data_length, void* user_data); + +class MediaPlayerProxy { + public: + MediaPlayerProxy(); + ~MediaPlayerProxy(); + int player_set_ecore_wl_display(player_h player, player_display_type_e type, + void* ecore_wl_window, int x, int y, + int width, int height); + int player_set_drm_handle(player_h player, player_drm_type_e drm_type, + int drm_handle); + int player_set_drm_init_complete_cb(player_h player, + security_init_complete_cb callback, + void* user_data); + int player_set_drm_init_data_cb(player_h player, + set_drm_init_data_cb callback, + void* user_data); + int player_get_track_count_v2(player_h player, player_stream_type_e type, + int* pcount); + int player_get_video_track_info_v2(player_h player, int index, + player_video_track_info_v2** track_info); + int player_get_audio_track_info_v2(player_h player, int index, + player_audio_track_info_v2** track_info); + int player_get_subtitle_track_info_v2( + player_h player, int index, player_subtitle_track_info_v2** track_info); + + private: + void* media_player_handle_ = nullptr; +}; + +#endif // FLUTTER_PLUGIN_MEDIA_PLAYER_PROXY_H_ diff --git a/packages/video_player_videohole/tizen/src/messages.cc b/packages/video_player_videohole/tizen/src/messages.cc index 090d888ff..72196de75 100644 --- a/packages/video_player_videohole/tizen/src/messages.cc +++ b/packages/video_player_videohole/tizen/src/messages.cc @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS @@ -153,7 +153,8 @@ TrackMessage TrackMessage::FromEncodableList(const EncodableList& list) { // TrackTypeMessage -TrackTypeMessage::TrackTypeMessage(int64_t player_id, int64_t track_type) +TrackTypeMessage::TrackTypeMessage(int64_t player_id, + const std::string& track_type) : player_id_(player_id), track_type_(track_type) {} int64_t TrackTypeMessage::player_id() const { return player_id_; } @@ -162,9 +163,9 @@ void TrackTypeMessage::set_player_id(int64_t value_arg) { player_id_ = value_arg; } -int64_t TrackTypeMessage::track_type() const { return track_type_; } +const std::string& TrackTypeMessage::track_type() const { return track_type_; } -void TrackTypeMessage::set_track_type(int64_t value_arg) { +void TrackTypeMessage::set_track_type(std::string_view value_arg) { track_type_ = value_arg; } @@ -178,7 +179,7 @@ EncodableList TrackTypeMessage::ToEncodableList() const { TrackTypeMessage TrackTypeMessage::FromEncodableList( const EncodableList& list) { - TrackTypeMessage decoded(list[0].LongValue(), list[1].LongValue()); + TrackTypeMessage decoded(list[0].LongValue(), std::get(list[1])); return decoded; } @@ -186,7 +187,7 @@ TrackTypeMessage TrackTypeMessage::FromEncodableList( SelectedTracksMessage::SelectedTracksMessage(int64_t player_id, int64_t track_id, - int64_t track_type) + const std::string& track_type) : player_id_(player_id), track_id_(track_id), track_type_(track_type) {} int64_t SelectedTracksMessage::player_id() const { return player_id_; } @@ -201,9 +202,11 @@ void SelectedTracksMessage::set_track_id(int64_t value_arg) { track_id_ = value_arg; } -int64_t SelectedTracksMessage::track_type() const { return track_type_; } +const std::string& SelectedTracksMessage::track_type() const { + return track_type_; +} -void SelectedTracksMessage::set_track_type(int64_t value_arg) { +void SelectedTracksMessage::set_track_type(std::string_view value_arg) { track_type_ = value_arg; } @@ -219,7 +222,7 @@ EncodableList SelectedTracksMessage::ToEncodableList() const { SelectedTracksMessage SelectedTracksMessage::FromEncodableList( const EncodableList& list) { SelectedTracksMessage decoded(list[0].LongValue(), list[1].LongValue(), - list[2].LongValue()); + std::get(list[2])); return decoded; } @@ -259,7 +262,8 @@ CreateMessage::CreateMessage(const std::string* asset, const std::string* uri, const std::string* package_name, const std::string* format_hint, const EncodableMap* http_headers, - const EncodableMap* drm_configs) + const EncodableMap* drm_configs, + const EncodableMap* player_options) : asset_(asset ? std::optional(*asset) : std::nullopt), uri_(uri ? std::optional(*uri) : std::nullopt), package_name_(package_name ? std::optional(*package_name) @@ -269,7 +273,10 @@ CreateMessage::CreateMessage(const std::string* asset, const std::string* uri, http_headers_(http_headers ? std::optional(*http_headers) : std::nullopt), drm_configs_(drm_configs ? std::optional(*drm_configs) - : std::nullopt) {} + : std::nullopt), + player_options_(player_options + ? std::optional(*player_options) + : std::nullopt) {} const std::string* CreateMessage::asset() const { return asset_ ? &(*asset_) : nullptr; @@ -345,9 +352,22 @@ void CreateMessage::set_drm_configs(const EncodableMap& value_arg) { drm_configs_ = value_arg; } +const EncodableMap* CreateMessage::player_options() const { + return player_options_ ? &(*player_options_) : nullptr; +} + +void CreateMessage::set_player_options(const EncodableMap* value_arg) { + player_options_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void CreateMessage::set_player_options(const EncodableMap& value_arg) { + player_options_ = value_arg; +} + EncodableList CreateMessage::ToEncodableList() const { EncodableList list; - list.reserve(6); + list.reserve(7); list.push_back(asset_ ? EncodableValue(*asset_) : EncodableValue()); list.push_back(uri_ ? EncodableValue(*uri_) : EncodableValue()); list.push_back(package_name_ ? EncodableValue(*package_name_) @@ -358,6 +378,8 @@ EncodableList CreateMessage::ToEncodableList() const { : EncodableValue()); list.push_back(drm_configs_ ? EncodableValue(*drm_configs_) : EncodableValue()); + list.push_back(player_options_ ? EncodableValue(*player_options_) + : EncodableValue()); return list; } @@ -387,6 +409,11 @@ CreateMessage CreateMessage::FromEncodableList(const EncodableList& list) { if (!encodable_drm_configs.IsNull()) { decoded.set_drm_configs(std::get(encodable_drm_configs)); } + auto& encodable_player_options = list[6]; + if (!encodable_player_options.IsNull()) { + decoded.set_player_options( + std::get(encodable_player_options)); + } return decoded; } @@ -613,7 +640,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.initialize", &GetCodec()); + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "initialize", + &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( [api](const EncodableValue& message, @@ -637,7 +666,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.create", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "create", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -671,7 +702,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.dispose", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "dispose", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -705,7 +738,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.setLooping", &GetCodec()); + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setLooping", + &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( [api](const EncodableValue& message, @@ -738,7 +773,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.setVolume", &GetCodec()); + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setVolume", + &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( [api](const EncodableValue& message, @@ -771,7 +808,8 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.setPlaybackSpeed", + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setPlaybackSpeed", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -805,7 +843,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.play", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "play", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -838,7 +878,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.position", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setDeactivate", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -853,14 +895,13 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } const auto& msg_arg = std::any_cast( std::get(encodable_msg_arg)); - ErrorOr output = api->Position(msg_arg); + ErrorOr output = api->SetDeactivate(msg_arg); if (output.has_error()) { reply(WrapError(output.error())); return; } EncodableList wrapped; - wrapped.push_back( - CustomEncodableValue(std::move(output).TakeValue())); + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); @@ -872,7 +913,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.seekTo", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setActivate", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -885,18 +928,16 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, reply(WrapError("msg_arg unexpectedly null.")); return; } - const auto& msg_arg = std::any_cast( + const auto& msg_arg = std::any_cast( std::get(encodable_msg_arg)); - api->SeekTo(msg_arg, - [reply](std::optional&& output) { - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - }); + ErrorOr output = api->SetActivate(msg_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -907,7 +948,9 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.track", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "track", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -942,7 +985,8 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.setTrackSelection", + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setTrackSelection", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -957,14 +1001,49 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } const auto& msg_arg = std::any_cast( std::get(encodable_msg_arg)); - std::optional output = - api->SetTrackSelection(msg_arg); - if (output.has_value()) { - reply(WrapError(output.value())); + ErrorOr output = api->SetTrackSelection(msg_arg); + if (output.has_error()) { + reply(WrapError(output.error())); return; } EncodableList wrapped; - wrapped.push_back(EncodableValue()); + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "position", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_msg_arg = args.at(0); + if (encodable_msg_arg.IsNull()) { + reply(WrapError("msg_arg unexpectedly null.")); + return; + } + const auto& msg_arg = std::any_cast( + std::get(encodable_msg_arg)); + ErrorOr output = api->Position(msg_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back( + CustomEncodableValue(std::move(output).TakeValue())); reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); @@ -976,7 +1055,46 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, } { auto channel = std::make_unique>( - binary_messenger, "dev.flutter.pigeon.VideoPlayerVideoholeApi.pause", + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "seekTo", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_msg_arg = args.at(0); + if (encodable_msg_arg.IsNull()) { + reply(WrapError("msg_arg unexpectedly null.")); + return; + } + const auto& msg_arg = std::any_cast( + std::get(encodable_msg_arg)); + api->SeekTo(msg_arg, + [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "pause", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -1010,7 +1128,8 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.setMixWithOthers", + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setMixWithOthers", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( @@ -1045,7 +1164,8 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, { auto channel = std::make_unique>( binary_messenger, - "dev.flutter.pigeon.VideoPlayerVideoholeApi.setDisplayGeometry", + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "setDisplayGeometry", &GetCodec()); if (api != nullptr) { channel->SetMessageHandler( diff --git a/packages/video_player_videohole/tizen/src/messages.h b/packages/video_player_videohole/tizen/src/messages.h index 3a40ddbb3..af3c6cd3e 100644 --- a/packages/video_player_videohole/tizen/src/messages.h +++ b/packages/video_player_videohole/tizen/src/messages.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_MESSAGES_H_ @@ -160,13 +160,13 @@ class TrackMessage { class TrackTypeMessage { public: // Constructs an object setting all fields. - explicit TrackTypeMessage(int64_t player_id, int64_t track_type); + explicit TrackTypeMessage(int64_t player_id, const std::string& track_type); int64_t player_id() const; void set_player_id(int64_t value_arg); - int64_t track_type() const; - void set_track_type(int64_t value_arg); + const std::string& track_type() const; + void set_track_type(std::string_view value_arg); private: static TrackTypeMessage FromEncodableList(const flutter::EncodableList& list); @@ -174,7 +174,7 @@ class TrackTypeMessage { friend class VideoPlayerVideoholeApi; friend class VideoPlayerVideoholeApiCodecSerializer; int64_t player_id_; - int64_t track_type_; + std::string track_type_; }; // Generated class from Pigeon that represents data sent in messages. @@ -182,7 +182,7 @@ class SelectedTracksMessage { public: // Constructs an object setting all fields. explicit SelectedTracksMessage(int64_t player_id, int64_t track_id, - int64_t track_type); + const std::string& track_type); int64_t player_id() const; void set_player_id(int64_t value_arg); @@ -190,8 +190,8 @@ class SelectedTracksMessage { int64_t track_id() const; void set_track_id(int64_t value_arg); - int64_t track_type() const; - void set_track_type(int64_t value_arg); + const std::string& track_type() const; + void set_track_type(std::string_view value_arg); private: static SelectedTracksMessage FromEncodableList( @@ -201,7 +201,7 @@ class SelectedTracksMessage { friend class VideoPlayerVideoholeApiCodecSerializer; int64_t player_id_; int64_t track_id_; - int64_t track_type_; + std::string track_type_; }; // Generated class from Pigeon that represents data sent in messages. @@ -236,7 +236,8 @@ class CreateMessage { const std::string* package_name, const std::string* format_hint, const flutter::EncodableMap* http_headers, - const flutter::EncodableMap* drm_configs); + const flutter::EncodableMap* drm_configs, + const flutter::EncodableMap* player_options); const std::string* asset() const; void set_asset(const std::string_view* value_arg); @@ -262,6 +263,10 @@ class CreateMessage { void set_drm_configs(const flutter::EncodableMap* value_arg); void set_drm_configs(const flutter::EncodableMap& value_arg); + const flutter::EncodableMap* player_options() const; + void set_player_options(const flutter::EncodableMap* value_arg); + void set_player_options(const flutter::EncodableMap& value_arg); + private: static CreateMessage FromEncodableList(const flutter::EncodableList& list); flutter::EncodableList ToEncodableList() const; @@ -273,6 +278,7 @@ class CreateMessage { std::optional format_hint_; std::optional http_headers_; std::optional drm_configs_; + std::optional player_options_; }; // Generated class from Pigeon that represents data sent in messages. @@ -359,13 +365,14 @@ class VideoPlayerVideoholeApi { virtual std::optional SetPlaybackSpeed( const PlaybackSpeedMessage& msg) = 0; virtual std::optional Play(const PlayerMessage& msg) = 0; + virtual ErrorOr SetDeactivate(const PlayerMessage& msg) = 0; + virtual ErrorOr SetActivate(const PlayerMessage& msg) = 0; + virtual ErrorOr Track(const TrackTypeMessage& msg) = 0; + virtual ErrorOr SetTrackSelection(const SelectedTracksMessage& msg) = 0; virtual ErrorOr Position(const PlayerMessage& msg) = 0; virtual void SeekTo( const PositionMessage& msg, std::function reply)> result) = 0; - virtual ErrorOr Track(const TrackTypeMessage& msg) = 0; - virtual std::optional SetTrackSelection( - const SelectedTracksMessage& msg) = 0; virtual std::optional Pause(const PlayerMessage& msg) = 0; virtual std::optional SetMixWithOthers( const MixWithOthersMessage& msg) = 0; diff --git a/packages/video_player_videohole/tizen/src/pending_call.h b/packages/video_player_videohole/tizen/src/pending_call.h deleted file mode 100644 index 9728a6f7b..000000000 --- a/packages/video_player_videohole/tizen/src/pending_call.h +++ /dev/null @@ -1,90 +0,0 @@ -// 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. - -#ifndef FLUTTER_PLUGIN_PENDING_CALL_H_ -#define FLUTTER_PLUGIN_PENDING_CALL_H_ - -#include - -#include -#include - -#include "log.h" - -class PendingCall { - public: - PendingCall(void **buffer, size_t *length) - : response_buffer_(buffer), response_length_(length) { - receive_port_ = - Dart_NewNativePort_DL("cpp-response", &PendingCall::HandleResponse, - /*handle_concurrently=*/false); - } - ~PendingCall() { Dart_CloseNativePort_DL(receive_port_); } - - Dart_Port port() const { return receive_port_; } - - void PostAndWait(Dart_Port port, Dart_CObject *object) { - std::unique_lock lock(mutex); - const bool success = Dart_PostCObject_DL(port, object); - if (!success) { - LOG_ERROR("[ffi] Failed to send message, invalid port or isolate died."); - return; - } - - LOG_INFO("[ffi] Waiting for result."); - while (!notified) { - cv.wait(lock); - } - } - - static void HandleResponse(Dart_Port port, Dart_CObject *message) { - if (message->type != Dart_CObject_kArray) { - LOG_ERROR("[ffi] Wrong Data: message->type != Dart_CObject_kArray"); - } - Dart_CObject **c_response_args = message->value.as_array.values; - Dart_CObject *c_pending_call = c_response_args[0]; - Dart_CObject *c_message = c_response_args[1]; - LOG_INFO("[ffi] HandleResponse (call: %d)", - reinterpret_cast(c_pending_call)); - - auto *pending_call = reinterpret_cast( - c_pending_call->type == Dart_CObject_kInt64 - ? c_pending_call->value.as_int64 - : c_pending_call->value.as_int32); - - pending_call->ResolveCall(c_message); - } - - private: - static bool NonEmptyBuffer(void **value) { return *value != nullptr; } - - void ResolveCall(Dart_CObject *bytes) { - assert(bytes->type == Dart_CObject_kTypedData); - if (bytes->type != Dart_CObject_kTypedData) { - LOG_ERROR("[ffi] Wrong Data: bytes->type != Dart_CObject_kTypedData"); - } - const intptr_t response_length = bytes->value.as_typed_data.length; - const uint8_t *response_buffer = bytes->value.as_typed_data.values; - - void *buffer = malloc(response_length); - memmove(buffer, response_buffer, response_length); - - *response_buffer_ = buffer; - *response_length_ = response_length; - - LOG_INFO("[ffi] Notify result ready."); - notified = true; - cv.notify_one(); - } - - std::mutex mutex; - std::condition_variable cv; - bool notified = false; - - Dart_Port receive_port_; - void **response_buffer_; - size_t *response_length_; -}; - -#endif // FLUTTER_PLUGIN_PENDING_CALL_H_ diff --git a/packages/video_player_videohole/tizen/src/video_player.cc b/packages/video_player_videohole/tizen/src/video_player.cc index 4bbc25dd9..56981f1a6 100644 --- a/packages/video_player_videohole/tizen/src/video_player.cc +++ b/packages/video_player_videohole/tizen/src/video_player.cc @@ -4,605 +4,48 @@ #include "video_player.h" -#include #include #include -#include - #include "log.h" -#include "pending_call.h" static int64_t player_index = 1; -template -static bool GetValueFromEncodableMap(const flutter::EncodableMap *map, - const char *key, T &out) { - auto iter = map->find(flutter::EncodableValue(key)); - if (iter != map->end()) { - if (std::holds_alternative(iter->second)) { - out = std::get(iter->second); - return true; - } - } - return false; -} - -VideoPlayer::VideoPlayer(flutter::PluginRegistrar *plugin_registrar, - void *native_window) - : plugin_registrar_(plugin_registrar), native_window_(native_window) { +VideoPlayer::VideoPlayer(flutter::BinaryMessenger *messenger, + FlutterDesktopViewRef flutter_view) + : ecore_wl2_window_proxy_(std::make_unique()), + binary_messenger_(messenger), + flutter_view_(flutter_view) { sink_event_pipe_ = ecore_pipe_add( [](void *data, void *buffer, unsigned int nbyte) -> void { auto *self = static_cast(data); - self->SendPendingEvents(); + self->ExecuteSinkEvents(); }, this); } -void VideoPlayer::SendPendingEvents() { - std::lock_guard lock(queue_mutex_); - while (!encodable_event_queue_.empty()) { - if (event_sink_) { - event_sink_->Success(encodable_event_queue_.front()); - } - encodable_event_queue_.pop(); - } - - while (!error_event_queue_.empty()) { - if (event_sink_) { - event_sink_->Error(error_event_queue_.front().first, - error_event_queue_.front().second); - } - error_event_queue_.pop(); - } -} - -void VideoPlayer::PushEvent(const flutter::EncodableValue &encodable_value) { - if (!event_sink_) { - LOG_ERROR("[VideoPlayer] event sink is nullptr."); - return; - } - std::lock_guard lock(queue_mutex_); - encodable_event_queue_.push(encodable_value); - ecore_pipe_write(sink_event_pipe_, nullptr, 0); -} - -void VideoPlayer::SendError(const std::string &error_code, - const std::string &error_message) { - if (!event_sink_) { - LOG_ERROR("[VideoPlayer] event sink is nullptr."); - return; - } - std::lock_guard lock(queue_mutex_); - error_event_queue_.push(std::make_pair(error_code, error_message)); - ecore_pipe_write(sink_event_pipe_, nullptr, 0); -} - -bool VideoPlayer::SetDisplay() { - int x = 0, y = 0, width = 0, height = 0; - void *ecore_lib_handle = dlopen("libecore_wl2.so.1", RTLD_LAZY); - if (ecore_lib_handle) { - FuncEcoreWl2WindowGeometryGet ecore_wl2_window_geometry_get = - reinterpret_cast( - dlsym(ecore_lib_handle, "ecore_wl2_window_geometry_get")); - if (ecore_wl2_window_geometry_get) { - ecore_wl2_window_geometry_get(native_window_, &x, &y, &width, &height); - } else { - LOG_ERROR("[VideoPlayer] Symbol not found: %s", dlerror()); - dlclose(ecore_lib_handle); - return false; - } - dlclose(ecore_lib_handle); - } else { - LOG_ERROR("[VideoPlayer] dlopen failed: %s", dlerror()); - return false; - } - - void *player_lib_handle = dlopen("libcapi-media-player.so.0", RTLD_LAZY); - if (player_lib_handle) { - FuncPlayerSetEcoreWlDisplay player_set_ecore_wl_display = - reinterpret_cast( - dlsym(player_lib_handle, "player_set_ecore_wl_display")); - if (player_set_ecore_wl_display) { - int ret = - player_set_ecore_wl_display(player_, PLAYER_DISPLAY_TYPE_OVERLAY, - native_window_, x, y, width, height); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_ecore_wl_display failed: %s", - get_error_message(ret)); - dlclose(player_lib_handle); - return false; - } - } else { - LOG_ERROR("[VideoPlayer] Symbol not found: %s", dlerror()); - dlclose(ecore_lib_handle); - return false; - } - dlclose(player_lib_handle); - } else { - LOG_ERROR("[VideoPlayer] dlopen failed: %s", dlerror()); - return false; - } - - int ret = player_set_display_mode(player_, PLAYER_DISPLAY_MODE_DST_ROI); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_display_mode failed: %s", - get_error_message(ret)); - return false; - } - return true; -} - -int64_t VideoPlayer::Create(const std::string &uri, int drm_type, - const std::string &license_server_url, - const flutter::EncodableMap *http_headers) { - LOG_INFO("[VideoPlayer] uri: %s, drm_type: %d", uri.c_str(), drm_type); - - player_id_ = player_index++; - - if (uri.empty()) { - LOG_ERROR("[VideoPlayer] The uri must not be empty."); - return -1; - } - - int ret = player_create(&player_); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_create failed: %s", get_error_message(ret)); - return -1; - } - - if (drm_type != DRM_TYPE_NONE) { - drm_manager_ = - std::make_unique(drm_type, license_server_url, player_); - drm_manager_->SetChallengeCallback( - [this](const std::vector &challenge) -> std::vector { - return OnLicenseChallenge(challenge); - }); - - if (!drm_manager_->InitializeDrmSession(uri)) { - LOG_ERROR("[VideoPlayer] Failed to initialize the DRM session."); - drm_manager_->ReleaseDrmSession(); - } - } - - if (http_headers && !http_headers->empty()) { - std::string cookie; - if (GetValueFromEncodableMap(http_headers, "Cookie", cookie)) { - ret = player_set_streaming_cookie(player_, cookie.c_str(), cookie.size()); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[MediaPlayer] player_set_streaming_cookie failed: %s.", - get_error_message(ret)); - } - } - - std::string user_agent; - if (GetValueFromEncodableMap(http_headers, "User-Agent", user_agent)) { - ret = player_set_streaming_user_agent(player_, user_agent.c_str(), - user_agent.size()); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[MediaPlayer] player_set_streaming_user_agent failed: %s.", - get_error_message(ret)); - } - } - } - - ret = player_set_uri(player_, uri.c_str()); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_uri failed: %s", - get_error_message(ret)); - return -1; - } - - if (!SetDisplay()) { - LOG_ERROR("[VideoPlayer] Failed to set display."); - return -1; - } - SetDisplayRoi(0, 0, 1, 1); - - ret = player_set_display_visible(player_, true); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_display_visible failed: %s", - get_error_message(ret)); - return -1; - } - - ret = player_set_buffering_cb(player_, OnBuffering, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_buffering_cb failed: %s", - get_error_message(ret)); - return -1; - } - - ret = player_set_completed_cb(player_, OnPlayCompleted, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_completed_cb failed: %s", - get_error_message(ret)); - return -1; - } - - ret = player_set_interrupted_cb(player_, OnInterrupted, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_interrupted_cb failed: %s", - get_error_message(ret)); - return -1; - } - - ret = player_set_error_cb(player_, OnError, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_error_cb failed: %s", - get_error_message(ret)); - return -1; - } - - ret = player_prepare_async(player_, OnPrepared, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_prepare_async failed: %s", - get_error_message(ret)); - return -1; - } - - ret = player_set_subtitle_updated_cb(player_, OnSubtitleUpdated, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_subtitle_updated_cb failed: %s", - get_error_message(ret)); - } - - SetUpEventChannel(plugin_registrar_->messenger()); - - return player_id_; -} - -void VideoPlayer::SetDisplayRoi(int32_t x, int32_t y, int32_t width, - int32_t height) { - int ret = player_set_display_roi_area(player_, x, y, width, height); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_display_roi_area failed: %s", - get_error_message(ret)); - } -} - VideoPlayer::~VideoPlayer() { - if (drm_manager_) { - drm_manager_->ReleaseDrmSession(); - } - Dispose(); -} - -void VideoPlayer::Play() { - LOG_INFO("[VideoPlayer] Player starting."); - - player_state_e state = PLAYER_STATE_NONE; - int ret = player_get_state(player_, &state); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] Unable to get player state."); - return; - } - if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { - LOG_ERROR("[VideoPlayer] Player not ready."); - return; - } - if (state == PLAYER_STATE_PLAYING) { - LOG_INFO("[VideoPlayer] Player already playing."); - return; - } - - ret = player_start(player_); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_start failed: %s", get_error_message(ret)); - } -} - -void VideoPlayer::Pause() { - LOG_INFO("[VideoPlayer] Player pausing."); - - player_state_e state = PLAYER_STATE_NONE; - int ret = player_get_state(player_, &state); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] Unable to get player state."); - return; - } - if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { - LOG_ERROR("[VideoPlayer] Player not ready."); - return; - } - if (state != PLAYER_STATE_PLAYING) { - LOG_INFO("[VideoPlayer] Player not playing."); - return; - } - - ret = player_pause(player_); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_pause failed: %s", get_error_message(ret)); - } -} - -void VideoPlayer::SetLooping(bool is_looping) { - LOG_INFO("[VideoPlayer] is_looping: %d", is_looping); - - int ret = player_set_looping(player_, is_looping); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_looping failed: %s", - get_error_message(ret)); - } -} - -void VideoPlayer::SetVolume(double volume) { - LOG_INFO("[VideoPlayer] volume: %f", volume); - - int ret = player_set_volume(player_, volume, volume); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_volume failed: %s", - get_error_message(ret)); - } -} - -void VideoPlayer::SetPlaybackSpeed(double speed) { - LOG_INFO("[VideoPlayer] speed: %f", speed); - - int ret = player_set_playback_rate(player_, speed); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_playback_rate failed: %s", - get_error_message(ret)); - } -} - -flutter::EncodableList VideoPlayer::getTrackInfo(int32_t track_type) { - player_state_e state = PLAYER_STATE_NONE; - int ret = player_get_state(player_, &state); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_state failed: %s", - get_error_message(ret)); - return {}; - } - if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { - LOG_ERROR("[VideoPlayer] Player not ready."); - return {}; - } - - void *player_lib_handle = dlopen("libcapi-media-player.so.0", RTLD_LAZY); - if (!player_lib_handle) { - LOG_ERROR("[VideoPlayer] dlopen failed: %s", dlerror()); - return {}; - } - - FuncPlayerGetTrackCountV2 player_get_track_count_v2 = - reinterpret_cast( - dlsym(player_lib_handle, "player_get_track_count_v2")); - if (!player_get_track_count_v2) { - LOG_ERROR("[VideoPlayer] Symbol not found: %s", dlerror()); - dlclose(player_lib_handle); - return {}; - } - - int track_count = 0; - ret = player_get_track_count_v2(player_, (player_stream_type_e)track_type, - &track_count); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_track_count_v2 failed: %s", - get_error_message(ret)); - dlclose(player_lib_handle); - return {}; - } - if (track_count <= 0) { - return {}; - } - - flutter::EncodableList trackSelections = {}; - if (track_type == PLAYER_STREAM_TYPE_VIDEO) { - LOG_INFO("[VideoPlayer] video_count: %d", track_count); - - FuncPlayerGetVideoTrackInfoV2 player_get_video_track_info_v2 = - reinterpret_cast( - dlsym(player_lib_handle, "player_get_video_track_info_v2")); - if (!player_get_video_track_info_v2) { - LOG_ERROR("[VideoPlayer] Symbol not found: %s", dlerror()); - dlclose(player_lib_handle); - return {}; - } - - for (int video_index = 0; video_index < track_count; video_index++) { - flutter::EncodableMap trackSelection = {}; - player_video_track_info_v2 *video_track_info = nullptr; - - ret = player_get_video_track_info_v2(player_, video_index, - &video_track_info); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_video_track_info_v2 failed: %s", - get_error_message(ret)); - dlclose(player_lib_handle); - return {}; - } - LOG_INFO( - "[VideoPlayer] video track info: width[%d], height[%d], " - "bitrate[%d]", - video_track_info->width, video_track_info->height, - video_track_info->bit_rate); - - trackSelection.insert( - {flutter::EncodableValue("trackType"), - flutter::EncodableValue(PLAYER_STREAM_TYPE_VIDEO)}); - trackSelection.insert({flutter::EncodableValue("trackId"), - flutter::EncodableValue(video_index)}); - trackSelection.insert({flutter::EncodableValue("width"), - flutter::EncodableValue(video_track_info->width)}); - trackSelection.insert( - {flutter::EncodableValue("height"), - flutter::EncodableValue(video_track_info->height)}); - trackSelection.insert( - {flutter::EncodableValue("bitrate"), - flutter::EncodableValue(video_track_info->bit_rate)}); - - trackSelections.push_back(flutter::EncodableValue(trackSelection)); - } - - } else if (track_type == PLAYER_STREAM_TYPE_AUDIO) { - LOG_INFO("[VideoPlayer] audio_count: %d", track_count); - - FuncPlayerGetAudioTrackInfoV2 player_get_audio_track_info_v2 = - reinterpret_cast( - dlsym(player_lib_handle, "player_get_audio_track_info_v2")); - if (!player_get_audio_track_info_v2) { - LOG_ERROR("[VideoPlayer] Symbol not found: %s", dlerror()); - dlclose(player_lib_handle); - return {}; - } - - for (int audio_index = 0; audio_index < track_count; audio_index++) { - flutter::EncodableMap trackSelection = {}; - player_audio_track_info_v2 *audio_track_info = nullptr; - - ret = player_get_audio_track_info_v2(player_, audio_index, - &audio_track_info); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_audio_track_info_v2 failed: %s", - get_error_message(ret)); - dlclose(player_lib_handle); - return {}; - } - LOG_INFO( - "[VideoPlayer] audio track info: language[%s], channel[%d], " - "sample_rate[%d], bitrate[%d]", - audio_track_info->language, audio_track_info->channel, - audio_track_info->sample_rate, audio_track_info->bit_rate); - - trackSelection.insert( - {flutter::EncodableValue("trackType"), - flutter::EncodableValue(PLAYER_STREAM_TYPE_AUDIO)}); - trackSelection.insert({flutter::EncodableValue("trackId"), - flutter::EncodableValue(audio_index)}); - trackSelection.insert( - {flutter::EncodableValue("language"), - flutter::EncodableValue(std::string(audio_track_info->language))}); - trackSelection.insert( - {flutter::EncodableValue("channel"), - flutter::EncodableValue(audio_track_info->channel)}); - trackSelection.insert( - {flutter::EncodableValue("bitrate"), - flutter::EncodableValue(audio_track_info->bit_rate)}); - - trackSelections.push_back(flutter::EncodableValue(trackSelection)); - } - - } else if (track_type == PLAYER_STREAM_TYPE_TEXT) { - LOG_INFO("[VideoPlayer] subtitle_count: %d", track_count); - - FuncPlayerGetSubtitleTrackInfoV2 player_get_subtitle_track_info_v2 = - reinterpret_cast( - dlsym(player_lib_handle, "player_get_subtitle_track_info_v2")); - if (!player_get_subtitle_track_info_v2) { - LOG_ERROR("[VideoPlayer] Symbol not found: %s", dlerror()); - dlclose(player_lib_handle); - return {}; - } - - for (int sub_index = 0; sub_index < track_count; sub_index++) { - flutter::EncodableMap trackSelection = {}; - player_subtitle_track_info_v2 *sub_track_info = nullptr; - - ret = player_get_subtitle_track_info_v2(player_, sub_index, - &sub_track_info); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_subtitle_track_info_v2 failed: %s", - get_error_message(ret)); - dlclose(player_lib_handle); - return {}; - } - LOG_INFO( - "[VideoPlayer] subtitle track info: language[%s], " - "subtitle_type[%d]", - sub_track_info->language, sub_track_info->subtitle_type); - - trackSelection.insert({flutter::EncodableValue("trackType"), - flutter::EncodableValue(PLAYER_STREAM_TYPE_TEXT)}); - trackSelection.insert({flutter::EncodableValue("trackId"), - flutter::EncodableValue(sub_index)}); - trackSelection.insert( - {flutter::EncodableValue("language"), - flutter::EncodableValue(std::string(sub_track_info->language))}); - trackSelection.insert( - {flutter::EncodableValue("subtitleType"), - flutter::EncodableValue(sub_track_info->subtitle_type)}); - - trackSelections.push_back(flutter::EncodableValue(trackSelection)); - } - } - - dlclose(player_lib_handle); - return trackSelections; -} - -void VideoPlayer::SetTrackSelection(int32_t track_id, int32_t track_type) { - LOG_INFO("[VideoPlayer] track_id: %d,track_type: %d", track_id, track_type); - - player_state_e state = PLAYER_STATE_NONE; - int ret = player_get_state(player_, &state); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_state failed: %s", - get_error_message(ret)); - return; - } - if (state == PLAYER_STATE_NONE || state == PLAYER_STATE_IDLE) { - LOG_ERROR("[VideoPlayer] Player not ready."); - return; - } - - ret = - player_select_track(player_, (player_stream_type_e)track_type, track_id); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_select_track failed: %s", - get_error_message(ret)); - } -} - -void VideoPlayer::SeekTo(int32_t position, SeekCompletedCallback callback) { - LOG_INFO("[VideoPlayer] position: %d", position); - - on_seek_completed_ = std::move(callback); - int ret = - player_set_play_position(player_, position, true, OnSeekCompleted, this); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_set_play_position failed: %s", - get_error_message(ret)); - } -} - -int32_t VideoPlayer::GetPosition() { - int position = 0; - int ret = player_get_play_position(player_, &position); - if (ret != PLAYER_ERROR_NONE) { - LOG_ERROR("[VideoPlayer] player_get_play_position failed: %s", - get_error_message(ret)); + if (sink_event_pipe_) { + ecore_pipe_del(sink_event_pipe_); + sink_event_pipe_ = nullptr; } - return position; } -void VideoPlayer::Dispose() { - LOG_INFO("[VideoPlayer] Player disposing."); - +void VideoPlayer::ClearUpEventChannel() { is_initialized_ = false; event_sink_ = nullptr; - event_channel_->SetStreamHandler(nullptr); - if (sink_event_pipe_) { - ecore_pipe_del(sink_event_pipe_); - } - - if (player_) { - player_unprepare(player_); - player_unset_buffering_cb(player_); - player_unset_completed_cb(player_); - player_unset_interrupted_cb(player_); - player_unset_error_cb(player_); - player_destroy(player_); - player_ = nullptr; + if (event_channel_) { + event_channel_->SetStreamHandler(nullptr); } } -void VideoPlayer::SetUpEventChannel(flutter::BinaryMessenger *messenger) { +int64_t VideoPlayer::SetUpEventChannel() { + int64_t player_id = player_index++; std::string channel_name = - "tizen/video_player/video_events_" + std::to_string(player_id_); + "tizen/video_player/video_events_" + std::to_string(player_id); auto channel = std::make_unique>( - messenger, channel_name, + binary_messenger_, channel_name, &flutter::StandardMethodCodec::GetInstance()); auto handler = std::make_unique< flutter::StreamHandlerFunctions>( @@ -610,7 +53,11 @@ void VideoPlayer::SetUpEventChannel(flutter::BinaryMessenger *messenger) { std::unique_ptr> &&events) -> std::unique_ptr> { event_sink_ = std::move(events); - Initialize(); + if (IsReady()) { + SendInitialized(); + } else { + LOG_INFO("[VideoPlayer] Player is not ready."); + } return nullptr; }, [&](const flutter::EncodableValue *arguments) @@ -619,53 +66,43 @@ void VideoPlayer::SetUpEventChannel(flutter::BinaryMessenger *messenger) { return nullptr; }); channel->SetStreamHandler(std::move(handler)); - event_channel_ = std::move(channel); + return player_id; } -void VideoPlayer::Initialize() { - player_state_e state = PLAYER_STATE_NONE; - int ret = player_get_state(player_, &state); - if (ret == PLAYER_ERROR_NONE) { - LOG_INFO("[VideoPlayer] Player state: %d", state); - if (state == PLAYER_STATE_READY && !is_initialized_) { - SendInitialized(); +void VideoPlayer::ExecuteSinkEvents() { + std::lock_guard lock(queue_mutex_); + while (!encodable_event_queue_.empty()) { + if (event_sink_) { + event_sink_->Success(encodable_event_queue_.front()); } - } else { - LOG_ERROR("[VideoPlayer] player_get_state failed: %s", - get_error_message(ret)); + encodable_event_queue_.pop(); } -} -void VideoPlayer::SendInitialized() { - if (!is_initialized_ && !is_interrupted_ && event_sink_) { - int duration = 0; - int ret = player_get_duration(player_, &duration); - if (ret != PLAYER_ERROR_NONE) { - SendError("player_get_duration failed", get_error_message(ret)); - return; - } - LOG_INFO("[VideoPlayer] Video duration: %d", duration); - - int width = 0, height = 0; - ret = player_get_video_size(player_, &width, &height); - if (ret != PLAYER_ERROR_NONE) { - SendError("player_get_video_size failed", get_error_message(ret)); - return; + while (!error_event_queue_.empty()) { + if (event_sink_) { + event_sink_->Error(error_event_queue_.front().first, + error_event_queue_.front().second); } - LOG_INFO("[VideoPlayer] Video width: %d, height: %d", width, height); + error_event_queue_.pop(); + } +} - player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE; - ret = player_get_display_rotation(player_, &rotation); - if (ret != PLAYER_ERROR_NONE) { - SendError("player_get_display_rotation failed", get_error_message(ret)); - } else { - if (rotation == PLAYER_DISPLAY_ROTATION_90 || - rotation == PLAYER_DISPLAY_ROTATION_270) { - std::swap(width, height); - } - } +void VideoPlayer::PushEvent(flutter::EncodableValue encodable_value) { + std::lock_guard lock(queue_mutex_); + if (event_sink_ == nullptr) { + LOG_ERROR("[VideoPlayer] event sink is nullptr."); + return; + } + encodable_event_queue_.push(encodable_value); + ecore_pipe_write(sink_event_pipe_, nullptr, 0); +} +void VideoPlayer::SendInitialized() { + if (!is_initialized_ && event_sink_) { + int32_t width = 0, height = 0; + int64_t duration = GetDuration(); + GetVideoSize(&width, &height); is_initialized_ = true; flutter::EncodableMap result = { {flutter::EncodableValue("event"), @@ -715,123 +152,22 @@ void VideoPlayer::SendSubtitleUpdate(int32_t duration, PushEvent(flutter::EncodableValue(result)); } -void VideoPlayer::OnSubtitleUpdated(unsigned long duration, char *text, - void *data) { - LOG_INFO("[VideoPlayer] duration: %ld, text: %s", duration, text); - - VideoPlayer *player = static_cast(data); - player->SendSubtitleUpdate(duration, std::string(text)); -} - -void VideoPlayer::OnPrepared(void *data) { - LOG_INFO("[VideoPlayer] Player prepared."); - - VideoPlayer *player = static_cast(data); - if (!player->is_initialized_) { - player->SendInitialized(); - } -} - -void VideoPlayer::OnBuffering(int percent, void *data) { - LOG_INFO("[VideoPlayer] percent: %d", percent); - - VideoPlayer *player = static_cast(data); - if (percent == 100) { - player->SendBufferingEnd(); - player->is_buffering_ = false; - } else if (!player->is_buffering_ && percent <= 5) { - player->SendBufferingStart(); - player->is_buffering_ = true; - } else { - player->SendBufferingUpdate(percent); - } -} - -void VideoPlayer::OnSeekCompleted(void *data) { - LOG_INFO("[VideoPlayer] Seek completed."); - - VideoPlayer *player = static_cast(data); - if (player->on_seek_completed_) { - player->on_seek_completed_(); - player->on_seek_completed_ = nullptr; - } -} - -void VideoPlayer::OnPlayCompleted(void *data) { - LOG_INFO("[VideoPlayer] Play completed."); - - VideoPlayer *player = static_cast(data); +void VideoPlayer::SendPlayCompleted() { flutter::EncodableMap result = { {flutter::EncodableValue("event"), flutter::EncodableValue("completed")}, }; - player->PushEvent(flutter::EncodableValue(result)); - - player->Pause(); -} - -void VideoPlayer::OnError(int error_code, void *data) { - LOG_ERROR("[VideoPlayer] Error code: %d (%s)", error_code, - get_error_message(error_code)); - - VideoPlayer *player = static_cast(data); - player->SendError("Player error", - std::string("Error: ") + get_error_message(error_code)); + PushEvent(flutter::EncodableValue(result)); } -void VideoPlayer::OnInterrupted(player_interrupted_code_e code, void *data) { - LOG_ERROR("[VideoPlayer] Interrupt code: %d", code); - - VideoPlayer *player = static_cast(data); - player->is_interrupted_ = true; - player->SendError("Player interrupted", "Video player has been interrupted."); +void VideoPlayer::SendError(const std::string &error_code, + const std::string &error_message) { + if (event_sink_) { + std::lock_guard lock(queue_mutex_); + error_event_queue_.push(std::make_pair(error_code, error_message)); + ecore_pipe_write(sink_event_pipe_, nullptr, 0); + } } -std::vector VideoPlayer::OnLicenseChallenge( - const std::vector &challenge) { - const char *method_name = "onLicenseChallenge"; - size_t request_length = challenge.size(); - void *request_buffer = malloc(request_length); - memcpy(request_buffer, challenge.data(), challenge.size()); - - void *response_buffer = nullptr; - size_t response_length = 0; - PendingCall pending_call(&response_buffer, &response_length); - - Dart_CObject c_send_port; - c_send_port.type = Dart_CObject_kSendPort; - c_send_port.value.as_send_port.id = pending_call.port(); - c_send_port.value.as_send_port.origin_id = ILLEGAL_PORT; - - Dart_CObject c_pending_call; - c_pending_call.type = Dart_CObject_kInt64; - c_pending_call.value.as_int64 = reinterpret_cast(&pending_call); - - Dart_CObject c_method_name; - c_method_name.type = Dart_CObject_kString; - c_method_name.value.as_string = const_cast(method_name); - - Dart_CObject c_request_data; - c_request_data.type = Dart_CObject_kExternalTypedData; - c_request_data.value.as_external_typed_data.type = Dart_TypedData_kUint8; - c_request_data.value.as_external_typed_data.length = request_length; - c_request_data.value.as_external_typed_data.data = - static_cast(request_buffer); - c_request_data.value.as_external_typed_data.peer = request_buffer; - c_request_data.value.as_external_typed_data.callback = - [](void *isolate_callback_data, void *peer) { free(peer); }; - - Dart_CObject *c_request_arr[] = {&c_send_port, &c_pending_call, - &c_method_name, &c_request_data}; - Dart_CObject c_request; - c_request.type = Dart_CObject_kArray; - c_request.value.as_array.values = c_request_arr; - c_request.value.as_array.length = - sizeof(c_request_arr) / sizeof(c_request_arr[0]); - - pending_call.PostAndWait(send_port_, &c_request); - LOG_INFO("[ffi] Received result (size: %d)", response_length); - - return std::vector( - static_cast(response_buffer), - static_cast(response_buffer) + response_length); +void *VideoPlayer::GetWindowHandle() { + return FlutterDesktopViewGetNativeHandle(flutter_view_); } diff --git a/packages/video_player_videohole/tizen/src/video_player.h b/packages/video_player_videohole/tizen/src/video_player.h index 0eb02900e..53c1ebd92 100644 --- a/packages/video_player_videohole/tizen/src/video_player.h +++ b/packages/video_player_videohole/tizen/src/video_player.h @@ -6,139 +6,80 @@ #define FLUTTER_PLUGIN_VIDEO_PLAYER_H_ #include -#include #include #include -#include -#include +#include #include #include #include #include -#include +#include -#include "drm_manager.h" -#include "video_player_options.h" - -#define MAX_STRING_NAME_LEN 255 -#define MMPLAYER_FOUR_CC_LEN 14 -#define PLAYER_LANG_NAME_SIZE 10 - -typedef struct { - char fourCC[MMPLAYER_FOUR_CC_LEN + 1]; /**< codec fourcc */ - char name[MAX_STRING_NAME_LEN]; /**< name: video/audio, it maybe not exit in - some track*/ - /*dynamic infos in hls,ss,dash streams*/ - int width; /**< resolution width */ - int height; /**< resolution height */ - int bit_rate; /**< bitrate in bps */ -} player_video_track_info_v2; - -typedef struct { - char fourCC[MMPLAYER_FOUR_CC_LEN + 1]; /**< codec fourcc */ - char language[PLAYER_LANG_NAME_SIZE]; /**< language info*/ - /*dynamic infos in hls,ss,dash streams*/ - int sample_rate; /**< sample rate in this track*/ - int channel; /**< channel in this track*/ - int bit_rate; /**< bitrate in this track*/ -} player_audio_track_info_v2; - -typedef struct { - char fourCC[MMPLAYER_FOUR_CC_LEN + 1]; /**< codec fourcc */ - char language[PLAYER_LANG_NAME_SIZE]; /**< language info*/ - int subtitle_type; /**< text subtitle = 0, picture subtitle = 1 */ -} player_subtitle_track_info_v2; - -typedef void (*FuncEcoreWl2WindowGeometryGet)(void *window, int *x, int *y, - int *width, int *height); -typedef int (*FuncPlayerSetEcoreWlDisplay)(player_h player, - player_display_type_e type, - void *ecore_wl_window, int x, int y, - int width, int height); -typedef int (*FuncPlayerGetTrackCountV2)(player_h player, - player_stream_type_e type, - int *pcount); -typedef int (*FuncPlayerGetVideoTrackInfoV2)( - player_h player, int index, player_video_track_info_v2 **track_info); -typedef int (*FuncPlayerGetAudioTrackInfoV2)( - player_h player, int index, player_audio_track_info_v2 **track_info); -typedef int (*FuncPlayerGetSubtitleTrackInfoV2)( - player_h player, int index, player_subtitle_track_info_v2 **track_info); +#include "ecore_wl2_window_proxy.h" class VideoPlayer { public: using SeekCompletedCallback = std::function; - explicit VideoPlayer(flutter::PluginRegistrar *plugin_registrar, - void *native_window); - ~VideoPlayer(); - - int64_t Create(const std::string &uri, int drm_type, - const std::string &license_server_url, - const flutter::EncodableMap *http_headers); - void Dispose(); - - void SetDisplayRoi(int32_t x, int32_t y, int32_t width, int32_t height); - void Play(); - void Pause(); - void SetLooping(bool is_looping); - void SetVolume(double volume); - void SetPlaybackSpeed(double speed); - void SeekTo(int32_t position, SeekCompletedCallback callback); - int32_t GetPosition(); - flutter::EncodableList getTrackInfo(int32_t track_type); - void SetTrackSelection(int32_t track_id, int32_t track_type); - - void RegisterSendPort(Dart_Port send_port) { send_port_ = send_port; } - - private: - void SendPendingEvents(); - void PushEvent(const flutter::EncodableValue &encodable_value); - void SendError(const std::string &error_code, - const std::string &error_message); - bool SetDisplay(); - void SetUpEventChannel(flutter::BinaryMessenger *messenger); - void Initialize(); - + explicit VideoPlayer(flutter::BinaryMessenger *messenger, + FlutterDesktopViewRef flutter_view); + VideoPlayer(const VideoPlayer &) = delete; + VideoPlayer &operator=(const VideoPlayer &) = delete; + virtual ~VideoPlayer(); + + virtual int64_t Create(const std::string &uri, int drm_type, + const std::string &license_server_url, + bool is_prebuffer_mode, + flutter::EncodableMap &http_headers) = 0; + virtual void Dispose() = 0; + + virtual void SetDisplayRoi(int32_t x, int32_t y, int32_t width, + int32_t height) = 0; + virtual bool Play() = 0; + virtual bool Deactivate() { return false; }; + virtual bool Activate() { return false; }; + virtual bool Pause() = 0; + virtual bool SetLooping(bool is_looping) = 0; + virtual bool SetVolume(double volume) = 0; + virtual bool SetPlaybackSpeed(double speed) = 0; + virtual bool SeekTo(int64_t position, SeekCompletedCallback callback) = 0; + virtual int64_t GetPosition() = 0; + virtual int64_t GetDuration() = 0; + virtual bool IsReady() = 0; + virtual flutter::EncodableList GetTrackInfo(std::string track_type) = 0; + virtual bool SetTrackSelection(int32_t track_id, std::string track_type) = 0; + + protected: + virtual void GetVideoSize(int32_t *width, int32_t *height) = 0; + void *GetWindowHandle(); + int64_t SetUpEventChannel(); + void ClearUpEventChannel(); void SendInitialized(); void SendBufferingStart(); void SendBufferingUpdate(int32_t value); void SendBufferingEnd(); void SendSubtitleUpdate(int32_t duration, const std::string &text); + void SendPlayCompleted(); + void SendError(const std::string &error_code, + const std::string &error_message); - static void OnPrepared(void *data); - static void OnBuffering(int percent, void *data); - static void OnSeekCompleted(void *data); - static void OnPlayCompleted(void *data); - static void OnError(int error_code, void *data); - static void OnInterrupted(player_interrupted_code_e code, void *data); - static void OnSubtitleUpdated(unsigned long duration, char *text, void *data); + std::mutex queue_mutex_; + std::unique_ptr ecore_wl2_window_proxy_ = nullptr; + flutter::BinaryMessenger *binary_messenger_; + bool is_initialized_ = false; + FlutterDesktopViewRef flutter_view_; - std::vector OnLicenseChallenge( - const std::vector &challenge); + private: + void ExecuteSinkEvents(); + void PushEvent(flutter::EncodableValue encodable_value); + std::queue encodable_event_queue_; + std::queue> error_event_queue_; std::unique_ptr> event_channel_; std::unique_ptr> event_sink_; - - player_h player_ = nullptr; - flutter::PluginRegistrar *plugin_registrar_; - void *native_window_; - int64_t player_id_ = -1; - std::unique_ptr drm_manager_; - - bool is_initialized_ = false; - bool is_interrupted_ = false; - bool is_buffering_ = false; - - SeekCompletedCallback on_seek_completed_; - Dart_Port send_port_; - Ecore_Pipe *sink_event_pipe_ = nullptr; - std::mutex queue_mutex_; - std::queue encodable_event_queue_; - std::queue> error_event_queue_; }; #endif // FLUTTER_PLUGIN_VIDEO_PLAYER_H_ diff --git a/packages/video_player_videohole/tizen/src/video_player_tizen_plugin.cc b/packages/video_player_videohole/tizen/src/video_player_tizen_plugin.cc index e32bad05e..94411c4e7 100644 --- a/packages/video_player_videohole/tizen/src/video_player_tizen_plugin.cc +++ b/packages/video_player_videohole/tizen/src/video_player_tizen_plugin.cc @@ -15,6 +15,7 @@ #include #include +#include "media_player.h" #include "messages.h" #include "video_player.h" #include "video_player_options.h" @@ -39,14 +40,15 @@ class VideoPlayerTizenPlugin : public flutter::Plugin, std::optional SetVolume(const VolumeMessage &msg) override; std::optional SetPlaybackSpeed( const PlaybackSpeedMessage &msg) override; + ErrorOr Track(const TrackTypeMessage &msg) override; + ErrorOr SetTrackSelection(const SelectedTracksMessage &msg) override; std::optional Play(const PlayerMessage &msg) override; + ErrorOr SetDeactivate(const PlayerMessage &msg) override; + ErrorOr SetActivate(const PlayerMessage &msg) override; ErrorOr Position(const PlayerMessage &msg) override; void SeekTo( const PositionMessage &msg, std::function reply)> result) override; - virtual ErrorOr Track(const TrackTypeMessage &msg) override; - std::optional SetTrackSelection( - const SelectedTracksMessage &msg) override; std::optional Pause(const PlayerMessage &msg) override; std::optional SetMixWithOthers( const MixWithOthersMessage &msg) override; @@ -102,23 +104,15 @@ std::optional VideoPlayerTizenPlugin::Initialize() { ErrorOr VideoPlayerTizenPlugin::Create( const CreateMessage &msg) { - FlutterDesktopViewRef flutter_view = - FlutterDesktopPluginRegistrarGetView(registrar_ref_); - if (!flutter_view) { + if (!FlutterDesktopPluginRegistrarGetView(registrar_ref_)) { return FlutterError("Operation failed", "Could not get a Flutter view."); } - void *native_window = FlutterDesktopViewGetNativeHandle(flutter_view); - if (!native_window) { - return FlutterError("Operation failed", - "Could not get a native window handle."); - } - std::unique_ptr player = - std::make_unique(plugin_registrar_, native_window); - std::string uri; int32_t drm_type = 0; // DRM_TYPE_NONE std::string license_server_url; - const flutter::EncodableMap *http_headers = nullptr; + bool prebuffer_mode = false; + std::string format; + flutter::EncodableMap http_headers = {}; if (msg.asset() && !msg.asset()->empty()) { char *res_path = app_get_resource_path(); @@ -130,6 +124,9 @@ ErrorOr VideoPlayerTizenPlugin::Create( } } else if (msg.uri() && !msg.uri()->empty()) { uri = *msg.uri(); + if (msg.format_hint() && !msg.format_hint()->empty()) { + format = *msg.format_hint(); + } const flutter::EncodableMap *drm_configs = msg.drm_configs(); if (drm_configs) { @@ -147,18 +144,35 @@ ErrorOr VideoPlayerTizenPlugin::Create( } } - http_headers = msg.http_headers(); + const flutter::EncodableMap *player_options = msg.player_options(); + if (player_options) { + auto iter = + player_options->find(flutter::EncodableValue("prebufferMode")); + if (iter != player_options->end()) { + if (std::holds_alternative(iter->second)) { + prebuffer_mode = std::get(iter->second); + } + } + } + + const flutter::EncodableMap *http_headers_map = msg.http_headers(); + if (http_headers_map) { + http_headers = *http_headers_map; + } + } else { return FlutterError("Invalid argument", "Either asset or uri must be set."); } - int64_t player_id = - player->Create(uri, drm_type, license_server_url, http_headers); + auto player = std::make_unique( + plugin_registrar_->messenger(), + FlutterDesktopPluginRegistrarGetView(registrar_ref_)); + int64_t player_id = player->Create(uri, drm_type, license_server_url, + prebuffer_mode, http_headers); if (player_id == -1) { return FlutterError("Operation failed", "Failed to create a player."); } players_[player_id] = std::move(player); - PlayerMessage result(player_id); return result; } @@ -177,10 +191,11 @@ std::optional VideoPlayerTizenPlugin::SetLooping( const LoopingMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); + } + if (!player->SetLooping(msg.is_looping())) { + return FlutterError("SetLooping", "Player set looping failed"); } - player->SetLooping(msg.is_looping()); - return std::nullopt; } @@ -188,10 +203,11 @@ std::optional VideoPlayerTizenPlugin::SetVolume( const VolumeMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); + } + if (!player->SetVolume(msg.volume())) { + return FlutterError("SetVolume", "Player set volume failed"); } - player->SetVolume(msg.volume()); - return std::nullopt; } @@ -199,88 +215,106 @@ std::optional VideoPlayerTizenPlugin::SetPlaybackSpeed( const PlaybackSpeedMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); + } + if (!player->SetPlaybackSpeed(msg.speed())) { + return FlutterError("SetPlaybackSpeed", "Player set playback speed failed"); } - player->SetPlaybackSpeed(msg.speed()); - return std::nullopt; } -std::optional VideoPlayerTizenPlugin::Play( - const PlayerMessage &msg) { +ErrorOr VideoPlayerTizenPlugin::Track( + const TrackTypeMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); + if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); } - player->Play(); - return std::nullopt; + TrackMessage result(msg.player_id(), player->GetTrackInfo(msg.track_type())); + return result; } -std::optional VideoPlayerTizenPlugin::Pause( - const PlayerMessage &msg) { +ErrorOr VideoPlayerTizenPlugin::SetTrackSelection( + const SelectedTracksMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); } - player->Pause(); - - return std::nullopt; + return player->SetTrackSelection(msg.track_id(), msg.track_type()); } -ErrorOr VideoPlayerTizenPlugin::Position( +std::optional VideoPlayerTizenPlugin::Play( const PlayerMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); } - - PositionMessage result(msg.player_id(), player->GetPosition()); - return result; + if (!player->Play()) { + return FlutterError("Play", "Player play failed"); + } + return std::nullopt; } -void VideoPlayerTizenPlugin::SeekTo( - const PositionMessage &msg, - std::function reply)> result) { +ErrorOr VideoPlayerTizenPlugin::SetDeactivate(const PlayerMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - result(FlutterError("Invalid argument", "Player not found.")); - return; + return FlutterError("Invalid argument", "Player not found"); } - player->SeekTo(msg.position(), [result]() -> void { result(std::nullopt); }); + return player->Deactivate(); } -ErrorOr VideoPlayerTizenPlugin::Track( - const TrackTypeMessage &msg) { +ErrorOr VideoPlayerTizenPlugin::SetActivate(const PlayerMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); + if (!player) { + return FlutterError("Invalid argument", "Player not found"); + } + return player->Activate(); +} +std::optional VideoPlayerTizenPlugin::Pause( + const PlayerMessage &msg) { + VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); } + if (!player->Pause()) { + return FlutterError("Pause", "Player pause failed"); + } + return std::nullopt; +} - TrackMessage result(msg.player_id(), player->getTrackInfo(msg.track_type())); +ErrorOr VideoPlayerTizenPlugin::Position( + const PlayerMessage &msg) { + VideoPlayer *player = FindPlayerById(msg.player_id()); + if (!player) { + return FlutterError("Invalid argument", "Player not found"); + } + PositionMessage result(msg.player_id(), player->GetPosition()); return result; } -std::optional VideoPlayerTizenPlugin::SetTrackSelection( - const SelectedTracksMessage &msg) { +void VideoPlayerTizenPlugin::SeekTo( + const PositionMessage &msg, + std::function reply)> result) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + result(FlutterError("Invalid argument", "Player not found")); + return; + } + if (!player->SeekTo(msg.position(), + [result]() -> void { result(std::nullopt); })) { + result(FlutterError("SeekTo", "Player seek to failed")); } - player->SetTrackSelection(msg.track_id(), msg.track_type()); - - return std::nullopt; } std::optional VideoPlayerTizenPlugin::SetDisplayGeometry( const GeometryMessage &msg) { VideoPlayer *player = FindPlayerById(msg.player_id()); if (!player) { - return FlutterError("Invalid argument", "Player not found."); + return FlutterError("Invalid argument", "Player not found"); } player->SetDisplayRoi(msg.x(), msg.y(), msg.width(), msg.height()); - return std::nullopt; } @@ -298,15 +332,3 @@ void VideoPlayerTizenPluginRegisterWithRegistrar( registrar, flutter::PluginRegistrarManager::GetInstance() ->GetRegistrar(registrar)); } - -intptr_t VideoPlayerTizenPluginInitDartApi(void *data) { - return Dart_InitializeApiDL(data); -} - -void VideoPlayerTizenPluginRegisterSendPort(int64_t player_id, - Dart_Port send_port) { - VideoPlayer *player = VideoPlayerTizenPlugin::FindPlayerById(player_id); - if (player) { - player->RegisterSendPort(send_port); - } -}