avplayer: implemented pause/resume

This commit is contained in:
Vladislav Mikhalin 2025-02-16 12:07:48 +03:00
parent f48fa9f447
commit c39179a5f4
8 changed files with 77 additions and 12 deletions

View file

@ -159,11 +159,11 @@ s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) {
} }
s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) { s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); LOG_TRACE(Lib_AvPlayer, "(STUBBED) called");
if (handle == nullptr) { if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
} }
return ORBIS_OK; return handle->Pause();
} }
s32 PS4_SYSV_ABI sceAvPlayerPostInit(AvPlayerHandle handle, AvPlayerPostInitData* data) { s32 PS4_SYSV_ABI sceAvPlayerPostInit(AvPlayerHandle handle, AvPlayerPostInitData* data) {
@ -180,11 +180,11 @@ s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) {
} }
s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) { s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); LOG_TRACE(Lib_AvPlayer, "(STUBBED) called");
if (handle == nullptr) { if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
} }
return ORBIS_OK; return handle->Resume();
} }
s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) { s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) {

View file

@ -16,6 +16,7 @@
namespace Libraries::AvPlayer { namespace Libraries::AvPlayer {
enum class AvState { enum class AvState {
Unknown,
Initial, Initial,
AddingSource, AddingSource,
Ready, Ready,

View file

@ -148,7 +148,21 @@ s32 AvPlayer::EnableStream(u32 stream_index) {
} }
s32 AvPlayer::Start() { s32 AvPlayer::Start() {
if (!m_state->Start()) { if (m_state == nullptr || !m_state->Start()) {
return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED;
}
return ORBIS_OK;
}
s32 AvPlayer::Pause() {
if (m_state == nullptr || !m_state->Pause()) {
return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED;
}
return ORBIS_OK;
}
s32 AvPlayer::Resume() {
if (m_state == nullptr || !m_state->Resume()) {
return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED;
} }
return ORBIS_OK; return ORBIS_OK;

View file

@ -28,6 +28,8 @@ public:
s32 GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); s32 GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info);
s32 EnableStream(u32 stream_index); s32 EnableStream(u32 stream_index);
s32 Start(); s32 Start();
s32 Pause();
s32 Resume();
bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetAudioData(AvPlayerFrameInfo& audio_info);
bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfo& video_info);
bool GetVideoData(AvPlayerFrameInfoEx& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info);

View file

@ -280,6 +280,16 @@ bool AvPlayerSource::Stop() {
return true; return true;
} }
void AvPlayerSource::Pause() {
m_last_paused_time = std::chrono::high_resolution_clock::now();
m_is_paused = true;
}
void AvPlayerSource::Resume() {
m_stalled_time += std::chrono::high_resolution_clock::now() - m_last_paused_time;
m_is_paused = false;
}
bool AvPlayerSource::GetVideoData(AvPlayerFrameInfo& video_info) { bool AvPlayerSource::GetVideoData(AvPlayerFrameInfo& video_info) {
if (!IsActive()) { if (!IsActive()) {
return false; return false;
@ -299,7 +309,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfo& video_info) {
} }
bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) {
if (!IsActive()) { if (!IsActive() || m_is_paused) {
return false; return false;
} }
@ -313,8 +323,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) {
{ {
using namespace std::chrono; using namespace std::chrono;
auto elapsed_time = auto elapsed_time = CurrentTime();
duration_cast<milliseconds>(high_resolution_clock::now() - m_start_time).count();
if (elapsed_time < frame->info.timestamp) { if (elapsed_time < frame->info.timestamp) {
if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time), if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time),
[&] { return elapsed_time >= frame->info.timestamp; })) { [&] { return elapsed_time >= frame->info.timestamp; })) {
@ -334,7 +343,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) {
} }
bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) {
if (!IsActive()) { if (!IsActive() || m_is_paused) {
return false; return false;
} }
@ -348,8 +357,7 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) {
{ {
using namespace std::chrono; using namespace std::chrono;
auto elapsed_time = auto elapsed_time = CurrentTime();
duration_cast<milliseconds>(high_resolution_clock::now() - m_start_time).count();
if (elapsed_time < frame->info.timestamp) { if (elapsed_time < frame->info.timestamp) {
if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time), if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time),
[&] { return elapsed_time >= frame->info.timestamp; })) { [&] { return elapsed_time >= frame->info.timestamp; })) {
@ -379,7 +387,8 @@ u64 AvPlayerSource::CurrentTime() {
return 0; return 0;
} }
using namespace std::chrono; using namespace std::chrono;
return duration_cast<milliseconds>(high_resolution_clock::now() - m_start_time).count(); return duration_cast<milliseconds>(high_resolution_clock::now() - m_start_time - m_stalled_time)
.count();
} }
bool AvPlayerSource::IsActive() { bool AvPlayerSource::IsActive() {

View file

@ -130,6 +130,8 @@ public:
std::optional<bool> HasFrames(u32 num_frames); std::optional<bool> HasFrames(u32 num_frames);
bool Start(); bool Start();
bool Stop(); bool Stop();
void Pause();
void Resume();
bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetAudioData(AvPlayerFrameInfo& audio_info);
bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfo& video_info);
bool GetVideoData(AvPlayerFrameInfoEx& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info);
@ -170,6 +172,7 @@ private:
u32 m_num_output_video_framebuffers{}; u32 m_num_output_video_framebuffers{};
std::atomic_bool m_is_looping = false; std::atomic_bool m_is_looping = false;
std::atomic_bool m_is_paused = false;
std::atomic_bool m_is_eof = false; std::atomic_bool m_is_eof = false;
std::unique_ptr<IDataStreamer> m_up_data_streamer; std::unique_ptr<IDataStreamer> m_up_data_streamer;
@ -211,6 +214,8 @@ private:
SWSContextPtr m_sws_context{nullptr, &ReleaseSWSContext}; SWSContextPtr m_sws_context{nullptr, &ReleaseSWSContext};
std::chrono::high_resolution_clock::time_point m_start_time{}; std::chrono::high_resolution_clock::time_point m_start_time{};
std::chrono::high_resolution_clock::time_point m_last_paused_time{};
std::chrono::high_resolution_clock::duration m_stalled_time{};
}; };
} // namespace Libraries::AvPlayer } // namespace Libraries::AvPlayer

