diff --git a/plugins/channeltx/modatv/atvmod.cpp b/plugins/channeltx/modatv/atvmod.cpp index 1b522cc9b..4724d5cf8 100644 --- a/plugins/channeltx/modatv/atvmod.cpp +++ b/plugins/channeltx/modatv/atvmod.cpp @@ -84,6 +84,7 @@ void ATVMod::configure(MessageQueue* messageQueue, ATVModulation atvModulation, bool videoPlayLoop, bool videoPlay, + bool cameraPlay, bool channelMute) { Message* cmd = MsgConfigureATVMod::create( @@ -93,7 +94,8 @@ void ATVMod::configure(MessageQueue* messageQueue, uniformLevel, atvModulation, videoPlayLoop, - videoPlay); + videoPlay, + cameraPlay); messageQueue->push(cmd); } @@ -245,6 +247,44 @@ void ATVMod::pullVideo(Real& sample) m_videoFPSCount = m_videoFPSq; } } + else if ((m_running.m_atvModInput == ATVModInputCamera) && (m_running.m_cameraPlay)) + { + ATVCamera& camera = m_cameras[m_cameraIndex]; // currently selected canera + int grabOK; + int fpsIncrement = (int) camera.m_videoFPSCount - camera.m_videoPrevFPSCount; + + // move a number of frames according to increment + // use grab to test for EOF then retrieve to preserve last valid frame as the current original frame + // TODO: handle pause (no move) + for (int i = 0; i < fpsIncrement; i++) + { + grabOK = camera.m_camera.grab(); + if (!grabOK) break; + } + + if (grabOK) + { + cv::Mat colorFrame; + camera.m_camera.retrieve(colorFrame); + + if (!colorFrame.empty()) // some frames may not come out properly + { + cv::cvtColor(colorFrame, camera.m_videoframeOriginal, CV_BGR2GRAY); + resizeCamera(); + } + + if (camera.m_videoFPSCount < camera.m_videoFPS) + { + camera.m_videoPrevFPSCount = (int) camera.m_videoFPSCount; + camera.m_videoFPSCount += camera.m_videoFPSq; + } + else + { + camera.m_videoPrevFPSCount = 0; + camera.m_videoFPSCount = camera.m_videoFPSq; + } + } + } } m_horizontalCount = 0; @@ -308,6 +348,7 @@ bool ATVMod::handleMessage(const Message& cmd) m_config.m_atvModulation = cfg.getModulation(); m_config.m_videoPlayLoop = cfg.getVideoPlayLoop(); m_config.m_videoPlay = cfg.getVideoPlay(); + m_config.m_cameraPlay = cfg.getCameraPlay(); apply(); @@ -318,7 +359,8 @@ bool ATVMod::handleMessage(const Message& cmd) << " m_uniformLevel: " << m_config.m_uniformLevel << " m_atvModulation: " << (int) m_config.m_atvModulation << " m_videoPlayLoop: " << m_config.m_videoPlayLoop - << " m_videoPlay: " << m_config.m_videoPlay; + << " m_videoPlay: " << m_config.m_videoPlay + << " m_cameraPlay: " << m_config.m_cameraPlay; return true; } @@ -424,6 +466,7 @@ void ATVMod::apply(bool force) m_running.m_atvModulation = m_config.m_atvModulation; m_running.m_videoPlayLoop = m_config.m_videoPlayLoop; m_running.m_videoPlay = m_config.m_videoPlay; + m_running.m_cameraPlay = m_config.m_cameraPlay; } int ATVMod::getSampleRateUnits(ATVStd std) @@ -500,6 +543,8 @@ void ATVMod::applyStandard() calculateVideoSizes(); resizeVideo(); } + + calculateCamerasSizes(); } void ATVMod::openImage(const QString& fileName) @@ -582,6 +627,9 @@ void ATVMod::calculateCamerasSizes() it->m_videoFy = (m_nbImageLines - 2*m_nbBlankLines) / (float) it->m_videoHeight; it->m_videoFx = m_pointsPerImgLine / (float) it->m_videoWidth; it->m_videoFPSq = it->m_videoFPS / m_fps; + it->m_videoFPSCount = it->m_videoFPSq; + it->m_videoPrevFPSCount = 0; + qDebug("ATVMod::calculateCamerasSizes: [%d] factors: %f x %f FPSq: %f", (int) (it - m_cameras.begin()), it->m_videoFx, it->m_videoFy, it->m_videoFPSq); } } @@ -596,6 +644,15 @@ void ATVMod::resizeCameras() } } +void ATVMod::resizeCamera() +{ + ATVCamera& camera = m_cameras[m_cameraIndex]; + + if (!camera.m_videoframeOriginal.empty()) { + cv::resize(camera.m_videoframeOriginal, camera.m_videoFrame, cv::Size(), camera.m_videoFx, camera.m_videoFy); // resize current frame + } +} + void ATVMod::seekVideoFileStream(int seekPercentage) { QMutexLocker mutexLocker(&m_settingsMutex); @@ -641,6 +698,7 @@ void ATVMod::scanCameras() if (m_cameras.size() > 0) { + calculateCamerasSizes(); m_cameraIndex = 0; } } diff --git a/plugins/channeltx/modatv/atvmod.h b/plugins/channeltx/modatv/atvmod.h index 560e7ec87..c6d968463 100644 --- a/plugins/channeltx/modatv/atvmod.h +++ b/plugins/channeltx/modatv/atvmod.h @@ -261,6 +261,7 @@ public: ATVModulation atvModulation, bool videoPlayLoop, bool videoPlay, + bool cameraPLay, bool channelMute); virtual void pull(Sample& sample); @@ -297,6 +298,7 @@ private: ATVModulation getModulation() const { return m_atvModulation; } bool getVideoPlayLoop() const { return m_videoPlayLoop; } bool getVideoPlay() const { return m_videoPlay; } + bool getCameraPlay() const { return m_cameraPlay; } static MsgConfigureATVMod* create( Real rfBandwidth, @@ -305,7 +307,8 @@ private: Real uniformLevel, ATVModulation atvModulation, bool videoPlayLoop, - bool videoPlay) + bool videoPlay, + bool cameraPlay) { return new MsgConfigureATVMod( rfBandwidth, @@ -314,7 +317,8 @@ private: uniformLevel, atvModulation, videoPlayLoop, - videoPlay); + videoPlay, + cameraPlay); } private: @@ -325,6 +329,7 @@ private: ATVModulation m_atvModulation; bool m_videoPlayLoop; bool m_videoPlay; + bool m_cameraPlay; MsgConfigureATVMod( Real rfBandwidth, @@ -333,7 +338,8 @@ private: Real uniformLevel, ATVModulation atvModulation, bool videoPlayLoop, - bool videoPlay) : + bool videoPlay, + bool cameraPlay) : Message(), m_rfBandwidth(rfBandwidth), m_atvStd(atvStd), @@ -341,7 +347,8 @@ private: m_uniformLevel(uniformLevel), m_atvModulation(atvModulation), m_videoPlayLoop(videoPlayLoop), - m_videoPlay(videoPlay) + m_videoPlay(videoPlay), + m_cameraPlay(cameraPlay) { } }; @@ -357,6 +364,8 @@ private: float m_videoFx; //!< camera horizontal scaling factor float m_videoFy; //!< camera vertictal scaling factor float m_videoFPSq; //!< camera FPS sacaling factor + float m_videoFPSCount; //!< camera FPS fractional counter + int m_videoPrevFPSCount; //!< camera FPS previous integer counter ATVCamera() : m_cameraNumber(-1), @@ -365,7 +374,9 @@ private: m_videoHeight(1), m_videoFx(1.0f), m_videoFy(1.0f), - m_videoFPSq(1.0f) + m_videoFPSq(1.0f), + m_videoFPSCount(0.0f), + m_videoPrevFPSCount(0) {} }; @@ -380,6 +391,7 @@ private: ATVModulation m_atvModulation; //!< RF modulation type bool m_videoPlayLoop; //!< Play video in a loop bool m_videoPlay; //!< True to play video and false to pause + bool m_cameraPlay; //!< True to play camera video and false to pause Config() : m_outputSampleRate(-1), @@ -390,7 +402,8 @@ private: m_uniformLevel(0.5f), m_atvModulation(ATVModulationAM), m_videoPlayLoop(false), - m_videoPlay(false) + m_videoPlay(false), + m_cameraPlay(false) { } }; @@ -476,6 +489,7 @@ private: void releaseCameras(); void calculateCamerasSizes(); void resizeCameras(); + void resizeCamera(); inline void pullImageLine(Real& sample) { @@ -547,6 +561,33 @@ private: sample = (pixv / 256.0f) * m_spanLevel + m_blackLevel; } break; + case ATVModInputCamera: + if ((iLineImage < 0) || (m_cameraIndex < 0)) + { + sample = m_spanLevel * m_running.m_uniformLevel + m_blackLevel; + } + else + { + ATVCamera& camera = m_cameras[m_cameraIndex]; + + if (camera.m_videoFrame.empty()) + { + sample = m_spanLevel * m_running.m_uniformLevel + m_blackLevel; + } + 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) + } + + sample = (pixv / 256.0f) * m_spanLevel + m_blackLevel; + } + } + break; case ATVModInputUniform: default: sample = m_spanLevel * m_running.m_uniformLevel + m_blackLevel; diff --git a/plugins/channeltx/modatv/atvmodgui.cpp b/plugins/channeltx/modatv/atvmodgui.cpp index 79d51e630..ced7cf3bf 100644 --- a/plugins/channeltx/modatv/atvmodgui.cpp +++ b/plugins/channeltx/modatv/atvmodgui.cpp @@ -290,6 +290,16 @@ void ATVModGUI::on_navTimeSlider_valueChanged(int value) } } +void ATVModGUI::on_playCamera_toggled(bool checked) +{ + applySettings(); +} + +void ATVModGUI::on_camSelect_currentIndexChanged(int index) +{ + ATVMod::MsgConfigureCameraIndex* message = ATVMod::MsgConfigureCameraIndex::create(index); + m_atvMod->getInputMessageQueue()->push(message); +} void ATVModGUI::configureImageFileName() { @@ -410,6 +420,7 @@ void ATVModGUI::applySettings() (ATVMod::ATVModulation) ui->modulation->currentIndex(), ui->playLoop->isChecked(), ui->playVideo->isChecked(), + ui->playCamera->isChecked(), ui->channelMute->isChecked()); } } diff --git a/plugins/channeltx/modatv/atvmodgui.h b/plugins/channeltx/modatv/atvmodgui.h index 0ded39277..9364b6130 100644 --- a/plugins/channeltx/modatv/atvmodgui.h +++ b/plugins/channeltx/modatv/atvmodgui.h @@ -72,6 +72,9 @@ private slots: void on_playLoop_toggled(bool checked); void on_navTimeSlider_valueChanged(int value); + void on_playCamera_toggled(bool checked); + void on_camSelect_currentIndexChanged(int index); + void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDoubleClicked(); diff --git a/plugins/channeltx/modatv/atvmodgui.ui b/plugins/channeltx/modatv/atvmodgui.ui index 3bbb4b72e..754e84e6f 100644 --- a/plugins/channeltx/modatv/atvmodgui.ui +++ b/plugins/channeltx/modatv/atvmodgui.ui @@ -363,6 +363,11 @@ Video + + + Camera + +