diff --git a/plugins/channeltx/modatv/atvmodgui.cpp b/plugins/channeltx/modatv/atvmodgui.cpp index b311088d6..39af73cb0 100644 --- a/plugins/channeltx/modatv/atvmodgui.cpp +++ b/plugins/channeltx/modatv/atvmodgui.cpp @@ -292,42 +292,45 @@ int ATVModGUI::getNbLines() switch(ui->nbLines->currentIndex()) { case 0: - return 640; - break; - case 2: - return 525; - break; - case 3: - return 480; - break; - case 4: - return 405; - break; - case 5: - return 360; - break; - case 6: - return 343; - break; - case 7: - return 240; - break; - case 8: - return 180; - break; - case 9: - return 120; - break; - case 10: - return 90; - break; - case 11: - return 60; - break; - case 12: - return 32; + return 819; break; case 1: + return 640; + break; + case 3: + return 525; + break; + case 4: + return 480; + break; + case 5: + return 405; + break; + case 6: + return 360; + break; + case 7: + return 343; + break; + case 8: + return 240; + break; + case 9: + return 180; + break; + case 10: + return 120; + break; + case 11: + return 90; + break; + case 12: + return 60; + break; + case 13: + return 32; + break; + case 2: default: return 625; break; @@ -337,30 +340,32 @@ int ATVModGUI::getNbLines() int ATVModGUI::getNbLinesIndex(int nbLines) { if (nbLines < 32) { - return 1; - } else if (nbLines < 60) { - return 12; - } else if (nbLines < 90) { - return 11; - } else if (nbLines < 120) { - return 10; - } else if (nbLines < 180) { - return 9; - } else if (nbLines < 240) { - return 8; - } else if (nbLines < 343) { - return 7; - } else if (nbLines < 360) { - return 6; - } else if (nbLines < 405) { - return 5; - } else if (nbLines < 480) { - return 4; - } else if (nbLines < 525) { - return 3; - } else if (nbLines < 625) { return 2; + } else if (nbLines < 60) { + return 13; + } else if (nbLines < 90) { + return 12; + } else if (nbLines < 120) { + return 11; + } else if (nbLines < 180) { + return 10; + } else if (nbLines < 240) { + return 9; + } else if (nbLines < 343) { + return 8; + } else if (nbLines < 360) { + return 7; + } else if (nbLines < 405) { + return 6; + } else if (nbLines < 480) { + return 5; + } else if (nbLines < 525) { + return 4; + } else if (nbLines < 625) { + return 3; } else if (nbLines < 640) { + return 2; + } else if (nbLines < 819) { return 1; } else { return 0; diff --git a/plugins/channeltx/modatv/atvmodgui.ui b/plugins/channeltx/modatv/atvmodgui.ui index 6744353ab..86af812c5 100644 --- a/plugins/channeltx/modatv/atvmodgui.ui +++ b/plugins/channeltx/modatv/atvmodgui.ui @@ -537,6 +537,11 @@ Lines per full frame + + + 819 + + 640 @@ -698,7 +703,7 @@ - PAL405 + 819L diff --git a/plugins/channeltx/modatv/atvmodsettings.h b/plugins/channeltx/modatv/atvmodsettings.h index a664d9edd..f099773af 100644 --- a/plugins/channeltx/modatv/atvmodsettings.h +++ b/plugins/channeltx/modatv/atvmodsettings.h @@ -28,12 +28,12 @@ struct ATVModSettings { typedef enum { - ATVStdPAL625, - ATVStdPAL525, - ATVStd405, - ATVStdShortInterleaved, - ATVStdShort, - ATVStdHSkip, + ATVStdPAL625, //!< standard 625 lines B, D, G, H, I, K, K1 and N + ATVStdPAL525, //!< standard 525 lines M + ATVStd819, //!< standard 819 lines F (Belgium) + ATVStdShortInterlaced, //!< non-standard with mimimal vertical sync sequences permitted by SDR technology + ATVStdShort, //!< same as above + ATVStdHSkip //!< first introduced vertical sync by skipping horizontal sync to indicate start of image } ATVStd; typedef enum diff --git a/plugins/channeltx/modatv/atvmodsource.cpp b/plugins/channeltx/modatv/atvmodsource.cpp index cd6b01809..efa30ca27 100644 --- a/plugins/channeltx/modatv/atvmodsource.cpp +++ b/plugins/channeltx/modatv/atvmodsource.cpp @@ -39,12 +39,80 @@ const int ATVModSource::m_nbBars = 6; const int ATVModSource::m_cameraFPSTestNbFrames = 100; const int ATVModSource::m_ssbFftLen = 1024; +const ATVModSource::LineType ATVModSource::StdPAL625_F1Start[] = { + LineBroadPulses, // 1 (index 0) + LineBroadPulses, // 2 + LineBroadShortPulses, // 3 + LineShortPulses, // 4 + LineShortPulses // 5 +}; + +const ATVModSource::LineType ATVModSource::StdPAL625_F2Start[] = { + LineBroadPulses, // 314 (index 313) + LineBroadPulses, // 315 + LineShortPulses, // 316 + LineShortPulses, // 317 + LineShortBlackPulses // 318 +}; + +const ATVModSource::LineType ATVModSource::StdPAL525_F1Start[] = { + LineShortPulses, // 1 (index 0) + LineShortPulses, + LineShortPulses, + LineBroadPulses, // 4 + LineBroadPulses, + LineBroadPulses, + LineShortPulses, // 7 + LineShortPulses, + LineShortPulses, // 9 +}; + +const ATVModSource::LineType ATVModSource::StdPAL525_F2Start[] = { + LineShortPulses, // 264 (index 263) + LineShortPulses, // 265 + LineShortBroadPulses, // 266 + LineBroadPulses, // 267 + LineBroadPulses, // 268 + LineBroadShortPulses, // 269 + LineShortPulses, // 270 + LineShortPulses, // 271 + LineShortBlackPulses // 272 +}; + +const ATVModSource::LineType ATVModSource::Std819_F1Start[] = { + LineBroadPulses, // 1 (index 0) + LineBroadPulses, // 2 + LineBroadPulses, // 3 + LineBroadShortPulses, // 4 + LineShortPulses, // 5 + LineShortPulses, // 6 + LineShortPulses, // 7 +}; + +const ATVModSource::LineType ATVModSource::Std819_F2Start[] = { + LineBroadPulses, // 410 (index 409) + LineBroadPulses, // 411 + LineBroadPulses, // 412 + LineShortPulses, // 413 + LineShortPulses, // 414 + LineShortPulses, // 415 +}; + +const ATVModSource::LineType ATVModSource::StdShort_F1Start[] = { + LineBroadPulses, + LineShortPulses, +}; + +const ATVModSource::LineType ATVModSource::StdShort_F2Start[] = { + LineBroadPulses, + LineShortPulses, +}; + ATVModSource::ATVModSource() : m_channelSampleRate(1000000), m_channelFrequencyOffset(0), m_modPhasor(0.0f), m_tvSampleRate(1000000), - m_evenImage(true), m_horizontalCount(0), m_lineCount(0), m_imageOK(false), @@ -61,7 +129,8 @@ ATVModSource::ATVModSource() : m_DSBFilter(nullptr), m_DSBFilterBuffer(nullptr), m_DSBFilterBufferIndex(0), - m_messageQueueToGUI(nullptr) + m_messageQueueToGUI(nullptr), + m_imageLine(0) { scanCameras(); @@ -78,6 +147,8 @@ ATVModSource::ATVModSource() : applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); applySettings(m_settings, true); // does applyStandard() too; + + m_lineType = getLineType(m_settings.m_atvStd, m_lineCount); } ATVModSource::~ATVModSource() @@ -236,42 +307,44 @@ Complex& ATVModSource::modulateVestigialSSB(Real& sample) void ATVModSource::pullVideo(Real& sample) { - if ((m_settings.m_atvStd == ATVModSettings::ATVStdHSkip) && (m_lineCount == m_nbLines2)) // last line in skip mode + if (m_settings.m_atvStd == ATVModSettings::ATVStdHSkip) { - pullImageLine(sample, true); // pull image line without sync + pullImageSample(sample, m_lineCount == m_nbLines - 1); // pull image line without sync at end of image } - else if (m_lineCount < m_nbLines2 + 1) // even image or non interlaced + else { - int iLine = m_lineCount; - - if (iLine < m_nbSyncLinesHeadE + m_nbBlankLines) + switch(m_lineType) { - pullVSyncLine(sample); - } - else if (iLine > m_nbLines2 - m_nbSyncLinesBottom) - { - pullVSyncLine(sample); - } - else - { - pullImageLine(sample); - } - } - else // odd image - { - int iLine = m_lineCount - m_nbLines2 - 1; - - if (iLine < m_nbSyncLinesHeadO + m_nbBlankLines) - { - pullVSyncLine(sample); - } - else if (iLine > m_nbLines2 - 1 - m_nbSyncLinesBottom) - { - pullVSyncLine(sample); - } - else - { - pullImageLine(sample); + case LineImage: + pullImageSample(sample); + break; + case LineImageHalf1Short: + pullImageFirstHalfShortSample(sample); + break; + case LineImageHalf1Broad: + pullImageFirstHalfBroadSample(sample); + break; + case LineImageHalf2: + pullImageLastHalfSample(sample); + break; + case LineShortPulses: + pullVSyncLineEquPulsesSample(sample); + break; + case LineBroadPulses: + pullVSyncLineLongPulsesSample(sample); + break; + case LineShortBroadPulses: + pullVSyncLineEquLongPulsesSample(sample); + break; + case LineBroadShortPulses: + pullVSyncLineLongEquPulsesSample(sample); + break; + case LineShortBlackPulses: + pullVSyncLineEquBlackPulsesSample(sample); + break; + case LineBlack: + default: + pullBlackLineSample(sample); } } @@ -284,12 +357,25 @@ void ATVModSource::pullVideo(Real& sample) if (m_lineCount < m_nbLines - 1) { m_lineCount++; - if (m_lineCount > (m_nbLines/2)) m_evenImage = !m_evenImage; + + if ((m_lineType == LineImage) + || (m_lineType == LineImageHalf1Short) + || (m_lineType == LineImageHalf1Broad) + || (m_lineType == LineImageHalf2)) { + m_imageLine += m_interlaced ? 2 : 1; + } + + if (m_lineCount == m_nbLinesField1) { // field 1 -> field 2 or first field2 + m_imageLine = m_imageLineStart2; // field2 image line start index + } + + m_lineType = getLineType(m_settings.m_atvStd, m_lineCount); } else // new image { m_lineCount = 0; - m_evenImage = !m_evenImage; + m_imageLine = m_imageLineStart1; // field1 image line start index + m_lineType = getLineType(m_settings.m_atvStd, m_lineCount); if ((m_settings.m_atvModInput == ATVModSettings::ATVModInputVideo) && m_videoOK && (m_settings.m_videoPlay) && !m_videoEOF) { @@ -519,14 +605,15 @@ void ATVModSource::applyStandard(const ATVModSettings& settings) m_pointsPerSync = (uint32_t) ((4.7f / 64.0f) * m_pointsPerLine); m_pointsPerBP = (uint32_t) ((5.8f / 64.0f) * m_pointsPerLine); m_pointsPerFP = (uint32_t) ((1.5f / 64.0f) * m_pointsPerLine); - m_pointsPerFSync = (uint32_t) ((2.3f / 64.0f) * m_pointsPerLine); + m_pointsPerVEqu = (uint32_t) ((2.3f / 64.0f) * m_pointsPerLine); // short vertical sync pulse (equalizing) + m_pointsPerVSync = (uint32_t) (((32.0f - 4.7f) / 64.0f) * m_pointsPerLine); // broad vertical sync pulse (field sync) m_pointsPerImgLine = m_pointsPerLine - m_pointsPerSync - m_pointsPerBP - m_pointsPerFP; m_nbHorizPoints = m_pointsPerLine; m_pointsPerHBar = m_pointsPerImgLine / m_nbBars; - m_hBarIncrement = m_spanLevel / (float) (m_nbBars-1); - m_vBarIncrement = m_spanLevel / (float) m_nbBars; + m_hBarIncrement = m_spanLevel / (float) (m_nbBars - 1); + m_vBarIncrement = m_spanLevel / (float) (m_nbBars - 1); m_nbLines = settings.m_nbLines; m_nbLines2 = m_nbLines / 2; @@ -537,101 +624,69 @@ void ATVModSource::applyStandard(const ATVModSettings& settings) // << " m_fps: " << m_config.m_fps // << " rateUnits: " << rateUnits // << " nbPointsPerRateUnit: " << nbPointsPerRateUnit -// << " m_tvSampleRate: " << m_tvSampleRate -// << " m_pointsPerTU: " << m_pointsPerTU; +// << " m_tvSampleRate: " << m_tvSampleRate; switch(settings.m_atvStd) { case ATVModSettings::ATVStdHSkip: - m_nbImageLines = m_nbLines; // lines less the total number of sync lines - m_nbImageLines2 = m_nbImageLines; // force non interleaved for vbars + m_nbImageLines = m_nbLines; // lines less the total number of sync lines (0) + m_nbImageLines2 = m_nbImageLines; // non interlaced (unused) + m_imageLineStart1 = 0; + m_imageLineStart2 = 0; m_interlaced = false; - m_nbSyncLinesHeadE = 0; // number of sync lines on the top of a frame even - m_nbSyncLinesHeadO = 0; // number of sync lines on the top of a frame odd - m_nbSyncLinesBottom = -1; // force no vsync in even block - m_nbLongSyncLines = 0; - m_nbHalfLongSync = 0; - m_nbWholeEqLines = 0; - m_singleLongSync = true; - m_nbBlankLines = 0; m_blankLineLvel = 0.7f; - m_nbLines2 = m_nbLines - 1; + m_nbLines2 = m_nbLines; // non interlaced + m_nbLinesField1 = m_nbLines; // non interlaced break; case ATVModSettings::ATVStdShort: - m_nbImageLines = m_nbLines - 2; // lines less the total number of sync lines - m_nbImageLines2 = m_nbImageLines; // force non interleaved for vbars + m_nbImageLines = m_nbLines - 2; // lines less the total number of sync lines + m_nbImageLines2 = m_nbImageLines; // non interlaced (unused) + m_imageLineStart1 = 0; + m_imageLineStart2 = 0; m_interlaced = false; - m_nbSyncLinesHeadE = 1; // number of sync lines on the top of a frame even - m_nbSyncLinesHeadO = 1; // number of sync lines on the top of a frame odd - m_nbSyncLinesBottom = 0; - m_nbLongSyncLines = 1; - m_nbHalfLongSync = 0; - m_nbWholeEqLines = 0; - m_singleLongSync = true; - m_nbBlankLines = 1; m_blankLineLvel = 0.7f; - m_nbLines2 = m_nbLines; // force non interleaved => treated as even for all lines + m_nbLines2 = m_nbLines; // non interlaced + m_nbLinesField1 = m_nbLines; // non interlaced break; - case ATVModSettings::ATVStdShortInterleaved: - m_nbImageLines = m_nbLines - 2; // lines less the total number of sync lines - m_nbImageLines2 = m_nbImageLines / 2; + case ATVModSettings::ATVStdShortInterlaced: + m_nbImageLines2 = m_nbLines2 - 2; // lines in half image less number of sync/service lines + m_nbImageLines = 2*m_nbImageLines2; + m_imageLineStart1 = 1; //m_nbLines % 2; + m_imageLineStart2 = 0; //1 - (m_nbLines % 2); m_interlaced = true; - m_nbSyncLinesHeadE = 1; // number of sync lines on the top of a frame even - m_nbSyncLinesHeadO = 1; // number of sync lines on the top of a frame odd - m_nbSyncLinesBottom = 0; - m_nbLongSyncLines = 1; - m_nbHalfLongSync = 0; - m_nbWholeEqLines = 0; - m_singleLongSync = true; - m_nbBlankLines = 1; m_blankLineLvel = 0.7f; - break; - case ATVModSettings::ATVStd405: // Follows loosely the 405 lines standard - m_nbImageLines = m_nbLines - 14; // lines less the total number of sync lines - // 14 = m_nbSyncLinesHeadE + m_nbSyncLinesHeadO + m_nbSyncLinesBottom + m_nbHalfLongSync + m_nbWholeEqLines - m_nbImageLines2 = m_nbImageLines / 2; - m_interlaced = true; - m_nbSyncLinesHeadE = 4; // number of sync lines on the top of a frame even - m_nbSyncLinesHeadO = 4; // number of sync lines on the top of a frame odd - m_nbSyncLinesBottom = 3; - m_nbLongSyncLines = 2; - m_nbHalfLongSync = 1; - m_nbWholeEqLines = 2; - m_singleLongSync = false; - m_nbBlankLines = 7; // yields 376 lines (195 - 7) * 2 - m_blankLineLvel = m_blackLevel; + m_nbLinesField1 = m_nbLines2; break; case ATVModSettings::ATVStdPAL525: // Follows PAL-M standard - m_nbImageLines = m_nbLines - 14; - m_nbImageLines2 = m_nbImageLines / 2; + m_nbImageLines2 = (m_nbLines/2) - 19; // 525 -> 243 per half + m_nbImageLines = 2*m_nbImageLines2; + m_imageLineStart1 = 1; + m_imageLineStart2 = 0; m_interlaced = true; - m_nbSyncLinesHeadE = 4; - m_nbSyncLinesHeadO = 4; // number of sync lines on the top of a frame odd - m_nbSyncLinesBottom = 3; - m_nbLongSyncLines = 2; - m_nbHalfLongSync = 1; - m_nbWholeEqLines = 2; - m_singleLongSync = false; - m_nbBlankLines = 15; // yields 480 lines (255 - 15) * 2 m_blankLineLvel = m_blackLevel; + m_nbLinesField1 = m_nbLines2+1; + break; + case ATVModSettings::ATVStd819: // Follows 819 F standard (belgium) + m_nbImageLines2 = (m_nbLines/2) - 28; + m_nbImageLines = 2*m_nbImageLines2; + m_imageLineStart1 = 1; + m_imageLineStart2 = 0; + m_interlaced = true; + m_blankLineLvel = m_blackLevel; + m_nbLinesField1 = m_nbLines2; break; case ATVModSettings::ATVStdPAL625: // Follows PAL-B/G/H standard default: - m_nbImageLines = m_nbLines - 14; - m_nbImageLines2 = m_nbImageLines / 2; + m_nbImageLines2 = (m_nbLines/2) - 24; // 625 -> 288 per half + m_nbImageLines = 2*m_nbImageLines2; + m_imageLineStart1 = 0; + m_imageLineStart2 = 1; m_interlaced = true; - m_nbSyncLinesHeadE = 4; - m_nbSyncLinesHeadO = 4; // number of sync lines on the top of a frame odd - m_nbSyncLinesBottom = 3; - m_nbLongSyncLines = 2; - m_nbHalfLongSync = 1; - m_nbWholeEqLines = 2; - m_singleLongSync = false; - m_nbBlankLines = 17; // yields 576 lines (305 - 17) * 2 m_blankLineLvel = m_blackLevel; + m_nbLinesField1 = m_nbLines2+1; } - m_linesPerVBar = m_nbImageLines2 / m_nbBars; + m_linesPerVBar = m_nbImageLines / m_nbBars; if (m_imageOK) { @@ -713,7 +768,7 @@ void ATVModSource::openVideo(const QString& fileName) void ATVModSource::resizeImage() { - float fy = (m_nbImageLines - 2*m_nbBlankLines) / (float) m_imageOriginal.rows; + float fy = (float) m_nbImageLines / (float) m_imageOriginal.rows; float fx = m_pointsPerImgLine / (float) m_imageOriginal.cols; cv::resize(m_imageOriginal, m_image, cv::Size(), fx, fy); qDebug("ATVModSource::resizeImage: %d x %d -> %d x %d", m_imageOriginal.cols, m_imageOriginal.rows, m_image.cols, m_image.rows); @@ -721,7 +776,7 @@ void ATVModSource::resizeImage() void ATVModSource::calculateVideoSizes() { - m_videoFy = (m_nbImageLines - 2*m_nbBlankLines) / (float) m_videoHeight; + m_videoFy = (float) m_nbImageLines / (float) m_videoHeight; m_videoFx = m_pointsPerImgLine / (float) m_videoWidth; m_videoFPSq = m_videoFPS / m_fps; m_videoFPSCount = m_videoFPSq; @@ -741,7 +796,7 @@ void ATVModSource::calculateCamerasSizes() { for (std::vector::iterator it = m_cameras.begin(); it != m_cameras.end(); ++it) { - it->m_videoFy = (m_nbImageLines - 2*m_nbBlankLines) / (float) it->m_videoHeight; + it->m_videoFy = (float) m_nbImageLines / (float) it->m_videoHeight; it->m_videoFx = m_pointsPerImgLine / (float) it->m_videoWidth; it->m_videoFPSq = it->m_videoFPS / m_fps; it->m_videoFPSqManual = it->m_videoFPSManual / m_fps; diff --git a/plugins/channeltx/modatv/atvmodsource.h b/plugins/channeltx/modatv/atvmodsource.h index e0cce2864..103ba86b2 100644 --- a/plugins/channeltx/modatv/atvmodsource.h +++ b/plugins/channeltx/modatv/atvmodsource.h @@ -128,6 +128,20 @@ private: {} }; + enum LineType + { + LineImage, //!< Full image line + LineImageHalf1Short, //!< Half image line first then short pulse + LineImageHalf1Broad, //!< Half image line first then broad pulse + LineImageHalf2, //!< Half image line first black then image + LineShortPulses, //!< VSync short pulses a.k.a equalizing + LineBroadPulses, //!< VSync broad pulses a.k.a field sync + LineShortBroadPulses, //!< VSync short then broad pulses + LineBroadShortPulses, //!< VSync broad then short pulses + LineShortBlackPulses, //!< VSync short pulse then black + LineBlack, //!< Full black line + }; + int m_channelSampleRate; int m_channelFrequencyOffset; ATVModSettings m_settings; @@ -144,31 +158,27 @@ private: int m_pointsPerBP; //!< number of line points for the back porch int m_pointsPerImgLine; //!< number of line points for the image line uint32_t m_pointsPerFP; //!< number of line points for the front porch - int m_pointsPerFSync; //!< number of line points for the field first sync - a.k.a Equalizing pulse - uint32_t m_pointsPerHBar; //!< number of line points for a bar of the bar chart - uint32_t m_linesPerVBar; //!< number of lines for a bar of the bar chart - uint32_t m_pointsPerTU; //!< number of line points per time unit + int m_pointsPerVEqu; //!< number of line points for the equalizing (short) pulse + int m_pointsPerVSync; //!< number of line points for the vertical sync (broad) pulse int m_nbLines; //!< number of lines per complete frame - int m_nbLines2; //!< same number as above (non interlaced) or half the number above (interlaced) - uint32_t m_nbImageLines; //!< number of image lines excluding synchronization lines - uint32_t m_nbImageLines2; //!< same number as above (non interlaced) or half the number above (interlaced) + int m_nbLines2; //!< same number as above (non interlaced) or Euclidean half the number above (interlaced) + int m_nbLinesField1; //!< In interlaced mode: number of lines in field1 transition included + uint32_t m_nbImageLines2; //!< half the number of effective image lines + uint32_t m_nbImageLines; //!< number of effective image lines + uint32_t m_imageLineStart1; //!< start index of line for field 1 + uint32_t m_imageLineStart2; //!< start index of line for field 2 int m_nbHorizPoints; //!< number of line points per horizontal line - int m_nbSyncLinesHeadE; //!< number of header sync lines on even frame - int m_nbSyncLinesHeadO; //!< number of header sync lines on odd frame - int m_nbSyncLinesBottom;//!< number of sync lines at bottom - int m_nbLongSyncLines; //!< number of whole long sync lines for vertical synchronization - int m_nbHalfLongSync; //!< number of half long sync / equalization lines - int m_nbWholeEqLines; //!< number of whole equalizing lines - bool m_singleLongSync; //!< single or double long sync per long sync line - int m_nbBlankLines; //!< number of lines in a frame (full or half) that are blanked (black) at the top of the image float m_blankLineLvel; //!< video level of blank lines + uint32_t m_pointsPerHBar; //!< number of line points for a bar of the bar chart float m_hBarIncrement; //!< video level increment at each horizontal bar increment + uint32_t m_linesPerVBar; //!< number of lines for a bar of the bar chart float m_vBarIncrement; //!< video level increment at each vertical bar increment - bool m_interlaced; //!< true if image is interlaced (2 half frames per frame) - bool m_evenImage; //!< in interlaced mode true if this is an even image + bool m_interlaced; //!< true if image is interlaced (2 half frames per frame) int m_horizontalCount; //!< current point index on line int m_lineCount; //!< current line index in frame + int m_imageLine; //!< current line index in image float m_fps; //!< resulting frames per second + LineType m_lineType; //!< current line type MovingAverageUtil m_movingAverage; quint32 m_levelCalcCount; @@ -223,6 +233,15 @@ private: static const int m_nbBars; //!< number of bars in bar or chessboard patterns static const int m_cameraFPSTestNbFrames; //!< number of frames for camera FPS test + static const LineType StdPAL625_F1Start[]; + static const LineType StdPAL625_F2Start[]; + static const LineType StdPAL525_F1Start[]; + static const LineType StdPAL525_F2Start[]; + static const LineType Std819_F1Start[]; + static const LineType Std819_F2Start[]; + static const LineType StdShort_F1Start[]; + static const LineType StdShort_F2Start[]; + void pullFinalize(Complex& ci, Sample& sample); void pullVideo(Real& sample); void calculateLevel(Real& sample); @@ -242,7 +261,185 @@ private: MessageQueue *getMessageQueueToGUI() { return m_messageQueueToGUI; } - inline void pullImageLine(Real& sample, bool noHSync = false) + inline LineType getLineType(ATVModSettings::ATVStd standard, int lineNumber) + { + if (standard == ATVModSettings::ATVStdHSkip) + { + return LineImage; // all lines are image lines + } + else if (standard == ATVModSettings::ATVStdPAL625) // m_nbLines2 = 312 - fieldLine 0 = 313 + { + if (lineNumber < m_nbLines2) + { + if (lineNumber < 5) { // field 1 start (0..4 in line index = line number - 1) + return StdPAL625_F1Start[lineNumber]; + } else if (lineNumber < 22) { // field 1 black lines (5..21) + return LineBlack; + } else if (lineNumber == 22) { // field 1 half image line (22) + return LineImageHalf2; + } else if (lineNumber < m_nbLines2 - 2) { // field 1 full image (23..309) + return LineImage; + } else if (lineNumber < m_nbLines2) { // field 1 bottom (310..311) + return LineShortPulses; + } + } + else if (lineNumber == m_nbLines2) // field transition 1 -> 2 (312) + { + return LineShortBroadPulses; + } + else + { + int fieldLine = lineNumber - m_nbLines2 - 1; + + if (fieldLine < 5) { // field 2 start (313..(313+5-1=317)) + return StdPAL625_F2Start[fieldLine]; + } else if (fieldLine < 22) { // field 2 black lines (318..(313+22-1=334)) + return LineBlack; + } else if (fieldLine < m_nbLines2 - 3) { // field 2 full image (335..(313+309-1=621)) + return LineImage; + } else if (fieldLine == m_nbLines2 - 3) { // field 2 half image line (313+309=622) + return LineImageHalf1Short; + } else { // field 2 bottom (623..624..) + return LineShortPulses; + } + } + } + else if (standard == ATVModSettings::ATVStdPAL525) // m_nbLines2 = 262 - fieldLine 0 = 263 + { + if (lineNumber < m_nbLines2) + { + + if (lineNumber < 9) { // field 1 start (0..8 in line index) + return StdPAL525_F1Start[lineNumber]; + } else if (lineNumber < 20) { // field 1 black lines (9..19) + return LineBlack; + } else if (lineNumber < m_nbLines2) { // field 1 full image (20..261) + return LineImage; + } + } + else if (lineNumber == m_nbLines2) // field transition 1 -> 2 or field 1 half image line (262) + { + return LineImageHalf1Short; + } + else + { + int fieldLine = lineNumber - m_nbLines2 - 1; + + if (fieldLine < 9) { // field 2 start (263..(263+9-1=271)) + return StdPAL525_F2Start[fieldLine]; + } else if (fieldLine < 19) { // field 2 black lines (272..(263+19-1=281)) + return LineBlack; + } else if (fieldLine == 19) { // field 2 half image line (263+19=282) + return LineImageHalf2; + } else if (fieldLine < m_nbLines2) { // field 2 full line (283..(263+262-1=524)) + return LineImage; + } else { // failsafe: should not get there - same as field 1 start first line + return LineShortPulses; + } + } + } + else if (standard == ATVModSettings::ATVStd819) // Standard F (Belgian) - m_nbLines2 = 409 - fieldLine 0 = 409 + { + if (lineNumber < m_nbLines2 - 1) + { + if (lineNumber < 7) { // field 1 start (0..6 in line index) + return Std819_F1Start[lineNumber]; + } else if (lineNumber < 26) { // field 1 black lines (7..25) + return LineBlack; + } else if (lineNumber == 26) { // field 1 half image line (26) + return LineImageHalf2; + } else if (lineNumber < m_nbLines2 - 4) { // field 1 full image (27..404) + return LineImage; + } else if (lineNumber < m_nbLines2 - 1) { // field 1 bottom (405..407) + return LineShortPulses; + } + } + else if (lineNumber == m_nbLines2 - 1) // transition field 1 -> 2 (408) + { + return LineShortBroadPulses; + } + else + { + int fieldLine = lineNumber - m_nbLines2; + + if (fieldLine < 6) { // field 2 start (409..(409+6-1=414)) + return Std819_F2Start[fieldLine]; + } else if (fieldLine < 26) { // field 2 black lines (415..(409+26-1=434)) + return LineBlack; + } else if (fieldLine < m_nbLines2 - 3) { // field 2 full image (435..(409+406-1=814)) + return LineImage; + } else if (fieldLine == m_nbLines2 - 3) { // field 2 half image line (409+406=815) + return LineImageHalf1Short; + } else { // field 2 bottom (816..818..) + return LineShortPulses; + } + } + } + else if (standard == ATVModSettings::ATVStdShortInterlaced) + { + if (lineNumber < m_nbLines2) + { + if (lineNumber < 2) { + return StdShort_F1Start[lineNumber]; + } else { + return LineImage; + } + } + else + { + int fieldLine = lineNumber - m_nbLines2; + + if (fieldLine < 2) { + return StdShort_F2Start[fieldLine]; + } else if (fieldLine < m_nbLines2) { + return LineImage; + } else { // failsafe - will add a black line for odd number of lines + return LineBlack; + } + } + } + else if (standard == ATVModSettings::ATVStdShort) + { + if (lineNumber < 2) { + return StdShort_F2Start[lineNumber]; + } else if (lineNumber < m_nbLines) { + return LineImage; + } else { + return LineBlack; + } + } + } + + inline void pullImageLastHalfSample(Real& sample) + { + if (m_horizontalCount < m_pointsPerSync + m_pointsPerBP) { // sync + pullImageSample(sample); + } else if (m_horizontalCount < (m_nbHorizPoints/2)) { + sample = m_blackLevel; + } else { + pullImageSample(sample); + } + } + + inline void pullImageFirstHalfShortSample(Real& sample) + { + if (m_horizontalCount < (m_nbHorizPoints/2)) { + pullImageSample(sample); + } else { + pullVSyncLineEquPulsesSample(sample); + } + } + + inline void pullImageFirstHalfBroadSample(Real& sample) + { + if (m_horizontalCount < (m_nbHorizPoints/2)) { + pullImageSample(sample); + } else { + pullVSyncLineLongPulsesSample(sample); + } + } + + inline void pullImageSample(Real& sample, bool noHSync = false) { if (m_horizontalCount < m_pointsPerSync) // sync pulse { @@ -254,10 +451,13 @@ private: } else if (m_horizontalCount < m_pointsPerSync + m_pointsPerBP + m_pointsPerImgLine) { + if (m_imageLine >= m_nbImageLines) // out of image zone + { + sample = m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; // uniform line + return; + } + int pointIndex = m_horizontalCount - (m_pointsPerSync + m_pointsPerBP); - int oddity = m_lineCount < m_nbLines2 + 1 ? 0 : 1; - int iLine = oddity == 0 ? m_lineCount : m_lineCount - m_nbLines2 - 1; - int iLineImage = iLine - m_nbBlankLines - (oddity == 0 ? m_nbSyncLinesHeadE : m_nbSyncLinesHeadO); switch(m_settings.m_atvModInput) { @@ -265,58 +465,46 @@ private: sample = (pointIndex / m_pointsPerHBar) * m_hBarIncrement + m_blackLevel; break; case ATVModSettings::ATVModInputVBars: - sample = (iLine / m_linesPerVBar) * m_vBarIncrement + m_blackLevel; + sample = (m_imageLine / m_linesPerVBar) * m_vBarIncrement + m_blackLevel; break; case ATVModSettings::ATVModInputChessboard: - sample = (((iLine / m_linesPerVBar)*5 + (pointIndex / m_pointsPerHBar)) % 2) * m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; + sample = (((m_imageLine / m_linesPerVBar)*5 + (pointIndex / m_pointsPerHBar)) % 2) * m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; break; case ATVModSettings::ATVModInputHGradient: sample = (pointIndex / (float) m_pointsPerImgLine) * m_spanLevel + m_blackLevel; break; case ATVModSettings::ATVModInputVGradient: - sample = ((iLine -5) / (float) m_nbImageLines2) * m_spanLevel + m_blackLevel; + sample = (m_imageLine / (float) m_nbImageLines) * m_spanLevel + m_blackLevel; break; case ATVModSettings::ATVModInputDiagonal: - sample = pointIndex < (iLine * m_pointsPerImgLine) / m_nbLines2 ? m_blackLevel : m_settings.m_uniformLevel + m_blackLevel; + sample = pointIndex < (m_imageLine * m_pointsPerImgLine) / m_nbImageLines ? m_blackLevel : m_settings.m_uniformLevel + m_blackLevel; break; case ATVModSettings::ATVModInputImage: - if (!m_imageOK || (iLineImage < -oddity) || m_image.empty()) + if (!m_imageOK || m_image.empty()) { sample = m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; } else { unsigned char pixv; - - if (m_interlaced) { - pixv = m_image.at(2*iLineImage + oddity, pointIndex); // row (y), col (x) - } else { - pixv = m_image.at(iLineImage, pointIndex); // row (y), col (x) - } - + pixv = m_image.at(m_imageLine, pointIndex); // row (y), col (x) sample = (pixv / 256.0f) * m_spanLevel + m_blackLevel; } break; case ATVModSettings::ATVModInputVideo: - if (!m_videoOK || (iLineImage < -oddity) || m_videoFrame.empty()) + if (!m_videoOK || m_videoFrame.empty()) { sample = m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; } else { unsigned char pixv; - - if (m_interlaced) { - pixv = m_videoFrame.at(2*iLineImage + oddity, pointIndex); // row (y), col (x) - } else { - pixv = m_videoFrame.at(iLineImage, pointIndex); // row (y), col (x) - } - + pixv = m_videoFrame.at(m_imageLine, pointIndex); // row (y), col (x) sample = (pixv / 256.0f) * m_spanLevel + m_blackLevel; } break; case ATVModSettings::ATVModInputCamera: - if ((iLineImage < -oddity) || (m_cameraIndex < 0)) + if (m_cameraIndex < 0) { sample = m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; } @@ -331,20 +519,14 @@ private: else { unsigned char pixv; - - if (m_interlaced) { - pixv = camera.m_videoFrame.at(2*iLineImage + oddity, pointIndex); // row (y), col (x) - } else { - pixv = camera.m_videoFrame.at(iLineImage, pointIndex); // row (y), col (x) - } - + pixv = camera.m_videoFrame.at(m_imageLine, pointIndex); // row (y), col (x) sample = (pixv / 256.0f) * m_spanLevel + m_blackLevel; } } break; case ATVModSettings::ATVModInputUniform: default: - sample = m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; + sample = m_spanLevel * m_settings.m_uniformLevel + m_blackLevel; // uniform line } } else // front porch @@ -353,149 +535,82 @@ private: } } - inline void pullVSyncLineLongPulses(Real& sample) + inline void pullVSyncLineEquPulsesSample(Real& sample) { - int halfIndex = m_horizontalCount % (m_nbHorizPoints/2); - - if (halfIndex < (m_nbHorizPoints/2) - m_pointsPerSync) // ultra-black - { - sample = 0.0f; - } - else // black - { - if (m_singleLongSync && (m_horizontalCount < m_nbHorizPoints/2)) { - sample = 0.0f; - } else { - sample = m_blackLevel; - } - } - } - - inline void pullVSyncLineEqualizingPulses(Real& sample) - { - if (m_horizontalCount < m_pointsPerSync) - { + if (m_horizontalCount < m_pointsPerVEqu) { sample = 0.0f; // ultra-black - } - else if (m_horizontalCount < (m_nbHorizPoints/2)) - { + } else if (m_horizontalCount < (m_nbHorizPoints/2)) { sample = m_blackLevel; // black - } - else if (m_horizontalCount < (m_nbHorizPoints/2) + m_pointsPerFSync) - { + } else if (m_horizontalCount < (m_nbHorizPoints/2) + m_pointsPerVEqu) { sample = 0.0f; // ultra-black - } - else - { + } else { sample = m_blackLevel; // black } } - inline void pullVSyncLineEqualizingThenLongPulses(Real& sample) + inline void pullVSyncLineLongPulsesSample(Real& sample) { - if (m_horizontalCount < m_pointsPerSync) - { + if (m_horizontalCount < m_pointsPerVSync) { sample = 0.0f; // ultra-black - } - else if (m_horizontalCount < (m_nbHorizPoints/2)) - { + } else if (m_horizontalCount < (m_nbHorizPoints/2)) { sample = m_blackLevel; // black - } - else if (m_horizontalCount < m_nbHorizPoints - m_pointsPerSync) - { + } else if (m_horizontalCount < (m_nbHorizPoints/2) + m_pointsPerVSync) { sample = 0.0f; // ultra-black - } - else - { + } else { sample = m_blackLevel; // black } } - inline void pullVSyncLineLongThenEqualizingPulses(Real& sample) + inline void pullVSyncLineEquLongPulsesSample(Real& sample) { - if (m_horizontalCount < (m_nbHorizPoints/2) - m_pointsPerSync) - { + if (m_horizontalCount < m_pointsPerVEqu) { sample = 0.0f; // ultra-black - } - else if (m_horizontalCount < (m_nbHorizPoints/2)) - { + } else if (m_horizontalCount < (m_nbHorizPoints/2)) { sample = m_blackLevel; // black - } - else if (m_horizontalCount < (m_nbHorizPoints/2) + m_pointsPerFSync) - { + } else if (m_horizontalCount < (m_nbHorizPoints/2) + m_pointsPerVSync) { sample = 0.0f; // ultra-black - } - else - { + } else { sample = m_blackLevel; // black } } - inline void pullVSyncLine(Real& sample) + inline void pullVSyncLineEquBlackPulsesSample(Real& sample) { - if (m_lineCount < m_nbLines2 + 1) // even - { - int fieldLine = m_lineCount; - - if (fieldLine < m_nbLongSyncLines) // 0,1: Whole line "long" pulses - { - pullVSyncLineLongPulses(sample); - } - else if (fieldLine < m_nbLongSyncLines + m_nbHalfLongSync) // long pulse then equalizing pulse - { - pullVSyncLineLongThenEqualizingPulses(sample); - } - else if (fieldLine < m_nbLongSyncLines + m_nbHalfLongSync + m_nbWholeEqLines) // Whole line equalizing pulses - { - pullVSyncLineEqualizingPulses(sample); - } - else if (fieldLine > m_nbLines2 - m_nbHalfLongSync) // equalizing pulse then long pulse - { - pullVSyncLineEqualizingThenLongPulses(sample); - } - else if (fieldLine > m_nbLines2 - m_nbHalfLongSync - m_nbWholeEqLines) // Whole line equalizing pulses - { - pullVSyncLineEqualizingPulses(sample); - } - else // black images - { - if (m_horizontalCount < m_pointsPerSync) - { - sample = 0.0f; - } - else - { - sample = m_blankLineLvel; - } - } + if (m_horizontalCount < m_pointsPerVEqu) { + sample = 0.0f; // ultra-black + } else { + sample = m_blackLevel; // black } - else // odd - { - int fieldLine = m_lineCount - m_nbLines2 - 1; + } - if (fieldLine < m_nbLongSyncLines) // 0,1: Whole line "long" pulses - { - pullVSyncLineLongPulses(sample); - } - else if (fieldLine < m_nbLongSyncLines + m_nbWholeEqLines) // Whole line equalizing pulses - { - pullVSyncLineEqualizingPulses(sample); - } - else if (fieldLine > m_nbLines2 - 1 - m_nbWholeEqLines - m_nbHalfLongSync) // Whole line equalizing pulses - { - pullVSyncLineEqualizingPulses(sample); - } - else // black images - { - if (m_horizontalCount < m_pointsPerSync) - { - sample = 0.0f; - } - else - { - sample = m_blankLineLvel; - } - } + inline void pullVSyncLineLongEquPulsesSample(Real& sample) + { + if (m_horizontalCount < m_pointsPerVSync) { + sample = 0.0f; // ultra-black + } else if (m_horizontalCount < (m_nbHorizPoints/2)) { + sample = m_blackLevel; // black + } else if (m_horizontalCount < (m_nbHorizPoints/2) + m_pointsPerVEqu) { + sample = 0.0f; // ultra-black + } else { + sample = m_blackLevel; // black + } + } + + inline void pullVSyncLineLongBlackPulsesSample(Real& sample) + { + if (m_horizontalCount < m_pointsPerVSync) { + sample = 0.0f; // ultra-black + } else { + sample = m_blackLevel; // black + } + } + + inline void pullBlackLineSample(Real& sample) + { + if (m_horizontalCount < m_pointsPerSync) { + sample = 0.0f; // ultra-black + } else { + sample = m_blackLevel; // black } } };