Skip to content

Commit

Permalink
[video_player] Live streaming content starts playing immediately when…
Browse files Browse the repository at this point in the history
… seekTo is called (#742)
  • Loading branch information
JSUYA authored Sep 19, 2024
1 parent fdc1c50 commit 95fe22f
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 18 deletions.
4 changes: 4 additions & 0 deletions packages/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.5.2

* Live streaming content starts playing immediately when SeekTo() is called.

## 2.5.1

* Update pigeon to 22.3.0.
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This package is not an _endorsed_ implementation of `video_player`. Therefore, y
```yaml
dependencies:
video_player: ^2.9.1
video_player_tizen: ^2.5.1
video_player_tizen: ^2.5.2
```
Then you can import `video_player` in your Dart code:
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: video_player_tizen
description: Tizen implementation of the video_player plugin.
homepage: https://github.com/flutter-tizen/plugins
repository: https://github.com/flutter-tizen/plugins/tree/master/packages/video_player
version: 2.5.1
version: 2.5.2

environment:
sdk: ">=3.3.0 <4.0.0"
Expand Down
45 changes: 45 additions & 0 deletions packages/video_player/tizen/src/media_player_proxy.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media_player_proxy.h"

#include <dlfcn.h>

#include "log.h"

typedef int (*FuncPlayerGetAdaptiveStreamingInfo)(player_h player,
void* adaptive_info,
int adaptive_type);

MediaPlayerProxy::MediaPlayerProxy() {
media_player_handle_ = dlopen("libcapi-media-player.so.0", RTLD_LAZY);
if (media_player_handle_ == nullptr) {
LOG_ERROR("Failed to open media player.");
}
}

MediaPlayerProxy::~MediaPlayerProxy() {
if (media_player_handle_) {
dlclose(media_player_handle_);
media_player_handle_ = nullptr;
}
}

int MediaPlayerProxy::player_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<FuncPlayerGetAdaptiveStreamingInfo>(
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);
}
60 changes: 60 additions & 0 deletions packages/video_player/tizen/src/media_player_proxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_PLUGIN_MEDIA_PLAYER_PROXY_H_
#define FLUTTER_PLUGIN_MEDIA_PLAYER_PROXY_H_

#include <player.h>

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;

class MediaPlayerProxy {
public:
MediaPlayerProxy();
~MediaPlayerProxy();

int player_get_adaptive_streaming_info(player_h player, void* adaptive_info,
int adaptive_type);

private:
void* media_player_handle_ = nullptr;
};

#endif // FLUTTER_PLUGIN_MEDIA_PLAYER_PROXY_H_
111 changes: 95 additions & 16 deletions packages/video_player/tizen/src/video_player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <flutter/standard_method_codec.h>

#include <algorithm>
#include <sstream>

