From 4b0d00cc12962113e9574b4effa7e9c0553a65ec Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Wed, 20 Dec 2023 20:20:42 +0800 Subject: [PATCH 1/5] Re-implement get duration interface Live stream duration is a range. --- .../lib/src/messages.g.dart | 97 ++++++++++--- .../lib/src/video_player_tizen.dart | 4 +- .../lib/video_player.dart | 34 +++-- .../lib/video_player_platform_interface.dart | 2 +- .../pigeons/messages.dart | 7 + .../tizen/src/media_player.cc | 4 +- .../tizen/src/media_player.h | 2 +- .../tizen/src/messages.cc | 134 +++++++++++++++--- .../tizen/src/messages.h | 27 ++++ .../tizen/src/video_player.cc | 7 +- .../tizen/src/video_player.h | 2 +- .../tizen/src/video_player_tizen_plugin.cc | 16 +++ 12 files changed, 276 insertions(+), 60 deletions(-) diff --git a/packages/video_player_videohole/lib/src/messages.g.dart b/packages/video_player_videohole/lib/src/messages.g.dart index d20dddefc..4b3aac119 100644 --- a/packages/video_player_videohole/lib/src/messages.g.dart +++ b/packages/video_player_videohole/lib/src/messages.g.dart @@ -332,6 +332,32 @@ class GeometryMessage { } } +class DurationMessage { + DurationMessage({ + required this.playerId, + this.durationRange, + }); + + int playerId; + + List? durationRange; + + Object encode() { + return [ + playerId, + durationRange, + ]; + } + + static DurationMessage decode(Object result) { + result as List; + return DurationMessage( + playerId: result[0]! as int, + durationRange: (result[1] as List?)?.cast(), + ); + } +} + class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec { const _VideoPlayerVideoholeApiCodec(); @override @@ -339,36 +365,39 @@ class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec { if (value is CreateMessage) { buffer.putUint8(128); writeValue(buffer, value.encode()); - } else if (value is GeometryMessage) { + } else if (value is DurationMessage) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is LoopingMessage) { + } else if (value is GeometryMessage) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is MixWithOthersMessage) { + } else if (value is LoopingMessage) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PlaybackSpeedMessage) { + } else if (value is MixWithOthersMessage) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PlayerMessage) { + } else if (value is PlaybackSpeedMessage) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PositionMessage) { + } else if (value is PlayerMessage) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is SelectedTracksMessage) { + } else if (value is PositionMessage) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is TrackMessage) { + } else if (value is SelectedTracksMessage) { buffer.putUint8(136); writeValue(buffer, value.encode()); - } else if (value is TrackTypeMessage) { + } else if (value is TrackMessage) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is VolumeMessage) { + } else if (value is TrackTypeMessage) { buffer.putUint8(138); writeValue(buffer, value.encode()); + } else if (value is VolumeMessage) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -380,24 +409,26 @@ class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec { case 128: return CreateMessage.decode(readValue(buffer)!); case 129: - return GeometryMessage.decode(readValue(buffer)!); + return DurationMessage.decode(readValue(buffer)!); case 130: - return LoopingMessage.decode(readValue(buffer)!); + return GeometryMessage.decode(readValue(buffer)!); case 131: - return MixWithOthersMessage.decode(readValue(buffer)!); + return LoopingMessage.decode(readValue(buffer)!); case 132: - return PlaybackSpeedMessage.decode(readValue(buffer)!); + return MixWithOthersMessage.decode(readValue(buffer)!); case 133: - return PlayerMessage.decode(readValue(buffer)!); + return PlaybackSpeedMessage.decode(readValue(buffer)!); case 134: - return PositionMessage.decode(readValue(buffer)!); + return PlayerMessage.decode(readValue(buffer)!); case 135: - return SelectedTracksMessage.decode(readValue(buffer)!); + return PositionMessage.decode(readValue(buffer)!); case 136: - return TrackMessage.decode(readValue(buffer)!); + return SelectedTracksMessage.decode(readValue(buffer)!); case 137: - return TrackTypeMessage.decode(readValue(buffer)!); + return TrackMessage.decode(readValue(buffer)!); case 138: + return TrackTypeMessage.decode(readValue(buffer)!); + case 139: return VolumeMessage.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -811,4 +842,32 @@ class VideoPlayerVideoholeApi { return; } } + + Future duration(PlayerMessage arg_msg) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.duration', + 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 DurationMessage?)!; + } + } } 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 6520d7e4b..59fe0a085 100644 --- a/packages/video_player_videohole/lib/src/video_player_tizen.dart +++ b/packages/video_player_videohole/lib/src/video_player_tizen.dart @@ -196,9 +196,11 @@ class VideoPlayerTizen extends VideoPlayerPlatform { final Map map = event as Map; switch (map['event']) { case 'initialized': + final List durationVal = map['duration']! as List; return VideoEvent( eventType: VideoEventType.initialized, - duration: Duration(milliseconds: map['duration']! as int), + duration: DurationRange(Duration(milliseconds: durationVal[0]), + Duration(milliseconds: durationVal[1])), size: Size((map['width'] as num?)?.toDouble() ?? 0.0, (map['height'] as num?)?.toDouble() ?? 0.0), ); diff --git a/packages/video_player_videohole/lib/video_player.dart b/packages/video_player_videohole/lib/video_player.dart index 86548d7bf..a6077d11d 100644 --- a/packages/video_player_videohole/lib/video_player.dart +++ b/packages/video_player_videohole/lib/video_player.dart @@ -57,12 +57,14 @@ class VideoPlayerValue { /// Returns an instance for a video that hasn't been loaded. VideoPlayerValue.uninitialized() - : this(duration: Duration.zero, isInitialized: false); + : this( + duration: DurationRange(Duration.zero, Duration.zero), + isInitialized: false); /// Returns an instance with the given [errorDescription]. VideoPlayerValue.erroneous(String errorDescription) : this( - duration: Duration.zero, + duration: DurationRange(Duration.zero, Duration.zero), isInitialized: false, errorDescription: errorDescription); @@ -73,7 +75,7 @@ class VideoPlayerValue { /// The total duration of the video. /// /// The duration is [Duration.zero] if the video hasn't been initialized. - final Duration duration; + final DurationRange duration; /// The current playback position. final Duration position; @@ -145,7 +147,7 @@ class VideoPlayerValue { /// Returns a new instance that has the same values as this current instance, /// except for any overrides passed in as arguments to [copyWidth]. VideoPlayerValue copyWith({ - Duration? duration, + DurationRange? duration, Size? size, Duration? position, Caption? caption, @@ -226,7 +228,8 @@ class VideoPlayerController extends ValueNotifier { httpHeaders = const {}, drmConfigs = null, playerOptions = const {}, - super(VideoPlayerValue(duration: Duration.zero)); + super(VideoPlayerValue( + duration: DurationRange(Duration.zero, Duration.zero))); /// Constructs a [VideoPlayerController] playing a video from obtained from /// the network. @@ -247,7 +250,8 @@ class VideoPlayerController extends ValueNotifier { this.playerOptions, }) : dataSourceType = DataSourceType.network, package = null, - super(VideoPlayerValue(duration: Duration.zero)); + super(VideoPlayerValue( + duration: DurationRange(Duration.zero, Duration.zero))); /// Constructs a [VideoPlayerController] playing a video from a file. /// @@ -264,7 +268,8 @@ class VideoPlayerController extends ValueNotifier { httpHeaders = const {}, drmConfigs = null, playerOptions = const {}, - super(VideoPlayerValue(duration: Duration.zero)); + super(VideoPlayerValue( + duration: DurationRange(Duration.zero, Duration.zero))); /// Constructs a [VideoPlayerController] playing a video from a contentUri. /// @@ -283,7 +288,8 @@ class VideoPlayerController extends ValueNotifier { httpHeaders = const {}, drmConfigs = null, playerOptions = const {}, - super(VideoPlayerValue(duration: Duration.zero)); + super(VideoPlayerValue( + duration: DurationRange(Duration.zero, Duration.zero))); /// The URI to the video file. This will be in different formats depending on /// the [DataSourceType] of the original video. @@ -419,7 +425,7 @@ class VideoPlayerController extends ValueNotifier { // position=value.duration. Instead of setting the values directly, // we use pause() and seekTo() to ensure the platform stops playing // and seeks to the last frame of the video. - pause().then((void pauseResult) => seekTo(value.duration)); + pause().then((void pauseResult) => seekTo(value.duration.end)); break; case VideoEventType.bufferingUpdate: value = value.copyWith(buffered: event.buffered); @@ -434,7 +440,7 @@ class VideoPlayerController extends ValueNotifier { final Caption caption = Caption( number: 0, start: value.position, - end: value.position + (event.duration ?? Duration.zero), + end: value.position + (event.duration?.end ?? Duration.zero), text: event.text ?? '', ); value = value.copyWith(caption: caption); @@ -627,8 +633,8 @@ class VideoPlayerController extends ValueNotifier { if (_isDisposedOrNotInitialized) { return; } - if (position > value.duration) { - position = value.duration; + if (position > value.duration.end) { + position = value.duration.end; } else if (position < Duration.zero) { position = Duration.zero; } @@ -954,7 +960,7 @@ class _VideoScrubberState extends State<_VideoScrubber> { final RenderBox box = context.findRenderObject()! as RenderBox; final Offset tapPos = box.globalToLocal(globalPosition); final double relative = tapPos.dx / box.size.width; - final Duration position = controller.value.duration * relative; + final Duration position = controller.value.duration.end * relative; controller.seekTo(position); } @@ -1071,7 +1077,7 @@ class _VideoProgressIndicatorState extends State { Widget build(BuildContext context) { Widget progressIndicator; if (controller.value.isInitialized) { - final int duration = controller.value.duration.inMilliseconds; + final int duration = controller.value.duration.end.inMilliseconds; final int position = controller.value.position.inMilliseconds; progressIndicator = Stack( 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 db56b9a3f..7118f3308 100644 --- a/packages/video_player_videohole/lib/video_player_platform_interface.dart +++ b/packages/video_player_videohole/lib/video_player_platform_interface.dart @@ -271,7 +271,7 @@ class VideoEvent { /// Duration of the video. /// /// Only used if [eventType] is [VideoEventType.initialized]. - final Duration? duration; + final DurationRange? duration; /// Size of the video. /// diff --git a/packages/video_player_videohole/pigeons/messages.dart b/packages/video_player_videohole/pigeons/messages.dart index 89dbbb011..6c9ecdb21 100644 --- a/packages/video_player_videohole/pigeons/messages.dart +++ b/packages/video_player_videohole/pigeons/messages.dart @@ -82,6 +82,12 @@ class GeometryMessage { int height; } +class DurationMessage{ + DurationMessage(this.playerId); + int playerId; + List? durationRange; +} + @HostApi() abstract class VideoPlayerVideoholeApi { void initialize(); @@ -101,4 +107,5 @@ abstract class VideoPlayerVideoholeApi { void pause(PlayerMessage msg); void setMixWithOthers(MixWithOthersMessage msg); void setDisplayGeometry(GeometryMessage msg); + DurationMessage duration(PlayerMessage msg); } diff --git a/packages/video_player_videohole/tizen/src/media_player.cc b/packages/video_player_videohole/tizen/src/media_player.cc index 5d25041a2..dfb945407 100644 --- a/packages/video_player_videohole/tizen/src/media_player.cc +++ b/packages/video_player_videohole/tizen/src/media_player.cc @@ -301,7 +301,7 @@ int64_t MediaPlayer::GetPosition() { return position; } -int64_t MediaPlayer::GetDuration() { +std::pair MediaPlayer::GetDuration() { int duration = 0; int ret = player_get_duration(player_, &duration); if (ret != PLAYER_ERROR_NONE) { @@ -309,7 +309,7 @@ int64_t MediaPlayer::GetDuration() { get_error_message(ret)); } LOG_INFO("[MediaPlayer] Video duration: %d.", duration); - return duration; + return std::make_pair(0, duration); } void MediaPlayer::GetVideoSize(int32_t *width, int32_t *height) { diff --git a/packages/video_player_videohole/tizen/src/media_player.h b/packages/video_player_videohole/tizen/src/media_player.h index 01e0e91c6..ab3a8213f 100644 --- a/packages/video_player_videohole/tizen/src/media_player.h +++ b/packages/video_player_videohole/tizen/src/media_player.h @@ -35,7 +35,7 @@ class MediaPlayer : public VideoPlayer { bool SetPlaybackSpeed(double speed) override; bool SeekTo(int64_t position, SeekCompletedCallback callback) override; int64_t GetPosition() override; - int64_t GetDuration() override; + std::pair GetDuration() override; void GetVideoSize(int32_t *width, int32_t *height) override; bool IsReady() override; flutter::EncodableList GetTrackInfo(std::string track_type) override; diff --git a/packages/video_player_videohole/tizen/src/messages.cc b/packages/video_player_videohole/tizen/src/messages.cc index 72196de75..73889ca06 100644 --- a/packages/video_player_videohole/tizen/src/messages.cc +++ b/packages/video_player_videohole/tizen/src/messages.cc @@ -487,6 +487,55 @@ GeometryMessage GeometryMessage::FromEncodableList(const EncodableList& list) { return decoded; } +// DurationMessage + +DurationMessage::DurationMessage(int64_t player_id) : player_id_(player_id) {} + +DurationMessage::DurationMessage(int64_t player_id, + const EncodableList* duration_range) + : player_id_(player_id), + duration_range_(duration_range + ? std::optional(*duration_range) + : std::nullopt) {} + +int64_t DurationMessage::player_id() const { return player_id_; } + +void DurationMessage::set_player_id(int64_t value_arg) { + player_id_ = value_arg; +} + +const EncodableList* DurationMessage::duration_range() const { + return duration_range_ ? &(*duration_range_) : nullptr; +} + +void DurationMessage::set_duration_range(const EncodableList* value_arg) { + duration_range_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void DurationMessage::set_duration_range(const EncodableList& value_arg) { + duration_range_ = value_arg; +} + +EncodableList DurationMessage::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(EncodableValue(player_id_)); + list.push_back(duration_range_ ? EncodableValue(*duration_range_) + : EncodableValue()); + return list; +} + +DurationMessage DurationMessage::FromEncodableList(const EncodableList& list) { + DurationMessage decoded(list[0].LongValue()); + auto& encodable_duration_range = list[1]; + if (!encodable_duration_range.IsNull()) { + decoded.set_duration_range( + std::get(encodable_duration_range)); + } + return decoded; +} + VideoPlayerVideoholeApiCodecSerializer:: VideoPlayerVideoholeApiCodecSerializer() {} @@ -497,33 +546,36 @@ EncodableValue VideoPlayerVideoholeApiCodecSerializer::ReadValueOfType( return CustomEncodableValue(CreateMessage::FromEncodableList( std::get(ReadValue(stream)))); case 129: - return CustomEncodableValue(GeometryMessage::FromEncodableList( + return CustomEncodableValue(DurationMessage::FromEncodableList( std::get(ReadValue(stream)))); case 130: - return CustomEncodableValue(LoopingMessage::FromEncodableList( + return CustomEncodableValue(GeometryMessage::FromEncodableList( std::get(ReadValue(stream)))); case 131: - return CustomEncodableValue(MixWithOthersMessage::FromEncodableList( + return CustomEncodableValue(LoopingMessage::FromEncodableList( std::get(ReadValue(stream)))); case 132: - return CustomEncodableValue(PlaybackSpeedMessage::FromEncodableList( + return CustomEncodableValue(MixWithOthersMessage::FromEncodableList( std::get(ReadValue(stream)))); case 133: - return CustomEncodableValue(PlayerMessage::FromEncodableList( + return CustomEncodableValue(PlaybackSpeedMessage::FromEncodableList( std::get(ReadValue(stream)))); case 134: - return CustomEncodableValue(PositionMessage::FromEncodableList( + return CustomEncodableValue(PlayerMessage::FromEncodableList( std::get(ReadValue(stream)))); case 135: - return CustomEncodableValue(SelectedTracksMessage::FromEncodableList( + return CustomEncodableValue(PositionMessage::FromEncodableList( std::get(ReadValue(stream)))); case 136: - return CustomEncodableValue(TrackMessage::FromEncodableList( + return CustomEncodableValue(SelectedTracksMessage::FromEncodableList( std::get(ReadValue(stream)))); case 137: - return CustomEncodableValue(TrackTypeMessage::FromEncodableList( + return CustomEncodableValue(TrackMessage::FromEncodableList( std::get(ReadValue(stream)))); case 138: + return CustomEncodableValue(TrackTypeMessage::FromEncodableList( + std::get(ReadValue(stream)))); + case 139: return CustomEncodableValue(VolumeMessage::FromEncodableList( std::get(ReadValue(stream)))); default: @@ -543,8 +595,16 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( stream); return; } - if (custom_value->type() == typeid(GeometryMessage)) { + if (custom_value->type() == typeid(DurationMessage)) { stream->WriteByte(129); + WriteValue( + EncodableValue( + std::any_cast(*custom_value).ToEncodableList()), + stream); + return; + } + if (custom_value->type() == typeid(GeometryMessage)) { + stream->WriteByte(130); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -552,7 +612,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(LoopingMessage)) { - stream->WriteByte(130); + stream->WriteByte(131); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -560,7 +620,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(MixWithOthersMessage)) { - stream->WriteByte(131); + stream->WriteByte(132); WriteValue( EncodableValue(std::any_cast(*custom_value) .ToEncodableList()), @@ -568,7 +628,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(PlaybackSpeedMessage)) { - stream->WriteByte(132); + stream->WriteByte(133); WriteValue( EncodableValue(std::any_cast(*custom_value) .ToEncodableList()), @@ -576,7 +636,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(PlayerMessage)) { - stream->WriteByte(133); + stream->WriteByte(134); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -584,7 +644,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(PositionMessage)) { - stream->WriteByte(134); + stream->WriteByte(135); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -592,7 +652,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(SelectedTracksMessage)) { - stream->WriteByte(135); + stream->WriteByte(136); WriteValue( EncodableValue(std::any_cast(*custom_value) .ToEncodableList()), @@ -600,7 +660,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(TrackMessage)) { - stream->WriteByte(136); + stream->WriteByte(137); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -608,7 +668,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(TrackTypeMessage)) { - stream->WriteByte(137); + stream->WriteByte(138); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -616,7 +676,7 @@ void VideoPlayerVideoholeApiCodecSerializer::WriteValue( return; } if (custom_value->type() == typeid(VolumeMessage)) { - stream->WriteByte(138); + stream->WriteByte(139); WriteValue( EncodableValue( std::any_cast(*custom_value).ToEncodableList()), @@ -1197,6 +1257,42 @@ void VideoPlayerVideoholeApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi." + "duration", + &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->Duration(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())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } } EncodableValue VideoPlayerVideoholeApi::WrapError( diff --git a/packages/video_player_videohole/tizen/src/messages.h b/packages/video_player_videohole/tizen/src/messages.h index af3c6cd3e..809411ea2 100644 --- a/packages/video_player_videohole/tizen/src/messages.h +++ b/packages/video_player_videohole/tizen/src/messages.h @@ -333,6 +333,32 @@ class GeometryMessage { int64_t height_; }; +// Generated class from Pigeon that represents data sent in messages. +class DurationMessage { + public: + // Constructs an object setting all non-nullable fields. + explicit DurationMessage(int64_t player_id); + + // Constructs an object setting all fields. + explicit DurationMessage(int64_t player_id, + const flutter::EncodableList* duration_range); + + int64_t player_id() const; + void set_player_id(int64_t value_arg); + + const flutter::EncodableList* duration_range() const; + void set_duration_range(const flutter::EncodableList* value_arg); + void set_duration_range(const flutter::EncodableList& value_arg); + + private: + static DurationMessage FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class VideoPlayerVideoholeApi; + friend class VideoPlayerVideoholeApiCodecSerializer; + int64_t player_id_; + std::optional duration_range_; +}; + class VideoPlayerVideoholeApiCodecSerializer : public flutter::StandardCodecSerializer { public: @@ -378,6 +404,7 @@ class VideoPlayerVideoholeApi { const MixWithOthersMessage& msg) = 0; virtual std::optional SetDisplayGeometry( const GeometryMessage& msg) = 0; + virtual ErrorOr Duration(const PlayerMessage& msg) = 0; // The codec used by VideoPlayerVideoholeApi. static const flutter::StandardMessageCodec& GetCodec(); diff --git a/packages/video_player_videohole/tizen/src/video_player.cc b/packages/video_player_videohole/tizen/src/video_player.cc index 56981f1a6..f5eb7b812 100644 --- a/packages/video_player_videohole/tizen/src/video_player.cc +++ b/packages/video_player_videohole/tizen/src/video_player.cc @@ -101,14 +101,17 @@ void VideoPlayer::PushEvent(flutter::EncodableValue encodable_value) { void VideoPlayer::SendInitialized() { if (!is_initialized_ && event_sink_) { int32_t width = 0, height = 0; - int64_t duration = GetDuration(); GetVideoSize(&width, &height); is_initialized_ = true; + auto duration = GetDuration(); + flutter::EncodableList duration_range; + duration_range.push_back(flutter::EncodableValue(duration.first)); + duration_range.push_back(flutter::EncodableValue(duration.second)); flutter::EncodableMap result = { {flutter::EncodableValue("event"), flutter::EncodableValue("initialized")}, {flutter::EncodableValue("duration"), - flutter::EncodableValue(duration)}, + flutter::EncodableValue(duration_range)}, {flutter::EncodableValue("width"), flutter::EncodableValue(width)}, {flutter::EncodableValue("height"), flutter::EncodableValue(height)}, }; diff --git a/packages/video_player_videohole/tizen/src/video_player.h b/packages/video_player_videohole/tizen/src/video_player.h index 53c1ebd92..d10ebb2f6 100644 --- a/packages/video_player_videohole/tizen/src/video_player.h +++ b/packages/video_player_videohole/tizen/src/video_player.h @@ -45,7 +45,7 @@ class VideoPlayer { 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 std::pair 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; 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 94411c4e7..23a1b6a52 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 @@ -36,6 +36,7 @@ class VideoPlayerTizenPlugin : public flutter::Plugin, std::optional Initialize() override; ErrorOr Create(const CreateMessage &msg) override; std::optional Dispose(const PlayerMessage &msg) override; + ErrorOr Duration(const PlayerMessage &msg) override; std::optional SetLooping(const LoopingMessage &msg) override; std::optional SetVolume(const VolumeMessage &msg) override; std::optional SetPlaybackSpeed( @@ -177,6 +178,21 @@ ErrorOr VideoPlayerTizenPlugin::Create( return result; } +ErrorOr VideoPlayerTizenPlugin::Duration( + const PlayerMessage &msg) { + VideoPlayer *player = FindPlayerById(msg.player_id()); + if (!player) { + return FlutterError("Invalid argument", "Player not found"); + } + DurationMessage result(msg.player_id()); + auto duration_pair = player->GetDuration(); + flutter::EncodableList duration_range; + duration_range.push_back(flutter::EncodableValue(duration_pair.first)); + duration_range.push_back(flutter::EncodableValue(duration_pair.second)); + result.set_duration_range(duration_range); + return result; +} + std::optional VideoPlayerTizenPlugin::Dispose( const PlayerMessage &msg) { auto iter = players_.find(msg.player_id()); From 9b3a9ec2ab0b2285535f5a43d8941b5f5214426f Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Fri, 22 Dec 2023 14:45:32 +0800 Subject: [PATCH 2/5] Add get duration timer --- .../integration_test/video_player_test.dart | 4 +- .../lib/src/video_player_tizen.dart | 15 ++++- .../lib/video_player.dart | 36 +++++++++- .../lib/video_player_platform_interface.dart | 5 ++ .../tizen/src/media_player.cc | 65 +++++++++++++++++-- .../tizen/src/media_player.h | 2 + .../tizen/src/media_player_proxy.cc | 23 +++++++ .../tizen/src/media_player_proxy.h | 40 ++++++++++++ .../tizen/src/video_player.cc | 6 +- .../tizen/src/video_player_tizen_plugin.cc | 6 +- 10 files changed, 183 insertions(+), 19 deletions(-) diff --git a/packages/video_player_videohole/example/integration_test/video_player_test.dart b/packages/video_player_videohole/example/integration_test/video_player_test.dart index cf2fcd259..1d4de2335 100644 --- a/packages/video_player_videohole/example/integration_test/video_player_test.dart +++ b/packages/video_player_videohole/example/integration_test/video_player_test.dart @@ -125,7 +125,7 @@ void main() { // See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes await controller.setVolume(0); final Duration timeBeforeEnd = - controller.value.duration - const Duration(milliseconds: 500); + controller.value.duration.end - const Duration(milliseconds: 500); await controller.seekTo(timeBeforeEnd); await controller.play(); await tester.pumpAndSettle(_playDuration); @@ -148,7 +148,7 @@ void main() { // See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes await controller.setVolume(0); await controller.seekTo( - controller.value.duration - const Duration(milliseconds: 500)); + controller.value.duration.end - const Duration(milliseconds: 500)); await controller.play(); await tester.pumpAndSettle(_playDuration); expect(controller.value.isPlaying, false); 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 59fe0a085..5ec4e1e2b 100644 --- a/packages/video_player_videohole/lib/src/video_player_tizen.dart +++ b/packages/video_player_videohole/lib/src/video_player_tizen.dart @@ -181,6 +181,14 @@ class VideoPlayerTizen extends VideoPlayerPlatform { )); } + @override + Future getDuration(int playerId) async { + final DurationMessage message = + await _api.duration(PlayerMessage(playerId: playerId)); + return DurationRange(Duration(milliseconds: message.durationRange?[0] ?? 0), + Duration(milliseconds: message.durationRange?[1] ?? 0)); + } + @override Future getPosition(int playerId) async { final PositionMessage response = @@ -196,11 +204,12 @@ class VideoPlayerTizen extends VideoPlayerPlatform { final Map map = event as Map; switch (map['event']) { case 'initialized': - final List durationVal = map['duration']! as List; + final List? durationVal = map['duration'] as List?; return VideoEvent( eventType: VideoEventType.initialized, - duration: DurationRange(Duration(milliseconds: durationVal[0]), - Duration(milliseconds: durationVal[1])), + duration: DurationRange( + Duration(milliseconds: durationVal?[0] as int), + Duration(milliseconds: durationVal?[1] as int)), size: Size((map['width'] as num?)?.toDouble() ?? 0.0, (map['height'] as num?)?.toDouble() ?? 0.0), ); diff --git a/packages/video_player_videohole/lib/video_player.dart b/packages/video_player_videohole/lib/video_player.dart index a6077d11d..c9a7abb9d 100644 --- a/packages/video_player_videohole/lib/video_player.dart +++ b/packages/video_player_videohole/lib/video_player.dart @@ -331,6 +331,7 @@ class VideoPlayerController extends ValueNotifier { ClosedCaptionFile? _closedCaptionFile; Timer? _timer; + Timer? _durationTimer; bool _isDisposed = false; Completer? _creatingCompleter; StreamSubscription? _eventSubscription; @@ -419,6 +420,8 @@ class VideoPlayerController extends ValueNotifier { _applyLooping(); _applyVolume(); _applyPlayPause(); + _durationTimer?.cancel(); + _durationTimer = _createDurationTimer(); break; case VideoEventType.completed: // In this case we need to stop _timer, set isPlaying=false, and @@ -426,6 +429,7 @@ class VideoPlayerController extends ValueNotifier { // we use pause() and seekTo() to ensure the platform stops playing // and seeks to the last frame of the video. pause().then((void pauseResult) => seekTo(value.duration.end)); + _durationTimer?.cancel(); break; case VideoEventType.bufferingUpdate: value = value.copyWith(buffered: event.buffered); @@ -472,6 +476,7 @@ class VideoPlayerController extends ValueNotifier { final PlatformException e = obj as PlatformException; value = VideoPlayerValue.erroneous(e.message!); _timer?.cancel(); + _durationTimer?.cancel(); if (!initializingCompleter.isCompleted) { initializingCompleter.completeError(obj); } @@ -490,6 +495,7 @@ class VideoPlayerController extends ValueNotifier { if (!_isDisposed) { _isDisposed = true; _timer?.cancel(); + _durationTimer?.cancel(); await _eventSubscription?.cancel(); await _videoPlayerPlatform.dispose(_playerId); } @@ -537,6 +543,30 @@ class VideoPlayerController extends ValueNotifier { await _applyPlayPause(); } + /// The duration in the current video. + Future get duration async { + if (_isDisposed) { + return null; + } + return _videoPlayerPlatform.getDuration(_playerId); + } + + Timer _createDurationTimer() { + return Timer.periodic( + const Duration(milliseconds: 1000), + (Timer timer) async { + if (_isDisposed) { + return; + } + final DurationRange? newDuration = await duration; + if (newDuration == null) { + return; + } + _updateDuration(newDuration); + }, + ); + } + Future _applyLooping() async { if (_isDisposedOrNotInitialized) { return; @@ -763,6 +793,10 @@ class VideoPlayerController extends ValueNotifier { ); } + void _updateDuration(DurationRange duration) { + value = value.copyWith(duration: duration); + } + @override void removeListener(VoidCallback listener) { // Prevent VideoPlayer from causing an exception to be thrown when attempting to @@ -984,7 +1018,7 @@ class _VideoScrubberState extends State<_VideoScrubber> { }, onHorizontalDragEnd: (DragEndDetails details) { if (_controllerWasPlaying && - controller.value.position != controller.value.duration) { + controller.value.position != controller.value.duration.end) { controller.play(); } }, 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 7118f3308..d1fb0e917 100644 --- a/packages/video_player_videohole/lib/video_player_platform_interface.dart +++ b/packages/video_player_videohole/lib/video_player_platform_interface.dart @@ -127,6 +127,11 @@ abstract class VideoPlayerPlatform extends PlatformInterface { throw UnimplementedError('getPosition() has not been implemented.'); } + /// Gets the video duration as [DurationRange]. + Future getDuration(int playerId) { + throw UnimplementedError('getDuration() 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_videohole/tizen/src/media_player.cc b/packages/video_player_videohole/tizen/src/media_player.cc index dfb945407..97fbb86e1 100644 --- a/packages/video_player_videohole/tizen/src/media_player.cc +++ b/packages/video_player_videohole/tizen/src/media_player.cc @@ -6,6 +6,8 @@ #include +#include + #include "log.h" static std::string RotationToString(player_display_rotation_e rotation) { @@ -302,14 +304,18 @@ int64_t MediaPlayer::GetPosition() { } std::pair 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)); + if (IsLive()) { + return GetLiveDuration(); + } else { + 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 std::make_pair(0, duration); } - LOG_INFO("[MediaPlayer] Video duration: %d.", duration); - return std::make_pair(0, duration); } void MediaPlayer::GetVideoSize(int32_t *width, int32_t *height) { @@ -378,6 +384,51 @@ bool MediaPlayer::SetDisplay() { return true; } +bool MediaPlayer::IsLive() { + int is_live = 0; + int ret = media_player_proxy_->player_get_adaptive_streaming_info( + player_, &is_live, PLAYER_ADAPTIVE_INFO_IS_LIVE); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_adaptive_streaming_info failed: %s", + get_error_message(ret)); + return false; + } + return is_live != 0; +} + +static std::vector split(const std::string &s, char delim) { + std::stringstream ss(s); + std::string item; + std::vector tokens; + while (getline(ss, item, delim)) { + tokens.push_back(item); + } + return tokens; +} + +std::pair MediaPlayer::GetLiveDuration() { + std::string live_duration_str = ""; + char *live_duration_buff = static_cast(malloc(sizeof(char) * 64)); + memset(live_duration_buff, 0, sizeof(char) * 64); + int ret = media_player_proxy_->player_get_adaptive_streaming_info( + player_, (void *)&live_duration_buff, PLAYER_ADAPTIVE_INFO_LIVE_DURATION); + if (ret != PLAYER_ERROR_NONE) { + LOG_ERROR("[MediaPlayer] player_get_adaptive_streaming_info failed: %s", + get_error_message(ret)); + free(live_duration_buff); + return std::make_pair(0, 0); + } + if (*live_duration_buff) { + live_duration_str = std::string(live_duration_buff); + } + free(live_duration_buff); + if (live_duration_str.empty()) { + return std::make_pair(0, 0); + } + std::vector time_vec = split(live_duration_str, '|'); + return std::make_pair(std::stoll(time_vec[0]), std::stoll(time_vec[1])); +} + flutter::EncodableList MediaPlayer::GetTrackInfo(std::string track_type) { player_state_e state = PLAYER_STATE_NONE; int ret = player_get_state(player_, &state); diff --git a/packages/video_player_videohole/tizen/src/media_player.h b/packages/video_player_videohole/tizen/src/media_player.h index ab3a8213f..bdf6b36d5 100644 --- a/packages/video_player_videohole/tizen/src/media_player.h +++ b/packages/video_player_videohole/tizen/src/media_player.h @@ -42,6 +42,8 @@ class MediaPlayer : public VideoPlayer { bool SetTrackSelection(int32_t track_id, std::string track_type) override; private: + std::pair GetLiveDuration(); + bool IsLive(); bool SetDisplay(); bool SetDrm(const std::string &uri, int drm_type, const std::string &license_server_url); diff --git a/packages/video_player_videohole/tizen/src/media_player_proxy.cc b/packages/video_player_videohole/tizen/src/media_player_proxy.cc index 06adafac1..a6927b8c8 100644 --- a/packages/video_player_videohole/tizen/src/media_player_proxy.cc +++ b/packages/video_player_videohole/tizen/src/media_player_proxy.cc @@ -21,6 +21,11 @@ typedef int (*FuncPlayerSetDrmInitCompleteCB)( typedef int (*FuncPlayerSetDrmInitDataCB)(player_h player, set_drm_init_data_cb callback, void* user_data); + +typedef int (*FuncPlayerGetAdaptiveStreamingInfo)(player_h player, + void* adaptive_info, + int adaptive_type); + typedef int (*FuncPlayerGetTrackCountV2)(player_h player, player_stream_type_e type, int* pcount); @@ -115,6 +120,24 @@ int MediaPlayerProxy::player_set_drm_init_data_cb(player_h player, return player_set_drm_init_data_cb(player, callback, user_data); } +int MediaPlayerProxy::player_get_adaptive_streaming_info(player_h player, + void* adaptive_info, + int adaptive_type) { + if (!media_player_handle_) { + LOG_ERROR("media_player_handle_ not valid"); + return PLAYER_ERROR_NOT_AVAILABLE; + } + FuncPlayerGetAdaptiveStreamingInfo player_get_adaptive_streaming_info = + reinterpret_cast( + dlsym(media_player_handle_, "player_get_adaptive_streaming_info")); + if (!player_get_adaptive_streaming_info) { + LOG_ERROR("Fail to find player_get_adaptive_streaming_info."); + return PLAYER_ERROR_NOT_AVAILABLE; + } + return player_get_adaptive_streaming_info(player, adaptive_info, + adaptive_type); +} + int MediaPlayerProxy::player_get_track_count_v2(player_h player, player_stream_type_e type, int* pcount) { diff --git a/packages/video_player_videohole/tizen/src/media_player_proxy.h b/packages/video_player_videohole/tizen/src/media_player_proxy.h index 6e9e94d90..1229a42b4 100644 --- a/packages/video_player_videohole/tizen/src/media_player_proxy.h +++ b/packages/video_player_videohole/tizen/src/media_player_proxy.h @@ -55,6 +55,44 @@ typedef enum { PLAYER_DRM_TYPE_MAX_COUNT, } player_drm_type_e; +typedef enum { + PLAYER_ADAPTIVE_INFO_BITRATE_INIT, + PLAYER_ADAPTIVE_INFO_BITRATE_INIT_NUM, + PLAYER_ADAPTIVE_INFO_DURATION, + PLAYER_ADAPTIVE_INFO_LIVE_DURATION, + PLAYER_ADAPTIVE_INFO_AVAILABLE_BITRATES, + PLAYER_ADAPTIVE_INFO_RATE_RETURNED, + PLAYER_ADAPTIVE_INFO_CURRENT_BITRATE, + PLAYER_ADAPTIVE_INFO_GET_BUFFER_SIZE, + PLAYER_ADAPTIVE_INFO_FIXED_BITRATE, + PLAYER_ADAPTIVE_INFO_ADAPTIVE_BITRATE, + PLAYER_ADAPTIVE_INFO_MAX_BYTES, + PLAYER_ADAPTIVE_INFO_DRM_TYPE, + PLAYER_ADAPTIVE_INFO_RATE_REQUESTED, + PLAYER_ADAPTIVE_INFO_AUDIO_TRACK_REQUESTED, + PLAYER_ADAPTIVE_INFO_FORMAT, + PLAYER_ADAPTIVE_INFO_BLOCK, + PLAYER_ADAPTIVE_INFO_MIN_PERCENT, + PLAYER_ADAPTIVE_INFO_MIN_LATENCY, + PLAYER_ADAPTIVE_INFO_MAX_LATENCY, + PLAYER_ADAPTIVE_INFO_IS_LIVE, + PLAYER_ADAPTIVE_INFO_EMIT_SIGNAL, + PLAYER_ADAPTIVE_INFO_LOG_LEVEL, + PLAYER_ADAPTIVE_INFO_CURRENT_BANDWIDTH, + PLAYER_ADAPTIVE_INFO_URL_CUSTOM, + PLAYER_ADAPTIVE_INFO_GET_AUDIO_INFO, + PLAYER_ADAPTIVE_INFO_GET_VIDEO_INFO, + PLAYER_ADAPTIVE_INFO_GET_TEXT_INFO, + PLAYER_ADAPTIVE_INFO_RESUME_TIME, + PLAYER_ADAPTIVE_INFO_AUDIO_INDEX, + PLAYER_ADAPTIVE_INFO_PROXY_SETTING, + PLAYER_ADAPTIVE_INFO_ATSC3_L1_SERVER_TIME, + PLAYER_ADAPTIVE_INFO_VIDEO_FRAMES_DROPPED, + PLAYER_ADAPTIVE_INFO_STREAMING_IS_BUFFERING, + PLAYER_ADAPTIVE_INFO_PRESELECTION_ID, + PLAYER_ADAPTIVE_INFO_URI_TYPE +} player_adaptive_Info_e; + typedef enum { CENC = 0, KEYIDS = 1, @@ -82,6 +120,8 @@ class MediaPlayerProxy { int player_set_drm_init_data_cb(player_h player, set_drm_init_data_cb callback, void* user_data); + int player_get_adaptive_streaming_info(player_h player, void* adaptive_info, + int adaptive_type); 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, diff --git a/packages/video_player_videohole/tizen/src/video_player.cc b/packages/video_player_videohole/tizen/src/video_player.cc index f5eb7b812..8f1a162d2 100644 --- a/packages/video_player_videohole/tizen/src/video_player.cc +++ b/packages/video_player_videohole/tizen/src/video_player.cc @@ -104,9 +104,9 @@ void VideoPlayer::SendInitialized() { GetVideoSize(&width, &height); is_initialized_ = true; auto duration = GetDuration(); - flutter::EncodableList duration_range; - duration_range.push_back(flutter::EncodableValue(duration.first)); - duration_range.push_back(flutter::EncodableValue(duration.second)); + flutter::EncodableList duration_range{ + flutter::EncodableValue(duration.first), + flutter::EncodableValue(duration.second)}; flutter::EncodableMap result = { {flutter::EncodableValue("event"), flutter::EncodableValue("initialized")}, 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 23a1b6a52..7ee7b4c92 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 @@ -186,9 +186,9 @@ ErrorOr VideoPlayerTizenPlugin::Duration( } DurationMessage result(msg.player_id()); auto duration_pair = player->GetDuration(); - flutter::EncodableList duration_range; - duration_range.push_back(flutter::EncodableValue(duration_pair.first)); - duration_range.push_back(flutter::EncodableValue(duration_pair.second)); + flutter::EncodableList duration_range{ + flutter::EncodableValue(duration_pair.first), + flutter::EncodableValue(duration_pair.second)}; result.set_duration_range(duration_range); return result; } From 85c5bc6caca6ce7ac7cffbcce333b96f14048af9 Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Fri, 22 Dec 2023 15:18:25 +0800 Subject: [PATCH 3/5] Fix format error and dart analyze issue --- packages/video_player_videohole/lib/video_player.dart | 2 +- packages/video_player_videohole/pigeons/messages.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/video_player_videohole/lib/video_player.dart b/packages/video_player_videohole/lib/video_player.dart index c9a7abb9d..8f660bc34 100644 --- a/packages/video_player_videohole/lib/video_player.dart +++ b/packages/video_player_videohole/lib/video_player.dart @@ -513,7 +513,7 @@ class VideoPlayerController extends ValueNotifier { /// has been sent to the platform, not when playback itself is totally /// finished. Future play() async { - if (value.position == value.duration) { + if (value.position == value.duration.end) { await seekTo(Duration.zero); } value = value.copyWith(isPlaying: true); diff --git a/packages/video_player_videohole/pigeons/messages.dart b/packages/video_player_videohole/pigeons/messages.dart index 6c9ecdb21..c184baff0 100644 --- a/packages/video_player_videohole/pigeons/messages.dart +++ b/packages/video_player_videohole/pigeons/messages.dart @@ -82,7 +82,7 @@ class GeometryMessage { int height; } -class DurationMessage{ +class DurationMessage { DurationMessage(this.playerId); int playerId; List? durationRange; From d4d82497cd60f40e135ff3c09cc6c30f4ee6da95 Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Fri, 22 Dec 2023 17:28:32 +0800 Subject: [PATCH 4/5] Version up --- packages/video_player_videohole/CHANGELOG.md | 4 ++++ packages/video_player_videohole/README.md | 2 +- packages/video_player_videohole/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/video_player_videohole/CHANGELOG.md b/packages/video_player_videohole/CHANGELOG.md index c82ca3ef6..f99b5b4db 100644 --- a/packages/video_player_videohole/CHANGELOG.md +++ b/packages/video_player_videohole/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0 + +* Add get duration API for live stream + ## 0.4.0 * Merge media player code from avplay. diff --git a/packages/video_player_videohole/README.md b/packages/video_player_videohole/README.md index c80a76d13..f7fcc8ea9 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.4.0 + video_player_videohole: ^0.5.0 ``` Then you can import `video_player_videohole` in your Dart code: diff --git a/packages/video_player_videohole/pubspec.yaml b/packages/video_player_videohole/pubspec.yaml index bfd9edd4f..3a2dae2d1 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.4.0 +version: 0.5.0 environment: sdk: ">=2.18.0 <4.0.0" From 52a83e698f1ffaec4989603f0af291192a82da97 Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Thu, 28 Dec 2023 09:50:59 +0800 Subject: [PATCH 5/5] log format --- .../tizen/src/video_player_tizen_plugin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7ee7b4c92..9ff70c84c 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 @@ -182,7 +182,7 @@ ErrorOr VideoPlayerTizenPlugin::Duration( 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."); } DurationMessage result(msg.player_id()); auto duration_pair = player->GetDuration();