Qt: play SND0.AT3 in game lists when a movie would play

This commit is contained in:
Megamouse 2026-03-10 05:33:55 +01:00
parent 71f0d5c602
commit ba95ae25fb
9 changed files with 140 additions and 7 deletions

View file

@ -8,6 +8,7 @@ struct GameInfo
std::string path;
std::string icon_path;
std::string movie_path;
std::string audio_path;
std::string name;
std::string serial;

View file

@ -637,6 +637,12 @@ void game_list_frame::OnParsingFinished()
game.has_hover_pam = true;
}
if (std::string audio_path = sfo_dir + "/SND0.AT3"; file_exists(audio_path))
{
game.info.audio_path = std::move(audio_path);
game.has_audio_file = true;
}
const QString serial = QString::fromStdString(game.info.serial);
m_games_mutex.lock();

View file

@ -109,11 +109,23 @@ void game_list_grid::populate(
}
});
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam || game->has_audio_file))
{
item->set_video_path(game->info.movie_path);
bool check_iso = false;
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
if (game->has_hover_gif || game->has_hover_pam)
{
item->set_video_path(game->info.movie_path);
check_iso |= !fs::exists(game->info.movie_path);
}
if (game->has_audio_file)
{
item->set_audio_path(game->info.audio_path);
check_iso |= !fs::exists(game->info.audio_path);
}
if (check_iso && is_file_iso(game->info.path))
{
item->set_iso_path(game->info.path);
}

View file

@ -299,11 +299,23 @@ void game_list_table::populate(
}
});
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam || game->has_audio_file))
{
icon_item->set_video_path(game->info.movie_path);
bool check_iso = false;
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
if (game->has_hover_gif || game->has_hover_pam)
{
icon_item->set_video_path(game->info.movie_path);
check_iso |= !fs::exists(game->info.movie_path);
}
if (game->has_audio_file)
{
icon_item->set_audio_path(game->info.audio_path);
check_iso |= !fs::exists(game->info.audio_path);
}
if (check_iso && is_file_iso(game->info.path))
{
icon_item->set_iso_path(game->info.path);
}

View file

@ -21,6 +21,7 @@ struct gui_game_info
bool has_custom_icon = false;
bool has_hover_gif = false;
bool has_hover_pam = false;
bool has_audio_file = false;
bool icon_in_archive = false;
movie_item_base* item = nullptr;

View file

@ -1,11 +1,19 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "qt_video_source.h"
#include "Loader/ISO.h"
#include <QAudioOutput>
#include <QFile>
static video_source* s_audio_source = nullptr;
static std::unique_ptr<QMediaPlayer> s_audio_player = nullptr;
static std::unique_ptr<QAudioOutput> s_audio_output = nullptr;
static std::unique_ptr<QBuffer> s_audio_buffer = nullptr;
static std::unique_ptr<QByteArray> s_audio_data = nullptr;
qt_video_source::qt_video_source()
: video_source()
{
@ -21,6 +29,11 @@ void qt_video_source::set_video_path(const std::string& video_path)
m_video_path = QString::fromStdString(video_path);
}
void qt_video_source::set_audio_path(const std::string& audio_path)
{
m_audio_path = QString::fromStdString(audio_path);
}
void qt_video_source::set_iso_path(const std::string& iso_path)
{
m_iso_path = iso_path;
@ -89,7 +102,6 @@ void qt_video_source::init_movie()
m_video_buffer = std::make_unique<QBuffer>(&m_video_data);
m_video_buffer->open(QIODevice::ReadOnly);
m_movie = std::make_unique<QMovie>(m_video_buffer.get());
}
if (!m_movie->isValid())
@ -179,6 +191,8 @@ void qt_video_source::start_movie()
m_media_player->play();
}
start_audio();
m_active = true;
}
@ -196,6 +210,71 @@ void qt_video_source::stop_movie()
m_media_player.reset();
m_video_buffer.reset();
m_video_data.clear();
stop_audio();
}
void qt_video_source::start_audio()
{
if (m_audio_path.isEmpty() || s_audio_source == this) return;
if (!s_audio_player)
{
s_audio_output = std::make_unique<QAudioOutput>();
s_audio_player = std::make_unique<QMediaPlayer>();
s_audio_player->setAudioOutput(s_audio_output.get());
}
if (m_iso_path.empty())
{
s_audio_player->setSource(QUrl::fromLocalFile(m_audio_path));
}
else
{
iso_archive archive(m_iso_path);
auto audio_file = archive.open(m_audio_path.toStdString());
const auto audio_size = audio_file.size();
if (audio_size == 0) return;
std::unique_ptr<QByteArray> old_audio_data = std::move(s_audio_data);
s_audio_data = std::make_unique<QByteArray>(audio_size, 0);
audio_file.read(s_audio_data->data(), audio_size);
if (!s_audio_buffer)
{
s_audio_buffer = std::make_unique<QBuffer>();
}
s_audio_buffer->setBuffer(s_audio_data.get());
s_audio_buffer->open(QIODevice::ReadOnly);
s_audio_player->setSourceDevice(s_audio_buffer.get());
if (old_audio_data)
{
old_audio_data.reset();
}
}
s_audio_output->setVolume(g_cfg.audio.volume.get() / 100.0f);
s_audio_player->play();
s_audio_source = this;
}
void qt_video_source::stop_audio()
{
if (s_audio_source != this) return;
s_audio_source = nullptr;
if (s_audio_player)
{
s_audio_player->stop();
s_audio_player.reset();
}
s_audio_output.reset();
s_audio_buffer.reset();
s_audio_data.reset();
}
QPixmap qt_video_source::get_movie_image(const QVideoFrame& frame) const
@ -288,6 +367,14 @@ void qt_video_source_wrapper::set_video_path(const std::string& video_path)
});
}
void qt_video_source_wrapper::set_audio_path(const std::string& audio_path)
{
Emu.CallFromMainThread([this, path = audio_path]()
{
// TODO
});
}
void qt_video_source_wrapper::set_active(bool active)
{
Emu.CallFromMainThread([this, active]()

View file

@ -19,7 +19,9 @@ public:
void set_iso_path(const std::string& iso_path);
void set_video_path(const std::string& video_path) override;
void set_audio_path(const std::string& audio_path) override;
const QString& video_path() const { return m_video_path; }
const QString& audio_path() const { return m_audio_path; }
void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) override;
bool has_new() const override { return m_has_new; }
@ -30,6 +32,9 @@ public:
void start_movie();
void stop_movie();
void start_audio();
void stop_audio();
QPixmap get_movie_image(const QVideoFrame& frame) const;
void image_change_callback(const QVideoFrame& frame = {}) const;
@ -44,6 +49,7 @@ protected:
atomic_t<bool> m_has_new = false;
QString m_video_path;
QString m_audio_path;
std::string m_iso_path; // path of the source archive
QByteArray m_video_data{};
QImage m_image{};
@ -67,6 +73,7 @@ public:
virtual ~qt_video_source_wrapper();
void set_video_path(const std::string& video_path) override;
void set_audio_path(const std::string& audio_path) override;
void set_active(bool active) override;
bool get_active() const override;
bool has_new() const override { return m_qt_video_source && m_qt_video_source->has_new(); }

View file

@ -360,6 +360,11 @@ void save_manager_dialog::UpdateList()
icon_item->set_video_path(movie_path);
}
if (const std::string audio_path = dir_path + "SND0.AT3"; fs::is_file(audio_path))
{
icon_item->set_audio_path(audio_path);
}
icon_item->set_image_change_callback([this, icon_item](const QVideoFrame& frame)
{
if (!icon_item)
@ -686,6 +691,7 @@ void save_manager_dialog::UpdateDetails()
const SaveDataEntry& save = ::at32(m_save_entries, idx);
m_details_icon->set_video_path(icon_item->video_path().toStdString());
m_details_icon->set_audio_path(icon_item->audio_path().toStdString());
m_details_icon->set_thumbnail(icon_item->data(SaveUserRole::Pixmap).value<QPixmap>());
m_details_icon->set_active(false);

View file

@ -9,6 +9,7 @@ public:
video_source() {};
virtual ~video_source() {};
virtual void set_video_path(const std::string& video_path) = 0;
virtual void set_audio_path(const std::string& audio_path) = 0;
virtual void set_active(bool active) = 0;
virtual bool get_active() const = 0;
virtual bool has_new() const = 0;