Fix recording encoder selection

Codecs are identified by name, not by ID.
Let's keep the ID as fallback instead.
This commit is contained in:
Megamouse
2026-07-27 16:18:26 +02:00
parent 7a3deb649f
commit 4add14cb72
7 changed files with 86 additions and 51 deletions
+5
View File
@@ -707,6 +707,11 @@ namespace cfg
return *m_value.load().get();
}
std::string get() const
{
return *m_value.load().get();
}
std::string def_to_string() const override
{
return def;
+2 -2
View File
@@ -1290,11 +1290,11 @@ error_code cellRecOpen(vm::cptr<char> pDirName, vm::cptr<char> pFileName, vm::cp
rec.encoder->set_path(vfs::get(rec.param.filename));
rec.encoder->set_framerate(rec.fps);
rec.encoder->set_video_bitrate(rec.video_bps);
rec.encoder->set_video_codec(rec.video_codec_id);
rec.encoder->set_video_codec(rec.video_codec_id, "");
rec.encoder->set_sample_rate(rec.sample_rate);
rec.encoder->set_audio_channels(rec.channels);
rec.encoder->set_audio_bitrate(rec.audio_bps);
rec.encoder->set_audio_codec(rec.audio_codec_id);
rec.encoder->set_audio_codec(rec.audio_codec_id, "");
rec.encoder->set_output_format(rec.output_format);
sysutil_register_cb([&rec](ppu_thread& ppu) -> s32
+4 -2
View File
@@ -16,7 +16,8 @@ struct cfg_recording final : cfg::node
cfg::uint<640, 7680> width{this, "Width", 1280};
cfg::uint<360, 4320> height{this, "Height", 720};
cfg::uint<0, 192> pixel_format{this, "AVPixelFormat", 0}; // AVPixelFormat::AV_PIX_FMT_YUV420P
cfg::uint<0, 0xFFFF> video_codec{this, "AVCodecID", 12}; // AVCodecID::AV_CODEC_ID_MPEG4
cfg::string codec_name{this, "Video Codec", ""};
cfg::uint<0, 0xFFFF> codec_id{this, "AVCodecID", 12}; // AVCodecID::AV_CODEC_ID_MPEG4
cfg::uint<1'000'000, 60'000'000> video_bps{this, "Video Bitrate", 4'000'000};
cfg::uint<0, 3> max_b_frames{this, "Max B-Frames", 2};
cfg::uint<1, 120> gop_size{this, "Group of Pictures Size", 30};
@@ -27,7 +28,8 @@ struct cfg_recording final : cfg::node
{
node_audio(cfg::node* _this) : cfg::node(_this, "Audio") {}
cfg::uint<0x10000, 0x17000> audio_codec{this, "AVCodecID", 86018}; // AVCodecID::AV_CODEC_ID_AAC
cfg::string codec_name{this, "Audio Codec", ""};
cfg::uint<0x10000, 0x17000> codec_id{this, "AVCodecID", 86018}; // AVCodecID::AV_CODEC_ID_AAC
cfg::uint<64'000, 320'000> audio_bps{this, "Audio Bitrate", 192'000};
} audio{ this };
+2 -2
View File
@@ -527,7 +527,7 @@ void gs_frame::toggle_recording()
m_video_encoder->set_path(video_path);
m_video_encoder->set_framerate(g_cfg_recording.video.framerate);
m_video_encoder->set_video_bitrate(g_cfg_recording.video.video_bps);
m_video_encoder->set_video_codec(g_cfg_recording.video.video_codec);
m_video_encoder->set_video_codec(g_cfg_recording.video.codec_id, g_cfg_recording.video.codec_name.get());
m_video_encoder->set_max_b_frames(g_cfg_recording.video.max_b_frames);
m_video_encoder->set_gop_size(g_cfg_recording.video.gop_size);
m_video_encoder->set_output_format(output_format);
@@ -557,7 +557,7 @@ void gs_frame::toggle_recording()
}
m_video_encoder->set_audio_bitrate(g_cfg_recording.audio.audio_bps);
m_video_encoder->set_audio_codec(g_cfg_recording.audio.audio_codec);
m_video_encoder->set_audio_codec(g_cfg_recording.audio.codec_id, g_cfg_recording.audio.codec_name.get());
m_video_encoder->encode();
if (m_video_encoder->has_error)
+54 -19
View File
@@ -24,6 +24,8 @@ extern "C" {
LOG_CHANNEL(cfg_log, "CFG");
constexpr int codec_name_role = Qt::UserRole + 1;
static std::vector<const AVCodec*> get_video_codecs(const AVOutputFormat* fmt)
{
std::vector<const AVCodec*> codecs;
@@ -142,36 +144,42 @@ recording_settings_dialog::recording_settings_dialog(QWidget* parent)
{
if (!codec) continue;
const std::string name = codec->long_name ? codec->long_name : avcodec_get_name(codec->id);
const char* codec_name = avcodec_get_name(codec->id);
const std::string name = codec->long_name ? codec->long_name : codec_name;
ui->combo_video_codec->addItem(QString::fromStdString(name), static_cast<int>(codec->id));
ui->combo_video_codec->setItemData(ui->combo_video_codec->findData(static_cast<int>(codec->id)), QString(codec_name), codec_name_role);
}
for (const AVCodec* codec : m_audio_codecs)
{
if (!codec) continue;
const std::string name = codec->long_name ? codec->long_name : avcodec_get_name(codec->id);
const char* codec_name = avcodec_get_name(codec->id);
const std::string name = codec->long_name ? codec->long_name : codec_name;
ui->combo_audio_codec->addItem(QString::fromStdString(name), static_cast<int>(codec->id));
ui->combo_audio_codec->setItemData(ui->combo_audio_codec->findData(static_cast<int>(codec->id)), QString(codec_name), codec_name_role);
}
connect(ui->combo_video_codec, &QComboBox::currentIndexChanged, this, [this](int index)
{
const QVariant var = ui->combo_video_codec->itemData(index);
if (var.canConvert<int>())
const QVariant codec_id = ui->combo_video_codec->itemData(index);
const QVariant codec_name = ui->combo_video_codec->itemData(index, codec_name_role);
if (codec_id.canConvert<int>() && codec_name.canConvert<QString>())
{
const int codec_id = var.toInt();
g_cfg_recording.video.video_codec.set(codec_id);
g_cfg_recording.video.codec_name.set(codec_name.toString().toStdString());
g_cfg_recording.video.codec_id.set(codec_id.toInt());
update_preset();
}
});
connect(ui->combo_audio_codec, &QComboBox::currentIndexChanged, this, [this](int index)
{
const QVariant var = ui->combo_audio_codec->itemData(index);
if (var.canConvert<int>())
const QVariant codec_id = ui->combo_audio_codec->itemData(index);
const QVariant codec_name = ui->combo_audio_codec->itemData(index, codec_name_role);
if (codec_id.canConvert<int>() && codec_name.canConvert<QString>())
{
const int codec_id = var.toInt();
g_cfg_recording.audio.audio_codec.set(codec_id);
g_cfg_recording.audio.codec_name.set(codec_name.toString().toStdString());
g_cfg_recording.audio.codec_id.set(codec_id.toInt());
update_preset();
}
});
@@ -279,8 +287,25 @@ void recording_settings_dialog::update_ui()
ui->combo_resolution->setCurrentIndex(ui->combo_resolution->findData(QVariant::fromValue(QPair<int, int>(g_cfg_recording.video.width.get(), g_cfg_recording.video.height.get()))));
ui->combo_framerate->setCurrentIndex(ui->combo_framerate->findData(static_cast<int>(g_cfg_recording.video.framerate.get())));
ui->combo_video_codec->setCurrentIndex(ui->combo_video_codec->findData(static_cast<int>(g_cfg_recording.video.video_codec.get())));
ui->combo_audio_codec->setCurrentIndex(ui->combo_audio_codec->findData(static_cast<int>(g_cfg_recording.audio.audio_codec.get())));
if (const int index = ui->combo_video_codec->findData(QString::fromStdString(g_cfg_recording.video.codec_name.get()), codec_name_role); index >= 0)
{
ui->combo_video_codec->setCurrentIndex(index);
}
else
{
ui->combo_video_codec->setCurrentIndex(ui->combo_video_codec->findData(static_cast<int>(g_cfg_recording.video.codec_id.get())));
}
if (const int index = ui->combo_audio_codec->findData(QString::fromStdString(g_cfg_recording.audio.codec_name.get()), codec_name_role); index >= 0)
{
ui->combo_audio_codec->setCurrentIndex(index);
}
else
{
ui->combo_audio_codec->setCurrentIndex(ui->combo_audio_codec->findData(static_cast<int>(g_cfg_recording.audio.codec_id.get())));
}
ui->spinbox_video_bitrate->setValue(g_cfg_recording.video.video_bps);
ui->spinbox_audio_bitrate->setValue(g_cfg_recording.audio.audio_bps);
ui->spinbox_gop_size->setValue(g_cfg_recording.video.gop_size);
@@ -295,8 +320,14 @@ void recording_settings_dialog::update_ui()
ui->spinbox_gop_size->blockSignals(false);
ui->spinbox_max_b_frames->blockSignals(false);
const auto get_codec_name = [](const std::vector<const AVCodec*>& codecs, u32 id)
const auto get_codec_name = [](const std::vector<const AVCodec*>& codecs, u32 id, const std::string& codec_name)
{
if (const AVCodec* codec = avcodec_find_encoder_by_name(codec_name.c_str()))
{
const std::string name = codec->long_name ? codec->long_name : avcodec_get_name(codec->id);
return name;
}
for (const AVCodec* codec : codecs)
{
if (codec && codec->id == static_cast<AVCodecID>(id))
@@ -323,9 +354,9 @@ void recording_settings_dialog::update_ui()
fmt::format("%d x %d\n%d fps\n%s\n%d\n%s\n%d\n%d\n%d",
g_cfg_recording.video.width.get(), g_cfg_recording.video.height.get(),
g_cfg_recording.video.framerate.get(),
get_codec_name(m_video_codecs, g_cfg_recording.video.video_codec.get()),
get_codec_name(m_video_codecs, g_cfg_recording.video.codec_id.get(), g_cfg_recording.video.codec_name.get()),
g_cfg_recording.video.video_bps.get(),
get_codec_name(m_audio_codecs, g_cfg_recording.audio.audio_codec.get()),
get_codec_name(m_audio_codecs, g_cfg_recording.audio.codec_id.get(), g_cfg_recording.audio.codec_name.get()),
g_cfg_recording.audio.audio_bps.get(),
g_cfg_recording.video.gop_size.get(),
g_cfg_recording.video.max_b_frames.get()
@@ -340,10 +371,12 @@ void recording_settings_dialog::select_preset(quality_preset preset, cfg_recordi
return;
}
cfg.audio.audio_codec.set(static_cast<u32>(AVCodecID::AV_CODEC_ID_AAC));
cfg.audio.codec_name.set("");
cfg.audio.codec_id.set(static_cast<u32>(AVCodecID::AV_CODEC_ID_AAC));
cfg.audio.audio_bps.set(192'000); // 192 kbps
cfg.video.video_codec.set(static_cast<u32>(AVCodecID::AV_CODEC_ID_MPEG4));
cfg.video.codec_name.set("");
cfg.video.codec_id.set(static_cast<u32>(AVCodecID::AV_CODEC_ID_MPEG4));
cfg.video.pixel_format.set(static_cast<u32>(::AV_PIX_FMT_YUV420P));
switch (preset)
@@ -437,11 +470,13 @@ recording_settings_dialog::quality_preset recording_settings_dialog::current_pre
g_cfg_recording.video.width.get() == cfg.video.width.get() &&
g_cfg_recording.video.height.get() == cfg.video.height.get() &&
g_cfg_recording.video.pixel_format.get() == cfg.video.pixel_format.get() &&
g_cfg_recording.video.video_codec.get() == cfg.video.video_codec.get() &&
g_cfg_recording.video.codec_name.get() == cfg.video.codec_name.get() &&
g_cfg_recording.video.codec_id.get() == cfg.video.codec_id.get() &&
g_cfg_recording.video.video_bps.get() == cfg.video.video_bps.get() &&
g_cfg_recording.video.max_b_frames.get() == cfg.video.max_b_frames.get() &&
g_cfg_recording.video.gop_size.get() == cfg.video.gop_size.get() &&
g_cfg_recording.audio.audio_codec.get() == cfg.audio.audio_codec.get() &&
g_cfg_recording.audio.codec_name.get() == cfg.audio.codec_name.get() &&
g_cfg_recording.audio.codec_id.get() == cfg.audio.codec_id.get() &&
g_cfg_recording.audio.audio_bps.get() == cfg.audio.audio_bps.get())
{
return preset;
+15 -24
View File
@@ -799,9 +799,10 @@ namespace utils
m_out_format = std::move(format);
}
void video_encoder::set_video_codec(s32 codec_id)
void video_encoder::set_video_codec(s32 codec_id, std::string_view codec_name)
{
m_video_codec_id = codec_id;
m_video_codec_name = codec_name;
}
void video_encoder::set_max_b_frames(s32 max_b_frames)
@@ -829,9 +830,10 @@ namespace utils
m_audio_bitrate_bps = bitrate;
}
void video_encoder::set_audio_codec(s32 codec_id)
void video_encoder::set_audio_codec(s32 codec_id, std::string_view codec_name)
{
m_audio_codec_id = codec_id;
m_audio_codec_name = codec_name;
}
void video_encoder::pause(bool flush)
@@ -992,9 +994,12 @@ namespace utils
return nullptr;
};
const AVCodecID video_codec = static_cast<AVCodecID>(m_video_codec_id);
const AVCodecID audio_codec = static_cast<AVCodecID>(m_audio_codec_id);
const AVOutputFormat* out_format = find_format(video_codec, audio_codec);
const AVCodec* selected_video_codec = avcodec_find_encoder_by_name(m_video_codec_name.c_str());
const AVCodec* selected_audio_codec = avcodec_find_encoder_by_name(m_audio_codec_name.c_str());
const AVCodecID video_codec_id = selected_video_codec ? selected_video_codec->id : static_cast<AVCodecID>(m_video_codec_id);
const AVCodecID audio_codec_id = selected_audio_codec ? selected_audio_codec->id : static_cast<AVCodecID>(m_audio_codec_id);
const AVOutputFormat* out_format = find_format(video_codec_id, audio_codec_id);
if (out_format)
{
@@ -1002,7 +1007,7 @@ namespace utils
}
else
{
media_log.error("video_encoder: Could not find a format for the requested video_codec %d and audio_codec %d", m_video_codec_id, m_audio_codec_id);
media_log.error("video_encoder: Could not find a format for the requested video_codec '%s' (ID=%d) and audio_codec '%s' (ID=%d)", m_video_codec_name, m_video_codec_id, m_audio_codec_name, m_audio_codec_id);
// Fallback to some other codec
for (const AVCodec* video_codec : video_codecs)
@@ -1014,6 +1019,8 @@ namespace utils
if (out_format)
{
media_log.success("video_encoder: Found fallback output format '%s'", out_format->name);
selected_video_codec = video_codec;
selected_audio_codec = audio_codec;
break;
}
}
@@ -1046,27 +1053,11 @@ namespace utils
return;
}
const auto create_context = [this, &av](bool is_video) -> bool
const auto create_context = [this, &av, &selected_video_codec, &selected_audio_codec](bool is_video) -> bool
{
const std::string type = is_video ? "video" : "audio";
scoped_av::ctx& ctx = is_video ? av.video : av.audio;
if (is_video)
{
if (!(ctx.codec = avcodec_find_encoder(av.format_context->oformat->video_codec)))
{
media_log.error("video_encoder: avcodec_find_encoder for video failed. video_codec=%d", static_cast<int>(av.format_context->oformat->video_codec));
return false;
}
}
else
{
if (!(ctx.codec = avcodec_find_encoder(av.format_context->oformat->audio_codec)))
{
media_log.error("video_encoder: avcodec_find_encoder for audio failed. audio_codec=%d", static_cast<int>(av.format_context->oformat->audio_codec));
return false;
}
}
ctx.codec = is_video ? selected_video_codec : selected_audio_codec;
if (!(ctx.stream = avformat_new_stream(av.format_context, nullptr)))
{
+4 -2
View File
@@ -111,13 +111,13 @@ namespace utils
void set_framerate(u32 framerate);
void set_video_bitrate(u32 bitrate);
void set_output_format(frame_format format);
void set_video_codec(s32 codec_id);
void set_video_codec(s32 codec_id, std::string_view codec_name);
void set_max_b_frames(s32 max_b_frames);
void set_gop_size(s32 gop_size);
void set_sample_rate(u32 sample_rate);
void set_audio_channels(u32 channels);
void set_audio_bitrate(u32 bitrate);
void set_audio_codec(s32 codec_id);
void set_audio_codec(s32 codec_id, std::string_view codec_name);
void pause(bool flush = true) override;
void stop(bool flush = true) override;
void resume() override;
@@ -135,6 +135,7 @@ namespace utils
// Video parameters
u32 m_video_bitrate_bps = 0;
s32 m_video_codec_id = 12; // AV_CODEC_ID_MPEG4
std::string m_video_codec_name;
s32 m_max_b_frames = 2;
s32 m_gop_size = 12;
frame_format m_out_format{};
@@ -143,5 +144,6 @@ namespace utils
u32 m_channels = 2;
u32 m_audio_bitrate_bps = 320000;
s32 m_audio_codec_id = 86018; // AV_CODEC_ID_AAC
std::string m_audio_codec_name;
};
}