Skip to content

Commit

Permalink
add event mechanism;
Browse files Browse the repository at this point in the history
  • Loading branch information
RealChuan committed Aug 29, 2023
1 parent 1ea991d commit feae712
Show file tree
Hide file tree
Showing 24 changed files with 470 additions and 198 deletions.
2 changes: 1 addition & 1 deletion examples/player/controlwidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ void ControlWidget::setPosition(int value)
d_ptr->slider->blockSignals(false);
}

void ControlWidget::onReadSpeedChanged(qint64 speed)
void ControlWidget::setCacheSpeed(qint64 speed)
{
d_ptr->readSpeedLabel->setText(Utils::convertBytesToString(speed) + "/S");
}
Expand Down
3 changes: 1 addition & 2 deletions examples/player/controlwidget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ class ControlWidget : public QWidget
void setVolume(int value);
[[nodiscard]] auto volume() const -> int;

public slots:
void onReadSpeedChanged(qint64 speed);
void setCacheSpeed(qint64 speed);

signals:
void previous();
Expand Down
128 changes: 75 additions & 53 deletions examples/player/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "titlewidget.hpp"

#include <ffmpeg/averror.h>
#include <ffmpeg/event/valueevent.hpp>
#include <ffmpeg/ffmpegutils.hpp>
#include <ffmpeg/player.h>
#include <ffmpeg/videorender/videopreviewwidget.hpp>
Expand Down Expand Up @@ -121,7 +122,28 @@ class MainWindow::MainWindowPrivate
titleWidget->setVisible(visible);
}

void started()
{
controlWidget->setSourceFPS(playerPtr->fps());

auto size = playerPtr->resolutionRatio();
q_ptr->setWindowTitle(QString("%1[%2x%3]")
.arg(playlistModel->playlist()->currentMedia().fileName(),
QString::number(size.width()),
QString::number(size.height())));

fpsTimer->start(1000);
}

void finished()
{
fpsTimer->stop();
controlWidget->setDuration(0);
controlWidget->setPosition(0);
}

MainWindow *q_ptr;

QScopedPointer<Ffmpeg::Player> playerPtr;
QScopedPointer<Ffmpeg::VideoRender> videoRender;
QScopedPointer<Ffmpeg::VideoPreviewWidget> videoPreviewWidgetPtr;
Expand Down Expand Up @@ -177,26 +199,6 @@ void MainWindow::onError(const Ffmpeg::AVError &avError)
qWarning() << str;
}

void MainWindow::onStarted()
{
d_ptr->controlWidget->setSourceFPS(d_ptr->playerPtr->fps());

auto size = d_ptr->playerPtr->resolutionRatio();
setWindowTitle(QString("%1[%2x%3]")
.arg(d_ptr->playlistModel->playlist()->currentMedia().fileName(),
QString::number(size.width()),
QString::number(size.height())));

d_ptr->fpsTimer->start(1000);
}

void MainWindow::onFinished()
{
d_ptr->fpsTimer->stop();
d_ptr->controlWidget->setDuration(0);
d_ptr->controlWidget->setPosition(0);
}

void MainWindow::onHoverSlider(int pos, int value)
{
auto index = d_ptr->playerPtr->videoIndex();
Expand Down Expand Up @@ -250,12 +252,14 @@ void MainWindow::onShowCurrentFPS()

void MainWindow::onOpenLocalMedia()
{
const QString path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
.value(0, QDir::homePath());
const auto path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
.value(0, QDir::homePath());
const auto filter = tr("Media (*.mp4 *.flv *.ts *.avi *.rmvb *.mkv *.wmv *.mp3 *.wav *.flac "
"*.ape *.m4a *.aac *.ogg *.ac3 *.mpg)");
const auto urls = QFileDialog::getOpenFileUrls(this,
tr("Open File"),
path,
tr("Audio Video (*.mp3 *.mp4 *.mkv *.rmvb)"));
tr("Open Media"),
QUrl::fromUserInput(path),
filter);
if (urls.isEmpty()) {
return;
}
Expand Down Expand Up @@ -309,6 +313,48 @@ void MainWindow::jump(const QModelIndex &index)
}
}

