Open huluwa-dev opened 1 month ago
Hi, thank you for your interest.
- video_player_tizen is implemented using player.h provided by TizenSDK. (https://docs.tizen.org/application/native/api/iot-headed/6.0/group__CAPI__MEDIA__PLAYER__MODULE.html) Basic Media spcification can be found at the link below. https://developer.samsung.com/smarttv/develop/specifications/media-specifications.html https://developer.samsung.com/smarttv/develop/specifications/tv-model-groups.html
- (This may vary depending on the device's model, specifications, and Tizen version.) Tizen 8.0 provides an API that can find out the codec type (HW, SW, DEFAULT) of the video in the Player module. When I checked on my test device, the DEFAULT value was returned, and this can be SW or HW depending on the system priority. And I checked in the logs of my test tv device that the SW codec is being used. (Tizen 8.0) Maybe, if nothing else is set, it will work as a SW decoder.
If you have a Tizen 8.0 development environment set up, you can test the test code below. https://github.com/JSUYA/plugins/commit/efe4140de95ba2f7d24920b74b2d0a4415d11165
Hi @JSUYA , thanks for your quick reply.
Did you mean that you have ran the code I provided and confirmed that the Tizen OS decoded the video(https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8) with a SW codec?
If that is the case, could you help me to get an video example(url) which can be played with a HW codec? Thanks.
Hi @JSUYA , thanks for your quick reply.
Did you mean that you have ran the code I provided and confirmed that the Tizen OS decoded the video(https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8) with a SW codec?
If that is the case, could you help me to get an video example(url) which can be played with a HW codec? Thanks.
@huluwa-dev Hello, do you play video on TV device?
Hi @JSUYA , thanks for your quick reply.
Did you mean that you have ran the code I provided and confirmed that the Tizen OS decoded the video(https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8) with a SW codec?
yes I played https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 Your code looks like it uses flutter riverpod. (because of ConsumerStatefulWidget). this will not affect the decoder. I tested it in the example of video_player and only changed the url. (https://github.com/JSUYA/plugins/commit/efe4140de95ba2f7d24920b74b2d0a4415d11165)
If that is the case, could you help me to get an video example(url) which can be played with a HW codec? Thanks.
Unfortunately I don't know much about content that forces the use of HW codec.
Hi @xiaowei-guan Yes, I played the video on a Samsung TV with Tizen 6.0. Tomorrow I will post the TV's model information.
Hi @JSUYA , thanks for your quick reply. Did you mean that you have ran the code I provided and confirmed that the Tizen OS decoded the video(https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8) with a SW codec?
yes I played https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 Your code looks like it uses flutter riverpod. (because of ConsumerStatefulWidget). this will not affect the decoder. I tested it in the example of video_player and only changed the url. (JSUYA@efe4140)
If that is the case, could you help me to get an video example(url) which can be played with a HW codec? Thanks.
Unfortunately I don't know much about content that forces the use of HW codec.
Thanks for the confirmation.
As you are one of the contributors, do you know anybody who can help to make this plugin work with HW codec. SW codec is inefficient and produces poor user experience. I believe it could improve the performance a lot by utilizing a HW codec.
Thank you for your time.
I downloaded the video with yt-dlp
yt-dlp https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8
and checked the video's information with FFmpeg.
ffmpeg -i x36xhzz\ \[x36xhzz\].mp4
ffmpeg version 7.0.2 Copyright (c) 2000-2024 the FFmpeg developers
built with Apple clang version 16.0.0 (clang-1600.0.26.3)
configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.0.2_1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'x36xhzz [x36xhzz].mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf61.1.100
Duration: 00:10:34.59, start: 0.000000, bitrate: 6154 kb/s
Stream #0:0[0x1](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 151 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 5985 kb/s, 60 fps, 60 tbr, 90k tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
It is an H.264 video, it should be played with HW codec on most devices. But unfortunately, video_player_tizen plays it with SW codec.
It would be great if the tizen team could solve this problem.
Hi @JSUYA , thanks for your quick reply. Did you mean that you have ran the code I provided and confirmed that the Tizen OS decoded the video(https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8) with a SW codec?
yes I played https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 Your code looks like it uses flutter riverpod. (because of ConsumerStatefulWidget). this will not affect the decoder. I tested it in the example of video_player and only changed the url. (JSUYA@efe4140)
If that is the case, could you help me to get an video example(url) which can be played with a HW codec? Thanks.
Unfortunately I don't know much about content that forces the use of HW codec.
Thanks for the confirmation.
As you are one of the contributors, do you know anybody who can help to make this plugin work with HW codec. SW codec is inefficient and produces poor user experience. I believe it could improve the performance a lot by utilizing a HW codec.
Thank you for your time.
If you want to have a better performance, we suggest you use video_player_videohole. If you are a partner of Samsung, we suggest you use video_player_avplay.
@huluwa-dev The video_player_videohole and video_player_avplay only support TV device.
@huluwa-dev The video_player_videohole and video_player_avplay only support TV device.
Hi, thanks for the suggestion, I tried video_player_videohole, but some error occured, I think that's because the video I tried is not with DRM, I will post the detail of the errors tomorrow.
Hi @xiaowei-guan is video_player_videohole suitable for playing a content without DRM?
@huluwa-dev The video_player_videohole and video_player_avplay only support TV device.
Hi, thanks for the suggestion, I tried video_player_videohole, but some error occured, I think that's because the video I tried is not with DRM, I will post the detail of the errors tomorrow.
I can play the URL with video_player_videohole and video_player. video_player_videohole plugin has a goode performance, because video_player_videohole render the video on video plane layer, not on graphic layer.
if your app just for Tizen TV device, we suggest you use video_player_videohole plugin
Hi @xiaowei-guan is video_player_videohole suitable for playing a content without DRM?
@EricLinPixelforce Hi, if your app just run on Tizen TV device, we suggest you use video_player_videohole plugin, video_player_videohole also supports play DRM content, you need to be a partner of samsung.
As you are one of the contributors, do you know anybody who can help to make this plugin work with HW codec. SW codec is inefficient and produces poor user experience. I believe it could improve the performance a lot by utilizing a HW codec.
Thank you for your time.
@huluwa-dev
If you're just testing purposes, you can temporarily use the internal API(Does not guarantee operation) and I've created a commit to test it.
(There is absolutely no guarantee that this commit will be merged into master.)
https://github.com/JSUYA/plugins/commit/c8f94dba3bc02ac511027634a1c8cd7f591f5461
With this patch, try using VideoPlayerTizen.forceUseHwDecoder = true;
before calling Initialize of VideoController.
As I said before...Tizen 8.0 provides an API that can set the decoder. So if you are in an environment with Tizen 8.0, this operation maybe guaranteed, but in other environments (6.0, 6.5, 7.0), the operation may not be guaranteed. Also, when using the HW decoder, there was a abnormal behavior(?) in which certain contents on my device were initially displayed in a small screen size and then restored.
As far as I know, TV devices basically use HW decoder if HW decoder is available. The basic settings are not fixed to HW or SW. So, it is due to internal logic that your device uses SW decoder for playback. (There may be various reasons, such as device performance. If there is a difference with other apps, there may be a difference in the video player.) Therefore, if you want better performance or environment, you can use video_player_avplay or video_player_videohole.
Hi @xiaowei-guan is video_player_videohole suitable for playing a content without DRM?
@EricLinPixelforce Hi, if your app just run on Tizen TV device, we suggest you use video_player_videohole plugin, video_player_videohole also supports play DRM content, you need to be a partner of samsung.
Hi, thanks for the great news. Can video_player_videohole also play non-DRM contents?
I already regisered a Samsung seller account and will distribute a TV app to the Tizen store within a month.
@huluwa-dev The video_player_videohole and video_player_avplay only support TV device.
Hi, thanks for the suggestion, I tried video_player_videohole, but some error occured, I think that's because the video I tried is not with DRM, I will post the detail of the errors tomorrow.
I can play the URL with video_player_videohole and video_player. video_player_videohole plugin has a goode performance, because video_player_videohole render the video on video plane layer, not on graphic layer.
if your app just for Tizen TV device, we suggest you use video_player_videohole plugin
Hi, I tried to play the URL with video_player_videohole, but the player keeps producing an error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Pause, Player pause failed, null, null)
#0 VideoPlayerVideoholeApi.pause (package:video_player_videohole/src/messages.g.dart:790:7)
<asynchronous suspension>
#1 VideoPlayerController._applyPlayPause (package:video_player_videohole/video_player.dart:610:7)
<asynchronous suspension>
My code:
class VideoholdPlayerWidget extends StatefulWidget {
const VideoholdPlayerWidget({
super.key,
});
@override
State<VideoholdPlayerWidget> createState() => _VideoholdPlayerWidgetState();
}
class _VideoholdPlayerWidgetState extends State<VideoholdPlayerWidget> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_initPlayer();
}
void _initPlayer() {
_controller = VideoPlayerController.network(
// widget.videoUrl,
"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
);
_controller.addListener(() => setState(() {}));
_controller.initialize().then((_) => setState(() {}));
}
@override
Widget build(BuildContext context) {
return Center(
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
ClosedCaption(text: _controller.value.caption.text),
GestureDetector(
onTap: () {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
},
),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
I would appreciate it if you could give me any suggestions. Thanks.
@xiaowei-guan I also tried to play it with video_player_avplayer. I got this error:
[E]
(process:1400): GLib-CRITICAL **: 15:22:16.399: g_path_get_basename: assertion 'file_name != NULL' failed
[E]
(<unknown>:1400): GStreamer-WARNING **: 15:22:16.621: Failed to load plugin '/opt/usr/apps/com.traininpink.tv/lib/libgsthls.so': libclearkey.so.0: cannot open shared object file: Operation not permitted
[I] size of instance = 1240
size of class = 1428
[I] size of basesrc = 448
size of basesrcclass = 404
[E]
(<unknown>:1400): GStreamer-WARNING **: 15:22:17.423: Failed to load plugin '/usr/lib/gstreamer-1.0/libgsthls.so': libclearkey.so.0: cannot open shared object file: Operation not permitted
My code:
class AVPlayerWidget extends StatefulWidget {
const AVPlayerWidget({
super.key,
});
@override
State<AVPlayerWidget> createState() => _AVPlayerWidgetState();
}
class _AVPlayerWidgetState extends State<AVPlayerWidget> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_initPlayer();
}
void _initPlayer() {
_controller = VideoPlayerController.network(
"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
);
_controller.addListener(() => setState(() {}));
_controller.initialize().then((_) => setState(() {}));
}
@override
Widget build(BuildContext context) {
return Center(
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
ClosedCaption(text: _controller.value.caption.text),
GestureDetector(
onTap: () {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
},
),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
@JSUYA @xiaowei-guan The TV is a Samsung TV, model code: UA75BU8000WXXY (the model name should be 75" BU8000), with Tizen 6.5 running on it.
As you are one of the contributors, do you know anybody who can help to make this plugin work with HW codec. SW codec is inefficient and produces poor user experience. I believe it could improve the performance a lot by utilizing a HW codec. Thank you for your time.
@huluwa-dev If you're just testing purposes, you can temporarily use the internal API(Does not guarantee operation) and I've created a commit to test it. (There is absolutely no guarantee that this commit will be merged into master.) JSUYA@c8f94db With this patch, try using
VideoPlayerTizen.forceUseHwDecoder = true;
before calling Initialize of VideoController.As I said before...Tizen 8.0 provides an API that can set the decoder. So if you are in an environment with Tizen 8.0, this operation maybe guaranteed, but in other environments (6.0, 6.5, 7.0), the operation may not be guaranteed. Also, when using the HW decoder, there was a abnormal behavior(?) in which certain contents on my device were initially displayed in a small screen size and then restored.
As far as I know, TV devices basically use HW decoder if HW decoder is available. The basic settings are not fixed to HW or SW. So, it is due to internal logic that your device uses SW decoder for playback. (There may be various reasons, such as device performance. If there is a difference with other apps, there may be a difference in the video player.) Therefore, if you want better performance or environment, you can use video_player_avplay or video_player_videohole.
Thanks for the solution, I tried it on the TV, but still, it utilized HW codec to decode the video, because it was lagging.
@huluwa-dev The video_player_videohole and video_player_avplay only support TV device.
Hi, thanks for the suggestion, I tried video_player_videohole, but some error occured, I think that's because the video I tried is not with DRM, I will post the detail of the errors tomorrow.
I can play the URL with video_player_videohole and video_player. video_player_videohole plugin has a goode performance, because video_player_videohole render the video on video plane layer, not on graphic layer. if your app just for Tizen TV device, we suggest you use video_player_videohole plugin
Hi, I tried to play the URL with video_player_videohole, but the player keeps producing an error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Pause, Player pause failed, null, null) #0 VideoPlayerVideoholeApi.pause (package:video_player_videohole/src/messages.g.dart:790:7) <asynchronous suspension> #1 VideoPlayerController._applyPlayPause (package:video_player_videohole/video_player.dart:610:7) <asynchronous suspension>
My code:
class VideoholdPlayerWidget extends StatefulWidget { const VideoholdPlayerWidget({ super.key, }); @override State<VideoholdPlayerWidget> createState() => _VideoholdPlayerWidgetState(); } class _VideoholdPlayerWidgetState extends State<VideoholdPlayerWidget> { late VideoPlayerController _controller; @override void initState() { super.initState(); _initPlayer(); } void _initPlayer() { _controller = VideoPlayerController.network( // widget.videoUrl, "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8", ); _controller.addListener(() => setState(() {})); _controller.initialize().then((_) => setState(() {})); } @override Widget build(BuildContext context) { return Center( child: AspectRatio( aspectRatio: _controller.value.aspectRatio, child: Stack( alignment: Alignment.bottomCenter, children: <Widget>[ VideoPlayer(_controller), ClosedCaption(text: _controller.value.caption.text), GestureDetector( onTap: () { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }, ), VideoProgressIndicator(_controller, allowScrubbing: true), ], ), ), ); } @override void dispose() { _controller.dispose(); super.dispose(); } }
I would appreciate it if you could give me any suggestions. Thanks.
Hello, @EricLinPixelforce I can play the URL(https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8) by videohole sample code. code sample as follows:
class _HlsRomoteVideo extends StatefulWidget {
@override
State<_HlsRomoteVideo> createState() => _HlsRomoteVideoState();
}
class _HlsRomoteVideoState extends State<_HlsRomoteVideo> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(
'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8');
_controller.addListener(() {
if (_controller.value.hasError) {
print(_controller.value.errorDescription);
}
setState(() {});
});
_controller.setLooping(true);
_controller.initialize().then((_) => setState(() {}));
_controller.play();
}
plugin logs
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: GetDuration(316) > [MediaPlayer] Video duration: 33002.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: Create(67) > [MediaPlayer] uri: https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8, drm_type: 0.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 0.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 1.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 2.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 3.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 4.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 5.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 6.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 7.
I/VideoPlayerVideoHolePlugin(16752): media_player.cc: OnBuffering(648) > [MediaPlayer] Buffering percent: 8.
@xiaowei-guan I also tried to play it with video_player_avplayer. I got this error:
[E] (process:1400): GLib-CRITICAL **: 15:22:16.399: g_path_get_basename: assertion 'file_name != NULL' failed [E] (<unknown>:1400): GStreamer-WARNING **: 15:22:16.621: Failed to load plugin '/opt/usr/apps/com.traininpink.tv/lib/libgsthls.so': libclearkey.so.0: cannot open shared object file: Operation not permitted [I] size of instance = 1240 size of class = 1428 [I] size of basesrc = 448 size of basesrcclass = 404 [E] (<unknown>:1400): GStreamer-WARNING **: 15:22:17.423: Failed to load plugin '/usr/lib/gstreamer-1.0/libgsthls.so': libclearkey.so.0: cannot open shared object file: Operation not permitted
My code:
class AVPlayerWidget extends StatefulWidget { const AVPlayerWidget({ super.key, }); @override State<AVPlayerWidget> createState() => _AVPlayerWidgetState(); } class _AVPlayerWidgetState extends State<AVPlayerWidget> { late VideoPlayerController _controller; @override void initState() { super.initState(); _initPlayer(); } void _initPlayer() { _controller = VideoPlayerController.network( "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8", ); _controller.addListener(() => setState(() {})); _controller.initialize().then((_) => setState(() {})); } @override Widget build(BuildContext context) { return Center( child: AspectRatio( aspectRatio: _controller.value.aspectRatio, child: Stack( alignment: Alignment.bottomCenter, children: <Widget>[ VideoPlayer(_controller), ClosedCaption(text: _controller.value.caption.text), GestureDetector( onTap: () { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }, ), VideoProgressIndicator(_controller, allowScrubbing: true), ], ), ), ); } @override void dispose() { _controller.dispose(); super.dispose(); } }
If you want to use avplay plugin, you need to be a partner of samsung.
@xiaowei-guan Thanks for the reply. Now I can play it with your code sample in a created new project. But still got error in my existing project. That's weird. I will check the difference and find the reason.
@xiaowei-guan I found the reason, if I call play after the video is initialized, the error will occur
_controller.initialize().then((_) {
setState(() {});
_controller.play();
});
But if I play it without waiting for the initilization, it works well.
_controller.initialize().then((_) {
setState(() {});
});
_controller.play();
Hi @xiaowei-guan Currently I am playing videos with video_player_videohole, I tried to detect if the video playing is finished with the following code
_videoPlayerController.addListener(() {
print(
"_videoPlayerController.value.position = ${_videoPlayerController.value.position.inSeconds}, _videoPlayerController.value.duration.start = ${_videoPlayerController.value.duration.start.inSeconds}, _videoPlayerController.value.duration.end = ${_videoPlayerController.value.duration.end.inSeconds}");
if (_videoPlayerController.value.position >=
_videoPlayerController.value.duration.end &&
_videoPlayerController.value.position.inMilliseconds != 0) {
widget.onFinished?.call();
}
});
Finally I got this log and never detected it.
[I] flutter: _videoPlayerController.value.position = 23, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[I] flutter: _videoPlayerController.value.position = 23, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[I] flutter: _videoPlayerController.value.position = 23, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[I] flutter: _videoPlayerController.value.position = 24, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[I] flutter: _videoPlayerController.value.position = 24, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[I] flutter: _videoPlayerController.value.position = 24, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[I] flutter: _videoPlayerController.value.position = 24, _videoPlayerController.value.duration.start = 0, _videoPlayerController.value.duration.end = 26
[E] [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Pause, Player pause failed, null, null)
#0 VideoPlayerVideoholeApi.pause (package:video_player_videohole/src/messages.g.dart:790:7)
<asynchronous suspension>
#1 VideoPlayerController._applyPlayPause (package:video_player_videohole/video_player.dart:610:7)
<asynchronous suspension>
#2 VideoPlayerController.pause (package:video_player_videohole/video_player.dart:533:5)
<asynchronous suspension>
#3 VideoPlayerController.initialize.eventListener.<anonymous closure> (package:video_player_videohole/video_player.dart:426:24)
<asynchronous suspension>
_videoPlayerController.value.position never reached the end.
Could you help me to resolve it? Thanks.
Hello, @EricLinPixelforce , I have checked the position value, the value of position really cannot reach the end. Do you need a completed event from the player?
Hello, @EricLinPixelforce , I have checked the position value, the value of position really cannot reach the end. Do you need a completed event from the player?
Yes, that's exactly what I want! I would be grateful if you could expose the event.
Hello, @EricLinPixelforce , I have checked the position value, the value of position really cannot reach the end. Do you need a completed event from the player?
Yes, that's exactly what I want! I would be grateful if you could expose the event.
Ok, I will add it.
@EricLinPixelforce Please verify this new PR #766
@EricLinPixelforce Please verify this new PR #766
Looks good, thanks. Have you tested it?
@EricLinPixelforce Please verify this new PR #766
Looks good, thanks. Have you tested it?
Yes, I have tested it at my side. you can verify this PR at your side.
@EricLinPixelforce Please verify this new PR #766
Looks good, thanks. Have you tested it?
Yes, I have tested it at my side. you can verify this PR at your side.
Hi @xiaowei-guan thank you for the solution, it works as expected, but an error message printed in the console.
[E] [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Pause, Player pause failed, null, null)
#0 VideoPlayerVideoholeApi.pause (package:video_player_videohole/src/messages.g.dart:790:7)
<asynchronous suspension>
#1 VideoPlayerController._applyPlayPause (package:video_player_videohole/video_player.dart:636:7)
<asynchronous suspension>
#2 VideoPlayerController.pause (package:video_player_videohole/video_player.dart:559:5)
<asynchronous suspension>
#3 VideoPlayerController.initialize.eventListener.<anonymous closure> (package:video_player_videohole/video_player.dart:448:24)
<asynchronous suspension>
@EricLinPixelforce Please verify this new PR #766
Looks good, thanks. Have you tested it?
Yes, I have tested it at my side. you can verify this PR at your side.
Hi @xiaowei-guan thank you for the solution, it works as expected, but an error message printed in the console.
[E] [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Pause, Player pause failed, null, null) #0 VideoPlayerVideoholeApi.pause (package:video_player_videohole/src/messages.g.dart:790:7) <asynchronous suspension> #1 VideoPlayerController._applyPlayPause (package:video_player_videohole/video_player.dart:636:7) <asynchronous suspension> #2 VideoPlayerController.pause (package:video_player_videohole/video_player.dart:559:5) <asynchronous suspension> #3 VideoPlayerController.initialize.eventListener.<anonymous closure> (package:video_player_videohole/video_player.dart:448:24) <asynchronous suspension>
I have checked the code, plugin need to stop position timer and keep position value = duration.end when receiving completed event, so plugin need call pause() and seekTo() to ensure the platfomr stops playing and seeks to the last frame of the video. Because the native player's state not playing, so call pause() failed, got the pause failed message, I think we can ignore this message.
Hi @xiaowei-guan thanks for the explanation. The last issue I met is about the seekTo function. I saw the following limitation of the plugin
The seekTo method works only when the playback speed is 1.0, and it sets the video position to the nearest keyframe, not the exact value passed.
In my code, it listens the right arrow and left arrow buttons, the video will fast forward or backward when I click the buttons. But if I click a same button, say the right arrow button, multiple times in a short time, the current position of the video will back and forth, which make the progress bar looks weird. My code about fast forward/backward:
final duration = _videoPlayerController.value.duration;
final currentPosition = await _videoPlayerController.position;
if (currentPosition != null) {
final lengthSeconds =
duration.end.inSeconds - duration.start.inSeconds;
final currentSeconds = currentPosition.inSeconds;
var newPosition = currentSeconds + 15;
if (newPosition < 0) {
newPosition = 0;
}
if (newPosition > lengthSeconds) {
newPosition = lengthSeconds;
}
final newPositionDuration = Duration(seconds: newPosition);
_videoPlayerController.seekTo(newPositionDuration);
}
Hi @xiaowei-guan thanks for the explanation. The last issue I met is about the seekTo function. I saw the following limitation of the plugin
The seekTo method works only when the playback speed is 1.0, and it sets the video position to the nearest keyframe, not the exact value passed.
In my code, it listens the right arrow and left arrow buttons, the video will fast forward or backward when I click the buttons. But if I click a same button, say the right arrow button, multiple times in a short time, the current position of the video will back and forth, which make the progress bar looks weird. My code about fast forward/backward:
final duration = _videoPlayerController.value.duration; final currentPosition = await _videoPlayerController.position; if (currentPosition != null) { final lengthSeconds = duration.end.inSeconds - duration.start.inSeconds; final currentSeconds = currentPosition.inSeconds; var newPosition = currentSeconds + 15; if (newPosition < 0) { newPosition = 0; } if (newPosition > lengthSeconds) { newPosition = lengthSeconds; } final newPositionDuration = Duration(seconds: newPosition); _videoPlayerController.seekTo(newPositionDuration); }
Hi @xiaowei-guan @JSUYA could you help on this issue? Thanks
Hi @xiaowei-guan thanks for the explanation. The last issue I met is about the seekTo function. I saw the following limitation of the plugin
The seekTo method works only when the playback speed is 1.0, and it sets the video position to the nearest keyframe, not the exact value passed.
In my code, it listens the right arrow and left arrow buttons, the video will fast forward or backward when I click the buttons. But if I click a same button, say the right arrow button, multiple times in a short time, the current position of the video will back and forth, which make the progress bar looks weird. My code about fast forward/backward:
final duration = _videoPlayerController.value.duration; final currentPosition = await _videoPlayerController.position; if (currentPosition != null) { final lengthSeconds = duration.end.inSeconds - duration.start.inSeconds; final currentSeconds = currentPosition.inSeconds; var newPosition = currentSeconds + 15; if (newPosition < 0) { newPosition = 0; } if (newPosition > lengthSeconds) { newPosition = lengthSeconds; } final newPositionDuration = Duration(seconds: newPosition); _videoPlayerController.seekTo(newPositionDuration); }
Hi @xiaowei-guan @JSUYA could you help on this issue? Thanks
@EricLinPixelforce Below comment is native player seekTo guide:
/**
* @brief Seek for playback, asynchronously.
* @remarks In case of non-seekable content, it will return @c False \n
* If application ignore this error,
* player will keep playing without changing play position. \n
* EventListener::OnSeekDone() will be called if seek operation is
* finished \n Seek result can be succeeded or not at this moment. \n
* Resumeplay : Seek() can be called in #State::kIdle \n
* Call sequence of resumeplay : Open() -> Seek() with
* resume_position -> Prepare() -> Start()
* @param [in] time_millisecond : the absolute position(playingtime) of
* the stream in milliseconds
* @pre The player state must be one of #State::kReady,
* #State::kPlaying or #State::kPaused or #State::kIdle
* @post None
* @exception None
* @return @c True if seek operation is started without any problem
* otherwise @c False
* @see EventListener::OnSeekDone()
*/
virtual bool Seek(const uint64_t time_millisecond) { return false; }
Because SeekTo is asynchronously method, we need make sure previous seekTo operation is completed, then we can call next seekTo. If you call seekTo multiple times in a short time, it may only be processed once.
@xiaowei-guan Hi, thanks for the reply. I understand the logic. However, if I call seekTo multiple times, currently it will wait for the completion of the first call, the other calls will be ignored. I believe it is ideal to take the last call as the valid one and cancel the previous calls.
@xiaowei-guan Hi, thanks for the reply. I understand the logic. However, if I call seekTo multiple times, currently it will wait for the completion of the first call, the other calls will be ignored. I believe it is ideal to take the last call as the valid one and cancel the previous calls.
@xiaowei-guan Hi, is it possible to fix this issue as well? Thanks.
I tried to play an HLS video with video_player_tizen, but when the video quality automatically updated to 1080P, the playback started stuttering significantly. I assume the video was played using a software codec, as other video-playing apps work well (like YouTube), even with 4K videos.
Could you help me confirm whether this plugin uses a software decoder for video playback? Thanks.
This is the code snippet: