#ifndef RM_PLAYER_H #define RM_PLAYER_H #include #include #include #include "rm_constants.h" #include "rm_include.h" #include "rm_player_base.h" #include "rm_player_zoom.h" #define DEBUG_RM_PLAYER 0 #define USE_RM_D2_PLAYER 0 #define CAPTURE_DEBUG 0 class RMVideoItem; class RMFrameSlider; #if (MODEL_BBVIEWER) class RMEQWidget; #endif #define DEBUG_HIGH_SPEED_STOP 0 #define REMOVE_CLOCK_UPDATE_WHEN_SEEKING 1 #define STEP_SEEK_DURATION 34 //extern const int g_PlaySpeed1XIndex; #if (MODEL_BBVIEWER) #define PLAY_SPEED_COUNT 5 #elif (RM_MODEL == RM_MODEL_TYPE_TB4000 || RM_MODEL_EMT_KR) #define PLAY_SPEED_COUNT 5 #else #define PLAY_SPEED_COUNT 4 #endif extern float g_PlaySpeedList[PLAY_SPEED_COUNT]; extern int DEFAULT_SPEED_INDEX; class RMPlayer : public RMPlayerZoom { Q_OBJECT public: static RMPlayer* instance() { static RMPlayer * _instance = 0; if ( _instance == NULL ) { _instance = new RMPlayer(); } return _instance; } //#if (USE_LIBRARY_MODE) // 360 DLL // static RMPlayer* libraryInstance; //#endif // #if !(SINGLE_CH_VIEWER) // 는 _isSwapped() 와는 별도로 사용자 swap 상태만 확인하기 위해 사용 bool isSwapped() { return _swaped; } #endif void stop() override; QString currentTimeString(double* lat, double* lon); #if (PENTA_CHANNEL) void changeCHMode(RMApp::ChannelMode mode) override; #endif void updateSpeedForce(qreal speed) { _speedValue = speed; updateSpeed(_speedValue); } #if !(RM_MODEL == RM_MODEL_TYPE_TB4000) void setMuteButton(FMButton* btn) { _muteButton = btn; } #endif // #if !(RM_MODEL == RM_MODEL_TYPE_TB4000) void setSlider(QSlider* slider) { _slider = slider; // PRESSED -> MOVED -> RELEASED 순서대로 호출 되도록 이벤트 처리해야함 // 노브가 아닌 지점 CLICK 시에는 Slider는 (Slider)PRESSED 이벤트 만 호출됨 (RMSlider 내부에서 구현) // PRESSED 이벤트 발생시 KNOB 가 false 일 경우 released 이벤트 발생하지 않으니 별도의 처리 하지 말아야함 connect(_slider, SIGNAL(sliderPressedWithKnob(bool)),SLOT(onSliderPress(bool))); // 이벤트 두번씩 발생함 connect(_slider, SIGNAL(sliderMoved(int)),SLOT(onSliderMove(int))); // 슬라이더 컨트롤 connect(_slider, SIGNAL(mouseReleased()),SLOT(onSliderRelease())); } #if !(RM_MODEL == RM_MODEL_TYPE_TB4000) void setVolumeSlider(QSlider* slider) { _volumeSlider = slider; connect(_volumeSlider, SIGNAL(sliderPressed()), SLOT(onSetVolume())); connect(_volumeSlider, SIGNAL(valueChanged(int)), SLOT(onSetVolume())); onSetVolume(); } #endif // RM_MODEL_TYPE_TB4000 void setSpeedSlider(QSlider* slider, QLabel* label) { _speedLabel = label; connect(slider, SIGNAL(mouseReleased()),SLOT(onSpeedSliderReleased())); connect(slider, SIGNAL(sliderMoved(int)),SLOT(onSpeedSliderMoved(int))); } private: // SLIDER 이동중에는 강제 PAUSE bool _pauseWhileSeek; QTimer* _captureTimer; QTimer* _captureWatcher; //#if (SEEK_BY_SLIDER) // QTimer* _seekPositionTimer; // void startSeekTimer(); //#endif #if (USE_RM_KEYBOARD_EVENT) int _seekAcceleration; // 가속 QTimer* _seekPressedTimer; // Slider 이동 타이머 QTimer* _seekReleasedTimer; // Seek Update 타이머 QTimer* _seekUpdateTimer; // Pressed 중간 Seek Update 타이머 void startSeekUpdateTimer(); void stopSeekUpdateTimer() override; bool isSeekProcessing() override { return (_seekPressedTimer != NULL || _seekReleasedTimer != NULL || _seekUpdateTimer != NULL); } //#else // QElapsedTimer _stepTimer; #endif protected: virtual void timerEvent(QTimerEvent *e); public: explicit RMPlayer(QObject *parent = 0); RMVideoItem* getCurrentItem() { return _currentItem; } QDateTime currentTime(double* lon = NULL,double* lat = NULL); VIDEO_MODE videoMode() { return _videoMode; } FAV::AVPlayer* playerF() { return _playerF; } QWidget* playWidgetF() { return _videoOutputF->widget(); } #if ((!SINGLE_CH_VIEWER && !TOGGLE_PLAYER) || DUAL_VIEWER || DUAL_VIDEO_WIDGET) QWidget* playWidgetR() { return _videoOutputR->widget(); } #endif #if !(SINGLE_CH_VIEWER) FAV::AVPlayer* playerR() { return _playerR; } #endif // #if !(SINGLE_CH_VIEWER) #if (RM_MODEL_360) // SWAP 되더라도 메인 Renderer 는 항상 _videoOutputF 임 FAV::VideoRenderer* mainRenderer() { return _videoOutputF; } FAV::VideoRenderer* renderer360() { #if (SINGLE_CH_VIEWER) return _videoOutputF; #else // SINGLE_CH_VIEWER return _swaped ? _videoOutputR : _videoOutputF; #endif // SINGLE_CH_VIEWER } #endif // RM_MODEL_360 //void setSliderFrame(RMFrameSlider* frame); // 슬라이더 설정 #if (MODEL_BBVIEWER) void setEQFrame(RMEQWidget* eq); #endif // 비디오 캡쳐 요청 bool requestVideoCapture(); qreal speedValue() { return _speedValue; } #if (SUPPORT_WIDE_MODE) /** * @brief 현재 재생중인 영상이 WIDE 모드 지원 영상일 경우 * @return */ bool itemIsWideMode(); /** * @brief 현재 재생중인 모드가 WIDE 모드일 경우 * @return */ bool isWideMode(); #endif // SUPPORT_WIDE_MODE #if (RM_TESTING) FAV::LibAVFilterVideo* _testFilterF; void applyTestFilter(QString filter); #endif qint64 titleSeconds; // 슬라이더에 표시된 시간 (Capture 등에서 동기화 처리위해 사용) public slots: void requestVideoCaptureProcess(); // Slider Control void onSliderPress(bool bKnob); void onSliderMove(int value); void onSliderRelease(); //void onPlotMove(qreal ratio); // 사용자 정지 void onUserStop(); #if (USE_RM_KEYBOARD_EVENT) void onSeekForwardStart(); void onSeekBackwardStart(); void onSeekFrameForwardStart(); #if (PLAY_SYNC_FIX2) void onSeekFrameBackwardStart(); #endif // PLAY_SYNC_FIX2 void onSeekStepEnd(); #endif #if (PLAYER_ONLY_LIBRARY_MODE) void clear(); void create(); #endif // PLAYER_ONLY_LIBRARY_MODE bool prepareForCapture(); void onCaptureSavedFront(const QString& path); #if !(SINGLE_CH_VIEWER) void onCaptureSavedRear(const QString& path); void toggleSwap(bool forceEmit = false); #endif #if (TRI_CHANNEL || TRI_CHANNEL2) void toggleIndoor(bool forceEmit = false); // 후방 <-> 실내 #endif #if (SUPPORT_WIDE_MODE) void toggleWide(); // NORMAL <-> WIDE #endif // SUPPORT_WIDE_MODE void onSpeedSliderMoved(int position); void onSpeedSliderReleased(); private: // 재생시간이 AVI:60260 VIDEO(Audio):59281 일 경우 // 현재 POSITION + step 을 // 실제 재생시간을 N 분할 하여 사용자가 보기 적합한 간격으로 표시함 // eg 988.0166667 msec 씩 이동할 경우 #if (USE_RM_KEYBOARD_EVENT) quint64 _stepPosition(); //#else // quint64 _stepPosition(int step=1); // +1,-1 #endif bool _isLastStep(); // 이벤트 블럭처리함 void blockEvents(int msec,bool b_show_indicator = false); // pause 된 상태에서도 positionChanged 가 계속호출되어 방지용 // int timeToSliderValue(qint64 time); qint64 ratioToSliderValue(qreal ratio); QString _captureDir; QList* _captureFileList; // 통합관리 + 화면갱신을 위한 seek 구분 void seek(qint64 pos,bool refresh) override; // 정지된 상태에서 SEEK 를 통해 화면 갱신 void updatePausedScreen(); void seekFrontOnly(qint64 pos,bool refresh); #if !(SINGLE_CH_VIEWER) void seekRearOnly(qint64 pos,bool refresh); #endif // 후방만 갱신 #if (!(SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL) void updatePausedScreenRearOnly(); #endif void updatePausedScreenFrontOnly(); void clearCaptureTimer(); void clearCaptureWatcher(); //void clearSliderReleaseTimer(); // Rear 는 V+H Flip 모두 지원 void updateRearFlip(); #if (RM_MODEL == RM_MODEL_TYPE_TELEBIT) void updateFrontFlip(); #endif // 메인 clock 과 각 player 의 clock 동기화 void clear_seek_timer(); void sync_clock(); private slots: #if (USE_RM_KEYBOARD_EVENT) void onSeekUpdate(); // 업데이트 후 타이머 제거하지 않음 void onSeekLastUpdate(); // 업데이트 후 타이머 제거 void onSeekPressed(); #endif #if (CAPTURE_DEBUG) void onSeekCapture(); void onImageCaptured(const QImage& image); void onCaptureFailed(); #endif //#if !(FORCE_SINGLE_PLAYER) // 이벤트 블럭 해제 (전후방 swap 중에 별도 이벤트 받지 못하도록 처리) void onReleaseBlockEvent(); //#endif // 캡쳐 대기 완료 void onReadyForCapture(); // 캡쳐 실패 void onFailToCapture(); #if (PENTA_CHANNEL) void onUpdateCHMode() override; #endif // PENTA_CHANNEL // 동기화 시작 타이머 void on_sync_timer_restarted(); // 처음으로 이동 void onPlayRestart(); //---------------------------------------------------------------------------------------------- signals: void videoCaptureDone(QList* list); void swapChanged(bool swap); #if (H265_SUPPORT) void show_indicator(bool show); #endif void cancelFullScreen(); void userStop(); }; #endif // RM_PLAYER_H