Qt: Clean up video recording for GB

This commit is contained in:
Jeffrey Pfau 2016-09-06 20:41:55 -07:00
parent c0689783da
commit 8c8361477d
6 changed files with 307 additions and 254 deletions

View File

@ -16,7 +16,6 @@ struct NoIntroDB;
extern "C" {
#include "core/log.h"
#include "gba/sio.h"
}
mLOG_DECLARE_CATEGORY(QT);

View File

@ -12,6 +12,12 @@
#include <QMap>
#ifdef M_CORE_GB
extern "C" {
#include "gb/video.h"
}
#endif
using namespace QGBA;
QMap<QString, QString> VideoView::s_acodecMap;
@ -34,10 +40,10 @@ bool VideoView::Preset::compatible(const Preset& other) const {
if (other.vbr && vbr && other.vbr != vbr) {
return false;
}
if (other.width && width && other.width != width) {
if (other.dims.width() && dims.width() && other.dims.width() != dims.width()) {
return false;
}
if (other.height && height && other.height != height) {
if (other.dims.height() && dims.height() && other.dims.height() != dims.height()) {
return false;
}
return true;
@ -48,6 +54,10 @@ VideoView::VideoView(QWidget* parent)
, m_audioCodecCstr(nullptr)
, m_videoCodecCstr(nullptr)
, m_containerCstr(nullptr)
, m_nativeWidth(0)
, m_nativeHeight(0)
, m_width(1)
, m_height(1)
{
m_ui.setupUi(this);
@ -96,67 +106,80 @@ VideoView::VideoView(QWidget* parent)
FFmpegEncoderInit(&m_encoder);
addPreset(m_ui.preset1080, (Preset) {
updatePresets();
setPreset({
.container = "MKV",
.vcodec = "PNG",
.acodec = "FLAC",
.vbr = 0,
.abr = 0,
.dims = QSize(),
});
showAdvanced(false);
}
void VideoView::updatePresets() {
m_presets.clear();
addPreset(m_ui.preset1080, {
.container = QString(),
.vcodec = QString(),
.acodec = QString(),
.vbr = 0,
.abr = 0,
.width = 1620,
.height = 1080
.dims = maintainAspect(QSize(1920, 1080))
});
addPreset(m_ui.preset720, (Preset) {
addPreset(m_ui.preset720, {
.container = QString(),
.vcodec = QString(),
.acodec = QString(),
.vbr = 0,
.abr = 0,
.width = 1080,
.height = 720
.dims = maintainAspect(QSize(1280, 720))
});
addPreset(m_ui.preset480, (Preset) {
addPreset(m_ui.preset480, {
.container = QString(),
.vcodec = QString(),
.acodec = QString(),
.vbr = 0,
.abr = 0,
.width = 720,
.height = 480
.dims = maintainAspect(QSize(720, 480))
});
addPreset(m_ui.preset160, (Preset) {
.container = QString(),
.vcodec = QString(),
.acodec = QString(),
.vbr = 0,
.abr = 0,
.width = VIDEO_HORIZONTAL_PIXELS,
.height = VIDEO_VERTICAL_PIXELS
});
if (m_nativeWidth && m_nativeHeight) {
addPreset(m_ui.presetNative, {
.container = QString(),
.vcodec = QString(),
.acodec = QString(),
.vbr = 0,
.abr = 0,
.dims = QSize(m_nativeWidth, m_nativeHeight)
});
m_ui.presetNative->setEnabled(true);
}
addPreset(m_ui.presetHQ, (Preset) {
addPreset(m_ui.presetHQ, {
.container = "MP4",
.vcodec = "h.264",
.acodec = "AAC",
.vbr = 8000,
.abr = 384,
.width = 1620,
.height = 1080
.dims = maintainAspect(QSize(1920, 1080))
});
addPreset(m_ui.presetYoutube, (Preset) {
addPreset(m_ui.presetYoutube, {
.container = "MP4",
.vcodec = "h.264",
.acodec = "AAC",
.vbr = 5000,
.abr = 256,
.width = 1080,
.height = 720
.dims = maintainAspect(QSize(1280, 720))
});
addPreset(m_ui.presetWebM, (Preset) {
addPreset(m_ui.presetWebM, {
.container = "WebM",
.vcodec = "VP8",
.acodec = "Vorbis",
@ -164,27 +187,16 @@ VideoView::VideoView(QWidget* parent)
.abr = 128
});
addPreset(m_ui.presetLossless, (Preset) {
.container = "MKV",
.vcodec = "PNG",
.acodec = "FLAC",
.vbr = 0,
.abr = 0,
.width = VIDEO_HORIZONTAL_PIXELS,
.height = VIDEO_VERTICAL_PIXELS,
});
setPreset((Preset) {
.container = "MKV",
.vcodec = "PNG",
.acodec = "FLAC",
.vbr = 0,
.abr = 0,
.width = VIDEO_HORIZONTAL_PIXELS,
.height = VIDEO_VERTICAL_PIXELS,
});
showAdvanced(false);
if (m_nativeWidth && m_nativeHeight) {
addPreset(m_ui.presetLossless, {
.container = "MKV",
.vcodec = "PNG",
.acodec = "FLAC",
.vbr = 0,
.abr = 0,
.dims = QSize(m_nativeWidth, m_nativeHeight)
});
}
}
VideoView::~VideoView() {
@ -214,6 +226,23 @@ void VideoView::stopRecording() {
validateSettings();
}
void VideoView::setNativeResolution(const QSize& dims) {
m_nativeWidth = dims.width();
m_nativeHeight = dims.height();
m_ui.presetNative->setText(tr("Native (%0x%1)").arg(m_nativeWidth).arg(m_nativeHeight));
QSize newSize = maintainAspect(QSize(m_width, m_height));
m_width = newSize.width();
m_height = newSize.height();
updateAspectRatio(m_nativeWidth, m_nativeHeight, false);
updatePresets();
for (auto iterator = m_presets.constBegin(); iterator != m_presets.constEnd(); ++iterator) {
if (iterator.key()->isChecked()) {
setPreset(*iterator);
break;
}
}
}
void VideoView::selectFile() {
QString filename = GBAApp::app()->getSaveFileName(this, tr("Select output file"));
if (!filename.isEmpty()) {
@ -295,7 +324,7 @@ void VideoView::setVideoBitrate(int br, bool manual) {
void VideoView::setWidth(int width, bool manual) {
m_width = width;
updateAspectRatio(width, 0);
updateAspectRatio(width, 0, false);
FFmpegEncoderSetDimensions(&m_encoder, m_width, m_height);
if (manual) {
uncheckIncompatible();
@ -304,7 +333,7 @@ void VideoView::setWidth(int width, bool manual) {
void VideoView::setHeight(int height, bool manual) {
m_height = height;
updateAspectRatio(0, height);
updateAspectRatio(0, height, false);
FFmpegEncoderSetDimensions(&m_encoder, m_width, m_height);
if (manual) {
uncheckIncompatible();
@ -401,8 +430,7 @@ void VideoView::uncheckIncompatible() {
.acodec = m_audioCodec,
.vbr = m_vbr / 1000,
.abr = m_abr / 1000,
.width = m_width,
.height = m_height
.dims = QSize(m_width, m_height)
};
m_ui.presets->setExclusive(false);
@ -419,8 +447,8 @@ void VideoView::uncheckIncompatible() {
m_ui.presets->setExclusive(true);
m_ui.resolutions->setExclusive(true);
if (current.compatible(m_presets[m_ui.preset160])) {
safelyCheck(m_ui.preset160);
if (current.compatible(m_presets[m_ui.presetNative])) {
safelyCheck(m_ui.presetNative);
}
if (current.compatible(m_presets[m_ui.preset480])) {
safelyCheck(m_ui.preset480);
@ -465,6 +493,7 @@ void VideoView::safelySet(QComboBox* box, const QString& value) {
void VideoView::addPreset(QAbstractButton* button, const Preset& preset) {
m_presets[button] = preset;
button->disconnect();
connect(button, &QAbstractButton::pressed, [this, preset]() {
setPreset(preset);
});
@ -491,17 +520,27 @@ void VideoView::setPreset(const Preset& preset) {
setVideoBitrate(preset.vbr, false);
safelySet(m_ui.vbr, preset.vbr);
}
if (preset.width) {
setWidth(preset.width, false);
safelySet(m_ui.width, preset.width);
if (preset.dims.width() > 0) {
setWidth(preset.dims.width(), false);
safelySet(m_ui.width, preset.dims.width());
}
if (preset.height) {
setHeight(preset.height, false);
safelySet(m_ui.height, preset.height);
if (preset.dims.height() > 0) {
setHeight(preset.dims.height(), false);
safelySet(m_ui.height, preset.dims.height());
}
uncheckIncompatible();
validateSettings();
}
QSize VideoView::maintainAspect(const QSize& size) {
QSize ds = size;
if (ds.width() * m_nativeHeight > ds.height() * m_nativeWidth) {
ds.setWidth(ds.height() * m_nativeWidth / m_nativeHeight);
} else if (ds.width() * m_nativeHeight < ds.height() * m_nativeWidth) {
ds.setHeight(ds.width() * m_nativeHeight / m_nativeWidth);
}
return ds;
}
#endif

View File

@ -22,18 +22,6 @@ class VideoView : public QWidget {
Q_OBJECT
public:
struct Preset {
QString container;
QString vcodec;
QString acodec;
int vbr;
int abr;
int width;
int height;
bool compatible(const Preset&) const;
};
VideoView(QWidget* parent = nullptr);
virtual ~VideoView();
@ -42,6 +30,7 @@ public:
public slots:
void startRecording();
void stopRecording();
void setNativeResolution(const QSize&);
signals:
void recordingStarted(mAVStream*);
@ -65,8 +54,20 @@ private slots:
void showAdvanced(bool);
void uncheckIncompatible();
void updatePresets();
private:
struct Preset {
QString container;
QString vcodec;
QString acodec;
int vbr;
int abr;
QSize dims;
bool compatible(const Preset&) const;
};
bool validateSettings();
void updateAspectRatio(int width, int height, bool force = false);
static QString sanitizeCodec(const QString&, const QMap<QString, QString>& mapping);
@ -77,6 +78,8 @@ private:
void addPreset(QAbstractButton*, const Preset&);
void setPreset(const Preset&);
QSize maintainAspect(const QSize&);
Ui::VideoView m_ui;
FFmpegEncoder m_encoder;
@ -95,6 +98,9 @@ private:
int m_width;
int m_height;
int m_nativeWidth;
int m_nativeHeight;
QMap<QAbstractButton*, Preset> m_presets;
static QMap<QString, QString> s_acodecMap;

View File

@ -181,9 +181,12 @@
</widget>
</item>
<item>
<widget class="QRadioButton" name="preset160">
<widget class="QRadioButton" name="presetNative">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>GBA (240x160)</string>
<string>Native</string>
</property>
<property name="checked">
<bool>true</bool>
@ -417,7 +420,7 @@
<item row="0" column="3">
<widget class="QSpinBox" name="height">
<property name="minimum">
<number>160</number>
<number>1</number>
</property>
<property name="maximum">
<number>3160</number>
@ -427,7 +430,7 @@
<item row="0" column="1">
<widget class="QSpinBox" name="width">
<property name="minimum">
<number>240</number>
<number>1</number>
</property>
<property name="maximum">
<number>3840</number>
@ -442,9 +445,6 @@
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="1">
@ -455,9 +455,6 @@
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>3</number>
</property>
</widget>
</item>
<item row="1" column="4">
@ -505,7 +502,7 @@
<tabstop>preset1080</tabstop>
<tabstop>preset720</tabstop>
<tabstop>preset480</tabstop>
<tabstop>preset160</tabstop>
<tabstop>presetNative</tabstop>
<tabstop>container</tabstop>
<tabstop>video</tabstop>
<tabstop>audio</tabstop>

View File

@ -492,6 +492,12 @@ void Window::openVideoWindow() {
connect(m_videoView, SIGNAL(recordingStopped()), m_controller, SLOT(clearAVStream()), Qt::DirectConnection);
connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_videoView, SLOT(stopRecording()));
connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_videoView, SLOT(close()));
connect(m_controller, &GameController::gameStarted, [this]() {
m_videoView->setNativeResolution(m_controller->screenDimensions());
});
if (m_controller->isLoaded()) {
m_videoView->setNativeResolution(m_controller->screenDimensions());
}
connect(this, SIGNAL(shutdown()), m_videoView, SLOT(close()));
}
m_videoView->show();
@ -1253,6 +1259,7 @@ void Window::setupMenu(QMenuBar* menubar) {
QAction* recordOutput = new QAction(tr("Record output..."), avMenu);
connect(recordOutput, SIGNAL(triggered()), this, SLOT(openVideoWindow()));
addControlledAction(avMenu, recordOutput, "recordOutput");
m_gameActions.append(recordOutput);
#endif
#ifdef USE_MAGICK

File diff suppressed because it is too large Load Diff