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

Added enhanced Multidisc dropout correction feature to ld-dropout-correct #393

Merged
merged 9 commits into from
Dec 31, 2019
137 changes: 86 additions & 51 deletions tools/ld-dropout-correct/correctorpool.cpp

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions tools/ld-dropout-correct/correctorpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
correctorpool.h

ld-dropout-correct - Dropout correction for ld-decode
Copyright (C) 2018-2019 Simon Inns
Copyright (C) 2018-2020 Simon Inns

This file is part of ld-decode-tools.

Expand Down Expand Up @@ -41,7 +41,7 @@ class CorrectorPool : public QObject
Q_OBJECT
public:
explicit CorrectorPool(QString _outputFilename, QString _outputJsonFilename,
qint32 _maxThreads, QVector<LdDecodeMetaData> &_ldDecodeMetaData, QVector<SourceVideo> &_sourceVideos,
qint32 _maxThreads, QVector<LdDecodeMetaData *> &_ldDecodeMetaData, QVector<SourceVideo *> &_sourceVideos,
bool _reverse, bool _intraField, bool _overCorrect, QObject *parent = nullptr);

bool process();
Expand All @@ -51,11 +51,13 @@ class CorrectorPool : public QObject
QVector<qint32> &firstFieldNumber, QVector<QByteArray> &firstFieldVideoData, QVector<LdDecodeMetaData::Field> &firstFieldMetadata,
QVector<qint32> &secondFieldNumber, QVector<QByteArray> &secondFieldVideoData, QVector<LdDecodeMetaData::Field> &secondFieldMetadata,
QVector<LdDecodeMetaData::VideoParameters> &videoParameters,
bool& _reverse, bool& _intraField, bool& _overCorrect);
bool& _reverse, bool& _intraField, bool& _overCorrect, QVector<qint32> &minVbiForSource,
QVector<qint32> &maxVbiForSource, QVector<qint32> &availableSourcesForFrame, QVector<qreal> &sourceFrameQuality);

bool setOutputFrame(qint32 frameNumber,
QByteArray firstTargetFieldData, QByteArray secondTargetFieldData,
qint32 firstFieldSeqNo, qint32 secondFieldSeqNo);
qint32 firstFieldSeqNo, qint32 secondFieldSeqNo,
qint32 sameSourceReplacement, qint32 multiSourceReplacement, qint32 totalReplacementDistance);

private:
QString outputFilename;
Expand All @@ -74,8 +76,8 @@ class CorrectorPool : public QObject
QMutex inputMutex;
qint32 inputFrameNumber;
qint32 lastFrameNumber;
QVector<LdDecodeMetaData> &ldDecodeMetaData;
QVector<SourceVideo> &sourceVideos;
QVector<LdDecodeMetaData *> &ldDecodeMetaData;
QVector<SourceVideo *> &sourceVideos;

// Output stream information (all guarded by outputMutex while threads are running)
QMutex outputMutex;
Expand All @@ -85,6 +87,11 @@ class CorrectorPool : public QObject
QByteArray secondTargetFieldData;
qint32 firstFieldSeqNo;
qint32 secondFieldSeqNo;

// Statistics
qint32 sameSourceReplacement;
qint32 multiSourceReplacement;
qint32 totalReplacementDistance;
};

qint32 outputFrameNumber;
Expand Down
226 changes: 156 additions & 70 deletions tools/ld-dropout-correct/dropoutcorrect.cpp

Large diffs are not rendered by default.

38 changes: 26 additions & 12 deletions tools/ld-dropout-correct/dropoutcorrect.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
dropoutcorrect.h

ld-dropout-correct - Dropout correction for ld-decode
Copyright (C) 2018-2019 Simon Inns
Copyright (C) 2018-2020 Simon Inns

This file is part of ld-decode-tools.

Expand Down Expand Up @@ -65,6 +65,18 @@ class DropOutCorrect : public QThread

bool isSameField;
qint32 fieldLine;

qint32 sourceNumber;
qreal quality;

qint32 distance;
};

// Statistics
struct Statistics {
qint32 sameSourceReplacement;
qint32 multiSourceReplacement;
qint32 totalReplacementDistance;
};

// Decoder pool
Expand All @@ -74,24 +86,26 @@ class DropOutCorrect : public QThread
LdDecodeMetaData ldDecodeMetaData;
QVector<LdDecodeMetaData::VideoParameters> videoParameters;