View file

@ -185,6 +185,38 @@ bool AvPlayerState::Start() {
return true; return true;
} }
// Called inside GAME thread
bool AvPlayerState::Pause() {
std::shared_lock lock(m_source_mutex);
if (m_current_state == AvState::EndOfFile) {
return true;
}
if (m_up_source == nullptr || m_current_state == AvState::Pause ||
m_current_state == AvState::Ready || m_current_state == AvState::Initial ||
m_current_state == AvState::Unknown || m_current_state == AvState::AddingSource) {
LOG_ERROR(Lib_AvPlayer, "Could not pause playback.");
return false;
}
m_up_source->Pause();
SetState(AvState::Pause);
OnPlaybackStateChanged(AvState::Pause);
return true;
}
// Called inside GAME thread
bool AvPlayerState::Resume() {
std::shared_lock lock(m_source_mutex);
if (m_up_source == nullptr || m_current_state != AvState::Pause) {
LOG_ERROR(Lib_AvPlayer, "Could not resume playback.");
return false;
}
m_up_source->Resume();
const auto state = m_previous_state.load();
SetState(state);
OnPlaybackStateChanged(state);
return true;
}
void AvPlayerState::AvControllerThread(std::stop_token stop) { void AvPlayerState::AvControllerThread(std::stop_token stop) {
using std::chrono::milliseconds; using std::chrono::milliseconds;
Common::SetCurrentThreadName("shadPS4:AvController"); Common::SetCurrentThreadName("shadPS4:AvController");

View file

@ -28,6 +28,8 @@ public:
bool EnableStream(u32 stream_index); bool EnableStream(u32 stream_index);
bool Start(); bool Start();
bool Stop(); bool Stop();
bool Pause();
bool Resume();
bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetAudioData(AvPlayerFrameInfo& audio_info);
bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfo& video_info);
bool GetVideoData(AvPlayerFrameInfoEx& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info);