first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

View File

@@ -0,0 +1,383 @@
#ifndef RM_PLAYER_H
#define RM_PLAYER_H
#include <QObject>
#include <qslider.h>
#include <QElapsedTimer>
#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<QString>* _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<QString>* list);
void swapChanged(bool swap);
#if (H265_SUPPORT)
void show_indicator(bool show);
#endif
void cancelFullScreen();
void userStop();
};
#endif // RM_PLAYER_H