From 2d354a095ae41cf58d72cf8ec88fffcd84dd4d68 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Tue, 27 Aug 2024 09:32:42 +0300 Subject: [PATCH] AvPlayer: Handle Initialization errors --- .../avplayer/avplayer_data_streamer.h | 3 + .../avplayer/avplayer_file_streamer.cpp | 30 +++++---- .../avplayer/avplayer_file_streamer.h | 4 +- src/core/libraries/avplayer/avplayer_impl.cpp | 9 ++- .../libraries/avplayer/avplayer_source.cpp | 64 +++++++++++-------- src/core/libraries/avplayer/avplayer_source.h | 8 +-- .../libraries/avplayer/avplayer_state.cpp | 37 +++++++---- src/core/libraries/avplayer/avplayer_state.h | 6 +- 8 files changed, 95 insertions(+), 66 deletions(-) diff --git a/src/core/libraries/avplayer/avplayer_data_streamer.h b/src/core/libraries/avplayer/avplayer_data_streamer.h index 04097bb4..319c88a9 100644 --- a/src/core/libraries/avplayer/avplayer_data_streamer.h +++ b/src/core/libraries/avplayer/avplayer_data_streamer.h @@ -7,6 +7,8 @@ #include "common/types.h" +#include + struct AVIOContext; namespace Libraries::AvPlayer { @@ -14,6 +16,7 @@ namespace Libraries::AvPlayer { class IDataStreamer { public: virtual ~IDataStreamer() = default; + virtual bool Init(std::string_view path) = 0; virtual AVIOContext* GetContext() = 0; }; diff --git a/src/core/libraries/avplayer/avplayer_file_streamer.cpp b/src/core/libraries/avplayer/avplayer_file_streamer.cpp index dc1386a4..c7bd5b5d 100644 --- a/src/core/libraries/avplayer/avplayer_file_streamer.cpp +++ b/src/core/libraries/avplayer/avplayer_file_streamer.cpp @@ -18,19 +18,8 @@ extern "C" { namespace Libraries::AvPlayer { -AvPlayerFileStreamer::AvPlayerFileStreamer(const SceAvPlayerFileReplacement& file_replacement, - std::string_view path) - : m_file_replacement(file_replacement) { - const auto ptr = m_file_replacement.object_ptr; - m_fd = m_file_replacement.open(ptr, path.data()); - ASSERT(m_fd >= 0); - m_file_size = m_file_replacement.size(ptr); - // avio_buffer is deallocated in `avio_context_free` - const auto avio_buffer = reinterpret_cast(av_malloc(AVPLAYER_AVIO_BUFFER_SIZE)); - m_avio_context = - avio_alloc_context(avio_buffer, AVPLAYER_AVIO_BUFFER_SIZE, 0, this, - &AvPlayerFileStreamer::ReadPacket, nullptr, &AvPlayerFileStreamer::Seek); -} +AvPlayerFileStreamer::AvPlayerFileStreamer(const SceAvPlayerFileReplacement& file_replacement) + : m_file_replacement(file_replacement) {} AvPlayerFileStreamer::~AvPlayerFileStreamer() { if (m_avio_context != nullptr) { @@ -43,6 +32,21 @@ AvPlayerFileStreamer::~AvPlayerFileStreamer() { } } +bool AvPlayerFileStreamer::Init(std::string_view path) { + const auto ptr = m_file_replacement.object_ptr; + m_fd = m_file_replacement.open(ptr, path.data()); + if (m_fd < 0) { + return false; + } + m_file_size = m_file_replacement.size(ptr); + // avio_buffer is deallocated in `avio_context_free` + const auto avio_buffer = reinterpret_cast(av_malloc(AVPLAYER_AVIO_BUFFER_SIZE)); + m_avio_context = + avio_alloc_context(avio_buffer, AVPLAYER_AVIO_BUFFER_SIZE, 0, this, + &AvPlayerFileStreamer::ReadPacket, nullptr, &AvPlayerFileStreamer::Seek); + return true; +} + s32 AvPlayerFileStreamer::ReadPacket(void* opaque, u8* buffer, s32 size) { const auto self = reinterpret_cast(opaque); if (self->m_position >= self->m_file_size) { diff --git a/src/core/libraries/avplayer/avplayer_file_streamer.h b/src/core/libraries/avplayer/avplayer_file_streamer.h index 658ce8c1..034e40dd 100644 --- a/src/core/libraries/avplayer/avplayer_file_streamer.h +++ b/src/core/libraries/avplayer/avplayer_file_streamer.h @@ -15,9 +15,11 @@ namespace Libraries::AvPlayer { class AvPlayerFileStreamer : public IDataStreamer { public: - AvPlayerFileStreamer(const SceAvPlayerFileReplacement& file_replacement, std::string_view path); + AvPlayerFileStreamer(const SceAvPlayerFileReplacement& file_replacement); ~AvPlayerFileStreamer(); + bool Init(std::string_view path) override; + AVIOContext* GetContext() override { return m_avio_context; } diff --git a/src/core/libraries/avplayer/avplayer_impl.cpp b/src/core/libraries/avplayer/avplayer_impl.cpp index cdfff827..6de7b4c2 100644 --- a/src/core/libraries/avplayer/avplayer_impl.cpp +++ b/src/core/libraries/avplayer/avplayer_impl.cpp @@ -110,7 +110,7 @@ s32 AvPlayer::AddSource(std::string_view path) { if (path.empty()) { return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS; } - if (AVPLAYER_IS_ERROR(m_state->AddSource(path, GetSourceType(path)))) { + if (!m_state->AddSource(path, GetSourceType(path))) { return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; } return ORBIS_OK; @@ -128,7 +128,7 @@ s32 AvPlayer::GetStreamCount() { } s32 AvPlayer::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { - if (AVPLAYER_IS_ERROR(m_state->GetStreamInfo(stream_index, info))) { + if (!m_state->GetStreamInfo(stream_index, info)) { return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; } return ORBIS_OK; @@ -145,7 +145,10 @@ s32 AvPlayer::EnableStream(u32 stream_index) { } s32 AvPlayer::Start() { - return m_state->Start(); + if (!m_state->Start()) { + return ORBIS_AVPLAYER_ERROR_OPERATION_FAILED; + } + return ORBIS_OK; } bool AvPlayer::GetVideoData(SceAvPlayerFrameInfo& video_info) { diff --git a/src/core/libraries/avplayer/avplayer_source.cpp b/src/core/libraries/avplayer/avplayer_source.cpp index 2e4ea8aa..99ba2e8b 100644 --- a/src/core/libraries/avplayer/avplayer_source.cpp +++ b/src/core/libraries/avplayer/avplayer_source.cpp @@ -24,31 +24,39 @@ namespace Libraries::AvPlayer { using namespace Kernel; -AvPlayerSource::AvPlayerSource(AvPlayerStateCallback& state, std::string_view path, - const SceAvPlayerInitData& init_data, - SceAvPlayerSourceType source_type) - : m_state(state), m_memory_replacement(init_data.memory_replacement), - m_num_output_video_framebuffers( - std::min(std::max(2, init_data.num_output_video_framebuffers), 16)) { - AVFormatContext* context = avformat_alloc_context(); - if (init_data.file_replacement.open != nullptr) { - m_up_data_streamer = - std::make_unique(init_data.file_replacement, path); - context->pb = m_up_data_streamer->GetContext(); - ASSERT(!AVPLAYER_IS_ERROR(avformat_open_input(&context, nullptr, nullptr, nullptr))); - } else { - const auto mnt = Common::Singleton::Instance(); - const auto filepath = mnt->GetHostPath(path); - ASSERT(!AVPLAYER_IS_ERROR( - avformat_open_input(&context, filepath.string().c_str(), nullptr, nullptr))); - } - m_avformat_context = AVFormatContextPtr(context, &ReleaseAVFormatContext); -} +AvPlayerSource::AvPlayerSource(AvPlayerStateCallback& state) : m_state(state) {} AvPlayerSource::~AvPlayerSource() { Stop(); } +bool AvPlayerSource::Init(const SceAvPlayerInitData& 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); + + AVFormatContext* context = avformat_alloc_context(); + if (init_data.file_replacement.open != nullptr) { + m_up_data_streamer = std::make_unique(init_data.file_replacement); + if (!m_up_data_streamer->Init(path)) { + return false; + } + context->pb = m_up_data_streamer->GetContext(); + if (AVPLAYER_IS_ERROR(avformat_open_input(&context, nullptr, nullptr, nullptr))) { + return false; + } + } else { + const auto mnt = Common::Singleton::Instance(); + const auto filepath = mnt->GetHostPath(path); + if (AVPLAYER_IS_ERROR( + avformat_open_input(&context, filepath.string().c_str(), nullptr, nullptr))) { + return false; + } + } + m_avformat_context = AVFormatContextPtr(context, &ReleaseAVFormatContext); + return true; +} + bool AvPlayerSource::FindStreamInfo() { if (m_avformat_context == nullptr) { LOG_ERROR(Lib_AvPlayer, "Could not find stream info. NULL context."); @@ -87,16 +95,16 @@ static f32 AVRationalToF32(const AVRational rational) { return f32(rational.num) / rational.den; } -s32 AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { +bool AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& 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); - return -1; + return false; } const auto p_stream = m_avformat_context->streams[stream_index]; if (p_stream == nullptr || p_stream->codecpar == nullptr) { LOG_ERROR(Lib_AvPlayer, "Could not get stream {} info. NULL stream.", stream_index); - return -1; + return false; } info.type = CodecTypeToStreamType(p_stream->codecpar->codec_type); info.start_time = p_stream->start_time; @@ -140,9 +148,9 @@ s32 AvPlayerSource::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) break; default: LOG_ERROR(Lib_AvPlayer, "Stream {} type is unknown: {}.", stream_index, info.type); - return -1; + return false; } - return 0; + return true; } bool AvPlayerSource::EnableStream(u32 stream_index) { @@ -215,12 +223,12 @@ std::optional AvPlayerSource::HasFrames(u32 num_frames) { return m_video_packets.Size() > num_frames || m_is_eof; } -s32 AvPlayerSource::Start() { +bool AvPlayerSource::Start() { std::unique_lock lock(m_state_mutex); if (m_audio_codec_context == nullptr && m_video_codec_context == nullptr) { LOG_ERROR(Lib_AvPlayer, "Could not start playback. NULL context."); - return -1; + return false; } m_demuxer_thread = std::jthread([this](std::stop_token stop) { this->DemuxerThread(stop); }); m_video_decoder_thread = @@ -228,7 +236,7 @@ s32 AvPlayerSource::Start() { m_audio_decoder_thread = std::jthread([this](std::stop_token stop) { this->AudioDecoderThread(stop); }); m_start_time = std::chrono::high_resolution_clock::now(); - return 0; + return true; } bool AvPlayerSource::Stop() { diff --git a/src/core/libraries/avplayer/avplayer_source.h b/src/core/libraries/avplayer/avplayer_source.h index 7144e7ee..90612214 100644 --- a/src/core/libraries/avplayer/avplayer_source.h +++ b/src/core/libraries/avplayer/avplayer_source.h @@ -120,17 +120,17 @@ private: class AvPlayerSource { public: - AvPlayerSource(AvPlayerStateCallback& state, std::string_view path, - const SceAvPlayerInitData& init_data, SceAvPlayerSourceType source_type); + AvPlayerSource(AvPlayerStateCallback& state); ~AvPlayerSource(); + bool Init(const SceAvPlayerInitData& init_data, std::string_view path); bool FindStreamInfo(); s32 GetStreamCount(); - s32 GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); + bool GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); bool EnableStream(u32 stream_index); void SetLooping(bool is_looping); std::optional HasFrames(u32 num_frames); - s32 Start(); + bool Start(); bool Stop(); bool GetAudioData(SceAvPlayerFrameInfo& audio_info); bool GetVideoData(SceAvPlayerFrameInfo& video_info); diff --git a/src/core/libraries/avplayer/avplayer_state.cpp b/src/core/libraries/avplayer/avplayer_state.cpp index cb3be2f5..a512063f 100644 --- a/src/core/libraries/avplayer/avplayer_state.cpp +++ b/src/core/libraries/avplayer/avplayer_state.cpp @@ -24,6 +24,7 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, s32 event_i s32 timedtext_stream_index = -1; const s32 stream_count = self->GetStreamCount(); if (AVPLAYER_IS_ERROR(stream_count)) { + self->Stop(); return; } if (stream_count == 0) { @@ -32,7 +33,10 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, s32 event_i } for (u32 stream_index = 0; stream_index < stream_count; ++stream_index) { SceAvPlayerStreamInfo info{}; - self->GetStreamInfo(stream_index, info); + if (!self->GetStreamInfo(stream_index, info)) { + self->Stop(); + return; + } const std::string_view default_language( reinterpret_cast(self->m_default_language)); @@ -116,23 +120,28 @@ AvPlayerState::~AvPlayerState() { } // Called inside GAME thread -s32 AvPlayerState::AddSource(std::string_view path, SceAvPlayerSourceType source_type) { +bool AvPlayerState::AddSource(std::string_view path, SceAvPlayerSourceType source_type) { if (path.empty()) { LOG_ERROR(Lib_AvPlayer, "File path is empty."); - return -1; + return false; } { std::unique_lock lock(m_source_mutex); if (m_up_source != nullptr) { LOG_ERROR(Lib_AvPlayer, "Only one source is supported."); - return -1; + return false; } - m_up_source = std::make_unique(*this, path, m_init_data, source_type); + m_up_source = std::make_unique(*this); + if (!m_up_source->Init(m_init_data, path)) { + SetState(AvState::Error); + m_up_source.reset(); + return false; + } } AddSourceEvent(); - return 0; + return true; } // Called inside GAME thread @@ -146,25 +155,25 @@ s32 AvPlayerState::GetStreamCount() { } // Called inside GAME thread -s32 AvPlayerState::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info) { +bool AvPlayerState::GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& 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); - return -1; + return false; } return m_up_source->GetStreamInfo(stream_index, info); } // Called inside GAME thread -s32 AvPlayerState::Start() { +bool AvPlayerState::Start() { std::shared_lock lock(m_source_mutex); - if (m_up_source == nullptr || m_up_source->Start() < 0) { + if (m_up_source == nullptr || !m_up_source->Start()) { LOG_ERROR(Lib_AvPlayer, "Could not start playback."); - return -1; + return false; } SetState(AvState::Play); OnPlaybackStateChanged(AvState::Play); - return 0; + return true; } void AvPlayerState::AvControllerThread(std::stop_token stop) { @@ -219,10 +228,10 @@ bool AvPlayerState::Stop() { if (m_up_source == nullptr || m_current_state == AvState::Stop) { return false; } - if (!SetState(AvState::Stop)) { + if (!m_up_source->Stop()) { return false; } - if (!m_up_source->Stop()) { + if (!SetState(AvState::Stop)) { return false; } OnPlaybackStateChanged(AvState::Stop); diff --git a/src/core/libraries/avplayer/avplayer_state.h b/src/core/libraries/avplayer/avplayer_state.h index ff80b6ce..a5a3bd68 100644 --- a/src/core/libraries/avplayer/avplayer_state.h +++ b/src/core/libraries/avplayer/avplayer_state.h @@ -24,11 +24,11 @@ public: AvPlayerState(const SceAvPlayerInitData& init_data); ~AvPlayerState(); - s32 AddSource(std::string_view filename, SceAvPlayerSourceType source_type); + bool AddSource(std::string_view filename, SceAvPlayerSourceType source_type); s32 GetStreamCount(); - s32 GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); + bool GetStreamInfo(u32 stream_index, SceAvPlayerStreamInfo& info); bool EnableStream(u32 stream_index); - s32 Start(); + bool Start(); bool Stop(); bool GetAudioData(SceAvPlayerFrameInfo& audio_info); bool GetVideoData(SceAvPlayerFrameInfo& video_info);