From b1dc519917cb441161dbe5db2d70b7958a0a068e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B5=AE=E7=94=9F=E8=8B=A5=E6=A2=A6?= <1070753498@qq.com>
Date: Thu, 29 Feb 2024 18:40:35 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84transcode-3=EF=BC=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 +-
examples/player/CMakeLists.txt | 13 +-
examples/player/main.cpp | 2 +-
examples/player/player.pro | 2 +-
examples/transcoder/CMakeLists.txt | 23 +-
examples/transcoder/audioencoderwidget.cc | 64 ++++
examples/transcoder/audioencoderwidget.hpp | 28 ++
examples/transcoder/main.cc | 2 +-
examples/transcoder/mainwindow.cc | 325 ++++-----------------
examples/transcoder/mainwindow.hpp | 2 -
examples/transcoder/outputwidget.cc | 64 ++++
examples/transcoder/outputwidget.hpp | 27 ++
examples/transcoder/previewwidget.cc | 1 +
examples/transcoder/sourcewidget.cc | 12 +-
examples/transcoder/stautuswidget.cc | 75 +++++
examples/transcoder/stautuswidget.hpp | 33 +++
examples/transcoder/transcoder.pro | 14 +-
examples/transcoder/videoencoderwidget.cc | 293 +++++++++++++++++++
examples/transcoder/videoencoderwidget.hpp | 54 ++++
ffmpeg/codeccontext.cpp | 4 +-
ffmpeg/ffmpegutils.cc | 4 +-
ffmpeg/transcoder.cc | 17 +-
ffmpeg/transcoder.hpp | 4 +-
23 files changed, 759 insertions(+), 308 deletions(-)
create mode 100644 examples/transcoder/audioencoderwidget.cc
create mode 100644 examples/transcoder/audioencoderwidget.hpp
create mode 100644 examples/transcoder/outputwidget.cc
create mode 100644 examples/transcoder/outputwidget.hpp
create mode 100644 examples/transcoder/stautuswidget.cc
create mode 100644 examples/transcoder/stautuswidget.hpp
create mode 100644 examples/transcoder/videoencoderwidget.cc
create mode 100644 examples/transcoder/videoencoderwidget.hpp
diff --git a/README.md b/README.md
index f3ff6b2..080f2ed 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
- [简体中文](README.md)
- [English](README.en.md)
-## QFfmpegPlayer
+## Player
@@ -56,7 +56,7 @@ Dialogue: 0,0:01:06.77,0:01:08.00,en,,0000,0000,0000,,Peek-a-boo!\r\n
subtitles=filename='%1':original_size=%2x%3
```
-## QFfmpegTranscoder
+## Transcoder
如何设置编码参数以获得更小的文件和更好的视频质量?
diff --git a/examples/player/CMakeLists.txt b/examples/player/CMakeLists.txt
index 392ac7e..c875166 100644
--- a/examples/player/CMakeLists.txt
+++ b/examples/player/CMakeLists.txt
@@ -22,14 +22,13 @@ set(PROJECT_SOURCES
titlewidget.cc
titlewidget.hpp)
-qt_add_executable(QFfmpegPlayer MANUAL_FINALIZATION ${PROJECT_SOURCES})
-target_link_libraries(
- QFfmpegPlayer PRIVATE ffmpeg thirdparty utils Qt6::Widgets Qt6::Multimedia
- Qt6::OpenGLWidgets)
-target_link_libraries(QFfmpegPlayer PRIVATE PkgConfig::ffmpeg)
+qt_add_executable(Player MANUAL_FINALIZATION ${PROJECT_SOURCES})
+target_link_libraries(Player PRIVATE ffmpeg thirdparty utils Qt6::Widgets
+ Qt6::Multimedia Qt6::OpenGLWidgets)
+target_link_libraries(Player PRIVATE PkgConfig::ffmpeg)
if(CMAKE_HOST_APPLE)
target_link_libraries(
- QFfmpegPlayer
+ Player
PRIVATE ${Foundation_LIBRARY}
${CoreAudio_LIBRARY}
${AVFoundation_LIBRARY}
@@ -46,4 +45,4 @@ if(CMAKE_HOST_APPLE)
${CoreVideo_LIBRARY}
${CoreServices_LIBRARY})
endif()
-qt_finalize_executable(QFfmpegPlayer)
+qt_finalize_executable(Player)
diff --git a/examples/player/main.cpp b/examples/player/main.cpp
index 8d34b3b..acc1480 100644
--- a/examples/player/main.cpp
+++ b/examples/player/main.cpp
@@ -11,7 +11,7 @@
#include
#include
-#define AppName "QFfmpegPlayer"
+#define AppName "Player"
void setAppInfo()
{
diff --git a/examples/player/player.pro b/examples/player/player.pro
index f923a5d..a923210 100644
--- a/examples/player/player.pro
+++ b/examples/player/player.pro
@@ -4,7 +4,7 @@ QT += core gui widgets network multimedia openglwidgets core5compat
TEMPLATE = app
-TARGET = QFfmpegPlayer
+TARGET = Player
LIBS += \
-L$$APP_OUTPUT_PATH/../libs \
diff --git a/examples/transcoder/CMakeLists.txt b/examples/transcoder/CMakeLists.txt
index f2162ae..1bf27b3 100644
--- a/examples/transcoder/CMakeLists.txt
+++ b/examples/transcoder/CMakeLists.txt
@@ -1,21 +1,28 @@
set(PROJECT_SOURCES
+ audioencoderwidget.cc
+ audioencoderwidget.hpp
main.cc
mainwindow.cc
mainwindow.hpp
+ outputwidget.cc
+ outputwidget.hpp
previewwidget.cc
previewwidget.hpp
sourcewidget.cc
- sourcewidget.hpp)
+ sourcewidget.hpp
+ stautuswidget.cc
+ stautuswidget.hpp
+ videoencoderwidget.cc
+ videoencoderwidget.hpp)
-qt_add_executable(QFfmpegTranscoder MANUAL_FINALIZATION ${PROJECT_SOURCES})
-target_link_libraries(
- QFfmpegTranscoder PRIVATE ffmpeg thirdparty utils Qt6::Widgets
- Qt6::Multimedia Qt6::OpenGLWidgets)
-target_link_libraries(QFfmpegTranscoder PRIVATE PkgConfig::ffmpeg)
+qt_add_executable(Transcoder MANUAL_FINALIZATION ${PROJECT_SOURCES})
+target_link_libraries(Transcoder PRIVATE ffmpeg thirdparty utils Qt6::Widgets
+ Qt6::Multimedia Qt6::OpenGLWidgets)
+target_link_libraries(Transcoder PRIVATE PkgConfig::ffmpeg)
if(CMAKE_HOST_APPLE)
target_link_libraries(
- QFfmpegTranscoder
+ Transcoder
PRIVATE ${Foundation_LIBRARY}
${CoreAudio_LIBRARY}
${AVFoundation_LIBRARY}
@@ -33,4 +40,4 @@ if(CMAKE_HOST_APPLE)
${CoreServices_LIBRARY})
endif()
-qt_finalize_executable(QFfmpegTranscoder)
+qt_finalize_executable(Transcoder)
diff --git a/examples/transcoder/audioencoderwidget.cc b/examples/transcoder/audioencoderwidget.cc
new file mode 100644
index 0000000..1ca1d2f
--- /dev/null
+++ b/examples/transcoder/audioencoderwidget.cc
@@ -0,0 +1,64 @@
+#include "audioencoderwidget.hpp"
+
+#include
+
+#include
+
+class AudioEncoderWidget::AudioEncoderWidgetPrivate
+{
+public:
+ explicit AudioEncoderWidgetPrivate(AudioEncoderWidget *q)
+ : q_ptr(q)
+ {
+ audioEncoderCbx = new QComboBox(q_ptr);
+ audioEncoderCbx->setView(new QListView(audioEncoderCbx));
+ audioEncoderCbx->setMaxVisibleItems(10);
+ audioEncoderCbx->setStyleSheet("QComboBox {combobox-popup:0;}");
+
+ auto audioEncodercs = Ffmpeg::getCurrentSupportCodecs(AVMEDIA_TYPE_AUDIO, true);
+ for (auto iter = audioEncodercs.cbegin(); iter != audioEncodercs.cend(); ++iter) {
+ audioEncoderCbx->addItem(iter.value(), iter.key());
+ }
+ audioEncoderCbx->setCurrentIndex(audioEncoderCbx->findData(AV_CODEC_ID_AAC));
+ audioEncoderCbx->model()->sort(0);
+ }
+
+ AudioEncoderWidget *q_ptr;
+
+ QComboBox *audioEncoderCbx;
+};
+
+AudioEncoderWidget::AudioEncoderWidget(QWidget *parent)
+ : QWidget{parent}
+ , d_ptr(new AudioEncoderWidgetPrivate(this))
+{
+ setupUI();
+ buildConnect();
+}
+
+AudioEncoderWidget::~AudioEncoderWidget() = default;
+
+auto AudioEncoderWidget::setEncoder(AVCodecID codecId) -> bool
+{
+ auto index = d_ptr->audioEncoderCbx->findData(codecId);
+ auto finded = (index >= 0);
+ if (finded) {
+ d_ptr->audioEncoderCbx->setCurrentIndex(index);
+ }
+ return finded;
+}
+
+auto AudioEncoderWidget::encoder() const -> QString
+{
+ return d_ptr->audioEncoderCbx->currentText();
+}
+
+void AudioEncoderWidget::setupUI()
+{
+ auto *layout = new QHBoxLayout(this);
+ layout->addWidget(new QLabel(tr("Encoder:")));
+ layout->addWidget(d_ptr->audioEncoderCbx);
+ layout->addStretch();
+}
+
+void AudioEncoderWidget::buildConnect() {}
diff --git a/examples/transcoder/audioencoderwidget.hpp b/examples/transcoder/audioencoderwidget.hpp
new file mode 100644
index 0000000..da98530
--- /dev/null
+++ b/examples/transcoder/audioencoderwidget.hpp
@@ -0,0 +1,28 @@
+#ifndef AUDIOENCODERWIDGET_HPP
+#define AUDIOENCODERWIDGET_HPP
+
+#include
+
+extern "C" {
+#include
+}
+
+class AudioEncoderWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit AudioEncoderWidget(QWidget *parent = nullptr);
+ ~AudioEncoderWidget() override;
+
+ auto setEncoder(AVCodecID codecId) -> bool;
+ [[nodiscard]] auto encoder() const -> QString;
+
+private:
+ void setupUI();
+ void buildConnect();
+
+ class AudioEncoderWidgetPrivate;
+ QScopedPointer d_ptr;
+};
+
+#endif // AUDIOENCODERWIDGET_HPP
diff --git a/examples/transcoder/main.cc b/examples/transcoder/main.cc
index fe92f34..ad22f24 100644
--- a/examples/transcoder/main.cc
+++ b/examples/transcoder/main.cc
@@ -10,7 +10,7 @@
#include
#include
-#define AppnName "QFfmpegTranscoder"
+#define AppnName "Transcoder"
void setAppInfo()
{
diff --git a/examples/transcoder/mainwindow.cc b/examples/transcoder/mainwindow.cc
index 52291b7..1295182 100644
--- a/examples/transcoder/mainwindow.cc
+++ b/examples/transcoder/mainwindow.cc
@@ -1,6 +1,10 @@
#include "mainwindow.hpp"
+#include "audioencoderwidget.hpp"
+#include "outputwidget.hpp"
#include "previewwidget.hpp"
#include "sourcewidget.hpp"
+#include "stautuswidget.hpp"
+#include "videoencoderwidget.hpp"
#include
#include
@@ -12,8 +16,6 @@
#include
-#define BUTTON_SIZE QSize(100, 35)
-
class MainWindow::MainWindowPrivate
{
public:
@@ -27,108 +29,24 @@ class MainWindow::MainWindowPrivate
sourceWidget = new SourceWidget(q_ptr);
tabWidget = new QTabWidget(q_ptr);
previewWidget = new PreviewWidget(q_ptr);
+ videoEncoderWidget = new VideoEncoderWidget(q_ptr);
+ videoEncoderWidget->setPreset(transcoder->presets(), transcoder->preset());
+ videoEncoderWidget->setTune(transcoder->tunes(), transcoder->tune());
+ videoEncoderWidget->setProfile(transcoder->profiles(), transcoder->profile());
+ audioEncoderWidget = new AudioEncoderWidget(q_ptr);
tabWidget->addTab(previewWidget,
QCoreApplication::translate("MainWindowPrivate", "Preview"));
+ tabWidget->addTab(videoEncoderWidget,
+ QCoreApplication::translate("MainWindowPrivate", "Video"));
+ tabWidget->addTab(audioEncoderWidget,
+ QCoreApplication::translate("MainWindowPrivate", "Audio"));
- subtitleTextEdit = new QTextEdit(q_ptr);
- outTextEdit = new QTextEdit(q_ptr);
-
- audioCodecCbx = new QComboBox(q_ptr);
- audioCodecCbx->setView(new QListView(audioCodecCbx));
- audioCodecCbx->setMaxVisibleItems(10);
- audioCodecCbx->setStyleSheet("QComboBox {combobox-popup:0;}");
- auto audioCodecs = Ffmpeg::getCurrentSupportCodecs(AVMEDIA_TYPE_AUDIO, true);
- for (auto iter = audioCodecs.cbegin(); iter != audioCodecs.cend(); ++iter) {
- audioCodecCbx->addItem(iter.value(), iter.key());
- }
- audioCodecCbx->setCurrentIndex(audioCodecCbx->findData(AV_CODEC_ID_AAC));
-
- videoCodecCbx = new QComboBox(q_ptr);
- videoCodecCbx->setView(new QListView(videoCodecCbx));
- videoCodecCbx->setMaxVisibleItems(10);
- videoCodecCbx->setStyleSheet("QComboBox {combobox-popup:0;}");
- auto videoCodecs = Ffmpeg::getCurrentSupportCodecs(AVMEDIA_TYPE_VIDEO, true);
- for (auto iter = videoCodecs.cbegin(); iter != videoCodecs.cend(); ++iter) {
- videoCodecCbx->addItem(iter.value(), iter.key());
- }
- videoCodecCbx->setCurrentIndex(videoCodecCbx->findData(AV_CODEC_ID_H264));
-
- quailtySbx = new QSpinBox(q_ptr);
- quailtySbx->setRange(2, 31);
- quailtySbx->setToolTip(tr("smaller -> better"));
- crfSbx = new QSpinBox(q_ptr);
- crfSbx->setRange(0, 51);
- crfSbx->setToolTip(tr("smaller -> better"));
- crfSbx->setValue(18);
- presetCbx = new QComboBox(q_ptr);
- presetCbx->setView(new QListView(presetCbx));
- presetCbx->addItems(transcoder->presets());
- presetCbx->setCurrentText(transcoder->preset());
- tuneCbx = new QComboBox(q_ptr);
- tuneCbx->setView(new QListView(tuneCbx));
- tuneCbx->addItems(transcoder->tunes());
- tuneCbx->setCurrentText(transcoder->tune());
- profileCbx = new QComboBox(q_ptr);
- profileCbx->setView(new QListView(profileCbx));
- profileCbx->addItems(transcoder->profiles());
- profileCbx->setCurrentText(transcoder->profile());
-
- widthLineEdit = new QLineEdit(q_ptr);
- widthLineEdit->setValidator(new QIntValidator(0, INT_MAX, widthLineEdit));
- heightLineEdit = new QLineEdit(q_ptr);
- heightLineEdit->setValidator(new QIntValidator(0, INT_MAX, heightLineEdit));
- keepAspectRatioCkb = new QCheckBox(tr("keepAspectRatio"), q_ptr);
- keepAspectRatioCkb->setChecked(true);
-
- videoMinBitrateLineEdit = new QLineEdit(q_ptr);
- videoMaxBitrateLineEdit = new QLineEdit(q_ptr);
-
- startButton = new QToolButton(q_ptr);
- startButton->setText(QObject::tr("Start"));
- startButton->setMinimumSize(BUTTON_SIZE);
- progressBar = new QProgressBar(q_ptr);
- progressBar->setRange(0, 100);
- fpsLabel = new QLabel(q_ptr);
- fpsLabel->setToolTip(QObject::tr("Video Encoder FPS."));
- fpsTimer = new QTimer(q_ptr);
- }
+ outPutWidget = new OutPutWidget(q_ptr);
+ statusWidget = new StautusWidget(q_ptr);
- [[nodiscard]] auto initVideoSetting() const -> QGroupBox *
- {
- auto *layout1 = new QHBoxLayout;
- layout1->addWidget(new QLabel(tr("Width:"), q_ptr));
- layout1->addWidget(widthLineEdit);
- layout1->addWidget(new QLabel(tr("height:"), q_ptr));
- layout1->addWidget(heightLineEdit);
- layout1->addWidget(keepAspectRatioCkb);
- auto *layout2 = new QHBoxLayout;
- layout2->addWidget(new QLabel(tr("Min Bitrate:"), q_ptr));
- layout2->addWidget(videoMinBitrateLineEdit);
- layout2->addWidget(new QLabel(tr("Max Bitrate:"), q_ptr));
- layout2->addWidget(videoMaxBitrateLineEdit);
-
- auto *groupBox = new QGroupBox(tr("Video"), q_ptr);
- auto *layout = new QVBoxLayout(groupBox);
- layout->addLayout(layout1);
- layout->addLayout(layout2);
- return groupBox;
- }
+ fpsTimer = new QTimer(q_ptr);
- [[nodiscard]] auto invalidSetting() const -> QGroupBox *
- {
- auto *groupBox = new QGroupBox(tr("Invalid setting"), q_ptr);
- auto *layout = new QHBoxLayout(groupBox);
- layout->addWidget(new QLabel(tr("Quality:"), q_ptr));
- layout->addWidget(quailtySbx);
- layout->addWidget(new QLabel(tr("Crf:"), q_ptr));
- layout->addWidget(crfSbx);
- layout->addWidget(new QLabel(tr("Preset:"), q_ptr));
- layout->addWidget(presetCbx);
- layout->addWidget(new QLabel(tr("Tune:"), q_ptr));
- layout->addWidget(tuneCbx);
- layout->addWidget(new QLabel(tr("Profile:"), q_ptr));
- layout->addWidget(profileCbx);
- return groupBox;
+ subtitleTextEdit = new QTextEdit(q_ptr);
}
void initInputFileAttribute(const QString &filePath) const
@@ -176,14 +94,6 @@ class MainWindow::MainWindowPrivate
sourceWidget->setDuration(mediaInfo.duration / 1000);
}
- void calBitrate() const
- {
- auto w = widthLineEdit->text().toInt();
- auto h = heightLineEdit->text().toInt();
- videoMinBitrateLineEdit->setText(QString::number(w * h));
- videoMaxBitrateLineEdit->setText(QString::number(w * h * 4));
- }
-
MainWindow *q_ptr;
Ffmpeg::Transcoder *transcoder;
@@ -191,29 +101,14 @@ class MainWindow::MainWindowPrivate
SourceWidget *sourceWidget;
QTabWidget *tabWidget;
PreviewWidget *previewWidget;
+ VideoEncoderWidget *videoEncoderWidget;
+ AudioEncoderWidget *audioEncoderWidget;
+ OutPutWidget *outPutWidget;
+ StautusWidget *statusWidget;
- QTextEdit *subtitleTextEdit;
- QTextEdit *outTextEdit;
-
- QComboBox *audioCodecCbx;
- QComboBox *videoCodecCbx;
- QSpinBox *quailtySbx;
- QSpinBox *crfSbx;
- QComboBox *presetCbx;
- QComboBox *tuneCbx;
- QComboBox *profileCbx;
-
- QLineEdit *widthLineEdit;
- QLineEdit *heightLineEdit;
- QSize originalSize = QSize(-1, -1);
- QCheckBox *keepAspectRatioCkb;
- QLineEdit *videoMinBitrateLineEdit;
- QLineEdit *videoMaxBitrateLineEdit;
-
- QToolButton *startButton;
- QProgressBar *progressBar;
- QLabel *fpsLabel;
QTimer *fpsTimer;
+
+ QTextEdit *subtitleTextEdit;
};
MainWindow::MainWindow(QWidget *parent)
@@ -228,12 +123,6 @@ MainWindow::MainWindow(QWidget *parent)
MainWindow::~MainWindow() = default;
-void MainWindow::onVideoEncoderChanged()
-{
- auto quantizer = Ffmpeg::getCodecQuantizer(d_ptr->videoCodecCbx->currentText());
- d_ptr->quailtySbx->setRange(quantizer.first, quantizer.second);
-}
-
void MainWindow::onOpenInputFile()
{
const auto path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
@@ -248,8 +137,8 @@ void MainWindow::onOpenInputFile()
}
d_ptr->sourceWidget->setSource(filePath);
-
d_ptr->initInputFileAttribute(filePath);
+ d_ptr->outPutWidget->setOutputFileName(QFileInfo(filePath).fileName());
}
void MainWindow::onResetConfig()
@@ -286,49 +175,34 @@ void MainWindow::onOpenSubtitle()
d_ptr->subtitleTextEdit->setPlainText(filePath);
}
-void MainWindow::onOpenOutputFile()
-{
- const QString path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
- .value(0, QDir::homePath());
- const QString filePath
- = QFileDialog::getSaveFileName(this,
- tr("Save File"),
- path,
- tr("Audio Video (*.mp3 *.mp4 *.mkv *.rmvb)"));
- if (filePath.isEmpty()) {
- return;
- }
-
- d_ptr->outTextEdit->setPlainText(filePath);
-}
-
void MainWindow::onStart()
{
- if (d_ptr->startButton->text() == tr("Start")) {
+ if (d_ptr->statusWidget->status() == tr("Start")) {
auto inPath = d_ptr->sourceWidget->source();
auto subtitlePath = d_ptr->subtitleTextEdit->toPlainText();
- auto outPath = d_ptr->outTextEdit->toPlainText();
+ auto outPath = d_ptr->outPutWidget->outputFilePath();
if (inPath.isEmpty() || outPath.isEmpty()) {
return;
}
d_ptr->transcoder->setInFilePath(inPath);
d_ptr->transcoder->setOutFilePath(outPath);
- d_ptr->transcoder->setAudioEncodecName(d_ptr->audioCodecCbx->currentText());
- d_ptr->transcoder->setVideoEncodecName(d_ptr->videoCodecCbx->currentText());
- d_ptr->transcoder->setSize(
- {d_ptr->widthLineEdit->text().toInt(), d_ptr->heightLineEdit->text().toInt()});
+ d_ptr->transcoder->setAudioEncodecName(d_ptr->audioEncoderWidget->encoder());
+ d_ptr->transcoder->setVideoEncodecName(d_ptr->videoEncoderWidget->encoder());
+ d_ptr->transcoder->setUseGpuDecode(d_ptr->videoEncoderWidget->gpuDecode());
+ d_ptr->transcoder->setUseGpuEncode(d_ptr->videoEncoderWidget->gpuEncode());
+ d_ptr->transcoder->setSize(d_ptr->videoEncoderWidget->videoSize());
if (QFile::exists(subtitlePath)) {
d_ptr->transcoder->setSubtitleFilename(subtitlePath);
}
- d_ptr->transcoder->setQuailty(d_ptr->quailtySbx->value());
- d_ptr->transcoder->setMinBitrate(d_ptr->videoMinBitrateLineEdit->text().toInt());
- d_ptr->transcoder->setMaxBitrate(d_ptr->videoMaxBitrateLineEdit->text().toInt());
- d_ptr->transcoder->setCrf(d_ptr->crfSbx->value());
- d_ptr->transcoder->setPreset(d_ptr->presetCbx->currentText());
- d_ptr->transcoder->setProfile(d_ptr->profileCbx->currentText());
+ d_ptr->transcoder->setQuailty(d_ptr->videoEncoderWidget->quality());
+ d_ptr->transcoder->setMinBitrate(d_ptr->videoEncoderWidget->minBitrate());
+ d_ptr->transcoder->setMaxBitrate(d_ptr->videoEncoderWidget->maxBitrate());
+ d_ptr->transcoder->setCrf(d_ptr->videoEncoderWidget->crf());
+ d_ptr->transcoder->setPreset(d_ptr->videoEncoderWidget->preset());
+ d_ptr->transcoder->setProfile(d_ptr->videoEncoderWidget->profile());
d_ptr->transcoder->startTranscode();
- d_ptr->startButton->setText(tr("Stop"));
+ d_ptr->statusWidget->setStatus(tr("Stop"));
auto filename = QFile::exists(inPath) ? QFileInfo(inPath).fileName()
: QFileInfo(QUrl(inPath).toString()).fileName();
@@ -336,10 +210,10 @@ void MainWindow::onStart()
d_ptr->fpsTimer->start(1000);
- } else if (d_ptr->startButton->text() == tr("Stop")) {
+ } else if (d_ptr->statusWidget->status() == tr("Stop")) {
d_ptr->transcoder->stopTranscode();
- d_ptr->progressBar->setValue(0);
- d_ptr->startButton->setText(tr("Start"));
+ d_ptr->statusWidget->setProgress(0);
+ d_ptr->statusWidget->setStatus(tr("Start"));
d_ptr->fpsTimer->stop();
}
@@ -358,8 +232,9 @@ void MainWindow::onProcessEvents()
auto eventPtr = d_ptr->transcoder->takePropertyChangeEvent();
switch (eventPtr->type()) {
case Ffmpeg::PropertyChangeEvent::EventType::Position: {
- // auto *positionEvent = dynamic_cast(eventPtr.data());
- // d_ptr->controlWidget->setPosition(positionEvent->position() / AV_TIME_BASE);
+ auto *positionEvent = dynamic_cast(eventPtr.data());
+ d_ptr->statusWidget->setProgress(positionEvent->position() * 100.0
+ / d_ptr->transcoder->duration());
} break;
case Ffmpeg::PropertyChangeEvent::MediaTrack: {
bool audioSet = false;
@@ -370,28 +245,17 @@ void MainWindow::onProcessEvents()
switch (track.mediaType) {
case AVMEDIA_TYPE_AUDIO:
if (!audioSet) {
- auto index = d_ptr->audioCodecCbx->findData(track.codecId);
- if (index > 0) {
- d_ptr->audioCodecCbx->setCurrentIndex(index);
+ if (d_ptr->audioEncoderWidget->setEncoder(track.codecId)) {
audioSet = true;
}
}
break;
case AVMEDIA_TYPE_VIDEO:
if (!videoSet) {
- auto index = d_ptr->videoCodecCbx->findData(track.codecId);
- if (index > 0) {
- d_ptr->videoCodecCbx->setCurrentIndex(index);
+ if (d_ptr->videoEncoderWidget->setEncoder(track.codecId)) {
+ d_ptr->videoEncoderWidget->setVideoSize(track.size);
+ videoSet = true;
}
- videoSet = true;
- d_ptr->widthLineEdit->blockSignals(true);
- d_ptr->heightLineEdit->blockSignals(true);
- d_ptr->widthLineEdit->setText(QString::number(track.size.width()));
- d_ptr->heightLineEdit->setText(QString::number(track.size.height()));
- d_ptr->originalSize = track.size;
- d_ptr->widthLineEdit->blockSignals(false);
- d_ptr->heightLineEdit->blockSignals(false);
- d_ptr->calBitrate();
}
break;
default: break;
@@ -424,54 +288,24 @@ void MainWindow::setupUI()
auto *subtitleBtn = new QToolButton(this);
subtitleBtn->setText(tr("Add Subtitle"));
- subtitleBtn->setMinimumSize(BUTTON_SIZE);
connect(subtitleBtn, &QToolButton::clicked, this, &MainWindow::onOpenSubtitle);
- auto *outBtn = new QToolButton(this);
- outBtn->setText(tr("Open Out"));
- outBtn->setMinimumSize(BUTTON_SIZE);
- connect(outBtn, &QToolButton::clicked, this, &MainWindow::onOpenOutputFile);
auto *editLayout = new QGridLayout;
editLayout->addWidget(d_ptr->subtitleTextEdit, 1, 0, 1, 1);
editLayout->addWidget(subtitleBtn, 1, 1, 1, 1);
- editLayout->addWidget(d_ptr->outTextEdit, 2, 0, 1, 1);
- editLayout->addWidget(outBtn, 2, 1, 1, 1);
-
- auto *groupLayout1 = new QHBoxLayout;
- groupLayout1->addWidget(new QLabel(tr("Audio Codec Name:"), this));
- groupLayout1->addWidget(d_ptr->audioCodecCbx);
- groupLayout1->addWidget(new QLabel(tr("Video Codec Name:"), this));
- groupLayout1->addWidget(d_ptr->videoCodecCbx);
- auto *groupBox = new QGroupBox(tr("Encoder Settings"), this);
- auto *groupLayout = new QVBoxLayout(groupBox);
- groupLayout->addLayout(groupLayout1);
- groupLayout->addWidget(d_ptr->invalidSetting());
- groupLayout->addWidget(d_ptr->initVideoSetting());
-
- auto *useGpuCheckBox = new QCheckBox(tr("GPU Decode"), this);
- useGpuCheckBox->setToolTip(tr("GPU Decode"));
- useGpuCheckBox->setChecked(true);
- connect(useGpuCheckBox, &QCheckBox::clicked, this, [this, useGpuCheckBox] {
- d_ptr->transcoder->setUseGpuDecode(useGpuCheckBox->isChecked());
- });
- d_ptr->transcoder->setUseGpuDecode(useGpuCheckBox->isChecked());
- auto *displayLayout = new QHBoxLayout;
- displayLayout->addWidget(d_ptr->startButton);
- displayLayout->addWidget(useGpuCheckBox);
- displayLayout->addWidget(d_ptr->progressBar);
- displayLayout->addWidget(d_ptr->fpsLabel);
auto *widget = new QWidget(this);
auto *layout = new QVBoxLayout(widget);
layout->addWidget(d_ptr->sourceWidget);
layout->addWidget(d_ptr->tabWidget);
+ layout->addWidget(d_ptr->outPutWidget);
setCentralWidget(widget);
+ statusBar()->addWidget(d_ptr->statusWidget);
+
auto *tempWidget = new QWidget(this);
auto *tempLayout = new QVBoxLayout(tempWidget);
tempLayout->addLayout(editLayout);
- tempLayout->addWidget(groupBox);
- tempLayout->addLayout(displayLayout);
d_ptr->tabWidget->addTab(tempWidget, tr("Temp Widget"));
}
@@ -481,59 +315,16 @@ void MainWindow::buildConnect()
&Ffmpeg::Transcoder::eventIncrease,
this,
&MainWindow::onProcessEvents);
-
- connect(d_ptr->sourceWidget, &SourceWidget::showMediaInfo, this, &MainWindow::onShowMediaInfo);
-
- connect(d_ptr->videoCodecCbx,
- &QComboBox::currentTextChanged,
- this,
- &MainWindow::onVideoEncoderChanged);
-
- connect(d_ptr->widthLineEdit, &QLineEdit::textChanged, this, [this](const QString &text) {
- if (!d_ptr->keepAspectRatioCkb->isChecked() || !d_ptr->originalSize.isValid()) {
- return;
- }
- auto multiple = d_ptr->originalSize.width() * 1.0 / text.toInt();
- int height = d_ptr->originalSize.height() / multiple;
- d_ptr->heightLineEdit->blockSignals(true);
- d_ptr->heightLineEdit->setText(QString::number(height));
- d_ptr->heightLineEdit->blockSignals(false);
- d_ptr->calBitrate();
- });
- connect(d_ptr->heightLineEdit, &QLineEdit::textChanged, this, [this](const QString &text) {
- if (!d_ptr->keepAspectRatioCkb->isChecked() || !d_ptr->originalSize.isValid()) {
- return;
- }
- auto multiple = d_ptr->originalSize.height() * 1.0 / text.toInt();
- int width = d_ptr->originalSize.width() / multiple;
- d_ptr->widthLineEdit->blockSignals(true);
- d_ptr->widthLineEdit->setText(QString::number(width));
- d_ptr->widthLineEdit->blockSignals(false);
- d_ptr->calBitrate();
- });
- connect(d_ptr->keepAspectRatioCkb, &QCheckBox::stateChanged, this, [this] {
- if (!d_ptr->keepAspectRatioCkb->isChecked() || !d_ptr->originalSize.isValid()) {
- return;
- }
- auto multiple = d_ptr->originalSize.width() * 1.0 / d_ptr->widthLineEdit->text().toInt();
- int height = d_ptr->originalSize.height() / multiple;
- d_ptr->heightLineEdit->blockSignals(true);
- d_ptr->heightLineEdit->setText(QString::number(height));
- d_ptr->heightLineEdit->blockSignals(false);
- d_ptr->calBitrate();
- });
-
- connect(d_ptr->startButton, &QToolButton::clicked, this, &MainWindow::onStart);
- connect(d_ptr->transcoder, &Ffmpeg::Transcoder::progressChanged, this, [this](qreal value) {
- d_ptr->progressBar->setValue(value * 100);
- });
connect(d_ptr->transcoder, &Ffmpeg::Transcoder::finished, this, [this] {
- if (d_ptr->startButton->text() == tr("Stop")) {
- d_ptr->startButton->click();
+ if (d_ptr->statusWidget->status() == tr("Stop")) {
+ d_ptr->statusWidget->click();
}
});
+
+ connect(d_ptr->sourceWidget, &SourceWidget::showMediaInfo, this, &MainWindow::onShowMediaInfo);
+ connect(d_ptr->statusWidget, &StautusWidget::start, this, &MainWindow::onStart);
+
connect(d_ptr->fpsTimer, &QTimer::timeout, this, [this] {
- auto str = QString("FPS: %1").arg(QString::number(d_ptr->transcoder->fps(), 'f', 2));
- d_ptr->fpsLabel->setText(str);
+ d_ptr->statusWidget->setFPS(d_ptr->transcoder->fps());
});
}
diff --git a/examples/transcoder/mainwindow.hpp b/examples/transcoder/mainwindow.hpp
index cefb2d9..d1b5d1f 100644
--- a/examples/transcoder/mainwindow.hpp
+++ b/examples/transcoder/mainwindow.hpp
@@ -15,11 +15,9 @@ class MainWindow : public QMainWindow
~MainWindow() override;
private slots:
- void onVideoEncoderChanged();
void onOpenInputFile();
void onResetConfig();
void onOpenSubtitle();
- void onOpenOutputFile();
void onStart();
void onShowMediaInfo();
diff --git a/examples/transcoder/outputwidget.cc b/examples/transcoder/outputwidget.cc
new file mode 100644
index 0000000..59dfd3e
--- /dev/null
+++ b/examples/transcoder/outputwidget.cc
@@ -0,0 +1,64 @@
+#include "outputwidget.hpp"
+
+#include
+
+class OutPutWidget::OutPutWidgetPrivate
+{
+public:
+ explicit OutPutWidgetPrivate(OutPutWidget *q)
+ : q_ptr(q)
+ {
+ outLineEdit = new QLineEdit(q_ptr);
+ }
+
+ OutPutWidget *q_ptr;
+
+ QLineEdit *outLineEdit;
+};
+
+OutPutWidget::OutPutWidget(QWidget *parent)
+ : QWidget{parent}
+ , d_ptr(new OutPutWidgetPrivate(this))
+{
+ setupUI();
+ buildConnect();
+}
+
+OutPutWidget::~OutPutWidget() {}
+
+void OutPutWidget::setOutputFileName(const QString &fileName)
+{
+ const auto path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
+ .value(0, QDir::homePath());
+ d_ptr->outLineEdit->setText(QDir(path).filePath(fileName));
+}
+
+auto OutPutWidget::outputFilePath() const -> QString
+{
+ return d_ptr->outLineEdit->text().trimmed();
+}
+
+void OutPutWidget::onBrowse()
+{
+ const auto filePath = QFileDialog::getSaveFileName(this,
+ tr("Save File"),
+ d_ptr->outLineEdit->text().trimmed());
+ if (filePath.isEmpty()) {
+ return;
+ }
+ d_ptr->outLineEdit->setText(filePath);
+}
+
+void OutPutWidget::setupUI()
+{
+ auto *button = new QToolButton(this);
+ button->setText(tr("Browse"));
+ connect(button, &QToolButton::clicked, this, &OutPutWidget::onBrowse);
+
+ auto *layout = new QHBoxLayout(this);
+ layout->addWidget(new QLabel(tr("Save File:"), this));
+ layout->addWidget(d_ptr->outLineEdit);
+ layout->addWidget(button);
+}
+
+void OutPutWidget::buildConnect() {}
diff --git a/examples/transcoder/outputwidget.hpp b/examples/transcoder/outputwidget.hpp
new file mode 100644
index 0000000..cd86133
--- /dev/null
+++ b/examples/transcoder/outputwidget.hpp
@@ -0,0 +1,27 @@
+#ifndef OUTPUTWIDGET_HPP
+#define OUTPUTWIDGET_HPP
+
+#include
+
+class OutPutWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit OutPutWidget(QWidget *parent = nullptr);
+ ~OutPutWidget() override;
+
+ void setOutputFileName(const QString &fileName);
+ auto outputFilePath() const -> QString;
+
+private slots:
+ void onBrowse();
+
+private:
+ void setupUI();
+ void buildConnect();
+
+ class OutPutWidgetPrivate;
+ QScopedPointer d_ptr;
+};
+
+#endif // OUTPUTWIDGET_HPP
diff --git a/examples/transcoder/previewwidget.cc b/examples/transcoder/previewwidget.cc
index beb674d..f8c5d75 100644
--- a/examples/transcoder/previewwidget.cc
+++ b/examples/transcoder/previewwidget.cc
@@ -17,6 +17,7 @@ class PreviewWidget::PreviewWidgetPrivate
renderPtr->widget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
renderPtr->setBackgroundColor(Qt::white);
infoLabel = new QLabel(q_ptr);
+ infoLabel->setAlignment(Qt::AlignCenter);
leftButton = new QToolButton(q_ptr);
leftButton->setMinimumSize(buttonSize);
leftButton->setText("<");
diff --git a/examples/transcoder/sourcewidget.cc b/examples/transcoder/sourcewidget.cc
index a943991..a4368b0 100644
--- a/examples/transcoder/sourcewidget.cc
+++ b/examples/transcoder/sourcewidget.cc
@@ -8,7 +8,7 @@ class SourceWidget::SourceWidgetPrivate
explicit SourceWidgetPrivate(SourceWidget *q)
: q_ptr(q)
{
- inTextEdit = new QTextEdit(q_ptr);
+ inLineEdit = new QLineEdit(q_ptr);
infoLabel = new QLabel(q_ptr);
infoLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
startTimeEdit = new QTimeEdit(q_ptr);
@@ -20,7 +20,7 @@ class SourceWidget::SourceWidgetPrivate
SourceWidget *q_ptr;
- QTextEdit *inTextEdit;
+ QLineEdit *inLineEdit;
QLabel *infoLabel;
QTimeEdit *startTimeEdit;
QTimeEdit *endTimeEdit;
@@ -35,16 +35,16 @@ SourceWidget::SourceWidget(QWidget *parent)
buildConnect();
}
-SourceWidget::~SourceWidget() {}
+SourceWidget::~SourceWidget() = default;
void SourceWidget::setSource(const QString &source)
{
- d_ptr->inTextEdit->setPlainText(source);
+ d_ptr->inLineEdit->setText(source);
}
auto SourceWidget::source() const -> QString
{
- return d_ptr->inTextEdit->toPlainText();
+ return d_ptr->inLineEdit->text().trimmed();
}
void SourceWidget::setDuration(qint64 duration)
@@ -81,7 +81,7 @@ void SourceWidget::setupUI()
auto *layout1 = new QHBoxLayout;
layout1->addWidget(new QLabel(tr("Input File:"), this));
- layout1->addWidget(d_ptr->inTextEdit);
+ layout1->addWidget(d_ptr->inLineEdit);
auto *layout2 = new QHBoxLayout;
layout2->addWidget(fileInfoButton);
diff --git a/examples/transcoder/stautuswidget.cc b/examples/transcoder/stautuswidget.cc
new file mode 100644
index 0000000..3a9fbfb
--- /dev/null
+++ b/examples/transcoder/stautuswidget.cc
@@ -0,0 +1,75 @@
+#include "stautuswidget.hpp"
+
+#include
+
+class StautusWidget::StautusWidgetPrivate
+{
+public:
+ explicit StautusWidgetPrivate(StautusWidget *q)
+ : q_ptr(q)
+ {
+ startButton = new QToolButton(q_ptr);
+ startButton->setText(QCoreApplication::translate("StautusWidgetPrivate", "Start"));
+ progressBar = new QProgressBar(q_ptr);
+ progressBar->setRange(0, 100);
+ fpsLabel = new QLabel(q_ptr);
+ fpsLabel->setToolTip(
+ QCoreApplication::translate("StautusWidgetPrivate", "Video Encoder FPS."));
+ }
+
+ StautusWidget *q_ptr = nullptr;
+
+ QToolButton *startButton;
+ QProgressBar *progressBar;
+ QLabel *fpsLabel;
+};
+
+StautusWidget::StautusWidget(QWidget *parent)
+ : QWidget{parent}
+ , d_ptr(new StautusWidgetPrivate(this))
+{
+ setupUI();
+ buildConnect();
+}
+
+StautusWidget::~StautusWidget() {}
+
+void StautusWidget::setStatus(const QString &status)
+{
+ d_ptr->startButton->setText(status);
+}
+
+QString StautusWidget::status() const
+{
+ return d_ptr->startButton->text();
+}
+
+void StautusWidget::setProgress(int progress)
+{
+ d_ptr->progressBar->setValue(progress);
+}
+
+void StautusWidget::setFPS(double fps)
+{
+ auto text = QString("FPS: %1").arg(QString::number(fps, 'f', 2));
+ d_ptr->fpsLabel->setText(text);
+ d_ptr->fpsLabel->setToolTip(text);
+}
+
+void StautusWidget::click()
+{
+ d_ptr->startButton->click();
+}
+
+void StautusWidget::setupUI()
+{
+ auto *layout = new QHBoxLayout(this);
+ layout->addWidget(d_ptr->startButton);
+ layout->addWidget(d_ptr->progressBar);
+ layout->addWidget(d_ptr->fpsLabel);
+}
+
+void StautusWidget::buildConnect()
+{
+ connect(d_ptr->startButton, &QToolButton::clicked, this, &StautusWidget::start);
+}
diff --git a/examples/transcoder/stautuswidget.hpp b/examples/transcoder/stautuswidget.hpp
new file mode 100644
index 0000000..3288531
--- /dev/null
+++ b/examples/transcoder/stautuswidget.hpp
@@ -0,0 +1,33 @@
+#ifndef STAUTUSWIDGET_HPP
+#define STAUTUSWIDGET_HPP
+
+#include
+
+class StautusWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit StautusWidget(QWidget *parent = nullptr);
+ ~StautusWidget() override;
+
+ void setStatus(const QString &status);
+ QString status() const;
+
+ void setProgress(int progress);
+
+ void setFPS(double fps);
+
+ void click();
+
+signals:
+ void start();
+
+private:
+ void setupUI();
+ void buildConnect();
+
+ class StautusWidgetPrivate;
+ QScopedPointer d_ptr;
+};
+
+#endif // STAUTUSWIDGET_HPP
diff --git a/examples/transcoder/transcoder.pro b/examples/transcoder/transcoder.pro
index 38ee124..7956cba 100644
--- a/examples/transcoder/transcoder.pro
+++ b/examples/transcoder/transcoder.pro
@@ -4,7 +4,7 @@ QT += core gui widgets network multimedia openglwidgets core5compat
TEMPLATE = app
-TARGET = QFfmpegTranscoder
+TARGET = Transcoder
LIBS += \
-L$$APP_OUTPUT_PATH/../libs \
@@ -15,15 +15,23 @@ LIBS += \
include(../../3rdparty/3rdparty.pri)
SOURCES += \
+ audioencoderwidget.cc \
main.cc \
mainwindow.cc \
+ outputwidget.cc \
previewwidget.cc \
- sourcewidget.cc
+ sourcewidget.cc \
+ stautuswidget.cc \
+ videoencoderwidget.cc
HEADERS += \
+ audioencoderwidget.hpp \
mainwindow.hpp \
+ outputwidget.hpp \
previewwidget.hpp \
- sourcewidget.hpp
+ sourcewidget.hpp \
+ stautuswidget.hpp \
+ videoencoderwidget.hpp
DESTDIR = $$APP_OUTPUT_PATH
diff --git a/examples/transcoder/videoencoderwidget.cc b/examples/transcoder/videoencoderwidget.cc
new file mode 100644
index 0000000..fb46794
--- /dev/null
+++ b/examples/transcoder/videoencoderwidget.cc
@@ -0,0 +1,293 @@
+#include "videoencoderwidget.hpp"
+
+#include
+
+#include
+
+class VideoEncoderWidget::VideoEncoderWidgetPrivate
+{
+public:
+ explicit VideoEncoderWidgetPrivate(VideoEncoderWidget *q)
+ : q_ptr(q)
+ {
+ const auto *const comboBoxStyleSheet{"QComboBox {combobox-popup:0;}"};
+ videoEncoderCbx = new QComboBox(q_ptr);
+ videoEncoderCbx->setView(new QListView(videoEncoderCbx));
+ videoEncoderCbx->setMaxVisibleItems(10);
+ videoEncoderCbx->setStyleSheet(comboBoxStyleSheet);
+ auto videoCodecs = Ffmpeg::getCurrentSupportCodecs(AVMEDIA_TYPE_VIDEO, true);
+ for (auto iter = videoCodecs.cbegin(); iter != videoCodecs.cend(); ++iter) {
+ videoEncoderCbx->addItem(iter.value(), iter.key());
+ }
+ videoEncoderCbx->setCurrentIndex(videoEncoderCbx->findData(AV_CODEC_ID_H264));
+ videoEncoderCbx->model()->sort(0);
+
+ gpuEncodeCbx = new QCheckBox(QCoreApplication::translate("VideoEncoderWidgetPrivate",
+ "Use GPU Encode"),
+ q_ptr);
+ gpuEncodeCbx->setChecked(true);
+ gpuDecodeCbx = new QCheckBox(QCoreApplication::translate("VideoEncoderWidgetPrivate",
+ "Use GPU Decode"),
+ q_ptr);
+ gpuDecodeCbx->setChecked(true);
+
+ quailtySbx = new QSpinBox(q_ptr);
+ quailtySbx->setRange(2, 31);
+ quailtySbx->setToolTip(
+ QCoreApplication::translate("VideoEncoderWidgetPrivate", "smaller -> better"));
+ crfSbx = new QSpinBox(q_ptr);
+ crfSbx->setRange(0, 51);
+ crfSbx->setToolTip(
+ QCoreApplication::translate("VideoEncoderWidgetPrivate", "smaller -> better"));
+ crfSbx->setValue(18);
+ presetCbx = new QComboBox(q_ptr);
+ presetCbx->setView(new QListView(presetCbx));
+ tuneCbx = new QComboBox(q_ptr);
+ tuneCbx->setView(new QListView(tuneCbx));
+ profileCbx = new QComboBox(q_ptr);
+ profileCbx->setView(new QListView(profileCbx));
+
+ widthSbx = new QSpinBox(q_ptr);
+ widthSbx->setRange(0, INT_MAX);
+ heightSbx = new QSpinBox(q_ptr);
+ heightSbx->setRange(0, INT_MAX);
+ aspectCheckBox = new QCheckBox(QCoreApplication::translate("VideoEncoderWidgetPrivate",
+ "Keep aspect ratio:"),
+ q_ptr);
+ aspectCheckBox->setChecked(true);
+
+ minBitrateSbx = new QSpinBox(q_ptr);
+ minBitrateSbx->setRange(0, INT_MAX);
+ maxBitrateSbx = new QSpinBox(q_ptr);
+ maxBitrateSbx->setRange(0, INT_MAX);
+ }
+
+ void calBitrate() const
+ {
+ auto w = widthSbx->value();
+ auto h = heightSbx->value();
+ minBitrateSbx->setValue(w * h);
+ maxBitrateSbx->setValue(w * h * 4);
+ }
+
+ VideoEncoderWidget *q_ptr;
+
+ QComboBox *videoEncoderCbx;
+ QCheckBox *gpuEncodeCbx;
+ QCheckBox *gpuDecodeCbx;
+
+ QSpinBox *quailtySbx;
+ QSpinBox *crfSbx;
+ QComboBox *presetCbx;
+ QComboBox *tuneCbx;
+ QComboBox *profileCbx;
+
+ QSpinBox *widthSbx;
+ QSpinBox *heightSbx;
+ QCheckBox *aspectCheckBox;
+
+ QSpinBox *minBitrateSbx;
+ QSpinBox *maxBitrateSbx;
+
+ QSize originalSize;
+};
+
+VideoEncoderWidget::VideoEncoderWidget(QWidget *parent)
+ : QWidget{parent}
+ , d_ptr(new VideoEncoderWidgetPrivate(this))
+{
+ setupUI();
+ buildConnect();
+}
+
+VideoEncoderWidget::~VideoEncoderWidget() = default;
+
+auto VideoEncoderWidget::setEncoder(AVCodecID codecId) -> bool
+{
+ auto index = d_ptr->videoEncoderCbx->findData(codecId);
+ auto finded = (index >= 0);
+ if (finded) {
+ d_ptr->videoEncoderCbx->setCurrentIndex(index);
+ }
+ return finded;
+}
+
+auto VideoEncoderWidget::encoder() const -> QString
+{
+ return d_ptr->videoEncoderCbx->currentText();
+}
+
+void VideoEncoderWidget::setPreset(const QStringList &presets, const QString ¤t)
+{
+ d_ptr->presetCbx->clear();
+ d_ptr->presetCbx->addItems(presets);
+ d_ptr->presetCbx->setCurrentText(current);
+}
+
+auto VideoEncoderWidget::preset() const -> QString
+{
+ return d_ptr->presetCbx->currentText();
+}
+
+void VideoEncoderWidget::setTune(const QStringList &tunes, const QString ¤t)
+{
+ d_ptr->tuneCbx->clear();
+ d_ptr->tuneCbx->addItems(tunes);
+ d_ptr->tuneCbx->setCurrentText(current);
+}
+
+auto VideoEncoderWidget::tune() const -> QString
+{
+ return d_ptr->tuneCbx->currentText();
+}
+
+void VideoEncoderWidget::setProfile(const QStringList &profiles, const QString ¤t)
+{
+ d_ptr->profileCbx->clear();
+ d_ptr->profileCbx->addItems(profiles);
+ d_ptr->profileCbx->setCurrentText(current);
+}
+
+auto VideoEncoderWidget::profile() const -> QString
+{
+ return d_ptr->profileCbx->currentText();
+}
+
+void VideoEncoderWidget::setVideoSize(const QSize &size)
+{
+ d_ptr->widthSbx->blockSignals(true);
+ d_ptr->heightSbx->blockSignals(true);
+ d_ptr->widthSbx->setValue(size.width());
+ d_ptr->heightSbx->setValue(size.height());
+ d_ptr->widthSbx->blockSignals(false);
+ d_ptr->heightSbx->blockSignals(false);
+
+ d_ptr->originalSize = size;
+ d_ptr->calBitrate();
+}
+
+auto VideoEncoderWidget::videoSize() const -> QSize
+{
+ return {d_ptr->widthSbx->value(), d_ptr->heightSbx->value()};
+}
+
+auto VideoEncoderWidget::quality() const -> int
+{
+ return d_ptr->quailtySbx->value();
+}
+
+auto VideoEncoderWidget::minBitrate() const -> int
+{
+ return d_ptr->minBitrateSbx->value();
+}
+
+auto VideoEncoderWidget::gpuEncode() const -> bool
+{
+ return d_ptr->gpuEncodeCbx->isChecked();
+}
+
+auto VideoEncoderWidget::gpuDecode() const -> bool
+{
+ return d_ptr->gpuDecodeCbx->isChecked();
+}
+
+auto VideoEncoderWidget::maxBitrate() const -> int
+{
+ return d_ptr->maxBitrateSbx->value();
+}
+
+auto VideoEncoderWidget::crf() const -> int
+{
+ return d_ptr->crfSbx->value();
+}
+
+void VideoEncoderWidget::onEncoderChanged()
+{
+ auto quantizer = Ffmpeg::getCodecQuantizer(d_ptr->videoEncoderCbx->currentText());
+ if (quantizer.first < 0 || quantizer.second < 0) {
+ return;
+ }
+ d_ptr->quailtySbx->setRange(quantizer.first, quantizer.second);
+}
+
+void VideoEncoderWidget::onVideoWidthChanged()
+{
+ if (!d_ptr->aspectCheckBox->isChecked() || !d_ptr->originalSize.isValid()) {
+ return;
+ }
+ auto multiple = d_ptr->originalSize.width() * 1.0 / d_ptr->widthSbx->value();
+ int height = d_ptr->originalSize.height() / multiple;
+ d_ptr->heightSbx->blockSignals(true);
+ d_ptr->heightSbx->setValue(height);
+ d_ptr->heightSbx->blockSignals(false);
+ d_ptr->calBitrate();
+}
+
+void VideoEncoderWidget::onVideoHeightChanged()
+{
+ if (!d_ptr->aspectCheckBox->isChecked() || !d_ptr->originalSize.isValid()) {
+ return;
+ }
+ auto multiple = d_ptr->originalSize.height() * 1.0 / d_ptr->heightSbx->value();
+ int width = d_ptr->originalSize.width() / multiple;
+ d_ptr->widthSbx->blockSignals(true);
+ d_ptr->widthSbx->setValue(width);
+ d_ptr->widthSbx->blockSignals(false);
+ d_ptr->calBitrate();
+}
+
+void VideoEncoderWidget::setupUI()
+{
+ auto *codecLayout = new QHBoxLayout;
+ codecLayout->setSpacing(20);
+ codecLayout->addWidget(new QLabel(tr("Encoder:"), this));
+ codecLayout->addWidget(d_ptr->videoEncoderCbx);
+ codecLayout->addStretch();
+ codecLayout->addWidget(d_ptr->gpuEncodeCbx);
+ codecLayout->addWidget(d_ptr->gpuDecodeCbx);
+
+ auto *invailedGroupBox = new QGroupBox(tr("Invalid setting"), this);
+ auto *invailedLayout = new QFormLayout(invailedGroupBox);
+ invailedLayout->addRow(tr("Quality:"), d_ptr->quailtySbx);
+ invailedLayout->addRow(tr("Crf:"), d_ptr->crfSbx);
+ invailedLayout->addRow(tr("Preset:"), d_ptr->presetCbx);
+ invailedLayout->addRow(tr("Tune:"), d_ptr->tuneCbx);
+ invailedLayout->addRow(tr("Profile:"), d_ptr->profileCbx);
+
+ auto *sizeGroupBox = new QGroupBox(tr("Size"), this);
+ auto *sizeLayout = new QFormLayout(sizeGroupBox);
+ sizeLayout->addRow(tr("Width:"), d_ptr->widthSbx);
+ sizeLayout->addRow(tr("Height:"), d_ptr->heightSbx);
+ sizeLayout->addRow(d_ptr->aspectCheckBox);
+
+ auto *bitrateGroupBox = new QGroupBox(tr("Bitrate"), this);
+ auto *bitrateLayout = new QFormLayout(bitrateGroupBox);
+ bitrateLayout->addRow(tr("Min Bitrate:"), d_ptr->minBitrateSbx);
+ bitrateLayout->addRow(tr("Max Bitrate:"), d_ptr->maxBitrateSbx);
+
+ auto *layout = new QGridLayout(this);
+ layout->addLayout(codecLayout, 0, 0, 1, 2);
+ layout->addWidget(invailedGroupBox, 1, 0, 2, 1);
+ layout->addWidget(sizeGroupBox, 1, 1, 1, 1);
+ layout->addWidget(bitrateGroupBox, 2, 1, 1, 1);
+}
+
+void VideoEncoderWidget::buildConnect()
+{
+ connect(d_ptr->videoEncoderCbx,
+ &QComboBox::currentTextChanged,
+ this,
+ &VideoEncoderWidget::onEncoderChanged);
+ connect(d_ptr->widthSbx,
+ &QSpinBox::valueChanged,
+ this,
+ &VideoEncoderWidget::onVideoWidthChanged);
+ connect(d_ptr->heightSbx,
+ &QSpinBox::valueChanged,
+ this,
+ &VideoEncoderWidget::onVideoHeightChanged);
+ connect(d_ptr->aspectCheckBox,
+ &QCheckBox::stateChanged,
+ this,
+ &VideoEncoderWidget::onVideoWidthChanged);
+}
diff --git a/examples/transcoder/videoencoderwidget.hpp b/examples/transcoder/videoencoderwidget.hpp
new file mode 100644
index 0000000..9ad128b
--- /dev/null
+++ b/examples/transcoder/videoencoderwidget.hpp
@@ -0,0 +1,54 @@
+#ifndef VIDEOENCODERWIDGET_HPP
+#define VIDEOENCODERWIDGET_HPP
+
+#include
+
+extern "C" {
+#include
+}
+
+class VideoEncoderWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit VideoEncoderWidget(QWidget *parent = nullptr);
+ ~VideoEncoderWidget() override;
+
+ auto setEncoder(AVCodecID codecId) -> bool;
+ [[nodiscard]] auto encoder() const -> QString;
+
+ void setPreset(const QStringList &presets, const QString ¤t);
+ [[nodiscard]] auto preset() const -> QString;
+
+ void setTune(const QStringList &tunes, const QString ¤t);
+ [[nodiscard]] auto tune() const -> QString;
+
+ void setProfile(const QStringList &profiles, const QString ¤t);
+ [[nodiscard]] auto profile() const -> QString;
+
+ void setVideoSize(const QSize &size);
+ [[nodiscard]] auto videoSize() const -> QSize;
+
+ [[nodiscard]] auto quality() const -> int;
+ [[nodiscard]] auto crf() const -> int;
+
+ [[nodiscard]] auto minBitrate() const -> int;
+ [[nodiscard]] auto maxBitrate() const -> int;
+
+ [[nodiscard]] auto gpuEncode() const -> bool;
+ [[nodiscard]] auto gpuDecode() const -> bool;
+
+private slots:
+ void onEncoderChanged();
+ void onVideoWidthChanged();
+ void onVideoHeightChanged();
+
+private:
+ void setupUI();
+ void buildConnect();
+
+ class VideoEncoderWidgetPrivate;
+ QScopedPointer d_ptr;
+};
+
+#endif // VIDEOENCODERWIDGET_HPP
diff --git a/ffmpeg/codeccontext.cpp b/ffmpeg/codeccontext.cpp
index 8dfc963..f741515 100644
--- a/ffmpeg/codeccontext.cpp
+++ b/ffmpeg/codeccontext.cpp
@@ -72,6 +72,7 @@ CodecContext::CodecContext(const AVCodec *codec, QObject *parent)
: QObject(parent)
, d_ptr(new CodecContextPrivate(this))
{
+ qInfo() << "AVCodec:" << codec->long_name;
d_ptr->codecCtx = avcodec_alloc_context3(codec);
d_ptr->init();
Q_ASSERT(d_ptr->codecCtx != nullptr);
@@ -263,7 +264,7 @@ void CodecContext::setCrf(int crf)
{
// 设置crf参数,范围是0-51,0是无损,23是默认值,51是最差质量
Q_ASSERT(crf >= 0 && crf <= 51);
- av_opt_set(d_ptr->codecCtx->priv_data, "crf", QString::number(crf).toLocal8Bit().constData(), 0);
+ av_opt_set_double(d_ptr->codecCtx->priv_data, "crf", crf, 0);
}
void CodecContext::setPreset(const QString &preset)
@@ -291,6 +292,7 @@ auto CodecContext::open() -> bool
auto CodecContext::sendPacket(Packet *packet) -> bool
{
int ret = avcodec_send_packet(d_ptr->codecCtx, packet->avPacket());
+ AVERROR(EINVAL);
ERROR_RETURN(ret)
}
diff --git a/ffmpeg/ffmpegutils.cc b/ffmpeg/ffmpegutils.cc
index fc3fc01..ccc43a0 100644
--- a/ffmpeg/ffmpegutils.cc
+++ b/ffmpeg/ffmpegutils.cc
@@ -151,10 +151,10 @@ auto compareAVRational(const AVRational &a, const AVRational &b) -> bool
return a.den == b.den && a.num == b.num;
}
-auto getCodecQuantizer(const QString &codecname) -> QPair
+auto getCodecQuantizer(const QString &codecName) -> QPair
{
QScopedPointer contextInfoPtr(new AVContextInfo);
- if (!contextInfoPtr->initEncoder(codecname)) {
+ if (!contextInfoPtr->initEncoder(codecName)) {
return {-1, -1};
}
auto quantizer = contextInfoPtr->codecCtx()->quantizer();
diff --git a/ffmpeg/transcoder.cc b/ffmpeg/transcoder.cc
index 622b08e..002a7ec 100644
--- a/ffmpeg/transcoder.cc
+++ b/ffmpeg/transcoder.cc
@@ -164,7 +164,8 @@ class Transcoder::TranscoderPrivate
!= 0) {
avCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
- contextInfoPtr->openCodec(AVContextInfo::GpuEncode);
+ contextInfoPtr->openCodec(useGpuEncode ? AVContextInfo::GpuEncode
+ : AVContextInfo::NotUseGpu);
auto ret = avcodec_parameters_from_context(stream->codecpar,
contextInfoPtr->codecCtx()->avCodecCtx());
if (ret < 0) {
@@ -388,7 +389,7 @@ class Transcoder::TranscoderPrivate
void loop()
{
auto duration = inFormatContext->duration();
- while (runing) {
+ while (runing.load()) {
PacketPtr packetPtr(new Packet);
if (!inFormatContext->readFrame(packetPtr.get())) {
break;
@@ -413,7 +414,7 @@ class Transcoder::TranscoderPrivate
calculatePts(packetPtr.data(),
transcodeContexts.at(stream_index)->decContextInfoPtr.data());
- emit q_ptr->progressChanged(packetPtr->pts() / duration);
+ addPropertyChangeEvent(new PositionEvent(packetPtr->pts()));
if (transcodeCtx->decContextInfoPtr->mediaType() == AVMEDIA_TYPE_VIDEO) {
fpsPtr->update();
}
@@ -512,6 +513,7 @@ class Transcoder::TranscoderPrivate
QString profile = "main";
bool useGpuDecode = false;
+ bool useGpuEncode = false;
std::atomic_bool runing = true;
QScopedPointer fpsPtr;
@@ -536,9 +538,14 @@ Transcoder::~Transcoder()
stopTranscode();
}
-void Transcoder::setUseGpuDecode(bool useGpu)
+void Transcoder::setUseGpuDecode(bool use)
+{
+ d_ptr->useGpuDecode = use;
+}
+
+void Transcoder::setUseGpuEncode(bool use)
{
- d_ptr->useGpuDecode = useGpu;
+ d_ptr->useGpuEncode = use;
}
void Transcoder::setInFilePath(const QString &filePath)
diff --git a/ffmpeg/transcoder.hpp b/ffmpeg/transcoder.hpp
index 5e57f8d..556529b 100644
--- a/ffmpeg/transcoder.hpp
+++ b/ffmpeg/transcoder.hpp
@@ -22,7 +22,8 @@ class FFMPEG_EXPORT Transcoder : public QThread
explicit Transcoder(QObject *parent = nullptr);
~Transcoder() override;
- void setUseGpuDecode(bool useGpu);
+ void setUseGpuDecode(bool use);
+ void setUseGpuEncode(bool use);
void setInFilePath(const QString &filePath);
auto parseInputFile() -> bool;
@@ -71,7 +72,6 @@ class FFMPEG_EXPORT Transcoder : public QThread
auto takePropertyChangeEvent() -> PropertyChangeEventPtr;
signals:
- void progressChanged(qreal); // 0.XXXX
void eventIncrease();
protected: