From f48fa9f44725eb32ae3189a1610f4864b5ad3c42 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sun, 16 Feb 2025 10:39:54 +0300 Subject: [PATCH 1/9] avplayer: code improvements --- src/core/libraries/avplayer/avplayer.cpp | 120 +++++-------- src/core/libraries/avplayer/avplayer.h | 164 +++++++++--------- .../libraries/avplayer/avplayer_common.cpp | 14 +- src/core/libraries/avplayer/avplayer_common.h | 2 +- .../avplayer/avplayer_file_streamer.cpp | 4 +- .../avplayer/avplayer_file_streamer.h | 4 +- src/core/libraries/avplayer/avplayer_impl.cpp | 34 ++-- src/core/libraries/avplayer/avplayer_impl.h | 19 +- .../libraries/avplayer/avplayer_source.cpp | 36 ++-- src/core/libraries/avplayer/avplayer_source.h | 22 +-- .../libraries/avplayer/avplayer_state.cpp | 44 ++--- src/core/libraries/avplayer/avplayer_state.h | 26 +-- 12 files changed, 234 insertions(+), 255 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index 176fda137..c58bf42e1 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -9,23 +9,22 @@ namespace Libraries::AvPlayer { -s32 PS4_SYSV_ABI sceAvPlayerAddSource(SceAvPlayerHandle handle, const char* filename) { +s32 PS4_SYSV_ABI sceAvPlayerAddSource(AvPlayerHandle handle, const char* filename) { LOG_TRACE(Lib_AvPlayer, "filename = {}", filename); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->AddSource(filename); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->AddSource(filename); } -s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(SceAvPlayerHandle handle, SceAvPlayerUriType uriType, - SceAvPlayerSourceDetails* sourceDetails) { +s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(AvPlayerHandle handle, AvPlayerUriType uri_type, + AvPlayerSourceDetails* source_details) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); - if (handle == nullptr) { + if (handle == nullptr || uri_type != AvPlayerUriType::Source) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - return ORBIS_OK; + const auto path = std::string_view(source_details->uri.name, source_details->uri.length); + return handle->AddSourceEx(path, source_details->source_type); } int PS4_SYSV_ABI sceAvPlayerChangeStream() { @@ -33,28 +32,24 @@ int PS4_SYSV_ABI sceAvPlayerChangeStream() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerClose(SceAvPlayerHandle handle) { +s32 PS4_SYSV_ABI sceAvPlayerClose(AvPlayerHandle handle) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { - LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS"); return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } delete handle; - LOG_TRACE(Lib_AvPlayer, "returning ORBIS_OK"); return ORBIS_OK; } -u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(SceAvPlayerHandle handle) { +u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(AvPlayerHandle handle) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->CurrentTime(); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->CurrentTime(); } -s32 PS4_SYSV_ABI sceAvPlayerDisableStream(SceAvPlayerHandle handle, u32 stream_id) { +s32 PS4_SYSV_ABI sceAvPlayerDisableStream(AvPlayerHandle handle, u32 stream_id) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -62,60 +57,49 @@ s32 PS4_SYSV_ABI sceAvPlayerDisableStream(SceAvPlayerHandle handle, u32 stream_i return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerEnableStream(SceAvPlayerHandle handle, u32 stream_id) { +s32 PS4_SYSV_ABI sceAvPlayerEnableStream(AvPlayerHandle handle, u32 stream_id) { LOG_TRACE(Lib_AvPlayer, "stream_id = {}", stream_id); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->EnableStream(stream_id); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->EnableStream(stream_id); } -bool PS4_SYSV_ABI sceAvPlayerGetAudioData(SceAvPlayerHandle handle, SceAvPlayerFrameInfo* p_info) { +bool PS4_SYSV_ABI sceAvPlayerGetAudioData(AvPlayerHandle handle, AvPlayerFrameInfo* p_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || p_info == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->GetAudioData(*p_info); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->GetAudioData(*p_info); } -s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(SceAvPlayerHandle handle, u32 stream_id, - SceAvPlayerStreamInfo* p_info) { +s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(AvPlayerHandle handle, u32 stream_id, + AvPlayerStreamInfo* p_info) { LOG_TRACE(Lib_AvPlayer, "stream_id = {}", stream_id); if (handle == nullptr || p_info == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->GetStreamInfo(stream_id, *p_info); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->GetStreamInfo(stream_id, *p_info); } -bool PS4_SYSV_ABI sceAvPlayerGetVideoData(SceAvPlayerHandle handle, - SceAvPlayerFrameInfo* video_info) { +bool PS4_SYSV_ABI sceAvPlayerGetVideoData(AvPlayerHandle handle, AvPlayerFrameInfo* video_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || video_info == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->GetVideoData(*video_info); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->GetVideoData(*video_info); } -bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(SceAvPlayerHandle handle, - SceAvPlayerFrameInfoEx* video_info) { +bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(AvPlayerHandle handle, + AvPlayerFrameInfoEx* video_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || video_info == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->GetVideoData(*video_info); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->GetVideoData(*video_info); } -SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) { +AvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(AvPlayerInitData* data) { LOG_TRACE(Lib_AvPlayer, "called"); if (data == nullptr) { return nullptr; @@ -125,15 +109,14 @@ SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) { data->memory_replacement.allocate_texture == nullptr || data->memory_replacement.deallocate == nullptr || data->memory_replacement.deallocate_texture == nullptr) { - LOG_ERROR(Lib_AvPlayer, "All allocators are required for AVPlayer Initialisation."); + LOG_ERROR(Lib_AvPlayer, "All allocators are required for AvPlayer Initialisation."); return nullptr; } return new AvPlayer(*data); } -s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data, - SceAvPlayerHandle* p_player) { +s32 PS4_SYSV_ABI sceAvPlayerInitEx(const AvPlayerInitDataEx* p_data, AvPlayerHandle* p_player) { LOG_TRACE(Lib_AvPlayer, "called"); if (p_data == nullptr || p_player == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -143,11 +126,11 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data, p_data->memory_replacement.allocate_texture == nullptr || p_data->memory_replacement.deallocate == nullptr || p_data->memory_replacement.deallocate_texture == nullptr) { - LOG_ERROR(Lib_AvPlayer, "All allocators are required for AVPlayer Initialisation."); + LOG_ERROR(Lib_AvPlayer, "All allocators are required for AvPlayer Initialisation."); return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - SceAvPlayerInitData data = {}; + AvPlayerInitData data = {}; data.memory_replacement = p_data->memory_replacement; data.file_replacement = p_data->file_replacement; data.event_replacement = p_data->event_replacement; @@ -159,18 +142,15 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data, return ORBIS_OK; } -bool PS4_SYSV_ABI sceAvPlayerIsActive(SceAvPlayerHandle handle) { +bool PS4_SYSV_ABI sceAvPlayerIsActive(AvPlayerHandle handle) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { - LOG_TRACE(Lib_AvPlayer, "returning false"); return false; } - const auto res = handle->IsActive(); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->IsActive(); } -s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(SceAvPlayerHandle handle, uint64_t time) { +s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called, time (msec) = {}", time); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -178,7 +158,7 @@ s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(SceAvPlayerHandle handle, uint64_t time) return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerPause(SceAvPlayerHandle handle) { +s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -186,14 +166,12 @@ s32 PS4_SYSV_ABI sceAvPlayerPause(SceAvPlayerHandle handle) { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerPostInit(SceAvPlayerHandle handle, SceAvPlayerPostInitData* data) { +s32 PS4_SYSV_ABI sceAvPlayerPostInit(AvPlayerHandle handle, AvPlayerPostInitData* data) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || data == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->PostInit(*data); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->PostInit(*data); } s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) { @@ -201,7 +179,7 @@ s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerResume(SceAvPlayerHandle handle) { +s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -209,8 +187,7 @@ s32 PS4_SYSV_ABI sceAvPlayerResume(SceAvPlayerHandle handle) { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(SceAvPlayerHandle handle, - SceAvPlayerAvSyncMode sync_mode) { +s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -218,12 +195,12 @@ s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(SceAvPlayerHandle handle, return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(SceAvPlayerLogCallback log_cb, void* user_data) { +s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(AvPlayerLogCallback log_cb, void* user_data) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerSetLooping(SceAvPlayerHandle handle, bool loop_flag) { +s32 PS4_SYSV_ABI sceAvPlayerSetLooping(AvPlayerHandle handle, bool loop_flag) { LOG_TRACE(Lib_AvPlayer, "called, looping = {}", loop_flag); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -234,7 +211,7 @@ s32 PS4_SYSV_ABI sceAvPlayerSetLooping(SceAvPlayerHandle handle, bool loop_flag) return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(SceAvPlayerHandle handle, s32 trick_speed) { +s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(AvPlayerHandle handle, s32 trick_speed) { LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; @@ -242,35 +219,28 @@ s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(SceAvPlayerHandle handle, s32 trick_sp return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAvPlayerStart(SceAvPlayerHandle handle) { +s32 PS4_SYSV_ABI sceAvPlayerStart(AvPlayerHandle handle) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->Start(); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->Start(); } -s32 PS4_SYSV_ABI sceAvPlayerStop(SceAvPlayerHandle handle) { +s32 PS4_SYSV_ABI sceAvPlayerStop(AvPlayerHandle handle) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { - LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS"); return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->Stop(); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->Stop(); } -s32 PS4_SYSV_ABI sceAvPlayerStreamCount(SceAvPlayerHandle handle) { +s32 PS4_SYSV_ABI sceAvPlayerStreamCount(AvPlayerHandle handle) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - const auto res = handle->GetStreamCount(); - LOG_TRACE(Lib_AvPlayer, "returning {}", res); - return res; + return handle->GetStreamCount(); } s32 PS4_SYSV_ABI sceAvPlayerVprintf(const char* format, va_list args) { diff --git a/src/core/libraries/avplayer/avplayer.h b/src/core/libraries/avplayer/avplayer.h index 2d472f801..2312acaec 100644 --- a/src/core/libraries/avplayer/avplayer.h +++ b/src/core/libraries/avplayer/avplayer.h @@ -16,38 +16,38 @@ namespace Libraries::AvPlayer { class AvPlayer; -using SceAvPlayerHandle = AvPlayer*; +using AvPlayerHandle = AvPlayer*; -enum class SceAvPlayerUriType : u32 { +enum class AvPlayerUriType : u32 { Source = 0, }; -struct SceAvPlayerUri { +struct AvPlayerUri { const char* name; u32 length; }; -enum class SceAvPlayerSourceType { +enum class AvPlayerSourceType { Unknown = 0, FileMp4 = 1, Hls = 8, }; -enum class SceAvPlayerStreamType : u32 { +enum class AvPlayerStreamType : u32 { Video, Audio, TimedText, Unknown, }; -struct SceAvPlayerSourceDetails { - SceAvPlayerUri uri; +struct AvPlayerSourceDetails { + AvPlayerUri uri; u8 reserved1[64]; - SceAvPlayerSourceType source_type; + AvPlayerSourceType source_type; u8 reserved2[44]; }; -struct SceAvPlayerAudio { +struct AvPlayerAudio { u16 channel_count; u8 reserved1[2]; u32 sample_rate; @@ -55,50 +55,50 @@ struct SceAvPlayerAudio { u8 language_code[4]; }; -struct SceAvPlayerVideo { +struct AvPlayerVideo { u32 width; u32 height; f32 aspect_ratio; char language_code[4]; }; -struct SceAvPlayerTextPosition { +struct AvPlayerTextPosition { u16 top; u16 left; u16 bottom; u16 right; }; -struct SceAvPlayerTimedText { +struct AvPlayerTimedText { u8 language_code[4]; u16 text_size; u16 font_size; - SceAvPlayerTextPosition position; + AvPlayerTextPosition position; }; -union SceAvPlayerStreamDetails { +union AvPlayerStreamDetails { u8 reserved[16]; - SceAvPlayerAudio audio; - SceAvPlayerVideo video; - SceAvPlayerTimedText subs; + AvPlayerAudio audio; + AvPlayerVideo video; + AvPlayerTimedText subs; }; -struct SceAvPlayerFrameInfo { - u8* pData; +struct AvPlayerFrameInfo { + u8* p_data; u8 reserved[4]; u64 timestamp; - SceAvPlayerStreamDetails details; + AvPlayerStreamDetails details; }; -struct SceAvPlayerStreamInfo { - SceAvPlayerStreamType type; +struct AvPlayerStreamInfo { + AvPlayerStreamType type; u8 reserved[4]; - SceAvPlayerStreamDetails details; + AvPlayerStreamDetails details; u64 duration; u64 start_time; }; -struct SceAvPlayerAudioEx { +struct AvPlayerAudioEx { u16 channel_count; u8 reserved[2]; u32 sample_rate; @@ -107,7 +107,7 @@ struct SceAvPlayerAudioEx { u8 reserved1[64]; }; -struct SceAvPlayerVideoEx { +struct AvPlayerVideoEx { u32 width; u32 height; f32 aspect_ratio; @@ -124,53 +124,53 @@ struct SceAvPlayerVideoEx { u8 reserved1[37]; }; -struct SceAvPlayerTimedTextEx { +struct AvPlayerTimedTextEx { u8 language_code[4]; u8 reserved[12]; u8 reserved1[64]; }; -union SceAvPlayerStreamDetailsEx { - SceAvPlayerAudioEx audio; - SceAvPlayerVideoEx video; - SceAvPlayerTimedTextEx subs; +union AvPlayerStreamDetailsEx { + AvPlayerAudioEx audio; + AvPlayerVideoEx video; + AvPlayerTimedTextEx subs; u8 reserved1[80]; }; -struct SceAvPlayerFrameInfoEx { - void* pData; +struct AvPlayerFrameInfoEx { + void* p_data; u8 reserved[4]; u64 timestamp; - SceAvPlayerStreamDetailsEx details; + AvPlayerStreamDetailsEx details; }; -using SceAvPlayerAllocate = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size); -using SceAvPlayerDeallocate = void PS4_SYSV_ABI (*)(void* p, void* mem); -using SceAvPlayerAllocateTexture = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size); -using SceAvPlayerDeallocateTexture = void PS4_SYSV_ABI (*)(void* p, void* mem); +using AvPlayerAllocate = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size); +using AvPlayerDeallocate = void PS4_SYSV_ABI (*)(void* p, void* mem); +using AvPlayerAllocateTexture = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size); +using AvPlayerDeallocateTexture = void PS4_SYSV_ABI (*)(void* p, void* mem); -struct SceAvPlayerMemAllocator { +struct AvPlayerMemAllocator { void* object_ptr; - SceAvPlayerAllocate allocate; - SceAvPlayerDeallocate deallocate; - SceAvPlayerAllocateTexture allocate_texture; - SceAvPlayerDeallocateTexture deallocate_texture; + AvPlayerAllocate allocate; + AvPlayerDeallocate deallocate; + AvPlayerAllocateTexture allocate_texture; + AvPlayerDeallocateTexture deallocate_texture; }; -using SceAvPlayerOpenFile = s32 PS4_SYSV_ABI (*)(void* p, const char* name); -using SceAvPlayerCloseFile = s32 PS4_SYSV_ABI (*)(void* p); -using SceAvPlayerReadOffsetFile = s32 PS4_SYSV_ABI (*)(void* p, u8* buf, u64 pos, u32 len); -using SceAvPlayerSizeFile = u64 PS4_SYSV_ABI (*)(void* p); +using AvPlayerOpenFile = s32 PS4_SYSV_ABI (*)(void* p, const char* name); +using AvPlayerCloseFile = s32 PS4_SYSV_ABI (*)(void* p); +using AvPlayerReadOffsetFile = s32 PS4_SYSV_ABI (*)(void* p, u8* buf, u64 pos, u32 len); +using AvPlayerSizeFile = u64 PS4_SYSV_ABI (*)(void* p); -struct SceAvPlayerFileReplacement { +struct AvPlayerFileReplacement { void* object_ptr; - SceAvPlayerOpenFile open; - SceAvPlayerCloseFile close; - SceAvPlayerReadOffsetFile readOffset; - SceAvPlayerSizeFile size; + AvPlayerOpenFile open; + AvPlayerCloseFile close; + AvPlayerReadOffsetFile read_offset; + AvPlayerSizeFile size; }; -enum class SceAvPlayerEvents { +enum class AvPlayerEvents { StateStop = 0x01, StateReady = 0x02, StatePlay = 0x03, @@ -182,26 +182,26 @@ enum class SceAvPlayerEvents { DrmError = 0x40, }; -using SceAvPlayerEventCallback = void PS4_SYSV_ABI (*)(void* p, SceAvPlayerEvents event, s32 src_id, - void* data); +using AvPlayerEventCallback = void PS4_SYSV_ABI (*)(void* p, AvPlayerEvents event, s32 src_id, + void* data); -struct SceAvPlayerEventReplacement { +struct AvPlayerEventReplacement { void* object_ptr; - SceAvPlayerEventCallback event_callback; + AvPlayerEventCallback event_callback; }; -enum class SceAvPlayerDebuglevels { +enum class AvPlayerDebuglevels { None, Info, Warnings, All, }; -struct SceAvPlayerInitData { - SceAvPlayerMemAllocator memory_replacement; - SceAvPlayerFileReplacement file_replacement; - SceAvPlayerEventReplacement event_replacement; - SceAvPlayerDebuglevels debug_level; +struct AvPlayerInitData { + AvPlayerMemAllocator memory_replacement; + AvPlayerFileReplacement file_replacement; + AvPlayerEventReplacement event_replacement; + AvPlayerDebuglevels debug_level; u32 base_priority; s32 num_output_video_framebuffers; bool auto_start; @@ -209,13 +209,13 @@ struct SceAvPlayerInitData { const char* default_language; }; -struct SceAvPlayerInitDataEx { +struct AvPlayerInitDataEx { size_t this_size; - SceAvPlayerMemAllocator memory_replacement; - SceAvPlayerFileReplacement file_replacement; - SceAvPlayerEventReplacement event_replacement; + AvPlayerMemAllocator memory_replacement; + AvPlayerFileReplacement file_replacement; + AvPlayerEventReplacement event_replacement; const char* default_language; - SceAvPlayerDebuglevels debug_level; + AvPlayerDebuglevels debug_level; u32 audio_decoder_priority; u32 audio_decoder_affinity; u32 video_decoder_priority; @@ -233,25 +233,25 @@ struct SceAvPlayerInitDataEx { u8 reserved[3]; }; -enum class SceAvPlayerVideoDecoderType { +enum class AvPlayerVideoDecoderType { Default = 0, Reserved1, Software, Software2, }; -enum class SceAvPlayerAudioDecoderType { +enum class AvPlayerAudioDecoderType { Default = 0, Reserved1, Reserved2, }; -struct SceAvPlayerDecoderInit { +struct AvPlayerDecoderInit { union { - SceAvPlayerVideoDecoderType video_type; - SceAvPlayerAudioDecoderType audio_type; + AvPlayerVideoDecoderType video_type; + AvPlayerAudioDecoderType audio_type; u8 reserved[4]; - } decoderType; + } decoder_type; union { struct { s32 cpu_affinity_mask; @@ -261,34 +261,34 @@ struct SceAvPlayerDecoderInit { u8 compute_queue_id; u8 enable_interlaced; u8 reserved[16]; - } avcSw2; + } avc_sw2; struct { u8 audio_channel_order; u8 reserved[27]; } aac; u8 reserved[28]; - } decoderParams; + } decoder_params; }; -struct SceAvPlayerHTTPCtx { +struct AvPlayerHTTPCtx { u32 http_context_id; u32 ssl_context_id; }; -struct SceAvPlayerPostInitData { +struct AvPlayerPostInitData { u32 demux_video_buffer_size; - SceAvPlayerDecoderInit video_decoder_init; - SceAvPlayerDecoderInit audio_decoder_init; - SceAvPlayerHTTPCtx http_context; + AvPlayerDecoderInit video_decoder_init; + AvPlayerDecoderInit audio_decoder_init; + AvPlayerHTTPCtx http_context; u8 reserved[56]; }; -enum class SceAvPlayerAvSyncMode { +enum class AvPlayerAvSyncMode { Default = 0, None, }; -using SceAvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args); +using AvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args); void RegisterlibSceAvPlayer(Core::Loader::SymbolsResolver* sym); diff --git a/src/core/libraries/avplayer/avplayer_common.cpp b/src/core/libraries/avplayer/avplayer_common.cpp index 28d7803a1..f42f690ed 100644 --- a/src/core/libraries/avplayer/avplayer_common.cpp +++ b/src/core/libraries/avplayer/avplayer_common.cpp @@ -13,9 +13,9 @@ static bool iequals(std::string_view l, std::string_view r) { return std::ranges::equal(l, r, [](u8 a, u8 b) { return std::tolower(a) == std::tolower(b); }); } -SceAvPlayerSourceType GetSourceType(std::string_view path) { +AvPlayerSourceType GetSourceType(std::string_view path) { if (path.empty()) { - return SceAvPlayerSourceType::Unknown; + return AvPlayerSourceType::Unknown; } std::string_view name = path; @@ -25,14 +25,14 @@ SceAvPlayerSourceType GetSourceType(std::string_view path) { // -> schema://server.domain/path/to/file.ext/and/beyond name = path.substr(0, path.find_first_of("?#")); if (name.empty()) { - return SceAvPlayerSourceType::Unknown; + return AvPlayerSourceType::Unknown; } } // schema://server.domain/path/to/file.ext/and/beyond -> .ext/and/beyond auto ext = name.substr(name.rfind('.')); if (ext.empty()) { - return SceAvPlayerSourceType::Unknown; + return AvPlayerSourceType::Unknown; } // .ext/and/beyond -> .ext @@ -40,14 +40,14 @@ SceAvPlayerSourceType GetSourceType(std::string_view path) { if (iequals(ext, ".mp4") || iequals(ext, ".m4v") || iequals(ext, ".m3d") || iequals(ext, ".m4a") || iequals(ext, ".mov")) { - return SceAvPlayerSourceType::FileMp4; + return AvPlayerSourceType::FileMp4; } if (iequals(ext, ".m3u8")) { - return SceAvPlayerSourceType::Hls; + return AvPlayerSourceType::Hls; } - return SceAvPlayerSourceType::Unknown; + return AvPlayerSourceType::Unknown; } } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_common.h b/src/core/libraries/avplayer/avplayer_common.h index dc3cd787f..eddd10d5e 100644 --- a/src/core/libraries/avplayer/avplayer_common.h +++ b/src/core/libraries/avplayer/avplayer_common.h @@ -84,6 +84,6 @@ private: std::queue m_queue{}; }; -SceAvPlayerSourceType GetSourceType(std::string_view path); +AvPlayerSourceType GetSourceType(std::string_view path); } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_file_streamer.cpp b/src/core/libraries/avplayer/avplayer_file_streamer.cpp index 19faeb273..c610012a5 100644 --- a/src/core/libraries/avplayer/avplayer_file_streamer.cpp +++ b/src/core/libraries/avplayer/avplayer_file_streamer.cpp @@ -14,7 +14,7 @@ constexpr u32 AVPLAYER_AVIO_BUFFER_SIZE = 4096; namespace Libraries::AvPlayer { -AvPlayerFileStreamer::AvPlayerFileStreamer(const SceAvPlayerFileReplacement& file_replacement) +AvPlayerFileStreamer::AvPlayerFileStreamer(const AvPlayerFileReplacement& file_replacement) : m_file_replacement(file_replacement) {} AvPlayerFileStreamer::~AvPlayerFileStreamer() { @@ -51,7 +51,7 @@ s32 AvPlayerFileStreamer::ReadPacket(void* opaque, u8* buffer, s32 size) { if (self->m_position + size > self->m_file_size) { size = self->m_file_size - self->m_position; } - const auto read_offset = self->m_file_replacement.readOffset; + const auto read_offset = self->m_file_replacement.read_offset; const auto ptr = self->m_file_replacement.object_ptr; const auto bytes_read = read_offset(ptr, buffer, self->m_position, size); if (bytes_read == 0 && size != 0) { diff --git a/src/core/libraries/avplayer/avplayer_file_streamer.h b/src/core/libraries/avplayer/avplayer_file_streamer.h index bc096bccc..c0cdb4a07 100644 --- a/src/core/libraries/avplayer/avplayer_file_streamer.h +++ b/src/core/libraries/avplayer/avplayer_file_streamer.h @@ -13,7 +13,7 @@ namespace Libraries::AvPlayer { class AvPlayerFileStreamer : public IDataStreamer { public: - AvPlayerFileStreamer(const SceAvPlayerFileReplacement& file_replacement); + AvPlayerFileStreamer(const AvPlayerFileReplacement& file_replacement); ~AvPlayerFileStreamer(); bool Init(std::string_view path) override; @@ -26,7 +26,7 @@ private: static s32 ReadPacket(void* opaque, u8* buffer, s32 size); static s64 Seek(void* opaque, s64 buffer, int whence); - SceAvPlayerFileReplacement m_file_replacement; + AvPlayerFileReplacement m_file_replacement; int m_fd = -1; u64 m_position{}; diff --git a/src/core/libraries/avplayer/avplayer_impl.cpp b/src/core/libraries/avplayer/avplayer_impl.cpp index d9a67134c..411908ae3 100644 --- a/src/core/libraries/avplayer/avplayer_impl.cpp +++ b/src/core/libraries/avplayer/avplayer_impl.cpp @@ -58,7 +58,7 @@ int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position auto const self = reinterpret_cast(handle); std::lock_guard guard(self->m_file_io_mutex); - const auto read_offset = self->m_init_data_original.file_replacement.readOffset; + const auto read_offset = self->m_init_data_original.file_replacement.read_offset; const auto ptr = self->m_init_data_original.file_replacement.object_ptr; return Core::ExecuteGuest(read_offset, ptr, buffer, position, length); } @@ -72,38 +72,46 @@ u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) { return Core::ExecuteGuest(size, ptr); } -SceAvPlayerInitData AvPlayer::StubInitData(const SceAvPlayerInitData& data) { - SceAvPlayerInitData result = data; +AvPlayerInitData AvPlayer::StubInitData(const AvPlayerInitData& data) { + AvPlayerInitData result = data; result.memory_replacement.object_ptr = this; result.memory_replacement.allocate = &AvPlayer::Allocate; result.memory_replacement.deallocate = &AvPlayer::Deallocate; result.memory_replacement.allocate_texture = &AvPlayer::AllocateTexture; result.memory_replacement.deallocate_texture = &AvPlayer::DeallocateTexture; if (data.file_replacement.open == nullptr || data.file_replacement.close == nullptr || - data.file_replacement.readOffset == nullptr || data.file_replacement.size == nullptr) { + data.file_replacement.read_offset == nullptr || data.file_replacement.size == nullptr) { result.file_replacement = {}; } else { result.file_replacement.object_ptr = this; result.file_replacement.open = &AvPlayer::OpenFile; result.file_replacement.close = &AvPlayer::CloseFile; - result.file_replacement.readOffset = &AvPlayer::ReadOffsetFile; + result.file_replacement.read_offset = &AvPlayer::ReadOffsetFile; result.file_replacement.size = &AvPlayer::SizeFile; } return result; } -AvPlayer::AvPlayer(const SceAvPlayerInitData& data) +AvPlayer::AvPlayer(const AvPlayerInitData& data) : m_init_data(StubInitData(data)), m_init_data_original(data), m_state(std::make_unique(m_init_data)) {} -s32 AvPlayer::PostInit(const SceAvPlayerPostInitData& data) { +s32 AvPlayer::PostInit(const AvPlayerPostInitData& data) { m_state->PostInit(data); return ORBIS_OK; } s32 AvPlayer::AddSource(std::string_view path) { - if (path.empty()) { - return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; + return AddSourceEx(path, AvPlayerSourceType::Unknown); +} + +s32 AvPlayer::AddSourceEx(std::string_view path, AvPlayerSourceType source_type) { + if (source_type == AvPlayerSourceType::Unknown) { + source_type = GetSourceType(path); + } + if (source_type == AvPlayerSourceType::Hls) { + LOG_ERROR(Lib_AvPlayer, "HTTP Live Streaming is not implemented"); + return ORBIS_AVPLAYER_ERROR_NOT_SUPPORTED; } if (!m_state->AddSource(path, GetSourceType(path))) { return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; @@ -122,7 +130,7 @@ s32 AvPlayer::GetStreamCount() { return res; } -s32 AvPlayer::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { +s32 AvPlayer::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { if (!m_state->GetStreamInfo(stream_index, info)) { return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; } @@ -146,21 +154,21 @@ s32 AvPlayer::Start() { return ORBIS_OK; } -bool AvPlayer::GetVideoData(SceAvPlayerFrameInfo& video_info) { +bool AvPlayer::GetVideoData(AvPlayerFrameInfo& video_info) { if (m_state == nullptr) { return false; } return m_state->GetVideoData(video_info); } -bool AvPlayer::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { +bool AvPlayer::GetVideoData(AvPlayerFrameInfoEx& video_info) { if (m_state == nullptr) { return false; } return m_state->GetVideoData(video_info); } -bool AvPlayer::GetAudioData(SceAvPlayerFrameInfo& audio_info) { +bool AvPlayer::GetAudioData(AvPlayerFrameInfo& audio_info) { if (m_state == nullptr) { return false; } diff --git a/src/core/libraries/avplayer/avplayer_impl.h b/src/core/libraries/avplayer/avplayer_impl.h index 984d81499..7033e191c 100644 --- a/src/core/libraries/avplayer/avplayer_impl.h +++ b/src/core/libraries/avplayer/avplayer_impl.h @@ -19,17 +19,18 @@ namespace Libraries::AvPlayer { class AvPlayer { public: - AvPlayer(const SceAvPlayerInitData& data); + AvPlayer(const AvPlayerInitData& data); - s32 PostInit(const SceAvPlayerPostInitData& data); + s32 PostInit(const AvPlayerPostInitData& data); s32 AddSource(std::string_view filename); + s32 AddSourceEx(std::string_view path, AvPlayerSourceType source_type); s32 GetStreamCount(); - s32 GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); + s32 GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); s32 EnableStream(u32 stream_index); s32 Start(); - bool GetAudioData(SceAvPlayerFrameInfo& audio_info); - bool GetVideoData(SceAvPlayerFrameInfo& video_info); - bool GetVideoData(SceAvPlayerFrameInfoEx& video_info); + bool GetAudioData(AvPlayerFrameInfo& audio_info); + bool GetVideoData(AvPlayerFrameInfo& video_info); + bool GetVideoData(AvPlayerFrameInfoEx& video_info); bool IsActive(); u64 CurrentTime(); s32 Stop(); @@ -48,10 +49,10 @@ private: static int PS4_SYSV_ABI ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length); static u64 PS4_SYSV_ABI SizeFile(void* handle); - SceAvPlayerInitData StubInitData(const SceAvPlayerInitData& data); + AvPlayerInitData StubInitData(const AvPlayerInitData& data); - SceAvPlayerInitData m_init_data{}; - SceAvPlayerInitData m_init_data_original{}; + AvPlayerInitData m_init_data{}; + AvPlayerInitData m_init_data_original{}; std::mutex m_file_io_mutex{}; std::atomic_bool m_has_source{}; diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index cf783403c..cc90a1a49 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -29,7 +29,7 @@ AvPlayerSource::~AvPlayerSource() { Stop(); } -bool AvPlayerSource::Init(const SceAvPlayerInitData& init_data, std::string_view path) { +bool AvPlayerSource::Init(const AvPlayerInitData& init_data, std::string_view path) { m_memory_replacement = init_data.memory_replacement, m_num_output_video_framebuffers = std::min(std::max(2, init_data.num_output_video_framebuffers), 16); @@ -76,17 +76,17 @@ s32 AvPlayerSource::GetStreamCount() { return m_avformat_context->nb_streams; } -static SceAvPlayerStreamType CodecTypeToStreamType(AVMediaType codec_type) { +static AvPlayerStreamType CodecTypeToStreamType(AVMediaType codec_type) { switch (codec_type) { case AVMediaType::AVMEDIA_TYPE_VIDEO: - return SceAvPlayerStreamType::Video; + return AvPlayerStreamType::Video; case AVMediaType::AVMEDIA_TYPE_AUDIO: - return SceAvPlayerStreamType::Audio; + return AvPlayerStreamType::Audio; case AVMediaType::AVMEDIA_TYPE_SUBTITLE: - return SceAvPlayerStreamType::TimedText; + return AvPlayerStreamType::TimedText; default: LOG_ERROR(Lib_AvPlayer, "Unexpected AVMediaType {}", magic_enum::enum_name(codec_type)); - return SceAvPlayerStreamType::Unknown; + return AvPlayerStreamType::Unknown; } } @@ -94,7 +94,7 @@ static f32 AVRationalToF32(const AVRational rational) { return f32(rational.num) / rational.den; } -bool AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { +bool AvPlayerSource::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { info = {}; if (m_avformat_context == nullptr || stream_index >= m_avformat_context->nb_streams) { LOG_ERROR(Lib_AvPlayer, "Could not get stream {} info.", stream_index); @@ -115,7 +115,7 @@ bool AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info LOG_WARNING(Lib_AvPlayer, "Stream {} language is unknown", stream_index); } switch (info.type) { - case SceAvPlayerStreamType::Video: { + case AvPlayerStreamType::Video: { LOG_INFO(Lib_AvPlayer, "Stream {} is a video stream.", stream_index); info.details.video.aspect_ratio = f32(p_stream->codecpar->width) / p_stream->codecpar->height; @@ -133,7 +133,7 @@ bool AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info } break; } - case SceAvPlayerStreamType::Audio: { + case AvPlayerStreamType::Audio: { LOG_INFO(Lib_AvPlayer, "Stream {} is an audio stream.", stream_index); info.details.audio.channel_count = p_stream->codecpar->ch_layout.nb_channels; info.details.audio.sample_rate = p_stream->codecpar->sample_rate; @@ -144,7 +144,7 @@ bool AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info } break; } - case SceAvPlayerStreamType::TimedText: { + case AvPlayerStreamType::TimedText: { LOG_WARNING(Lib_AvPlayer, "Stream {} is a timedtext stream.", stream_index); info.details.subs.font_size = 12; info.details.subs.text_size = 12; @@ -280,25 +280,25 @@ bool AvPlayerSource::Stop() { return true; } -bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfo& video_info) { +bool AvPlayerSource::GetVideoData(AvPlayerFrameInfo& video_info) { if (!IsActive()) { return false; } - SceAvPlayerFrameInfoEx info{}; + AvPlayerFrameInfoEx info{}; if (!GetVideoData(info)) { return false; } video_info = {}; video_info.timestamp = u64(info.timestamp); - video_info.pData = reinterpret_cast(info.pData); + video_info.p_data = reinterpret_cast(info.p_data); video_info.details.video.aspect_ratio = info.details.video.aspect_ratio; video_info.details.video.width = info.details.video.width; video_info.details.video.height = info.details.video.height; return true; } -bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { +bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { if (!IsActive()) { return false; } @@ -333,7 +333,7 @@ bool AvPlayerSource::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { return true; } -bool AvPlayerSource::GetAudioData(SceAvPlayerFrameInfo& audio_info) { +bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { if (!IsActive()) { return false; } @@ -367,7 +367,7 @@ bool AvPlayerSource::GetAudioData(SceAvPlayerFrameInfo& audio_info) { audio_info = {}; audio_info.timestamp = frame->info.timestamp; - audio_info.pData = reinterpret_cast(frame->info.pData); + audio_info.p_data = reinterpret_cast(frame->info.p_data); audio_info.details.audio.sample_rate = frame->info.details.audio.sample_rate; audio_info.details.audio.size = frame->info.details.audio.size; audio_info.details.audio.channel_count = frame->info.details.audio.channel_count; @@ -572,7 +572,7 @@ Frame AvPlayerSource::PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame .buffer = std::move(buffer), .info = { - .pData = p_buffer, + .p_data = p_buffer, .timestamp = timestamp, .details = { @@ -702,7 +702,7 @@ Frame AvPlayerSource::PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame .buffer = std::move(buffer), .info = { - .pData = p_buffer, + .p_data = p_buffer, .timestamp = timestamp, .details = { diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index 7e199c457..6d0590545 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -37,7 +37,7 @@ public: class FrameBuffer { public: - FrameBuffer(const SceAvPlayerMemAllocator& memory_replacement, u32 align, u32 size) noexcept + FrameBuffer(const AvPlayerMemAllocator& memory_replacement, u32 align, u32 size) noexcept : m_memory_replacement(memory_replacement), m_data(Allocate(memory_replacement, align, size)) { ASSERT_MSG(m_data, "Could not allocated frame buffer."); @@ -68,22 +68,22 @@ public: } private: - static u8* Allocate(const SceAvPlayerMemAllocator& memory_replacement, u32 align, u32 size) { + static u8* Allocate(const AvPlayerMemAllocator& memory_replacement, u32 align, u32 size) { return reinterpret_cast( memory_replacement.allocate(memory_replacement.object_ptr, align, size)); } - static void Deallocate(const SceAvPlayerMemAllocator& memory_replacement, void* ptr) { + static void Deallocate(const AvPlayerMemAllocator& memory_replacement, void* ptr) { memory_replacement.deallocate(memory_replacement.object_ptr, ptr); } - const SceAvPlayerMemAllocator& m_memory_replacement; + const AvPlayerMemAllocator& m_memory_replacement; u8* m_data = nullptr; }; struct Frame { FrameBuffer buffer; - SceAvPlayerFrameInfoEx info; + AvPlayerFrameInfoEx info; }; class EventCV { @@ -121,18 +121,18 @@ public: AvPlayerSource(AvPlayerStateCallback& state, bool use_vdec2); ~AvPlayerSource(); - bool Init(const SceAvPlayerInitData& init_data, std::string_view path); + bool Init(const AvPlayerInitData& init_data, std::string_view path); bool FindStreamInfo(); s32 GetStreamCount(); - bool GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); + bool GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); bool EnableStream(u32 stream_index); void SetLooping(bool is_looping); std::optional HasFrames(u32 num_frames); bool Start(); bool Stop(); - bool GetAudioData(SceAvPlayerFrameInfo& audio_info); - bool GetVideoData(SceAvPlayerFrameInfo& video_info); - bool GetVideoData(SceAvPlayerFrameInfoEx& video_info); + bool GetAudioData(AvPlayerFrameInfo& audio_info); + bool GetVideoData(AvPlayerFrameInfo& video_info); + bool GetVideoData(AvPlayerFrameInfoEx& video_info); u64 CurrentTime(); bool IsActive(); @@ -166,7 +166,7 @@ private: AvPlayerStateCallback& m_state; bool m_use_vdec2 = false; - SceAvPlayerMemAllocator m_memory_replacement{}; + AvPlayerMemAllocator m_memory_replacement{}; u32 m_num_output_video_framebuffers{}; std::atomic_bool m_is_looping = false; diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index 143df749c..e6885ea2d 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -12,11 +12,11 @@ namespace Libraries::AvPlayer { -void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayerEvents event_id, +void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, AvPlayerEvents event_id, s32 source_id, void* event_data) { auto const self = reinterpret_cast(opaque); - if (event_id == SceAvPlayerEvents::StateReady) { + if (event_id == AvPlayerEvents::StateReady) { s32 video_stream_index = -1; s32 audio_stream_index = -1; s32 timedtext_stream_index = -1; @@ -30,7 +30,7 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayer return; } for (u32 stream_index = 0; stream_index < stream_count; ++stream_index) { - SceAvPlayerStreamInfo info{}; + AvPlayerStreamInfo info{}; if (!self->GetStreamInfo(stream_index, info)) { self->Stop(); return; @@ -38,7 +38,7 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayer const std::string_view default_language{self->m_default_language}; switch (info.type) { - case SceAvPlayerStreamType::Video: + case AvPlayerStreamType::Video: if (video_stream_index == -1) { video_stream_index = stream_index; } @@ -47,7 +47,7 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayer video_stream_index = stream_index; } break; - case SceAvPlayerStreamType::Audio: + case AvPlayerStreamType::Audio: if (audio_stream_index == -1) { audio_stream_index = stream_index; } @@ -56,7 +56,7 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayer audio_stream_index = stream_index; } break; - case SceAvPlayerStreamType::TimedText: + case AvPlayerStreamType::TimedText: if (default_language.empty()) { timedtext_stream_index = stream_index; break; @@ -86,7 +86,7 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayer DefaultEventCallback(opaque, event_id, 0, event_data); } -void AvPlayerState::DefaultEventCallback(void* opaque, SceAvPlayerEvents event_id, s32 source_id, +void AvPlayerState::DefaultEventCallback(void* opaque, AvPlayerEvents event_id, s32 source_id, void* event_data) { auto const self = reinterpret_cast(opaque); const auto callback = self->m_event_replacement.event_callback; @@ -97,7 +97,7 @@ void AvPlayerState::DefaultEventCallback(void* opaque, SceAvPlayerEvents event_i } // Called inside GAME thread -AvPlayerState::AvPlayerState(const SceAvPlayerInitData& init_data) +AvPlayerState::AvPlayerState(const AvPlayerInitData& init_data) : m_init_data(init_data), m_event_replacement(init_data.event_replacement) { if (m_event_replacement.event_callback == nullptr || init_data.auto_start) { m_auto_start = true; @@ -122,12 +122,12 @@ AvPlayerState::~AvPlayerState() { m_event_queue.Clear(); } -void AvPlayerState::PostInit(const SceAvPlayerPostInitData& post_init_data) { +void AvPlayerState::PostInit(const AvPlayerPostInitData& post_init_data) { m_post_init_data = post_init_data; } // Called inside GAME thread -bool AvPlayerState::AddSource(std::string_view path, SceAvPlayerSourceType source_type) { +bool AvPlayerState::AddSource(std::string_view path, AvPlayerSourceType source_type) { if (path.empty()) { LOG_ERROR(Lib_AvPlayer, "File path is empty."); return false; @@ -141,8 +141,8 @@ bool AvPlayerState::AddSource(std::string_view path, SceAvPlayerSourceType sourc } m_up_source = std::make_unique( - *this, m_post_init_data.video_decoder_init.decoderType.video_type == - SceAvPlayerVideoDecoderType::Software2); + *this, m_post_init_data.video_decoder_init.decoder_type.video_type == + AvPlayerVideoDecoderType::Software2); if (!m_up_source->Init(m_init_data, path)) { SetState(AvState::Error); m_up_source.reset(); @@ -164,7 +164,7 @@ s32 AvPlayerState::GetStreamCount() { } // Called inside GAME thread -bool AvPlayerState::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { +bool AvPlayerState::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr) { LOG_ERROR(Lib_AvPlayer, "Could not get stream {} info. No source.", stream_index); @@ -247,7 +247,7 @@ bool AvPlayerState::Stop() { return true; } -bool AvPlayerState::GetVideoData(SceAvPlayerFrameInfo& video_info) { +bool AvPlayerState::GetVideoData(AvPlayerFrameInfo& video_info) { std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr) { return false; @@ -255,7 +255,7 @@ bool AvPlayerState::GetVideoData(SceAvPlayerFrameInfo& video_info) { return m_up_source->GetVideoData(video_info); } -bool AvPlayerState::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { +bool AvPlayerState::GetVideoData(AvPlayerFrameInfoEx& video_info) { std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr) { return false; @@ -263,7 +263,7 @@ bool AvPlayerState::GetVideoData(SceAvPlayerFrameInfoEx& video_info) { return m_up_source->GetVideoData(video_info); } -bool AvPlayerState::GetAudioData(SceAvPlayerFrameInfo& audio_info) { +bool AvPlayerState::GetAudioData(AvPlayerFrameInfo& audio_info) { std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr) { return false; @@ -318,23 +318,23 @@ void AvPlayerState::OnEOF() { void AvPlayerState::OnPlaybackStateChanged(AvState state) { switch (state) { case AvState::Ready: { - EmitEvent(SceAvPlayerEvents::StateReady); + EmitEvent(AvPlayerEvents::StateReady); break; } case AvState::Play: { - EmitEvent(SceAvPlayerEvents::StatePlay); + EmitEvent(AvPlayerEvents::StatePlay); break; } case AvState::Stop: { - EmitEvent(SceAvPlayerEvents::StateStop); + EmitEvent(AvPlayerEvents::StateStop); break; } case AvState::Pause: { - EmitEvent(SceAvPlayerEvents::StatePause); + EmitEvent(AvPlayerEvents::StatePause); break; } case AvState::Buffering: { - EmitEvent(SceAvPlayerEvents::StateBuffering); + EmitEvent(AvPlayerEvents::StateBuffering); break; } default: @@ -366,7 +366,7 @@ std::optional AvPlayerState::OnBufferingCheckEvent(u32 num_frames) { } // Called inside CONTROLLER thread -void AvPlayerState::EmitEvent(SceAvPlayerEvents event_id, void* event_data) { +void AvPlayerState::EmitEvent(AvPlayerEvents event_id, void* event_data) { LOG_INFO(Lib_AvPlayer, "Sending event to the game: id = {}", magic_enum::enum_name(event_id)); const auto callback = m_init_data.event_replacement.event_callback; if (callback) { diff --git a/src/core/libraries/avplayer/avplayer_state.h b/src/core/libraries/avplayer/avplayer_state.h index 48cd17bf2..139c5aa8b 100644 --- a/src/core/libraries/avplayer/avplayer_state.h +++ b/src/core/libraries/avplayer/avplayer_state.h @@ -18,29 +18,29 @@ class AvDecoder; class AvPlayerState : public AvPlayerStateCallback { public: - AvPlayerState(const SceAvPlayerInitData& init_data); + AvPlayerState(const AvPlayerInitData& init_data); ~AvPlayerState(); - void PostInit(const SceAvPlayerPostInitData& post_init_data); - bool AddSource(std::string_view filename, SceAvPlayerSourceType source_type); + void PostInit(const AvPlayerPostInitData& post_init_data); + bool AddSource(std::string_view filename, AvPlayerSourceType source_type); s32 GetStreamCount(); - bool GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); + bool GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); bool EnableStream(u32 stream_index); bool Start(); bool Stop(); - bool GetAudioData(SceAvPlayerFrameInfo& audio_info); - bool GetVideoData(SceAvPlayerFrameInfo& video_info); - bool GetVideoData(SceAvPlayerFrameInfoEx& video_info); + bool GetAudioData(AvPlayerFrameInfo& audio_info); + bool GetVideoData(AvPlayerFrameInfo& video_info); + bool GetVideoData(AvPlayerFrameInfoEx& video_info); bool IsActive(); u64 CurrentTime(); bool SetLooping(bool is_looping); private: // Event Replacement - static void PS4_SYSV_ABI AutoPlayEventCallback(void* handle, SceAvPlayerEvents event_id, + static void PS4_SYSV_ABI AutoPlayEventCallback(void* handle, AvPlayerEvents event_id, s32 source_id, void* event_data); - static void PS4_SYSV_ABI DefaultEventCallback(void* handle, SceAvPlayerEvents event_id, + static void PS4_SYSV_ABI DefaultEventCallback(void* handle, AvPlayerEvents event_id, s32 source_id, void* event_data); void OnWarning(u32 id) override; @@ -50,7 +50,7 @@ private: void OnPlaybackStateChanged(AvState state); std::optional OnBufferingCheckEvent(u32 num_frames); - void EmitEvent(SceAvPlayerEvents event_id, void* event_data = nullptr); + void EmitEvent(AvPlayerEvents event_id, void* event_data = nullptr); bool SetState(AvState state); void AvControllerThread(std::stop_token stop); @@ -65,9 +65,9 @@ private: std::unique_ptr m_up_source; - SceAvPlayerInitData m_init_data{}; - SceAvPlayerPostInitData m_post_init_data{}; - SceAvPlayerEventReplacement m_event_replacement{}; + AvPlayerInitData m_init_data{}; + AvPlayerPostInitData m_post_init_data{}; + AvPlayerEventReplacement m_event_replacement{}; bool m_auto_start{}; char m_default_language[4]{}; From c39179a5f4e5efffde29b0f50459c83376c60dfd Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sun, 16 Feb 2025 12:07:48 +0300 Subject: [PATCH 2/9] avplayer: implemented pause/resume --- src/core/libraries/avplayer/avplayer.cpp | 8 ++--- src/core/libraries/avplayer/avplayer_common.h | 1 + src/core/libraries/avplayer/avplayer_impl.cpp | 16 +++++++++- src/core/libraries/avplayer/avplayer_impl.h | 2 ++ .../libraries/avplayer/avplayer_source.cpp | 23 +++++++++---- src/core/libraries/avplayer/avplayer_source.h | 5 +++ .../libraries/avplayer/avplayer_state.cpp | 32 +++++++++++++++++++ src/core/libraries/avplayer/avplayer_state.h | 2 ++ 8 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index c58bf42e1..73d0b13c0 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -159,11 +159,11 @@ s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) { } s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) { - LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - return ORBIS_OK; + return handle->Pause(); } 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) { - LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - return ORBIS_OK; + return handle->Resume(); } s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) { diff --git a/src/core/libraries/avplayer/avplayer_common.h b/src/core/libraries/avplayer/avplayer_common.h index eddd10d5e..2c5f4ec13 100644 --- a/src/core/libraries/avplayer/avplayer_common.h +++ b/src/core/libraries/avplayer/avplayer_common.h @@ -16,6 +16,7 @@ namespace Libraries::AvPlayer { enum class AvState { + Unknown, Initial, AddingSource, Ready, diff --git a/src/core/libraries/avplayer/avplayer_impl.cpp b/src/core/libraries/avplayer/avplayer_impl.cpp index 411908ae3..6d7c8cc3e 100644 --- a/src/core/libraries/avplayer/avplayer_impl.cpp +++ b/src/core/libraries/avplayer/avplayer_impl.cpp @@ -148,7 +148,21 @@ s32 AvPlayer::EnableStream(u32 stream_index) { } 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_OK; diff --git a/src/core/libraries/avplayer/avplayer_impl.h b/src/core/libraries/avplayer/avplayer_impl.h index 7033e191c..a2812ee0b 100644 --- a/src/core/libraries/avplayer/avplayer_impl.h +++ b/src/core/libraries/avplayer/avplayer_impl.h @@ -28,6 +28,8 @@ public: s32 GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); s32 EnableStream(u32 stream_index); s32 Start(); + s32 Pause(); + s32 Resume(); bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info); diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index cc90a1a49..651353a11 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -280,6 +280,16 @@ bool AvPlayerSource::Stop() { 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) { if (!IsActive()) { return false; @@ -299,7 +309,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfo& video_info) { } bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { - if (!IsActive()) { + if (!IsActive() || m_is_paused) { return false; } @@ -313,8 +323,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { { using namespace std::chrono; - auto elapsed_time = - duration_cast(high_resolution_clock::now() - m_start_time).count(); + auto elapsed_time = CurrentTime(); if (elapsed_time < frame->info.timestamp) { if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time), [&] { return elapsed_time >= frame->info.timestamp; })) { @@ -334,7 +343,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { } bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { - if (!IsActive()) { + if (!IsActive() || m_is_paused) { return false; } @@ -348,8 +357,7 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { { using namespace std::chrono; - auto elapsed_time = - duration_cast(high_resolution_clock::now() - m_start_time).count(); + auto elapsed_time = CurrentTime(); if (elapsed_time < frame->info.timestamp) { if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time), [&] { return elapsed_time >= frame->info.timestamp; })) { @@ -379,7 +387,8 @@ u64 AvPlayerSource::CurrentTime() { return 0; } using namespace std::chrono; - return duration_cast(high_resolution_clock::now() - m_start_time).count(); + return duration_cast(high_resolution_clock::now() - m_start_time - m_stalled_time) + .count(); } bool AvPlayerSource::IsActive() { diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index 6d0590545..67e7a639a 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -130,6 +130,8 @@ public: std::optional HasFrames(u32 num_frames); bool Start(); bool Stop(); + void Pause(); + void Resume(); bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info); @@ -170,6 +172,7 @@ private: u32 m_num_output_video_framebuffers{}; std::atomic_bool m_is_looping = false; + std::atomic_bool m_is_paused = false; std::atomic_bool m_is_eof = false; std::unique_ptr m_up_data_streamer; @@ -211,6 +214,8 @@ private: SWSContextPtr m_sws_context{nullptr, &ReleaseSWSContext}; 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 diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index e6885ea2d..aa66d690e 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -185,6 +185,38 @@ bool AvPlayerState::Start() { 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) { using std::chrono::milliseconds; Common::SetCurrentThreadName("shadPS4:AvController"); diff --git a/src/core/libraries/avplayer/avplayer_state.h b/src/core/libraries/avplayer/avplayer_state.h index 139c5aa8b..93f0e0a89 100644 --- a/src/core/libraries/avplayer/avplayer_state.h +++ b/src/core/libraries/avplayer/avplayer_state.h @@ -28,6 +28,8 @@ public: bool EnableStream(u32 stream_index); bool Start(); bool Stop(); + bool Pause(); + bool Resume(); bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info); From 8162bc2af13bc155a462e2bbd537a2a16470f4f5 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sun, 16 Feb 2025 16:52:20 +0300 Subject: [PATCH 3/9] avplayer: implemented sync modes --- src/core/libraries/avplayer/avplayer.cpp | 4 +-- src/core/libraries/avplayer/avplayer_impl.cpp | 8 ++++++ src/core/libraries/avplayer/avplayer_impl.h | 1 + .../libraries/avplayer/avplayer_source.cpp | 28 ++++++++----------- src/core/libraries/avplayer/avplayer_source.h | 3 ++ .../libraries/avplayer/avplayer_state.cpp | 8 ++++++ src/core/libraries/avplayer/avplayer_state.h | 3 ++ 7 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index 73d0b13c0..2495db9e6 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -188,11 +188,11 @@ s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) { } s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) { - LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - return ORBIS_OK; + return handle->SetAvSyncMode(sync_mode); } s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(AvPlayerLogCallback log_cb, void* user_data) { diff --git a/src/core/libraries/avplayer/avplayer_impl.cpp b/src/core/libraries/avplayer/avplayer_impl.cpp index 6d7c8cc3e..138747da4 100644 --- a/src/core/libraries/avplayer/avplayer_impl.cpp +++ b/src/core/libraries/avplayer/avplayer_impl.cpp @@ -168,6 +168,14 @@ s32 AvPlayer::Resume() { return ORBIS_OK; } +s32 AvPlayer::SetAvSyncMode(AvPlayerAvSyncMode sync_mode) { + if (m_state == nullptr) { + return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; + } + m_state->SetAvSyncMode(sync_mode); + return ORBIS_OK; +} + bool AvPlayer::GetVideoData(AvPlayerFrameInfo& video_info) { if (m_state == nullptr) { return false; diff --git a/src/core/libraries/avplayer/avplayer_impl.h b/src/core/libraries/avplayer/avplayer_impl.h index a2812ee0b..7e4aec43c 100644 --- a/src/core/libraries/avplayer/avplayer_impl.h +++ b/src/core/libraries/avplayer/avplayer_impl.h @@ -30,6 +30,7 @@ public: s32 Start(); s32 Pause(); s32 Resume(); + s32 SetAvSyncMode(AvPlayerAvSyncMode sync_mode); bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info); diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index 651353a11..480df3011 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -321,12 +321,16 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { return false; } - { - using namespace std::chrono; - auto elapsed_time = CurrentTime(); - if (elapsed_time < frame->info.timestamp) { - if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time), - [&] { return elapsed_time >= frame->info.timestamp; })) { + if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default && m_audio_stream_index.has_value()) { + const auto audio_ts = m_last_audio_packet_time; + if (audio_ts < frame->info.timestamp) { + using namespace std::chrono; + const auto start = high_resolution_clock::now(); + if (!m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - audio_ts), [&] { + const auto passed = + duration_cast(high_resolution_clock::now() - start).count(); + return (audio_ts + passed) >= frame->info.timestamp; + })) { return false; } } @@ -355,23 +359,13 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { return false; } - { - using namespace std::chrono; - auto elapsed_time = CurrentTime(); - if (elapsed_time < frame->info.timestamp) { - if (m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - elapsed_time), - [&] { return elapsed_time >= frame->info.timestamp; })) { - return false; - } - } - } - // return the buffer to the queue if (m_current_audio_frame.has_value()) { m_audio_buffers.Push(std::move(m_current_audio_frame.value())); m_audio_buffers_cv.Notify(); } m_current_audio_frame = std::move(frame->buffer); + m_last_audio_packet_time = frame->info.timestamp; audio_info = {}; audio_info.timestamp = frame->info.timestamp; diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index 67e7a639a..5518b87d1 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -30,6 +30,8 @@ class AvPlayerStateCallback { public: virtual ~AvPlayerStateCallback() = default; + virtual AvPlayerAvSyncMode GetSyncMode() = 0; + virtual void OnWarning(u32 id) = 0; virtual void OnError() = 0; virtual void OnEOF() = 0; @@ -216,6 +218,7 @@ private: 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{}; + u64 m_last_audio_packet_time{}; }; } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index aa66d690e..889884945 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -217,6 +217,10 @@ bool AvPlayerState::Resume() { return true; } +void AvPlayerState::SetAvSyncMode(AvPlayerAvSyncMode sync_mode) { + m_sync_mode = sync_mode; +} + void AvPlayerState::AvControllerThread(std::stop_token stop) { using std::chrono::milliseconds; Common::SetCurrentThreadName("shadPS4:AvController"); @@ -337,6 +341,10 @@ void AvPlayerState::OnWarning(u32 id) { WarningEvent(id); } +AvPlayerAvSyncMode AvPlayerState::GetSyncMode() { + return m_sync_mode; +} + void AvPlayerState::OnError() { SetState(AvState::Error); OnPlaybackStateChanged(AvState::Error); diff --git a/src/core/libraries/avplayer/avplayer_state.h b/src/core/libraries/avplayer/avplayer_state.h index 93f0e0a89..c67855c89 100644 --- a/src/core/libraries/avplayer/avplayer_state.h +++ b/src/core/libraries/avplayer/avplayer_state.h @@ -30,6 +30,7 @@ public: bool Stop(); bool Pause(); bool Resume(); + void SetAvSyncMode(AvPlayerAvSyncMode sync_mode); bool GetAudioData(AvPlayerFrameInfo& audio_info); bool GetVideoData(AvPlayerFrameInfo& video_info); bool GetVideoData(AvPlayerFrameInfoEx& video_info); @@ -45,6 +46,7 @@ private: static void PS4_SYSV_ABI DefaultEventCallback(void* handle, AvPlayerEvents event_id, s32 source_id, void* event_data); + AvPlayerAvSyncMode GetSyncMode() override; void OnWarning(u32 id) override; void OnError() override; void OnEOF() override; @@ -72,6 +74,7 @@ private: AvPlayerEventReplacement m_event_replacement{}; bool m_auto_start{}; char m_default_language[4]{}; + AvPlayerAvSyncMode m_sync_mode = AvPlayerAvSyncMode::Default; std::atomic m_current_state; std::atomic m_previous_state; From 5a57c924ba63eefb83d71d9036d3c61e5d86022c Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sun, 16 Feb 2025 17:48:55 +0300 Subject: [PATCH 4/9] avplayer: issue warning on loopback --- src/core/libraries/avplayer/avplayer_source.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index 480df3011..4a4d8953d 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -5,6 +5,7 @@ #include "common/singleton.h" #include "common/thread.h" #include "core/file_sys/fs.h" +#include "core/libraries/avplayer/avplayer_error.h" #include "core/libraries/avplayer/avplayer_file_streamer.h" #include "core/libraries/avplayer/avplayer_source.h" @@ -448,6 +449,7 @@ void AvPlayerSource::DemuxerThread(std::stop_token stop) { if (res == AVERROR_EOF) { if (m_is_looping) { LOG_INFO(Lib_AvPlayer, "EOF reached in demuxer. Looping the source..."); + m_state.OnWarning(ORBIS_AVPLAYER_ERROR_WAR_LOOPING_BACK); avio_seek(m_avformat_context->pb, 0, SEEK_SET); if (m_video_stream_index.has_value()) { const auto index = m_video_stream_index.value(); From 3cd370d587d0f6c20d1f25c264cc06dfb77c6501 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sun, 16 Feb 2025 22:06:26 +0300 Subject: [PATCH 5/9] avplayer: sync on video ts in default mode when audio ts is not available --- src/core/libraries/avplayer/avplayer_source.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index 4a4d8953d..b2cc9c552 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -322,15 +322,16 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { return false; } - if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default && m_audio_stream_index.has_value()) { - const auto audio_ts = m_last_audio_packet_time; - if (audio_ts < frame->info.timestamp) { + if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default) { + const auto desired_time = + m_audio_stream_index.has_value() ? m_last_audio_packet_time : CurrentTime(); + if (desired_time < frame->info.timestamp) { using namespace std::chrono; const auto start = high_resolution_clock::now(); - if (!m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - audio_ts), [&] { + if (!m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - desired_time), [&] { const auto passed = duration_cast(high_resolution_clock::now() - start).count(); - return (audio_ts + passed) >= frame->info.timestamp; + return (desired_time + passed) >= frame->info.timestamp; })) { return false; } From dfb14018b43b6c2d783525642e8cbd5960fff908 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Wed, 19 Feb 2025 19:36:49 +0300 Subject: [PATCH 6/9] avplayer: removed waits for the frame in Get*Data, replaced cv with sleep --- src/core/libraries/avplayer/avplayer.cpp | 8 ++--- .../libraries/avplayer/avplayer_source.cpp | 32 ++++++------------- src/core/libraries/avplayer/avplayer_source.h | 2 -- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index 2495db9e6..3feef5e5b 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -19,7 +19,7 @@ s32 PS4_SYSV_ABI sceAvPlayerAddSource(AvPlayerHandle handle, const char* filenam s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(AvPlayerHandle handle, AvPlayerUriType uri_type, AvPlayerSourceDetails* source_details) { - LOG_ERROR(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); if (handle == nullptr || uri_type != AvPlayerUriType::Source) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } @@ -68,7 +68,7 @@ s32 PS4_SYSV_ABI sceAvPlayerEnableStream(AvPlayerHandle handle, u32 stream_id) { bool PS4_SYSV_ABI sceAvPlayerGetAudioData(AvPlayerHandle handle, AvPlayerFrameInfo* p_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || p_info == nullptr) { - return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; + return false; } return handle->GetAudioData(*p_info); } @@ -85,7 +85,7 @@ s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(AvPlayerHandle handle, u32 stream_id, bool PS4_SYSV_ABI sceAvPlayerGetVideoData(AvPlayerHandle handle, AvPlayerFrameInfo* video_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || video_info == nullptr) { - return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; + return false; } return handle->GetVideoData(*video_info); } @@ -94,7 +94,7 @@ bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(AvPlayerHandle handle, AvPlayerFrameInfoEx* video_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || video_info == nullptr) { - return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; + return false; } return handle->GetVideoData(*video_info); } diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index b2cc9c552..d65e5e3d8 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -272,7 +272,6 @@ bool AvPlayerSource::Stop() { m_video_buffers.Push(std::move(m_current_video_frame.value())); m_current_video_frame.reset(); } - m_stop_cv.Notify(); m_audio_packets.Clear(); m_video_packets.Clear(); @@ -314,27 +313,17 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { return false; } - m_video_frames_cv.Wait([this] { return m_video_frames.Size() != 0 || m_is_eof; }); - - auto frame = m_video_frames.Pop(); - if (!frame.has_value()) { - LOG_TRACE(Lib_AvPlayer, "Could get video frame. EOF reached."); + if (m_video_frames.Size() == 0) { return false; } + auto frame = m_video_frames.Pop(); if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default) { - const auto desired_time = + const auto current_time = m_audio_stream_index.has_value() ? m_last_audio_packet_time : CurrentTime(); - if (desired_time < frame->info.timestamp) { - using namespace std::chrono; - const auto start = high_resolution_clock::now(); - if (!m_stop_cv.WaitFor(milliseconds(frame->info.timestamp - desired_time), [&] { - const auto passed = - duration_cast(high_resolution_clock::now() - start).count(); - return (desired_time + passed) >= frame->info.timestamp; - })) { - return false; - } + if (0 < current_time && current_time < frame->info.timestamp) { + std::this_thread::sleep_for( + std::chrono::milliseconds(frame->info.timestamp - current_time)); } } @@ -353,16 +342,13 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { return false; } - m_audio_frames_cv.Wait([this] { return m_audio_frames.Size() != 0 || m_is_eof; }); - - auto frame = m_audio_frames.Pop(); - if (!frame.has_value()) { - LOG_TRACE(Lib_AvPlayer, "Could get audio frame. EOF reached."); + if (m_audio_frames.Size() == 0) { return false; } - // return the buffer to the queue + auto frame = m_audio_frames.Pop(); if (m_current_audio_frame.has_value()) { + // return the buffer to the queue m_audio_buffers.Push(std::move(m_current_audio_frame.value())); m_audio_buffers_cv.Notify(); } diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index 5518b87d1..edb0e680c 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -202,8 +202,6 @@ private: EventCV m_video_frames_cv{}; EventCV m_video_buffers_cv{}; - EventCV m_stop_cv{}; - std::mutex m_state_mutex{}; Kernel::Thread m_demuxer_thread{}; Kernel::Thread m_video_decoder_thread{}; From 33140095c4364feea17623e2ab20f76784086ae0 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sat, 22 Feb 2025 20:55:14 +0300 Subject: [PATCH 7/9] avplayer: removed all waits from GetVideoData --- src/core/libraries/avplayer/avplayer.cpp | 8 ++++---- src/core/libraries/avplayer/avplayer_common.h | 4 ++++ src/core/libraries/avplayer/avplayer_source.cpp | 14 +++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index 3feef5e5b..8d5a76199 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -19,7 +19,7 @@ s32 PS4_SYSV_ABI sceAvPlayerAddSource(AvPlayerHandle handle, const char* filenam s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(AvPlayerHandle handle, AvPlayerUriType uri_type, AvPlayerSourceDetails* source_details) { - LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || uri_type != AvPlayerUriType::Source) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } @@ -159,7 +159,7 @@ s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) { } s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) { - LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } @@ -180,7 +180,7 @@ s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) { } s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) { - LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } @@ -188,7 +188,7 @@ s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) { } s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) { - LOG_TRACE(Lib_AvPlayer, "(STUBBED) called"); + LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } diff --git a/src/core/libraries/avplayer/avplayer_common.h b/src/core/libraries/avplayer/avplayer_common.h index 2c5f4ec13..1e5715009 100644 --- a/src/core/libraries/avplayer/avplayer_common.h +++ b/src/core/libraries/avplayer/avplayer_common.h @@ -65,6 +65,10 @@ public: m_queue.emplace(std::forward(value)); } + T& Front() { + return m_queue.front(); + } + std::optional Pop() { if (Size() == 0) { return std::nullopt; diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index d65e5e3d8..4f637f1ba 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -291,10 +291,6 @@ void AvPlayerSource::Resume() { } bool AvPlayerSource::GetVideoData(AvPlayerFrameInfo& video_info) { - if (!IsActive()) { - return false; - } - AvPlayerFrameInfoEx info{}; if (!GetVideoData(info)) { return false; @@ -317,18 +313,18 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { return false; } - auto frame = m_video_frames.Pop(); + const auto& last_frame = m_video_frames.Front(); if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default) { const auto current_time = m_audio_stream_index.has_value() ? m_last_audio_packet_time : CurrentTime(); - if (0 < current_time && current_time < frame->info.timestamp) { - std::this_thread::sleep_for( - std::chrono::milliseconds(frame->info.timestamp - current_time)); + if (0 < current_time && current_time < last_frame.info.timestamp) { + return false; } } - // return the buffer to the queue + auto frame = m_video_frames.Pop(); if (m_current_video_frame.has_value()) { + // return the buffer to the queue m_video_buffers.Push(std::move(m_current_video_frame.value())); m_video_buffers_cv.Notify(); } From 577af4038a5cee6c804d3f0f6c78615018d27d1c Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sat, 1 Mar 2025 12:45:31 +0300 Subject: [PATCH 8/9] avplayer: fix warning propagation + small fixes --- .../libraries/avplayer/avplayer_source.cpp | 33 ++++++++----------- src/core/libraries/avplayer/avplayer_source.h | 9 +++-- .../libraries/avplayer/avplayer_state.cpp | 2 +- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index 4f637f1ba..0bbb662be 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -91,10 +91,6 @@ static AvPlayerStreamType CodecTypeToStreamType(AVMediaType codec_type) { } } -static f32 AVRationalToF32(const AVRational rational) { - return f32(rational.num) / rational.den; -} - bool AvPlayerSource::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { info = {}; if (m_avformat_context == nullptr || stream_index >= m_avformat_context->nb_streams) { @@ -265,11 +261,11 @@ bool AvPlayerSource::Stop() { m_demuxer_thread.Stop(); if (m_current_audio_frame.has_value()) { - m_audio_buffers.Push(std::move(m_current_audio_frame.value())); + m_audio_buffers.Push(std::move(m_current_audio_frame->buffer)); m_current_audio_frame.reset(); } if (m_current_video_frame.has_value()) { - m_video_buffers.Push(std::move(m_current_video_frame.value())); + m_video_buffers.Push(std::move(m_current_video_frame->buffer)); m_current_video_frame.reset(); } @@ -281,12 +277,12 @@ bool AvPlayerSource::Stop() { } void AvPlayerSource::Pause() { - m_last_paused_time = std::chrono::high_resolution_clock::now(); + m_pause_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_pause_duration += std::chrono::high_resolution_clock::now() - m_pause_time; m_is_paused = false; } @@ -313,11 +309,10 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { return false; } - const auto& last_frame = m_video_frames.Front(); + const auto& new_frame = m_video_frames.Front(); if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default) { - const auto current_time = - m_audio_stream_index.has_value() ? m_last_audio_packet_time : CurrentTime(); - if (0 < current_time && current_time < last_frame.info.timestamp) { + const auto current_time = CurrentTime(); + if (0 < current_time && current_time < new_frame.info.timestamp) { return false; } } @@ -325,11 +320,11 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { auto frame = m_video_frames.Pop(); if (m_current_video_frame.has_value()) { // return the buffer to the queue - m_video_buffers.Push(std::move(m_current_video_frame.value())); + m_video_buffers.Push(std::move(m_current_video_frame->buffer)); m_video_buffers_cv.Notify(); } - m_current_video_frame = std::move(frame->buffer); video_info = frame->info; + m_current_video_frame = std::move(frame); return true; } @@ -345,11 +340,9 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { auto frame = m_audio_frames.Pop(); if (m_current_audio_frame.has_value()) { // return the buffer to the queue - m_audio_buffers.Push(std::move(m_current_audio_frame.value())); + m_audio_buffers.Push(std::move(m_current_audio_frame->buffer)); m_audio_buffers_cv.Notify(); } - m_current_audio_frame = std::move(frame->buffer); - m_last_audio_packet_time = frame->info.timestamp; audio_info = {}; audio_info.timestamp = frame->info.timestamp; @@ -357,6 +350,7 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { audio_info.details.audio.sample_rate = frame->info.details.audio.sample_rate; audio_info.details.audio.size = frame->info.details.audio.size; audio_info.details.audio.channel_count = frame->info.details.audio.channel_count; + m_current_audio_frame = std::move(frame); return true; } @@ -365,7 +359,8 @@ u64 AvPlayerSource::CurrentTime() { return 0; } using namespace std::chrono; - return duration_cast(high_resolution_clock::now() - m_start_time - m_stalled_time) + return duration_cast(high_resolution_clock::now() - m_start_time - + m_pause_duration) .count(); } @@ -568,7 +563,7 @@ Frame AvPlayerSource::PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame { .width = width, .height = height, - .aspect_ratio = AVRationalToF32(frame.sample_aspect_ratio), + .aspect_ratio = (float)av_q2d(frame.sample_aspect_ratio), .crop_left_offset = u32(frame.crop_left), .crop_right_offset = u32(frame.crop_right + (width - frame.width)), .crop_top_offset = u32(frame.crop_top), diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index edb0e680c..cb0cef8f6 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -188,8 +188,8 @@ private: AvPlayerQueue m_audio_frames; AvPlayerQueue m_video_frames; - std::optional m_current_video_frame; - std::optional m_current_audio_frame; + std::optional m_current_video_frame; + std::optional m_current_audio_frame; std::optional m_video_stream_index{}; std::optional m_audio_stream_index{}; @@ -214,9 +214,8 @@ private: SWSContextPtr m_sws_context{nullptr, &ReleaseSWSContext}; 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{}; - u64 m_last_audio_packet_time{}; + std::chrono::high_resolution_clock::time_point m_pause_time{}; + std::chrono::high_resolution_clock::duration m_pause_duration{}; }; } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index 889884945..38811d853 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -429,7 +429,7 @@ void AvPlayerState::ProcessEvent() { } switch (event->event) { case AvEventType::WarningId: { - OnWarning(event->payload.error); + EmitEvent(AvPlayerEvents::WarningId, &event->payload.error); break; } case AvEventType::RevertState: { From 550ceb524eb7e025d63445d22a0e38a9311bcc4b Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Fri, 7 Mar 2025 11:31:01 +0300 Subject: [PATCH 9/9] WIP --- src/common/logging/log.h | 4 - src/common/native_clock.cpp | 49 +++-- src/common/native_clock.h | 12 +- src/common/rdtsc.cpp | 21 +- src/core/libraries/avplayer/avplayer.cpp | 40 +++- src/core/libraries/avplayer/avplayer.h | 1 + src/core/libraries/avplayer/avplayer_common.h | 3 +- src/core/libraries/avplayer/avplayer_impl.cpp | 11 +- src/core/libraries/avplayer/avplayer_impl.h | 2 +- .../libraries/avplayer/avplayer_source.cpp | 113 +++++++---- src/core/libraries/avplayer/avplayer_source.h | 7 +- .../libraries/avplayer/avplayer_state.cpp | 191 +++++++++++++++--- src/core/libraries/avplayer/avplayer_state.h | 35 +++- src/core/libraries/kernel/time.cpp | 7 +- 14 files changed, 366 insertions(+), 130 deletions(-) diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 5fa430348..de16cccf6 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -39,14 +39,10 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig Common::Log::FmtLogMessage(log_class, log_level, Common::Log::TrimSourcePath(__FILE__), \ __LINE__, __func__, __VA_ARGS__) -#ifdef _DEBUG #define LOG_TRACE(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Trace, \ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ __VA_ARGS__) -#else -#define LOG_TRACE(log_class, fmt, ...) (void(0)) -#endif #define LOG_DEBUG(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Debug, \ diff --git a/src/common/native_clock.cpp b/src/common/native_clock.cpp index 0c05dbe84..1ea5a4bfe 100644 --- a/src/common/native_clock.cpp +++ b/src/common/native_clock.cpp @@ -5,28 +5,51 @@ #include "common/rdtsc.h" #include "common/uint128.h" +#include + +#ifdef _WIN64 +#include + +#define MM_SHARED_USER_DATA_VA 0x7ffe0000 +#define QpcBias ((ULONGLONG volatile*)(MM_SHARED_USER_DATA_VA + 0x3b0)) +#endif + namespace Common { NativeClock::NativeClock() : rdtsc_frequency{EstimateRDTSCFrequency()}, - ns_rdtsc_factor{GetFixedPoint64Factor(std::nano::den, rdtsc_frequency)}, - us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)}, - ms_rdtsc_factor{GetFixedPoint64Factor(std::milli::den, rdtsc_frequency)} {} + us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)} {} -u64 NativeClock::GetTimeNS(u64 base_ptc /*= 0*/) const { - return MultiplyHigh(GetUptime() - base_ptc, ns_rdtsc_factor); -} - -u64 NativeClock::GetTimeUS(u64 base_ptc /*= 0*/) const { - return MultiplyHigh(GetUptime() - base_ptc, us_rdtsc_factor); -} - -u64 NativeClock::GetTimeMS(u64 base_ptc /*= 0*/) const { - return MultiplyHigh(GetUptime() - base_ptc, ms_rdtsc_factor); +u64 NativeClock::GetTimeUS(u64 time) const { + return MultiplyHigh(time, us_rdtsc_factor); } u64 NativeClock::GetUptime() const { +#ifdef _WIN64 + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return counter.QuadPart; +#else return FencedRDTSC(); +#endif +} + +u64 NativeClock::GetUnbiasedUptime() const { +#ifdef _WIN64 + ULONGLONG bias = 0; + u64 qpc = 0; + do { + bias = *QpcBias; + qpc = GetUptime(); + } while (bias != *QpcBias); + return qpc - bias; +#else + return GetUptime(); +#endif +} + +u64 NativeClock::GetTscFrequency() const { + return rdtsc_frequency; } } // namespace Common diff --git a/src/common/native_clock.h b/src/common/native_clock.h index 1542c2f3a..2a030b911 100644 --- a/src/common/native_clock.h +++ b/src/common/native_clock.h @@ -3,7 +3,6 @@ #pragma once -#include #include "common/types.h" namespace Common { @@ -12,20 +11,15 @@ class NativeClock final { public: explicit NativeClock(); - u64 GetTscFrequency() const { - return rdtsc_frequency; - } + u64 GetTimeUS(u64 time) const; - u64 GetTimeNS(u64 base_ptc = 0) const; - u64 GetTimeUS(u64 base_ptc = 0) const; - u64 GetTimeMS(u64 base_ptc = 0) const; u64 GetUptime() const; + u64 GetUnbiasedUptime() const; + u64 GetTscFrequency() const; private: u64 rdtsc_frequency; - u64 ns_rdtsc_factor; u64 us_rdtsc_factor; - u64 ms_rdtsc_factor; }; } // namespace Common diff --git a/src/common/rdtsc.cpp b/src/common/rdtsc.cpp index 48d1b7a40..316d8388a 100644 --- a/src/common/rdtsc.cpp +++ b/src/common/rdtsc.cpp @@ -6,11 +6,12 @@ #include "common/uint128.h" #ifdef _WIN64 -#include +#include #endif namespace Common { +#ifndef _WIN64 static constexpr size_t SecondToNanoseconds = 1000000000ULL; template @@ -20,16 +21,7 @@ static u64 RoundToNearest(u64 value) { } static u64 GetTimeNs() { -#ifdef _WIN64 - // GetSystemTimePreciseAsFileTime returns the file time in 100ns units. - static constexpr u64 Multiplier = 100; - // Convert Windows epoch to Unix epoch. - static constexpr u64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL; - FILETIME filetime; - GetSystemTimePreciseAsFileTime(&filetime); - return Multiplier * ((static_cast(filetime.dwHighDateTime) << 32) + - static_cast(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch); -#elif defined(__APPLE__) +#if defined(__APPLE__) return clock_gettime_nsec_np(CLOCK_REALTIME); #else timespec ts; @@ -37,8 +29,14 @@ static u64 GetTimeNs() { return ts.tv_sec * SecondToNanoseconds + ts.tv_nsec; #endif } +#endif u64 EstimateRDTSCFrequency() { +#ifdef _WIN64 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return frequency.QuadPart; +#else // Discard the first result measuring the rdtsc. FencedRDTSC(); std::this_thread::sleep_for(std::chrono::milliseconds{1}); @@ -55,6 +53,7 @@ u64 EstimateRDTSCFrequency() { const u64 tsc_diff = tsc_end - tsc_start; const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, end_time - start_time); return RoundToNearest<100'000>(tsc_freq); +#endif } } // namespace Common diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp index 8d5a76199..f8298424d 100644 --- a/src/core/libraries/avplayer/avplayer.cpp +++ b/src/core/libraries/avplayer/avplayer.cpp @@ -42,11 +42,14 @@ s32 PS4_SYSV_ABI sceAvPlayerClose(AvPlayerHandle handle) { } u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(AvPlayerHandle handle) { - LOG_TRACE(Lib_AvPlayer, "called"); + // LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { + LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS"); return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - return handle->CurrentTime(); + const auto res = handle->CurrentTime(); + LOG_TRACE(Lib_AvPlayer, "returning {}", res); + return res; } s32 PS4_SYSV_ABI sceAvPlayerDisableStream(AvPlayerHandle handle, u32 stream_id) { @@ -66,11 +69,18 @@ s32 PS4_SYSV_ABI sceAvPlayerEnableStream(AvPlayerHandle handle, u32 stream_id) { } bool PS4_SYSV_ABI sceAvPlayerGetAudioData(AvPlayerHandle handle, AvPlayerFrameInfo* p_info) { - LOG_TRACE(Lib_AvPlayer, "called"); + // LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || p_info == nullptr) { + LOG_TRACE(Lib_AvPlayer, "returning false"); return false; } - return handle->GetAudioData(*p_info); + const auto res = handle->GetAudioData(*p_info); + if (res) { + LOG_TRACE(Lib_AvPlayer, "returning {}, ts = {}", res, p_info->timestamp); + } else { + LOG_TRACE(Lib_AvPlayer, "returning false"); + } + return res; } s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(AvPlayerHandle handle, u32 stream_id, @@ -94,9 +104,20 @@ bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(AvPlayerHandle handle, AvPlayerFrameInfoEx* video_info) { LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr || video_info == nullptr) { + LOG_TRACE(Lib_AvPlayer, "returning {}", false); return false; } - return handle->GetVideoData(*video_info); + + // This is what the original library does, idk why + for (int i = 0; i < 20; ++i) { + if (handle->GetVideoData(*video_info)) { + LOG_TRACE(Lib_AvPlayer, "returning {}, ts = {}", true, video_info->timestamp); + return true; + } + } + + LOG_TRACE(Lib_AvPlayer, "returning {}", false); + return false; } AvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(AvPlayerInitData* data) { @@ -143,11 +164,14 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const AvPlayerInitDataEx* p_data, AvPlayerHan } bool PS4_SYSV_ABI sceAvPlayerIsActive(AvPlayerHandle handle) { - LOG_TRACE(Lib_AvPlayer, "called"); + // LOG_TRACE(Lib_AvPlayer, "called"); if (handle == nullptr) { + LOG_TRACE(Lib_AvPlayer, "returning false"); return false; } - return handle->IsActive(); + const auto res = handle->IsActive(); + LOG_TRACE(Lib_AvPlayer, "returning {}", res); + return res; } s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) { @@ -240,7 +264,7 @@ s32 PS4_SYSV_ABI sceAvPlayerStreamCount(AvPlayerHandle handle) { if (handle == nullptr) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - return handle->GetStreamCount(); + return static_cast(handle->GetStreamCount()); } s32 PS4_SYSV_ABI sceAvPlayerVprintf(const char* format, va_list args) { diff --git a/src/core/libraries/avplayer/avplayer.h b/src/core/libraries/avplayer/avplayer.h index 2312acaec..100f66108 100644 --- a/src/core/libraries/avplayer/avplayer.h +++ b/src/core/libraries/avplayer/avplayer.h @@ -171,6 +171,7 @@ struct AvPlayerFileReplacement { }; enum class AvPlayerEvents { + Initial = 0x00, StateStop = 0x01, StateReady = 0x02, StatePlay = 0x03, diff --git a/src/core/libraries/avplayer/avplayer_common.h b/src/core/libraries/avplayer/avplayer_common.h index 1e5715009..aedbbd9f9 100644 --- a/src/core/libraries/avplayer/avplayer_common.h +++ b/src/core/libraries/avplayer/avplayer_common.h @@ -24,12 +24,13 @@ enum class AvState { Stop, EndOfFile, Pause, - C0x08, + PauseOnEOF, Jump, TrickMode, C0x0B, Buffering, Starting, + C0x10, Error, }; diff --git a/src/core/libraries/avplayer/avplayer_impl.cpp b/src/core/libraries/avplayer/avplayer_impl.cpp index 138747da4..379fc9607 100644 --- a/src/core/libraries/avplayer/avplayer_impl.cpp +++ b/src/core/libraries/avplayer/avplayer_impl.cpp @@ -119,15 +119,8 @@ s32 AvPlayer::AddSourceEx(std::string_view path, AvPlayerSourceType source_type) return ORBIS_OK; } -s32 AvPlayer::GetStreamCount() { - if (m_state == nullptr) { - return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; - } - const auto res = m_state->GetStreamCount(); - if (AVPLAYER_IS_ERROR(res)) { - return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; - } - return res; +u32 AvPlayer::GetStreamCount() { + return m_state->GetStreamCount(); } s32 AvPlayer::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { diff --git a/src/core/libraries/avplayer/avplayer_impl.h b/src/core/libraries/avplayer/avplayer_impl.h index 7e4aec43c..d951964c7 100644 --- a/src/core/libraries/avplayer/avplayer_impl.h +++ b/src/core/libraries/avplayer/avplayer_impl.h @@ -24,7 +24,7 @@ public: s32 PostInit(const AvPlayerPostInitData& data); s32 AddSource(std::string_view filename); s32 AddSourceEx(std::string_view path, AvPlayerSourceType source_type); - s32 GetStreamCount(); + u32 GetStreamCount(); s32 GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); s32 EnableStream(u32 stream_index); s32 Start(); diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index 0bbb662be..30474303a 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -313,6 +313,7 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { if (m_state.GetSyncMode() == AvPlayerAvSyncMode::Default) { const auto current_time = CurrentTime(); if (0 < current_time && current_time < new_frame.info.timestamp) { + LOG_TRACE(Lib_AvPlayer, "{} < {}", current_time, new_frame.info.timestamp); return false; } } @@ -323,6 +324,11 @@ bool AvPlayerSource::GetVideoData(AvPlayerFrameInfoEx& video_info) { m_video_buffers.Push(std::move(m_current_video_frame->buffer)); m_video_buffers_cv.Notify(); } + + if (frame->is_loop && m_is_looping) { + m_state.OnLoop(); + } + video_info = frame->info; m_current_video_frame = std::move(frame); return true; @@ -344,6 +350,10 @@ bool AvPlayerSource::GetAudioData(AvPlayerFrameInfo& audio_info) { m_audio_buffers_cv.Notify(); } + if (frame->is_loop && m_is_looping) { + m_state.OnLoop(); + } + audio_info = {}; audio_info.timestamp = frame->info.timestamp; audio_info.p_data = reinterpret_cast(frame->info.p_data); @@ -405,8 +415,11 @@ void AvPlayerSource::ReleaseAVFormatContext(AVFormatContext* context) { } } +// Custom flag that is not passed to ffmpeg +// It's here to get rid of the need for a separate structure +#define AV_PKT_FLAG_LOOP 0x100000 + void AvPlayerSource::DemuxerThread(std::stop_token stop) { - using namespace std::chrono; Common::SetCurrentThreadName("shadPS4:AvDemuxer"); if (!m_audio_stream_index.has_value() && !m_video_stream_index.has_value()) { @@ -415,50 +428,46 @@ void AvPlayerSource::DemuxerThread(std::stop_token stop) { } LOG_INFO(Lib_AvPlayer, "Demuxer Thread started"); + bool is_loop = false; while (!stop.stop_requested()) { if (m_video_packets.Size() > 30 && (!m_audio_stream_index.has_value() || m_audio_packets.Size() > 8)) { - std::this_thread::sleep_for(milliseconds(5)); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); continue; } + AVPacketPtr up_packet(av_packet_alloc(), &ReleaseAVPacket); const auto res = av_read_frame(m_avformat_context.get(), up_packet.get()); - if (res < 0) { - if (res == AVERROR_EOF) { - if (m_is_looping) { - LOG_INFO(Lib_AvPlayer, "EOF reached in demuxer. Looping the source..."); - m_state.OnWarning(ORBIS_AVPLAYER_ERROR_WAR_LOOPING_BACK); - avio_seek(m_avformat_context->pb, 0, SEEK_SET); - if (m_video_stream_index.has_value()) { - const auto index = m_video_stream_index.value(); - const auto stream = m_avformat_context->streams[index]; - avformat_seek_file(m_avformat_context.get(), index, 0, 0, stream->duration, - 0); - } - if (m_audio_stream_index.has_value()) { - const auto index = m_audio_stream_index.value(); - const auto stream = m_avformat_context->streams[index]; - avformat_seek_file(m_avformat_context.get(), index, 0, 0, stream->duration, - 0); - } - continue; - } else { - LOG_INFO(Lib_AvPlayer, "EOF reached in demuxer. Exiting."); - break; - } - } else { - LOG_ERROR(Lib_AvPlayer, "Could not read AV frame: error = {}", res); - m_state.OnError(); - return; + if (res >= 0) [[likely]] { + if (is_loop) { + up_packet->flags |= AV_PKT_FLAG_LOOP; + is_loop = false; } + AddPacket(std::move(up_packet)); + continue; + } + + if (res != AVERROR_EOF) [[unlikely]] { + LOG_ERROR(Lib_AvPlayer, "Could not read AV frame: error = {}", res); + m_state.OnError(); break; } - if (up_packet->stream_index == m_video_stream_index) { - m_video_packets.Push(std::move(up_packet)); - m_video_packets_cv.Notify(); - } else if (up_packet->stream_index == m_audio_stream_index) { - m_audio_packets.Push(std::move(up_packet)); - m_audio_packets_cv.Notify(); + + if (!m_is_looping) { + LOG_INFO(Lib_AvPlayer, "EOF reached in demuxer. Exiting."); + break; + } + + is_loop = true; + + LOG_INFO(Lib_AvPlayer, "Looping the source..."); + avio_seek(m_avformat_context->pb, 0, SEEK_SET); + if (m_audio_stream_index.has_value()) { + const auto index = m_audio_stream_index.value(); + av_seek_frame(m_avformat_context.get(), index, 0, 0); + } else if (m_video_stream_index.has_value()) { + const auto index = m_video_stream_index.value(); + av_seek_frame(m_avformat_context.get(), index, 0, 0); } } @@ -476,6 +485,16 @@ void AvPlayerSource::DemuxerThread(std::stop_token stop) { LOG_INFO(Lib_AvPlayer, "Demuxer Thread exited normally"); } +void AvPlayerSource::AddPacket(AVPacketPtr up_packet) { + if (up_packet->stream_index == m_video_stream_index) { + m_video_packets.Push(std::move(up_packet)); + m_video_packets_cv.Notify(); + } else if (up_packet->stream_index == m_audio_stream_index) { + m_audio_packets.Push(std::move(up_packet)); + m_audio_packets_cv.Notify(); + } +} + AvPlayerSource::AVFramePtr AvPlayerSource::ConvertVideoFrame(const AVFrame& frame) { auto nv12_frame = AVFramePtr{av_frame_alloc(), &ReleaseAVFrame}; nv12_frame->pts = frame.pts; @@ -531,7 +550,7 @@ static void CopyNV12Data(u8* dst, const AVFrame& src, bool use_vdec2) { } } -Frame AvPlayerSource::PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame) { +Frame AvPlayerSource::PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame, bool is_loop) { ASSERT(frame.format == AV_PIX_FMT_NV12); auto p_buffer = buffer.GetBuffer(); @@ -575,6 +594,7 @@ Frame AvPlayerSource::PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame }, }, }, + .is_loop = is_loop, }; } @@ -593,6 +613,8 @@ void AvPlayerSource::VideoDecoderThread(std::stop_token stop) { continue; } + bool is_loop = (packet->get()->flags & AV_PKT_FLAG_LOOP) == AV_PKT_FLAG_LOOP; + packet->get()->flags &= ~AV_PKT_FLAG_LOOP; // Remove the fake flag auto res = avcodec_send_packet(m_video_codec_context.get(), packet->get()); if (res < 0 && res != AVERROR(EAGAIN)) { m_state.OnError(); @@ -628,10 +650,13 @@ void AvPlayerSource::VideoDecoderThread(std::stop_token stop) { } if (up_frame->format != AV_PIX_FMT_NV12) { const auto nv12_frame = ConvertVideoFrame(*up_frame); - m_video_frames.Push(PrepareVideoFrame(std::move(buffer.value()), *nv12_frame)); + m_video_frames.Push( + PrepareVideoFrame(std::move(buffer.value()), *nv12_frame, is_loop)); } else { - m_video_frames.Push(PrepareVideoFrame(std::move(buffer.value()), *up_frame)); + m_video_frames.Push( + PrepareVideoFrame(std::move(buffer.value()), *up_frame, is_loop)); } + is_loop = false; m_video_frames_cv.Notify(); } } @@ -666,7 +691,7 @@ AvPlayerSource::AVFramePtr AvPlayerSource::ConvertAudioFrame(const AVFrame& fram return pcm16_frame; } -Frame AvPlayerSource::PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame) { +Frame AvPlayerSource::PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame, bool is_loop) { ASSERT(frame.format == AV_SAMPLE_FMT_S16); ASSERT(frame.nb_samples <= 1024); @@ -697,6 +722,7 @@ Frame AvPlayerSource::PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame }, }, }, + .is_loop = is_loop, }; } @@ -714,6 +740,8 @@ void AvPlayerSource::AudioDecoderThread(std::stop_token stop) { if (!packet.has_value()) { continue; } + bool is_loop = (packet->get()->flags & AV_PKT_FLAG_LOOP) == AV_PKT_FLAG_LOOP; + packet->get()->flags &= ~AV_PKT_FLAG_LOOP; // Remove the fake flag auto res = avcodec_send_packet(m_audio_codec_context.get(), packet->get()); if (res < 0 && res != AVERROR(EAGAIN)) { m_state.OnError(); @@ -750,10 +778,13 @@ void AvPlayerSource::AudioDecoderThread(std::stop_token stop) { } if (up_frame->format != AV_SAMPLE_FMT_S16) { const auto pcm16_frame = ConvertAudioFrame(*up_frame); - m_audio_frames.Push(PrepareAudioFrame(std::move(buffer.value()), *pcm16_frame)); + m_audio_frames.Push( + PrepareAudioFrame(std::move(buffer.value()), *pcm16_frame, is_loop)); } else { - m_audio_frames.Push(PrepareAudioFrame(std::move(buffer.value()), *up_frame)); + m_audio_frames.Push( + PrepareAudioFrame(std::move(buffer.value()), *up_frame, is_loop)); } + is_loop = false; m_audio_frames_cv.Notify(); } } diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index cb0cef8f6..5ce18b922 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -34,6 +34,7 @@ public: virtual void OnWarning(u32 id) = 0; virtual void OnError() = 0; + virtual void OnLoop() = 0; virtual void OnEOF() = 0; }; @@ -86,6 +87,7 @@ private: struct Frame { FrameBuffer buffer; AvPlayerFrameInfoEx info; + bool is_loop = false; }; class EventCV { @@ -160,12 +162,13 @@ private: void AudioDecoderThread(std::stop_token stop); bool HasRunningThreads() const; + void AddPacket(AVPacketPtr up_packet); AVFramePtr ConvertAudioFrame(const AVFrame& frame); AVFramePtr ConvertVideoFrame(const AVFrame& frame); - Frame PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame); - Frame PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame); + Frame PrepareAudioFrame(FrameBuffer buffer, const AVFrame& frame, bool is_loop); + Frame PrepareVideoFrame(FrameBuffer buffer, const AVFrame& frame, bool is_loop); AvPlayerStateCallback& m_state; bool m_use_vdec2 = false; diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index 38811d853..b8b04e758 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -6,6 +6,7 @@ #include "core/libraries/avplayer/avplayer_error.h" #include "core/libraries/avplayer/avplayer_source.h" #include "core/libraries/avplayer/avplayer_state.h" +#include "core/libraries/kernel/time.h" #include "core/tls.h" #include @@ -154,15 +155,33 @@ bool AvPlayerState::AddSource(std::string_view path, AvPlayerSourceType source_t } // Called inside GAME thread -s32 AvPlayerState::GetStreamCount() { - std::shared_lock lock(m_source_mutex); +u32 AvPlayerState::GetStreamCount() { if (m_up_source == nullptr) { - LOG_ERROR(Lib_AvPlayer, "Could not get stream count. No source."); - return -1; + return 0; } - return m_up_source->GetStreamCount(); + auto count = m_up_source->GetStreamCount(); + if (!m_stream_infos.empty()) { + return count; + } + if (count > 0) { + m_stream_infos.reserve(count); + for (u32 i = 0; i < count; ++i) { + AvPlayerStreamInfo info; + if (!m_up_source->GetStreamInfo(i, info)) { + std::lock_guard guard(m_stream_infos_mutex); + m_stream_infos.clear(); + return 0; + } + std::lock_guard guard(m_stream_infos_mutex); + m_stream_infos.emplace_back(info); + } + } + InitFilters(); + return count; } +void AvPlayerState::InitFilters() {} + // Called inside GAME thread bool AvPlayerState::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { std::shared_lock lock(m_source_mutex); @@ -175,6 +194,12 @@ bool AvPlayerState::GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info) { // Called inside GAME thread bool AvPlayerState::Start() { + if (m_current_state != AvState::Ready && m_current_state != AvState::Stop) { + if (!Stop()) { + return false; + } + } + SetState(AvState::Starting); std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr || !m_up_source->Start()) { LOG_ERROR(Lib_AvPlayer, "Could not start playback."); @@ -187,34 +212,56 @@ bool AvPlayerState::Start() { // 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) { + if (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; } + std::shared_lock lock(m_source_mutex); + if (m_up_source == nullptr) { + return false; + } m_up_source->Pause(); SetState(AvState::Pause); + m_timer.Update(); 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."); + if (m_current_state == AvState::Initial || m_current_state == AvState::Stop || + m_current_state == AvState::Ready || m_current_state == AvState::AddingSource || + m_current_state == AvState::Error) { return false; } - m_up_source->Resume(); - const auto state = m_previous_state.load(); - SetState(state); - OnPlaybackStateChanged(state); - return true; + while (m_current_state == AvState::Starting || m_current_state == AvState::Jump || + m_current_state == AvState::TrickMode) { + std::this_thread::sleep_for(std::chrono::microseconds(90)); + } + if (m_current_state == AvState::Buffering || m_current_state == AvState::Pause || + m_current_state == AvState::C0x10) { + m_timer.UpdateVPts(); + std::shared_lock lock(m_source_mutex); + m_up_source->Resume(); + SetState(AvState::Play); + OnPlaybackStateChanged(AvState::Play); + return true; + } + if (m_current_state == AvState::PauseOnEOF) { + m_timer.UpdateVPts(); + SetState(AvState::EndOfFile); + OnPlaybackStateChanged(AvState::EndOfFile); + return true; + } + if (m_current_state == AvState::Play || m_current_state == AvState::EndOfFile) { + return true; + } + return false; } void AvPlayerState::SetAvSyncMode(AvPlayerAvSyncMode sync_mode) { @@ -269,21 +316,31 @@ bool AvPlayerState::EnableStream(u32 stream_index) { // Called inside GAME thread bool AvPlayerState::Stop() { - std::shared_lock lock(m_source_mutex); - if (m_up_source == nullptr || m_current_state == AvState::Stop) { + if (m_current_state == AvState::Unknown || m_current_state == AvState::Stop) { return false; } - if (!m_up_source->Stop()) { - return false; + while (m_current_state == AvState::Jump || m_current_state == AvState::TrickMode) { + std::this_thread::sleep_for(std::chrono::microseconds(90)); } if (!SetState(AvState::Stop)) { return false; } - OnPlaybackStateChanged(AvState::Stop); + EmitEvent(AvPlayerEvents::StateStop); + { + std::shared_lock lock(m_source_mutex); + if (m_up_source == nullptr || !m_up_source->Stop()) { + return false; + } + } + m_timer.Reset(); return true; } bool AvPlayerState::GetVideoData(AvPlayerFrameInfo& video_info) { + if (m_current_state == AvState::Play || m_current_state == AvState::EndOfFile || + m_current_state == AvState::C0x10) { + return false; + } std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr) { return false; @@ -292,6 +349,10 @@ bool AvPlayerState::GetVideoData(AvPlayerFrameInfo& video_info) { } bool AvPlayerState::GetVideoData(AvPlayerFrameInfoEx& video_info) { + if (m_current_state == AvState::Play || m_current_state == AvState::EndOfFile || + m_current_state == AvState::C0x10) { + return false; + } std::shared_lock lock(m_source_mutex); if (m_up_source == nullptr) { return false; @@ -350,6 +411,11 @@ void AvPlayerState::OnError() { OnPlaybackStateChanged(AvState::Error); } +void AvPlayerState::OnLoop() { + auto id = ORBIS_AVPLAYER_ERROR_WAR_LOOPING_BACK; + EmitEvent(AvPlayerEvents::WarningId, &id); +} + void AvPlayerState::OnEOF() { SetState(AvState::EndOfFile); } @@ -377,6 +443,10 @@ void AvPlayerState::OnPlaybackStateChanged(AvState state) { EmitEvent(AvPlayerEvents::StateBuffering); break; } + case AvState::EndOfFile: { + EmitEvent(AvPlayerEvents::Initial); + break; + } default: break; } @@ -467,6 +537,7 @@ void AvPlayerState::UpdateBufferingState() { if (has_frames.value()) { const auto state = m_previous_state >= AvState::C0x0B ? m_previous_state.load() : AvState::Play; + m_timer.UpdateVPts(); SetState(state); OnPlaybackStateChanged(state); } @@ -488,7 +559,7 @@ bool AvPlayerState::IsStateTransitionValid(AvState state) { switch (m_current_state.load()) { case AvState::Stop: case AvState::EndOfFile: - // case AvState::C0x08: + case AvState::PauseOnEOF: case AvState::Error: return false; default: @@ -499,7 +570,7 @@ bool AvPlayerState::IsStateTransitionValid(AvState state) { switch (m_current_state.load()) { case AvState::Stop: case AvState::EndOfFile: - // case AvState::C0x08: + case AvState::PauseOnEOF: case AvState::Starting: case AvState::Error: return false; @@ -511,7 +582,7 @@ bool AvPlayerState::IsStateTransitionValid(AvState state) { switch (m_current_state.load()) { case AvState::Stop: case AvState::EndOfFile: - // case AvState::C0x08: + case AvState::PauseOnEOF: case AvState::TrickMode: case AvState::Starting: case AvState::Error: @@ -524,7 +595,7 @@ bool AvPlayerState::IsStateTransitionValid(AvState state) { switch (m_current_state.load()) { case AvState::Stop: case AvState::EndOfFile: - // case AvState::C0x08: + case AvState::PauseOnEOF: case AvState::Jump: case AvState::Starting: case AvState::Error: @@ -538,7 +609,7 @@ bool AvPlayerState::IsStateTransitionValid(AvState state) { case AvState::Stop: case AvState::EndOfFile: case AvState::Pause: - // case AvState::C0x08: + case AvState::PauseOnEOF: case AvState::Starting: case AvState::Error: return false; @@ -551,4 +622,70 @@ bool AvPlayerState::IsStateTransitionValid(AvState state) { } } +u64 AvPlayerTimer::Now() { + auto now = Kernel::sceKernelGetProcessTimeCounter(); + const auto frequency = Kernel::sceKernelGetProcessTimeCounterFrequency(); + if (frequency != 0) { + now = ((now % frequency) * 1'000'000) / frequency + (now / frequency) * 1'000'000; + } + return now / 100; +} + +void AvPlayerTimer::Update() { + UpdateAPts(m_v_hint_pts); +} + +void AvPlayerTimer::UpdateAPts(u64 timestamp) { + const auto now = Now(); + + m_last_update_pts = now; + m_a_pts = timestamp; + m_ts_diff = now - m_a_pts; +} + +void AvPlayerTimer::UpdateVPts() { + const auto now = Now(); + + m_last_update_pts = now; + m_v_pts = now; + m_ts_diff = now - m_a_pts; +} + +void AvPlayerTimer::UpdateVHintPts(u64 hint) { + const auto now = Now(); + + m_v_pts = now; + m_v_hint_pts = hint; +} + +void AvPlayerTimer::Reset() { + m_ts_diff = -1; + m_v_pts = -1; + m_v_hint_pts = -1; + m_last_update_pts = 0; + m_a_pts = 0; +} + +AvPlayerTimer::State AvPlayerTimer::GetState(AvPlayerAvSyncMode sync_mode) { + if (m_ts_diff == -1 || m_v_hint_pts == -1) { + return State::Error; + } + + if (sync_mode == AvPlayerAvSyncMode::None) { + return State::Ok; + } + + const s64 diff = (Now() - m_last_update_pts) + (m_a_pts - m_v_hint_pts); + if (diff > 2800) { + return State::VideoBehind; + } + if (diff < -6900) { + return State::VideoAhead; + } + if (diff < 200) { + return State::WaitForSync; + } + return State::Ok; +} + } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/avplayer/avplayer_state.h b/src/core/libraries/avplayer/avplayer_state.h index c67855c89..4bab2b414 100644 --- a/src/core/libraries/avplayer/avplayer_state.h +++ b/src/core/libraries/avplayer/avplayer_state.h @@ -16,6 +16,33 @@ namespace Libraries::AvPlayer { class Stream; class AvDecoder; +class AvPlayerTimer { +public: + enum class State { + Ok, + WaitForSync, + VideoAhead, + VideoBehind, + Error, + }; + + void Update(); + void UpdateAPts(u64 timestamp); + void UpdateVHintPts(u64 hint); + void UpdateVPts(); + void Reset(); + State GetState(AvPlayerAvSyncMode sync_mode); + +private: + static u64 Now(); + + std::atomic m_ts_diff = -1; + std::atomic m_v_pts = -1; + std::atomic m_v_hint_pts = -1; + std::atomic m_last_update_pts = 0; + std::atomic m_a_pts = 0; +}; + class AvPlayerState : public AvPlayerStateCallback { public: AvPlayerState(const AvPlayerInitData& init_data); @@ -23,7 +50,7 @@ public: void PostInit(const AvPlayerPostInitData& post_init_data); bool AddSource(std::string_view filename, AvPlayerSourceType source_type); - s32 GetStreamCount(); + u32 GetStreamCount(); bool GetStreamInfo(u32 stream_index, AvPlayerStreamInfo& info); bool EnableStream(u32 stream_index); bool Start(); @@ -49,6 +76,7 @@ private: AvPlayerAvSyncMode GetSyncMode() override; void OnWarning(u32 id) override; void OnError() override; + void OnLoop() override; void OnEOF() override; void OnPlaybackStateChanged(AvState state); @@ -59,6 +87,7 @@ private: void AvControllerThread(std::stop_token stop); + void InitFilters(); void AddSourceEvent(); void WarningEvent(s32 id); @@ -78,6 +107,7 @@ private: std::atomic m_current_state; std::atomic m_previous_state; + AvPlayerTimer m_timer; u32 m_thread_priority; u32 m_thread_affinity; std::atomic_uint32_t m_some_event_result{}; @@ -87,6 +117,9 @@ private: std::mutex m_event_handler_mutex{}; Kernel::Thread m_controller_thread{}; AvPlayerQueue m_event_queue{}; + + std::mutex m_stream_infos_mutex; + std::vector m_stream_infos; }; } // namespace Libraries::AvPlayer diff --git a/src/core/libraries/kernel/time.cpp b/src/core/libraries/kernel/time.cpp index 2fe74d0a3..ae3e05ae4 100644 --- a/src/core/libraries/kernel/time.cpp +++ b/src/core/libraries/kernel/time.cpp @@ -28,6 +28,7 @@ namespace Libraries::Kernel { static u64 initial_ptc; +static u64 initial_unbiased_ptc; static std::unique_ptr clock; u64 PS4_SYSV_ABI sceKernelGetTscFrequency() { @@ -35,12 +36,11 @@ u64 PS4_SYSV_ABI sceKernelGetTscFrequency() { } u64 PS4_SYSV_ABI sceKernelGetProcessTime() { - // TODO: this timer should support suspends, so initial ptc needs to be updated on wake up - return clock->GetTimeUS(initial_ptc); + return clock->GetTimeUS(clock->GetUnbiasedUptime() - initial_unbiased_ptc); } u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter() { - return clock->GetUptime() - initial_ptc; + return clock->GetUnbiasedUptime() - initial_unbiased_ptc; } u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency() { @@ -511,6 +511,7 @@ s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, void RegisterTime(Core::Loader::SymbolsResolver* sym) { clock = std::make_unique(); initial_ptc = clock->GetUptime(); + initial_unbiased_ptc = clock->GetUnbiasedUptime(); // POSIX LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);