Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split decoding from output conversion #635

Merged
merged 5 commits into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 59 additions & 3 deletions tools/ld-analyse/chromadecoderconfigdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,36 @@
#include "chromadecoderconfigdialog.h"
#include "ui_chromadecoderconfigdialog.h"

#include <cmath>

/*
* These two functions provide a non-linear mapping for sliders that control
* phase adjustments in degrees. The maximum range is from -180 to +180
* degrees, but phase errors are usually < 10 degrees so we need more precise
* adjustment in the middle.
*/

static constexpr double DEGREE_SLIDER_POWER = 3.0;
static constexpr qint32 DEGREE_SLIDER_SCALE = 1000;

static double degreesToSliderPos(double degrees) {
double sliderPos = pow(abs(degrees) / 180, 1 / DEGREE_SLIDER_POWER) * DEGREE_SLIDER_SCALE;
if (degrees < 0) {
return -sliderPos;
} else {
return sliderPos;
}
}

static double sliderPosToDegrees(double sliderPos) {
double degrees = pow(abs(sliderPos) / DEGREE_SLIDER_SCALE, DEGREE_SLIDER_POWER) * 180;
if (sliderPos < 0) {
return -degrees;
} else {
return degrees;
}
}

ChromaDecoderConfigDialog::ChromaDecoderConfigDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ChromaDecoderConfigDialog)
Expand All @@ -36,6 +66,9 @@ ChromaDecoderConfigDialog::ChromaDecoderConfigDialog(QWidget *parent) :
ui->chromaGainHorizontalSlider->setMinimum(0);
ui->chromaGainHorizontalSlider->setMaximum(200);

ui->chromaPhaseHorizontalSlider->setMinimum(-DEGREE_SLIDER_SCALE);
ui->chromaPhaseHorizontalSlider->setMaximum(DEGREE_SLIDER_SCALE);

ui->thresholdHorizontalSlider->setMinimum(0);
ui->thresholdHorizontalSlider->setMaximum(100);

Expand All @@ -55,21 +88,25 @@ ChromaDecoderConfigDialog::~ChromaDecoderConfigDialog()
}

