diff --git a/CHANGES b/CHANGES index 46c838cf0..5448bff6a 100644 --- a/CHANGES +++ b/CHANGES @@ -62,7 +62,9 @@ Emulation fixes: - ARM: Fix long and accumulate multiply timing - GB: Partially fix timing for skipped BIOS - GB: Downgrade DMG-only ROMs from CGB mode even without boot ROM + - GB: Fix marking BIOS as unmapped when skipping BIOS (fixes mgba.io/i/2061) - GB Audio: Fix serializing sweep time + - GB Audio: Fix some channel 4 timing edge cases - GB MBC: Fix MBC1 mode changing behavior - GB MBC: Fix some MBC3 bit masking - GB Video: Fix state after skipping BIOS (fixes mgba.io/i/1715 and mgba.io/i/1716) @@ -128,6 +130,7 @@ Other fixes: - Qt: Fix crashing when no OpenGL context can be obtained - Qt: Fix issues with I/O viewer not properly synchronizing state - Qt: Fix loading a new game crashing on Wayland (fixes mgba.io/i/1992) + - Qt: Fix inability to clear hat bindings - SM83: Simplify register pair access on big endian - SM83: Disassemble STOP as one byte - Wii: Fix crash on unloading irregularly sized GBA ROMs @@ -153,6 +156,7 @@ Misc: - GBA Video: Avoid integer division using reciprocal tricks - Debugger: Keep track of global cycle count - FFmpeg: Add looping option for GIF/APNG + - FFmpeg: Add CRF support for applicable codecs - mGUI: Show battery percentage - mGUI: Skip second scan loop when possible - mGUI: Improve loading speed (fixes mgba.io/i/1957) diff --git a/src/core/input.c b/src/core/input.c index 307fed216..c143805ac 100644 --- a/src/core/input.c +++ b/src/core/input.c @@ -541,7 +541,6 @@ void mInputBindHat(struct mInputMap* map, uint32_t type, int id, const struct mI *mInputHatListGetPointer(&impl->hats, id) = *bindings; } - bool mInputQueryHat(const struct mInputMap* map, uint32_t type, int id, struct mInputHatBindings* bindings) { const struct mInputMapImpl* impl = _lookupMapConst(map, type); if (!impl) { @@ -559,18 +558,23 @@ void mInputUnbindHat(struct mInputMap* map, uint32_t type, int id) { if (!impl) { return; } - if (mInputHatListSize(&impl->hats) && id + 1 == (ssize_t) mInputHatListSize(&impl->hats)) { - mInputHatListResize(&impl->hats, -1); - } else { - struct mInputHatBindings* description = mInputHatListGetPointer(&impl->hats, id); - memset(description, -1, sizeof(*description)); + if (id >= (ssize_t) mInputHatListSize(&impl->hats)) { + return; } + struct mInputHatBindings* description = mInputHatListGetPointer(&impl->hats, id); + memset(description, -1, sizeof(*description)); } void mInputUnbindAllHats(struct mInputMap* map, uint32_t type) { struct mInputMapImpl* impl = _lookupMap(map, type); - if (impl) { - mInputHatListClear(&impl->hats); + if (!impl) { + return; + } + + size_t id; + for (id = 0; id < mInputHatListSize(&impl->hats); ++id) { + struct mInputHatBindings* description = mInputHatListGetPointer(&impl->hats, id); + memset(description, -1, sizeof(*description)); } } diff --git a/src/feature/ffmpeg/ffmpeg-encoder.c b/src/feature/ffmpeg/ffmpeg-encoder.c index dc8d04c10..a55008f0d 100644 --- a/src/feature/ffmpeg/ffmpeg-encoder.c +++ b/src/feature/ffmpeg/ffmpeg-encoder.c @@ -168,7 +168,7 @@ bool FFmpegEncoderSetAudio(struct FFmpegEncoder* encoder, const char* acodec, un return true; } -bool FFmpegEncoderSetVideo(struct FFmpegEncoder* encoder, const char* vcodec, unsigned vbr, int frameskip) { +bool FFmpegEncoderSetVideo(struct FFmpegEncoder* encoder, const char* vcodec, int vbr, int frameskip) { static const struct { enum AVPixelFormat format; int priority; @@ -218,6 +218,9 @@ bool FFmpegEncoderSetVideo(struct FFmpegEncoder* encoder, const char* vcodec, un if (encoder->pixFormat == AV_PIX_FMT_NONE) { return false; } + if (vbr < 0 && !av_opt_find(&codec->priv_class, "crf", NULL, 0, 0)) { + return false; + } encoder->videoCodec = vcodec; encoder->videoBitrate = vbr; encoder->frameskip = frameskip + 1; @@ -412,7 +415,7 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->video->pix_fmt = AV_PIX_FMT_BGR0; } #endif - if (strcmp(vcodec->name, "libx264") == 0) { + if (strcmp(vcodec->name, "libx264") == 0 || strcmp(vcodec->name, "libx264rgb") == 0) { // Try to adaptively figure out when you can use a slower encoder if (encoder->width * encoder->height > 1000000) { av_opt_set(encoder->video->priv_data, "preset", "superfast", 0); @@ -421,10 +424,26 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { } else { av_opt_set(encoder->video->priv_data, "preset", "faster", 0); } + av_opt_set(encoder->video->priv_data, "tune", "zerolatency", 0); if (encoder->videoBitrate == 0) { av_opt_set(encoder->video->priv_data, "qp", "0", 0); - encoder->video->pix_fmt = AV_PIX_FMT_YUV444P; + if (strcmp(vcodec->name, "libx264") == 0) { + encoder->video->pix_fmt = AV_PIX_FMT_YUV444P; + } + } else if (encoder->videoBitrate < 0) { + av_opt_set_int(encoder->video->priv_data, "crf", -encoder->videoBitrate, 0); } + } else if (encoder->videoBitrate < 0) { + if (strcmp(vcodec->name, "libvpx") == 0 || strcmp(vcodec->name, "libvpx-vp9") == 0 || strcmp(vcodec->name, "libx265") == 0) { + av_opt_set_int(encoder->video->priv_data, "crf", -encoder->videoBitrate, 0); + } else { + FFmpegEncoderClose(encoder); + return false; + } + } + if (strncmp(vcodec->name, "libvpx", 6) == 0) { + av_opt_set_int(encoder->video->priv_data, "cpu-used", 2, 0); + av_opt_set(encoder->video->priv_data, "deadline", "realtime", 0); } if (strcmp(vcodec->name, "libvpx-vp9") == 0 && encoder->videoBitrate == 0) { av_opt_set_int(encoder->video->priv_data, "lossless", 1, 0); diff --git a/src/feature/ffmpeg/ffmpeg-encoder.h b/src/feature/ffmpeg/ffmpeg-encoder.h index 562d71edc..26e21184d 100644 --- a/src/feature/ffmpeg/ffmpeg-encoder.h +++ b/src/feature/ffmpeg/ffmpeg-encoder.h @@ -23,7 +23,7 @@ struct FFmpegEncoder { unsigned audioBitrate; const char* audioCodec; - unsigned videoBitrate; + int videoBitrate; const char* videoCodec; const char* containerFormat; @@ -76,7 +76,7 @@ struct FFmpegEncoder { void FFmpegEncoderInit(struct FFmpegEncoder*); bool FFmpegEncoderSetAudio(struct FFmpegEncoder*, const char* acodec, unsigned abr); -bool FFmpegEncoderSetVideo(struct FFmpegEncoder*, const char* vcodec, unsigned vbr, int frameskip); +bool FFmpegEncoderSetVideo(struct FFmpegEncoder*, const char* vcodec, int vbr, int frameskip); bool FFmpegEncoderSetContainer(struct FFmpegEncoder*, const char* container); void FFmpegEncoderSetDimensions(struct FFmpegEncoder*, int width, int height); void FFmpegEncoderSetInputFrameRate(struct FFmpegEncoder*, int numerator, int denominator); diff --git a/src/gb/audio.c b/src/gb/audio.c index f20fa3fac..121db67d2 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -390,6 +390,7 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { } } if (audio->playingCh4 && audio->ch4.envelope.dead != 2) { + audio->ch4.lastEvent = mTimingCurrentTime(audio->timing); mTimingDeschedule(audio->timing, &audio->ch4Event); mTimingSchedule(audio->timing, &audio->ch4Event, 0); } @@ -581,14 +582,16 @@ void GBAudioUpdateFrame(struct GBAudio* audio, struct mTiming* timing) { if (audio->playingCh4 && !audio->ch4.envelope.dead) { --audio->ch4.envelope.nextStep; if (audio->ch4.envelope.nextStep == 0) { - int8_t sample = audio->ch4.sample > 0; - audio->ch4.samples -= audio->ch4.sample; + int8_t sample = audio->ch4.sample; _updateEnvelope(&audio->ch4.envelope); if (audio->ch4.envelope.dead == 2) { mTimingDeschedule(timing, &audio->ch4Event); } - audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; - audio->ch4.samples += audio->ch4.sample; + audio->ch4.sample = (sample > 0) * audio->ch4.envelope.currentVolume; + if (audio->ch4.nSamples) { + audio->ch4.samples -= sample; + audio->ch4.samples += audio->ch4.sample; + } } } break; diff --git a/src/gb/gb.c b/src/gb/gb.c index 519b39fe1..79d309cf6 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -577,6 +577,7 @@ void GBSkipBIOS(struct GB* gb) { mTimingSchedule(&gb->timing, &gb->timer.event, gb->timer.nextDiv); GBIOWrite(gb, GB_REG_LCDC, 0x91); + gb->memory.io[GB_REG_BANK] = 0x1; GBVideoSkipBIOS(&gb->video); if (gb->biosVf) { diff --git a/src/platform/qt/DebuggerConsoleController.cpp b/src/platform/qt/DebuggerConsoleController.cpp index 95c8638a6..b77609a5a 100644 --- a/src/platform/qt/DebuggerConsoleController.cpp +++ b/src/platform/qt/DebuggerConsoleController.cpp @@ -8,6 +8,7 @@ #include "CoreController.h" #include +#include #include @@ -30,6 +31,7 @@ DebuggerConsoleController::DebuggerConsoleController(QObject* parent) } void DebuggerConsoleController::enterLine(const QString& line) { + CoreController::Interrupter interrupter(m_gameController); QMutexLocker lock(&m_mutex); m_lines.append(line); if (m_cliDebugger.d.state == DEBUGGER_RUNNING) { @@ -39,14 +41,20 @@ void DebuggerConsoleController::enterLine(const QString& line) { } void DebuggerConsoleController::detach() { - if (m_cliDebugger.d.state != DEBUGGER_SHUTDOWN) { - m_lines.append(QString()); - m_cond.wakeOne(); + { + CoreController::Interrupter interrupter(m_gameController); + QMutexLocker lock(&m_mutex); + if (m_cliDebugger.d.state != DEBUGGER_SHUTDOWN) { + m_lines.append(QString()); + m_cond.wakeOne(); + } } DebuggerController::detach(); } void DebuggerConsoleController::attachInternal() { + CoreController::Interrupter interrupter(m_gameController); + QMutexLocker lock(&m_mutex); m_history.clear(); mCore* core = m_gameController->thread()->core; CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d); @@ -65,12 +73,13 @@ void DebuggerConsoleController::printf(struct CLIDebuggerBackend* be, const char void DebuggerConsoleController::init(struct CLIDebuggerBackend* be) { Backend* consoleBe = reinterpret_cast(be); DebuggerConsoleController* self = consoleBe->self; + UNUSED(self); } void DebuggerConsoleController::deinit(struct CLIDebuggerBackend* be) { Backend* consoleBe = reinterpret_cast(be); DebuggerConsoleController* self = consoleBe->self; - if (be->p->d.state != DEBUGGER_SHUTDOWN) { + if (QThread::currentThread() == self->thread() && be->p->d.state != DEBUGGER_SHUTDOWN) { self->m_lines.append(QString()); self->m_cond.wakeOne(); } @@ -109,6 +118,7 @@ const char* DebuggerConsoleController::historyLast(struct CLIDebuggerBackend* be return "i"; } self->m_last = self->m_history.last().toUtf8(); + *len = self->m_last.size(); return self->m_last.constData(); } diff --git a/src/platform/qt/GBAKeyEditor.cpp b/src/platform/qt/GBAKeyEditor.cpp index 16f0d29b9..7890812e7 100644 --- a/src/platform/qt/GBAKeyEditor.cpp +++ b/src/platform/qt/GBAKeyEditor.cpp @@ -215,6 +215,7 @@ void GBAKeyEditor::setNext() { void GBAKeyEditor::save() { #ifdef BUILD_SDL m_controller->unbindAllAxes(m_type); + m_controller->unbindAllHats(m_type); #endif bindKey(m_keyDU, GBA_KEY_UP); diff --git a/src/platform/qt/KeyEditor.cpp b/src/platform/qt/KeyEditor.cpp index bd867b856..2f32a6ba5 100644 --- a/src/platform/qt/KeyEditor.cpp +++ b/src/platform/qt/KeyEditor.cpp @@ -209,18 +209,22 @@ bool KeyEditor::event(QEvent* event) { void KeyEditor::updateButtonText() { QStringList text; if (m_hat >= 0) { + QString hatId("%0"); + if (m_hat) { + hatId += QString::number(m_hat); + } switch (m_hatDirection) { case GamepadHatEvent::UP: - text.append(QString("↑%0").arg(m_hat)); + text.append(hatId.arg("↑")); break; case GamepadHatEvent::RIGHT: - text.append(QString("→%0").arg(m_hat)); + text.append(hatId.arg("→")); break; case GamepadHatEvent::DOWN: - text.append(QString("↓%0").arg(m_hat)); + text.append(hatId.arg("↓")); break; case GamepadHatEvent::LEFT: - text.append(QString("←%0").arg(m_hat)); + text.append(hatId.arg("←")); break; default: break; diff --git a/src/platform/qt/VideoView.cpp b/src/platform/qt/VideoView.cpp index 5ef6d9141..d2a4850cd 100644 --- a/src/platform/qt/VideoView.cpp +++ b/src/platform/qt/VideoView.cpp @@ -86,14 +86,25 @@ VideoView::VideoView(QWidget* parent) connect(m_ui.video, SIGNAL(editTextChanged(const QString&)), this, SLOT(setVideoCodec(const QString&))); connect(m_ui.container, SIGNAL(editTextChanged(const QString&)), this, SLOT(setContainer(const QString&))); - connect(m_ui.abr, SIGNAL(valueChanged(int)), this, SLOT(setAudioBitrate(int))); - connect(m_ui.vbr, SIGNAL(valueChanged(int)), this, SLOT(setVideoBitrate(int))); + connect(m_ui.abr, static_cast(&QSpinBox::valueChanged), this, &VideoView::setAudioBitrate); + connect(m_ui.crf, static_cast(&QSpinBox::valueChanged), this, &VideoView::setVideoRateFactor); + connect(m_ui.vbr, static_cast(&QSpinBox::valueChanged), this, &VideoView::setVideoBitrate); + connect(m_ui.doVbr, &QAbstractButton::toggled, this, [this](bool set) { + if (set) { + setVideoBitrate(m_ui.vbr->value()); + } + }); + connect(m_ui.doCrf, &QAbstractButton::toggled, this, [this](bool set) { + if (set) { + setVideoRateFactor(m_ui.crf->value()); + } + }); - connect(m_ui.width, SIGNAL(valueChanged(int)), this, SLOT(setWidth(int))); - connect(m_ui.height, SIGNAL(valueChanged(int)), this, SLOT(setHeight(int))); + connect(m_ui.width, static_cast(&QSpinBox::valueChanged), this, &VideoView::setWidth); + connect(m_ui.height, static_cast(&QSpinBox::valueChanged), this, &VideoView::setHeight); - connect(m_ui.wratio, SIGNAL(valueChanged(int)), this, SLOT(setAspectWidth(int))); - connect(m_ui.hratio, SIGNAL(valueChanged(int)), this, SLOT(setAspectHeight(int))); + connect(m_ui.wratio, static_cast(&QSpinBox::valueChanged), this, &VideoView::setAspectWidth); + connect(m_ui.hratio, static_cast(&QSpinBox::valueChanged), this, &VideoView::setAspectHeight); connect(m_ui.showAdvanced, &QAbstractButton::clicked, this, &VideoView::showAdvanced); @@ -101,13 +112,7 @@ VideoView::VideoView(QWidget* parent) updatePresets(); - setPreset({ - "MKV", - "h.264", - "FLAC", - -1, - 0, - }); + m_ui.presetYoutube->setChecked(true); // Use the Youtube preset by default showAdvanced(false); } @@ -126,18 +131,18 @@ void VideoView::updatePresets() { addPreset(m_ui.presetHQ, { "MP4", - "h.264", + "H.264", "AAC", - 8000, + -18, 384, maintainAspect({ 1920, 1080 }) }); addPreset(m_ui.presetYoutube, { "MP4", - "h.264", + "H.264", "AAC", - 5000, + -20, 256, maintainAspect({ 1280, 720 }) }); @@ -152,16 +157,16 @@ void VideoView::updatePresets() { addPreset(m_ui.presetMP4, { "MP4", - "h.264", + "H.264", "AAC", - 800, + -22, 128 }); if (m_nativeWidth && m_nativeHeight) { addPreset(m_ui.presetLossless, { "MKV", - "h.264", + "libx264rgb", "FLAC", -1, 0, @@ -245,7 +250,7 @@ void VideoView::setFilename(const QString& fname) { validateSettings(); } -void VideoView::setAudioCodec(const QString& codec, bool manual) { +void VideoView::setAudioCodec(const QString& codec) { free(m_audioCodecCstr); m_audioCodec = sanitizeCodec(codec, s_acodecMap); if (m_audioCodec == "none") { @@ -253,18 +258,16 @@ void VideoView::setAudioCodec(const QString& codec, bool manual) { } else { m_audioCodecCstr = strdup(m_audioCodec.toUtf8().constData()); } - if (!FFmpegEncoderSetAudio(&m_encoder, m_audioCodecCstr, m_abr)) { + if (!FFmpegEncoderSetAudio(&m_encoder, m_audioCodecCstr, 128 * 1024)) { free(m_audioCodecCstr); m_audioCodecCstr = nullptr; m_audioCodec = QString(); } validateSettings(); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setVideoCodec(const QString& codec, bool manual) { +void VideoView::setVideoCodec(const QString& codec) { free(m_videoCodecCstr); m_videoCodec = sanitizeCodec(codec, s_vcodecMap); if (m_videoCodec == "none") { @@ -272,18 +275,16 @@ void VideoView::setVideoCodec(const QString& codec, bool manual) { } else { m_videoCodecCstr = strdup(m_videoCodec.toUtf8().constData()); } - if (!FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, m_vbr, 0)) { + if (!FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, 1024 * 1024, 0)) { free(m_videoCodecCstr); m_videoCodecCstr = nullptr; m_videoCodec = QString(); } validateSettings(); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setContainer(const QString& container, bool manual) { +void VideoView::setContainer(const QString& container) { free(m_containerCstr); m_container = sanitizeCodec(container, s_containerMap); m_containerCstr = strdup(m_container.toUtf8().constData()); @@ -293,61 +294,51 @@ void VideoView::setContainer(const QString& container, bool manual) { m_container = QString(); } validateSettings(); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setAudioBitrate(int br, bool manual) { +void VideoView::setAudioBitrate(int br) { m_abr = br * 1000; FFmpegEncoderSetAudio(&m_encoder, m_audioCodecCstr, m_abr); validateSettings(); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setVideoBitrate(int br, bool manual) { - m_vbr = br >= 0 ? br * 1000 : 0; +void VideoView::setVideoBitrate(int br) { + m_vbr = br > 0 ? br * 1000 : br; FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, m_vbr, 0); validateSettings(); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setWidth(int width, bool manual) { +void VideoView::setVideoRateFactor(int rf) { + setVideoBitrate(-rf); +} + +void VideoView::setWidth(int width) { m_width = width; updateAspectRatio(width, 0, false); FFmpegEncoderSetDimensions(&m_encoder, m_width, m_height); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setHeight(int height, bool manual) { +void VideoView::setHeight(int height) { m_height = height; updateAspectRatio(0, height, false); FFmpegEncoderSetDimensions(&m_encoder, m_width, m_height); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setAspectWidth(int, bool manual) { +void VideoView::setAspectWidth(int) { updateAspectRatio(0, m_height, true); FFmpegEncoderSetDimensions(&m_encoder, m_width, m_height); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } -void VideoView::setAspectHeight(int, bool manual) { +void VideoView::setAspectHeight(int) { updateAspectRatio(m_width, 0, true); FFmpegEncoderSetDimensions(&m_encoder, m_width, m_height); - if (manual) { - uncheckIncompatible(); - } + uncheckIncompatible(); } void VideoView::showAdvanced(bool show) { @@ -361,6 +352,11 @@ bool VideoView::validateSettings() { m_ui.audio->setStyleSheet("QComboBox { color: red; }"); } else { m_ui.audio->setStyleSheet(""); + if (!FFmpegEncoderSetAudio(&m_encoder, m_audioCodecCstr, m_abr)) { + m_ui.abr->setStyleSheet("QSpinBox { color: red; }"); + } else { + m_ui.abr->setStyleSheet(""); + } } if (m_videoCodec.isNull()) { @@ -368,6 +364,21 @@ bool VideoView::validateSettings() { m_ui.video->setStyleSheet("QComboBox { color: red; }"); } else { m_ui.video->setStyleSheet(""); + if (!FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, m_vbr, 0)) { + if (m_ui.doVbr->isChecked()) { + m_ui.vbr->setStyleSheet("QSpinBox { color: red; }"); + } else { + m_ui.vbr->setStyleSheet(""); + } + if (m_ui.doCrf->isChecked()) { + m_ui.crf->setStyleSheet("QSpinBox { color: red; }"); + } else { + m_ui.crf->setStyleSheet(""); + } + } else { + m_ui.vbr->setStyleSheet(""); + m_ui.crf->setStyleSheet(""); + } } if (m_container.isNull()) { @@ -410,11 +421,15 @@ void VideoView::updateAspectRatio(int width, int height, bool force) { } void VideoView::uncheckIncompatible() { + if (m_updatesBlocked) { + return; + } + Preset current = { m_container, m_videoCodec, m_audioCodec, - m_vbr / 1000, + m_vbr > 0 ? m_vbr / 1000 : m_vbr, m_abr / 1000, { m_width, m_height } }; @@ -459,24 +474,21 @@ QString VideoView::sanitizeCodec(const QString& codec, const QMapblockSignals(true); + QSignalBlocker blocker(button); bool autoExclusive = button->autoExclusive(); button->setAutoExclusive(false); button->setChecked(set); button->setAutoExclusive(autoExclusive); - button->blockSignals(signalsBlocked); } void VideoView::safelySet(QSpinBox* box, int value) { - bool signalsBlocked = box->blockSignals(true); + QSignalBlocker blocker(box); box->setValue(value); - box->blockSignals(signalsBlocked); } void VideoView::safelySet(QComboBox* box, const QString& value) { - bool signalsBlocked = box->blockSignals(true); + QSignalBlocker blocker(box); box->lineEdit()->setText(value); - box->blockSignals(signalsBlocked); } void VideoView::addPreset(QAbstractButton* button, const Preset& preset) { @@ -488,34 +500,46 @@ void VideoView::addPreset(QAbstractButton* button, const Preset& preset) { } void VideoView::setPreset(const Preset& preset) { + m_updatesBlocked = true; if (!preset.container.isNull()) { - setContainer(preset.container, false); + setContainer(preset.container); safelySet(m_ui.container, preset.container); } if (!preset.acodec.isNull()) { - setAudioCodec(preset.acodec, false); + setAudioCodec(preset.acodec); safelySet(m_ui.audio, preset.acodec); } if (!preset.vcodec.isNull()) { - setVideoCodec(preset.vcodec, false); + setVideoCodec(preset.vcodec); safelySet(m_ui.video, preset.vcodec); } if (preset.abr) { - setAudioBitrate(preset.abr, false); + setAudioBitrate(preset.abr); safelySet(m_ui.abr, preset.abr); } if (preset.vbr) { - setVideoBitrate(preset.vbr, false); - safelySet(m_ui.vbr, preset.vbr); + int vbr = preset.vbr; + if (vbr == -1) { + vbr = 0; + } + setVideoBitrate(vbr); + if (vbr > 0) { + safelySet(m_ui.vbr, vbr); + m_ui.doVbr->setChecked(true); + } else { + safelySet(m_ui.crf, -vbr); + m_ui.doCrf->setChecked(true); + } } if (preset.dims.width() > 0) { - setWidth(preset.dims.width(), false); + setWidth(preset.dims.width()); safelySet(m_ui.width, preset.dims.width()); } if (preset.dims.height() > 0) { - setHeight(preset.dims.height(), false); + setHeight(preset.dims.height()); safelySet(m_ui.height, preset.dims.height()); } + m_updatesBlocked = false; uncheckIncompatible(); validateSettings(); diff --git a/src/platform/qt/VideoView.h b/src/platform/qt/VideoView.h index 2b4eb3db6..2d61cf64a 100644 --- a/src/platform/qt/VideoView.h +++ b/src/platform/qt/VideoView.h @@ -45,17 +45,18 @@ signals: private slots: void selectFile(); void setFilename(const QString&); - void setAudioCodec(const QString&, bool manual = true); - void setVideoCodec(const QString&, bool manual = true); - void setContainer(const QString&, bool manual = true); + void setAudioCodec(const QString&); + void setVideoCodec(const QString&); + void setContainer(const QString&); - void setAudioBitrate(int, bool manual = true); - void setVideoBitrate(int, bool manual = true); + void setAudioBitrate(int); + void setVideoBitrate(int); + void setVideoRateFactor(int); - void setWidth(int, bool manual = true); - void setHeight(int, bool manual = true); - void setAspectWidth(int, bool manual = true); - void setAspectHeight(int, bool manual = true); + void setWidth(int); + void setHeight(int); + void setAspectWidth(int); + void setAspectHeight(int); void showAdvanced(bool); @@ -67,8 +68,8 @@ private: QString container; QString vcodec; QString acodec; - int vbr; - int abr; + int vbr = 0; + int abr = 0; QSize dims; Preset() {} @@ -107,6 +108,8 @@ private: char* m_videoCodecCstr = nullptr; char* m_containerCstr = nullptr; + bool m_updatesBlocked = false; + int m_abr; int m_vbr; diff --git a/src/platform/qt/VideoView.ui b/src/platform/qt/VideoView.ui index 162f69eb3..92e8d0ec2 100644 --- a/src/platform/qt/VideoView.ui +++ b/src/platform/qt/VideoView.ui @@ -6,8 +6,8 @@ 0 0 - 351 - 584 + 324 + 593 @@ -145,9 +145,6 @@ &Lossless - - true - presets @@ -155,6 +152,13 @@ + + + + Qt::Vertical + + + @@ -270,12 +274,12 @@ - h.264 + H.264 - h.264 (NVENC) + H.264 (NVENC) @@ -361,36 +365,20 @@ Bitrate (kbps) - - + + - VBR + - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - vbr + + true + + ratefactor + - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10000 - - - 400 - - - - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -406,7 +394,17 @@ - + + + + + + + ratefactor + + + + ABR @@ -419,6 +417,64 @@ + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 50 + + + 18 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10000 + + + + + + + VBR + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + vbr + + + + + + + CRF + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + crf + + + @@ -529,14 +585,20 @@ presetHQ presetYoutube presetWebM + presetMP4 presetLossless + preset4K preset1080 preset720 preset480 presetNative + showAdvanced container video audio + doCrf + doVbr + crf vbr abr width @@ -544,12 +606,45 @@ wratio hratio lockRatio - showAdvanced - + + + doCrf + toggled(bool) + crf + setEnabled(bool) + + + 200 + 324 + + + 301 + 314 + + + + + doVbr + toggled(bool) + vbr + setEnabled(bool) + + + 200 + 364 + + + 301 + 354 + + + + - + + diff --git a/src/platform/qt/input/InputController.cpp b/src/platform/qt/input/InputController.cpp index 737128d01..b86a8578c 100644 --- a/src/platform/qt/input/InputController.cpp +++ b/src/platform/qt/input/InputController.cpp @@ -704,6 +704,10 @@ void InputController::bindHat(uint32_t type, int hat, GamepadHatEvent::Direction mInputBindHat(&m_inputMap, type, hat, &bindings); } +void InputController::unbindAllHats(uint32_t type) { + mInputUnbindAllHats(&m_inputMap, type); +} + void InputController::testGamepad(int type) { QWriteLocker l(&m_eventsLock); auto activeAxes = activeGamepadAxes(type); diff --git a/src/platform/qt/input/InputController.h b/src/platform/qt/input/InputController.h index 3f272756b..ce5d6f34c 100644 --- a/src/platform/qt/input/InputController.h +++ b/src/platform/qt/input/InputController.h @@ -94,8 +94,12 @@ public: void recalibrateAxes(); void bindKey(uint32_t type, int key, const QString&); + void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, const QString&); + void unbindAllAxes(uint32_t type); + void bindHat(uint32_t type, int hat, GamepadHatEvent::Direction, const QString&); + void unbindAllHats(uint32_t type); QStringList connectedGamepads(uint32_t type) const; int gamepad(uint32_t type) const; diff --git a/src/platform/qt/ts/medusa-emu-de.ts b/src/platform/qt/ts/medusa-emu-de.ts index 87b1bdfb3..71b569c97 100644 --- a/src/platform/qt/ts/medusa-emu-de.ts +++ b/src/platform/qt/ts/medusa-emu-de.ts @@ -3301,7 +3301,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.QGBA::KeyEditor - + --- --- @@ -3981,17 +3981,17 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 Fehler beim Öffnen der Ausgabe-Videodatei: %1 - + Native (%0x%1) Nativ (%0x%1) - + Select output file Ausgabedatei auswählen @@ -5836,28 +5836,28 @@ wenn vorhanden - + WebM WebM - + Format Format - + MKV MKV - + AVI AVI - + MP4 MP4 @@ -5877,128 +5877,133 @@ wenn vorhanden Ver&lustfrei - + 4K 4K - + &1080p &1080p - + &720p &720p - + &480p &480p - + &Native &Nativ - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + HEVC (NVENC) HEVC (NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - - + + None Leer - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed Unkomprimiert - + Bitrate (kbps) Bitrate (kbps) - - VBR - VBR - - - + ABR ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions Abmessungen - + Lock aspect ratio Seitenverhältnis sperren - + Show advanced Erweiterte Optionen anzeigen diff --git a/src/platform/qt/ts/medusa-emu-es.ts b/src/platform/qt/ts/medusa-emu-es.ts index 1eadfbc7e..03adef69b 100644 --- a/src/platform/qt/ts/medusa-emu-es.ts +++ b/src/platform/qt/ts/medusa-emu-es.ts @@ -3255,7 +3255,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. QGBA::KeyEditor - + --- --- @@ -3935,17 +3935,17 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 Error al abrir el archivo de video de salida: %1 - + Native (%0x%1) Native (%0x%1) - + Select output file Seleccionar archivo de salida @@ -5740,28 +5740,28 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. - + WebM WebM - + Format Formato - + MKV MKV - + AVI AVI - + MP4 MP4 @@ -5781,128 +5781,133 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Sin pér&didas - + 4K 480p {4K?} - + &1080p &1080p - + &720p &720p - + &480p &480p - + &Native &NAtivo - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + HEVC (NVENC) HEVC (NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - - + + None Ninguno - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed Sin comprimir - + Bitrate (kbps) Tasa de bits (kbps) - - VBR - VBR - - - + ABR ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions Dimensiones - + Lock aspect ratio Bloquear proporción de aspecto - + Show advanced Mostrar ajustes avanzados diff --git a/src/platform/qt/ts/medusa-emu-it.ts b/src/platform/qt/ts/medusa-emu-it.ts index 0860f2134..e6f5cc5d2 100644 --- a/src/platform/qt/ts/medusa-emu-it.ts +++ b/src/platform/qt/ts/medusa-emu-it.ts @@ -3255,7 +3255,7 @@ Game Boy Advance è un marchio registrato di Nintendo Co., Ltd. QGBA::KeyEditor - + --- --- @@ -3935,17 +3935,17 @@ Game Boy Advance è un marchio registrato di Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 Errore durante l'archiviazione del video: %1 - + Native (%0x%1) Nativo (%0x%1) - + Select output file Seleziona file di uscita @@ -5740,48 +5740,38 @@ Game Boy Advance è un marchio registrato di Nintendo Co., Ltd. - + WebM WebM - + Format Formato - + MKV MKV - + AVI AVI - + MP4 MP4 - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + VP8 VP8 @@ -5801,108 +5791,123 @@ Game Boy Advance è un marchio registrato di Nintendo Co., Ltd. &Lossless - + 4K 4K - + &1080p &1080p - + &720p &720p - + &480p &480p - + &Native &Nativa - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + HEVC (NVENC) HEVC (NVENC) - + VP9 VP9 - + FFV1 FFV1 - - + + None Nessuno - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed Senza compressione - + Bitrate (kbps) Bitrate (kbps) - - VBR - VBR - - - + ABR ABR - + + VBR + VBR + + + + CRF + + + + Dimensions Dimensioni - + Lock aspect ratio Blocca rapporti aspetto - + Show advanced Mostra avanzate diff --git a/src/platform/qt/ts/mgba-en.ts b/src/platform/qt/ts/mgba-en.ts index 1289d735a..a57fc4a09 100644 --- a/src/platform/qt/ts/mgba-en.ts +++ b/src/platform/qt/ts/mgba-en.ts @@ -3254,7 +3254,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::KeyEditor - + --- @@ -3934,17 +3934,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file @@ -5747,13 +5747,13 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + WebM - + MP4 @@ -5763,143 +5763,148 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + 4K - + &1080p - + &720p - + &480p - + &Native - + Format - + MKV - + AVI - - h.264 - - - - - h.264 (NVENC) - - - - + HEVC - + HEVC (NVENC) - + VP8 - + VP9 - + FFV1 - - + + None - + FLAC - + Opus - + Vorbis - + MP3 - + AAC - + Uncompressed - + Bitrate (kbps) - - VBR - - - - + ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions - + Lock aspect ratio - + Show advanced diff --git a/src/platform/qt/ts/mgba-fr.ts b/src/platform/qt/ts/mgba-fr.ts index efc5d5fe5..efb76f53d 100644 --- a/src/platform/qt/ts/mgba-fr.ts +++ b/src/platform/qt/ts/mgba-fr.ts @@ -3267,7 +3267,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.QGBA::KeyEditor - + --- --- @@ -3954,17 +3954,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 Impossible d'ouvrir le fichier vidéo de sortie : %1 - + Native (%0x%1) Natif (%0x%1) - + Select output file Choisir le fichier de sortie @@ -5760,28 +5760,28 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. - + WebM WebM - + Format Format - + MKV MKV - + AVI AVI - + MP4 MP4 @@ -5801,128 +5801,133 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.&Lossless - + 4K 4K - + &1080p &1080p - + &720p &720p - + &480p &480p - + &Native &Natif - - h.264 - H.264 - - - - h.264 (NVENC) - H.264 (NVENC) - - - + HEVC HEVC - + HEVC (NVENC) HEVC (NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - - + + None Aucun - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed Non compressé - + Bitrate (kbps) Bitrate (kbps) - - VBR - VBR - - - + ABR ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions Dimensions - + Lock aspect ratio Bloquer les proportions - + Show advanced Paramètres avancés diff --git a/src/platform/qt/ts/mgba-ja.ts b/src/platform/qt/ts/mgba-ja.ts index b4f26e674..20d65e461 100644 --- a/src/platform/qt/ts/mgba-ja.ts +++ b/src/platform/qt/ts/mgba-ja.ts @@ -3255,7 +3255,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::KeyEditor - + --- --- @@ -3935,17 +3935,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 出力ビデオファイルを開けませんでした: %1 - + Native (%0x%1) ネイティブ(%0x%1) - + Select output file 出力ファイルを選択 @@ -5740,28 +5740,28 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + WebM WebM - + Format フォーマット - + MKV MKV - + AVI AVI - + MP4 MP4 @@ -5781,128 +5781,133 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. ロスレス (&L) - + 4K 4K - + &1080p 1080p (&1) - + &720p 720p (&7) - + &480p 480p (&4) - + &Native ネイティブ (&N) - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + HEVC (NVENC) HEVC(NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - - + + None なし - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed 圧縮なし - + Bitrate (kbps) ビットレート(kbps) - - VBR - VBR - - - + ABR ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions サイズ - + Lock aspect ratio 縦横比を固定 - + Show advanced 詳細表示 diff --git a/src/platform/qt/ts/mgba-ko.ts b/src/platform/qt/ts/mgba-ko.ts index 49486127b..311cd0721 100644 --- a/src/platform/qt/ts/mgba-ko.ts +++ b/src/platform/qt/ts/mgba-ko.ts @@ -3255,7 +3255,7 @@ Game Boy Advance는 Nintendo Co., Ltd.의 등록 상표입니다. QGBA::KeyEditor - + --- --- @@ -3935,17 +3935,17 @@ Game Boy Advance는 Nintendo Co., Ltd.의 등록 상표입니다. QGBA::VideoView - + Failed to open output video file: %1 출력 비디오 파일을 열지 못했습니다: %1 - + Native (%0x%1) 기본 (%0x%1) - + Select output file 출력 파일 선택 @@ -5740,48 +5740,38 @@ Game Boy Advance는 Nintendo Co., Ltd.의 등록 상표입니다. - + WebM WebM - + Format 형식 - + MKV MKV - + AVI AVI - + MP4 MP4 - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + VP8 VP8 @@ -5801,108 +5791,123 @@ Game Boy Advance는 Nintendo Co., Ltd.의 등록 상표입니다. - + 4K 480p {4K?} - + &1080p - + &720p - + &480p - + &Native - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + HEVC (NVENC) - + VP9 VP9 - + FFV1 FFV1 - - + + None 없음 - + FLAC FLAC - + Opus 오푸스 - + Vorbis 보비스 - + MP3 MP3 - + AAC AAC - + Uncompressed 미압축 - + Bitrate (kbps) 전송률 (kbps) - - VBR - VBR - - - + ABR ABR - + + VBR + VBR + + + + CRF + + + + Dimensions 크기 - + Lock aspect ratio 화면비 잠금 - + Show advanced 고급 보기 diff --git a/src/platform/qt/ts/mgba-nl.ts b/src/platform/qt/ts/mgba-nl.ts index c2a7d8081..32e21111e 100644 --- a/src/platform/qt/ts/mgba-nl.ts +++ b/src/platform/qt/ts/mgba-nl.ts @@ -3254,7 +3254,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::KeyEditor - + --- @@ -3934,17 +3934,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file @@ -5747,7 +5747,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + WebM @@ -5757,149 +5757,154 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + &1080p - + &720p - + &480p - + &Native - + Format - + MKV - + AVI - + MP4 - + 4K - - h.264 - - - - - h.264 (NVENC) - - - - + HEVC - + HEVC (NVENC) - + VP8 - + VP9 - + FFV1 - - + + None - + FLAC - + Opus - + Vorbis - + MP3 - + AAC - + Uncompressed - + Bitrate (kbps) - - VBR - - - - + ABR - + + H.264 + + + + + H.264 (NVENC) + + + + + VBR + + + + + CRF + + + + Dimensions - + Lock aspect ratio - + Show advanced diff --git a/src/platform/qt/ts/mgba-pt_BR.ts b/src/platform/qt/ts/mgba-pt_BR.ts index 1d954a85f..8e230bed4 100644 --- a/src/platform/qt/ts/mgba-pt_BR.ts +++ b/src/platform/qt/ts/mgba-pt_BR.ts @@ -3255,7 +3255,7 @@ Game Boy Advance é uma marca registrada da Nintendo Co., Ltd. QGBA::KeyEditor - + --- --- @@ -3935,17 +3935,17 @@ Game Boy Advance é uma marca registrada da Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 Falha ao abrir arquivo de vídeo de saída: %1 - + Native (%0x%1) Nativo (%0x%1) - + Select output file Selecione o arquivo de saída @@ -5740,28 +5740,28 @@ Game Boy Advance é uma marca registrada da Nintendo Co., Ltd. - + WebM WebM - + Format Formato - + MKV MKV - + AVI AVI - + MP4 MP4 @@ -5781,128 +5781,133 @@ Game Boy Advance é uma marca registrada da Nintendo Co., Ltd. &Sem perdas - + 4K 4K - + &1080p &1080p - + &720p &720p - + &480p &480p - + &Native &Nativo - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + HEVC (NVENC) HEVC (NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - - + + None Nenhum - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed Sem compressão - + Bitrate (kbps) Bitrate (kbps) - - VBR - VBR - - - + ABR ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions Dimensões - + Lock aspect ratio Fixar proporção - + Show advanced Mostrar opções avançadas diff --git a/src/platform/qt/ts/mgba-ru.ts b/src/platform/qt/ts/mgba-ru.ts index c812060b4..149d2ed15 100644 --- a/src/platform/qt/ts/mgba-ru.ts +++ b/src/platform/qt/ts/mgba-ru.ts @@ -3254,7 +3254,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::KeyEditor - + --- @@ -3934,17 +3934,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file @@ -5747,7 +5747,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + WebM @@ -5757,149 +5757,154 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + &1080p - + &720p - + &480p - + &Native - + Format - + MKV - + AVI - + MP4 - + 4K - - h.264 - - - - - h.264 (NVENC) - - - - + HEVC - + HEVC (NVENC) - + VP8 - + VP9 - + FFV1 - - + + None - + FLAC - + Opus - + Vorbis - + MP3 - + AAC - + Uncompressed - + Bitrate (kbps) - - VBR - - - - + ABR - + + H.264 + + + + + H.264 (NVENC) + + + + + VBR + + + + + CRF + + + + Dimensions - + Lock aspect ratio - + Show advanced diff --git a/src/platform/qt/ts/mgba-template.ts b/src/platform/qt/ts/mgba-template.ts index c5cae8561..e22b01476 100644 --- a/src/platform/qt/ts/mgba-template.ts +++ b/src/platform/qt/ts/mgba-template.ts @@ -3254,7 +3254,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::KeyEditor - + --- @@ -3934,17 +3934,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file @@ -5747,13 +5747,13 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + WebM - + MP4 @@ -5763,143 +5763,148 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + 4K - + &1080p - + &720p - + &480p - + &Native - + Format - + MKV - + AVI - - h.264 - - - - - h.264 (NVENC) - - - - + HEVC - + HEVC (NVENC) - + VP8 - + VP9 - + FFV1 - - + + None - + FLAC - + Opus - + Vorbis - + MP3 - + AAC - + Uncompressed - + Bitrate (kbps) - - VBR - - - - + ABR - + + H.264 + + + + + H.264 (NVENC) + + + + + VBR + + + + + CRF + + + + Dimensions - + Lock aspect ratio - + Show advanced diff --git a/src/platform/qt/ts/mgba-tr.ts b/src/platform/qt/ts/mgba-tr.ts index 36a67c7c8..fec67327d 100644 --- a/src/platform/qt/ts/mgba-tr.ts +++ b/src/platform/qt/ts/mgba-tr.ts @@ -3255,7 +3255,7 @@ Game Boy Advance, Nintendo Co., Ltd.'nin tescilli ticari markasıdır.QGBA::KeyEditor - + --- @@ -3935,17 +3935,17 @@ Game Boy Advance, Nintendo Co., Ltd.'nin tescilli ticari markasıdır. QGBA::VideoView - + Failed to open output video file: %1 Çıkış video dosyası açılamadı:%1 - + Native (%0x%1) - + Select output file Çıkış dosyasını seç @@ -5750,7 +5750,7 @@ Game Boy Advance, Nintendo Co., Ltd.'nin tescilli ticari markasıdır. - + WebM @@ -5760,149 +5760,154 @@ Game Boy Advance, Nintendo Co., Ltd.'nin tescilli ticari markasıdır. - + &1080p - + &720p - + &480p - + &Native - + Format Format - + MKV - + AVI - + MP4 - + 4K - - h.264 - - - - - h.264 (NVENC) - - - - + HEVC - + HEVC (NVENC) - + VP8 - + VP9 - + FFV1 - - + + None Hiçbiri - + FLAC - + Opus - + Vorbis - + MP3 - + AAC - + Uncompressed Sıkıştırılmamış - + Bitrate (kbps) - - VBR - - - - + ABR - + + H.264 + + + + + H.264 (NVENC) + + + + + VBR + + + + + CRF + + + + Dimensions Boyutlar - + Lock aspect ratio En boy oranını kilitle - + Show advanced Gelişmişi göster diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 3506b8719..2dd6bf7ff 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -3255,7 +3255,7 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::KeyEditor - + --- --- @@ -3935,17 +3935,17 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 QGBA::VideoView - + Failed to open output video file: %1 打开输出视频文件失败: %1 - + Native (%0x%1) 原生 (%0x%1) - + Select output file 选择输出文件 @@ -5750,13 +5750,13 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 - + WebM WebM - + MP4 MP4 @@ -5766,143 +5766,148 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 无损(&L) - + 4K 4K - + &1080p 1080p(&1) - + &720p 720p(&7) - + &480p 480p(&4) - + &Native 原生(&N) - + Format 格式 - + MKV MKV - + AVI AVI - - h.264 - h.264 - - - - h.264 (NVENC) - h.264 (NVENC) - - - + HEVC HEVC - + HEVC (NVENC) HEVC (NVENC) - + VP8 VP8 - + VP9 VP9 - + FFV1 FFV1 - - + + None - + FLAC FLAC - + Opus Opus - + Vorbis Vorbis - + MP3 MP3 - + AAC AAC - + Uncompressed 未压缩 - + Bitrate (kbps) 比特率 (kbps) - - VBR - VBR - - - + ABR ABR - + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + + + + Dimensions 维度 - + Lock aspect ratio 锁定纵横比 - + Show advanced 显示高级选项 diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 8cc007524..02adf12e2 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -94,7 +94,9 @@ static int enqueuedBuffers; static bool frameLimiter = true; static unsigned framecount = 0; static unsigned framecap = 10; -static u32 vibrationDeviceHandles[4]; +static PadState pad; +static HidSixAxisSensorHandle sixaxisHandles[4]; +static HidVibrationDeviceHandle vibrationDeviceHandles[4]; static HidVibrationValue vibrationStop = { .freq_low = 160.f, .freq_high = 320.f }; static bool usePbo = true; static u8 vmode; @@ -104,6 +106,9 @@ static bool interframeBlending = false; static bool sgbCrop = false; static bool useLightSensor = true; static struct mGUIRunnerLux lightSensor; +static float gyroZ = 0; +static float tiltX = 0; +static float tiltY = 0; static enum ScreenMode { SM_PA, @@ -192,12 +197,11 @@ static void _drawEnd(void) { static uint32_t _pollInput(const struct mInputMap* map) { int keys = 0; - hidScanInput(); - u32 padkeys = hidKeysHeld(CONTROLLER_P1_AUTO); + padUpdate(&pad); + u32 padkeys = padGetButtons(&pad); keys |= mInputMapKeyBits(map, AUTO_INPUT, padkeys, 0); - JoystickPosition jspos; - hidJoystickRead(&jspos, CONTROLLER_P1_AUTO, JOYSTICK_LEFT); + HidAnalogStickState jspos = padGetStickPos(&pad, 0); int l = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_LSTICK_LEFT)); int r = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_LSTICK_RIGHT)); @@ -217,45 +221,43 @@ static uint32_t _pollInput(const struct mInputMap* map) { d = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_DDOWN)); } - if (jspos.dx < -ANALOG_DEADZONE && l != -1) { + if (jspos.x < -ANALOG_DEADZONE && l != -1) { keys |= 1 << l; } - if (jspos.dx > ANALOG_DEADZONE && r != -1) { + if (jspos.x > ANALOG_DEADZONE && r != -1) { keys |= 1 << r; } - if (jspos.dy < -ANALOG_DEADZONE && d != -1) { + if (jspos.y < -ANALOG_DEADZONE && d != -1) { keys |= 1 << d; } - if (jspos.dy > ANALOG_DEADZONE && u != -1) { + if (jspos.y > ANALOG_DEADZONE && u != -1) { keys |= 1 << u; } return keys; } static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { - hidScanInput(); - if (hidTouchCount() < 1) { + HidTouchScreenState state = {0}; + hidGetTouchScreenStates(&state, 1); + if (state.count < 1) { return GUI_CURSOR_NOT_PRESENT; } - touchPosition touch; - hidTouchRead(&touch, 0); - *x = touch.px; - *y = touch.py; + *x = state.touches[0].x; + *y = state.touches[0].y; return GUI_CURSOR_DOWN; } - static void _setup(struct mGUIRunner* runner) { - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_A, GBA_KEY_A); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_B, GBA_KEY_B); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_PLUS, GBA_KEY_START); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_MINUS, GBA_KEY_SELECT); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_DUP, GBA_KEY_UP); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_DDOWN, GBA_KEY_DOWN); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_DLEFT, GBA_KEY_LEFT); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_DRIGHT, GBA_KEY_RIGHT); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_L, GBA_KEY_L); - _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_R, GBA_KEY_R); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_A, GBA_KEY_A); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_B, GBA_KEY_B); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_Plus, GBA_KEY_START); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_Minus, GBA_KEY_SELECT); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_Up, GBA_KEY_UP); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_Down, GBA_KEY_DOWN); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_Left, GBA_KEY_LEFT); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_Right, GBA_KEY_RIGHT); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_L, GBA_KEY_L); + _mapKey(&runner->core->inputMap, AUTO_INPUT, HidNpadButton_R, GBA_KEY_R); int fakeBool; if (mCoreConfigGetIntValue(&runner->config, "hwaccelVideo", &fakeBool) && fakeBool && runner->core->supportsFeature(runner->core, mCORE_FEATURE_OPENGL)) { @@ -518,7 +520,7 @@ static bool _running(struct mGUIRunner* runner) { UNUSED(runner); u8 newMode = appletGetOperationMode(); if (newMode != vmode) { - if (newMode == AppletOperationMode_Docked) { + if (newMode == AppletOperationMode_Console) { vwidth = 1920; vheight = 1080; } else { @@ -570,25 +572,41 @@ void _setRumble(struct mRumble* rumble, int enable) { } } +void _sampleRotation(struct mRotationSource* source) { + HidSixAxisSensorState sixaxis = {0}; + u64 styles = padGetStyleSet(&pad); + if (styles & HidNpadStyleTag_NpadHandheld) { + hidGetSixAxisSensorStates(sixaxisHandles[3], &sixaxis, 1); + } else if (styles & HidNpadStyleTag_NpadFullKey) { + hidGetSixAxisSensorStates(sixaxisHandles[2], &sixaxis, 1); + } else if (styles & HidNpadStyleTag_NpadJoyDual) { + u64 attrib = padGetAttributes(&pad); + if (attrib & HidNpadAttribute_IsLeftConnected) { + hidGetSixAxisSensorStates(sixaxisHandles[0], &sixaxis, 1); + } else if (attrib & HidNpadAttribute_IsRightConnected) { + hidGetSixAxisSensorStates(sixaxisHandles[1], &sixaxis, 1); + } else { + return; + } + } + tiltX = sixaxis.acceleration.x * 3e8f; + tiltY = sixaxis.acceleration.y * -3e8f; + gyroZ = sixaxis.angular_velocity.z * -1.1e9f; +} + int32_t _readTiltX(struct mRotationSource* source) { UNUSED(source); - SixAxisSensorValues sixaxis; - hidSixAxisSensorValuesRead(&sixaxis, CONTROLLER_P1_AUTO, 1); - return sixaxis.accelerometer.x * 3e8f; + return tiltX; } int32_t _readTiltY(struct mRotationSource* source) { UNUSED(source); - SixAxisSensorValues sixaxis; - hidSixAxisSensorValuesRead(&sixaxis, CONTROLLER_P1_AUTO, 1); - return sixaxis.accelerometer.y * -3e8f; + return tiltY; } int32_t _readGyroZ(struct mRotationSource* source) { UNUSED(source); - SixAxisSensorValues sixaxis; - hidSixAxisSensorValuesRead(&sixaxis, CONTROLLER_P1_AUTO, 1); - return sixaxis.gyroscope.z * -1.1e9f; + return gyroZ; } static void _lightSensorSample(struct GBALuminanceSource* lux) { @@ -636,7 +654,7 @@ int main(int argc, char* argv[]) { struct GUIFont* font = GUIFontCreate(); vmode = appletGetOperationMode(); - if (vmode == AppletOperationMode_Docked) { + if (vmode == AppletOperationMode_Console) { vwidth = 1920; vheight = 1080; } else { @@ -732,23 +750,27 @@ int main(int argc, char* argv[]) { glEnableVertexAttribArray(offsetLocation); glBindVertexArray(0); + hidInitializeTouchScreen(); + padConfigureInput(1, HidNpadStyleSet_NpadStandard); + padInitializeDefault(&pad); + rumble.d.setRumble = _setRumble; rumble.value.freq_low = 120.0; rumble.value.freq_high = 180.0; - hidInitializeVibrationDevices(&vibrationDeviceHandles[0], 2, CONTROLLER_HANDHELD, TYPE_HANDHELD | TYPE_JOYCON_PAIR); - hidInitializeVibrationDevices(&vibrationDeviceHandles[2], 2, CONTROLLER_PLAYER_1, TYPE_HANDHELD | TYPE_JOYCON_PAIR); + hidInitializeVibrationDevices(&vibrationDeviceHandles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld); + hidInitializeVibrationDevices(&vibrationDeviceHandles[2], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual); - u32 handles[4]; - hidGetSixAxisSensorHandles(&handles[0], 2, CONTROLLER_PLAYER_1, TYPE_JOYCON_PAIR); - hidGetSixAxisSensorHandles(&handles[2], 1, CONTROLLER_PLAYER_1, TYPE_PROCONTROLLER); - hidGetSixAxisSensorHandles(&handles[3], 1, CONTROLLER_HANDHELD, TYPE_HANDHELD); - hidStartSixAxisSensor(handles[0]); - hidStartSixAxisSensor(handles[1]); - hidStartSixAxisSensor(handles[2]); - hidStartSixAxisSensor(handles[3]); + hidGetSixAxisSensorHandles(&sixaxisHandles[0], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual); + hidGetSixAxisSensorHandles(&sixaxisHandles[2], 1, HidNpadIdType_No1, HidNpadStyleTag_NpadFullKey); + hidGetSixAxisSensorHandles(&sixaxisHandles[3], 1, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld); + hidStartSixAxisSensor(sixaxisHandles[0]); + hidStartSixAxisSensor(sixaxisHandles[1]); + hidStartSixAxisSensor(sixaxisHandles[2]); + hidStartSixAxisSensor(sixaxisHandles[3]); rotation.readTiltX = _readTiltX; rotation.readTiltY = _readTiltY; rotation.readGyroZ = _readGyroZ; + rotation.sample = _sampleRotation; lightSensor.d.readLuminance = _lightSensorRead; lightSensor.d.sample = _lightSensorSample; @@ -984,10 +1006,10 @@ int main(int argc, char* argv[]) { glDeleteProgram(program); glDeleteVertexArrays(1, &vao); - hidStopSixAxisSensor(handles[0]); - hidStopSixAxisSensor(handles[1]); - hidStopSixAxisSensor(handles[2]); - hidStopSixAxisSensor(handles[3]); + hidStopSixAxisSensor(sixaxisHandles[0]); + hidStopSixAxisSensor(sixaxisHandles[1]); + hidStopSixAxisSensor(sixaxisHandles[2]); + hidStopSixAxisSensor(sixaxisHandles[3]); psmExit(); audoutExit(); diff --git a/tools/perf.py b/tools/perf.py index 75f05fb7f..2793e53be 100755 --- a/tools/perf.py +++ b/tools/perf.py @@ -71,6 +71,7 @@ class GameClockTest(PerfTest): class PerfServer(object): ITERATIONS_PER_INSTANCE = 50 + RETRIES = 5 def __init__(self, address, root='/', command=None): s = address.rsplit(':', 1) @@ -100,8 +101,17 @@ class PerfServer(object): elif test.renderer == 'threaded-software': server_command.append('-T') subprocess.check_call(server_command) - time.sleep(4) - self.socket = socket.create_connection(self.address, timeout=1000) + time.sleep(3) + for backoff in range(self.RETRIES): + try: + self.socket = socket.create_connection(self.address, timeout=1000) + break + except OSError as e: + print("Failed to connect:", e, file=sys.stderr) + if backoff < self.RETRIES - 1: + time.sleep(2 ** backoff) + else: + raise kwargs = {} if sys.version_info[0] >= 3: kwargs["encoding"] = "utf-8" @@ -156,8 +166,10 @@ class Suite(object): sock = None for test in self.tests: print('Running test {}'.format(test.name), file=sys.stderr) + last_result = None if self.server: self.server.run(test) + last_result = self.server.results[-1] else: try: test.run(self.cwd) @@ -166,6 +178,9 @@ class Suite(object): return results if test.results: results.append(test.results) + last_result = results[-1] + if last_result: + print('{:.2f} fps'.format(int(last_result['frames']) * 1000000 / float(last_result['duration'])), file=sys.stderr) if self.server: self.server.finish() results.extend(self.server.results)