Skip to content

Commit

Permalink
添加seek和pause事件;
Browse files Browse the repository at this point in the history
pasue事件实现效果不好;
  • Loading branch information
RealChuan committed Aug 31, 2023
1 parent f48e37b commit 36fcfba
Show file tree
Hide file tree
Showing 29 changed files with 652 additions and 216 deletions.
74 changes: 35 additions & 39 deletions examples/player/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <ffmpeg/averror.h>
#include <ffmpeg/event/errorevent.hpp>
#include <ffmpeg/event/pauseevent.hpp>
#include <ffmpeg/event/seekevent.hpp>
#include <ffmpeg/event/trackevent.hpp>
#include <ffmpeg/event/valueevent.hpp>
#include <ffmpeg/ffmpegutils.hpp>
Expand Down Expand Up @@ -82,22 +84,12 @@ class MainWindow::MainWindowPrivate
void initShortcut()
{
new QShortcut(QKeySequence::MoveToNextChar, q_ptr, q_ptr, [this] {
qint64 value = controlWidget->position();
value += 5;
if (value > controlWidget->duration()) {
value = controlWidget->duration();
}
playerPtr->seek(value * AV_TIME_BASE);
setTitleWidgetText(tr("Fast forward: 5 seconds"));
Ffmpeg::EventPtr eventPtr(new Ffmpeg::SeekRelativeEvent(5));
playerPtr->addEvent(eventPtr);
});
new QShortcut(QKeySequence::MoveToPreviousChar, q_ptr, q_ptr, [this] {
qint64 value = controlWidget->position();
value -= 5;
if (value < 0) {
value = 0;
}
playerPtr->seek(value * AV_TIME_BASE);
setTitleWidgetText(tr("Fast return: 5 seconds"));
Ffmpeg::EventPtr eventPtr(new Ffmpeg::SeekRelativeEvent(-5));
playerPtr->addEvent(eventPtr);
});
new QShortcut(QKeySequence::MoveToPreviousLine, q_ptr, q_ptr, [this] {
controlWidget->setVolume(controlWidget->volume() + 5);
Expand Down Expand Up @@ -186,7 +178,7 @@ MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, d_ptr(new MainWindowPrivate(this))
{
Ffmpeg::Utils::printFfmpegInfo();
Ffmpeg::printFfmpegInfo();

setupUI();
buildConnect();
Expand Down Expand Up @@ -323,19 +315,19 @@ void MainWindow::jump(const QModelIndex &index)

void MainWindow::onProcessEvents()
{
while (d_ptr->playerPtr->eventCount() > 0) {
auto eventPtr = d_ptr->playerPtr->takeEvent();
while (d_ptr->playerPtr->propertyChangeEventSize() > 0) {
auto eventPtr = d_ptr->playerPtr->takePropertyChangeEvent();
switch (eventPtr->type()) {
case Ffmpeg::Event::EventType::DurationChanged: {
auto durationEvent = static_cast<Ffmpeg::DurationChangedEvent *>(eventPtr.data());
case Ffmpeg::PropertyChangeEvent::EventType::Duration: {
auto durationEvent = static_cast<Ffmpeg::DurationEvent *>(eventPtr.data());
d_ptr->controlWidget->setDuration(durationEvent->duration() / AV_TIME_BASE);
} break;
case Ffmpeg::Event::EventType::PositionChanged: {
auto positionEvent = static_cast<Ffmpeg::PositionChangedEvent *>(eventPtr.data());
case Ffmpeg::PropertyChangeEvent::EventType::Position: {
auto positionEvent = static_cast<Ffmpeg::PositionEvent *>(eventPtr.data());
d_ptr->controlWidget->setPosition(positionEvent->position() / AV_TIME_BASE);
} break;
case Ffmpeg::Event::EventType::MediaStateChanged: {
auto stateEvent = static_cast<Ffmpeg::MediaStateChangedEvent *>(eventPtr.data());
case Ffmpeg::PropertyChangeEvent::EventType::MediaState: {
auto stateEvent = static_cast<Ffmpeg::MediaStateEvent *>(eventPtr.data());
switch (stateEvent->state()) {
case Ffmpeg::MediaState::Stopped:
d_ptr->controlWidget->setPlayButtonChecked(false);
Expand All @@ -354,16 +346,16 @@ void MainWindow::onProcessEvents()
default: break;
}
} break;
case Ffmpeg::Event::EventType::CacheSpeedChanged: {
auto speedEvent = static_cast<Ffmpeg::CacheSpeedChangedEvent *>(eventPtr.data());
case Ffmpeg::PropertyChangeEvent::EventType::CacheSpeed: {
auto speedEvent = static_cast<Ffmpeg::CacheSpeedEvent *>(eventPtr.data());
d_ptr->controlWidget->setCacheSpeed(speedEvent->speed());
} break;
case Ffmpeg::Event::MediaTracksChanged: {
case Ffmpeg::PropertyChangeEvent::MediaTrack: {
qDeleteAll(d_ptr->audioTracksGroup->actions());
qDeleteAll(d_ptr->videoTracksGroup->actions());
qDeleteAll(d_ptr->subTracksGroup->actions());

auto tracksEvent = static_cast<Ffmpeg::TracksChangedEvent *>(eventPtr.data());
auto tracksEvent = static_cast<Ffmpeg::MediaTrackEvent *>(eventPtr.data());
auto tracks = tracksEvent->tracks();
for (const auto &track : qAsConst(tracks)) {
std::unique_ptr<QAction> actionPtr(new QAction(track.info(), this));
Expand Down Expand Up @@ -391,7 +383,18 @@ void MainWindow::onProcessEvents()
}
}
} break;
case Ffmpeg::Event::Error: {
case Ffmpeg::PropertyChangeEvent::SeekChanged: {
auto seekEvent = static_cast<Ffmpeg::SeekChangedEvent *>(eventPtr.data());
int value = seekEvent->position() * 100 / d_ptr->playerPtr->duration();
auto text = tr("Seeked To %1 (key frame) / %2 (%3%)")
.arg(QTime::fromMSecsSinceStartOfDay(seekEvent->position() / 1000)
.toString("hh:mm:ss"),
QTime::fromMSecsSinceStartOfDay(d_ptr->playerPtr->duration() / 1000)
.toString("hh:mm:ss"),
QString::number(value));
d_ptr->setTitleWidgetText(text);
} break;
case Ffmpeg::PropertyChangeEvent::Error: {
auto errorEvent = static_cast<Ffmpeg::ErrorEvent *>(eventPtr.data());
const auto text = tr("Error[%1]:%2.")
.arg(QString::number(errorEvent->error().errorCode()),
Expand Down Expand Up @@ -428,12 +431,6 @@ bool MainWindow::eventFilter(QObject *watched, QEvent *event)
auto e = static_cast<QContextMenuEvent *>(event);
d_ptr->menu->exec(e->globalPos());
} break;
// case QEvent::MouseButtonPress: {
// auto e = static_cast<QMouseEvent *>(event);
// if (e->button() & Qt::LeftButton) {
// d_ptr->mpvPlayer->pause();
// }
// } break;
case QEvent::MouseButtonDblClick:
if (isFullScreen()) {
showNormal();
Expand Down Expand Up @@ -518,16 +515,15 @@ void MainWindow::buildConnect()
connect(d_ptr->controlWidget, &ControlWidget::leavePosition, this, &MainWindow::onLeaveSlider);
connect(d_ptr->controlWidget, &ControlWidget::seek, d_ptr->playerPtr.data(), [this](int value) {
qint64 position = value;
d_ptr->playerPtr->seek(position * AV_TIME_BASE);
d_ptr->setTitleWidgetText(
tr("Fast forward to: %1")
.arg(QTime::fromMSecsSinceStartOfDay(value * 1000).toString("hh:mm:ss")));
Ffmpeg::EventPtr eventPtr(new Ffmpeg::SeekEvent(position * AV_TIME_BASE));
d_ptr->playerPtr->addEvent(eventPtr);
});
connect(d_ptr->controlWidget, &ControlWidget::play, this, [this](bool checked) {
if (checked && !d_ptr->playerPtr->isRunning())
d_ptr->playerPtr->onPlay();
else {
d_ptr->playerPtr->pause(!checked);
Ffmpeg::EventPtr eventPtr(new Ffmpeg::PauseEvent(!checked));
d_ptr->playerPtr->addEvent(eventPtr);
}
});
connect(d_ptr->controlWidget,
Expand Down
16 changes: 8 additions & 8 deletions examples/transcoder/mainwindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ class MainWindow::MainWindowPrivate
audioCodecCbx->setView(new QListView(audioCodecCbx));
audioCodecCbx->setMaxVisibleItems(10);
audioCodecCbx->setStyleSheet("QComboBox {combobox-popup:0;}");
audioCodecCbx->addItems(Ffmpeg::Utils::getCurrentSupportCodecs(AVMEDIA_TYPE_AUDIO, true));
audioCodecCbx->addItems(Ffmpeg::getCurrentSupportCodecs(AVMEDIA_TYPE_AUDIO, true));
audioCodecCbx->setCurrentIndex(audioCodecCbx->findData(AV_CODEC_ID_AAC));
audioCodecCbx->setCurrentText(avcodec_get_name(AV_CODEC_ID_AAC));

videoCodecCbx = new QComboBox(q_ptr);
videoCodecCbx->setView(new QListView(videoCodecCbx));
videoCodecCbx->setMaxVisibleItems(10);
videoCodecCbx->setStyleSheet("QComboBox {combobox-popup:0;}");
videoCodecCbx->addItems(Ffmpeg::Utils::getCurrentSupportCodecs(AVMEDIA_TYPE_VIDEO, true));
videoCodecCbx->addItems(Ffmpeg::getCurrentSupportCodecs(AVMEDIA_TYPE_VIDEO, true));
videoCodecCbx->setCurrentText(avcodec_get_name(AV_CODEC_ID_H264));

quailtySbx = new QSpinBox(q_ptr);
Expand Down Expand Up @@ -117,7 +117,7 @@ class MainWindow::MainWindowPrivate
{
bool audioSet = false;
bool videoSet = false;
auto codecs = Ffmpeg::Utils::getFileCodecInfo(filePath);
auto codecs = Ffmpeg::getFileCodecInfo(filePath);
for (const auto &codec : qAsConst(codecs)) {
if (audioSet && videoSet) {
break;
Expand Down Expand Up @@ -196,7 +196,7 @@ MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, d_ptr(new MainWindowPrivate(this))
{
Ffmpeg::Utils::printFfmpegInfo();
Ffmpeg::printFfmpegInfo();

setupUI();
buildConnect();
Expand All @@ -214,15 +214,15 @@ void MainWindow::onError(const Ffmpeg::AVError &avError)

void MainWindow::onVideoEncoderChanged()
{
auto quantizer = Ffmpeg::Utils::getCodecQuantizer(d_ptr->videoCodecCbx->currentText());
auto quantizer = Ffmpeg::getCodecQuantizer(d_ptr->videoCodecCbx->currentText());
d_ptr->quailtySbx->setRange(quantizer.first, quantizer.second);
}

void MainWindow::onOpenInputFile()
{
const QString path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
.value(0, QDir::homePath());
const QString filePath
const auto path = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation)
.value(0, QDir::homePath());
const auto filePath
= QFileDialog::getOpenFileName(this,
tr("Open File"),
path,
Expand Down
31 changes: 28 additions & 3 deletions ffmpeg/audiodecoder.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "audiodecoder.h"
#include "avcontextinfo.h"
#include "decoderaudioframe.h"
#include "ffmpegutils.hpp"

#include <event/seekevent.hpp>

#include <QDebug>

Expand All @@ -15,6 +18,23 @@ class AudioDecoder::AudioDecoderPrivate
decoderAudioFrame = new DecoderAudioFrame(q_ptr);
}

void processEvent()
{
while (q_ptr->m_runing.load() && q_ptr->m_eventQueue.size() > 0) {
auto eventPtr = q_ptr->m_eventQueue.take();
switch (eventPtr->type()) {
case Event::EventType::Pause: decoderAudioFrame->addEvent(eventPtr); break;
case Event::EventType::Seek: {
decoderAudioFrame->clear();
decoderAudioFrame->addEvent(eventPtr);
auto seekEvent = static_cast<SeekEvent *>(eventPtr.data());
seekEvent->countDown();
} break;
default: break;
}
}
}

AudioDecoder *q_ptr;

DecoderAudioFrame *decoderAudioFrame;
Expand All @@ -30,7 +50,10 @@ AudioDecoder::AudioDecoder(QObject *parent)
&AudioDecoder::positionChanged);
}

AudioDecoder::~AudioDecoder() = default;
AudioDecoder::~AudioDecoder()
{
stopDecoder();
}

void AudioDecoder::setVolume(qreal volume)
{
Expand All @@ -47,18 +70,20 @@ void AudioDecoder::runDecoder()
d_ptr->decoderAudioFrame->startDecoder(m_formatContext, m_contextInfo);

while (m_runing) {
d_ptr->processEvent();

auto packetPtr(m_queue.take());
if (packetPtr.isNull()) {
continue;
}
auto framePtrs = m_contextInfo->decodeFrame(packetPtr);
for (const auto &framePtr : framePtrs) {
Ffmpeg::calculatePts(framePtr.data(), m_contextInfo, m_formatContext);
calculatePts(framePtr.data(), m_contextInfo, m_formatContext);
d_ptr->decoderAudioFrame->append(framePtr);
}
}
while (m_runing && d_ptr->decoderAudioFrame->size() != 0) {
msleep(Sleep_Queue_Full_Milliseconds);
msleep(s_waitQueueEmptyMilliseconds);
}

d_ptr->decoderAudioFrame->stopDecoder();
Expand Down
2 changes: 1 addition & 1 deletion ffmpeg/clock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void Clock::setPaused(bool value)
QMutexLocker locker(&d_ptr->mutex);
d_ptr->paused = value;
if (!d_ptr->paused) {
d_ptr->last_updated = av_gettime_relative();
d_ptr->last_updated = 0;
}
}

Expand Down
40 changes: 0 additions & 40 deletions ffmpeg/decoder.cc
Original file line number Diff line number Diff line change
@@ -1,41 +1 @@
#include "decoder.h"
#include "frame.hpp"
#include "packet.h"

extern "C" {
#include <libavformat/avformat.h>
}

namespace Ffmpeg {

void calculatePts(Frame *frame, AVContextInfo *contextInfo, FormatContext *formatContext)
{
auto tb = contextInfo->stream()->time_base;
auto frame_rate = formatContext->guessFrameRate(contextInfo->stream());
// 当前帧播放时长
auto duration = (frame_rate.num && frame_rate.den
? av_q2d(AVRational{frame_rate.den, frame_rate.num})
: 0);
// 当前帧显示时间戳
auto *avFrame = frame->avFrame();
auto pts = (avFrame->pts == AV_NOPTS_VALUE) ? NAN : avFrame->pts * av_q2d(tb);
frame->setDuration(duration * AV_TIME_BASE);
frame->setPts(pts * AV_TIME_BASE);
// qDebug() << "Frame duration:" << duration << "pts:" << pts << "tb:" << tb.num << tb.den
// << "frame_rate:" << frame_rate.num << frame_rate.den;
}

void calculatePts(Packet *packet, AVContextInfo *contextInfo)
{
auto tb = contextInfo->stream()->time_base;
// 当前帧播放时长
auto *avPacket = packet->avPacket();
auto duration = avPacket->duration * av_q2d(tb);
// 当前帧显示时间戳
auto pts = (avPacket->pts == AV_NOPTS_VALUE) ? NAN : avPacket->pts * av_q2d(tb);
packet->setDuration(duration * AV_TIME_BASE);
packet->setPts(pts * AV_TIME_BASE);
// qDebug() << "Packet duration:" << duration << "pts:" << pts << "tb:" << tb.num << tb.den;
}

} // namespace Ffmpeg
25 changes: 17 additions & 8 deletions ffmpeg/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
#include <QSharedPointer>
#include <QThread>

#include <event/event.hpp>
#include <utils/boundedblockingqueue.hpp>
#include <utils/threadsafequeue.hpp>

#include "avcontextinfo.h"
#include "codeccontext.h"
#include "formatcontext.h"

#define Sleep_Queue_Full_Milliseconds 50

namespace Ffmpeg {

static const auto s_waitQueueEmptyMilliseconds = 50;
static const auto s_frameQueueSize = 25;

template<typename T>
Expand All @@ -24,7 +24,7 @@ class Decoder : public QThread
: QThread(parent)
, m_queue(s_frameQueueSize)
{}
~Decoder() override { stopDecoder(); }
~Decoder() override = default;

void startDecoder(FormatContext *formatContext, AVContextInfo *contextInfo)
{
Expand Down Expand Up @@ -53,7 +53,18 @@ class Decoder : public QThread

void clear() { m_queue.clear(); }

void wakeup() { m_queue.put(T()); }
void wakeup()
{
if (m_queue.empty()) {
m_queue.putHead(T());
}
}

void addEvent(const EventPtr &event)
{
m_eventQueue.put(event);
wakeup();
}

protected:
virtual void runDecoder() = 0;
Expand All @@ -74,14 +85,12 @@ class Decoder : public QThread
}

Utils::BoundedBlockingQueue<T> m_queue;
Utils::ThreadSafeQueue<EventPtr> m_eventQueue;
AVContextInfo *m_contextInfo = nullptr;
FormatContext *m_formatContext = nullptr;
std::atomic_bool m_runing = true;
};

void calculatePts(Frame *frame, AVContextInfo *contextInfo, FormatContext *formatContext);
void calculatePts(Packet *packet, AVContextInfo *contextInfo);

} // namespace Ffmpeg

#endif // DECODER_H
Loading

0 comments on commit 36fcfba

Please sign in to comment.