AvPlayer: Handle Initialization errors
This commit is contained in:
parent
af4356bfe1
commit
2d354a095a
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "common/types.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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<u8*>(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<u8*>(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<AvPlayerFileStreamer*>(opaque);
|
||||
if (self->m_position >= self->m_file_size) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<AvPlayerFileStreamer>(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<Core::FileSys::MntPoints>::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<AvPlayerFileStreamer>(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<Core::FileSys::MntPoints>::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<bool> 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() {
|
||||
|
|
|
@ -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<bool> HasFrames(u32 num_frames);
|
||||
s32 Start();
|
||||
bool Start();
|
||||
bool Stop();
|
||||
bool GetAudioData(SceAvPlayerFrameInfo& audio_info);
|
||||
bool GetVideoData(SceAvPlayerFrameInfo& video_info);
|
||||
|
|
|
@ -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<char*>(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<AvPlayerSource>(*this, path, m_init_data, source_type);
|
||||
m_up_source = std::make_unique<AvPlayerSource>(*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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue