1787 lines
52 KiB
C++
1787 lines
52 KiB
C++
#include "rm_player.h"
|
|
#include <QApplication>
|
|
#include <QMessageBox>
|
|
#include <QFileDialog>
|
|
#include <QThread>
|
|
#include <QTimer>
|
|
|
|
#include "../rm_include.h"
|
|
#include "../rm_app.h"
|
|
#include "../data/rm_video_item_2ch.h"
|
|
#include "../ui/rm_button.h"
|
|
#include "../ui/rm_slider.h"
|
|
//#include "../ui/rm_frame_slider.h"
|
|
#include "../ui/rm_play_slider.h"
|
|
#include "rm_key_event.h"
|
|
#include "fav/fav_common.h"
|
|
|
|
// 연속해서 press + release 문제 발생시 수정
|
|
#define FIX_PRESS_AND_RELEASE 1
|
|
|
|
#if (RM_MODEL_360 || SUPPORT_WIDE_MODE)
|
|
#include "../fav/OpenGLVideo.h"
|
|
#include "../fav/OpenGLRendererBase.h"
|
|
#endif
|
|
|
|
#if (MODEL_BBVIEWER)
|
|
#include "../ui/rm_eq_widget.h"
|
|
#endif // MODEL_BBVIEWER
|
|
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
QString g_errorMessage;
|
|
#endif
|
|
|
|
|
|
// 플레이 마지막에 AVDemux 가 종료된 시점에서 seek 하면 문제가 발생함.
|
|
// 실제 300~400ms 사이에서 발생함..
|
|
#define LAST_PLAY_SEEK_TEST 0
|
|
#define USE_LAST_PLAY_SEEK 1 // 플레이 종료 시점에서 전방으로 이동시 발생하는 문제 제거
|
|
|
|
#define LAST_PLAY_SEEK_LIMIT 500 // 100 으로 처리하면 step 이동시 종료되어 다음 파일로 넘어감
|
|
//const int kSyncInterval = 500;
|
|
//const qreal kVolumeInterval = 0.1;
|
|
//const int kMuteInterval = 10;//100;
|
|
|
|
//const qint64 gPausePosition = 1; // ???
|
|
|
|
// RMPlayer* RMPlayer::_instance = NULL;
|
|
|
|
#if (MODEL_BBVIEWER)
|
|
float g_PlaySpeedList[PLAY_SPEED_COUNT] = {0.3f,0.5f,1.0f,2.0f,3.0f};
|
|
//QList<QString> g_PlaySpeedNames = QList<QString>() << "0.5" << "1.0" << "2.0" << "4.0";
|
|
#elif (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || \
|
|
RM_MODEL == RM_MODEL_TYPE_MBJ5010 || \
|
|
RM_MODEL == RM_MODEL_TYPE_FC_DR232W)
|
|
float g_PlaySpeedList[PLAY_SPEED_COUNT] = {0.5f, 0.8f, 1.0f,2.0f};
|
|
int DEFAULT_SPEED_INDEX = 2;
|
|
QList<QString> g_PlaySpeedNames = QList<QString>() << "0.5 x" << "0.8 x" << "1 x" << "2.0 x";
|
|
#elif (RM_MODEL == RM_MODEL_TYPE_AN6000)
|
|
float g_PlaySpeedList[PLAY_SPEED_COUNT] = {1.0f, 2.0f,4.0f,16.0f};
|
|
QList<QString> g_PlaySpeedNames = QList<QString>() << "1x" << "2x" << "4x" << "16x";
|
|
int DEFAULT_SPEED_INDEX = 0;
|
|
#elif (RM_MODEL == RM_MODEL_TYPE_TB4000)
|
|
float g_PlaySpeedList[PLAY_SPEED_COUNT] = {0.5f, 1.0f, 2.0f,4.0f,8.0f};
|
|
QList<QString> g_PlaySpeedNames = QList<QString>() << "0.5 x" << "1 x" << "2 x" << "4 x" << "8 x";
|
|
int DEFAULT_SPEED_INDEX = 1;
|
|
#elif (RM_MODEL_EMT_KR)
|
|
float g_PlaySpeedList[PLAY_SPEED_COUNT] = {0.25f,0.5f, 1.0f, 2.0f,4.0f};
|
|
QList<QString> g_PlaySpeedNames = QList<QString>() << FM_WSTR(L"¼ x") << FM_WSTR(L"½ x") << "1 x" << "2 x" << "4 x";
|
|
int DEFAULT_SPEED_INDEX = 2;
|
|
#else // @OTHER
|
|
float g_PlaySpeedList[PLAY_SPEED_COUNT] = {0.5f, 1.0f, 2.0f,8.0f};
|
|
QList<QString> g_PlaySpeedNames = QList<QString>() << "0.5 x" << "1 x" << "2 x" << "8 x";
|
|
int DEFAULT_SPEED_INDEX = 1;
|
|
#endif
|
|
|
|
//const int g_PlaySpeed1XIndex = 1;
|
|
//#if (USE_LIBRARY_MODE) // 360 DLL
|
|
//RMPlayer* RMPlayer::libraryInstance = NULL;
|
|
//#endif //
|
|
|
|
RMPlayer::RMPlayer(QObject *parent) : RMPlayerZoom(parent)
|
|
{
|
|
|
|
_sync_time = false; // seek sync timer <- sub
|
|
_sync_restart_timer = NULL; // " <- sub
|
|
|
|
_stepping = false; // seek <- sub
|
|
|
|
// _sliderReleaseTimer = NULL; // seek <- sub
|
|
_refreshSeeking = false; // seek <- sub
|
|
|
|
_captureFileList = NULL; // capture <- sub
|
|
_captureTimer = NULL; // capture <- sub
|
|
_captureWatcher = NULL; // "
|
|
|
|
_pauseWhileSeek = false;
|
|
|
|
|
|
#if (USE_RM_KEYBOARD_EVENT)
|
|
_seekAcceleration = 1;
|
|
_seekPressedTimer = NULL;
|
|
_seekReleasedTimer = NULL;
|
|
_seekUpdateTimer = NULL;
|
|
#endif
|
|
|
|
#if (RM_TESTING)
|
|
_testFilterF = NULL;
|
|
#endif
|
|
|
|
// 슬라이더 업데이트
|
|
//qInfo() << _playerF << __FUNCTION__;
|
|
connect(_playerF, SIGNAL(started()), SLOT(updateSlider()));
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
void RMPlayer::onUserStop()
|
|
{
|
|
#if (PLAY_SEEK_FILE_MOVE)
|
|
// 사용자 STOP 요청시 step 모드 종료됨
|
|
endStepMode();
|
|
#endif
|
|
// 다음 파일로 넘어갈때는 호출하면 안됨 ???
|
|
#if (PLAY_CONTINUE_EVENT)
|
|
stop();
|
|
emit playEvent(PLAY_DID_USER_STOP,NULL);
|
|
#else
|
|
emit playEvent(PLAY_DID_USER_STOP,NULL);
|
|
stop();
|
|
#endif
|
|
|
|
// User Stop 시에는 잔상 남지 않도록 Clear
|
|
/*
|
|
int count = 0;
|
|
while(count++ < 100 &&
|
|
(_playerF->isPlaying() ||
|
|
(_playerR->isLoaded() && _playerR->isPlaying())))
|
|
{
|
|
QThread::msleep(10);
|
|
}
|
|
FAV::VideoFrame frame;
|
|
if(_videoOutputF != NULL)
|
|
{
|
|
_videoOutputF->receive(frame);
|
|
}
|
|
if(_videoOutputR != NULL)
|
|
{
|
|
_videoOutputR->receive(frame);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void RMPlayer::stop()
|
|
{
|
|
RMPlayerBase::stop();
|
|
stopSeekUpdateTimer();
|
|
}
|
|
#if (PLAYER_ONLY_LIBRARY_MODE)
|
|
void RMPlayer::clear()
|
|
{
|
|
if(_playerF != NULL) {
|
|
_playerF->stop();
|
|
delete _playerF;
|
|
_playerF = NULL;
|
|
}
|
|
}
|
|
void RMPlayer::create()
|
|
{
|
|
if(_playerF == NULL) {
|
|
_createVideoPlayers();
|
|
}
|
|
}
|
|
#endif // PLAYER_ONLY_LIBRARY_MODE
|
|
|
|
void RMPlayer::updatePausedScreen()
|
|
{
|
|
_pausePosition = MAX(_pausePosition,INITIAL_VIDEO_POSITION);
|
|
// 비동기화 seek 가 발생하면 업데이트가 일어남
|
|
if(_playerF->isPaused())
|
|
{
|
|
seek(_pausePosition,true);
|
|
}
|
|
}
|
|
void RMPlayer::updatePausedScreenFrontOnly()
|
|
{
|
|
if(_playerF == NULL) {
|
|
return;
|
|
}
|
|
_pausePosition = MAX(_pausePosition,INITIAL_VIDEO_POSITION);
|
|
|
|
// 비동기화 seek 가 발생하면 업데이트가 일어남
|
|
if(_playerF->isPaused())
|
|
{
|
|
seekFrontOnly(_pausePosition,true);
|
|
}
|
|
}
|
|
#if (!(SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL)
|
|
void RMPlayer::updatePausedScreenRearOnly()
|
|
{
|
|
if(_playerR == NULL) {
|
|
return;
|
|
}
|
|
_pausePosition = MAX(_pausePosition,INITIAL_VIDEO_POSITION);
|
|
|
|
// 비동기화 seek 가 발생하면 업데이트가 일어남
|
|
if(_playerR->isPaused())
|
|
{
|
|
seekRearOnly(_pausePosition,true);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Slider 컨트롤
|
|
/*
|
|
void RMPlayer::setSliderFrame(RMFrameSlider* frame)
|
|
{
|
|
//(QSlider*)
|
|
_slider = frame->playSlider->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()));
|
|
|
|
// 슬라이더 업데이트
|
|
connect(_playerF, SIGNAL(started()), SLOT(updateSlider()));
|
|
|
|
// _volumeSlider = frame->volumeSlider;
|
|
// connect(_volumeSlider, SIGNAL(sliderPressed()), SLOT(onSetVolume()));
|
|
// connect(_volumeSlider, SIGNAL(valueChanged(int)), SLOT(onSetVolume()));
|
|
// onSetVolume();
|
|
|
|
// connect(frame->speedSlider, SIGNAL(mouseReleased()),SLOT(onSpeedSliderReleased()));
|
|
// connect(frame->speedSlider, SIGNAL(sliderMoved(int)),SLOT(onSpeedSliderMoved(int)));
|
|
|
|
// 참조용
|
|
_muteButton = frame->muteButton;
|
|
|
|
}
|
|
*/
|
|
#if (MODEL_BBVIEWER)
|
|
void RMPlayer::setEQFrame(RMEQWidget* eq)
|
|
{
|
|
connect(eq->speedSlider, SIGNAL(mouseReleased()),SLOT(onSpeedSliderReleased()));
|
|
connect(eq->speedSlider, SIGNAL(sliderMoved(int)),SLOT(onSpeedSliderMoved(int)));
|
|
}
|
|
#endif
|
|
// ------------------------------------------------------------------------------------------------
|
|
// 캡쳐 기능
|
|
|
|
|
|
QString RMPlayer::currentTimeString(double* lat, double* lon)
|
|
{
|
|
qreal ratio = (qreal)_playerF->position() / (qreal)_playerF->duration();
|
|
QDateTime dateTime = _currentItem->dateTimeInPosition(ratio, lat, lon);
|
|
if(dateTime.isValid())
|
|
{
|
|
// range->setProperty("Value",FM_WSTR(L"20XX년 XX월 XX일 XX시 XX분"));
|
|
QString dateFormatString = "yyyy" + FM_WSTR(L"년") + " MM" + FM_WSTR(L"월") + " dd" + FM_WSTR(L"일");
|
|
QString date = dateTime.toString(dateFormatString);
|
|
QString timeFormatString = "HH" + FM_WSTR(L"시") + " mm" + FM_WSTR(L"분");
|
|
QString time = dateTime.toString(timeFormatString);
|
|
return date + " " + time;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
// 0. 캡쳐 요청
|
|
bool RMPlayer::requestVideoCapture()
|
|
{
|
|
bool readyForCapture = (_playerF->isPaused() == true); // 현재 정지된 상태인지 확인
|
|
|
|
if(_captureWatcher != NULL || prepareForCapture() == false) // 준비 (정지, 전체화면 취소, 확대 취소)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage = "0-1.Prepare for capture.\n";
|
|
#endif
|
|
|
|
// 혹시 capture 가 성공하지 못했을 경우 2초후 확인
|
|
clearCaptureWatcher();
|
|
_captureWatcher = new QTimer(this);
|
|
_captureWatcher->setSingleShot(true);
|
|
_captureWatcher->setInterval(2000);
|
|
connect(_captureWatcher,SIGNAL(timeout()),SLOT(onFailToCapture()));
|
|
_captureWatcher->start();
|
|
|
|
QApplication::setOverrideCursor(Qt::WaitCursor); // 커서 변경
|
|
if(readyForCapture == true) // 현재 준비 완료 상태이면 0.1초후 캡쳐 시작
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "0-2.Ready for capture.\n";
|
|
qInfo() << "0-2.Ready for capture.";
|
|
#endif
|
|
QTimer::singleShot(100, this, SLOT(requestVideoCaptureProcess()));
|
|
}
|
|
else // 준비가 완료되지 않은 상태이면 준비확인
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "0-2.Not ready for capture\n";;
|
|
qInfo() << "0-2.Not ready for capture";
|
|
#endif
|
|
clearCaptureTimer();
|
|
|
|
_captureTimer = new QTimer(this);
|
|
_captureTimer->setSingleShot(false);
|
|
_captureTimer->setInterval(500);
|
|
connect(_captureTimer,SIGNAL(timeout()),SLOT(onReadyForCapture()));
|
|
_captureTimer->start();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// 1. 캡쳐 준비 (다른 용도로도 사용될 수 있음)
|
|
bool RMPlayer::prepareForCapture()
|
|
{
|
|
if(_playerF != NULL) {
|
|
if(_playerF->isLoaded() == false || _playerF->position() < INITIAL_VIDEO_POSITION)
|
|
{
|
|
return false;
|
|
}
|
|
if(_playerF->isPaused() == false)
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "0-0.Try to pause\n";;
|
|
qInfo() << "0-0.Try to pause";
|
|
#endif
|
|
playOrPause(false);
|
|
}
|
|
}
|
|
emit cancelFullScreen();
|
|
return true;
|
|
}
|
|
|
|
// 0-1 캡쳐가 준비되지 않은 상태이면 전/후방 정지까지 대기
|
|
void RMPlayer::onReadyForCapture()
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "0-1.Check ready for capture.\n";
|
|
qInfo() << "0-1.Check ready for capture.";
|
|
#endif
|
|
|
|
#if (FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER) // 통합해야함..
|
|
if(_playerF->isPaused() == true)
|
|
#else
|
|
if(_playerF->isPaused() == true &&
|
|
(_playerR == NULL || (_playerR->isLoaded() == false || _playerR->isPaused() == true))) // 존재하지 않거나, 종료되었을 경우
|
|
#endif
|
|
{
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "0-1.Ready for capture all paused done.\n";
|
|
qInfo() << "0-1.Ready for capture all paused done.";
|
|
#endif
|
|
clearCaptureTimer();
|
|
QTimer::singleShot(100, this, SLOT(requestVideoCaptureProcess()));
|
|
}
|
|
}
|
|
|
|
// 0-2 캡쳐 준비가 완료되면 삭제
|
|
void RMPlayer::clearCaptureTimer()
|
|
{
|
|
if(_captureTimer != NULL)
|
|
{
|
|
_captureTimer->stop();
|
|
delete _captureTimer;
|
|
_captureTimer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// 0-99 2초 이후에도 캡쳐가 완료되지 않았을 경우
|
|
void RMPlayer::onFailToCapture()
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
QString message;
|
|
|
|
#if !(FORCE_SINGLE_PLAYER)
|
|
message.sprintf("capture error.\nplayerF:%d(%d),playerR:%d(%d)\n",(int)_playerF->isPaused(),(int)_playerF->position(),(int)_playerR->isPaused(),(int)_playerR->position());
|
|
#else
|
|
message.sprintf("capture error.\nplayerF:%d(%d)\n",(int)_playerF->isPaused(),(int)_playerF->position());
|
|
#endif
|
|
|
|
message += g_errorMessage;
|
|
|
|
QMessageBox msgBox(QMessageBox::Warning,
|
|
"",
|
|
message,
|
|
QMessageBox::Yes,
|
|
RMUIManager::window);
|
|
|
|
msgBox.setWindowFlags(Qt::WindowTitleHint | Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint);
|
|
msgBox.exec();
|
|
#endif
|
|
clearCaptureWatcher();
|
|
QApplication::restoreOverrideCursor(); // 커서 복구
|
|
}
|
|
|
|
// 2. 캡쳐 프로세스 시작
|
|
void RMPlayer::requestVideoCaptureProcess()
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "2-1.Capture process started.\n";
|
|
qInfo() << "2-1.Capture process started.";
|
|
#endif
|
|
|
|
if(_captureFileList != NULL)
|
|
{
|
|
delete _captureFileList;
|
|
_captureFileList = NULL;
|
|
}
|
|
_captureFileList = new QList<QString>(); // 파일명 리스트 생성
|
|
|
|
|
|
_captureDir = RMApp::appPath(RMApp::CAPTURE);
|
|
FAV::VideoCapture* captureF = _playerF->videoCapture(); // 캡쳐 instance
|
|
|
|
//#if (CAPTURE_DEBUG)
|
|
// qInfo() << "2-1. Capture async:" << captureF->isAsync() << " autosave:" << captureF->autoSave();
|
|
//#endif
|
|
|
|
if(captureF != NULL)
|
|
{
|
|
captureF->setAsync(false);
|
|
captureF->setCaptureDir(_captureDir); // 폴더 지정
|
|
captureF->setSaveFormat("jpg"); // 포멧 지정
|
|
|
|
// Slider 컨트롤에 표시한 시간과 다르게 나올 수 있어
|
|
// _playerF->position() 은 사용하지 않으며 최종 전송된 _lastPosition 사용
|
|
//
|
|
QString captureTitle = _currentItem->titleCapture(titleSeconds); // _lastPosition
|
|
captureTitle += "_CH1_";
|
|
captureF->setCaptureName(captureTitle);
|
|
|
|
connect(captureF,SIGNAL(saved(const QString&)),SLOT(onCaptureSavedFront(const QString&)),Qt::UniqueConnection);
|
|
#if (CAPTURE_DEBUG)
|
|
connect(captureF,SIGNAL(imageCaptured(const QImage&)),SLOT(onImageCaptured(const QImage&)),Qt::UniqueConnection);
|
|
connect(captureF,SIGNAL(failed()),SLOT(onCaptureFailed()),Qt::UniqueConnection);
|
|
#endif
|
|
captureF->capture(); // (전방)캡쳐 시작
|
|
// updatePausedScreen(); // 한번더 확인
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "2-2.Start front capture.\n";
|
|
qInfo() << "2-2.Start front capture.";
|
|
#endif
|
|
}
|
|
#if (CAPTURE_DEBUG)
|
|
else
|
|
{
|
|
g_errorMessage += "2-2.Error front capture.\n";
|
|
qInfo() << "2-2.Error front capture.";
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// 3. 전방 캡쳐 완료
|
|
void RMPlayer::onCaptureSavedFront(const QString& path)
|
|
{
|
|
if(_playerF != NULL) {
|
|
FAV::VideoCapture* captureF = _playerF->videoCapture(); // 캡쳐 instance
|
|
disconnect(captureF,SIGNAL(saved(const QString&)),this,SLOT(onCaptureSavedFront(const QString&)));
|
|
}
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "3-1.Front capture done:" + path + "\n";
|
|
qInfo() << "3-1.Front capture done:" << path;
|
|
#endif
|
|
|
|
if(_captureFileList != NULL)
|
|
{
|
|
_captureFileList->append(path);
|
|
}
|
|
|
|
#if (!(FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL)
|
|
//if(_playerF->videoStreamCount() == 1) // 1CH 파일일 경우 ??? (TELEBIT mp4 1CH)
|
|
if(_playerR == NULL || _playerR->isLoaded() == false) // 1CH 파일일 경우 ??? (TELEBIT mp4 1CH)
|
|
#endif
|
|
{
|
|
if(_captureFileList != NULL)
|
|
{
|
|
QApplication::restoreOverrideCursor(); // 커서 복구
|
|
clearCaptureWatcher(); // watcher 삭제
|
|
//qInfo() << __LINE__ << __FUNCTION__;
|
|
emit videoCaptureDone(_captureFileList); // 완료 시그널
|
|
}
|
|
}
|
|
#if (!(FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER || TOGGLE_PLAYER) || PENTA_CHANNEL)
|
|
else // 후방 캡쳐 시작
|
|
{
|
|
FAV::VideoCapture* captureR = _playerR->videoCapture();
|
|
if(captureR != NULL)
|
|
{
|
|
captureR->setAsync(false);
|
|
captureR->setCaptureDir(_captureDir); // 폴더, 파일, 포멧, 이름 지정
|
|
captureR->setSaveFormat("jpg");
|
|
|
|
QString captureTitle = _currentItem->titleCapture(_playerF->position());
|
|
captureTitle += "_CH2_";
|
|
captureR->setCaptureName(captureTitle);
|
|
|
|
// QString name = captureR->captureName();
|
|
// if(name.contains("_CH2_",Qt::CaseInsensitive) == false)
|
|
// {
|
|
// name += "_CH2_";
|
|
// captureR->setCaptureName(name);
|
|
// }
|
|
connect(captureR,SIGNAL(saved(const QString&)),SLOT(onCaptureSavedRear(const QString&)),Qt::UniqueConnection);
|
|
#if (CAPTURE_DEBUG)
|
|
connect(captureR,SIGNAL(imageCaptured(const QImage&)),SLOT(onImageCaptured(const QImage&)),Qt::UniqueConnection);
|
|
connect(captureR,SIGNAL(failed()),SLOT(onCaptureFailed()),Qt::UniqueConnection);
|
|
#endif
|
|
captureR->capture(); // 후방 캡쳐 시작
|
|
//updatePausedScreenRearOnly(); // 한번더 확인
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "3-2.Start rear capture.\n";
|
|
qInfo() << "3-2.Start rear capture.";
|
|
#endif
|
|
}
|
|
#if (CAPTURE_DEBUG)
|
|
else
|
|
{
|
|
g_errorMessage += "3-2.Error rear capture.\n";
|
|
qInfo() << "3-2.Error rear capture.";
|
|
}
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// 4. 후방 캡쳐 완료
|
|
#if !(FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER)
|
|
void RMPlayer::onCaptureSavedRear(const QString& path)
|
|
{
|
|
// 연결 해제
|
|
if(_playerR != NULL) {
|
|
FAV::VideoCapture* captureR = _playerR->videoCapture();
|
|
disconnect(captureR,SIGNAL(saved(const QString&)),this,SLOT(onCaptureSavedRear(const QString&)));
|
|
}
|
|
|
|
if(_captureFileList != NULL)
|
|
{
|
|
#if (CAPTURE_DEBUG)
|
|
g_errorMessage += "4.Rear capture done. All OK!:" + path + "\n";
|
|
qInfo() << "4.Rear capture done. All OK!:" << path;
|
|
#endif
|
|
_captureFileList->append(path); // 파일명 추가
|
|
QApplication::restoreOverrideCursor(); // 커서 복구
|
|
clearCaptureWatcher(); // Watcher 제거
|
|
//qInfo() << __LINE__ << __FUNCTION__;
|
|
emit videoCaptureDone(_captureFileList); // 시그널
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// 5. 캡쳐 Watcher 삭제
|
|
void RMPlayer::clearCaptureWatcher()
|
|
{
|
|
if(_captureWatcher != NULL)
|
|
{
|
|
_captureWatcher->stop();
|
|
delete _captureWatcher;
|
|
_captureWatcher = NULL;
|
|
}
|
|
}
|
|
#if (CAPTURE_DEBUG)
|
|
void RMPlayer::onImageCaptured(const QImage& image)
|
|
{
|
|
Q_UNUSED(image);
|
|
g_errorMessage += "999.image captured.\n";
|
|
qInfo() << "999.image captured.";
|
|
}
|
|
void RMPlayer::onCaptureFailed()
|
|
{
|
|
g_errorMessage += "999.image capture failed.\n";
|
|
qInfo() << "999.image capture failed.";
|
|
}
|
|
#endif
|
|
// 캡쳐 DONE
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// SEEK
|
|
|
|
qint64 RMPlayer::ratioToSliderValue(qreal ratio)
|
|
{
|
|
//return _playerF->mediaStopPosition() * ratio;
|
|
return _slider->maximum() * ratio;
|
|
}
|
|
void RMPlayer::on_sync_timer_restarted()
|
|
{
|
|
_sync_time = true;
|
|
}
|
|
|
|
|
|
#if (PENTA_CHANNEL)
|
|
#define CHANNEL_PAUSE_MODE 1
|
|
void RMPlayer::onUpdateCHMode()
|
|
{
|
|
changeCHMode(RMApp::instance()->chMode);
|
|
}
|
|
void RMPlayer::changeCHMode(RMApp::ChannelMode mode)
|
|
{
|
|
RMApp::instance()->chMode = mode;
|
|
|
|
// 채널 변경 시작
|
|
emit playEvent(PLAY_WILL_CHANGE_CH,_currentItem);
|
|
|
|
// 이전 채널 확인
|
|
FAV::AVPlayer* oldF = _playerF;
|
|
FAV::AVPlayer* oldR = _playerR;
|
|
|
|
// 커넥션 해제
|
|
_clearPlayerConnection();
|
|
|
|
// NULL 처리시 문제가 발생하므로
|
|
_playerF = NULL;//_players[RMApp::ChannelFront];
|
|
_playerR = NULL;//_players[RMApp::ChannelRear];
|
|
|
|
// 이미 playOrPause 에서 play 된 상태로 호출됨
|
|
for(int i=0;i<5;i++) {
|
|
#if (CHANNEL_PAUSE_MODE)
|
|
//qInfo() << "PLAYER:" << i << _players[i]->isLoaded() << __FUNCTION__;
|
|
if(_players[i]->isLoaded()) {
|
|
if(!_players[i]->isPaused()) {
|
|
//qInfo() << "PAUSE:" << i << __FUNCTION__;
|
|
_players[i]->pause(true);
|
|
}
|
|
}
|
|
#else // CHANNEL_PAUSE_MODE
|
|
_players[i]->setSkipVideo(true);
|
|
#endif // CHANNEL_PAUSE_MODE
|
|
}
|
|
|
|
switch(RMApp::instance()->chMode) {
|
|
case RMApp::ChannelModeFR:
|
|
_playerF = _players[RMApp::ChannelFront];
|
|
_playerR = _players[RMApp::ChannelRear];
|
|
break;
|
|
case RMApp::ChannelModeLR:
|
|
_playerF = _players[RMApp::ChannelLeft];
|
|
_playerR = _players[RMApp::ChannelRight];
|
|
break;
|
|
case RMApp::ChannelModeFront:
|
|
_playerF = _players[RMApp::ChannelFront];
|
|
break;
|
|
case RMApp::ChannelModeRear:
|
|
_playerF = _players[RMApp::ChannelRear];
|
|
break;
|
|
case RMApp::ChannelModeLeft:
|
|
_playerF = _players[RMApp::ChannelLeft];
|
|
break;
|
|
case RMApp::ChannelModeRight:
|
|
_playerF = _players[RMApp::ChannelRight];
|
|
break;
|
|
case RMApp::ChannelModeSub:
|
|
_playerF = _players[RMApp::ChannelSub];
|
|
break;
|
|
}
|
|
|
|
if(_playerF != NULL) {
|
|
#if (CHANNEL_PAUSE_MODE)
|
|
//qInfo() << "PLAYER LOADED:" << _playerF->isLoaded() << "PAUSED:" << _playerF->isPaused() << __FUNCTION__;
|
|
|
|
// 현재 정지상태일 경우
|
|
if(!_pausedState && _playerF->isPaused()) {
|
|
_playerF->pause(false);
|
|
//qInfo() << "PLAY F2:" << _playerF << __FUNCTION__;
|
|
}
|
|
|
|
if(oldF != NULL && oldF != _playerF) {
|
|
_playerF->setPosition(oldF->position());
|
|
}
|
|
#else // CHANNEL_PAUSE_MODE
|
|
_playerF->setSkipVideo(false);
|
|
#endif // CHANNEL_PAUSE_MODE
|
|
}
|
|
if(_playerR != NULL) {
|
|
#if (CHANNEL_PAUSE_MODE)
|
|
|
|
if(!_pausedState && _playerR->isPaused()) {
|
|
_playerR->pause(false);
|
|
//qInfo() << "PLAY R2:" << _playerR << __FUNCTION__;
|
|
}
|
|
if(oldR != NULL && oldR != _playerR) {
|
|
_playerR->setPosition(oldR->position());
|
|
}
|
|
|
|
#else // CHANNEL_PAUSE_MODE
|
|
_playerR->setSkipVideo(false);
|
|
#endif // CHANNEL_PAUSE_MODE
|
|
}
|
|
|
|
// 사운드 처리
|
|
if(!_isMuted()) {
|
|
if(oldF != NULL && _playerF != oldF) {
|
|
oldF->audio()->setMute(true);
|
|
//_players[RMApp::ChannelFront]->setAudioStream(-1);
|
|
|
|
_playerF->audio()->setMute(false);
|
|
_playerF->audio()->setVolume(oldF->audio()->volume());
|
|
oldF->audio()->setVolume(0);
|
|
}
|
|
// 후방은 무조건 끄기
|
|
if(_playerR != NULL && !_playerR->audio()->isMute()) {
|
|
_playerR->audio()->setMute(true);
|
|
_playerR->audio()->setVolume(0);
|
|
}
|
|
}
|
|
|
|
// 비디오 장치 연결
|
|
_configureVideoRenderers();
|
|
//qInfo() << "PLAYERS:" << _players[0] << _players[1] << _players[2] << _players[3] << _players[4] << __FUNCTION__;
|
|
// qInfo() << "F:" << _playerF << "R:" << _playerR << __FUNCTION__;
|
|
|
|
// 커넥션 처리
|
|
_updatePlayerConnection();
|
|
|
|
if(_playerF != NULL) {
|
|
_playerF->masterClock()->updateExternalClock(*_clock);
|
|
}
|
|
if(_playerR != NULL) {
|
|
_playerR->masterClock()->updateExternalClock(*_clock);
|
|
}
|
|
|
|
// 채널변경 종료
|
|
emit playEvent(PLAY_DID_CHANGE_CH,_currentItem);
|
|
|
|
// 필터 업데이트
|
|
_updateEQFilter(true);
|
|
|
|
// FLIP 업데이트
|
|
updateFlip(false);
|
|
|
|
if(_pausedState) {
|
|
updatePausedScreen();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void RMPlayer::clear_seek_timer()
|
|
{
|
|
// seek 종료시 일정시간 후 동기화 시작한다
|
|
if(_sync_restart_timer != NULL)
|
|
{
|
|
_sync_restart_timer->stop();
|
|
delete _sync_restart_timer;
|
|
_sync_restart_timer = NULL;
|
|
}
|
|
_sync_time = false;
|
|
}
|
|
|
|
void RMPlayer::seek(qint64 pos,bool refresh)
|
|
{
|
|
//qInfo() << pos << __FUNCTION__ << __LINE__;
|
|
|
|
#if (LIMIT_SEEK_END)
|
|
if(pos > _playerF->duration() - 2000)
|
|
{
|
|
//qInfo() << pos << _playerF->duration() << __FUNCTION__ << __LINE__;
|
|
pos = qMax((qint64)(_playerF->duration() - 2000),(qint64)0);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
#if (SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
|
if(_playerF->isPlaying() == false)
|
|
#else
|
|
if(_playerF->isPlaying() == false || (_playerR->isLoaded() == true && _playerR->isPlaying() == false))
|
|
#endif
|
|
{
|
|
//qInfo() << __FUNCTION__ << __LINE__;
|
|
return;
|
|
}
|
|
|
|
#if (USE_LAST_PLAY_SEEK && !(PLAY_SEEK_FILE_MOVE))
|
|
// 최종 종료단계에 들어간 경우 처리하지 않는다.
|
|
// 최종 종료단계로 이동할 경우 처리한다. (하지 않으면 이동하지 않는다.)
|
|
if(_playerF->position()+ LAST_PLAY_SEEK_LIMIT > _playerF->duration())
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
//#if (RM_MODEL != RM_MODEL_TYPE_KEIYO1)
|
|
clear_seek_timer(); // 동기화 중지
|
|
_refreshSeeking = refresh; // 화면갱신을 위한..
|
|
|
|
#if (PENTA_CHANNEL)
|
|
for(int i=0;i<5;i++) {
|
|
if(_players[i]->isLoaded()) {
|
|
_players[i]->setSeekType(VIDEO_SEEK_TYPE);
|
|
_players[i]->seek(pos);
|
|
}
|
|
}
|
|
#else // PENTA_CHANNEL
|
|
|
|
_playerF->setSeekType(VIDEO_SEEK_TYPE);
|
|
_playerF->seek(pos);
|
|
|
|
|
|
#if !(SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
|
if(_playerR->isLoaded())
|
|
{
|
|
// 이거 왜하는지 모르겠음
|
|
if(_pausedState == false)
|
|
{
|
|
_playerR->pause(false);
|
|
}
|
|
_playerR->setSeekType(VIDEO_SEEK_TYPE);
|
|
_playerR->seek(pos);
|
|
}
|
|
#endif // #if (SINGLE_CH_VIEWER)
|
|
|
|
#if (TRI_CHANNEL)
|
|
if(_playerI->isLoaded())
|
|
{
|
|
// 이거 왜하는지 모르겠음
|
|
if(_pausedState == false)
|
|
{
|
|
_playerI->pause(false);
|
|
}
|
|
_playerI->setSeekType(VIDEO_SEEK_TYPE);
|
|
_playerI->seek(pos);
|
|
}
|
|
#endif
|
|
|
|
//#endif // RM_MODEL_TYPE_KEIYO1
|
|
|
|
//#if (MODEL_BBVIEWER)
|
|
// // 처리하지 않으면 위치 클릭전 위치로 이동함.
|
|
// _clock->updateExternalClock( pos );
|
|
|
|
// // 처리하지 않으면 seek 가 play seek 되면서 delay 발생함
|
|
// _playerF->masterClock()->updateExternalClock(*_clock);
|
|
//#if !(FORCE_SINGLE_PLAYER)
|
|
// _playerR->masterClock()->updateExternalClock(*_clock);
|
|
//#endif
|
|
//#endif // MODEL_BBVIEWER
|
|
#endif // #else // PENTA_CHANNEL
|
|
}
|
|
|
|
|
|
void RMPlayer::onSliderMove(int value)
|
|
{
|
|
//LOG_TEST;
|
|
_refreshSeeking = false; // 초기화 해야함
|
|
if(_playerF == NULL)
|
|
{
|
|
return;
|
|
}
|
|
if (_playerF->isLoaded())
|
|
{
|
|
// Release 이후에 Slider Move 가 한번더 호출되어 _sliderMoving == true 처리하면 안됨
|
|
// 그러나 _sliderMoving 처리하지 않으면 다시 seek 발생하고 슬라이드 이동 재귀 호출됨
|
|
_sliderMoving = true;
|
|
#if (PLAY_SYNC_FIX2)
|
|
qint64 pos = value;
|
|
#else
|
|
qint64 pos = MAX(INITIAL_VIDEO_POSITION,value);
|
|
#endif
|
|
|
|
// 완전 뮤트
|
|
muteIfRequired(-1);
|
|
if(_playerF->isPaused() == true)
|
|
{
|
|
// 정지된 상태에서만 클럭 업데이트
|
|
#if !(PLAY_SYNC_FIX2)
|
|
_clock->updateExternalClock( pos );
|
|
#endif // PLAY_SYNC_FIX2
|
|
//qInfo() << "*** SLIDE MOVE" << pos << __FUNCTION__;
|
|
_playerF->setPosition( pos );
|
|
|
|
|
|
#if !(FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER || TOGGLE_PLAYER)
|
|
if(_playerR->isLoaded())
|
|
{
|
|
_playerR->setPosition( pos );
|
|
}
|
|
//qInfo() << __FUNCTION__ << "setPosition:" << pos;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
seek(pos,false);
|
|
}
|
|
_pausePosition = pos; // ???
|
|
|
|
|
|
|
|
// 정지 상태일 경우 지도 및 그래프는 업데이트 한다. -> 실제 정지 상태에서 onPositionChanged 가 발생함
|
|
//emit positionChanged(pos,_playerF->duration());
|
|
}
|
|
}
|
|
void RMPlayer::onSliderRelease()
|
|
{
|
|
//FLOG_OT << __FUNCTION__ << __LINE__;
|
|
|
|
// mouse relese 이후에 move 가 한번더 발생하여
|
|
// _sliderMoving 이 다시 true 가 되어 정지됨
|
|
_sliderMoving = false;
|
|
|
|
// SEEK 도중 PAUSE 처리 복구
|
|
// && _playerF->isPaused() 는 완전히 처리완료 되지 않은 경우가 있어 확인하지 않는다
|
|
if(_pauseWhileSeek ) {
|
|
//qInfo() << "_pauseWhileSeek:" << _pauseWhileSeek<< __FUNCTION__;
|
|
_pause(false,true);
|
|
_pauseWhileSeek = false;
|
|
}
|
|
onUnMuteIfRequired();
|
|
sync_clock();
|
|
}
|
|
|
|
void RMPlayer::onSliderPress(bool bKnob)
|
|
{
|
|
if(_playerF == NULL) {
|
|
return;
|
|
}
|
|
|
|
//FLOG_OT << __FUNCTION__ << __LINE__;
|
|
|
|
endStepMode();
|
|
RMSlider* slider = qobject_cast<RMSlider*>(QObject::sender());
|
|
if(slider == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 처리 도중에는 자동 파일 이동 방지
|
|
_sliderMoving = true;
|
|
|
|
// 적용안됨???
|
|
bKnob = true;
|
|
|
|
int sliderPos = slider->value();
|
|
|
|
// KNOB 가 아닐 경우 이후 이벤트 발생하지 않기 때문에 pause 등 처리할 필요 없음
|
|
#if (PLAY_SYNC_FIX2)
|
|
// isPaused 는 player 내부에서 SEEK 중 일 경우 사용자 paused 상태에서도 풀릴 수 있음
|
|
if(bKnob == true && _pausedState == false) {
|
|
#else
|
|
if(bKnob == true && _playerF->isPaused() == false) {
|
|
#endif
|
|
_pauseWhileSeek = true;
|
|
_pause(true,true);
|
|
}
|
|
|
|
// 클릭한 지점으로 이동
|
|
|
|
onSliderMove(sliderPos);
|
|
|
|
// 클릭한 경우 released 가 호출되지 않기 때문에 _sliderMoving 바로 해제
|
|
if(bKnob == false) {
|
|
_sliderMoving = false;
|
|
|
|
// MUTE 도 바로 해제
|
|
onUnMuteIfRequired();
|
|
}
|
|
}
|
|
|
|
void RMPlayer::startSeekUpdateTimer()
|
|
{
|
|
// 기존 타이머 제거
|
|
stopSeekUpdateTimer();
|
|
|
|
_seekPressedTimer = new QTimer(this);
|
|
_seekPressedTimer->setInterval(300);
|
|
connect(_seekPressedTimer,SIGNAL(timeout()),SLOT(onSeekPressed()));
|
|
_seekPressedTimer->start();
|
|
|
|
// pressed -> 중 업데이트
|
|
_seekUpdateTimer = new QTimer(this);
|
|
_seekUpdateTimer->setInterval(500);
|
|
connect(_seekUpdateTimer,SIGNAL(timeout()),SLOT(onSeekUpdate()));
|
|
_seekUpdateTimer->start();
|
|
}
|
|
void RMPlayer::stopSeekUpdateTimer()
|
|
{
|
|
if(_seekPressedTimer != NULL)
|
|
{
|
|
_seekPressedTimer->stop();
|
|
delete _seekPressedTimer;
|
|
_seekPressedTimer = NULL;
|
|
}
|
|
if(_seekReleasedTimer != NULL)
|
|
{
|
|
_seekReleasedTimer->stop();
|
|
delete _seekReleasedTimer;
|
|
_seekReleasedTimer = NULL;
|
|
}
|
|
if(_seekUpdateTimer != NULL)
|
|
{
|
|
_seekUpdateTimer->stop();
|
|
delete _seekUpdateTimer;
|
|
_seekUpdateTimer = NULL;
|
|
}
|
|
_seekAcceleration = 1;
|
|
}
|
|
void RMPlayer::onSeekPressed()
|
|
{
|
|
if(_firstStep == true) // && _stepMode == STEP_MODE_B1
|
|
{
|
|
return;
|
|
}
|
|
if(_seekPressedTimer != NULL)
|
|
{
|
|
_seekPressedTimer->setInterval(150);
|
|
}
|
|
|
|
int step = (_stepMode != STEP_MODE_B1) ? 1 : -1;
|
|
qint64 pos = _stepPosition();
|
|
if(_isLastStep() && step > 0)
|
|
{
|
|
// 다음파일이 없을 경우 이후 동작하지 않는다 _playItem == NULL 로 처리해서
|
|
stopSeekUpdateTimer();
|
|
if(RMVideoFileList::instance()->isNextPlayItemExist(true)) {
|
|
_onNaturalEnd = true;
|
|
RMVideoFileList::instance()->onPlayNextVideo(-1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(pos < 0 && step < 0)
|
|
{
|
|
stopSeekUpdateTimer();
|
|
if(RMVideoFileList::instance()->isNextPlayItemExist(false)) {
|
|
// stepping 처리시
|
|
_onNaturalEnd = true;
|
|
RMVideoFileList::instance()->onPlayPreviousVideo(-1);
|
|
//qInfo() << "BACK";
|
|
return;
|
|
}
|
|
}
|
|
|
|
pos = MAX(MIN(pos,_playerF->duration()),0);
|
|
_slider->setValue(pos);
|
|
|
|
// 처리하지 않으면 swap 처리시 문제가됨
|
|
_pausePosition = pos;
|
|
|
|
//qInfo() << __FUNCTION__ << pos << ":" << _slider->value() << _playerF->position();
|
|
|
|
emit RMPlayer::instance()->positionChanged(pos,_playerF->duration());
|
|
}
|
|
|
|
void RMPlayer::onSeekUpdate()
|
|
{
|
|
// 연속 클릭시 바로 업데이트 하지 않고 취소 할 수 있도록 처리
|
|
if(_firstStep == true) // && _stepMode == STEP_MODE_B1
|
|
{
|
|
return;
|
|
}
|
|
qint64 pos = _slider->value();
|
|
//qInfo() << __FUNCTION__ << pos << _playerF->isLoaded() << _playerR->isLoaded() << _playerF->position() << _playerR->position();
|
|
seek(pos,false);
|
|
#if (DO_NOT_USE_STEP_PAUSE)
|
|
_stepMode = STEP_MODE_NONE;
|
|
#endif // DO_NOT_USE_STEP_PAUSE
|
|
//qInfo() << __FUNCTION__ << " POS:" << pos;
|
|
}
|
|
void RMPlayer::onSeekLastUpdate()
|
|
{
|
|
onSeekUpdate();
|
|
stopSeekUpdateTimer();
|
|
}
|
|
|
|
void RMPlayer::onSeekForwardStart()
|
|
{
|
|
if(!_playerF->isLoaded()) {
|
|
return;
|
|
}
|
|
_stepMode = STEP_MODE_F1;
|
|
_firstStep = false;
|
|
// 정지
|
|
#if !(DO_NOT_USE_STEP_PAUSE)
|
|
if(_playerF->isPaused() == false)
|
|
{
|
|
_pause(true,true);
|
|
// _pause 는 slider 등에서 잠깐 이동시에도 사용하기 때문에
|
|
// 직접 아이콘 변경 해야함
|
|
emit playEvent(PLAY_DID_PAUSED,_currentItem);
|
|
}
|
|
#endif // DO_NOT_USE_STEP_PAUSE
|
|
// 최초 1회 실행 (슬라이드만 이동, 실제 SEEK 는 onSeekUpdate 에서 발생함)
|
|
onSeekPressed();
|
|
startSeekUpdateTimer();
|
|
}
|
|
void RMPlayer::onSeekBackwardStart()
|
|
{
|
|
if(!_playerF->isLoaded()) {
|
|
return;
|
|
}
|
|
// 연속해서 press+release 반복시 마지막 업데이트 취소
|
|
stopSeekUpdateTimer();
|
|
|
|
_stepMode = STEP_MODE_B1;
|
|
_firstStep = false;
|
|
#if !(DO_NOT_USE_STEP_PAUSE)
|
|
// 정지
|
|
if(_playerF->isPaused() == false)
|
|
{
|
|
_pause(true,true);
|
|
// _pause 는 slider 등에서 잠깐 이동시에도 사용하기 때문에
|
|
// 직접 아이콘 변경 해야함
|
|
emit playEvent(PLAY_DID_PAUSED,_currentItem);
|
|
}
|
|
#endif // DO_NOT_USE_STEP_PAUSE
|
|
onSeekPressed();
|
|
startSeekUpdateTimer();
|
|
}
|
|
#if (PLAY_SYNC_FIX2)
|
|
void RMPlayer::onSeekFrameBackwardStart()
|
|
{
|
|
_stepMode = STEP_MODE_BF;
|
|
_firstStep = false;
|
|
|
|
if(_playerF->isPaused() == false)
|
|
{
|
|
_pause(true,true);
|
|
// _pause 는 slider 등에서 잠깐 이동시에도 사용하기 때문에
|
|
// 직접 아이콘 변경 해야함
|
|
emit playEvent(PLAY_DID_PAUSED,_currentItem);
|
|
}
|
|
else // 처리 해 주지 않으면 뒤로 돌아가서 시작함
|
|
{
|
|
//qInfo() << __FUNCTION__ << _slider->value() << _playerF->position();
|
|
//_slider->setValue(_playerF->position());
|
|
}
|
|
onSeekPressed();
|
|
startSeekUpdateTimer();
|
|
}
|
|
#endif // #if (PLAY_SYNC_FIX2)
|
|
void RMPlayer::onSeekFrameForwardStart()
|
|
{
|
|
_stepMode = STEP_MODE_FF;
|
|
_firstStep = false;
|
|
|
|
if(_playerF->isPaused() == false)
|
|
{
|
|
_pause(true,true);
|
|
// _pause 는 slider 등에서 잠깐 이동시에도 사용하기 때문에
|
|
// 직접 아이콘 변경 해야함
|
|
emit playEvent(PLAY_DID_PAUSED,_currentItem);
|
|
}
|
|
else // 처리 해 주지 않으면 뒤로 돌아가서 시작함
|
|
{
|
|
//qInfo() << __FUNCTION__ << _slider->value() << _playerF->position();
|
|
//_slider->setValue(_playerF->position());
|
|
}
|
|
onSeekPressed();
|
|
startSeekUpdateTimer();
|
|
}
|
|
// KEY/MOUSE RELEASE
|
|
void RMPlayer::onSeekStepEnd()
|
|
{
|
|
// 모드 종료는 endStopMode() 에서 처리함..
|
|
stopSeekUpdateTimer();
|
|
|
|
_seekReleasedTimer = new QTimer(this);
|
|
#if (FIX_PRESS_AND_RELEASE)
|
|
// 연속해서 press+release 처리할 경우 임시로 해결
|
|
_seekReleasedTimer->setInterval(300);
|
|
#else
|
|
_seekReleasedTimer->setInterval(100);
|
|
#endif
|
|
_seekReleasedTimer->setSingleShot(true);
|
|
connect(_seekReleasedTimer,SIGNAL(timeout()),SLOT(onSeekLastUpdate()));
|
|
_seekReleasedTimer->start();
|
|
}
|
|
|
|
|
|
quint64 RMPlayer::_stepPosition()
|
|
{
|
|
#if (SEEK_STEP_SIZE == 10)
|
|
const double stepSize = 10000.0;
|
|
#else
|
|
const double stepSize = 1000.0;
|
|
#endif
|
|
qint64 nexPos = 0;
|
|
if(_stepMode == STEP_MODE_F1 || _stepMode == STEP_MODE_B1)
|
|
{
|
|
int step = _stepMode == STEP_MODE_F1 ? 1 : -1;
|
|
//double tolerance = 0;
|
|
step *= _seekAcceleration;
|
|
|
|
// 이전이동 + 마지막일 경우
|
|
if(step < 0 && _isLastStep())
|
|
{
|
|
//tolerance = 100;
|
|
}
|
|
#if (SEEK_SIMPLE_STEP) // 단순이동 모드
|
|
if(_stepMode == STEP_MODE_F1) {
|
|
nexPos = MIN((_slider->value() + stepSize),_playerF->duration());
|
|
} else {
|
|
nexPos = MAX((_slider->value() - stepSize),0);
|
|
}
|
|
#else // SEEK_SIMPLE_STEP
|
|
int currentIndex = (int)(((double)_slider->value()) / stepSize);
|
|
currentIndex += step;
|
|
nexPos = (qint64)(((double)currentIndex) * stepSize);
|
|
if(fabs( (double)(nexPos-_slider->value())) < 100)
|
|
{
|
|
nexPos = (qint64)(((double)currentIndex + step) * stepSize);
|
|
}
|
|
// 다음이 마지막 STEP 일 경우 영상 마지막으로 이동
|
|
if(step > 0 && (_playerF->duration() - nexPos) < 500)
|
|
{
|
|
nexPos = _playerF->duration();//_durationAddPTS;
|
|
}
|
|
#endif // #else // SEEK_SIMPLE_STEP
|
|
//qInfo() << nexPos;
|
|
}
|
|
else if (_stepMode == STEP_MODE_FF)
|
|
{
|
|
nexPos = MIN((_slider->value() + STEP_SEEK_DURATION),_playerF->duration());
|
|
//qInfo() << __FUNCTION__ << nexPos << _playerF->position() << _slider->value();
|
|
}
|
|
#if (PLAY_SYNC_FIX2)
|
|
else if (_stepMode == STEP_MODE_BF)
|
|
{
|
|
nexPos = MAX((_slider->value() - STEP_SEEK_DURATION),0);
|
|
//qInfo() << __FUNCTION__ << nexPos << _playerF->position() << _slider->value();
|
|
}
|
|
#endif // #if (PLAY_SYNC_FIX2)
|
|
_seekAcceleration = MIN(_seekAcceleration+1,3);
|
|
return nexPos;
|
|
}
|
|
bool RMPlayer::_isLastStep()
|
|
{
|
|
if(_stepMode != STEP_MODE_FF)
|
|
{
|
|
return (_playerF->duration() - _slider->value()) < 500;
|
|
}
|
|
return (_playerF->duration() - _slider->value()) < 1;
|
|
}
|
|
void RMPlayer::onPlayRestart()
|
|
{
|
|
_clock->updateExternalClock(0);
|
|
seek(0,false);
|
|
}
|
|
void RMPlayer::seekFrontOnly(qint64 pos,bool refresh)
|
|
{
|
|
_refreshSeeking = refresh; // 화면갱신을 위한..
|
|
if(_playerF->isLoaded())
|
|
{
|
|
_playerF->seek(pos);
|
|
}
|
|
}
|
|
#if !(FORCE_SINGLE_PLAYER || SINGLE_CH_VIEWER)
|
|
void RMPlayer::seekRearOnly(qint64 pos,bool refresh)
|
|
{
|
|
_refreshSeeking = refresh; // 화면갱신을 위한..
|
|
if(_playerR->isLoaded())
|
|
{
|
|
_playerR->seek(pos);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if (CAPTURE_DEBUG)
|
|
void RMPlayer::onSeekCapture()
|
|
{
|
|
requestVideoCapture();
|
|
}
|
|
|
|
#endif
|
|
|
|
void RMPlayer::onSpeedSliderMoved(int position)
|
|
{
|
|
RMSlider* slider = qobject_cast<RMSlider *>(QObject::sender());
|
|
if(slider != NULL)
|
|
{
|
|
if(position >= 0 && position < PLAY_SPEED_COUNT)
|
|
{
|
|
#if !(DEBUG_HIGH_SPEED_STOP)
|
|
_speedValue = g_PlaySpeedList[position];
|
|
#endif
|
|
if(_speedLabel != NULL)
|
|
{
|
|
_speedLabel->setText(g_PlaySpeedNames.at(position));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RMPlayer::onSpeedSliderReleased()
|
|
{
|
|
RMSlider* slider = qobject_cast<RMSlider *>(QObject::sender());
|
|
if(slider != NULL)
|
|
{
|
|
int index = slider->value();
|
|
if(index >= 0 && index < PLAY_SPEED_COUNT)
|
|
{
|
|
_speedValue = g_PlaySpeedList[index];
|
|
if(_speedLabel != NULL)
|
|
{
|
|
_speedLabel->setText(g_PlaySpeedNames.at(slider->value()));
|
|
}
|
|
updateSpeed(_speedValue);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if !(SINGLE_CH_VIEWER)
|
|
#if (TOGGLE_PLAYER)
|
|
void RMPlayer::toggleSwap(bool forceEmit)
|
|
{
|
|
//qInfo() << "TOGGLE SWAP:" << LOG_FL;
|
|
|
|
// 로딩되지 않은 상태에서도 처리
|
|
if(_eventBlocking == true)
|
|
{
|
|
return;
|
|
}
|
|
#if !(DO_NOT_USE_ZOOM)
|
|
if(_videoOutputZOOMMain != NULL) {
|
|
_playerF->removeVideoRenderer(_videoOutputZOOMMain);
|
|
}
|
|
#endif
|
|
if(forceEmit == false)
|
|
{
|
|
blockEvents(200);
|
|
}
|
|
disconnect(_playerF,SIGNAL(positionChanged(qint64)),this,SLOT(onPositionChanged(qint64)));
|
|
disconnect(_playerF,SIGNAL(firstFrameNotify(qreal)),this,SLOT(onFirstFrame(qreal)));
|
|
disconnect(_playerF,SIGNAL(error(const FAV::AVError&)),this,SLOT(onPlayerF(const FAV::AVError&)));
|
|
|
|
|
|
_swaped = !_swaped;
|
|
|
|
bool isPaused = _playerF->isPaused();
|
|
|
|
// Player SWAP
|
|
FAV::AVPlayer* pt = _playerR;
|
|
_playerR = _playerF;
|
|
_playerF = pt;
|
|
|
|
// 전방을 후방에 표시
|
|
if(_playerF->isLoaded()) {
|
|
// 2021/04/28-> 1000->100 으로 변경
|
|
_playerF->setPosition(qMax((qint64)(_playerR->position()-100),(qint64)0));
|
|
}
|
|
_playerF->setRenderer(_videoOutputF);
|
|
_playerR->removeVideoRenderer(_videoOutputF);
|
|
if(_playerF->isLoaded()) {
|
|
_playerF->pause(isPaused);
|
|
_playerR->pause(true);
|
|
_playerF->masterClock()->updateExternalClock(*_clock);
|
|
_playerR->masterClock()->updateExternalClock(*_clock);
|
|
}
|
|
connect(_playerF, SIGNAL(positionChanged(qint64)), SLOT(onPositionChanged(qint64)));
|
|
connect(_playerF,SIGNAL(firstFrameNotify(qreal)),this,SLOT(onFirstFrame(qreal)));
|
|
connect(_playerF,SIGNAL(error(const FAV::AVError&)), SLOT(onPlayerF(const FAV::AVError&)));
|
|
|
|
//qInfo() << "SET POSITION:" << _playerR->position() << __FUNCTION__;
|
|
|
|
#if !(DO_NOT_USE_ZOOM)
|
|
if(_videoOutputZOOMMain != NULL) {
|
|
_playerF->addVideoRenderer(_videoOutputZOOMMain);
|
|
}
|
|
#endif
|
|
_playerF->audio()->setMute(false);
|
|
_playerR->audio()->setMute(true);
|
|
|
|
updatePausedScreen();
|
|
|
|
emit playEvent(_swaped ? PLAY_DID_SWAPPED : PLAY_DID_UNSWAPPED, _currentItem);
|
|
}
|
|
#else // TOGGLE_PLAYER
|
|
void RMPlayer::toggleSwap(bool forceEmit)
|
|
{
|
|
// 로딩되지 않은 상태에서도 처리
|
|
if(_eventBlocking == true)
|
|
{
|
|
return;
|
|
}
|
|
#if !(DO_NOT_USE_ZOOM)
|
|
if(_videoOutputZOOMMain != NULL) {
|
|
mainScreenPlayer()->removeVideoRenderer(_videoOutputZOOMMain);
|
|
}
|
|
if(_videoOutputZOOMSub != NULL) {
|
|
subScreenPlayer()->removeVideoRenderer(_videoOutputZOOMSub);
|
|
}
|
|
#endif
|
|
|
|
if(forceEmit == false)
|
|
{
|
|
blockEvents(200);
|
|
}
|
|
_swaped = !_swaped;
|
|
//qInfo() << "_swaped:" << _swaped << __FUNCTION__;
|
|
if(_isSwaped())
|
|
{
|
|
#if (RM_MODEL_360)
|
|
//_videoOutputF->widget()->setHidden(true);
|
|
//_videoOutputR->widget()->setHidden(true);
|
|
// 현재 모드/각도 저장 후 복원
|
|
FAV::OpenGLVideo::RENDER_INFO_360 fi = {0,};
|
|
FAV::OpenGLVideo::RENDER_INFO_360 ri = {0,};
|
|
fi.aspectMode = (int)_videoOutputF->outAspectRatioMode();
|
|
fi.sourceAspectRatio = _videoOutputF->sourceAspectRatio();
|
|
//qInfo() << _videoOutputF->outAspectRatioMode();
|
|
ri.aspectMode = (int)_videoOutputR->outAspectRatioMode();
|
|
ri.sourceAspectRatio = _videoOutputR->sourceAspectRatio();
|
|
_videoOutputF->opengl()->getRenderInfo(&fi);
|
|
_videoOutputR->opengl()->getRenderInfo(&ri);
|
|
// 전환시 모드 리셋!
|
|
fi.mode = _videoOutputF->opengl()->mode(); // 전방 FISHEYE
|
|
ri.mode = 0;
|
|
#endif
|
|
|
|
// 전방을 후방에 표시
|
|
_playerF->setRenderer(_videoOutputR);
|
|
|
|
// 전방 파일이 존재하지 않을 경우
|
|
#if (FORCE_2CH)
|
|
if(_currentItem != NULL && _currentItem->filePath.length() == 0)
|
|
#else
|
|
if(_currentItem != NULL && (_currentItem->filePath.length() == 0 || _currentItem->filePathCH2.length() == 0))
|
|
#endif
|
|
{
|
|
_videoOutputF->receive(FAV::VideoFrame()); // clear
|
|
}
|
|
else
|
|
{
|
|
#if (TRI_CHANNEL)
|
|
if(isIndoor()) {
|
|
_playerI->setRenderer(_videoOutputF);
|
|
|
|
} else {
|
|
_playerR->setRenderer(_videoOutputF);
|
|
}
|
|
#else // TRI_CHANNEL
|
|
_playerR->setRenderer(_videoOutputF);
|
|
#endif // TRI_CHANNEL
|
|
}
|
|
#if (RM_MODEL_360)
|
|
//qInfo() << "----------------------- SWAP F-----------------------";
|
|
|
|
_videoOutputR->opengl()->setRenderInfo(&fi);
|
|
_videoOutputR->setOutAspectRatioMode((FAV::VideoRenderer::OutAspectRatioMode)fi.aspectMode);
|
|
_videoOutputR->setSourceAspectRatio(fi.sourceAspectRatio);
|
|
|
|
//qInfo() << "----------------------- R -----------------------";
|
|
|
|
_videoOutputF->opengl()->setRenderInfo(&ri);
|
|
_videoOutputF->setOutAspectRatioMode((FAV::VideoRenderer::OutAspectRatioMode)ri.aspectMode);
|
|
_videoOutputF->setSourceAspectRatio(ri.sourceAspectRatio);
|
|
|
|
//_videoOutputF->widget()->setHidden(false);
|
|
//_videoOutputR->widget()->setHidden(false);
|
|
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
#if (RM_MODEL_360)
|
|
|
|
FAV::OpenGLVideo::RENDER_INFO_360 fi = {0,};
|
|
FAV::OpenGLVideo::RENDER_INFO_360 ri = {0,};
|
|
fi.aspectMode = (int)_videoOutputR->outAspectRatioMode();
|
|
fi.sourceAspectRatio = _videoOutputR->sourceAspectRatio();
|
|
ri.aspectMode = (int)_videoOutputF->outAspectRatioMode();
|
|
ri.sourceAspectRatio = _videoOutputF->sourceAspectRatio();
|
|
|
|
_videoOutputR->opengl()->getRenderInfo(&fi);
|
|
_videoOutputF->opengl()->getRenderInfo(&ri);
|
|
ri.mode = 0;
|
|
#endif
|
|
|
|
_playerF->setRenderer(_videoOutputF);
|
|
// 후방 파일이 존재하지 않을 경우
|
|
#if (FORCE_2CH)
|
|
if(_currentItem != NULL && _currentItem->filePath.length() == 0)
|
|
#else
|
|
if(_currentItem != NULL && (_currentItem->filePath.length() == 0 || _currentItem->filePathCH2.length() == 0))
|
|
#endif
|
|
{
|
|
_videoOutputR->receive(FAV::VideoFrame());
|
|
}
|
|
else
|
|
{
|
|
#if (TRI_CHANNEL)
|
|
if(isIndoor()) {
|
|
_playerI->setRenderer(_videoOutputR);
|
|
|
|
} else {
|
|
_playerR->setRenderer(_videoOutputR);
|
|
}
|
|
#else // TRI_CHANNEL
|
|
_playerR->setRenderer(_videoOutputR); // clear
|
|
#endif // TRI_CHANNEL
|
|
}
|
|
#if (RM_MODEL_360)
|
|
//qInfo() << "----------------------- RESTORE F-----------------------";
|
|
|
|
_videoOutputF->opengl()->setRenderInfo(&fi);
|
|
_videoOutputF->setSourceAspectRatio(fi.sourceAspectRatio);
|
|
_videoOutputF->setOutAspectRatioMode((FAV::VideoRenderer::OutAspectRatioMode)fi.aspectMode);
|
|
|
|
//qInfo() << "----------------------- RESTORE R-----------------------";
|
|
_videoOutputR->opengl()->setRenderInfo(&ri);
|
|
_videoOutputR->setSourceAspectRatio(ri.sourceAspectRatio);
|
|
_videoOutputR->setOutAspectRatioMode((FAV::VideoRenderer::OutAspectRatioMode)ri.aspectMode);
|
|
#endif
|
|
}
|
|
#if !(DO_NOT_USE_ZOOM)
|
|
if(_videoOutputZOOMMain != NULL) {
|
|
mainScreenPlayer()->addVideoRenderer(_videoOutputZOOMMain);
|
|
}
|
|
if(_videoOutputZOOMSub != NULL) {
|
|
subScreenPlayer()->addVideoRenderer(_videoOutputZOOMSub);
|
|
}
|
|
#endif
|
|
|
|
#if (RM_MODEL_EMT_KR)
|
|
int m0 = _videoOutputR->opengl()->mode();
|
|
_videoOutputR->opengl()->setMode(_videoOutputF->opengl()->mode());
|
|
_videoOutputF->opengl()->setMode(m0);
|
|
#endif // #if (RM_MODEL_EMT_KR)
|
|
#if (USE_SHADER_FLIP)
|
|
updateFlip(true);
|
|
updateFlip(false);
|
|
#endif // USE_SHADER_FLIP
|
|
|
|
updatePausedScreen();
|
|
|
|
emit playEvent(_swaped ? PLAY_DID_SWAPPED : PLAY_DID_UNSWAPPED, _currentItem);
|
|
}
|
|
#endif // TOGGLE_PLAYER
|
|
#endif // #if !(SINGLE_CH_VIEWER)
|
|
|
|
#if (TRI_CHANNEL)
|
|
void RMPlayer::toggleIndoor(bool forceEmit)
|
|
{
|
|
// 로딩되지 않은 상태에서도 처리
|
|
if(_eventBlocking == true)
|
|
{
|
|
return;
|
|
}
|
|
#if !(DO_NOT_USE_ZOOM)
|
|
if(_videoOutputZOOMMain != NULL) {
|
|
mainScreenPlayer()->removeVideoRenderer(_videoOutputZOOMMain);
|
|
}
|
|
if(_videoOutputZOOMSub != NULL) {
|
|
subScreenPlayer()->removeVideoRenderer(_videoOutputZOOMSub);
|
|
}
|
|
#endif
|
|
|
|
if(forceEmit == false)
|
|
{
|
|
blockEvents(200);
|
|
}
|
|
_ch3mode = !_ch3mode;
|
|
if(_ch3mode)
|
|
{
|
|
// 전방을 후방에 표시
|
|
_playerI->setRenderer(_isSwaped() ? _videoOutputF : _videoOutputR);
|
|
|
|
// 전방 파일이 존재하지 않을 경우
|
|
if(_currentItem != NULL && _currentItem->filePathCH3.length() == 0)
|
|
{
|
|
_videoOutputR->receive(FAV::VideoFrame()); // clear
|
|
}
|
|
else
|
|
{
|
|
_playerR->setRenderer(NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_playerI->setRenderer(NULL);
|
|
// 전방 파일이 존재하지 않을 경우
|
|
if(_currentItem != NULL && (_currentItem->filePathCH2.length() == 0))
|
|
{
|
|
_videoOutputR->receive(FAV::VideoFrame());
|
|
}
|
|
else
|
|
{
|
|
_playerR->setRenderer(_isSwaped() ? _videoOutputF : _videoOutputR); // clear
|
|
}
|
|
}
|
|
#if !(DO_NOT_USE_ZOOM)
|
|
if(_videoOutputZOOMMain != NULL) {
|
|
mainScreenPlayer()->addVideoRenderer(_videoOutputZOOMMain);
|
|
}
|
|
if(_videoOutputZOOMSub != NULL) {
|
|
subScreenPlayer()->addVideoRenderer(_videoOutputZOOMSub);
|
|
}
|
|
#endif
|
|
updatePausedScreen();
|
|
|
|
emit playEvent(_ch3mode ? PLAY_DID_INDOOR_CH : PLAY_DID_OUTDOOR_CH, NULL);
|
|
}
|
|
#elif (TRI_CHANNEL2)
|
|
void RMPlayer::toggleIndoor(bool forceEmit)
|
|
{
|
|
Q_UNUSED(forceEmit)
|
|
if(_currentItem->realCHCount() < 3){
|
|
return;
|
|
}
|
|
|
|
_ch3mode = !_ch3mode;
|
|
_playerR->setVideoStream(_ch3mode ? 2 : 1);
|
|
|
|
// 정지시에도 업데이트
|
|
if(_playerF->isPaused()) {
|
|
_playerR->setPosition(_playerF->position());
|
|
}
|
|
|
|
//qInfo() << "_ch3mode:" << _ch3mode << __FUNCTION__;
|
|
emit playEvent(_ch3mode ? PLAY_DID_INDOOR_CH : PLAY_DID_OUTDOOR_CH, NULL);
|
|
}
|
|
#endif // TRI_CHANNEL
|
|
|
|
#if (SUPPORT_WIDE_MODE)
|
|
bool RMPlayer::itemIsWideMode()
|
|
{
|
|
return _currentItem != NULL && _currentItem->isWideMode();
|
|
}
|
|
bool RMPlayer::isWideMode()
|
|
{
|
|
if(_currentItem == NULL || !_currentItem->isWideMode()){
|
|
return false;
|
|
}
|
|
FAV::VideoRenderer *t = _currentVideoRenderer(playerR());
|
|
return (t->opengl()->mode() == 1);
|
|
}
|
|
void RMPlayer::toggleWide() // NORMAL <-> WIDE
|
|
{
|
|
if(!_currentItem->isWideMode()){
|
|
return;
|
|
}
|
|
FAV::VideoRenderer *t = _currentVideoRenderer(playerR());
|
|
|
|
int mode = t->opengl()->mode();
|
|
t->opengl()->setMode(mode == 1 ? 0 : 1);
|
|
|
|
// RendererAspectRatio //Use renderer's aspect ratio, i.e. stretch to fit the renderer rect
|
|
// , VideoAspectRatio //Use video's aspect ratio and align center in renderer.
|
|
// , CustomAspectRation //Use the ratio set by setOutAspectRatio(qreal). Mode will be set to this if that function is called
|
|
|
|
|
|
// 정지시에도 업데이트
|
|
t->widget()->update();
|
|
// if(_playerF->isPaused()) {
|
|
// _playerR->setPosition(_playerF->position());
|
|
// }
|
|
}
|
|
#endif // RM_MODEL_EMT_KR
|
|
|
|
void RMPlayer::blockEvents(int msec,bool b_show_indicator)
|
|
{
|
|
#if !(H265_SUPPORT)
|
|
Q_UNUSED(b_show_indicator)
|
|
#endif
|
|
_eventBlocking = true;
|
|
if (_blockTimer != NULL)
|
|
{
|
|
_blockTimer->stop();
|
|
delete _blockTimer;
|
|
_blockTimer = NULL;
|
|
}
|
|
_blockTimer = new QTimer(this);
|
|
_blockTimer->setSingleShot(true);
|
|
_blockTimer->setInterval(msec);
|
|
connect(_blockTimer,SIGNAL(timeout()),SLOT(onReleaseBlockEvent()));
|
|
_blockTimer->start();
|
|
|
|
#if (H265_SUPPORT)
|
|
if (b_show_indicator == true)
|
|
{
|
|
emit show_indicator(true);
|
|
}
|
|
#endif
|
|
|
|
|
|
//QTimer::singleShot(msec,this, SLOT(onReleaseBlockEvent()));
|
|
}
|
|
void RMPlayer::onReleaseBlockEvent()
|
|
{
|
|
_eventBlocking = false;
|
|
if (_blockTimer != NULL)
|
|
{
|
|
_blockTimer->stop();
|
|
delete _blockTimer;
|
|
_blockTimer = NULL;
|
|
}
|
|
#if (H265_SUPPORT)
|
|
emit show_indicator(false);
|
|
#endif
|
|
}
|
|
QDateTime RMPlayer::currentTime(double* lon,double* lat)
|
|
{
|
|
if(!_playerF->isLoaded()) {
|
|
return QDateTime();
|
|
}
|
|
|
|
double ratio = ((double)_playerF->position()) / ((double)_playerF->duration());
|
|
return _currentItem->dateTimeInPosition(ratio,lat,lon);
|
|
}
|
|
|
|
// 타이머
|
|
void RMPlayer::timerEvent(QTimerEvent *e)
|
|
{
|
|
if (e->timerId() != _timer_id)
|
|
{
|
|
return;
|
|
}
|
|
sync_clock();
|
|
|
|
//qInfo() << "P:" << _playerF->position() << "D:" << _playerF->duration();
|
|
|
|
}
|
|
void RMPlayer::sync_clock()
|
|
{
|
|
if (_sync_time == false)
|
|
{
|
|
return;
|
|
}
|
|
#if (PLAY_SYNC_FIX2)
|
|
return;
|
|
#endif //
|
|
|
|
// seek 직후 clock 을 update 해버리면 seek 와 clock 이 delay / diff 발생 => 비디오 타이밍 매칭 하기위해 정지함
|
|
// 하지만 고속 플레이 등을 위해서는 정기적으로 동기화가 필요함....
|
|
if (!_clock->isActive())
|
|
{
|
|
return;
|
|
}
|
|
// if(_clock->value() >= _playerF->durationF())
|
|
// {
|
|
// _clock->pause(true);
|
|
// _clock->updateValue(_playerF->durationF());
|
|
// }
|
|
// 화면깨짐 방지
|
|
//#if (RM_MODEL == RM_MODEL_TYPE_KEIYO1)
|
|
//qInfo() << "$$$SYNC CLOCK" << _clock->value() << __FUNCTION__;
|
|
_playerF->masterClock()->updateExternalClock(*_clock);
|
|
// if(_playerR->isLoaded()) {
|
|
// _playerR->masterClock()->updateExternalClock(*_clock);
|
|
// }
|
|
FLOG_OT << "TIME SYNC:" << _clock->value() << FLOGE;
|
|
//#endif
|
|
}
|
|
#if (RM_TESTING)
|
|
void RMPlayer::applyTestFilter(QString filter)
|
|
{
|
|
if(_testFilterF != NULL)
|
|
{
|
|
_testFilterF->uninstall();
|
|
delete _testFilterF;
|
|
_testFilterF = NULL;
|
|
}
|
|
if(filter.length() > 0)
|
|
{
|
|
_testFilterF = new FAV::LibAVFilterVideo(_playerF);
|
|
_testFilterF->installTo(_playerF);
|
|
_testFilterF->setOptions(filter);
|
|
}
|
|
updatePausedScreenFrontOnly();
|
|
}
|
|
|
|
#endif
|