#include "log.h"
#include "video_player_error.h"
Expand Down Expand Up @@ -130,6 +131,8 @@ VideoPlayer::VideoPlayer(flutter::PluginRegistrar *plugin_registrar,
gpu_surface_ = std::make_unique<FlutterDesktopGpuSurfaceDescriptor>();
texture_id_ = texture_registrar->RegisterTexture(texture_variant_.get());

media_player_proxy_ = std::make_unique<MediaPlayerProxy>();

int ret = player_create(&player_);
if (ret != PLAYER_ERROR_NONE) {
throw VideoPlayerError("player_create failed", get_error_message(ret));
Expand All @@ -140,6 +143,7 @@ VideoPlayer::VideoPlayer(flutter::PluginRegistrar *plugin_registrar,
player_destroy(player_);
throw VideoPlayerError("player_set_uri failed", get_error_message(ret));
}
uri_ = uri;

ret = player_set_display_visible(player_, true);
if (ret != PLAYER_ERROR_NONE) {
Expand Down Expand Up @@ -336,8 +340,15 @@ void VideoPlayer::SeekTo(int32_t position, SeekCompletedCallback callback) {
player_set_play_position(player_, position, true, OnSeekCompleted, this);
if (ret != PLAYER_ERROR_NONE) {
on_seek_completed_ = nullptr;
throw VideoPlayerError("player_set_play_position failed",
get_error_message(ret));
// TODO(jsuya):Live content does not provide a duration that allows
// SeekTo(), so we call Play() to start playback immediately from the
// current.
if (position == 0 && IsLive()) {
Play();
} else {
throw VideoPlayerError("player_set_play_position failed",
get_error_message(ret));
}
}
}

Expand Down Expand Up @@ -436,16 +447,11 @@ void VideoPlayer::Initialize() {

void VideoPlayer::SendInitialized() {
if (!is_initialized_ && event_sink_) {
int duration = 0;
int ret = player_get_duration(player_, &duration);
if (ret != PLAYER_ERROR_NONE) {
SendError("player_get_duration failed", get_error_message(ret));
return;
}
int duration = GetDuration();
LOG_DEBUG("[VideoPlayer] Video duration: %d", duration);

int width = 0, height = 0;
ret = player_get_video_size(player_, &width, &height);
int ret = player_get_video_size(player_, &width, &height);
if (ret != PLAYER_ERROR_NONE) {
SendError("player_get_video_size failed", get_error_message(ret));
return;
Expand All @@ -465,13 +471,15 @@ void VideoPlayer::SendInitialized() {
}
}

// TODO(jsuya):Some streaming resources may have a duration of 0 during the
// initialization step. If the duration is 0, it may affect the progress of
// video_player and cause unnecessary errors. Therefore, set it to 1
// temporarily. In the future, It can be updated depending on
// the loading status.
if (width != 0 && height != 0 && duration == 0) {
duration = 1;
// TODO(jsuya): Since media_player_proxy is not supported in Tizen
// profile(common), we cannot know whether the content is live or not. When
// the content is live, duration is always returned as 0, so we check if
// duration is 1(Because of we set it to 1 to prevent video_player from
// crashing when duration is returned as 0).
if (uri_.substr(0, 4) == "http" && duration == 1) {
is_live_ = true;
} else {
is_live_ = false;
}

is_initialized_ = true;
Expand Down Expand Up @@ -599,3 +607,74 @@ void VideoPlayer::OnRenderingCompleted() {
}
RequestRendering();
}

int64_t VideoPlayer::GetDuration() {
int duration = 0;
if (IsLive()) {
duration = GetLiveDuration();
} else {
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);
}

// TODO(jsuya):Some streaming resources may have a duration of 0 during the
// initialization step. If the duration is 0, it may affect the progress of
// video_player and cause unnecessary errors. Therefore, set it to 1
// temporarily. In the future, It can be updated depending on
// the loading status.
if (duration == 0) {
duration = 1;
}

return duration;
}

static std::vector<std::string> split(const std::string &s, char delim) {
std::stringstream ss(s);
std::string item;
std::vector<std::string> tokens;
while (getline(ss, item, delim)) {
tokens.push_back(item);
}
return tokens;
}

int64_t VideoPlayer::GetLiveDuration() {
std::string live_duration_str = "";
char *live_duration_buff = static_cast<char *>(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 0;
}
if (*live_duration_buff) {
live_duration_str = std::string(live_duration_buff);
}
free(live_duration_buff);
if (live_duration_str.empty()) {
return 0;
}
std::vector<std::string> time_vec = split(live_duration_str, '|');
return std::stoll(time_vec[1]);
}

bool VideoPlayer::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 is_live_;
}
is_live_ = is_live != 0;
return is_live_;
}
7 changes: 7 additions & 0 deletions packages/video_player/tizen/src/video_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <queue>
#include <string>

#include "media_player_proxy.h"
#include "video_player_options.h"

typedef int (*ScreensaverResetTimeout)(void);
Expand Down Expand Up @@ -69,19 +70,25 @@ class VideoPlayer {

void RequestRendering();
void OnRenderingCompleted();
int64_t GetDuration();
int64_t GetLiveDuration();
bool IsLive();

media_packet_h current_media_packet_ = nullptr;
media_packet_h previous_media_packet_ = nullptr;

bool is_initialized_ = false;
bool is_rendering_ = false;
bool is_live_ = false;

std::unique_ptr<flutter::EventChannel<flutter::EncodableValue>>
event_channel_;
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> event_sink_;

player_h player_ = nullptr;
std::unique_ptr<MediaPlayerProxy> media_player_proxy_ = nullptr;
int64_t texture_id_ = -1;
std::string uri_;

flutter::TextureRegistrar *texture_registrar_;
std::unique_ptr<flutter::TextureVariant> texture_variant_;
Expand Down

0 comments on commit 95fe22f

Please sign in to comment.