mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
Use system FFmpeg for VP9 playback on Linux
This commit is contained in:
@@ -289,9 +289,15 @@ jobs:
|
|||||||
clang \
|
clang \
|
||||||
glslang-tools \
|
glslang-tools \
|
||||||
libasound2-dev \
|
libasound2-dev \
|
||||||
|
libavcodec-dev \
|
||||||
|
libavfilter-dev \
|
||||||
|
libavformat-dev \
|
||||||
|
libavutil-dev \
|
||||||
libdbus-1-dev \
|
libdbus-1-dev \
|
||||||
libgl1-mesa-dev \
|
libgl1-mesa-dev \
|
||||||
libpulse-dev \
|
libpulse-dev \
|
||||||
|
libswresample-dev \
|
||||||
|
libswscale-dev \
|
||||||
libudev-dev \
|
libudev-dev \
|
||||||
libwayland-dev \
|
libwayland-dev \
|
||||||
libx11-dev \
|
libx11-dev \
|
||||||
@@ -304,6 +310,7 @@ jobs:
|
|||||||
libxss-dev \
|
libxss-dev \
|
||||||
lld \
|
lld \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
|
pkg-config \
|
||||||
wayland-protocols
|
wayland-protocols
|
||||||
|
|
||||||
- name: Install Qt 6.10.3
|
- name: Install Qt 6.10.3
|
||||||
|
|||||||
Vendored
+7
@@ -88,6 +88,13 @@ set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "" FORCE)
|
|||||||
set(SPDLOG_NO_EXCEPTIONS ON CACHE BOOL "" FORCE)
|
set(SPDLOG_NO_EXCEPTIONS ON CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(spdlog EXCLUDE_FROM_ALL)
|
add_subdirectory(spdlog EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
if (NOT TARGET FFmpeg::ffmpeg AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET GLOBAL
|
||||||
|
libavformat libavcodec libswscale libavutil libavfilter libswresample)
|
||||||
|
add_library(FFmpeg::ffmpeg ALIAS PkgConfig::FFMPEG)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT TARGET FFmpeg::ffmpeg)
|
if (NOT TARGET FFmpeg::ffmpeg)
|
||||||
# On macOS the target arch is driven by CMAKE_OSX_ARCHITECTURES, not the host
|
# On macOS the target arch is driven by CMAKE_OSX_ARCHITECTURES, not the host
|
||||||
# CMAKE_SYSTEM_PROCESSOR (which reports arm64 even for an x86_64/Rosetta build).
|
# CMAKE_SYSTEM_PROCESSOR (which reports arm64 even for an x86_64/Rosetta build).
|
||||||
|
|||||||
+1
-15
@@ -317,24 +317,10 @@ endif()
|
|||||||
|
|
||||||
set(kyty_emulator_link_libraries common Vulkan::Headers spirv-tools-opt spirv-tools SDL2-static imgui xxhash FFmpeg::ffmpeg fmt::fmt nlohmann_json::nlohmann_json LibAtrac9 kyty_git_version Zydis::Zydis xbyak::xbyak)
|
set(kyty_emulator_link_libraries common Vulkan::Headers spirv-tools-opt spirv-tools SDL2-static imgui xxhash FFmpeg::ffmpeg fmt::fmt nlohmann_json::nlohmann_json LibAtrac9 kyty_git_version Zydis::Zydis xbyak::xbyak)
|
||||||
|
|
||||||
# Linux system libraries required by the static FFmpeg archive.
|
# Linux system libraries.
|
||||||
if(LINUX)
|
if(LINUX)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
list(APPEND kyty_emulator_link_libraries m ${CMAKE_DL_LIBS} Threads::Threads)
|
list(APPEND kyty_emulator_link_libraries m ${CMAKE_DL_LIBS} Threads::Threads)
|
||||||
|
|
||||||
# Optional FFmpeg dependencies.
|
|
||||||
find_package(ZLIB)
|
|
||||||
if(ZLIB_FOUND)
|
|
||||||
list(APPEND kyty_emulator_link_libraries ZLIB::ZLIB)
|
|
||||||
endif()
|
|
||||||
find_library(KYTY_BZ2_LIBRARY bz2)
|
|
||||||
if(KYTY_BZ2_LIBRARY)
|
|
||||||
list(APPEND kyty_emulator_link_libraries ${KYTY_BZ2_LIBRARY})
|
|
||||||
endif()
|
|
||||||
find_library(KYTY_LZMA_LIBRARY lzma)
|
|
||||||
if(KYTY_LZMA_LIBRARY)
|
|
||||||
list(APPEND kyty_emulator_link_libraries ${KYTY_LZMA_LIBRARY})
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(inc_headers
|
set(inc_headers
|
||||||
|
|||||||
@@ -165,13 +165,14 @@ The finished application and its runtime dependencies will be placed in
|
|||||||
|
|
||||||
### Building on Linux
|
### Building on Linux
|
||||||
|
|
||||||
Install the toolchain and the libraries the bundled SDL2 needs. Without the audio, Wayland and
|
Install the toolchain, system FFmpeg, and the libraries the bundled SDL2 needs. Without the audio, Wayland and
|
||||||
udev development packages SDL2 quietly configures itself without those backends, and the resulting
|
udev development packages SDL2 quietly configures itself without those backends, and the resulting
|
||||||
build has no working sound and no gamepad hotplug:
|
build has no working sound and no gamepad hotplug:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install --no-install-recommends \
|
sudo apt-get install --no-install-recommends \
|
||||||
clang lld ninja-build cmake git glslang-tools \
|
clang lld ninja-build cmake git glslang-tools pkg-config \
|
||||||
|
libavformat-dev libavcodec-dev libswscale-dev libavutil-dev libavfilter-dev libswresample-dev \
|
||||||
libgl1-mesa-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev \
|
libgl1-mesa-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev \
|
||||||
libxi-dev libxrandr-dev libxss-dev libxkbcommon-dev \
|
libxi-dev libxrandr-dev libxss-dev libxkbcommon-dev \
|
||||||
libasound2-dev libpulse-dev libudev-dev libdbus-1-dev libwayland-dev wayland-protocols
|
libasound2-dev libpulse-dev libudev-dev libdbus-1-dev libwayland-dev wayland-protocols
|
||||||
@@ -192,7 +193,8 @@ cmake --install _Build/linux --prefix _Build/linux/install
|
|||||||
```
|
```
|
||||||
|
|
||||||
The install step copies the Qt libraries and plugins next to the binaries, so
|
The install step copies the Qt libraries and plugins next to the binaries, so
|
||||||
`_Build/linux/install` runs without a matching system Qt.
|
`_Build/linux/install` runs without a matching system Qt. The emulator still requires
|
||||||
|
the system FFmpeg runtime libraries matching those used to build it.
|
||||||
|
|
||||||
As on Windows, the MSVC compiler is not used; Clang is required. `cl.exe` is rejected at configure
|
As on Windows, the MSVC compiler is not used; Clang is required. `cl.exe` is rejected at configure
|
||||||
time.
|
time.
|
||||||
|
|||||||
+12
-2
@@ -384,6 +384,16 @@ static bool codec_is_supported_for_source(AvPlayerSourceType source_type, AVMedi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const AVCodec* find_decoder(AVCodecID codec_id) {
|
||||||
|
const auto* decoder = avcodec_find_decoder(codec_id);
|
||||||
|
if (decoder == nullptr && codec_id == AV_CODEC_ID_VP9) {
|
||||||
|
Log::WriteToConsoleAndLog(
|
||||||
|
"WARNING: AvPlayer: The game requested VP9 video, but FFmpeg has no VP9 "
|
||||||
|
"decoder. Use FFmpeg with VP9 decoding enabled.\n");
|
||||||
|
}
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
struct PacketDeleter {
|
struct PacketDeleter {
|
||||||
void operator()(AVPacket* packet) const { av_packet_free(&packet); }
|
void operator()(AVPacket* packet) const { av_packet_free(&packet); }
|
||||||
};
|
};
|
||||||
@@ -1064,7 +1074,7 @@ private:
|
|||||||
static_cast<int>(s->codecpar->codec_id), static_cast<uint32_t>(source_type));
|
static_cast<int>(s->codecpar->codec_id), static_cast<uint32_t>(source_type));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (avcodec_find_decoder(s->codecpar->codec_id) == nullptr) {
|
if (find_decoder(s->codecpar->codec_id) == nullptr) {
|
||||||
LOGF("\t decoder not found: stream=%d codec=%d\n", id,
|
LOGF("\t decoder not found: stream=%d codec=%d\n", id,
|
||||||
static_cast<int>(s->codecpar->codec_id));
|
static_cast<int>(s->codecpar->codec_id));
|
||||||
return false;
|
return false;
|
||||||
@@ -1073,7 +1083,7 @@ private:
|
|||||||
}
|
}
|
||||||
bool OpenCodec(int id, AVCodecContext** out) {
|
bool OpenCodec(int id, AVCodecContext** out) {
|
||||||
auto* s = fmt->streams[id];
|
auto* s = fmt->streams[id];
|
||||||
auto* dec = avcodec_find_decoder(s->codecpar->codec_id);
|
auto* dec = find_decoder(s->codecpar->codec_id);
|
||||||
if (dec == nullptr) {
|
if (dec == nullptr) {
|
||||||
LOGF("\t avcodec_find_decoder failed: stream=%d codec=%d\n", id,
|
LOGF("\t avcodec_find_decoder failed: stream=%d codec=%d\n", id,
|
||||||
static_cast<int>(s->codecpar->codec_id));
|
static_cast<int>(s->codecpar->codec_id));
|
||||||
|
|||||||
+11
-1
@@ -38,7 +38,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#include <libavutil/version.h>
|
||||||
|
#if LIBAVUTIL_VERSION_MAJOR < 61
|
||||||
extern const uint8_t avpriv_vga16_font[4096];
|
extern const uint8_t avpriv_vga16_font[4096];
|
||||||
|
#else
|
||||||
|
const uint8_t* avpriv_vga16_font_get(void);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Libs {
|
namespace Libs {
|
||||||
@@ -950,10 +955,15 @@ static void init_image(std::array<uint8_t, FONT_BITMAP_MAX_DIM * FONT_BITMAP_MAX
|
|||||||
|
|
||||||
const auto width = static_cast<uint32_t>(scaled_font_width(font));
|
const auto width = static_cast<uint32_t>(scaled_font_width(font));
|
||||||
const auto height = static_cast<uint32_t>(scaled_font_height(font));
|
const auto height = static_cast<uint32_t>(scaled_font_height(font));
|
||||||
|
#if LIBAVUTIL_VERSION_MAJOR < 61
|
||||||
|
const auto* vga_font = avpriv_vga16_font;
|
||||||
|
#else
|
||||||
|
const auto* vga_font = avpriv_vga16_font_get();
|
||||||
|
#endif
|
||||||
|
|
||||||
for (uint32_t y = 0; y < height; y++) {
|
for (uint32_t y = 0; y < height; y++) {
|
||||||
const uint32_t src_y = std::min<uint32_t>((y * 16u) / height, 15u);
|
const uint32_t src_y = std::min<uint32_t>((y * 16u) / height, 15u);
|
||||||
const uint8_t row = avpriv_vga16_font[code * 16 + src_y];
|
const uint8_t row = vga_font[code * 16 + src_y];
|
||||||
for (uint32_t x = 0; x < width; x++) {
|
for (uint32_t x = 0; x < width; x++) {
|
||||||
const uint32_t src_x = std::min<uint32_t>((x * 8u) / width, 7u);
|
const uint32_t src_x = std::min<uint32_t>((x * 8u) / width, 7u);
|
||||||
if ((row & (0x80u >> src_x)) != 0) {
|
if ((row & (0x80u >> src_x)) != 0) {
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ public:
|
|||||||
[[nodiscard]] bool Initialize() {
|
[[nodiscard]] bool Initialize() {
|
||||||
const AVCodec* decoder = avcodec_find_decoder(GetAvCodecId(m_config.codec_type));
|
const AVCodec* decoder = avcodec_find_decoder(GetAvCodecId(m_config.codec_type));
|
||||||
if (decoder == nullptr) {
|
if (decoder == nullptr) {
|
||||||
|
if (m_config.codec_type == CODEC_TYPE_VP9) {
|
||||||
|
Log::WriteToConsoleAndLog(
|
||||||
|
"WARNING: Videodec2: The game requested VP9 video, but FFmpeg has no VP9 "
|
||||||
|
"decoder. Use FFmpeg with VP9 decoding enabled.\n");
|
||||||
|
}
|
||||||
LOGF("Videodec2: FFmpeg decoder is unavailable for codec type %u\n",
|
LOGF("Videodec2: FFmpeg decoder is unavailable for codec type %u\n",
|
||||||
m_config.codec_type);
|
m_config.codec_type);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user