Skip to content

Commit

Permalink
添加亮度、对比度、饱和度控制;
Browse files Browse the repository at this point in the history
其中对比度调整和sws_setColorspaceDetails函数实现效果有差别;
  • Loading branch information
RealChuan committed Nov 8, 2023
1 parent eae1aba commit 87ede13
Show file tree
Hide file tree
Showing 37 changed files with 645 additions and 281 deletions.
62 changes: 51 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

### 需要一个强大的opengl和vulkan yuv渲染模块

1. Opengl中的shader有太多if else导致GPU空跑,影响GPU解码和av_hwframe_transfer_data速度,这个现象在4K视频图像上尤为明显
1. Opengl的片段着色器目前支持的图像格式有限
2. 在WidgetRender中,尽可能使用QImage::Format_RGB32和QImage::Format_ARGB32_Premultiplied图像格式。如下原因:
1. Avoid most rendering directly to most of these formats using QPainter. Rendering is best optimized to the Format_RGB32 and Format_ARGB32_Premultiplied formats, and secondarily for rendering to the Format_RGB16, Format_RGBX8888, Format_RGBA8888_Premultiplied, Format_RGBX64 and Format_RGBA64_Premultiplied formats.

Expand All @@ -19,22 +19,62 @@

#### 2. 非opengl渲染的情况下,又该怎么样添加filter实现图像补偿?

1. 现在对AVCOL_TRC_SMPTE2084调整了对比度,饱和度,亮度;效果并不是很好。
2. 如果不调整,就跟ffplay输出图像效果一致,整体颜色偏暗。Netflix的视频,视频开头的N,显示的颜色偏暗黄色。

```bash
contrast = 1.4;
saturation = 0.9;
brightness = 0;
```