void MainWindow::onProcessEvents()
{
while (d_ptr->playerPtr->eventCount() > 0) {
auto eventPtr = d_ptr->playerPtr->takeEvent();
switch (eventPtr->type()) {
case Ffmpeg::Event::EventType::DurationChanged: {
auto duration = static_cast<Ffmpeg::DurationChangedEvent *>(eventPtr.data());
d_ptr->controlWidget->setDuration(duration->duration() / AV_TIME_BASE);
} break;
case Ffmpeg::Event::EventType::PositionChanged: {
auto position = static_cast<Ffmpeg::PositionChangedEvent *>(eventPtr.data());
d_ptr->controlWidget->setPosition(position->position() / AV_TIME_BASE);
} break;
case Ffmpeg::Event::EventType::MediaStateChanged: {
auto state = static_cast<Ffmpeg::MediaStateChangedEvent *>(eventPtr.data());
switch (state->state()) {
case Ffmpeg::MediaState::Stopped:
d_ptr->controlWidget->setPlayButtonChecked(false);
d_ptr->finished();
break;
case Ffmpeg::MediaState::Pausing:
d_ptr->controlWidget->setPlayButtonChecked(false);
break;
case Ffmpeg::MediaState::Opening:
d_ptr->controlWidget->setPlayButtonChecked(true);
break;
case Ffmpeg::MediaState::Playing:
d_ptr->controlWidget->setPlayButtonChecked(true);
d_ptr->started();
break;
default: break;
}
} break;
case Ffmpeg::Event::EventType::CacheSpeedChanged: {
auto speed = static_cast<Ffmpeg::CacheSpeedChangedEvent *>(eventPtr.data());
d_ptr->controlWidget->setCacheSpeed(speed->speed());
} break;
default: break;
}
}
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (!d_ptr->videoRender.isNull() && watched == d_ptr->videoRender->widget()) {
Expand Down Expand Up @@ -406,14 +452,6 @@ void MainWindow::setupUI()
void MainWindow::buildConnect()
{
connect(d_ptr->playerPtr.data(), &Ffmpeg::Player::error, this, &MainWindow::onError);
connect(d_ptr->playerPtr.data(),
&Ffmpeg::Player::durationChanged,
d_ptr->controlWidget,
[this](qint64 duration) { d_ptr->controlWidget->setDuration(duration / AV_TIME_BASE); });
connect(d_ptr->playerPtr.data(),
&Ffmpeg::Player::positionChanged,
d_ptr->controlWidget,
[this](qint64 position) { d_ptr->controlWidget->setPosition(position / AV_TIME_BASE); });
connect(d_ptr->playerPtr.data(),
&Ffmpeg::Player::audioTracksChanged,
d_ptr->controlWidget,
Expand Down Expand Up @@ -464,27 +502,11 @@ void MainWindow::buildConnect()
break;
}
});
connect(d_ptr->playerPtr.data(), &Ffmpeg::Player::playStarted, this, &MainWindow::onStarted);
connect(d_ptr->playerPtr.data(), &Ffmpeg::Player::finished, this, &MainWindow::onFinished);
connect(d_ptr->playerPtr.data(),
&Ffmpeg::Player::stateChanged,
d_ptr->controlWidget,
[this](Ffmpeg::Player::MediaState state) {
switch (state) {
case Ffmpeg::Player::MediaState::StoppedState:
case Ffmpeg::Player::MediaState::PausedState:
d_ptr->controlWidget->setPlayButtonChecked(false);
break;
case Ffmpeg::Player::MediaState::PlayingState:
d_ptr->controlWidget->setPlayButtonChecked(true);
break;
default: break;
}
});

connect(d_ptr->playerPtr.data(),
&Ffmpeg::Player::readSpeedChanged,
d_ptr->controlWidget,
&ControlWidget::onReadSpeedChanged);
&Ffmpeg::Player::eventIncrease,
this,
&MainWindow::onProcessEvents);

