Rabbit Remote Control 0.1.0-bate16
Loading...
Searching...
No Matches
FrmPlayer.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QKeyEvent>
4#include <QMouseEvent>
5#include <QLoggingCategory>
6#include <QToolButton>
7#include <QTime>
8#include <QVBoxLayout>
9#include <QResizeEvent>
10
11#include "FrmPlayer.h"
12#ifndef HAVE_QVideoWidget
13#include <QGraphicsVideoItem>
14#include <QGraphicsScene>
15#include <QGraphicsView>
16#endif
17
18static Q_LOGGING_CATEGORY(log, "FrmPlayer")
19
20#ifndef HAVE_QVideoWidget
21class CVideoGraphicsView : public QGraphicsView {
22public:
23 using QGraphicsView::QGraphicsView;
24protected:
25 void resizeEvent(QResizeEvent *e) override {
26 QGraphicsView::resizeEvent(e);
27 if (scene() && !scene()->items().isEmpty()) {
28 auto *item = scene()->items().first();
29 fitInView(item, Qt::KeepAspectRatio);
30 }
31 }
32};
33#endif
34
35CFrmPlayer::CFrmPlayer(QWidget *parent) : QWidget(parent)
36 , m_paStart(nullptr)
37 , m_paPause(nullptr)
38#if HAVE_QT6_RECORD
39 , m_paRecord(nullptr)
40 , m_paRecordPause(nullptr)
41#endif
42 , m_paMuted(nullptr)
43 , m_paVolume(nullptr)
44#ifdef HAVE_QVideoWidget
45 , m_pVideoWidget(nullptr)
46#else
47 , m_pGraphicsView(nullptr)
48 , m_pVideoItem(nullptr)
49#endif
50 , m_pToolBar(nullptr)
51 , tm_ToolBar(this)
52 , m_pbVideo(Qt::Horizontal, this)
53 , m_pbVolume(Qt::Horizontal, this)
54 , m_bMoveVideo(false)
55 , m_pParameter(nullptr)
56 , m_pLabel(nullptr)
57 , m_bFullScreen(false)
58{
59 bool check = false;
60
61 qDebug(log) << Q_FUNC_INFO;
62
63 setFocusPolicy(Qt::WheelFocus);
64
65 QVBoxLayout* pLayout = new QVBoxLayout(this);
66 setLayout(pLayout);
67
68#ifdef HAVE_QVideoWidget
69 m_pVideoWidget = new QVideoWidget(this);
70 m_pVideoWidget->setFocusPolicy(Qt::WheelFocus);
71 m_pVideoWidget->installEventFilter(this);
72 m_pVideoWidget->setMouseTracking(true);
73 // ← 遍历内部子对象也装过滤器 + 开 tracking
74 for (QObject *o : m_pVideoWidget->findChildren<QObject*>()) {
75 o->installEventFilter(this);
76 if (auto *w = qobject_cast<QWidget*>(o))
77 w->setMouseTracking(true);
78 }
79 pLayout->addWidget(m_pVideoWidget);
80#else
81 // 创建场景和视频项
82 QGraphicsScene *pScene = new QGraphicsScene(this);
83 m_pVideoItem = new QGraphicsVideoItem;
84 pScene->addItem(m_pVideoItem);
85 // 创建视图并添加到布局
86 m_pGraphicsView = new CVideoGraphicsView(pScene, this);
87 m_pGraphicsView->setRenderHint(QPainter::SmoothPixmapTransform);
88 m_pGraphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
89 m_pGraphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
90 m_pGraphicsView->setFrameStyle(0);
91 m_pGraphicsView->setBackgroundBrush(Qt::black);
92 m_pGraphicsView->setMouseTracking(true);
93 m_pGraphicsView->viewport()->setMouseTracking(true);
94 m_pGraphicsView->viewport()->installEventFilter(this);
95 // 关视频尺寸变化时,重新 fitInView
96 connect(m_pVideoItem, &QGraphicsVideoItem::nativeSizeChanged,
97 this, [this](const QSizeF &size) {
98 if (size.isEmpty())
99 return;
100 if(!m_pGraphicsView || !m_pVideoItem)
101 return;
102 // 让 videoItem 的矩形匹配视频原始尺寸
103 m_pVideoItem->setSize(size);
104 UpdateGraphicsVideoGeometry();
105 });
106 pLayout->addWidget((m_pGraphicsView));
107#endif
108
109 m_pToolBar = new QToolBar(this);
110 m_paStart = m_pToolBar->addAction(
111 QIcon::fromTheme("media-playback-start"), tr("Start"));
112 m_paStart->setCheckable(true);
113 check = connect(m_paStart, SIGNAL(toggled(bool)),
114 this, SLOT(slotStart(bool)));
115 Q_ASSERT(check);
116
117 m_paPause = m_pToolBar->addAction(
118 QIcon::fromTheme("media-playback-pause"), tr("pause"));
119 m_paPause->setCheckable(true);
120 m_paPause->setEnabled(false);
121
122 m_pToolBar->addSeparator();
123 m_pToolBar->addAction(QIcon::fromTheme("media-seek-backward"), tr("Backward"),
124 this, [&](){
125 qDebug(log) << "Backward action";
126 emit sigChangePosition(m_pbVideo.value() - 1000);
127 });
128
129 m_pbVideo.setRange(0, 0);
130 m_pbVideo.setValue(0);
131 m_pbVideo.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
132 check = connect(&m_pbVideo, &QSlider::sliderPressed,
133 this, [&](){
134 m_bMoveVideo = true;
135 });
136 Q_ASSERT(check);
137 check = connect(&m_pbVideo, &QSlider::sliderReleased,
138 this, [&](){
139 m_bMoveVideo = false;
140 emit sigChangePosition(m_pbVideo.value());
141 });
142 Q_ASSERT(check);
143 m_pToolBar->addWidget(&m_pbVideo);
144
145 m_pToolBar->addAction(QIcon::fromTheme("media-seek-forward"), tr("Forward"),
146 this, [&](){
147 qDebug(log) << "Forward action";
148 emit sigChangePosition(m_pbVideo.value() + 1000);
149 });
150
151 m_pToolBar->addSeparator();
152 m_pLabel = new QLabel(m_pToolBar);
153 m_pLabel->setText("00:00:00 / 00:00:00");
154 m_pToolBar->addWidget(m_pLabel);
155 m_pToolBar->addSeparator();
156
157 m_paScreenShot = m_pToolBar->addAction(
158 QIcon::fromTheme("camera-photo"), tr("ScreenShot"));
159 m_paScreenShot->setEnabled(false);
160
161#if HAVE_QT6_RECORD
162 m_paRecordPause = m_pToolBar->addAction(
163 QIcon::fromTheme("media-playback-pause"), tr("Record pause"));
164 m_paRecordPause->setCheckable(true);
165 m_paRecordPause->setEnabled(false);
166
167 m_paRecord = m_pToolBar->addAction(
168 QIcon::fromTheme("media-record"), tr("Record"));
169 m_paRecord->setCheckable(true);
170 m_paRecord->setEnabled(false);
171 check = connect(m_paRecord, &QAction::toggled, this, [&](bool checked){
172 m_paRecordPause->setEnabled(checked);
173 m_paRecordPause->setChecked(false);
174 });
175 Q_ASSERT(check);
176#endif
177
178 m_paSettings = m_pToolBar->addAction(
179 QIcon::fromTheme("system-settings"), tr("Settings"));
180
181 m_paMuted = m_pToolBar->addAction(
182 QIcon::fromTheme("audio-volume-medium"), tr("Audio"));
183 m_paMuted->setCheckable(true);
184 check = connect(m_paMuted, SIGNAL(toggled(bool)),
185 this, SLOT(slotAudioMuted(bool)));
186 Q_ASSERT(check);
187
188 m_pbVolume.setRange(0, 100);
189 m_pbVolume.setValue(0);
190 m_pbVolume.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
191 m_paVolume = m_pToolBar->addWidget(&m_pbVolume);
192 check = connect(&m_pbVolume, SIGNAL(sliderMoved(int)),
193 this, SLOT(slotAduioVolume(int)));
194 Q_ASSERT(check);
195
196 pLayout->addWidget(m_pToolBar);
197}
198
199CFrmPlayer::~CFrmPlayer()
200{
201 qDebug(log) << Q_FUNC_INFO;
202}
203
204QVideoSink *CFrmPlayer::videoSink()
205{
206#ifdef HAVE_QVideoWidget
207 return m_pVideoWidget->videoSink();
208#else
209 return m_pVideoItem->videoSink();
210#endif
211}
212
213int CFrmPlayer::SetParameter(CParameterPlayer* pParameter)
214{
215 if(!pParameter || m_pParameter == pParameter)
216 return -1;
217
218 m_pParameter = pParameter;
219
220 m_paMuted->setChecked(m_pParameter->GetAudioOutputMuted());
221 m_pbVolume.setValue(m_pParameter->GetAudioOutputVolume());
222 return 0;
223}
224
225void CFrmPlayer::slotAudioMuted(bool bMuted)
226{
227 if(!m_pParameter)
228 return;
229
230 if(bMuted) {
231 m_paMuted->setIcon(QIcon::fromTheme("audio-volume-muted"));
232 m_paMuted->setText(tr("Muted"));
233 } else {
234 m_paMuted->setIcon(QIcon::fromTheme("audio-volume-medium"));
235 m_paMuted->setText(tr("Audio"));
236 }
237 m_pParameter->SetAudioOutputMuted(bMuted);
238 m_paVolume->setEnabled(!bMuted);
239}
240
241void CFrmPlayer::slotAduioVolume(int volume)
242{
243 qDebug(log) << "Volume:" << volume;
244 if(!m_pParameter)
245 return;
246 m_pParameter->SetAudioOutputVolume(volume);
247}
248
249void CFrmPlayer::slotPositionChanged(qint64 pos, qint64 duration)
250{
251 qint64 currentInfo = pos / 1000;
252 qint64 dur = duration / 1000;
253
254 QString szStr;
255 if (currentInfo || dur) {
256 QTime currentTime((currentInfo / 3600) % 60,
257 (currentInfo / 60) % 60,
258 currentInfo % 60,
259 (currentInfo * 1000) % 1000);
260 QTime totalTime((dur / 3600) % 60,
261 (dur / 60) % 60,
262 dur % 60,
263 (dur * 1000) % 1000);
264 QString format = "mm:ss";
265 if (dur > 3600)
266 format = "hh:mm:ss";
267 szStr = currentTime.toString(format)
268 + " / " + totalTime.toString(format);
269 m_pLabel->setText(szStr);
270 m_pbVideo.setRange(0, duration);
271 if(!m_bMoveVideo)
272 m_pbVideo.setValue(pos);
273 }
274}
275
278{
279 int nRet = 0;
280 m_bFullScreen = bFull;
281 if(bFull) {
282 m_Margins = layout()->contentsMargins();
283 layout()->setContentsMargins(QMargins());
284 } else {
285 layout()->setContentsMargins(m_Margins);
286 }
287 if(m_pToolBar && m_bFullScreen)
288 m_pToolBar->hide();
289 return nRet;
290}
291
292
293void CFrmPlayer::focusInEvent(QFocusEvent *event)
294{
295 qDebug(log) << Q_FUNC_INFO << event << this;
296 Q_UNUSED(event)
297 emit sigViewerFocusIn(this);
298}
299
300void CFrmPlayer::focusOutEvent(QFocusEvent *event)
301{
302 qDebug(log) << Q_FUNC_INFO << event << this;
303 Q_UNUSED(event)
304}
305
306void CFrmPlayer::mouseMoveEvent(QMouseEvent *event)
307{
308 //qDebug(log) << Q_FUNC_INFO;
309 Q_UNUSED(event)
310 if(m_pToolBar && m_pToolBar->isHidden()) {
311 m_pToolBar->show();
312 StartTimer();
313 }
314}
315
316void CFrmPlayer::slotStart(bool bStart)
317{
318 QAction* p = qobject_cast<QAction*>(sender());
319 if(!p) return;
320 if(p->isChecked()) {
321 p->setIcon(QIcon::fromTheme("media-playback-stop"));
322 p->setText(tr("Stop"));
323 m_paPause->setEnabled(true);
324 m_paPause->setChecked(false);
325 m_paScreenShot->setEnabled(true);
326#if HAVE_QT6_RECORD
327 m_paRecord->setEnabled(true);
328 m_paRecord->setChecked(false);
329 m_paRecordPause->setEnabled(true);
330 m_paRecordPause->setChecked(false);
331#endif
332 StartTimer();
333 } else {
334 p->setIcon(QIcon::fromTheme("media-playback-start"));
335 p->setText(tr("Start"));
336 m_paPause->setEnabled(false);
337 m_paPause->setChecked(false);
338 m_paScreenShot->setEnabled(false);
339#if HAVE_QT6_RECORD
340 m_paRecord->setEnabled(false);
341 m_paRecord->setChecked(false);
342 m_paRecordPause->setEnabled(false);
343 m_paRecordPause->setChecked(false);
344#endif
345 tm_ToolBar.stop();
346 m_pToolBar->show();
347 }
348}
349
350void CFrmPlayer::slotTimeOut()
351{
352 if(!m_pToolBar)
353 return;
354 m_pToolBar->hide();
355}
356
357void CFrmPlayer::StartTimer()
358{
359 if(m_pParameter && m_pParameter->GetHideToolBar() <= 0
360 || !m_bFullScreen)
361 return;
362 if(m_paStart->isChecked()) {
363 tm_ToolBar.stop();
364 tm_ToolBar.singleShot(m_pParameter->GetHideToolBar() * 1000,
365 this, SLOT(slotTimeOut()));
366 }
367}
368
369bool CFrmPlayer::eventFilter(QObject *watched, QEvent *event)
370{
371//qDebug(log) << Q_FUNC_INFO << event;
372#ifdef HAVE_QVideoWidget
373 if(m_pVideoWidget == watched
374 || m_pVideoWidget->isAncestorOf(qobject_cast<QWidget*>(watched)))
375 {
376 switch(event->type()){
377 case QEvent::MouseMove: {
378 qDebug(log) << "Mouse move";
379 QMouseEvent* e = (QMouseEvent*)event;
380 mouseMoveEvent(e);
381 return true;
382 }
383 case QEvent::MouseButtonRelease:
384 m_paPause->trigger();
385 break;
386 case QEvent::MouseButtonDblClick: {
387 m_pVideoWidget->setFullScreen(!m_pVideoWidget->isFullScreen());
388 break;
389 }
390 case QEvent::KeyRelease:
391 {
392 QKeyEvent* k = (QKeyEvent*)(event);
393 switch(k->key())
394 {
395 case Qt::Key_Escape:
396 if(m_pVideoWidget->isFullScreen()) {
397 m_pVideoWidget->setFullScreen(false);
398 }
399 break;
400 case Qt::Key_Enter:
401 case Qt::Key_Space:
402 m_paPause->trigger();
403 break;
404 default:
405 break;
406 }
407 break;
408 }
409 case QEvent::FocusIn:
410 {
411 //qDebug(log) << Q_FUNC_INFO << event;
412 emit sigViewerFocusIn(this);
413 return false;
414 }
415 default:
416 return false;
417 }
418 return true;
419 }
420#else
421 if(m_pGraphicsView->viewport() == watched) {
422 switch(event->type()){
423 case QEvent::MouseMove: {
424 qDebug(log) << "Mouse move";
425 QMouseEvent* e = (QMouseEvent*)event;
426 mouseMoveEvent(e);
427 return true;
428 }
429 default:
430 break;
431 }
432 }
433#endif
434 return false; // 让 widget 自己继续处理
435}
436
437#ifndef HAVE_QVideoWidget
438void CFrmPlayer::UpdateGraphicsVideoGeometry()
439{
440 if (!m_pGraphicsView || !m_pVideoItem)
441 return;
442 if (m_pVideoItem->boundingRect().isEmpty())
443 return;
444
445 // 保证场景矩形和 item 一致,避免偏移
446 m_pGraphicsView->setSceneRect(m_pVideoItem->boundingRect());
447 m_pGraphicsView->fitInView(m_pVideoItem, Qt::KeepAspectRatio);
448}
449#endif
virtual void focusInEvent(QFocusEvent *event) override
[Full Screen]
Q_INVOKABLE int OnFullScreen(bool bFull)
Full Screen.
void sigViewerFocusIn(QWidget *pView)
The view is focus.