void correctField(const QVector<DropOutLocation> &thisFieldDropouts,
const QVector<DropOutLocation> &otherFieldDropouts,
QByteArray &thisFieldData, const QByteArray &otherFieldData,
bool thisFieldIsFirst, bool intraField);
void correctField(const QVector<QVector<DropOutLocation> > &thisFieldDropouts,
const QVector<QVector<DropOutLocation> > &otherFieldDropouts,
QVector<QByteArray> &thisFieldData, const QVector<QByteArray> &otherFieldData,
bool thisFieldIsFirst, bool intraField, QVector<qint32> &availableSourcesForFrame,
QVector<qreal> &sourceFrameQuality, Statistics &statistics);
QVector<DropOutLocation> populateDropoutsVector(LdDecodeMetaData::Field field, bool overCorrect);
QVector<DropOutLocation> setDropOutLocations(QVector<DropOutLocation> dropOuts);
Replacement findReplacementLine(const QVector<DropOutLocation> &thisFieldDropouts,
const QVector<DropOutLocation> &otherFieldDropouts,
Replacement findReplacementLine(const QVector<QVector<DropOutLocation>> &thisFieldDropouts,
const QVector<QVector<DropOutLocation>> &otherFieldDropouts,
qint32 dropOutIndex, bool thisFieldIsFirst, bool matchChromaPhase,
bool isColourBurst, bool intraField);
void findPotentialReplacementLine(const QVector<DropOutLocation> &targetDropouts, qint32 targetIndex,
const QVector<DropOutLocation> &sourceDropouts, bool isSameField,
bool isColourBurst, bool intraField, QVector<qint32> &availableSourcesForFrame,
QVector<qreal> &sourceFrameQuality);
void findPotentialReplacementLine(const QVector<QVector<DropOutLocation>> &targetDropouts, qint32 targetIndex,
const QVector<QVector<DropOutLocation>> &sourceDropouts, bool isSameField,
qint32 sourceOffset, qint32 stepAmount,
qint32 firstActiveFieldLine, qint32 lastActiveFieldLine,
QVector<Replacement> &candidates);
QVector<Replacement> &candidates, qint32 sourceNo, QVector<qreal> sourceFrameQuality);
void correctDropOut(const DropOutLocation &dropOut,
const Replacement &replacement, const Replacement &chromaReplacement,
QByteArray &thisFieldData, const QByteArray &otherFieldData);
QVector<QByteArray> &thisFieldData, const QVector<QByteArray> &otherFieldData, Statistics &statistics);
};

#endif // DROPOUTCORRECT_H
54 changes: 37 additions & 17 deletions tools/ld-dropout-correct/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
main.cpp

ld-dropout-correct - Dropout correction for ld-decode
Copyright (C) 2018-2019 Simon Inns
Copyright (C) 2018-2020 Simon Inns

This file is part of ld-decode-tools.

Expand All @@ -29,7 +29,6 @@
#include <QThread>

#include "correctorpool.h"
#include "dropoutcorrect.h"

// Global for debug output
static bool showDebug = false;
Expand Down Expand Up @@ -166,7 +165,6 @@ int main(int argc, char *argv[])
QString outputFilename = "-";
QStringList positionalArguments = parser.positionalArguments();
qint32 totalNumberOfInputFiles = positionalArguments.count() - 1;
inputFilenames.resize(totalNumberOfInputFiles);