void ChromaDecoderConfigDialog::setConfiguration(bool _isSourcePal, const PalColour::Configuration &_palConfiguration,
const Comb::Configuration &_ntscConfiguration)
const Comb::Configuration &_ntscConfiguration,
const OutputWriter::Configuration &_outputConfiguration)
{
double yNRLevel = _isSourcePal ? palConfiguration.yNRLevel : ntscConfiguration.yNRLevel;
isSourcePal = _isSourcePal;
palConfiguration = _palConfiguration;
ntscConfiguration = _ntscConfiguration;
outputConfiguration = _outputConfiguration;

palConfiguration.chromaGain = qBound(0.0, palConfiguration.chromaGain, 2.0);
palConfiguration.chromaPhase = qBound(-180.0, palConfiguration.chromaPhase, 180.0);
palConfiguration.transformThreshold = qBound(0.0, palConfiguration.transformThreshold, 1.0);
palConfiguration.yNRLevel = qBound(0.0, yNRLevel, 10.0);
ntscConfiguration.cNRLevel = qBound(0.0, ntscConfiguration.cNRLevel, 10.0);
ntscConfiguration.yNRLevel = qBound(0.0, yNRLevel, 10.0);

// For settings that both decoders share, the PAL default takes precedence
ntscConfiguration.chromaGain = palConfiguration.chromaGain;
ntscConfiguration.chromaPhase = palConfiguration.chromaPhase;

// Select the tab corresponding to the current standard automatically
if (isSourcePal) {
Expand All @@ -92,6 +129,11 @@ const Comb::Configuration &ChromaDecoderConfigDialog::getNtscConfiguration()
return ntscConfiguration;
}

const OutputWriter::Configuration &ChromaDecoderConfigDialog::getOutputConfiguration()
{
return outputConfiguration;
}

void ChromaDecoderConfigDialog::updateDialog()
{
// Shared settings
Expand All @@ -101,6 +143,12 @@ void ChromaDecoderConfigDialog::updateDialog()

ui->chromaGainValueLabel->setEnabled(true);
ui->chromaGainValueLabel->setText(QString::number(palConfiguration.chromaGain, 'f', 2));

ui->chromaPhaseHorizontalSlider->setEnabled(true);
ui->chromaPhaseHorizontalSlider->setValue(static_cast<qint32>(degreesToSliderPos(palConfiguration.chromaPhase)));

ui->chromaPhaseValueLabel->setEnabled(true);
ui->chromaPhaseValueLabel->setText(QString::number(palConfiguration.chromaPhase, 'f', 1) + QChar(0xB0));

double yNRLevel = isSourcePal ? palConfiguration.yNRLevel : ntscConfiguration.yNRLevel;

Expand Down Expand Up @@ -170,7 +218,7 @@ void ChromaDecoderConfigDialog::updateDialog()
ui->showMapCheckBox->setChecked(ntscConfiguration.showMap);

ui->whitePoint75CheckBox->setEnabled(isSourceNtsc);
ui->whitePoint75CheckBox->setChecked(ntscConfiguration.whitePoint75);
ui->whitePoint75CheckBox->setChecked(outputConfiguration.whitePoint75);

ui->colorLpfCheckBox->setEnabled(isSourceNtsc);
ui->colorLpfCheckBox->setChecked(ntscConfiguration.colorlpf);
Expand All @@ -197,6 +245,14 @@ void ChromaDecoderConfigDialog::on_chromaGainHorizontalSlider_valueChanged(int v
emit chromaDecoderConfigChanged();
}

void ChromaDecoderConfigDialog::on_chromaPhaseHorizontalSlider_valueChanged(int value)
{
palConfiguration.chromaPhase = sliderPosToDegrees(static_cast<double>(value));
ntscConfiguration.chromaPhase = palConfiguration.chromaPhase;
ui->chromaPhaseValueLabel->setText(QString::number(palConfiguration.chromaPhase, 'f', 1) + QChar(0xB0));
emit chromaDecoderConfigChanged();
}

void ChromaDecoderConfigDialog::on_palFilterButtonGroup_buttonClicked(QAbstractButton *button)
{
if (button == ui->palFilterPalColourRadioButton) {
Expand Down Expand Up @@ -267,7 +323,7 @@ void ChromaDecoderConfigDialog::on_showMapCheckBox_clicked()

void ChromaDecoderConfigDialog::on_whitePoint75CheckBox_clicked()
{
ntscConfiguration.whitePoint75 = ui->whitePoint75CheckBox->isChecked();
outputConfiguration.whitePoint75 = ui->whitePoint75CheckBox->isChecked();
emit chromaDecoderConfigChanged();
}

Expand Down
8 changes: 7 additions & 1 deletion tools/ld-analyse/chromadecoderconfigdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <QDialog>

#include "comb.h"
#include "outputwriter.h"
#include "palcolour.h"

namespace Ui {
Expand All @@ -43,15 +44,19 @@ class ChromaDecoderConfigDialog : public QDialog
explicit ChromaDecoderConfigDialog(QWidget *parent = nullptr);
~ChromaDecoderConfigDialog();

void setConfiguration(bool isSourcePal, const PalColour::Configuration &palConfiguration, const Comb::Configuration &ntscConfiguration);
void setConfiguration(bool isSourcePal, const PalColour::Configuration &palConfiguration,
const Comb::Configuration &ntscConfiguration,
const OutputWriter::Configuration &outputConfiguration);
const PalColour::Configuration &getPalConfiguration();
const Comb::Configuration &getNtscConfiguration();
const OutputWriter::Configuration &getOutputConfiguration();

signals:
void chromaDecoderConfigChanged();

private slots:
void on_chromaGainHorizontalSlider_valueChanged(int value);
void on_chromaPhaseHorizontalSlider_valueChanged(int value);

void on_palFilterButtonGroup_buttonClicked(QAbstractButton *button);
void on_thresholdModeCheckBox_clicked();
Expand All @@ -73,6 +78,7 @@ private slots:
bool isSourcePal;
PalColour::Configuration palConfiguration;
Comb::Configuration ntscConfiguration;
OutputWriter::Configuration outputConfiguration;

void updateDialog();
};
Expand Down
27 changes: 27 additions & 0 deletions tools/ld-analyse/chromadecoderconfigdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,33 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="chromaPhaseLabel">
<property name="text">
<string>Chroma phase:</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="chromaPhaseHorizontalSlider">
<property name="maximum">
<number>200</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="chromaPhaseValueLabel">
<property name="text">
<string>0.0°</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="yNRLabel">
<property name="text">
Expand Down
10 changes: 4 additions & 6 deletions tools/ld-analyse/ld-analyse.pro
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ SOURCES += \
dropoutanalysisdialog.cpp \
../ld-chroma-decoder/palcolour.cpp \
../ld-chroma-decoder/comb.cpp \
../ld-chroma-decoder/rgb.cpp \
../ld-chroma-decoder/ycbcr.cpp \
../ld-chroma-decoder/componentframe.cpp \
../ld-chroma-decoder/outputwriter.cpp \
../ld-chroma-decoder/transformpal.cpp \
../ld-chroma-decoder/transformpal2d.cpp \
../ld-chroma-decoder/transformpal3d.cpp \
Expand Down Expand Up @@ -68,10 +68,8 @@ HEADERS += \
dropoutanalysisdialog.h \
../ld-chroma-decoder/palcolour.h \
../ld-chroma-decoder/comb.h \
../ld-chroma-decoder/rgb.h \
../ld-chroma-decoder/outputframe.h \
../ld-chroma-decoder/ycbcr.h \
../ld-chroma-decoder/yiq.h \
../ld-chroma-decoder/componentframe.h \
../ld-chroma-decoder/outputwriter.h \
../ld-chroma-decoder/transformpal.h \
../ld-chroma-decoder/transformpal2d.h \
../ld-chroma-decoder/transformpal3d.h \
Expand Down
7 changes: 5 additions & 2 deletions tools/ld-analyse/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ void MainWindow::updateGuiLoaded()
aspect43On = false;

// Update the chroma decoder configuration dialogue
chromaDecoderConfigDialog->setConfiguration(tbcSource.getIsSourcePal(), tbcSource.getPalConfiguration(), tbcSource.getNtscConfiguration());
chromaDecoderConfigDialog->setConfiguration(tbcSource.getIsSourcePal(), tbcSource.getPalConfiguration(),
tbcSource.getNtscConfiguration(), tbcSource.getOutputConfiguration());

// Show the current frame
showFrame();
Expand Down Expand Up @@ -865,7 +866,9 @@ void MainWindow::mouseScanLineSelect(qint32 oX, qint32 oY)
void MainWindow::chromaDecoderConfigChangedSignalHandler()
{
// Set the new configuration
tbcSource.setChromaConfiguration(chromaDecoderConfigDialog->getPalConfiguration(), chromaDecoderConfigDialog->getNtscConfiguration());
tbcSource.setChromaConfiguration(chromaDecoderConfigDialog->getPalConfiguration(),
chromaDecoderConfigDialog->getNtscConfiguration(),
chromaDecoderConfigDialog->getOutputConfiguration());

// Update the frame viewer;
updateFrameViewer();
Expand Down
52 changes: 36 additions & 16 deletions tools/ld-analyse/tbcsource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

ld-analyse - TBC output analysis
Copyright (C) 2018-2021 Simon Inns
Copyright (C) 2021 Adam Sampson

This file is part of ld-decode-tools.

Expand Down Expand Up @@ -35,10 +36,12 @@ TbcSource::TbcSource(QObject *parent) : QObject(parent)
sourceReady = false;
frameCacheFrameNumber = -1;

// Set the chroma decoder configuration to default
// Configure the chroma decoder
palConfiguration = palColour.getConfiguration();
palConfiguration.chromaFilter = PalColour::transform2DFilter;
ntscConfiguration = ntscColour.getConfiguration();
outputConfiguration.pixelFormat = OutputWriter::PixelFormat::RGB48;
outputConfiguration.usePadding = false;
decoderConfigurationChanged = false;
}

Expand Down Expand Up @@ -417,10 +420,13 @@ qint32 TbcSource::getCcData1(qint32 frameNumber)
return secondField.ntsc.ccData1;
}

void TbcSource::setChromaConfiguration(const PalColour::Configuration &_palConfiguration, const Comb::Configuration &_ntscConfiguration)
void TbcSource::setChromaConfiguration(const PalColour::Configuration &_palConfiguration,
const Comb::Configuration &_ntscConfiguration,
const OutputWriter::Configuration &_outputConfiguration)
{
palConfiguration = _palConfiguration;
ntscConfiguration = _ntscConfiguration;
outputConfiguration = _outputConfiguration;

// Configure the chroma decoder
LdDecodeMetaData::VideoParameters videoParameters = ldDecodeMetaData.getVideoParameters();
Expand All @@ -430,6 +436,10 @@ void TbcSource::setChromaConfiguration(const PalColour::Configuration &_palConfi
ntscColour.updateConfiguration(videoParameters, ntscConfiguration);
}

// Configure the OutputWriter.
// Because we have padding disabled, this won't change the VideoParameters.
outputWriter.updateConfiguration(videoParameters, outputConfiguration);

decoderConfigurationChanged = true;
}

Expand All @@ -443,6 +453,11 @@ const Comb::Configuration &TbcSource::getNtscConfiguration()
return ntscConfiguration;
}

const OutputWriter::Configuration &TbcSource::getOutputConfiguration()
{
return outputConfiguration;
}

// Return the frame number of the start of the next chapter
qint32 TbcSource::startOfNextChapter(qint32 currentFrameNumber)
{
Expand Down Expand Up @@ -535,32 +550,37 @@ QImage TbcSource::generateQImage(qint32 frameNumber)
if (chromaOn) {
// Chroma decode the current frame and display

// Decode colour for the current frame, to RGB 16-16-16 interlaced output
QVector<OutputFrame> outputFrames(1);
// Decode the current frame to components
QVector<ComponentFrame> componentFrames(1);
if (videoParameters.isSourcePal) {
// PAL source
palColour.decodeFrames(inputFields, startIndex, endIndex, outputFrames);
palColour.decodeFrames(inputFields, startIndex, endIndex, componentFrames);
} else {
// NTSC source
ntscColour.decodeFrames(inputFields, startIndex, endIndex, outputFrames);
ntscColour.decodeFrames(inputFields, startIndex, endIndex, componentFrames);
}

// Convert component video to RGB
OutputFrame outputFrame;
outputWriter.convert(componentFrames[0], outputFrame);

// Get a pointer to the RGB data
const quint16 *rgbPointer = outputFrames[0].RGB.data();
const quint16 *rgbPointer = outputFrame.data();

// Fill the QImage with black
frameImage.fill(Qt::black);

// Copy the RGB16-16-16 data into the RGB888 QImage
for (qint32 y = videoParameters.firstActiveFrameLine; y < videoParameters.lastActiveFrameLine; y++) {
for (qint32 x = videoParameters.activeVideoStart; x < videoParameters.activeVideoEnd; x++) {
qint32 pixelOffset = ((y * videoParameters.fieldWidth) + x) * 3;

// Take just the MSB of the input data
qint32 xpp = x * 3;
*(frameImage.scanLine(y) + xpp + 0) = static_cast<uchar>(rgbPointer[pixelOffset + 0] / 256); // R
*(frameImage.scanLine(y) + xpp + 1) = static_cast<uchar>(rgbPointer[pixelOffset + 1] / 256); // G
*(frameImage.scanLine(y) + xpp + 2) = static_cast<uchar>(rgbPointer[pixelOffset + 2] / 256); // B
const qint32 activeHeight = videoParameters.lastActiveFrameLine - videoParameters.firstActiveFrameLine;
const qint32 activeWidth = videoParameters.activeVideoEnd - videoParameters.activeVideoStart;
for (qint32 y = 0; y < activeHeight; y++) {
const quint16 *inputLine = rgbPointer + (y * activeWidth * 3);
uchar *outputLine = frameImage.scanLine(y + videoParameters.firstActiveFrameLine)
+ (videoParameters.activeVideoStart * 3);

// Take just the MSB of the RGB input data
for (qint32 i = 0; i < activeWidth * 3; i++) {
*outputLine++ = static_cast<uchar>((*inputLine++) / 256);
}
}
} else {
Expand Down
8 changes: 6 additions & 2 deletions tools/ld-analyse/tbcsource.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,11 @@ class TbcSource : public QObject
qint32 getCcData0(qint32 frameNumber);
qint32 getCcData1(qint32 frameNumber);

void setChromaConfiguration(const PalColour::Configuration &palConfiguration, const Comb::Configuration &ntscConfiguration);
void setChromaConfiguration(const PalColour::Configuration &palConfiguration, const Comb::Configuration &ntscConfiguration,
const OutputWriter::Configuration &outputConfiguration);
const PalColour::Configuration &getPalConfiguration();
const Comb::Configuration &getNtscConfiguration();
const OutputWriter::Configuration &getOutputConfiguration();

qint32 startOfNextChapter(qint32 currentFrameNumber);
qint32 startOfChapter(qint32 currentFrameNumber);
Expand Down Expand Up @@ -129,9 +131,10 @@ private slots:
QString currentSourceFilename;
QString lastLoadError;

// Chroma decoders
// Chroma decoder objects
PalColour palColour;
Comb ntscColour;
OutputWriter outputWriter;

// VBI decoder
VbiDecoder vbiDecoder;
Expand All @@ -147,6 +150,7 @@ private slots:
// Chroma decoder configuration
PalColour::Configuration palConfiguration;
Comb::Configuration ntscConfiguration;
OutputWriter::Configuration outputConfiguration;
bool decoderConfigurationChanged;

// Chapter map
Expand Down
Loading