21 #include <QNetworkAccessManager> 22 #include <QNetworkReply> 29 #include "opencv2/imgproc/imgproc.hpp" 63 m_deviceAPI(deviceAPI),
64 m_outputSampleRate(1000000),
65 m_inputFrequencyOffset(0),
67 m_tvSampleRate(1000000),
69 m_settingsMutex(QMutex::Recursive),
74 m_videoFPSCount(0.0f),
75 m_videoPrevFPSCount(0),
82 m_SSBFilterBufferIndex(0),
85 m_DSBFilterBufferIndex(0)
186 double magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
332 for (
int i = 0;
i < fpsIncrement;
i++)
343 if (!colorFrame.empty())
403 if (!frame.empty()) nbFrames++;
408 double seconds = difftime (end, start);
457 for (
int i = 0;
i < fpsIncrement;
i++)
460 if (colorFrame.empty())
break;
463 if (!colorFrame.empty())
525 qDebug() <<
"ATVMod::handleMessage: MsgChannelizerNotification:" 548 qDebug() <<
"ATVMod::handleMessage: MsgConfigureATVMod";
579 framesCount =
m_video.get(CV_CAP_PROP_POS_FRAMES);;
628 m_cameras[index].m_videoFPSManual = mnaualFPS;
629 m_cameras[index].m_videoFPSManualEnable = manualFPSEnable;
646 int maxPoints = outputSampleRate / linesPerSecond;
651 if ((i * linesPerSecond) % 10 == 0)
655 nbPointsPerRateUnit = i == 0 ? maxPoints :
i;
656 sampleRateUnits = nbPointsPerRateUnit * linesPerSecond;
810 m_imageFromFile = cv::imread(qPrintable(fileName), CV_LOAD_IMAGE_GRAYSCALE);
827 qDebug(
"ATVMod::openImage: cannot open image file %s", qPrintable(fileName));
844 int ex =
static_cast<int>(
m_video.get(CV_CAP_PROP_FOURCC));
845 char ext[] = {(char)(ex & 0XFF),(char)((ex & 0XFF00) >> 8),(
char)((ex & 0XFF0000) >> 16),(char)((ex & 0XFF000000) >> 24),0};
847 qDebug(
"ATVMod::openVideo: %s FPS: %f size: %d x %d #frames: %d codec: %s",
848 m_video.isOpened() ?
"OK" :
"KO",
868 qDebug(
"ATVMod::openVideo: cannot open video file %s", qPrintable(fileName));
900 for (std::vector<ATVCamera>::iterator it =
m_cameras.begin(); it !=
m_cameras.end(); ++it)
904 it->m_videoFPSq = it->m_videoFPS /
m_fps;
905 it->m_videoFPSqManual = it->m_videoFPSManual /
m_fps;
906 it->m_videoFPSCount = 0;
907 it->m_videoPrevFPSCount = 0;
909 qDebug(
"ATVMod::calculateCamerasSizes: [%d] factors: %f x %f FPSq: %f", (
int) (it -
m_cameras.begin()), it->m_videoFx, it->m_videoFy, it->m_videoFPSq);
915 for (std::vector<ATVCamera>::iterator it =
m_cameras.begin(); it !=
m_cameras.end(); ++it)
917 if (!it->m_videoframeOriginal.empty()) {
918 cv::resize(it->m_videoframeOriginal, it->m_videoFrame, cv::Size(), it->m_videoFx, it->m_videoFy);
939 m_video.set(CV_CAP_PROP_POS_FRAMES, seekPoint);
948 for (
int i = 0;
i < 4;
i++)
955 if (
m_cameras.back().m_camera.isOpened())
958 m_cameras.back().m_videoWidth = (int)
m_cameras.back().m_camera.get(CV_CAP_PROP_FRAME_WIDTH);
959 m_cameras.back().m_videoHeight = (int)
m_cameras.back().m_camera.get(CV_CAP_PROP_FRAME_HEIGHT);
963 qDebug(
"ATVMod::scanCameras: [%d] FPS: %f %dx%d",
984 for (std::vector<ATVCamera>::iterator it =
m_cameras.begin(); it !=
m_cameras.end(); ++it)
986 if (it->m_camera.isOpened()) it->m_camera.release();
992 for (std::vector<ATVCamera>::iterator it =
m_cameras.begin(); it !=
m_cameras.end(); ++it) {
993 numbers.push_back(it->m_cameraNumber);
1018 int fontFace = cv::FONT_HERSHEY_PLAIN;
1019 double fontScale = image.rows / 100.0;
1020 int thickness = image.cols / 160;
1023 fontScale = fontScale < 4.0f ? 4.0f : fontScale;
1024 cv::Size textSize = cv::getTextSize(
m_settings.
m_overlayText.toStdString(), fontFace, fontScale, thickness, &baseline);
1025 baseline += thickness;
1028 cv::Point textOrg(6, textSize.height+10);
1035 qDebug() <<
"AMMod::applyChannelSettings:" 1036 <<
" outputSampleRate: " << outputSampleRate
1037 <<
" inputFrequencyOffset: " << inputFrequencyOffset;
1088 qDebug() <<
"ATVMod::applySettings:" 1092 <<
" m_atvStd: " << (int) settings.
m_atvStd 1094 <<
" m_fps: " << settings.
m_fps 1108 <<
" force: " << force;
1110 QList<QString> reverseAPIKeys;
1113 reverseAPIKeys.append(
"inputFrequencyOffset");
1116 reverseAPIKeys.append(
"rfBandwidth");
1119 reverseAPIKeys.append(
"rfOppBandwidth");
1122 reverseAPIKeys.append(
"atvStd");
1125 reverseAPIKeys.append(
"nbLines");
1128 reverseAPIKeys.append(
"fps");
1131 reverseAPIKeys.append(
"atvModInput");
1134 reverseAPIKeys.append(
"uniformLevel");
1137 reverseAPIKeys.append(
"uniformLevel");
1140 reverseAPIKeys.append(
"atvModulation");
1143 reverseAPIKeys.append(
"videoPlayLoop");
1146 reverseAPIKeys.append(
"videoPlay");
1149 reverseAPIKeys.append(
"cameraPlay");
1152 reverseAPIKeys.append(
"channelMute");
1155 reverseAPIKeys.append(
"invertedVideo");
1158 reverseAPIKeys.append(
"rfScalingFactor");
1161 reverseAPIKeys.append(
"fmExcursion");
1164 reverseAPIKeys.append(
"forceDecimator");
1167 reverseAPIKeys.append(
"showOverlayText");
1170 reverseAPIKeys.append(
"overlayText");
1230 qDebug(
"ATVMod::applySettings: set overlay text");
1233 qDebug(
"ATVMod::applySettings: clear overlay text");
1277 QString& errorMessage)
1279 (void) errorMessage;
1288 const QStringList& channelSettingsKeys,
1290 QString& errorMessage)
1292 (void) errorMessage;
1294 bool frequencyOffsetChanged =
false;
1296 if (channelSettingsKeys.contains(
"inputFrequencyOffset"))
1299 frequencyOffsetChanged =
true;
1301 if (channelSettingsKeys.contains(
"rfBandwidth")) {
1304 if (channelSettingsKeys.contains(
"rfOppBandwidth")) {
1307 if (channelSettingsKeys.contains(
"atvStd")) {
1310 if (channelSettingsKeys.contains(
"nbLines")) {
1313 if (channelSettingsKeys.contains(
"fps")) {
1316 if (channelSettingsKeys.contains(
"atvModInput")) {
1319 if (channelSettingsKeys.contains(
"uniformLevel")) {
1322 if (channelSettingsKeys.contains(
"atvModulation")) {
1325 if (channelSettingsKeys.contains(
"videoPlayLoop")) {
1328 if (channelSettingsKeys.contains(
"videoPlay")) {
1331 if (channelSettingsKeys.contains(
"cameraPlay")) {
1334 if (channelSettingsKeys.contains(
"channelMute")) {
1337 if (channelSettingsKeys.contains(
"invertedVideo")) {
1340 if (channelSettingsKeys.contains(
"rfScalingFactor")) {
1343 if (channelSettingsKeys.contains(
"fmExcursion")) {
1346 if (channelSettingsKeys.contains(
"forceDecimator")) {
1349 if (channelSettingsKeys.contains(
"showOverlayText")) {
1352 if (channelSettingsKeys.contains(
"overlayText")) {
1355 if (channelSettingsKeys.contains(
"rgbColor")) {
1358 if (channelSettingsKeys.contains(
"title")) {
1361 if (channelSettingsKeys.contains(
"useReverseAPI")) {
1364 if (channelSettingsKeys.contains(
"reverseAPIAddress")) {
1367 if (channelSettingsKeys.contains(
"reverseAPIPort")) {
1370 if (channelSettingsKeys.contains(
"reverseAPIDeviceIndex")) {
1373 if (channelSettingsKeys.contains(
"reverseAPIChannelIndex")) {
1376 if (frequencyOffsetChanged)
1392 if (channelSettingsKeys.contains(
"imageFileName"))
1406 if (channelSettingsKeys.contains(
"videoFileName"))
1427 QString& errorMessage)
1429 (void) errorMessage;
1514 if (channelSettingsKeys.contains(
"inputFrequencyOffset") || force) {
1517 if (channelSettingsKeys.contains(
"rfBandwidth") || force) {
1520 if (channelSettingsKeys.contains(
"rfOppBandwidth") || force) {
1523 if (channelSettingsKeys.contains(
"atvStd") || force) {
1526 if (channelSettingsKeys.contains(
"nbLines") || force) {
1529 if (channelSettingsKeys.contains(
"fps") || force) {
1532 if (channelSettingsKeys.contains(
"atvModInput") || force) {
1535 if (channelSettingsKeys.contains(
"uniformLevel") || force) {
1538 if (channelSettingsKeys.contains(
"atvModulation") || force) {
1541 if (channelSettingsKeys.contains(
"videoPlayLoop") || force) {
1544 if (channelSettingsKeys.contains(
"videoPlay") || force) {
1547 if (channelSettingsKeys.contains(
"cameraPlay") || force) {
1550 if (channelSettingsKeys.contains(
"channelMute") || force) {
1553 if (channelSettingsKeys.contains(
"invertedVideo") || force) {
1556 if (channelSettingsKeys.contains(
"rfScalingFactor") || force) {
1559 if (channelSettingsKeys.contains(
"fmExcursion") || force) {
1562 if (channelSettingsKeys.contains(
"forceDecimator") || force) {
1565 if (channelSettingsKeys.contains(
"showOverlayText") || force) {
1568 if (channelSettingsKeys.contains(
"overlayText") || force) {
1571 if (channelSettingsKeys.contains(
"rgbColor") || force) {
1574 if (channelSettingsKeys.contains(
"title") || force) {
1578 QString channelSettingsURL = QString(
"http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
1584 m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader,
"application/json");
1586 QBuffer *buffer=
new QBuffer();
1587 buffer->open((QBuffer::ReadWrite));
1588 buffer->write(swgChannelSettings->
asJson().toUtf8());
1594 delete swgChannelSettings;
1599 QNetworkReply::NetworkError replyError = reply->error();
1603 qWarning() <<
"ATVMod::networkManagerFinished:" 1604 <<
" error(" << (int) replyError
1605 <<
"): " << replyError
1606 <<
": " << reply->errorString();
1610 QString answer = reply->readAll();
1612 qDebug(
"ATVMod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
uint32_t m_pointsPerFP
number of line points for the front porch
void setOriginatorChannelIndex(qint32 originator_channel_index)
float m_videoFPSCount
camera FPS fractional counter
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
float m_videoFPSqManual
camera FPS sacaling factor manually set
static const QString m_channelIdURI
QString * getImageFileName()
uint32_t m_pointsPerLine
Number of points per full line.
float m_rfScalingFactor
Scaling factor from +/-1 to +/-2^15.
void setUseReverseApi(qint32 use_reverse_api)
cv::Mat m_videoFrame
displayable camera frame
void setInvertedVideo(qint32 inverted_video)
float m_videoFPSq
camera FPS sacaling factor
std::vector< ATVCamera > m_cameras
vector of available cameras
bool m_evenImage
in interlaced mode true if this is an even image
Complex nextIQ()
Return next complex sample.
bool decimate(Real *distance, const Complex &next, Complex *result)
ATVMod(DeviceAPI *deviceAPI)
void setCameraPlay(qint32 camera_play)
void push(Message *message, bool emitSignal=true)
Push message onto queue.
static MsgReportCameraData * create(int deviceNumber, float fps, float fpsManual, bool fpsManualEnable, int width, int height, int status)
ATVModulation m_atvModulation
RF modulation type.
Fixed< IntType, IntBits > cos(Fixed< IntType, IntBits > const &x)
uint16_t m_reverseAPIDeviceIndex
int m_pointsPerSync
number of line points for the horizontal sync
void removeChannelSourceAPI(ChannelAPI *channelAPI, int streamIndex=0)
int m_nbLines
number of lines per complete frame
static double dbPower(double magsq, double floor=1e-12)
qint32 getUseReverseApi()
float getRfScalingFactor()
int m_DSBFilterBufferIndex
float m_videoFPS
current video FPS rate
int m_nbLines
Number of lines per full frame.
bool m_videoFPSManualEnable
Enable camera FPS rate manual set value.
qint32 getAtvModulation()
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
void pullFinalize(Complex &ci, Sample &sample)
static MsgReportVideoFileSourceStreamData * create(int frameRate, quint32 recordLength)
int m_cameraIndex
curent camera index in list of available cameras
bool interpolate(Real *distance, const Complex &next, Complex *result)
void setAtvModInput(qint32 atv_mod_input)
uint32_t m_linesPerVBar
number of lines for a bar of the bar chart
float m_videoFy
current video vertictal scaling factor
void setOverlayText(QString *overlay_text)
void setTitle(QString *title)
int getDeviceSetIndex() const
Complex & modulateVestigialSSB(Real &sample)
QByteArray serialize() const
void setChannelSampleRate(qint32 channel_sample_rate)
void setReverseApiAddress(QString *reverse_api_address)
void removeChannelSource(ThreadedBasebandSampleSource *sink, int streamIndex=0)
Remove a channel source (Tx)
void setFmExcursion(float fm_excursion)
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
int m_nbWholeEqLines
number of whole equalizing lines
QString * getVideoFileName()
void setUniformLevel(float uniform_level)
int m_videoLength
current video length in frames
void setVideoPlay(qint32 video_play)
float m_hBarIncrement
video level increment at each horizontal bar increment
int m_videoPrevFPSCount
current video FPS previous integer counter
static const int m_cameraFPSTestNbFrames
number of frames for camera FPS test
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
void setShowOverlayText(qint32 show_overlay_text)
void setForceDecimator(qint32 force_decimator)
static const QString m_channelId
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setVideoFileName(QString *video_file_name)
int m_pointsPerFSync
number of line points for the field first sync
float m_videoFx
camera horizontal scaling factor
void setRfOppBandwidth(float rf_opp_bandwidth)
qint64 getInputFrequencyOffset()
int m_nbSyncLinesHeadO
number of header sync lines on odd frame
void setRfBandwidth(float rf_bandwidth)
int getOutputSampleRate() const
static const int m_ssbFftLen
void setChannelType(QString *channel_type)
void addChannelSource(ThreadedBasebandSampleSource *sink, int streamIndex=0)
Add a channel source (Tx)
qint64 m_inputFrequencyOffset
offset from baseband center frequency
int m_nbSyncLinesBottom
number of sync lines at bottom
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
void openImage(const QString &fileName)
int m_cameraNumber
camera device number
float m_videoFx
current video horizontal scaling factor
std::complex< float > cmplx
void setAtvStd(qint32 atv_std)
void setNbLines(qint32 nb_lines)
int m_nbHorizPoints
number of line points per horizontal line
static const int m_nbBars
number of bars in bar or chessboard patterns
void applySettings(const ATVModSettings &settings, bool force=false)
virtual QByteArray serialize() const
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
float m_modPhasor
For FM modulation.
bool m_channelMute
Mute channel baseband output.
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples)
QNetworkAccessManager * m_networkManager
bool m_forceDecimator
Forces decimator even when channel and source sample rates are equal.
void calculateCamerasSizes()
void openVideo(const QString &fileName)
virtual void pullAudio(int nbSamples)
UpChannelizer * m_channelizer
void setImageFileName(QString *image_file_name)
int m_videoHeight
camera frame height
ThreadedBasebandSampleSource * m_threadedChannelizer
uint32_t m_nbImageLines2
same number as above (non interlaced) or half the number above (interlaced)
void setAtvModReport(SWGATVModReport *atv_mod_report)
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
void setVideoPlayLoop(qint32 video_play_loop)
void create_filter(float f1, float f2)
static MsgReportVideoFileSourceStreamTiming * create(int frameCount)
float m_videoFy
camera vertictal scaling factor
cv::Mat m_imageOriginal
original not resized image
void pullVSyncLine(Real &sample)
Complex * m_SSBFilterBuffer
cv::VideoCapture m_video
current video capture
float m_videoFPS
camera FPS rate
float m_vBarIncrement
video level increment at each vertical bar increment
QNetworkRequest m_networkRequest
void getCameraNumbers(std::vector< int > &numbers)
int m_videoHeight
current video frame height
void pullImageLine(Real &sample, bool noHSync=false)
int m_fps
Number of frames per second.
uint16_t m_reverseAPIChannelIndex
ATVModSettings m_settings
qint32 getReverseApiChannelIndex()
uint32_t m_pointsPerHBar
number of line points for a bar of the bar chart
Fixed< IntType, IntBits > sin(Fixed< IntType, IntBits > const &x)
SWGATVModSettings * getAtvModSettings()
void setRgbColor(qint32 rgb_color)
qint32 getInvertedVideo()
QString m_reverseAPIAddress
static bool match(const Message *message)
int m_SSBFilterBufferIndex
int m_nbHalfLongSync
number of half long sync / equalization lines
int m_tvSampleRate
sample rate for generating signal
void setFreq(Real freq, Real sampleRate)
static float getRFBandwidthDivisor(ATVModSettings::ATVModulation modulation)
Real m_interpolatorDistanceRemain
int m_videoPrevFPSCount
camera FPS previous integer counter
MovingAverageUtil< double, double, 16 > m_movingAverage
cv::Mat m_videoFrame
current displayable video frame
void setInputFrequencyOffset(qint64 input_frequency_offset)
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
cv::Mat m_imageFromFile
original image not resized not overlaid by text
float m_fmExcursion
FM excursion factor relative to full bandwidth.
bool m_showOverlayText
Show overlay text on image.
bool m_invertedVideo
True if video signal is inverted before modulation.
Fixed< IntType, IntBits > sqrt(Fixed< IntType, IntBits > const &x)
void networkManagerFinished(QNetworkReply *reply)
void setDirection(qint32 direction)
void setChannelMute(qint32 channel_mute)
cv::Mat m_videoframeOriginal
camera non resized image
Real m_interpolatorDistance
virtual QString asJson() override
void setAtvModulation(qint32 atv_modulation)
ATVModInput m_atvModInput
Input source type.
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
cv::Mat m_videoframeOriginal
current frame from video
int m_pointsPerImgLine
number of line points for the image line
float m_videoFPSCount
current video FPS fractional counter
int m_nbBlankLines
number of lines in a frame (full or half) that are blanked (black) at the top of the image ...
static const int m_levelNbSamples
cv::VideoCapture m_camera
camera object
bool m_videoEOF
current video has reached end of file
int m_videoWidth
current video frame width
bool m_videoPlay
True to play video and false to pause.
qint64 getFrequencyOffset() const
Interpolator m_interpolator
SWGATVModReport * getAtvModReport()
qint32 getVideoPlayLoop()
uint32_t m_nbImageLines
number of image lines excluding synchronization lines
bool m_cameraPlay
True to play camera video and false to pause.
MessageQueue * getMessageQueueToGUI()
bool m_interleaved
true if image is interlaced (2 half frames per frame)
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
Real m_uniformLevel
Percentage between black and white for uniform screen display.
static MsgReportEffectiveSampleRate * create(int sampleRate, uint32_t nbPointsPerLine)
float getRfOppBandwidth()
void setRfScalingFactor(float rf_scaling_factor)
int m_horizontalCount
current point index on line
float m_videoFPSManual
camera FPS rate manually set
int runSSB(const cmplx &in, cmplx **out, bool usb, bool getDC=true)
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const ATVModSettings &settings, bool force)
virtual bool deserialize(const QByteArray &data)
void calculateVideoSizes()
Complex & modulateSSB(Real &sample)
virtual void pull(Sample &sample)
float m_blankLineLvel
video level of blank lines
cv::Mat m_image
resized image for transmission at given rate
int m_videoWidth
camera frame width
void setAtvModSettings(SWGATVModSettings *atv_mod_settings)
int getSampleRate() const
static void getBaseValues(int outputSampleRate, int linesPerSecond, int &sampleRateUnits, uint32_t &nbPointsPerRateUnit)
QString * getReverseApiAddress()
void create_asym_filter(float fopp, float fin)
two different filters for in band and opposite band
Real m_rfBandwidth
Bandwidth of modulated signal or direct sideband for SSB / vestigial SSB.
float m_fps
resulting frames per second
static const float m_spanLevel
void addChannelSourceAPI(ChannelAPI *channelAPI, int streamIndex=0)
bool m_singleLongSync
single or double long sync per long sync line
int m_lineCount
current line index in frame
qint32 getForceDecimator()
int m_pointsPerBP
number of line points for the back porch
int getIndexInDeviceSet() const
std::complex< Real > Complex
void setReverseApiPort(qint32 reverse_api_port)
uint16_t m_reverseAPIPort
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
int m_nbSyncLinesHeadE
number of header sync lines on even frame
Real m_rfOppBandwidth
Bandwidth of opposite sideband for vestigial SSB.
void applyChannelSettings(int outputSampleRate, int inputFrequencyOffset, bool force=false)
QString * getOverlayText()
void seekVideoFileStream(int seekPercentage)
void pullVideo(Real &sample)
void mixImageAndText(cv::Mat &image)
bool deserialize(const QByteArray &data)
qint32 getReverseApiDeviceIndex()
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const ATVModSettings &settings)
T max(const T &x, const T &y)
qint32 getShowOverlayText()
static const float m_blackLevel
float m_videoFPSq
current video FPS sacaling factor
void setChannelPowerDb(float channel_power_db)
qint32 getReverseApiPort()
bool m_videoPlayLoop
Play video in a loop.
int m_inputFrequencyOffset
int m_nbLines2
same number as above (non interlaced) or half the number above (interlaced)
int runAsym(const cmplx &in, cmplx **out, bool usb)
Asymmetrical fitering can be used for vestigial sideband.
Complex * m_DSBFilterBuffer
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
int m_nbLongSyncLines
number of whole long sync lines for vertical synchronization
void calculateLevel(Real &sample)