Skip to content

Commit

Permalink
重构transcode-4;
Browse files Browse the repository at this point in the history
  • Loading branch information
RealChuan committed Mar 5, 2024
1 parent b1dc519 commit 9922265
Show file tree
Hide file tree
Showing 34 changed files with 759 additions and 498 deletions.
18 changes: 3 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ zscale=p=709;
0,,en,,0000,0000,0000,,Peek-a-boo!
```

你必须使用 ``ass_process_chunk`` 并设置 pts 和持续时间, 如在 libavfilter/vf_subtitles.c 中一样。
你必须使用 ``ass_process_chunk`` 并设置 pts 和持续时间, 和在[vf_subtitles.c](https://github.com/FFmpeg/FFmpeg/blob/master/libavfilter/vf_subtitles.c#L490) 中一样。

#### ASS 标准格式应为(ffmpeg-n4.4.3)

Expand All @@ -60,19 +60,7 @@ subtitles=filename='%1':original_size=%2x%3

如何设置编码参数以获得更小的文件和更好的视频质量?

1. 设置非常高的比特率;
2. 设置编码器 ``global_quality`` 无效。代码如下:

```C++
d_ptr->codecCtx->flags |= AV_CODEC_FLAG_QSCALE;
d_ptr->codecCtx->global_quality = FF_QP2LAMBDA * quailty;
```

3. 设置 ``crf`` 无效。代码如下:

```C++
av_opt_set_int(d_ptr->codecCtx, "crf", crf, AV_OPT_SEARCH_CHILDREN);
```
1. 参考[HandBrake encavcodec](https://github.com/HandBrake/HandBrake/blob/master/libhb/encavcodec.c#L359)

### 如何从AVAudioFifo获取的帧中计算pts?

Expand All @@ -89,7 +77,7 @@ transcodeCtx->audioPts += frame->nb_samples;

## QT-BUG

#### 动态切换Video Render,从opengl切换到widget,还是有GPU 0-3D占用,而且使用量是opengl的2倍!!!QT-BUG?
### 动态切换Video Render,从opengl切换到widget,还是有GPU 0-3D占用,而且使用量是opengl的2倍!!!QT-BUG?

### QOpenGLWidget内存泄漏,移动放大和缩小窗口,代码如下

Expand Down
26 changes: 13 additions & 13 deletions examples/player/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ void MainWindow::onProcessEvents()
auto *speedEvent = dynamic_cast<Ffmpeg::CacheSpeedEvent *>(eventPtr.data());
d_ptr->controlWidget->setCacheSpeed(speedEvent->speed());
} break;
case Ffmpeg::PropertyChangeEvent::MediaTrack: {
case Ffmpeg::PropertyChangeEvent::EventType::MediaTrack: {
d_ptr->resetTrackMenu();

auto *tracksEvent = dynamic_cast<Ffmpeg::MediaTrackEvent *>(eventPtr.data());
Expand Down Expand Up @@ -444,7 +444,7 @@ void MainWindow::onProcessEvents()
}
}
} break;
case Ffmpeg::PropertyChangeEvent::SeekChanged: {
case Ffmpeg::PropertyChangeEvent::EventType::SeekChanged: {
auto *seekEvent = dynamic_cast<Ffmpeg::SeekChangedEvent *>(eventPtr.data());
int value = seekEvent->position() * 100 / d_ptr->playerPtr->duration();
auto text = tr("Seeked To %1 (key frame) / %2 (%3%)")
Expand All @@ -455,8 +455,8 @@ void MainWindow::onProcessEvents()
QString::number(value));
d_ptr->setTitleWidgetText(text);
} break;
case Ffmpeg::PropertyChangeEvent::Error: {
auto *errorEvent = dynamic_cast<Ffmpeg::ErrorEvent *>(eventPtr.data());
case Ffmpeg::PropertyChangeEvent::EventType::AVError: {
auto *errorEvent = dynamic_cast<Ffmpeg::AVErrorEvent *>(eventPtr.data());
const auto text = tr("Error[%1]:%2.")
.arg(QString::number(errorEvent->error().errorCode()),
errorEvent->error().errorString());
Expand Down Expand Up @@ -641,19 +641,19 @@ void MainWindow::initMenu()
renderMenu();

connect(d_ptr->audioTracksGroup, &QActionGroup::triggered, this, [this](QAction *action) {
d_ptr->playerPtr->addEvent(
Ffmpeg::EventPtr(new Ffmpeg::SelectedMediaTrackEvent(action->property("index").toInt(),
Ffmpeg::Event::AudioTarck)));
d_ptr->playerPtr->addEvent(Ffmpeg::EventPtr(
new Ffmpeg::SelectedMediaTrackEvent(action->property("index").toInt(),
Ffmpeg::Event::EventType::AudioTarck)));
});
connect(d_ptr->videoTracksGroup, &QActionGroup::triggered, this, [this](QAction *action) {
d_ptr->playerPtr->addEvent(
Ffmpeg::EventPtr(new Ffmpeg::SelectedMediaTrackEvent(action->property("index").toInt(),
Ffmpeg::Event::VideoTrack)));
d_ptr->playerPtr->addEvent(Ffmpeg::EventPtr(
new Ffmpeg::SelectedMediaTrackEvent(action->property("index").toInt(),
Ffmpeg::Event::EventType::VideoTrack)));
});
connect(d_ptr->subTracksGroup, &QActionGroup::triggered, this, [this](QAction *action) {
d_ptr->playerPtr->addEvent(
Ffmpeg::EventPtr(new Ffmpeg::SelectedMediaTrackEvent(action->property("index").toInt(),
Ffmpeg::Event::SubtitleTrack)));
d_ptr->playerPtr->addEvent(Ffmpeg::EventPtr(
new Ffmpeg::SelectedMediaTrackEvent(action->property("index").toInt(),
Ffmpeg::Event::EventType::SubtitleTrack)));
});

connect(d_ptr->mediaInfoAction, &QAction::triggered, this, &MainWindow::onShowMediaInfo);
Expand Down
130 changes: 116 additions & 14 deletions examples/transcoder/audioencoderwidget.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "audioencoderwidget.hpp"

#include <ffmpeg/avcontextinfo.h>
#include <ffmpeg/ffmpegutils.hpp>

#include <QtWidgets>
Expand All @@ -10,22 +11,71 @@ class AudioEncoderWidget::AudioEncoderWidgetPrivate
explicit AudioEncoderWidgetPrivate(AudioEncoderWidget *q)
: q_ptr(q)
{
const auto *comboBoxStyleSheet = "QComboBox {combobox-popup:0;}";

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->setStyleSheet(comboBoxStyleSheet);
auto audioEncodercs = Ffmpeg::getCodecsInfo(AVMEDIA_TYPE_AUDIO, true);
for (const auto &codec : std::as_const(audioEncodercs)) {
auto text = QString("%1 (%2)").arg(codec.longName).arg(codec.name);
audioEncoderCbx->addItem(text, QVariant::fromValue(codec));
if (codec.codecId == AV_CODEC_ID_AAC) {
audioEncoderCbx->setCurrentText(text);
}
}
audioEncoderCbx->setCurrentIndex(audioEncoderCbx->findData(AV_CODEC_ID_AAC));
audioEncoderCbx->model()->sort(0);

chLayoutCbx = new QComboBox(q_ptr);
chLayoutCbx->setView(new QListView(chLayoutCbx));
chLayoutCbx->setMaxVisibleItems(10);
chLayoutCbx->setStyleSheet(comboBoxStyleSheet);

crfSbx = new QSpinBox(q_ptr);
crfSbx->setToolTip(
QCoreApplication::translate("VideoEncoderWidgetPrivate", "smaller -> better"));

profileCbx = new QComboBox(q_ptr);
profileCbx->setView(new QListView(profileCbx));
profileCbx->setMaxVisibleItems(10);
profileCbx->setStyleSheet(comboBoxStyleSheet);

const int defaultBitrate = 512 * 1000;
minBitrateSbx = new QSpinBox(q_ptr);
minBitrateSbx->setRange(0, INT_MAX);
minBitrateSbx->setValue(defaultBitrate);
maxBitrateSbx = new QSpinBox(q_ptr);
maxBitrateSbx->setRange(0, INT_MAX);
maxBitrateSbx->setValue(defaultBitrate);

init();
}

void init()
{
Ffmpeg::EncodeContext encodeParam;

profileCbx->clear();

crfSbx->setRange(Ffmpeg::EncodeLimit::crf_min, Ffmpeg::EncodeLimit::crf_max);
crfSbx->setValue(encodeParam.crf);
}

[[nodiscard]] auto currentCodecName() const -> QString
{
return audioEncoderCbx->currentData().value<Ffmpeg::CodecInfo>().name;
}

AudioEncoderWidget *q_ptr;

QComboBox *audioEncoderCbx;
QComboBox *chLayoutCbx;
QSpinBox *crfSbx;
QComboBox *profileCbx;

QSpinBox *minBitrateSbx;
QSpinBox *maxBitrateSbx;
};

AudioEncoderWidget::AudioEncoderWidget(QWidget *parent)
Expand All @@ -34,31 +84,83 @@ AudioEncoderWidget::AudioEncoderWidget(QWidget *parent)
{
setupUI();
buildConnect();
onEncoderChanged();
}

AudioEncoderWidget::~AudioEncoderWidget() = default;

auto AudioEncoderWidget::setEncoder(AVCodecID codecId) -> bool
{
auto index = d_ptr->audioEncoderCbx->findData(codecId);
Ffmpeg::CodecInfo codec{"", "", codecId};
auto index = d_ptr->audioEncoderCbx->findData(QVariant::fromValue(codec));
auto finded = (index >= 0);
if (finded) {
d_ptr->audioEncoderCbx->setCurrentIndex(index);
}
return finded;
}

auto AudioEncoderWidget::encoder() const -> QString
auto AudioEncoderWidget::encodeParam() const -> Ffmpeg::EncodeContext
{
return d_ptr->audioEncoderCbx->currentText();
Ffmpeg::EncodeContext encodeParam;
encodeParam.mediaType = AVMEDIA_TYPE_AUDIO;
encodeParam.encoderName = d_ptr->currentCodecName();
encodeParam.channel = static_cast<AVChannel>(d_ptr->chLayoutCbx->currentData().toLongLong());
encodeParam.crf = d_ptr->crfSbx->value();
encodeParam.minBitrate = d_ptr->minBitrateSbx->value();
encodeParam.maxBitrate = d_ptr->maxBitrateSbx->value();
encodeParam.bitrate = d_ptr->maxBitrateSbx->value();

return encodeParam;
}

void AudioEncoderWidget::onEncoderChanged()
{
d_ptr->profileCbx->clear();
d_ptr->chLayoutCbx->clear();

QScopedPointer<Ffmpeg::AVContextInfo> contextInfoPtr(new Ffmpeg::AVContextInfo);
if (!contextInfoPtr->initEncoder(d_ptr->currentCodecName())) {
return;
}
auto profiles = contextInfoPtr->profiles();
for (const auto &profile : std::as_const(profiles)) {
d_ptr->profileCbx->addItem(profile.name, profile.profile);
}
auto chLayouts = Ffmpeg::getChLayouts(contextInfoPtr->chLayouts());
for (const auto &chLayout : std::as_const(chLayouts)) {
d_ptr->chLayoutCbx->addItem(chLayout.channelName, chLayout.channel);
}
auto index = d_ptr->chLayoutCbx->findData(AV_CH_LAYOUT_STEREO);
d_ptr->chLayoutCbx->setCurrentIndex(index >= 0 ? index : 0);
}

void AudioEncoderWidget::setupUI()
{
auto *layout = new QHBoxLayout(this);
layout->addWidget(new QLabel(tr("Encoder:")));
layout->addWidget(d_ptr->audioEncoderCbx);
layout->addStretch();
auto *invailedGroupBox = new QGroupBox(tr("Invalid setting"), this);
auto *invailedLayout = new QFormLayout(invailedGroupBox);
invailedLayout->addRow(tr("Crf:"), d_ptr->crfSbx);
invailedLayout->addRow(tr("Profile:"), d_ptr->profileCbx);

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 *hLayout = new QHBoxLayout;
hLayout->addWidget(invailedGroupBox);
hLayout->addWidget(bitrateGroupBox);

auto *layout = new QFormLayout(this);
layout->addRow(tr("Encoder:"), d_ptr->audioEncoderCbx);
layout->addRow(tr("Channel Layout:"), d_ptr->chLayoutCbx);
layout->addRow(hLayout);
}

void AudioEncoderWidget::buildConnect() {}
void AudioEncoderWidget::buildConnect()
{
connect(d_ptr->audioEncoderCbx,
&QComboBox::currentIndexChanged,
this,
&AudioEncoderWidget::onEncoderChanged);
}
8 changes: 7 additions & 1 deletion examples/transcoder/audioencoderwidget.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef AUDIOENCODERWIDGET_HPP
#define AUDIOENCODERWIDGET_HPP

#include <ffmpeg/encodecontext.hpp>

#include <QWidget>

extern "C" {
Expand All @@ -15,7 +17,11 @@ class AudioEncoderWidget : public QWidget
~AudioEncoderWidget() override;

auto setEncoder(AVCodecID codecId) -> bool;
[[nodiscard]] auto encoder() const -> QString;

[[nodiscard]] auto encodeParam() const -> Ffmpeg::EncodeContext;

private slots:
void onEncoderChanged();

private:
void setupUI();
Expand Down
37 changes: 18 additions & 19 deletions examples/transcoder/mainwindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "videoencoderwidget.hpp"

#include <ffmpeg/averror.h>
#include <ffmpeg/encodecontext.hpp>
#include <ffmpeg/event/errorevent.hpp>
#include <ffmpeg/event/trackevent.hpp>
#include <ffmpeg/event/valueevent.hpp>
Expand All @@ -24,15 +25,14 @@ class MainWindow::MainWindowPrivate
{
Ffmpeg::printFfmpegInfo();

Ffmpeg::EncodeContext encodeContext;

transcoder = new Ffmpeg::Transcoder(q_ptr);

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"));
Expand Down Expand Up @@ -187,20 +187,12 @@ void MainWindow::onStart()

d_ptr->transcoder->setInFilePath(inPath);
d_ptr->transcoder->setOutFilePath(outPath);
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());
d_ptr->transcoder->setVideoEncodeContext(d_ptr->videoEncoderWidget->encodeParam());
d_ptr->transcoder->setAudioEncodeContext(d_ptr->audioEncoderWidget->encodeParam());

if (QFile::exists(subtitlePath)) {
d_ptr->transcoder->setSubtitleFilename(subtitlePath);
}
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->statusWidget->setStatus(tr("Stop"));

Expand Down Expand Up @@ -236,7 +228,7 @@ void MainWindow::onProcessEvents()
d_ptr->statusWidget->setProgress(positionEvent->position() * 100.0
/ d_ptr->transcoder->duration());
} break;
case Ffmpeg::PropertyChangeEvent::MediaTrack: {
case Ffmpeg::PropertyChangeEvent::EventType::MediaTrack: {
bool audioSet = false;
bool videoSet = false;
auto *mediaTrackEvent = dynamic_cast<Ffmpeg::MediaTrackEvent *>(eventPtr.data());
Expand Down Expand Up @@ -265,13 +257,20 @@ void MainWindow::onProcessEvents()
case Ffmpeg::PropertyChangeEvent::EventType::PreviewFramesChanged:
d_ptr->previewWidget->setFrames(d_ptr->transcoder->previewFrames());
break;
case Ffmpeg::PropertyChangeEvent::Error: {
auto *errorEvent = dynamic_cast<Ffmpeg::ErrorEvent *>(eventPtr.data());
case Ffmpeg::PropertyChangeEvent::EventType::AVError: {
auto *errorEvent = dynamic_cast<Ffmpeg::AVErrorEvent *>(eventPtr.data());
const auto text = tr("Error[%1]:%2.")
.arg(QString::number(errorEvent->error().errorCode()),
errorEvent->error().errorString());
qWarning() << text;
}
statusBar()->showMessage(text);
} break;
case Ffmpeg::PropertyChangeEvent::EventType::Error: {
auto *errorEvent = dynamic_cast<Ffmpeg::ErrorEvent *>(eventPtr.data());
const auto text = tr("Error:%1.").arg(errorEvent->error());
qWarning() << text;
statusBar()->showMessage(text);
} break;
default: break;
}
}
Expand Down Expand Up @@ -301,7 +300,7 @@ void MainWindow::setupUI()
layout->addWidget(d_ptr->outPutWidget);
setCentralWidget(widget);

statusBar()->addWidget(d_ptr->statusWidget);
statusBar()->addPermanentWidget(d_ptr->statusWidget);

auto *tempWidget = new QWidget(this);
auto *tempLayout = new QVBoxLayout(tempWidget);
Expand Down
Loading

0 comments on commit 9922265

Please sign in to comment.