diff --git a/packages/video_player_avplay/CHANGELOG.md b/packages/video_player_avplay/CHANGELOG.md index 5c7d0bece..273201ae6 100644 --- a/packages/video_player_avplay/CHANGELOG.md +++ b/packages/video_player_avplay/CHANGELOG.md @@ -1,7 +1,8 @@ -## NEXT +## 0.4.8 * Call the open before calling the SetStreamingProperty. * Change getStreamingProperty API return type from StreamingPropertyMessage to String. +* Add setStreamingProperty API. ## 0.4.7 diff --git a/packages/video_player_avplay/README.md b/packages/video_player_avplay/README.md index 82b9ee13e..1d543bfd1 100644 --- a/packages/video_player_avplay/README.md +++ b/packages/video_player_avplay/README.md @@ -12,7 +12,7 @@ To use this package, add `video_player_avplay` as a dependency in your `pubspec. ```yaml dependencies: - video_player_avplay: ^0.4.7 + video_player_avplay: ^0.4.8 ``` Then you can import `video_player_avplay` in your Dart code: diff --git a/packages/video_player_avplay/lib/src/messages.g.dart b/packages/video_player_avplay/lib/src/messages.g.dart index 28f376625..f7e9ede48 100644 --- a/packages/video_player_avplay/lib/src/messages.g.dart +++ b/packages/video_player_avplay/lib/src/messages.g.dart @@ -390,6 +390,37 @@ class StreamingPropertyTypeMessage { } } +class StreamingPropertyMessage { + StreamingPropertyMessage({ + required this.playerId, + required this.streamingPropertyType, + required this.streamingPropertyValue, + }); + + int playerId; + + String streamingPropertyType; + + String streamingPropertyValue; + + Object encode() { + return [ + playerId, + streamingPropertyType, + streamingPropertyValue, + ]; + } + + static StreamingPropertyMessage decode(Object result) { + result as List; + return StreamingPropertyMessage( + playerId: result[0]! as int, + streamingPropertyType: result[1]! as String, + streamingPropertyValue: result[2]! as String, + ); + } +} + class BufferConfigMessage { BufferConfigMessage({ required this.playerId, @@ -455,18 +486,21 @@ class _VideoPlayerAvplayApiCodec extends StandardMessageCodec { } else if (value is SelectedTracksMessage) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is StreamingPropertyTypeMessage) { + } else if (value is StreamingPropertyMessage) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is TrackMessage) { + } else if (value is StreamingPropertyTypeMessage) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is TrackTypeMessage) { + } else if (value is TrackMessage) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is VolumeMessage) { + } else if (value is TrackTypeMessage) { buffer.putUint8(141); writeValue(buffer, value.encode()); + } else if (value is VolumeMessage) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -496,12 +530,14 @@ class _VideoPlayerAvplayApiCodec extends StandardMessageCodec { case 137: return SelectedTracksMessage.decode(readValue(buffer)!); case 138: - return StreamingPropertyTypeMessage.decode(readValue(buffer)!); + return StreamingPropertyMessage.decode(readValue(buffer)!); case 139: - return TrackMessage.decode(readValue(buffer)!); + return StreamingPropertyTypeMessage.decode(readValue(buffer)!); case 140: - return TrackTypeMessage.decode(readValue(buffer)!); + return TrackMessage.decode(readValue(buffer)!); case 141: + return TrackTypeMessage.decode(readValue(buffer)!); + case 142: return VolumeMessage.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -1000,4 +1036,27 @@ class VideoPlayerAvplayApi { return (replyList[0] as bool?)!; } } + + Future setStreamingProperty(StreamingPropertyMessage arg_msg) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.video_player_avplay.VideoPlayerAvplayApi.setStreamingProperty', + 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 { + return; + } + } } diff --git a/packages/video_player_avplay/lib/src/video_player_tizen.dart b/packages/video_player_avplay/lib/src/video_player_tizen.dart index 17088e1e6..e411bc636 100644 --- a/packages/video_player_avplay/lib/src/video_player_tizen.dart +++ b/packages/video_player_avplay/lib/src/video_player_tizen.dart @@ -206,13 +206,23 @@ class VideoPlayerTizen extends VideoPlayerPlatform { } @override - Future setBufferConfig(int playerId, BufferConfigType type, int value) { + Future setBufferConfig( + int playerId, BufferConfigType type, int value) async { return _api.setBufferConfig(BufferConfigMessage( playerId: playerId, bufferConfigType: _bufferConfigTypeMap[type]!, bufferConfigValue: value)); } + @override + Future setStreamingProperty( + int playerId, StreamingPropertyType type, String value) async { + await _api.setStreamingProperty(StreamingPropertyMessage( + playerId: playerId, + streamingPropertyType: _streamingPropertyType[type]!, + streamingPropertyValue: value)); + } + @override Stream videoEventsFor(int playerId) { return _eventChannelFor(playerId) diff --git a/packages/video_player_avplay/lib/video_player.dart b/packages/video_player_avplay/lib/video_player.dart index 5863f2b50..eb141098b 100644 --- a/packages/video_player_avplay/lib/video_player.dart +++ b/packages/video_player_avplay/lib/video_player.dart @@ -712,6 +712,17 @@ class VideoPlayerController extends ValueNotifier { return _videoPlayerPlatform.getStreamingProperty(_playerId, type); } + /// Sets specific feature values for HTTP, MMS, or specific streaming engine (Smooth Streaming, HLS, DASH, DivX Plus Streaming, or Widevine). + /// The available streaming properties depend on the streaming protocol or engine. + /// Use the CUSTOM_MESSAGE property for streaming engine or CP-specific settings. + Future setStreamingProperty( + StreamingPropertyType type, String value) async { + if (_isDisposedOrNotInitialized) { + return; + } + return _videoPlayerPlatform.setStreamingProperty(_playerId, type, value); + } + /// Sets the buffer size for the play and resume scenarios. The time buffer size must be at least 4 seconds. /// For example, if a 10 second buffer size is set, playback can only start or resume after 10 seconds of media has accumulated in the buffer. /// Play scenarios include user-initiated streaming playback and whenever media playback is starting for the first time. diff --git a/packages/video_player_avplay/lib/video_player_platform_interface.dart b/packages/video_player_avplay/lib/video_player_platform_interface.dart index 32e678f1f..705fd2736 100644 --- a/packages/video_player_avplay/lib/video_player_platform_interface.dart +++ b/packages/video_player_avplay/lib/video_player_platform_interface.dart @@ -144,6 +144,13 @@ abstract class VideoPlayerPlatform extends PlatformInterface { throw UnimplementedError('setBufferConfig() has not been implemented.'); } + /// Set streamingengine property. + Future setStreamingProperty( + int playerId, StreamingPropertyType type, String value) { + throw UnimplementedError( + 'setStreamingProperty() has not been implemented.'); + } + /// Returns a widget displaying the video with a given playerId. Widget buildView(int playerId) { throw UnimplementedError('buildView() has not been implemented.'); diff --git a/packages/video_player_avplay/pigeons/messages.dart b/packages/video_player_avplay/pigeons/messages.dart index 08028a430..c98dd14e7 100644 --- a/packages/video_player_avplay/pigeons/messages.dart +++ b/packages/video_player_avplay/pigeons/messages.dart @@ -95,6 +95,14 @@ class StreamingPropertyTypeMessage { String streamingPropertyType; } +class StreamingPropertyMessage { + StreamingPropertyMessage( + this.playerId, this.streamingPropertyType, this.streamingPropertyValue); + int playerId; + String streamingPropertyType; + String streamingPropertyValue; +} + class BufferConfigMessage { BufferConfigMessage( this.playerId, this.bufferConfigType, this.bufferConfigValue); @@ -125,4 +133,5 @@ abstract class VideoPlayerAvplayApi { void setDisplayGeometry(GeometryMessage msg); String getStreamingProperty(StreamingPropertyTypeMessage msg); bool setBufferConfig(BufferConfigMessage msg); + void setStreamingProperty(StreamingPropertyMessage msg); } diff --git a/packages/video_player_avplay/pubspec.yaml b/packages/video_player_avplay/pubspec.yaml index d5df75655..fcf6c62df 100644 --- a/packages/video_player_avplay/pubspec.yaml +++ b/packages/video_player_avplay/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avplay 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_avplay -version: 0.4.7 +version: 0.4.8 environment: sdk: ">=3.1.0 <4.0.0" diff --git a/packages/video_player_avplay/tizen/src/messages.cc b/packages/video_player_avplay/tizen/src/messages.cc index 6682df1ab..b71a28ab8 100644 --- a/packages/video_player_avplay/tizen/src/messages.cc +++ b/packages/video_player_avplay/tizen/src/messages.cc @@ -598,6 +598,56 @@ StreamingPropertyTypeMessage StreamingPropertyTypeMessage::FromEncodableList( return decoded; } +// StreamingPropertyMessage + +StreamingPropertyMessage::StreamingPropertyMessage( + int64_t player_id, const std::string& streaming_property_type, + const std::string& streaming_property_value) + : player_id_(player_id), + streaming_property_type_(streaming_property_type), + streaming_property_value_(streaming_property_value) {} + +int64_t StreamingPropertyMessage::player_id() const { return player_id_; } + +void StreamingPropertyMessage::set_player_id(int64_t value_arg) { + player_id_ = value_arg; +} + +const std::string& StreamingPropertyMessage::streaming_property_type() const { + return streaming_property_type_; +} + +void StreamingPropertyMessage::set_streaming_property_type( + std::string_view value_arg) { + streaming_property_type_ = value_arg; +} + +const std::string& StreamingPropertyMessage::streaming_property_value() const { + return streaming_property_value_; +} + +void StreamingPropertyMessage::set_streaming_property_value( + std::string_view value_arg) { + streaming_property_value_ = value_arg; +} + +EncodableList StreamingPropertyMessage::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(player_id_)); + list.push_back(EncodableValue(streaming_property_type_)); + list.push_back(EncodableValue(streaming_property_value_)); + return list; +} + +StreamingPropertyMessage StreamingPropertyMessage::FromEncodableList( + const EncodableList& list) { + StreamingPropertyMessage decoded(list[0].LongValue(), + std::get(list[1]), + std::get(list[2])); + return decoded; +} + // BufferConfigMessage BufferConfigMessage::BufferConfigMessage(int64_t player_id, @@ -681,16 +731,19 @@ EncodableValue VideoPlayerAvplayApiCodecSerializer::ReadValueOfType( return CustomEncodableValue(SelectedTracksMessage::FromEncodableList( std::get(ReadValue(stream)))); case 138: + return CustomEncodableValue(StreamingPropertyMessage::FromEncodableList( + std::get(ReadValue(stream)))); + case 139: return CustomEncodableValue( StreamingPropertyTypeMessage::FromEncodableList( std::get(ReadValue(stream)))); - case 139: + case 140: return CustomEncodableValue(TrackMessage::FromEncodableList( std::get(ReadValue(stream)))); - case 140: + case 141: return CustomEncodableValue(TrackTypeMessage::FromEncodableList( std::get(ReadValue(stream)))); - case 141: + case 142: return CustomEncodableValue(VolumeMessage::FromEncodableList( std::get(ReadValue(stream)))); default: @@ -782,8 +835,16 @@ void VideoPlayerAvplayApiCodecSerializer::WriteValue( stream); return; } - if (custom_value->type() == typeid(StreamingPropertyTypeMessage)) { + if (custom_value->type() == typeid(StreamingPropertyMessage)) { stream->WriteByte(138); + WriteValue( + EncodableValue(std::any_cast(*custom_value) + .ToEncodableList()), + stream); + return; + } + if (custom_value->type() == typeid(StreamingPropertyTypeMessage)) { + stream->WriteByte(139); WriteValue(EncodableValue( std::any_cast(*custom_value) .ToEncodableList()), @@ -791,7 +852,7 @@ void VideoPlayerAvplayApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(TrackMessage)) { - stream->WriteByte(139); + stream->WriteByte(140); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -799,7 +860,7 @@ void VideoPlayerAvplayApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(TrackTypeMessage)) { - stream->WriteByte(140); + stream->WriteByte(141); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -807,7 +868,7 @@ void VideoPlayerAvplayApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(VolumeMessage)) { - stream->WriteByte(141); + stream->WriteByte(142); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -1486,6 +1547,43 @@ void VideoPlayerAvplayApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.video_player_avplay.VideoPlayerAvplayApi." + "setStreamingProperty", + &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)); + std::optional output = + api->SetStreamingProperty(msg_arg); + 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); + } + } } EncodableValue VideoPlayerAvplayApi::WrapError(std::string_view error_message) { diff --git a/packages/video_player_avplay/tizen/src/messages.h b/packages/video_player_avplay/tizen/src/messages.h index 4c7071f72..3946daeb6 100644 --- a/packages/video_player_avplay/tizen/src/messages.h +++ b/packages/video_player_avplay/tizen/src/messages.h @@ -388,6 +388,34 @@ class StreamingPropertyTypeMessage { std::string streaming_property_type_; }; +// Generated class from Pigeon that represents data sent in messages. +class StreamingPropertyMessage { + public: + // Constructs an object setting all fields. + explicit StreamingPropertyMessage( + int64_t player_id, const std::string& streaming_property_type, + const std::string& streaming_property_value); + + int64_t player_id() const; + void set_player_id(int64_t value_arg); + + const std::string& streaming_property_type() const; + void set_streaming_property_type(std::string_view value_arg); + + const std::string& streaming_property_value() const; + void set_streaming_property_value(std::string_view value_arg); + + private: + static StreamingPropertyMessage FromEncodableList( + const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class VideoPlayerAvplayApi; + friend class VideoPlayerAvplayApiCodecSerializer; + int64_t player_id_; + std::string streaming_property_type_; + std::string streaming_property_value_; +}; + // Generated class from Pigeon that represents data sent in messages. class BufferConfigMessage { public: @@ -465,6 +493,8 @@ class VideoPlayerAvplayApi { virtual ErrorOr GetStreamingProperty( const StreamingPropertyTypeMessage& msg) = 0; virtual ErrorOr SetBufferConfig(const BufferConfigMessage& msg) = 0; + virtual std::optional SetStreamingProperty( + const StreamingPropertyMessage& msg) = 0; // The codec used by VideoPlayerAvplayApi. static const flutter::StandardMessageCodec& GetCodec(); diff --git a/packages/video_player_avplay/tizen/src/plus_player.cc b/packages/video_player_avplay/tizen/src/plus_player.cc index bbf1f4750..6ca10a75a 100644 --- a/packages/video_player_avplay/tizen/src/plus_player.cc +++ b/packages/video_player_avplay/tizen/src/plus_player.cc @@ -96,7 +96,7 @@ int64_t PlusPlayer::Create(const std::string &uri, if (create_message.streaming_property() != nullptr && !create_message.streaming_property()->empty()) { for (const auto &[key, value] : *create_message.streaming_property()) { - SetStreamingProperty(player_, std::get(key), + SetStreamingProperty(std::get(key), std::get(value)); } } @@ -597,6 +597,23 @@ bool PlusPlayer::SetBufferConfig(const std::string &key, int64_t value) { return ::SetBufferConfig(player_, config); } +void PlusPlayer::SetStreamingProperty(const std::string &type, + const std::string &value) { + if (!player_) { + LOG_ERROR("[PlusPlayer] Player not created."); + return; + } + plusplayer::State state = GetState(player_); + if (state == plusplayer::State::kNone) { + LOG_ERROR("[PlusPlayer] Player is in invalid state[%d]", state); + return; + } + + LOG_INFO("[PlusPlayer] SetStreamingProp: type[%s], value[%s]", type.c_str(), + value.c_str()); + ::SetStreamingProperty(player_, type, value); +} + bool PlusPlayer::OnLicenseAcquired(int *drm_handle, unsigned int length, unsigned char *pssh_data, void *user_data) { LOG_INFO("[PlusPlayer] License acquired."); diff --git a/packages/video_player_avplay/tizen/src/plus_player.h b/packages/video_player_avplay/tizen/src/plus_player.h index 5004063ef..348b6eb5c 100644 --- a/packages/video_player_avplay/tizen/src/plus_player.h +++ b/packages/video_player_avplay/tizen/src/plus_player.h @@ -44,6 +44,8 @@ class PlusPlayer : public VideoPlayer { std::string GetStreamingProperty( const std::string &streaming_property_type) override; bool SetBufferConfig(const std::string &key, int64_t value) override; + void SetStreamingProperty(const std::string &type, + const std::string &value) override; private: bool IsLive(); diff --git a/packages/video_player_avplay/tizen/src/video_player.h b/packages/video_player_avplay/tizen/src/video_player.h index 3b41d5199..74a88631a 100644 --- a/packages/video_player_avplay/tizen/src/video_player.h +++ b/packages/video_player_avplay/tizen/src/video_player.h @@ -56,6 +56,9 @@ class VideoPlayer { return false; }; + virtual void SetStreamingProperty(const std::string &type, + const std::string &value){}; + protected: virtual void GetVideoSize(int32_t *width, int32_t *height) = 0; void *GetWindowHandle(); diff --git a/packages/video_player_avplay/tizen/src/video_player_tizen_plugin.cc b/packages/video_player_avplay/tizen/src/video_player_tizen_plugin.cc index a97c476ed..03836dcfd 100644 --- a/packages/video_player_avplay/tizen/src/video_player_tizen_plugin.cc +++ b/packages/video_player_avplay/tizen/src/video_player_tizen_plugin.cc @@ -58,6 +58,8 @@ class VideoPlayerTizenPlugin : public flutter::Plugin, ErrorOr GetStreamingProperty( const StreamingPropertyTypeMessage &msg) override; ErrorOr SetBufferConfig(const BufferConfigMessage &msg) override; + std::optional SetStreamingProperty( + const StreamingPropertyMessage &msg) override; static VideoPlayer *FindPlayerById(int64_t player_id) { auto iter = players_.find(player_id); @@ -321,6 +323,17 @@ ErrorOr VideoPlayerTizenPlugin::SetBufferConfig( msg.buffer_config_value()); } +std::optional VideoPlayerTizenPlugin::SetStreamingProperty( + const StreamingPropertyMessage &msg) { + VideoPlayer *player = FindPlayerById(msg.player_id()); + if (!player) { + return FlutterError("Invalid argument", "Player not found"); + } + player->SetStreamingProperty(msg.streaming_property_type(), + msg.streaming_property_value()); + return std::nullopt; +} + std::optional VideoPlayerTizenPlugin::SetMixWithOthers( const MixWithOthersMessage &msg) { options_.SetMixWithOthers(msg.mix_with_others());