diff --git a/tools/ld-analyse/ld-analyse.pro b/tools/ld-analyse/ld-analyse.pro index 7cf2b7f50..385bafa22 100644 --- a/tools/ld-analyse/ld-analyse.pro +++ b/tools/ld-analyse/ld-analyse.pro @@ -82,6 +82,7 @@ HEADERS += \ ../library/tbc/filters.h \ ../library/tbc/jsonio.h \ ../library/tbc/lddecodemetadata.h \ + ../library/tbc/linenumber.h \ ../library/tbc/logging.h \ ../library/tbc/sourcevideo.h \ ../library/tbc/vbidecoder.h \ diff --git a/tools/ld-analyse/mainwindow.cpp b/tools/ld-analyse/mainwindow.cpp index 90af71995..4c70e4542 100644 --- a/tools/ld-analyse/mainwindow.cpp +++ b/tools/ld-analyse/mainwindow.cpp @@ -72,7 +72,7 @@ MainWindow::MainWindow(QString inputFilenameParam, QWidget *parent) : if (tbcSource.getIsWidescreen()) aspectRatio = Aspect::DAR_169; // Connect to the scan line changed signal from the oscilloscope dialogue - connect(oscilloscopeDialog, &OscilloscopeDialog::scanLineChanged, this, &MainWindow::scanLineChangedSignalHandler); + connect(oscilloscopeDialog, &OscilloscopeDialog::scopeCoordsChanged, this, &MainWindow::scopeCoordsChangedSignalHandler); lastScopeLine = 1; lastScopeDot = 1; @@ -453,8 +453,8 @@ void MainWindow::updateOscilloscopeDialogue() { // Update the oscilloscope dialogue oscilloscopeDialog->showTraceImage(tbcSource.getScanLineData(lastScopeLine), - lastScopeLine, lastScopeDot, - tbcSource.getFrameHeight()); + lastScopeDot, lastScopeLine - 1, + tbcSource.getFrameWidth(), tbcSource.getFrameHeight()); } // Menu bar signal handlers ------------------------------------------------------------------------------------------- @@ -875,14 +875,14 @@ void MainWindow::on_aspectPushButton_clicked() // Miscellaneous handler methods -------------------------------------------------------------------------------------- // Handler called when another class changes the currenly selected scan line -void MainWindow::scanLineChangedSignalHandler(qint32 scanLine, qint32 pictureDot) +void MainWindow::scopeCoordsChangedSignalHandler(qint32 xCoord, qint32 yCoord) { - qDebug() << "MainWindow::scanLineChangedSignalHandler(): Called with scanLine =" << scanLine << "and picture dot" << pictureDot; + qDebug() << "MainWindow::scanLineChangedSignalHandler(): Called with xCoord =" << xCoord << "and yCoord =" << yCoord; if (tbcSource.getIsSourceLoaded()) { // Show the oscilloscope dialogue for the selected scan-line - lastScopeDot = pictureDot; - lastScopeLine = scanLine; + lastScopeDot = xCoord; + lastScopeLine = yCoord + 1; updateOscilloscopeDialogue(); oscilloscopeDialog->show(); diff --git a/tools/ld-analyse/mainwindow.h b/tools/ld-analyse/mainwindow.h index 32fd00573..61af7ef14 100644 --- a/tools/ld-analyse/mainwindow.h +++ b/tools/ld-analyse/mainwindow.h @@ -98,7 +98,7 @@ private slots: void on_aspectPushButton_clicked(); // Miscellaneous handlers - void scanLineChangedSignalHandler(qint32 scanLine, qint32 pictureDot); + void scopeCoordsChangedSignalHandler(qint32 xCoord, qint32 yCoord); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void chromaDecoderConfigChangedSignalHandler(); diff --git a/tools/ld-analyse/oscilloscopedialog.cpp b/tools/ld-analyse/oscilloscopedialog.cpp index 2cc736332..09e866e7e 100644 --- a/tools/ld-analyse/oscilloscopedialog.cpp +++ b/tools/ld-analyse/oscilloscopedialog.cpp @@ -34,14 +34,17 @@ OscilloscopeDialog::OscilloscopeDialog(QWidget *parent) : ui->setupUi(this); setWindowFlags(Qt::Window); - maximumScanLines = 625; - lastScopeLine = 0; - lastScopeDot = 0; + maximumX = 1135; + maximumY = 625; + lastScopeX = 0; + lastScopeY = 0; scopeWidth = 0; // Configure the GUI - ui->scanLineSpinBox->setMinimum(1); - ui->scanLineSpinBox->setMaximum(625); + ui->xCoordSpinBox->setMinimum(0); + ui->xCoordSpinBox->setMaximum(maximumX - 1); + ui->yCoordSpinBox->setMinimum(0); + ui->yCoordSpinBox->setMaximum(maximumY - 1); ui->previousPushButton->setAutoRepeat(true); ui->previousPushButton->setAutoRepeatInterval(50); @@ -58,19 +61,18 @@ OscilloscopeDialog::~OscilloscopeDialog() delete ui; } -void OscilloscopeDialog::showTraceImage(TbcSource::ScanLineData scanLineData, qint32 scanLine, qint32 pictureDot, qint32 frameHeight) +void OscilloscopeDialog::showTraceImage(TbcSource::ScanLineData scanLineData, qint32 xCoord, qint32 yCoord, qint32 frameWidth, qint32 frameHeight) { - qDebug() << "OscilloscopeDialog::showTraceImage(): Called for scan-line" << scanLine << "with picture dot" << pictureDot; + qDebug() << "OscilloscopeDialog::showTraceImage(): Called with xCoord =" << xCoord << "and yCoord =" << yCoord; - // Set the dialogue title based on the scan-line - this->setWindowTitle("Oscilloscope trace for scan-line #" + QString::number(scanLine)); + // Store coordinates + maximumX = frameWidth; + maximumY = frameHeight; + lastScopeX = xCoord; + lastScopeY = yCoord; // Get the raw field data for the selected line - QImage traceImage; - lastScopeLine = scanLine; - lastScopeDot = pictureDot; - - traceImage = getFieldLineTraceImage(scanLineData, pictureDot); + QImage traceImage = getFieldLineTraceImage(scanLineData, lastScopeX); // Add the QImage to the QLabel in the dialogue ui->scopeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -78,12 +80,22 @@ void OscilloscopeDialog::showTraceImage(TbcSource::ScanLineData scanLineData, qi ui->scopeLabel->setScaledContents(true); ui->scopeLabel->setPixmap(QPixmap::fromImage(traceImage)); - // Update the scan-line spinbox - ui->scanLineSpinBox->setMaximum(frameHeight); - ui->scanLineSpinBox->setValue(scanLine); + // Update the X coordinate spinbox + ui->xCoordSpinBox->setMaximum(maximumX - 1); + ui->xCoordSpinBox->setValue(lastScopeX); + + // Update the Y coordinate spinbox + ui->yCoordSpinBox->setMaximum(maximumY - 1); + ui->yCoordSpinBox->setValue(lastScopeY); + + // Update the line number displays + ui->standardLineLabel->setText(QString("%1 line %2") + .arg(scanLineData.systemDescription) + .arg(scanLineData.lineNumber.standard())); + ui->fieldLineLabel->setText(QString("Field %1 line %2") + .arg(scanLineData.lineNumber.isFirstField() ? "1" : "2") + .arg(scanLineData.lineNumber.field1())); - // Update the maximum scan-lines limit - maximumScanLines = frameHeight; // QT Bug workaround for some macOS versions #if defined(Q_OS_MACOS) repaint(); @@ -233,43 +245,50 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi void OscilloscopeDialog::on_previousPushButton_clicked() { - if (ui->scanLineSpinBox->value() != 1) { - emit scanLineChanged(ui->scanLineSpinBox->value() - 1, lastScopeDot); + if (ui->yCoordSpinBox->value() != 0) { + emit scopeCoordsChanged(lastScopeX, ui->yCoordSpinBox->value() - 1); } } void OscilloscopeDialog::on_nextPushButton_clicked() { - if (ui->scanLineSpinBox->value() < maximumScanLines) { - emit scanLineChanged(ui->scanLineSpinBox->value() + 1, lastScopeDot); + if (ui->yCoordSpinBox->value() < maximumY - 1) { + emit scopeCoordsChanged(lastScopeX, ui->yCoordSpinBox->value() + 1); } } -void OscilloscopeDialog::on_scanLineSpinBox_valueChanged(int arg1) +void OscilloscopeDialog::on_xCoordSpinBox_valueChanged(int arg1) +{ + (void)arg1; + if (ui->xCoordSpinBox->value() != lastScopeX) + emit scopeCoordsChanged(ui->xCoordSpinBox->value(), lastScopeY); +} + +void OscilloscopeDialog::on_yCoordSpinBox_valueChanged(int arg1) { (void)arg1; - if (ui->scanLineSpinBox->value() != lastScopeLine) - emit scanLineChanged(ui->scanLineSpinBox->value(), lastScopeDot); + if (ui->yCoordSpinBox->value() != lastScopeY) + emit scopeCoordsChanged(lastScopeX, ui->yCoordSpinBox->value() ); } void OscilloscopeDialog::on_YCcheckBox_clicked() { - emit scanLineChanged(ui->scanLineSpinBox->value(), lastScopeDot); + emit scopeCoordsChanged(lastScopeX, lastScopeY); } void OscilloscopeDialog::on_YcheckBox_clicked() { - emit scanLineChanged(ui->scanLineSpinBox->value(), lastScopeDot); + emit scopeCoordsChanged(lastScopeX, lastScopeY); } void OscilloscopeDialog::on_CcheckBox_clicked() { - emit scanLineChanged(ui->scanLineSpinBox->value(), lastScopeDot); + emit scopeCoordsChanged(lastScopeX, lastScopeY); } void OscilloscopeDialog::on_dropoutsCheckBox_clicked() { - emit scanLineChanged(ui->scanLineSpinBox->value(), lastScopeDot); + emit scopeCoordsChanged(lastScopeX, lastScopeY); } // Mouse press event handler @@ -322,7 +341,7 @@ void OscilloscopeDialog::mousePictureDotSelect(qint32 oX) if (unscaledX < 0) unscaledX = 0; // Remember the last dot selected - lastScopeDot = unscaledX; + lastScopeX = unscaledX; - emit scanLineChanged(ui->scanLineSpinBox->value(), lastScopeDot); + emit scopeCoordsChanged(lastScopeX, lastScopeY); } diff --git a/tools/ld-analyse/oscilloscopedialog.h b/tools/ld-analyse/oscilloscopedialog.h index c8170e280..ec63c5c43 100644 --- a/tools/ld-analyse/oscilloscopedialog.h +++ b/tools/ld-analyse/oscilloscopedialog.h @@ -47,15 +47,16 @@ class OscilloscopeDialog : public QDialog explicit OscilloscopeDialog(QWidget *parent = nullptr); ~OscilloscopeDialog(); - void showTraceImage(TbcSource::ScanLineData scanLineData, qint32 scanLine, qint32 pictureDot, qint32 frameHeight); + void showTraceImage(TbcSource::ScanLineData scanLineData, qint32 xCoord, qint32 yCoord, qint32 frameWidth, qint32 frameHeight); signals: - void scanLineChanged(qint32 scanLine, qint32 lastScopeDot); + void scopeCoordsChanged(qint32 xCoord, qint32 yCoord); private slots: void on_previousPushButton_clicked(); void on_nextPushButton_clicked(); - void on_scanLineSpinBox_valueChanged(int arg1); + void on_xCoordSpinBox_valueChanged(int arg1); + void on_yCoordSpinBox_valueChanged(int arg1); void on_YCcheckBox_clicked(); void on_YcheckBox_clicked(); void on_CcheckBox_clicked(); @@ -66,10 +67,11 @@ private slots: private: Ui::OscilloscopeDialog *ui; - qint32 maximumScanLines; + qint32 maximumX; + qint32 maximumY; qint32 scopeWidth; - qint32 lastScopeLine; - qint32 lastScopeDot; + qint32 lastScopeX; + qint32 lastScopeY; QImage getFieldLineTraceImage(TbcSource::ScanLineData scanLineData, qint32 pictureDot); void mousePictureDotSelect(qint32 oX); diff --git a/tools/ld-analyse/oscilloscopedialog.ui b/tools/ld-analyse/oscilloscopedialog.ui index 9e5591183..2f87d1532 100644 --- a/tools/ld-analyse/oscilloscopedialog.ui +++ b/tools/ld-analyse/oscilloscopedialog.ui @@ -7,13 +7,13 @@ 0 0 480 - 250 + 300 480 - 250 + 300 @@ -37,13 +37,13 @@ - 120 + 180 130 - 100 + 180 16777215 @@ -64,7 +64,7 @@ - 100 + 32767 16777215 @@ -86,7 +86,7 @@ - 100 + 32767 16777215 @@ -99,20 +99,116 @@ - - - - 50 - 0 - + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + X: + + + + + + + + 0 + 0 + + + + + 50 + 28 + + + + + 100 + 16777215 + + + + + + + + Y: + + + + + + + + 0 + 0 + + + + + 50 + 28 + + + + + 100 + 16777215 + + + + + + + + + + + SECAM line 888 - + + + + + + Field 8 line 888 + + + + + + + Qt::Vertical + + - 100 - 16777215 + 20 + 40 - + @@ -148,19 +244,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/tools/ld-analyse/tbcsource.cpp b/tools/ld-analyse/tbcsource.cpp index 2f62613a8..ac33e2ccd 100644 --- a/tools/ld-analyse/tbcsource.cpp +++ b/tools/ld-analyse/tbcsource.cpp @@ -335,18 +335,10 @@ TbcSource::ScanLineData TbcSource::getScanLineData(qint32 scanLine) ScanLineData scanLineData; LdDecodeMetaData::VideoParameters videoParameters = ldDecodeMetaData.getVideoParameters(); - // Convert the scan line into field and field line - bool isFieldTop = true; - qint32 fieldLine = 0; - - if (scanLine % 2 == 0) isFieldTop = false; - else isFieldTop = true; - - if (isFieldTop) { - fieldLine = (scanLine / 2) + 1; - } else { - fieldLine = (scanLine / 2); - } + // Set the system and line number + scanLineData.systemDescription = ldDecodeMetaData.getVideoSystemDescription(); + scanLineData.lineNumber = LineNumber::fromFrame1(scanLine, videoParameters.system); + const LineNumber &lineNumber = scanLineData.lineNumber; // Set the video parameters scanLineData.blackIre = videoParameters.black16bIre; @@ -366,11 +358,11 @@ TbcSource::ScanLineData TbcSource::getScanLineData(qint32 scanLine) decodeFrame(); // Get the field video and dropout data - const SourceVideo::Data &fieldData = isFieldTop ? inputFields[inputStartIndex].data - : inputFields[inputStartIndex + 1].data; + const SourceVideo::Data &fieldData = lineNumber.isFirstField() ? inputFields[inputStartIndex].data + : inputFields[inputStartIndex + 1].data; const ComponentFrame &componentFrame = componentFrames[0]; - DropOuts &dropouts = isFieldTop ? firstField.dropOuts - : secondField.dropOuts; + DropOuts &dropouts = lineNumber.isFirstField() ? firstField.dropOuts + : secondField.dropOuts; scanLineData.composite.resize(videoParameters.fieldWidth); scanLineData.luma.resize(videoParameters.fieldWidth); @@ -378,14 +370,14 @@ TbcSource::ScanLineData TbcSource::getScanLineData(qint32 scanLine) for (qint32 xPosition = 0; xPosition < videoParameters.fieldWidth; xPosition++) { // Get the 16-bit composite value for the current pixel (frame data is numbered 0-624 or 0-524) - scanLineData.composite[xPosition] = fieldData[((fieldLine - 1) * videoParameters.fieldWidth) + xPosition]; + scanLineData.composite[xPosition] = fieldData[(lineNumber.field0() * videoParameters.fieldWidth) + xPosition]; // Get the decoded luma value for the current pixel (only computed in the active region) scanLineData.luma[xPosition] = static_cast(componentFrame.y(scanLine - 1)[xPosition]); scanLineData.isDropout[xPosition] = false; for (qint32 doCount = 0; doCount < dropouts.size(); doCount++) { - if (dropouts.fieldLine(doCount) == fieldLine) { + if (dropouts.fieldLine(doCount) == lineNumber.field1()) { if (xPosition >= dropouts.startx(doCount) && xPosition <= dropouts.endx(doCount)) scanLineData.isDropout[xPosition] = true; } } diff --git a/tools/ld-analyse/tbcsource.h b/tools/ld-analyse/tbcsource.h index 316687e1b..c38600961 100644 --- a/tools/ld-analyse/tbcsource.h +++ b/tools/ld-analyse/tbcsource.h @@ -35,6 +35,7 @@ // TBC library includes #include "sourcevideo.h" #include "lddecodemetadata.h" +#include "linenumber.h" #include "vbidecoder.h" #include "filters.h" @@ -50,6 +51,8 @@ class TbcSource : public QObject explicit TbcSource(QObject *parent = nullptr); struct ScanLineData { + QString systemDescription; + LineNumber lineNumber; QVector composite; QVector luma; QVector isDropout;