// Ensure we don't have more than 32 sources
if (totalNumberOfInputFiles > 32) {
Expand All @@ -176,6 +174,9 @@ int main(int argc, char *argv[])

// Get the input TBC sources
if (positionalArguments.count() >= 2) {
// Resize the input filenames vector according to the number of input files supplied
inputFilenames.resize(totalNumberOfInputFiles);

for (qint32 i = 0; i < positionalArguments.count() - 1; i++) {
inputFilenames[i] = positionalArguments.at(i);
}
Expand Down Expand Up @@ -238,16 +239,21 @@ int main(int argc, char *argv[])
qInfo() << "Starting preparation for dropout correction processes...";
// Open the source video metadata
qDebug() << "main(): Opening source video metadata files..";
QVector<LdDecodeMetaData> ldDecodeMetaData;
QVector<LdDecodeMetaData *> ldDecodeMetaData;
ldDecodeMetaData.resize(totalNumberOfInputFiles);
for (qint32 i = 0; i < totalNumberOfInputFiles; i++) {
// Create an object for the source video
ldDecodeMetaData[i] = new LdDecodeMetaData;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete these at the end.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

for (qint32 i = 0; i < totalNumberOfInputFiles; i++) {
// Work out the metadata filename
QString jsonFilename = inputFilenames[i] + ".json";
if (parser.isSet(inputJsonOption) && i == 0) jsonFilename = parser.value(inputJsonOption);
qInfo().nospace().noquote() << "Reading input #" << i << " JSON metadata from " << jsonFilename;

// Open it
if (!ldDecodeMetaData[i].read(jsonFilename)) {
if (!ldDecodeMetaData[i]->read(jsonFilename)) {
qCritical() << "Unable to open TBC JSON metadata file - cannot continue";
return -1;
}
Expand All @@ -257,7 +263,7 @@ int main(int argc, char *argv[])
if (reverse) {
qInfo() << "Expected field order is reversed to second field/first field";
for (qint32 i = 0; i < totalNumberOfInputFiles; i++)
ldDecodeMetaData[i].setIsFirstFieldFirst(false);
ldDecodeMetaData[i]->setIsFirstFieldFirst(false);
}

// Intrafield only correction if required
Expand All @@ -272,42 +278,46 @@ int main(int argc, char *argv[])

// Show and open input source TBC files
qDebug() << "main(): Opening source video files...";
QVector<SourceVideo> sourceVideos;
QVector<SourceVideo *> sourceVideos;
sourceVideos.resize(totalNumberOfInputFiles);
for (qint32 i = 0; i < totalNumberOfInputFiles; i++) {
// Create an object for the source video
sourceVideos[i] = new SourceVideo;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete these at the end.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

for (qint32 i = 0; i < totalNumberOfInputFiles; i++) {
LdDecodeMetaData::VideoParameters videoParameters = ldDecodeMetaData[i].getVideoParameters();
LdDecodeMetaData::VideoParameters videoParameters = ldDecodeMetaData[i]->getVideoParameters();

qInfo().nospace() << "Opening input #" << i << ": " << videoParameters.fieldWidth << "x" << videoParameters.fieldHeight <<
" - input filename is " << inputFilenames[i];

// Open the source TBC
if (!sourceVideos[i].open(inputFilenames[i], videoParameters.fieldWidth * videoParameters.fieldHeight)) {
if (!sourceVideos[i]->open(inputFilenames[i], videoParameters.fieldWidth * videoParameters.fieldHeight)) {
// Could not open source video file
qInfo() << "Unable to open input source" << i;
qInfo() << "Please verify that the specified source video files exist with the correct file permissions";
return 1;
}

// Verify TBC and JSON input fields match
if (sourceVideos[i].getNumberOfAvailableFields() != ldDecodeMetaData[0].getNumberOfFields()) {
qInfo() << "Warning: TBC file contains" << sourceVideos[i].getNumberOfAvailableFields() <<
"fields but the JSON indicates" << ldDecodeMetaData[0].getNumberOfFields() <<
if (sourceVideos[i]->getNumberOfAvailableFields() != ldDecodeMetaData[0]->getNumberOfFields()) {
qInfo() << "Warning: TBC file contains" << sourceVideos[i]->getNumberOfAvailableFields() <<
"fields but the JSON indicates" << ldDecodeMetaData[0]->getNumberOfFields() <<
"fields - some fields will be ignored";
qInfo() << "Update your copy of ld-decode and try again, this shouldn't happen unless the JSON metadata has been corrupted";
}

// Additional checks when using multiple input sources
if (totalNumberOfInputFiles > 1) {
// Ensure source video has VBI data
if (!ldDecodeMetaData[i].getFieldVbi(1).inUse) {
if (!ldDecodeMetaData[i]->getFieldVbi(1).inUse) {
qInfo() << "Source video" << i << "does not appear to have valid VBI data in the JSON metadata.";
qInfo() << "Please try running ld-process-vbi on the source video and then try again";
return 1;
}

// Ensure that the video source standard matches the primary source
if (ldDecodeMetaData[0].getVideoParameters().isSourcePal != videoParameters.isSourcePal) {
if (ldDecodeMetaData[0]->getVideoParameters().isSourcePal != videoParameters.isSourcePal) {
qInfo() << "All additional input sources must have the same video format (PAL/NTSC) as the initial source!";
return 1;
}
Expand All @@ -322,11 +332,21 @@ int main(int argc, char *argv[])

// Perform the DOC process ----------------------------------------------------------------------------------------
qInfo() << "Initial source checks are ok and sources are loaded";
qint32 result = 0;
CorrectorPool correctorPool(outputFilename, outputJsonFilename, maxThreads,
ldDecodeMetaData, sourceVideos,
reverse, intraField, overCorrect);
if (!correctorPool.process()) return 1;
if (!correctorPool.process()) result = 1;

// Close open source video files
for (qint32 i = 0; i < totalNumberOfInputFiles; i++) sourceVideos[i]->close();

// Remove metadata objects
for (qint32 i = 0; i < totalNumberOfInputFiles; i++) delete ldDecodeMetaData[i];

// Remove source video objects
for (qint32 i = 0; i < totalNumberOfInputFiles; i++) delete sourceVideos[i];

// Quit with success
return 0;
// Quit
return result;
}
3 changes: 3 additions & 0 deletions tools/library/tbc/lddecodemetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ class LdDecodeMetaData

LdDecodeMetaData();

// Prevent implicit copying
LdDecodeMetaData(const LdDecodeMetaData &src) = delete;

bool read(QString fileName);
bool write(QString fileName);
bool writeVitsCsv(QString fileName);
Expand Down
3 changes: 3 additions & 0 deletions tools/library/tbc/sourcevideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class SourceVideo
SourceVideo();
~SourceVideo();

// Prevent implicit copying
SourceVideo(const SourceVideo &src) = delete;

// File handling methods
bool open(QString filename, qint32 _fieldLength, qint32 _fieldLineLength = -1);
void close(void);
Expand Down