connect(d_ptr->controlWidget,
&ControlWidget::previous,
Expand Down
4 changes: 2 additions & 2 deletions examples/player/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ class MainWindow : public QMainWindow

private slots:
void onError(const Ffmpeg::AVError &averror);
void onStarted();
void onFinished();
void onHoverSlider(int pos, int value);
void onLeaveSlider();
void onShowCurrentFPS();
Expand All @@ -29,6 +27,8 @@ private slots:
void playlistPositionChanged(int);
void jump(const QModelIndex &index);

void onProcessEvents();

protected:
auto eventFilter(QObject *watched, QEvent *event) -> bool override;
void keyPressEvent(QKeyEvent *ev) override;
Expand Down
9 changes: 7 additions & 2 deletions ffmpeg/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
set(PROJECT_SOURCES
event/errorevent.hpp
event/event.hpp
event/pauseevent.hpp
event/seekevent.hpp
event/trackevent.hpp
event/valueevent.hpp
filter/filtercontext.cc
filter/filtercontext.hpp
filter/filtergraph.cc
Expand Down Expand Up @@ -50,15 +56,14 @@ set(PROJECT_SOURCES
decodersubtitleframe.hpp
decodervideoframe.cpp
decodervideoframe.h
event.cc
event.hpp
ffmepg_global.h
ffmpegutils.cc
ffmpegutils.hpp
formatcontext.cpp
formatcontext.h
frame.cc
frame.hpp
mediainfo.hpp
packet.cpp
packet.h
player.cpp
Expand Down
45 changes: 32 additions & 13 deletions ffmpeg/clock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ class Clock::ClockPrivate
Clock *q_ptr;

mutable QMutex mutex;
qint64 pts = 0; // 当前 AVFrame 的时间戳 microseconds
qint64 pts_drift = 0; // 时钟漂移量,用于计算当前时钟的状态 microseconds
qint64 last_updated = av_gettime_relative(); // 上一次更新时钟状态的时间 microseconds
qint64 serial = s_serial.load(); // 时钟序列号 for seek
bool paused = false; // 是否暂停播放
qint64 pts = 0; // 当前 AVFrame 的时间戳 microseconds
qint64 pts_drift = 0; // 时钟漂移量,用于计算当前时钟的状态 microseconds
qint64 last_updated = 0; // 上一次更新时钟状态的时间 microseconds
qint64 serial = s_serial.load(); // 时钟序列号 for seek
bool paused = false; // 是否暂停播放

static std::atomic<qint64> s_serial;
static constexpr QPair<double, double> s_speedRange = {0.5, 3.0};
Expand All @@ -44,29 +44,41 @@ Clock::Clock(QObject *parent)

Clock::~Clock() = default;

void Clock::reset()
void Clock::reset(qint64 pts)
{
QMutexLocker locker(&d_ptr->mutex);
d_ptr->pts = 0;
d_ptr->pts = pts;
d_ptr->pts_drift = 0;
d_ptr->last_updated = av_gettime_relative();
d_ptr->serial = Clock::ClockPrivate::s_serial.load();
d_ptr->paused = false;
}

auto Clock::pts() -> qint64
void Clock::invalidate()
{
QMutexLocker locker(&d_ptr->mutex);
d_ptr->last_updated = 0;
}

auto Clock::isVaild() const -> bool
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->last_updated != 0;
}

auto Clock::pts() const -> qint64
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->pts;
}

auto Clock::ptsDrift() -> qint64
auto Clock::ptsDrift() const -> qint64
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->pts_drift;
}

auto Clock::lastUpdated() -> qint64
auto Clock::lastUpdated() const -> qint64
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->last_updated;
Expand All @@ -78,13 +90,13 @@ void Clock::resetSerial()
d_ptr->serial = Clock::ClockPrivate::s_serial.load();
}

auto Clock::serial() -> qint64
auto Clock::serial() const -> qint64
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->serial;
}

auto Clock::paused() -> bool
auto Clock::paused() const -> bool
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->paused;
Expand All @@ -108,6 +120,8 @@ void Clock::update(qint64 pts, qint64 time)
if (this == Clock::ClockPrivate::s_clock) {
qint64 timediff = (time - d_ptr->last_updated) * speed();
d_ptr->pts_drift += pts - d_ptr->pts - timediff;
} else if (Clock::ClockPrivate::s_clock->d_ptr->last_updated == 0) {
d_ptr->pts_drift = pts;
} else {
auto *masterClock = Clock::ClockPrivate::s_clock;
auto masterClockPts = masterClock->d_ptr->pts - masterClock->d_ptr->pts_drift;
Expand All @@ -119,7 +133,7 @@ void Clock::update(qint64 pts, qint64 time)
d_ptr->last_updated = time;
}

auto Clock::getDelayWithMaster(qint64 &delay) -> bool
auto Clock::getDelayWithMaster(qint64 &delay) const -> bool
{
if (serial() != Clock::ClockPrivate::s_serial.load()) {
return false;
Expand Down Expand Up @@ -177,4 +191,9 @@ void Clock::setMaster(Clock *clock)
Clock::ClockPrivate::s_clock = clock;
}

auto Clock::master() -> Clock *
{
return Clock::ClockPrivate::s_clock;
}

} // namespace Ffmpeg
18 changes: 11 additions & 7 deletions ffmpeg/clock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,25 @@ class Clock : public QObject
explicit Clock(QObject *parent = nullptr);
~Clock() override;

void reset();
void reset(qint64 pts);

auto pts() -> qint64;
auto ptsDrift() -> qint64;
auto lastUpdated() -> qint64;
void invalidate();
[[nodiscard]] auto isVaild() const -> bool;

[[nodiscard]] auto pts() const -> qint64;
[[nodiscard]] auto ptsDrift() const -> qint64;
[[nodiscard]] auto lastUpdated() const -> qint64;

void resetSerial();
auto serial() -> qint64;
[[nodiscard]] auto serial() const -> qint64;

void setPaused(bool value);
auto paused() -> bool;
[[nodiscard]] auto paused() const -> bool;

void update(qint64 pts, qint64 time);

// return true if delay is valid
auto getDelayWithMaster(qint64 &delay) -> bool;
auto getDelayWithMaster(qint64 &delay) const -> bool;

// return true if delay is valid
static auto adjustDelay(qint64 &delay) -> bool;
Expand All @@ -41,6 +44,7 @@ class Clock : public QObject

// not thread safe and not delete clock
static void setMaster(Clock *clock);
static auto master() -> Clock *;

private:
class ClockPrivate;
Expand Down
Loading

0 comments on commit feae712

Please sign in to comment.