#ifndef DRONESCREWCTRL_PRESENTER_H #define DRONESCREWCTRL_PRESENTER_H #include #include #include #include #include #include #include #include #include "IVrConfig.h" #include "IYDroneScrewCtrlStatus.h" #include "IVrFFMediaPuller.h" #include "IWDRemoteReceiver.h" /** * @brief 板二 Presenter * * 远程访问已经收敛到 WDRemoteReceiver 动态库中: * - REQ-REP 控制 * - PUB-SUB 检测结果 * - PUB-SUB 原始图像(可选) * * Presenter 只关心: * - 通过 IVrFFMediaPuller 拉取板一 RTSP 视频流 * - 通过 IWDRemoteReceiver 完成所有控制与订阅 * - 把拉流帧 + 检测结果合并送给 IYDroneScrewCtrlStatus 显示 */ class DroneScrewCtrlPresenter : public QObject { Q_OBJECT public: explicit DroneScrewCtrlPresenter(QObject* parent = nullptr); ~DroneScrewCtrlPresenter() override; void SetStatusReceiver(IYDroneScrewCtrlStatus* receiver) { m_pReceiver = receiver; } void ApplyConfig(const DroneScrewCtrlConfigResult& cfg); void UpdateDisplayOptions(const DroneScrewDisplayOption& options); int InitApp(); void DeinitApp(); bool TriggerSingleDetection(); bool StartLiveStream(); bool StopLiveStream(); bool StartDetection(); bool StopDetection(); bool StopAll(); // 同时停止实时推流与检测(主开关停止用) bool SetServerExposure(double exposureTime); bool SetServerGain(double gain); bool PushAlgoParams(const DroneScrewAlgoUiParams& params); bool QueryServerInfo(WDRemoteServerInfo& info, int timeoutMs = 3000); QImage GetLastDisplayImage() const; signals: void displayFrameReady(const QImage& img, const QSize& sourceSize, qint64 frameId, bool rtspFrame, const CtrlDetectionFrame& result, bool hasResult); void detectionResultReady(const CtrlDetectionFrame& result); void serverConnectionChanged(bool connected); void statusMessage(const QString& msg); void serverInfoReceived(const WDRemoteServerInfo& info); // 服务器参数更新 private slots: void onReconnectTimer(); void onOverlayFrameReady(const QImage& img, const QSize& sourceSize, qint64 frameId, bool rtspFrame, const CtrlDetectionFrame& result, bool hasResult); void onResultReceived(const CtrlDetectionFrame& result); private: // RTSP 拉流回调 void onRtspFrame(const VrFFPulledFrame& frame); bool initPuller(const QString& streamUrl, bool quiet = false); bool startPullerOnce(const QString& streamUrl, bool quiet = false); bool waitForRtspFirstFrame(int timeoutMs); bool startPullerWithRetry(const QString& streamUrl); void releasePuller(); QString resolveStreamUrl(const QString& streamUrl) const; void updateStreamInfo(const WDRemoteServerInfo& info); // WDRemoteReceiver 回调 void onRemoteDetection(const WDRemoteDetectionFrame& frame); void onRemoteRawImage (const WDRemoteBinocularRawImage& img); // 检测模式下的图像(ZMQ 原始图通道) void onRemoteEvent (WDRemoteEventType ev, const std::string& msg); void overlayDetectionBoxes(QImage& img, const CtrlDetectionFrame& frame, const QSize& sourceSize); void clearCachedDisplayState(); void prunePendingMatchesLocked(); static CtrlDetectionFrame toCtrlFrame(const WDRemoteDetectionFrame& f); private: struct DisplayFrame { QImage image; QSize sourceSize; }; struct PendingRawFrame { DisplayFrame frame; qint64 receivedAtMs{0}; }; struct PendingDetectionResult { CtrlDetectionFrame result; qint64 receivedAtMs{0}; }; DroneScrewCtrlConfigResult m_cfg; IVrFFMediaPuller* m_pPuller{nullptr}; IWDRemoteReceiver* m_pRemote{nullptr}; QString m_streamUrl; IYDroneScrewCtrlStatus* m_pReceiver{nullptr}; std::atomic m_bConnected{false}; std::atomic m_bRunning{false}; std::atomic m_liveStreamMode{false}; std::atomic m_rtspReceiving{false}; std::atomic m_rtspFirstFrameReported{false}; QTimer* m_pReconnectTimer{nullptr}; // 最近检测结果(用于叠加显示) mutable QMutex m_lastResultMutex; CtrlDetectionFrame m_lastResult; bool m_bHasResult{false}; // 最近显示帧 mutable QMutex m_lastImgMutex; QImage m_lastSourceImage; qint64 m_lastSourceFrameId{-1}; bool m_lastSourceIsRtsp{false}; QImage m_lastDisplay; std::map m_pendingRawFrames; std::map m_pendingDetectionResults; }; #endif // DRONESCREWCTRL_PRESENTER_H