3. 参考[MPV video_shaders](https://github.com/mpv-player/mpv/blob/master/video/out/gpu/video_shaders.c#L341),效果也不是很好;应该是哪里有遗漏。
1. 参考[MPV video_shaders](https://github.com/mpv-player/mpv/blob/master/video/out/gpu/video_shaders.c#L341),效果也不是很好;应该是哪里有遗漏。

```cpp
void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc);
void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc);
```
2. 在NV12的shader上,参考MPV实现的对SMPTE2084进行图像调整shader
```glsl
#version 330 core
in vec2 TexCord; // 纹理坐标
out vec4 FragColor; // 输出颜色
uniform sampler2D tex_y;
uniform sampler2D tex_uv;
uniform vec3 offset;
uniform mat3 colorConversion;
const float PQ_M1 = 2610. / 4096 * 1. / 4, PQ_M2 = 2523. / 4096 * 128, PQ_C1 = 3424. / 4096,
PQ_C2 = 2413. / 4096 * 32, PQ_C3 = 2392. / 4096 * 32;
#define MP_REF_WHITE 203.0
#define MP_REF_WHITE_HLG 3.17955
void main()
{
vec3 yuv;
vec3 rgb;
yuv.x = texture(tex_y, TexCord).r;
yuv.yz = texture(tex_uv, TexCord).rg;
yuv += offset;
rgb = yuv * colorConversion;
vec4 color = vec4(rgb, 1.0);
// ------------------
color.rgb = clamp(color.rgb, 0.0, 1.0);
color.rgb = pow(color.rgb, vec3(1.0 / PQ_M2));
color.rgb = max(color.rgb - vec3(PQ_C1), vec3(0.0)) / (vec3(PQ_C2) - vec3(PQ_C3) * color.rgb);
color.rgb = pow(color.rgb, vec3(1.0 / PQ_M1));
// ------------------
color.rgb = clamp(color.rgb, 0.0, 1.0);
color.rgb = pow(color.rgb, vec3(PQ_M1));
color.rgb = (vec3(PQ_C1) + vec3(PQ_C2) * color.rgb) / (vec3(1.0) + vec3(PQ_C3) * color.rgb);
color.rgb = pow(color.rgb, vec3(PQ_M2));
// ------------------
rgb = color.rgb;
FragColor = vec4(rgb, 1.0);
}
```

### OpenGL 渲染图像,怎么实现画质增强的效果?

### Ffmpeg(5.0)在解码字幕与4.4.3不太一样
Expand Down
2 changes: 2 additions & 0 deletions examples/player/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
set(PROJECT_SOURCES
colorspacedialog.cc
colorspacedialog.hpp
controlwidget.cc
controlwidget.hpp
main.cpp
Expand Down
194 changes: 194 additions & 0 deletions examples/player/colorspacedialog.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#include "colorspacedialog.hpp"
#include "slider.h"

#include <QtWidgets>

void setBlockValue(QSpinBox *spinBox, int value)
{
spinBox->blockSignals(true);
spinBox->setValue(value);
spinBox->blockSignals(false);
}

void setBlockValue(QSlider *slider, int value)
{
slider->blockSignals(true);
slider->setValue(value);
slider->blockSignals(false);
}

class ColorSpaceDialog::ColorSpaceDialogPrivate
{
public:
explicit ColorSpaceDialogPrivate(ColorSpaceDialog *q)
: q_ptr(q)
{
Ffmpeg::ColorSpaceTrc colorTrc;

contrastSlider = new Slider(q_ptr);
contrastSlider->setRange(colorTrc.contrast_min * multiple, colorTrc.contrast_max * multiple);
contrastSlider->setValue(colorTrc.contrast * multiple);
saturationSlider = new Slider(q_ptr);
saturationSlider->setRange(colorTrc.saturation_min * multiple,
colorTrc.saturation_max * multiple);
saturationSlider->setValue(colorTrc.saturation * multiple);
brightnessSlider = new Slider(q_ptr);
brightnessSlider->setRange(colorTrc.brightness_min * multiple,
colorTrc.brightness_max * multiple);
brightnessSlider->setValue(colorTrc.brightness * multiple);

contrastSpinBox = new QSpinBox(q_ptr);
contrastSpinBox->setKeyboardTracking(false);
contrastSpinBox->setRange(colorTrc.contrast_min * multiple,
colorTrc.contrast_max * multiple);
contrastSpinBox->setValue(colorTrc.contrast * multiple);
saturationSpinBox = new QSpinBox(q_ptr);
saturationSpinBox->setKeyboardTracking(false);
saturationSpinBox->setRange(colorTrc.saturation_min * multiple,
colorTrc.saturation_max * multiple);
saturationSpinBox->setValue(colorTrc.saturation * multiple);
brightnessSpinBox = new QSpinBox(q_ptr);
brightnessSpinBox->setKeyboardTracking(false);
brightnessSpinBox->setRange(colorTrc.brightness_min * multiple,
colorTrc.brightness_max * multiple);
brightnessSpinBox->setValue(colorTrc.brightness * multiple);

resetButton = new QToolButton(q_ptr);
resetButton->setText("Reset");
}

void setupUI()
{
auto *layout = new QGridLayout(q_ptr);
layout->addWidget(new QLabel(QObject::tr("Contrast:"), q_ptr), 0, 0);
layout->addWidget(contrastSlider, 0, 1);
layout->addWidget(contrastSpinBox, 0, 2);
layout->addWidget(new QLabel(QObject::tr("Saturation:"), q_ptr), 1, 0);
layout->addWidget(saturationSlider, 1, 1);
layout->addWidget(saturationSpinBox, 1, 2);
layout->addWidget(new QLabel(QObject::tr("Brightness:"), q_ptr), 2, 0);
layout->addWidget(brightnessSlider, 2, 1);
layout->addWidget(brightnessSpinBox, 2, 2);
layout->addWidget(resetButton, 3, 2, Qt::AlignRight);
}

ColorSpaceDialog *q_ptr;

Slider *contrastSlider;
Slider *saturationSlider;
Slider *brightnessSlider;
QSpinBox *contrastSpinBox;
QSpinBox *saturationSpinBox;
QSpinBox *brightnessSpinBox;
QToolButton *resetButton;

const float multiple = 100.0;
};

ColorSpaceDialog::ColorSpaceDialog(QWidget *parent)
: QDialog(parent)
, d_ptr(new ColorSpaceDialogPrivate(this))
{
d_ptr->setupUI();
buildConnect();
resize(400, 250);
}

ColorSpaceDialog::~ColorSpaceDialog() = default;

void ColorSpaceDialog::setColorSpace(const Ffmpeg::ColorSpaceTrc &colorTrc)
{
setBlockValue(d_ptr->contrastSpinBox, colorTrc.contrast * d_ptr->multiple);
setBlockValue(d_ptr->saturationSpinBox, colorTrc.saturation * d_ptr->multiple);
setBlockValue(d_ptr->brightnessSpinBox, colorTrc.brightness * d_ptr->multiple);
setBlockValue(d_ptr->contrastSlider, colorTrc.contrast * d_ptr->multiple);
setBlockValue(d_ptr->saturationSlider, colorTrc.saturation * d_ptr->multiple);
setBlockValue(d_ptr->brightnessSlider, colorTrc.brightness * d_ptr->multiple);
}

Ffmpeg::ColorSpaceTrc ColorSpaceDialog::colorSpace() const
{
Ffmpeg::ColorSpaceTrc colorTrc;
colorTrc.contrast = d_ptr->contrastSlider->value() / d_ptr->multiple;
colorTrc.saturation = d_ptr->saturationSlider->value() / d_ptr->multiple;
colorTrc.brightness = d_ptr->brightnessSlider->value() / d_ptr->multiple;
return colorTrc;
}

void ColorSpaceDialog::onContrastSliderChanged(int value)
{
setBlockValue(d_ptr->contrastSpinBox, value);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::onSaturationSliderChanged(int value)
{
setBlockValue(d_ptr->saturationSpinBox, value);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::onBrightnessSliderChanged(int value)
{
setBlockValue(d_ptr->brightnessSpinBox, value);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::onContrastSpinBoxChanged(int value)
{
setBlockValue(d_ptr->contrastSlider, value);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::onSaturationSpinBoxChanged(int value)
{
setBlockValue(d_ptr->saturationSlider, value);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::onBrightnessSpinBoxChanged(int value)
{
setBlockValue(d_ptr->brightnessSlider, value);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::onReset()
{
Ffmpeg::ColorSpaceTrc colorTrc;
setBlockValue(d_ptr->contrastSlider, colorTrc.contrast_default * d_ptr->multiple);
setBlockValue(d_ptr->saturationSlider, colorTrc.saturation_default * d_ptr->multiple);
setBlockValue(d_ptr->brightnessSlider, colorTrc.brightness_default * d_ptr->multiple);
setBlockValue(d_ptr->contrastSpinBox, colorTrc.contrast_default * d_ptr->multiple);
setBlockValue(d_ptr->saturationSpinBox, colorTrc.saturation_default * d_ptr->multiple);
setBlockValue(d_ptr->brightnessSpinBox, colorTrc.brightness_default * d_ptr->multiple);
emit d_ptr->q_ptr->colorSpaceChanged();
}

void ColorSpaceDialog::buildConnect()
{
connect(d_ptr->contrastSlider,
&Slider::valueChanged,
this,
&ColorSpaceDialog::onContrastSliderChanged);
connect(d_ptr->saturationSlider,
&Slider::valueChanged,
this,
&ColorSpaceDialog::onSaturationSliderChanged);
connect(d_ptr->brightnessSlider,
&Slider::valueChanged,
this,
&ColorSpaceDialog::onBrightnessSliderChanged);
connect(d_ptr->contrastSpinBox,
&QSpinBox::valueChanged,
this,
&ColorSpaceDialog::onContrastSpinBoxChanged);
connect(d_ptr->saturationSpinBox,
&QSpinBox::valueChanged,
this,
&ColorSpaceDialog::onSaturationSpinBoxChanged);
connect(d_ptr->brightnessSpinBox,
&QSpinBox::valueChanged,
this,
&ColorSpaceDialog::onBrightnessSpinBoxChanged);

connect(d_ptr->resetButton, &QToolButton::clicked, this, &ColorSpaceDialog::onReset);
}
37 changes: 37 additions & 0 deletions examples/player/colorspacedialog.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef COLORSPACEDIALOG_HPP
#define COLORSPACEDIALOG_HPP

#include <ffmpeg/videorender/videorender.hpp>

#include <QDialog>

class ColorSpaceDialog : public QDialog
{
Q_OBJECT
public:
explicit ColorSpaceDialog(QWidget *parent = nullptr);
~ColorSpaceDialog() override;

void setColorSpace(const Ffmpeg::ColorSpaceTrc &colorTrc);
[[nodiscard]] Ffmpeg::ColorSpaceTrc colorSpace() const;

signals:
void colorSpaceChanged();

private slots:
void onContrastSliderChanged(int value);
void onSaturationSliderChanged(int value);
void onBrightnessSliderChanged(int value);
void onContrastSpinBoxChanged(int value);
void onSaturationSpinBoxChanged(int value);
void onBrightnessSpinBoxChanged(int value);
void onReset();

private:
void buildConnect();

class ColorSpaceDialogPrivate;
QScopedPointer<ColorSpaceDialogPrivate> d_ptr;
};

#endif // COLORSPACEDIALOG_HPP
8 changes: 8 additions & 0 deletions examples/player/controlwidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ class ControlWidget::ControlWidgetPrivate
auto volumeBotton = new QToolButton(q_ptr);
volumeBotton->setIcon(q_ptr->style()->standardIcon(QStyle::SP_MediaVolume));

auto colorSpaceButton = new QToolButton(q_ptr);
colorSpaceButton->setText(tr("Color Space"));
QObject::connect(colorSpaceButton,
&QToolButton::clicked,
q_ptr,
&ControlWidget::showColorSpace);

auto listButton = new QToolButton(q_ptr);
listButton->setText(tr("List"));
QObject::connect(listButton, &QToolButton::clicked, q_ptr, &ControlWidget::showList);
Expand All @@ -86,6 +93,7 @@ class ControlWidget::ControlWidgetPrivate
controlLayout->addWidget(new QLabel("->", q_ptr));
controlLayout->addWidget(currentFPSLabel);
controlLayout->addWidget(modelButton);
controlLayout->addWidget(colorSpaceButton);
controlLayout->addWidget(listButton);

auto widget = new QWidget(q_ptr);
Expand Down
1 change: 1 addition & 0 deletions examples/player/controlwidget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class ControlWidget : public QWidget
void volumeChanged(int value);
void speedChanged(double value);
void modelChanged(int model);
void showColorSpace();
void showList();

private slots:
Expand Down
Loading

0 comments on commit 87ede13

Please sign in to comment.