diff --git a/AVQt/CMakeLists.txt b/AVQt/CMakeLists.txt index 2d92e7ac4d5e2bf2dd1dbdb869e17b52f9dbbdda..e25acb2bbccaae27fe138b8c508326c4aa8a055c 100644 --- a/AVQt/CMakeLists.txt +++ b/AVQt/CMakeLists.txt @@ -63,6 +63,10 @@ set(SOURCES filter/private/EncoderVAAPI_p.h filter/EncoderVAAPI.cpp + output/Muxer.h + output/private/Muxer_p.h + output/Muxer.cpp + output/RenderClock.h output/private/RenderClock_p.h output/RenderClock.cpp @@ -85,6 +89,7 @@ target_compile_options(AVQt PRIVATE -Werror=all -Werror=extra -Werror=pedantic + -Wno-float-equal -ansi -Werror=init-self -Werror=old-style-cast diff --git a/AVQt/filter/AudioDecoder.cpp b/AVQt/filter/AudioDecoder.cpp index 88dbccb5171de9d27f330b56f81482340951314a..f591355a9f1d1a7714f592948ea102b2732cc874 100644 --- a/AVQt/filter/AudioDecoder.cpp +++ b/AVQt/filter/AudioDecoder.cpp @@ -10,8 +10,6 @@ #include <QtCore> -#include <AL/al.h> -#include <AL/alc.h> #include <AL/alext.h> namespace AVQt { @@ -23,9 +21,12 @@ namespace AVQt { Q_D(AVQt::AudioDecoder); } - AudioDecoder::~AudioDecoder() { - deinit(); + AudioDecoder::AudioDecoder(AudioDecoder &&other) noexcept: d_ptr(other.d_ptr) { + d_ptr->q_ptr = this; + other.d_ptr = nullptr; + } + AudioDecoder::~AudioDecoder() { delete d_ptr; d_ptr = nullptr; } @@ -128,7 +129,7 @@ namespace AVQt { return d->m_paused.load(); } - int AudioDecoder::registerCallback(IAudioSink *callback) { + qsizetype AudioDecoder::registerCallback(IAudioSink *callback) { Q_D(AVQt::AudioDecoder); QMutexLocker lock(&d->m_cbListMutex); @@ -142,12 +143,13 @@ namespace AVQt { if (d->m_running) { callback->start(this); } + return d->m_cbList.indexOf(callback); } - return 0; + return -1; } - int AudioDecoder::unregisterCallback(IAudioSink *callback) { + qsizetype AudioDecoder::unregisterCallback(IAudioSink *callback) { Q_D(AVQt::AudioDecoder); QMutexLocker lock(&d->m_cbListMutex); @@ -161,10 +163,10 @@ namespace AVQt { void AudioDecoder::init(IPacketSource *source, AVRational framerate, AVRational timebase, int64_t duration, AVCodecParameters *vParams, AVCodecParameters *aParams, AVCodecParameters *sParams) { Q_D(AVQt::AudioDecoder); - Q_UNUSED(source); - Q_UNUSED(framerate); - Q_UNUSED(vParams); - Q_UNUSED(sParams); + Q_UNUSED(source) + Q_UNUSED(framerate) + Q_UNUSED(vParams) + Q_UNUSED(sParams) d->m_timebase = timebase; d->m_duration = duration; @@ -191,21 +193,21 @@ namespace AVQt { void AudioDecoder::start(IPacketSource *source) { Q_D(AVQt::AudioDecoder); - Q_UNUSED(source); + Q_UNUSED(source) start(); } void AudioDecoder::stop(IPacketSource *source) { Q_D(AVQt::AudioDecoder); - Q_UNUSED(source); + Q_UNUSED(source) stop(); } void AudioDecoder::onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) { Q_D(AVQt::AudioDecoder); - Q_UNUSED(source); + Q_UNUSED(source) if (packetType == IPacketSource::CB_AUDIO) { AVPacket *queuePacket = av_packet_clone(packet); @@ -225,7 +227,7 @@ namespace AVQt { QTime time1 = QTime::currentTime(); qDebug("Audio packet queue size: %lld", d->m_inputQueue.size()); - int ret = 0; + int ret; constexpr size_t strBufSize = 64; char strBuf[strBufSize]; @@ -291,12 +293,13 @@ namespace AVQt { qDebug("Calling audio frame callback for PTS: %ld, Timebase: %d/%d", cbFrame->pts, d->m_timebase.num, d->m_timebase.den); QTime time = QTime::currentTime(); - cb->onAudioFrame(this, cbFrame, frame->nb_samples * 1.0 / frame->sample_rate / frame->channels * 1000.0); + cb->onAudioFrame(this, cbFrame, + static_cast<uint32_t>(frame->nb_samples * 1.0 / frame->sample_rate / frame->channels * 1000.0)); qDebug() << "Audio CB time:" << time.msecsTo(QTime::currentTime()); av_frame_unref(cbFrame); } int64_t sleepDuration = (frame->nb_samples / frame->sample_rate * 1000) - time1.msecsTo(QTime::currentTime()); - msleep(sleepDuration <= 0 ? 0 : sleepDuration); + msleep(sleepDuration <= 0 ? 0 : static_cast<unsigned long>(sleepDuration)); time1 = QTime::currentTime(); av_frame_unref(frame); } diff --git a/AVQt/filter/AudioDecoder.h b/AVQt/filter/AudioDecoder.h index 44487311c0bcdb733dc03bada30031afc37f3e0a..6b198c176cb685a2796619e19308ec1543ee16b6 100644 --- a/AVQt/filter/AudioDecoder.h +++ b/AVQt/filter/AudioDecoder.h @@ -24,13 +24,19 @@ namespace AVQt { public: explicit AudioDecoder(QObject *parent = nullptr); + AudioDecoder(AudioDecoder &&other) noexcept; + + AudioDecoder(const AudioDecoder &) = delete; + + void operator=(const AudioDecoder &) = delete; + ~AudioDecoder() Q_DECL_OVERRIDE; bool isPaused() Q_DECL_OVERRIDE; - int registerCallback(IAudioSink *callback) Q_DECL_OVERRIDE; + qsizetype registerCallback(IAudioSink *callback) Q_DECL_OVERRIDE; - int unregisterCallback(IAudioSink *callback) Q_DECL_OVERRIDE; + qsizetype unregisterCallback(IAudioSink *callback) Q_DECL_OVERRIDE; void run() Q_DECL_OVERRIDE; @@ -73,4 +79,4 @@ namespace AVQt { }; } -#endif //LIBAVQT_AUDIODECODER_H +#endif //LIBAVQT_AUDIODECODER_H \ No newline at end of file diff --git a/AVQt/filter/DecoderDXVA2.cpp b/AVQt/filter/DecoderDXVA2.cpp index 3362f7a34e45aba3775aae6a5fcbdc2f6c3027c3..151668d4b02fdcdd3f3ec9aa986422f174b6c9f9 100644 --- a/AVQt/filter/DecoderDXVA2.cpp +++ b/AVQt/filter/DecoderDXVA2.cpp @@ -10,12 +10,11 @@ #include <QApplication> #include <QtConcurrent> -#include <QImage> -#ifndef DOXYGEN_SHOULD_SKIP_THIS -#define NOW() std::chrono::high_resolution_clock::now() -#define TIME_US(t1, t2) std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() -#endif +//#ifndef DOXYGEN_SHOULD_SKIP_THIS +//#define NOW() std::chrono::high_resolution_clock::now() +//#define TIME_US(t1, t2) std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() +//#endif namespace AVQt { @@ -27,9 +26,12 @@ namespace AVQt { } - DecoderDXVA2::~DecoderDXVA2() { - deinit(); + DecoderDXVA2::DecoderDXVA2(DecoderDXVA2 &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; + } + DecoderDXVA2::~DecoderDXVA2() { delete d_ptr; } @@ -158,7 +160,7 @@ namespace AVQt { return d->m_paused.load(); } - int DecoderDXVA2::registerCallback(IFrameSink *frameSink) { + qsizetype DecoderDXVA2::registerCallback(IFrameSink *frameSink) { Q_D(AVQt::DecoderDXVA2); QMutexLocker lock(&d->m_cbListMutex); @@ -173,11 +175,11 @@ namespace AVQt { return -1; } - int DecoderDXVA2::unregisterCallback(IFrameSink *frameSink) { + qsizetype DecoderDXVA2::unregisterCallback(IFrameSink *frameSink) { Q_D(AVQt::DecoderDXVA2); QMutexLocker lock(&d->m_cbListMutex); if (d->m_cbList.contains(frameSink)) { - int result = d->m_cbList.indexOf(frameSink); + auto result = d->m_cbList.indexOf(frameSink); d->m_cbList.removeOne(frameSink); frameSink->stop(this); frameSink->deinit(this); @@ -187,7 +189,7 @@ namespace AVQt { } void DecoderDXVA2::onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) { - Q_UNUSED(source); + Q_UNUSED(source) Q_D(AVQt::DecoderDXVA2); diff --git a/AVQt/filter/DecoderDXVA2.h b/AVQt/filter/DecoderDXVA2.h index 9079a432095def79cb3ade21224bbdf3d5aa4582..501b565bfb5c70b0c20df2b5edaf1555c8bb4a8d 100644 --- a/AVQt/filter/DecoderDXVA2.h +++ b/AVQt/filter/DecoderDXVA2.h @@ -35,10 +35,10 @@ namespace AVQt { * that either at least one callback is registered or the decoder is paused, or frames will be dropped */ class DecoderDXVA2 : public QThread, public IDecoder { - Q_OBJECT - Q_INTERFACES(AVQt::IDecoder) - // Q_INTERFACES(AVQt::IFrameSource) - // Q_INTERFACES(AVQt::IPacketSink) + Q_OBJECT + Q_INTERFACES(AVQt::IDecoder) + // Q_INTERFACES(AVQt::IFrameSource) + // Q_INTERFACES(AVQt::IPacketSink) Q_DECLARE_PRIVATE(AVQt::DecoderDXVA2) @@ -52,6 +52,18 @@ namespace AVQt { */ explicit DecoderDXVA2(QObject *parent = nullptr); + DecoderDXVA2(DecoderDXVA2 &&other) noexcept; + + /*! + * \private + */ + DecoderDXVA2(const DecoderDXVA2 &) = delete; + + /*! + * \private + */ + void operator=(const DecoderDXVA2 &) = delete; + /*! * \private */ @@ -69,14 +81,14 @@ namespace AVQt { * @param type One element or some bitwise or combination of elements of IFrameSource::CB_TYPE * @return Current position in callback list */ - Q_INVOKABLE int registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; /*! * \brief Removes frame sink/filter from registry * @param frameSink Frame sink/filter to be removed * @return Last position in callback list, -1 when not found */ - Q_INVOKABLE int unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; public slots: /*! @@ -160,4 +172,4 @@ namespace AVQt { } -#endif //TRANSCODE_DECODERDXVA2_H +#endif //TRANSCODE_DECODERDXVA2_H \ No newline at end of file diff --git a/AVQt/filter/DecoderQSV.cpp b/AVQt/filter/DecoderQSV.cpp index 0ed9cf21bf62752952bdc654054c3228382bf02b..f8162528edd595a8db074f2fd399e65092f3331c 100644 --- a/AVQt/filter/DecoderQSV.cpp +++ b/AVQt/filter/DecoderQSV.cpp @@ -10,12 +10,11 @@ #include <QApplication> #include <QtConcurrent> -#include <QImage> -#ifndef DOXYGEN_SHOULD_SKIP_THIS -#define NOW() std::chrono::high_resolution_clock::now() -#define TIME_US(t1, t2) std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() -#endif +//#ifndef DOXYGEN_SHOULD_SKIP_THIS +//#define NOW() std::chrono::high_resolution_clock::now() +//#define TIME_US(t1, t2) std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() +//#endif namespace AVQt { @@ -27,9 +26,12 @@ namespace AVQt { } - DecoderQSV::~DecoderQSV() { - deinit(); + DecoderQSV::DecoderQSV(DecoderQSV &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; + } + DecoderQSV::~DecoderQSV() { delete d_ptr; } @@ -158,7 +160,7 @@ namespace AVQt { return d->m_paused.load(); } - int DecoderQSV::registerCallback(IFrameSink *frameSink) { + qsizetype DecoderQSV::registerCallback(IFrameSink *frameSink) { Q_D(AVQt::DecoderQSV); QMutexLocker lock(&d->m_cbListMutex); @@ -173,11 +175,11 @@ namespace AVQt { return -1; } - int DecoderQSV::unregisterCallback(IFrameSink *frameSink) { + qsizetype DecoderQSV::unregisterCallback(IFrameSink *frameSink) { Q_D(AVQt::DecoderQSV); QMutexLocker lock(&d->m_cbListMutex); if (d->m_cbList.contains(frameSink)) { - int result = d->m_cbList.indexOf(frameSink); + auto result = d->m_cbList.indexOf(frameSink); d->m_cbList.removeOne(frameSink); frameSink->stop(this); frameSink->deinit(this); @@ -187,7 +189,7 @@ namespace AVQt { } void DecoderQSV::onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) { - Q_UNUSED(source); + Q_UNUSED(source) Q_D(AVQt::DecoderQSV); @@ -206,7 +208,7 @@ namespace AVQt { while (d->m_running) { if (!d->m_paused.load() && !d->m_inputQueue.isEmpty()) { - int ret = 0; + int ret; constexpr size_t strBufSize = 64; char strBuf[strBufSize]; // If m_pCodecParams is nullptr, it is not initialized by packet source, if video codec context is nullptr, this is the first packet diff --git a/AVQt/filter/DecoderQSV.h b/AVQt/filter/DecoderQSV.h index 30a15ac507470295561b7d843e2af3a2b165e623..b23e824d3d77c272cbfa379ea581c391dcc6a6f8 100644 --- a/AVQt/filter/DecoderQSV.h +++ b/AVQt/filter/DecoderQSV.h @@ -52,6 +52,18 @@ namespace AVQt { */ explicit DecoderQSV(QObject *parent = nullptr); + DecoderQSV(DecoderQSV &&other) noexcept; + + /*! + * \private + */ + DecoderQSV(const DecoderQSV &) = delete; + + /*! + * \private + */ + void operator=(const DecoderQSV &) = delete; + /*! * \private */ @@ -69,14 +81,14 @@ namespace AVQt { * @param type One element or some bitwise or combination of elements of IFrameSource::CB_TYPE * @return Current position in callback list */ - Q_INVOKABLE int registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; /*! * \brief Removes frame sink/filter from registry * @param frameSink Frame sink/filter to be removed * @return Last position in callback list, -1 when not found */ - Q_INVOKABLE int unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; public slots: /*! diff --git a/AVQt/filter/DecoderVAAPI.cpp b/AVQt/filter/DecoderVAAPI.cpp index 7bd0a2e9de25b24eea7a6be0526f9355e1b3918a..9ab4713cc62e6b5515ede7cf17d882e56f1e4b7f 100644 --- a/AVQt/filter/DecoderVAAPI.cpp +++ b/AVQt/filter/DecoderVAAPI.cpp @@ -10,12 +10,11 @@ #include <QApplication> #include <QtConcurrent> -#include <QImage> -#ifndef DOXYGEN_SHOULD_SKIP_THIS -#define NOW() std::chrono::high_resolution_clock::now() -#define TIME_US(t1, t2) std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() -#endif +//#ifndef DOXYGEN_SHOULD_SKIP_THIS +//#define NOW() std::chrono::high_resolution_clock::now() +//#define TIME_US(t1, t2) std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() +//#endif namespace AVQt { @@ -27,9 +26,12 @@ namespace AVQt { } - DecoderVAAPI::~DecoderVAAPI() { - deinit(); + DecoderVAAPI::DecoderVAAPI(DecoderVAAPI &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; + } + DecoderVAAPI::~DecoderVAAPI() { delete d_ptr; } @@ -158,7 +160,7 @@ namespace AVQt { return d->m_paused.load(); } - int DecoderVAAPI::registerCallback(IFrameSink *frameSink) { + qsizetype DecoderVAAPI::registerCallback(IFrameSink *frameSink) { Q_D(AVQt::DecoderVAAPI); QMutexLocker lock(&d->m_cbListMutex); @@ -173,11 +175,11 @@ namespace AVQt { return -1; } - int DecoderVAAPI::unregisterCallback(IFrameSink *frameSink) { + qsizetype DecoderVAAPI::unregisterCallback(IFrameSink *frameSink) { Q_D(AVQt::DecoderVAAPI); QMutexLocker lock(&d->m_cbListMutex); if (d->m_cbList.contains(frameSink)) { - int result = d->m_cbList.indexOf(frameSink); + auto result = d->m_cbList.indexOf(frameSink); d->m_cbList.removeOne(frameSink); frameSink->stop(this); frameSink->deinit(this); @@ -187,7 +189,7 @@ namespace AVQt { } void DecoderVAAPI::onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) { - Q_UNUSED(source); + Q_UNUSED(source) Q_D(AVQt::DecoderVAAPI); @@ -206,7 +208,7 @@ namespace AVQt { while (d->m_running) { if (!d->m_paused.load() && !d->m_inputQueue.isEmpty()) { - int ret = 0; + int ret; constexpr size_t strBufSize = 64; char strBuf[strBufSize]; // If m_pCodecParams is nullptr, it is not initialized by packet source, if video codec context is nullptr, this is the first packet @@ -280,16 +282,16 @@ namespace AVQt { // QList<QFuture<void>> cbFutures; for (const auto &cb: d->m_cbList) { // cbFutures.append(QtConcurrent::run([=] { - AVFrame *cbFrame = av_frame_clone(frame); - cbFrame->pts = av_rescale_q(frame->pts, d->m_timebase, - av_make_q(1, 1000000)); // Rescale pts to microseconds for easier processing - qDebug("Calling video frame callback for PTS: %ld, Timebase: %d/%d", cbFrame->pts, d->m_timebase.num, - d->m_timebase.den); - QTime time = QTime::currentTime(); - cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0)); - qDebug() << "Video CB time:" << time.msecsTo(QTime::currentTime()); - av_frame_unref(cbFrame); - av_frame_free(&cbFrame); + AVFrame *cbFrame = av_frame_clone(frame); + cbFrame->pts = av_rescale_q(frame->pts, d->m_timebase, + av_make_q(1, 1000000)); // Rescale pts to microseconds for easier processing + qDebug("Calling video frame callback for PTS: %ld, Timebase: %d/%d", cbFrame->pts, d->m_timebase.num, + d->m_timebase.den); + QTime time = QTime::currentTime(); + cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0)); + qDebug() << "Video CB time:" << time.msecsTo(QTime::currentTime()); + av_frame_unref(cbFrame); + av_frame_free(&cbFrame); // })); } // bool cbBusy = true; diff --git a/AVQt/filter/DecoderVAAPI.h b/AVQt/filter/DecoderVAAPI.h index 3bb315c57201671f9de1564b70ea3116aece62b2..bab451b6ac12b6dabd6f4881d85b27169e2d1340 100644 --- a/AVQt/filter/DecoderVAAPI.h +++ b/AVQt/filter/DecoderVAAPI.h @@ -52,6 +52,18 @@ namespace AVQt { */ explicit DecoderVAAPI(QObject *parent = nullptr); + DecoderVAAPI(DecoderVAAPI &&other) noexcept; + + /*! + * \private + */ + DecoderVAAPI(const DecoderVAAPI &) = delete; + + /*! + * \private + */ + void operator=(const DecoderVAAPI &) = delete; + /*! * \private */ @@ -69,14 +81,14 @@ namespace AVQt { * @param type One element or some bitwise or combination of elements of IFrameSource::CB_TYPE * @return Current position in callback list */ - Q_INVOKABLE int registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; /*! * \brief Removes frame sink/filter from registry * @param frameSink Frame sink/filter to be removed * @return Last position in callback list, -1 when not found */ - Q_INVOKABLE int unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE; public slots: /*! @@ -160,4 +172,4 @@ namespace AVQt { } -#endif //TRANSCODE_DECODERVAAPI_H +#endif //TRANSCODE_DECODERVAAPI_H \ No newline at end of file diff --git a/AVQt/filter/EncoderVAAPI.cpp b/AVQt/filter/EncoderVAAPI.cpp index 7ce43ec0c972f188684b8bb75920865a5038ae9a..14acd26f196e12b838758759de4cf57ce9dc5c9d 100644 --- a/AVQt/filter/EncoderVAAPI.cpp +++ b/AVQt/filter/EncoderVAAPI.cpp @@ -5,7 +5,6 @@ #include "private/EncoderVAAPI_p.h" #include "EncoderVAAPI.h" -#include <QtCore> #include "output/IPacketSink.h" namespace AVQt { @@ -19,6 +18,11 @@ namespace AVQt { } + EncoderVAAPI::EncoderVAAPI(EncoderVAAPI &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; + } + EncoderVAAPI::~EncoderVAAPI() { delete d_ptr; } @@ -120,7 +124,7 @@ namespace AVQt { } int EncoderVAAPI::init(IFrameSource *source, AVRational framerate, int64_t duration) { - Q_UNUSED(source); + Q_UNUSED(source) Q_UNUSED(duration) Q_D(AVQt::EncoderVAAPI); d->m_framerate = framerate; @@ -155,7 +159,7 @@ namespace AVQt { this->pause(paused); } - qsizetype EncoderVAAPI::registerCallback(IPacketSink *packetSink, uint8_t type) { + qsizetype EncoderVAAPI::registerCallback(IPacketSink *packetSink, int8_t type) { Q_D(AVQt::EncoderVAAPI); if (type != IPacketSource::CB_VIDEO) { @@ -184,7 +188,7 @@ namespace AVQt { } void EncoderVAAPI::onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) { - Q_UNUSED(source); + Q_UNUSED(source) Q_D(AVQt::EncoderVAAPI); QPair<AVFrame *, int64_t> queueFrame{av_frame_alloc(), frameDuration}; @@ -213,7 +217,7 @@ namespace AVQt { void EncoderVAAPI::run() { Q_D(AVQt::EncoderVAAPI); - int ret{0}; + int ret; constexpr auto strBufSize{64}; char strBuf[strBufSize]; @@ -340,12 +344,8 @@ namespace AVQt { delete d_ptr; d_ptr = other.d_ptr; other.d_ptr = nullptr; + d_ptr->q_ptr = this; return *this; } - - EncoderVAAPI::EncoderVAAPI(EncoderVAAPI &&other) { - d_ptr = other.d_ptr; - other.d_ptr = nullptr; - } } \ No newline at end of file diff --git a/AVQt/filter/EncoderVAAPI.h b/AVQt/filter/EncoderVAAPI.h index 1b00d8e9ffa0a1fa179504206330a8c4bfc07c6a..dec1e74bf15450cd259f36a222e3e18d007b7ae9 100644 --- a/AVQt/filter/EncoderVAAPI.h +++ b/AVQt/filter/EncoderVAAPI.h @@ -34,19 +34,19 @@ namespace AVQt { public: explicit EncoderVAAPI(QString encoder, QObject *parent = nullptr); - explicit EncoderVAAPI(EncoderVAAPI &other) = delete; + EncoderVAAPI(EncoderVAAPI &&other) noexcept; - explicit EncoderVAAPI(EncoderVAAPI &&other); + explicit EncoderVAAPI(EncoderVAAPI &other) = delete; - ~EncoderVAAPI() override; + ~EncoderVAAPI() Q_DECL_OVERRIDE; - bool isPaused() override; + bool isPaused() Q_DECL_OVERRIDE; - qsizetype registerCallback(IPacketSink *packetSink, uint8_t type) override; + qsizetype registerCallback(IPacketSink *packetSink, int8_t type) Q_DECL_OVERRIDE; - qsizetype unregisterCallback(IPacketSink *packetSink) override; + qsizetype unregisterCallback(IPacketSink *packetSink) Q_DECL_OVERRIDE; - void run() override; + void run() Q_DECL_OVERRIDE; EncoderVAAPI &operator=(const EncoderVAAPI &other) = delete; @@ -54,35 +54,35 @@ namespace AVQt { public slots: - Q_INVOKABLE int init() override; + Q_INVOKABLE int init() Q_DECL_OVERRIDE; - Q_INVOKABLE int deinit() override; + Q_INVOKABLE int deinit() Q_DECL_OVERRIDE; - Q_INVOKABLE int start() override; + Q_INVOKABLE int start() Q_DECL_OVERRIDE; - Q_INVOKABLE int stop() override; + Q_INVOKABLE int stop() Q_DECL_OVERRIDE; - Q_INVOKABLE void pause(bool pause) override; + Q_INVOKABLE void pause(bool pause) Q_DECL_OVERRIDE; - Q_INVOKABLE int init(IFrameSource *source, AVRational framerate, int64_t duration) override; + Q_INVOKABLE int init(IFrameSource *source, AVRational framerate, int64_t duration) Q_DECL_OVERRIDE; - Q_INVOKABLE int deinit(IFrameSource *source) override; + Q_INVOKABLE int deinit(IFrameSource *source) Q_DECL_OVERRIDE; - Q_INVOKABLE int start(IFrameSource *source) override; + Q_INVOKABLE int start(IFrameSource *source) Q_DECL_OVERRIDE; - Q_INVOKABLE int stop(IFrameSource *source) override; + Q_INVOKABLE int stop(IFrameSource *source) Q_DECL_OVERRIDE; - Q_INVOKABLE void pause(IFrameSource *source, bool paused) override; + Q_INVOKABLE void pause(IFrameSource *source, bool paused) Q_DECL_OVERRIDE; - Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) override; + Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) Q_DECL_OVERRIDE; signals: - void started() override; + void started() Q_DECL_OVERRIDE; - void stopped() override; + void stopped() Q_DECL_OVERRIDE; - void paused(bool pause) override; + void paused(bool pause) Q_DECL_OVERRIDE; protected: [[maybe_unused]] explicit EncoderVAAPI(EncoderVAAPIPrivate &p); diff --git a/AVQt/filter/IDecoder.h b/AVQt/filter/IDecoder.h index 2751e39d00f9b157f3468901178c73a616e0ad77..a55e45983721ccaf7e04bbe724c4805027cef8a4 100644 --- a/AVQt/filter/IDecoder.h +++ b/AVQt/filter/IDecoder.h @@ -9,38 +9,54 @@ #define LIBAVQT_DECODER_H namespace AVQt { - class IDecoder: public IFrameSource, public IPacketSink { + class IDecoder : public IFrameSource, public IPacketSink { // IPacketSink interface public: - ~IDecoder() override {}; - virtual bool isPaused() override = 0; - virtual void init(IPacketSource *source, AVRational framerate, AVRational timebase, int64_t duration, AVCodecParameters *vParams, AVCodecParameters *aParams, AVCodecParameters *sParams) override = 0; - virtual void deinit(IPacketSource *source) override = 0; - virtual void start(IPacketSource *source) override = 0; - virtual void stop(IPacketSource *source) override = 0; - virtual void pause(bool paused) override = 0; - virtual void onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) override = 0; + ~IDecoder() Q_DECL_OVERRIDE {}; + + virtual bool isPaused() Q_DECL_OVERRIDE = 0; + + virtual void init(IPacketSource *source, AVRational framerate, AVRational timebase, int64_t duration, AVCodecParameters *vParams, + AVCodecParameters *aParams, AVCodecParameters *sParams) Q_DECL_OVERRIDE = 0; + + virtual void deinit(IPacketSource *source) Q_DECL_OVERRIDE = 0; + + virtual void start(IPacketSource *source) Q_DECL_OVERRIDE = 0; + + virtual void stop(IPacketSource *source) Q_DECL_OVERRIDE = 0; + + virtual void pause(bool paused) Q_DECL_OVERRIDE = 0; + + virtual void onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) Q_DECL_OVERRIDE = 0; signals: - virtual void started() override = 0; - virtual void stopped() override = 0; + + virtual void started() Q_DECL_OVERRIDE = 0; + + virtual void stopped() Q_DECL_OVERRIDE = 0; // IFrameSource interface public: - virtual int registerCallback(IFrameSink *frameSink) override = 0; - virtual int unregisterCallback(IFrameSink *frameSink) override = 0; - virtual int init() override = 0; - virtual int deinit() override = 0; - virtual int start() override = 0; - virtual int stop() override = 0; + virtual qsizetype registerCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE = 0; + + virtual qsizetype unregisterCallback(IFrameSink *frameSink) Q_DECL_OVERRIDE = 0; + + virtual int init() Q_DECL_OVERRIDE = 0; + + virtual int deinit() Q_DECL_OVERRIDE = 0; + + virtual int start() Q_DECL_OVERRIDE = 0; + + virtual int stop() Q_DECL_OVERRIDE = 0; signals: - virtual void paused(bool pause) override = 0; + + virtual void paused(bool pause) Q_DECL_OVERRIDE = 0; }; } Q_DECLARE_INTERFACE(AVQt::IDecoder, "AVQt::IDecoder") -#endif //LIBAVQT_DECODER_H +#endif //LIBAVQT_DECODER_H \ No newline at end of file diff --git a/AVQt/filter/IEncoder.h b/AVQt/filter/IEncoder.h index a262a025e7777991a3b0afdf49759c2d797a04d3..d3e1adafbb504db9aaa27bcb5f7346de2d8b6cbc 100644 --- a/AVQt/filter/IEncoder.h +++ b/AVQt/filter/IEncoder.h @@ -46,7 +46,7 @@ namespace AVQt { Q_INVOKABLE virtual void pause(bool pause) = 0; - Q_INVOKABLE virtual qsizetype registerCallback(IPacketSink *packetSink, uint8_t type) = 0; + Q_INVOKABLE virtual qsizetype registerCallback(IPacketSink *packetSink, int8_t type) = 0; Q_INVOKABLE virtual qsizetype unregisterCallback(IPacketSink *packetSink) = 0; diff --git a/AVQt/filter/private/AudioDecoder_p.h b/AVQt/filter/private/AudioDecoder_p.h index b766659c69a94e49902c1e37341165971a64ed80..9e11a3e02456cb3c2e08b3c17efa0fe88d282585 100644 --- a/AVQt/filter/private/AudioDecoder_p.h +++ b/AVQt/filter/private/AudioDecoder_p.h @@ -20,29 +20,35 @@ extern "C" { namespace AVQt { class AudioDecoderPrivate { + public: + AudioDecoderPrivate(const AudioDecoderPrivate &) = delete; + + void operator=(const AudioDecoderPrivate &) = delete; + + private: explicit AudioDecoderPrivate(AudioDecoder *q) : q_ptr(q) {}; AudioDecoder *q_ptr; - QMutex m_inputQueueMutex; - QQueue<AVPacket *> m_inputQueue; - int64_t m_duration {0}; + QMutex m_inputQueueMutex{}; + QQueue<AVPacket *> m_inputQueue{}; + int64_t m_duration{0}; - AVCodecParameters *m_pCodecParams {nullptr}; - AVCodec *m_pCodec {nullptr}; - AVCodecContext *m_pCodecCtx {nullptr}; - AVRational m_timebase; + AVCodecParameters *m_pCodecParams{nullptr}; + AVCodec *m_pCodec{nullptr}; + AVCodecContext *m_pCodecCtx{nullptr}; + AVRational m_timebase{0, 1}; // Callback stuff - QMutex m_cbListMutex; - QList<IAudioSink *> m_cbList; + QMutex m_cbListMutex{}; + QList<IAudioSink *> m_cbList{}; // Threading stuff - std::atomic_bool m_running {false}; - std::atomic_bool m_paused {false}; + std::atomic_bool m_running{false}; + std::atomic_bool m_paused{false}; friend class AudioDecoder; }; } -#endif //LIBAVQT_AUDIODECODER_P_H +#endif //LIBAVQT_AUDIODECODER_P_H \ No newline at end of file diff --git a/AVQt/filter/private/DecoderDXVA2_p.h b/AVQt/filter/private/DecoderDXVA2_p.h index c532b1ca1cb7d7ce8541406dd5dd8f2d50293c9f..87c8cc3f23d40035984c762d8002c4db11fb1138 100644 --- a/AVQt/filter/private/DecoderDXVA2_p.h +++ b/AVQt/filter/private/DecoderDXVA2_p.h @@ -16,6 +16,13 @@ namespace AVQt { * \private */ class DecoderDXVA2Private { + public: + DecoderDXVA2Private(const DecoderDXVA2Private &) = delete; + + void operator=(const DecoderDXVA2Private &) = delete; + + private: + explicit DecoderDXVA2Private(DecoderDXVA2 *q) : q_ptr(q) {}; DecoderDXVA2 *q_ptr; diff --git a/AVQt/filter/private/DecoderQSV_p.h b/AVQt/filter/private/DecoderQSV_p.h index 0e4112760821a0f900aa6b1b922802cddcc4985d..ef82bc0524eda150b17de6eb0fc7d0a05b6761be 100644 --- a/AVQt/filter/private/DecoderQSV_p.h +++ b/AVQt/filter/private/DecoderQSV_p.h @@ -18,15 +18,21 @@ namespace AVQt { * \private */ class DecoderQSVPrivate { + public: + DecoderQSVPrivate(const DecoderQSVPrivate &) = delete; + + void operator=(const DecoderQSVPrivate &) = delete; + + private: explicit DecoderQSVPrivate(DecoderQSV *q) : q_ptr(q) {}; DecoderQSV *q_ptr; - QMutex m_inputQueueMutex; - QQueue<AVPacket *> m_inputQueue; + QMutex m_inputQueueMutex{}; + QQueue<AVPacket *> m_inputQueue{}; int64_t m_duration{0}; - AVRational m_framerate; - AVRational m_timebase; + AVRational m_framerate{}; + AVRational m_timebase{}; AVCodec *m_pCodec{nullptr}; AVCodecParameters *m_pCodecParams{nullptr}; @@ -34,8 +40,8 @@ namespace AVQt { AVBufferRef *m_pDeviceCtx{nullptr}; // Callback stuff - QMutex m_cbListMutex; - QList<IFrameSink *> m_cbList; + QMutex m_cbListMutex{}; + QList<IFrameSink *> m_cbList{}; // Threading stuff std::atomic_bool m_running{false}; diff --git a/AVQt/filter/private/DecoderVAAPI_p.h b/AVQt/filter/private/DecoderVAAPI_p.h index 12cf4c882a9aabe536cbbcdaebbb4c435cc8f494..4a1f6f9184aa73f03283f9182804ccf9b5e9370f 100644 --- a/AVQt/filter/private/DecoderVAAPI_p.h +++ b/AVQt/filter/private/DecoderVAAPI_p.h @@ -18,15 +18,21 @@ namespace AVQt { * \private */ class DecoderVAAPIPrivate { + public: + DecoderVAAPIPrivate(const DecoderVAAPIPrivate &) = delete; + + void operator=(const DecoderVAAPIPrivate &) = delete; + + private: explicit DecoderVAAPIPrivate(DecoderVAAPI *q) : q_ptr(q) {}; DecoderVAAPI *q_ptr; - QMutex m_inputQueueMutex; - QQueue<AVPacket *> m_inputQueue; + QMutex m_inputQueueMutex{}; + QQueue<AVPacket *> m_inputQueue{}; int64_t m_duration{0}; - AVRational m_framerate; - AVRational m_timebase; + AVRational m_framerate{}; + AVRational m_timebase{}; AVCodec *m_pCodec{nullptr}; AVCodecParameters *m_pCodecParams{nullptr}; @@ -34,8 +40,8 @@ namespace AVQt { AVBufferRef *m_pDeviceCtx{nullptr}; // Callback stuff - QMutex m_cbListMutex; - QList<IFrameSink *> m_cbList; + QMutex m_cbListMutex{}; + QList<IFrameSink *> m_cbList{}; // Threading stuff std::atomic_bool m_running{false}; diff --git a/AVQt/filter/private/EncoderVAAPI_p.h b/AVQt/filter/private/EncoderVAAPI_p.h index d7be7f1186a6113d8c3a5887f39fb4ea5fd59c77..239bd63c8fde9d4705cdf6cfab0dc1cf98660e51 100644 --- a/AVQt/filter/private/EncoderVAAPI_p.h +++ b/AVQt/filter/private/EncoderVAAPI_p.h @@ -11,6 +11,12 @@ namespace AVQt { class EncoderVAAPIPrivate { + public: + EncoderVAAPIPrivate(const EncoderVAAPIPrivate &) = delete; + + void operator=(const EncoderVAAPIPrivate &) = delete; + + private: explicit EncoderVAAPIPrivate(EncoderVAAPI *q) : q_ptr(q) {}; EncoderVAAPI *q_ptr; @@ -23,11 +29,11 @@ namespace AVQt { AVBufferRef *m_pDeviceCtx{nullptr}, *m_pFramesCtx{nullptr}; AVFrame *m_pHWFrame{nullptr}; - QMutex m_inputQueueMutex; - QQueue<QPair<AVFrame *, int64_t>> m_inputQueue; + QMutex m_inputQueueMutex{}; + QQueue<QPair<AVFrame *, int64_t>> m_inputQueue{}; - QMutex m_cbListMutex; - QList<IPacketSink *> m_cbList; + QMutex m_cbListMutex{}; + QList<IPacketSink *> m_cbList{}; std::atomic_bool m_running{false}, m_paused{false}, m_firstFrame{true}; diff --git a/AVQt/input/Demuxer.cpp b/AVQt/input/Demuxer.cpp index a4fc9030b7141c2a48661b3f524ef5120e970f06..881e8063644e53536e332749a123499cd84af6dd 100644 --- a/AVQt/input/Demuxer.cpp +++ b/AVQt/input/Demuxer.cpp @@ -34,7 +34,7 @@ namespace AVQt { return d->m_paused.load(); } - qsizetype Demuxer::registerCallback(IPacketSink *packetSink, uint8_t type) { + qsizetype Demuxer::registerCallback(IPacketSink *packetSink, int8_t type) { Q_D(AVQt::Demuxer); QMutexLocker lock(&d->m_cbMutex); @@ -59,8 +59,9 @@ namespace AVQt { sParams = avcodec_parameters_alloc(); avcodec_parameters_copy(sParams, d->m_pFormatCtx->streams[d->m_subtitleStream]->codecpar); } - packetSink->init(this, d->m_pFormatCtx->streams[d->m_videoStream]->avg_frame_rate, AVRational(), - d->m_pFormatCtx->duration * 1000.0 / AV_TIME_BASE, vParams, aParams, sParams); + packetSink->init(this, d->m_pFormatCtx->streams[d->m_videoStream]->avg_frame_rate, av_make_q(1, AV_TIME_BASE), + static_cast<int64_t>(static_cast<double>(d->m_pFormatCtx->duration) * 1000.0 / AV_TIME_BASE), vParams, aParams, + sParams); if (vParams) { avcodec_parameters_free(&vParams); } @@ -118,7 +119,7 @@ namespace AVQt { avformat_find_stream_info(d->m_pFormatCtx, nullptr); // } - for (size_t si = 0; si < d->m_pFormatCtx->nb_streams; ++si) { + for (int64_t si = 0; si < d->m_pFormatCtx->nb_streams; ++si) { switch (d->m_pFormatCtx->streams[si]->codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: d->m_videoStreams.append(si); @@ -163,17 +164,20 @@ namespace AVQt { if (vParams) { cb->init(this, d->m_pFormatCtx->streams[d->m_videoStream]->avg_frame_rate, d->m_pFormatCtx->streams[d->m_videoStream]->time_base, - d->m_pFormatCtx->duration * 1000.0 / AV_TIME_BASE, vParams, nullptr, nullptr); + static_cast<int64_t>(static_cast<double>(d->m_pFormatCtx->duration) * 1000.0 / AV_TIME_BASE), vParams, nullptr, + nullptr); } if (aParams) { cb->init(this, d->m_pFormatCtx->streams[d->m_audioStream]->avg_frame_rate, d->m_pFormatCtx->streams[d->m_audioStream]->time_base, - d->m_pFormatCtx->duration * 1000.0 / AV_TIME_BASE, nullptr, aParams, nullptr); + static_cast<int64_t>(static_cast<double>(d->m_pFormatCtx->duration) * 1000.0 / AV_TIME_BASE), nullptr, aParams, + nullptr); } if (sParams) { cb->init(this, d->m_pFormatCtx->streams[d->m_subtitleStream]->avg_frame_rate, d->m_pFormatCtx->streams[d->m_subtitleStream]->time_base, - d->m_pFormatCtx->duration * 1000.0 / AV_TIME_BASE, nullptr, nullptr, sParams); + static_cast<int64_t>(static_cast<double>(d->m_pFormatCtx->duration) * 1000.0 / AV_TIME_BASE), nullptr, nullptr, + sParams); } if (vParams) { avcodec_parameters_free(&vParams); @@ -300,9 +304,12 @@ namespace AVQt { aP = QString("%1").arg(audioPackets, 12).toLocal8Bit(); vP = QString("%1").arg(videoPackets, 12).toLocal8Bit(); sP = QString("%1").arg(sttPackets, 12).toLocal8Bit(); - aR = QString("%1").arg((audioPackets * 1.0 / packetCount) * 100.0, 10).toLocal8Bit(); - vR = QString("%1").arg((videoPackets * 1.0 / packetCount) * 100.0, 10).toLocal8Bit(); - sR = QString("%1").arg((sttPackets * 1.0 / packetCount) * 100.0, 10).toLocal8Bit(); + aR = QString("%1").arg((static_cast<double>(audioPackets) * 1.0 / static_cast<double>(packetCount)) * 100.0, + 10).toLocal8Bit(); + vR = QString("%1").arg((static_cast<double>(videoPackets) * 1.0 / static_cast<double>(packetCount)) * 100.0, + 10).toLocal8Bit(); + sR = QString("%1").arg((static_cast<double>(sttPackets) * 1.0 / static_cast<double>(packetCount)) * 100.0, + 10).toLocal8Bit(); qDebug() << "Packet statistics"; qDebug() << "| Packet type | Packet count | Percentage |"; @@ -318,19 +325,9 @@ namespace AVQt { } } - Demuxer::Demuxer(Demuxer &&other) { - d_ptr = other.d_ptr; - d_ptr->q_ptr = this; + Demuxer::Demuxer(Demuxer &&other) noexcept: d_ptr(other.d_ptr) { other.d_ptr = nullptr; - } - - Demuxer &Demuxer::operator=(Demuxer &&other) noexcept { - delete d_ptr; - d_ptr = other.d_ptr; d_ptr->q_ptr = this; - other.d_ptr = nullptr; - - return *this; } int DemuxerPrivate::readFromIO(void *opaque, uint8_t *buf, int bufSize) { @@ -340,7 +337,7 @@ namespace AVQt { if (bytesRead == 0) { return AVERROR_EOF; } else { - return bytesRead; + return static_cast<int>(bytesRead); } } diff --git a/AVQt/input/Demuxer.h b/AVQt/input/Demuxer.h index 9ab24afa9987055adbf73ea7dc81b2b9df7e9351..2c66a39f53239c90cde299b4e7d3c6f854eb06b8 100644 --- a/AVQt/input/Demuxer.h +++ b/AVQt/input/Demuxer.h @@ -20,11 +20,13 @@ namespace AVQt { Q_DECLARE_PRIVATE(AVQt::Demuxer) public: - [[maybe_unused]] explicit Demuxer(QIODevice *inputDevice, QObject *parent = nullptr); + explicit Demuxer(QIODevice *inputDevice, QObject *parent = nullptr); explicit Demuxer(Demuxer &other) = delete; - explicit Demuxer(Demuxer &&other); + Demuxer &operator=(const Demuxer &other) = delete; + + Demuxer(Demuxer &&other) noexcept; /*! * \private @@ -43,7 +45,7 @@ namespace AVQt { * @param type Callback type, can be linked with bitwise or to set multiple options * @return */ - Q_INVOKABLE qsizetype registerCallback(IPacketSink *packetSink, uint8_t type) Q_DECL_OVERRIDE; + Q_INVOKABLE qsizetype registerCallback(IPacketSink *packetSink, int8_t type) Q_DECL_OVERRIDE; /*! * \brief Removes packet callback \c packetSink from registry @@ -52,10 +54,6 @@ namespace AVQt { */ Q_INVOKABLE qsizetype unregisterCallback(IPacketSink *packetSink) Q_DECL_OVERRIDE; - Demuxer &operator=(const Demuxer &other) = delete; - - Demuxer &operator=(Demuxer &&other) noexcept; - public slots: /*! * \brief Initialize packet source (e.g. open files, allocate buffers). diff --git a/AVQt/input/IAudioSource.h b/AVQt/input/IAudioSource.h index 76e30c1e18a3366b7fa1f7ebb817b6cff4861186..6c2137e700e3c232fbcfd8f1a7ff7cb3258b742b 100644 --- a/AVQt/input/IAudioSource.h +++ b/AVQt/input/IAudioSource.h @@ -18,9 +18,9 @@ namespace AVQt { virtual bool isPaused() = 0; - Q_INVOKABLE virtual int registerCallback(IAudioSink *callback) = 0; + Q_INVOKABLE virtual qsizetype registerCallback(IAudioSink *callback) = 0; - Q_INVOKABLE virtual int unregisterCallback(IAudioSink *callback) = 0; + Q_INVOKABLE virtual qsizetype unregisterCallback(IAudioSink *callback) = 0; public slots: Q_INVOKABLE virtual int init() = 0; diff --git a/AVQt/input/IFrameSource.h b/AVQt/input/IFrameSource.h index fcea49dff7b4c6bd393d2f63c29144ea89a12d8a..740bb0a45260fe1afbba9a6b8f86cb3184b4c0f9 100644 --- a/AVQt/input/IFrameSource.h +++ b/AVQt/input/IFrameSource.h @@ -63,14 +63,14 @@ namespace AVQt { * @param type Callback type, can be linked with bitwise or to set multiple options * @return */ - Q_INVOKABLE virtual int registerCallback(IFrameSink *frameSink) = 0; + Q_INVOKABLE virtual qsizetype registerCallback(IFrameSink *frameSink) = 0; /*! * \brief Removes frame callback \c frameSink from registry * @param frameSink Frame sink/filter to be removed * @return Previous position of the item, is -1 when not in registry */ - Q_INVOKABLE virtual int unregisterCallback(IFrameSink *frameSink) = 0; + Q_INVOKABLE virtual qsizetype unregisterCallback(IFrameSink *frameSink) = 0; public slots: /*! diff --git a/AVQt/input/IPacketSource.h b/AVQt/input/IPacketSource.h index de6ef2c1b1f09c5c842c5b85b90b97f857395f51..d40ff21fd854846f69cfd6f1ff5d2c7302e71260 100644 --- a/AVQt/input/IPacketSource.h +++ b/AVQt/input/IPacketSource.h @@ -57,7 +57,7 @@ namespace AVQt { * @param type Callback type, can be linked with bitwise or to set multiple options * @return */ - Q_INVOKABLE virtual qsizetype registerCallback(IPacketSink *packetSink, uint8_t type) = 0; + Q_INVOKABLE virtual qsizetype registerCallback(IPacketSink *packetSink, int8_t type) = 0; /*! * \brief Removes packet callback \c packetSink from registry diff --git a/AVQt/input/private/Demuxer_p.h b/AVQt/input/private/Demuxer_p.h index ff733d2a4c22c0ffc201764bf32a0905959d4d07..aa6cc518b355539e34baecb91b801520db1bc449 100644 --- a/AVQt/input/private/Demuxer_p.h +++ b/AVQt/input/private/Demuxer_p.h @@ -16,6 +16,12 @@ extern "C" { namespace AVQt { class DemuxerPrivate { + public: + DemuxerPrivate(const DemuxerPrivate &) = delete; + + void operator=(const DemuxerPrivate &) = delete; + + private: explicit DemuxerPrivate(Demuxer *q) : q_ptr(q) {}; static int readFromIO(void *opaque, uint8_t *buf, int bufSize); @@ -24,18 +30,18 @@ namespace AVQt { Demuxer *q_ptr; - std::atomic_bool m_running {false}, m_paused {false}, m_initialized {false}; - QMutex m_cbMutex; - QMap<IPacketSink *, int8_t> m_cbMap; + std::atomic_bool m_running{false}, m_paused{false}, m_initialized{false}; + QMutex m_cbMutex{}; + QMap<IPacketSink *, int8_t> m_cbMap{}; - QList<int> m_videoStreams, m_audioStreams, m_subtitleStreams; - int m_videoStream = -1, m_audioStream = -1, m_subtitleStream = -1; + QList<int64_t> m_videoStreams{}, m_audioStreams{}, m_subtitleStreams{}; + int64_t m_videoStream{-1}, m_audioStream{-1}, m_subtitleStream{-1}; - static constexpr size_t BUFFER_SIZE = 1024; - uint8_t *m_pBuffer {nullptr}; - AVFormatContext *m_pFormatCtx {nullptr}; - AVIOContext *m_pIOCtx {nullptr}; - QIODevice *m_inputDevice {nullptr}; + static constexpr size_t BUFFER_SIZE{1024}; + uint8_t *m_pBuffer{nullptr}; + AVFormatContext *m_pFormatCtx{nullptr}; + AVIOContext *m_pIOCtx{nullptr}; + QIODevice *m_inputDevice{nullptr}; friend class Demuxer; }; diff --git a/AVQt/output/IPacketSink.h b/AVQt/output/IPacketSink.h index 5e9ee3c0ee2378bf0fb7c10f6e4b76d88dbf1339..d922961aa0a66c3018223bc61e134156da4a8056 100644 --- a/AVQt/output/IPacketSink.h +++ b/AVQt/output/IPacketSink.h @@ -44,7 +44,7 @@ namespace AVQt { Q_INVOKABLE virtual void stop(IPacketSource *source) = 0; - Q_INVOKABLE virtual void pause(bool paused) = 0; + Q_INVOKABLE virtual void pause(bool p) = 0; /*! * \brief Callback method, is called for every registered packet type. @@ -61,6 +61,8 @@ namespace AVQt { virtual void started() = 0; virtual void stopped() = 0; + + virtual void paused(bool pause) = 0; }; } diff --git a/AVQt/output/Muxer.cpp b/AVQt/output/Muxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cff343960136270af5688c019d4660553c55c588 --- /dev/null +++ b/AVQt/output/Muxer.cpp @@ -0,0 +1,252 @@ +// +// Created by silas on 5/24/21. +// + +#include <input/IPacketSource.h> +#include "private/Muxer_p.h" +#include "Muxer.h" + +namespace AVQt { + Muxer::Muxer(QIODevice *outputDevice, QObject *parent) : QThread(parent), d_ptr(new MuxerPrivate(this)) { + Q_D(AVQt::Muxer); + d->m_outputDevice = outputDevice; + } + + Muxer::Muxer(AVQt::MuxerPrivate &p) : d_ptr(&p) { + + } + + AVQt::Muxer::Muxer(Muxer &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + } + + bool Muxer::isPaused() { + Q_D(AVQt::Muxer); + return d->m_paused.load(); + } + + void Muxer::init(IPacketSource *source, AVRational framerate, AVRational timebase, int64_t duration, AVCodecParameters *vParams, + AVCodecParameters *aParams, AVCodecParameters *sParams) { + Q_UNUSED(framerate) + Q_UNUSED(duration) + Q_D(AVQt::Muxer); + + if ((vParams && aParams) || (vParams && sParams) || (aParams && sParams)) { + qWarning("[AVQt::Muxer] init() called for multiple stream types at once. Ignoring call"); + return; + } + + if (d->m_sourceStreamMap.contains(source)) { + bool alreadyCalled = false; + for (const auto &stream: d->m_sourceStreamMap[source]) { + if ((vParams && stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || + (aParams && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) || + (sParams && stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)) { + alreadyCalled = true; + break; + } + } + if (alreadyCalled) { + qWarning("[AVQt::Muxer] init() called multiple times for the same stream type by the same source. Ignoring call"); + return; + } + } + QMutexLocker lock(&d->m_initMutex); + if (!d->m_pFormatContext) { + if (!d->m_outputDevice->isOpen()) { + if (!d->m_outputDevice->open((d->m_outputDevice->isSequential() ? QIODevice::WriteOnly : QIODevice::ReadWrite))) { + qFatal("[AVQt::Muxer] Could not open output device"); + } + } else if (!d->m_outputDevice->isWritable()) { + qFatal("[AVQt::Muxer] Output device is not writable"); + } + d->m_pFormatContext = avformat_alloc_context(); + d->m_pIOBuffer = static_cast<uint8_t *>(av_malloc(MuxerPrivate::IOBUF_SIZE)); + d->m_pIOContext = avio_alloc_context(d->m_pIOBuffer, MuxerPrivate::IOBUF_SIZE, 1, d->m_outputDevice, nullptr, + &MuxerPrivate::writeToIO, &MuxerPrivate::seekIO); + d->m_pIOContext->seekable = !d->m_outputDevice->isSequential(); + d->m_pFormatContext->pb = d->m_pIOContext; + d->m_pFormatContext->flags |= AVFMT_FLAG_CUSTOM_IO; + } + + if (!d->m_sourceStreamMap.contains(source)) { + d->m_sourceStreamMap[source] = QList<AVStream *>(); + } + if (vParams) { + AVStream *videoStream = avformat_new_stream(d->m_pFormatContext, avcodec_find_encoder(vParams->codec_id)); + videoStream->codecpar = avcodec_parameters_alloc(); + avcodec_parameters_copy(videoStream->codecpar, vParams); + videoStream->time_base = timebase; + d->m_sourceStreamMap[source].append(videoStream); + } else if (aParams) { + AVStream *audioStream = avformat_new_stream(d->m_pFormatContext, avcodec_find_encoder(aParams->codec_id)); + audioStream->codecpar = avcodec_parameters_alloc(); + avcodec_parameters_copy(audioStream->codecpar, aParams); + audioStream->time_base = timebase; + d->m_sourceStreamMap[source].append(audioStream); + } else if (sParams) { + AVStream *subtitleStream = avformat_new_stream(d->m_pFormatContext, avcodec_find_encoder(sParams->codec_id)); + subtitleStream->codecpar = avcodec_parameters_alloc(); + avcodec_parameters_copy(subtitleStream->codecpar, sParams); + subtitleStream->time_base = timebase; + d->m_sourceStreamMap[source].append(subtitleStream); + } + } + + void Muxer::deinit(IPacketSource *source) { + Q_D(AVQt::Muxer); + + if (d->m_sourceStreamMap.contains(source)) { + d->m_sourceStreamMap.remove(source); + } else { + qWarning("[AVQt::Muxer] deinit() called without preceding init() from source. Ignoring call"); + return; + } + + if (d->m_sourceStreamMap.isEmpty()) { + QMutexLocker lock(&d->m_initMutex); + if (d->m_pFormatContext) { + if (d->m_headerWritten.load()) { + av_write_trailer(d->m_pFormatContext); + } + int ret = av_interleaved_write_frame(d->m_pFormatContext, nullptr); + if (ret != 0) { + constexpr auto strBufSize = 32; + char strBuf[strBufSize]; + qWarning("%d: Couldn't flush AVFormatContext packet queue: %s", ret, av_make_error_string(strBuf, strBufSize, ret)); + } + avio_flush(d->m_pFormatContext->pb); + avio_closep(&d->m_pIOContext); + avformat_free_context(d->m_pFormatContext); + } + } + + } + + void Muxer::start(IPacketSource *source) { + Q_UNUSED(source) + Q_D(AVQt::Muxer); + + bool shouldBe = false; + if (d->m_running.compare_exchange_strong(shouldBe, true)) { + shouldBe = false; + if (d->m_headerWritten.compare_exchange_strong(shouldBe, true)) { + int ret = avformat_write_header(d->m_pFormatContext, nullptr); + if (ret != 0) { + constexpr auto strBufSize = 32; + char strBuf[strBufSize]; + qWarning("[AVQt::Muxer] %d: Couldn't init AVFormatContext: %s", ret, av_make_error_string(strBuf, strBufSize, ret)); + } + } + d->m_paused.store(false); + QThread::start(); + started(); + } + } + + void Muxer::stop(IPacketSource *source) { + Q_UNUSED(source) + Q_D(AVQt::Muxer); + + bool shouldBe = true; + if (d->m_running.compare_exchange_strong(shouldBe, false)) { + d->m_paused.store(false); + QThread::wait(); + stopped(); + } + } + + void Muxer::pause(bool p) { + Q_D(AVQt::Muxer); + + bool shouldBe = !p; + if (d->m_paused.compare_exchange_strong(shouldBe, p)) { + paused(p); + } + } + + void Muxer::onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) { + Q_D(AVQt::Muxer); + + bool unknownSource = !d->m_sourceStreamMap.contains(source); + bool initStream = false; + AVStream *addStream; + if (!unknownSource) { + for (const auto &stream : d->m_sourceStreamMap[source]) { + if ((packetType == IPacketSource::CB_VIDEO && stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || + (packetType == IPacketSource::CB_AUDIO && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) || + (packetType == IPacketSource::CB_SUBTITLE && stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)) { + addStream = stream; + initStream = true; + break; + } + } + } + if (unknownSource || !initStream) { + qWarning("[AVQt::Muxer] onPacket() called without preceding call to init() for stream type. Ignoring packet"); + return; + } + + QPair<AVPacket *, AVStream *> queuePacket{av_packet_clone(packet), addStream}; + queuePacket.first->stream_index = addStream->index; + + QMutexLocker lock(&d->m_inputQueueMutex); + d->m_inputQueue.enqueue(queuePacket); + } + + void Muxer::run() { + Q_D(AVQt::Muxer); + + while (d->m_running.load()) { + if (!d->m_paused.load()) { + QPair<AVPacket *, AVStream *> packet; + { + QMutexLocker lock(&d->m_inputQueueMutex); + packet = d->m_inputQueue.dequeue(); + } + int ret = av_interleaved_write_frame(d->m_pFormatContext, packet.first); + if (ret != 0) { + constexpr auto strBufSize = 32; + char strBuf[strBufSize]; + qWarning("%d: Couldn't write packet to AVFormatContext: %s", ret, av_make_error_string(strBuf, strBufSize, ret)); + } + } else { + msleep(4); + } + } + } + + int MuxerPrivate::writeToIO(void *opaque, uint8_t *buf, int buf_size) { + auto *outputDevice = reinterpret_cast<QIODevice *>(opaque); + + auto bytesWritten = outputDevice->write(reinterpret_cast<const char *>(buf), buf_size); + return bytesWritten == 0 ? AVERROR_UNKNOWN : static_cast<int>(bytesWritten); + } + + int64_t MuxerPrivate::seekIO(void *opaque, int64_t offset, int whence) { + auto *outputDevice = reinterpret_cast<QIODevice *>(opaque); + + if (outputDevice->isSequential()) { + return AVERROR_UNKNOWN; + } + + bool result; + switch (whence) { + case SEEK_SET: + result = outputDevice->seek(offset); + break; + case SEEK_CUR: + result = outputDevice->seek(outputDevice->pos() + offset); + break; + case SEEK_END: + result = outputDevice->seek(outputDevice->size() - offset); + break; + case AVSEEK_SIZE: + return outputDevice->size(); + default: + return AVERROR_UNKNOWN; + } + + return result ? outputDevice->pos() : AVERROR_UNKNOWN; + } +} \ No newline at end of file diff --git a/AVQt/output/Muxer.h b/AVQt/output/Muxer.h new file mode 100644 index 0000000000000000000000000000000000000000..f774631aa3505a4c3017aa18bc23af03b1cc6256 --- /dev/null +++ b/AVQt/output/Muxer.h @@ -0,0 +1,63 @@ +// +// Created by silas on 5/24/21. +// + +#include "IPacketSink.h" + +#include <QThread> + +#ifndef LIBAVQT_MUXER_H +#define LIBAVQT_MUXER_H + +namespace AVQt { + class MuxerPrivate; + + class Muxer : public QThread, public IPacketSink { + Q_OBJECT + Q_INTERFACES(AVQt::IPacketSink) + + Q_DECLARE_PRIVATE(AVQt::Muxer) + + protected: + void run() Q_DECL_OVERRIDE; + + public: + explicit Muxer(QIODevice *outputDevice, QObject *parent = nullptr); + + Muxer(Muxer &) = delete; + + Muxer(Muxer &&other) noexcept; + + bool isPaused() Q_DECL_OVERRIDE; + + void init(IPacketSource *source, AVRational framerate, AVRational timebase, int64_t duration, AVCodecParameters *vParams, + AVCodecParameters *aParams, AVCodecParameters *sParams) Q_DECL_OVERRIDE; + + void deinit(IPacketSource *source) Q_DECL_OVERRIDE; + + void start(IPacketSource *source) Q_DECL_OVERRIDE; + + void stop(IPacketSource *source) Q_DECL_OVERRIDE; + + void pause(bool p) Q_DECL_OVERRIDE; + + void onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) Q_DECL_OVERRIDE; + + void operator=(const Muxer &) = delete; + + signals: + + void started() Q_DECL_OVERRIDE; + + void stopped() Q_DECL_OVERRIDE; + + void paused(bool pause) Q_DECL_OVERRIDE; + + protected: + [[maybe_unused]] explicit Muxer(MuxerPrivate &p); + + MuxerPrivate *d_ptr; + }; +} + +#endif //LIBAVQT_MUXER_H \ No newline at end of file diff --git a/AVQt/output/OpenALAudioOutput.cpp b/AVQt/output/OpenALAudioOutput.cpp index 93afef3b12b3258921e92867470fb8fa61343055..66306e41a0b7c26ca88e4526b922b5546be02f13 100644 --- a/AVQt/output/OpenALAudioOutput.cpp +++ b/AVQt/output/OpenALAudioOutput.cpp @@ -8,9 +8,6 @@ #include "filter/private/OpenALErrorHandler.h" #include "OpenGLRenderer.h" -#include <QtCore> -#include <QtConcurrent> - namespace AVQt { OpenALAudioOutput::OpenALAudioOutput(QObject *parent) : QThread(parent), d_ptr(new OpenALAudioOutputPrivate(this)) { Q_D(AVQt::OpenALAudioOutput); @@ -18,8 +15,11 @@ namespace AVQt { } [[maybe_unused]] OpenALAudioOutput::OpenALAudioOutput(OpenALAudioOutputPrivate &p) : d_ptr(&p) { - Q_D(AVQt::OpenALAudioOutput); + } + OpenALAudioOutput::OpenALAudioOutput(OpenALAudioOutput &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; } int OpenALAudioOutput::init(IAudioSource *source, int64_t duration, int sampleRate) { @@ -54,7 +54,7 @@ namespace AVQt { qFatal("Could not make ALC context current"); } - d->m_ALBufferCount = static_cast<int>(std::ceil((1000 * 1.0 / 60) * static_cast<double>(d->m_sampleRate / 1536))); + d->m_ALBufferCount = static_cast<int>(std::ceil((1000 * 1.0 / 60) * (static_cast<double>(d->m_sampleRate) / 1536.0))); qDebug("Using %d OpenAL buffers", d->m_ALBufferCount); d->m_ALBuffers.resize(d->m_ALBufferCount); @@ -62,10 +62,10 @@ namespace AVQt { alCall(alGenBuffers, d->m_ALBufferCount, d->m_ALBuffers.data()); alCall(alGenSources, 1, &d->m_ALSource); - alCall(alSourcef, d->m_ALSource, AL_PITCH, 1); + alCall(alSourcef, d->m_ALSource, AL_PITCH, 1.0f); alCall(alSourcef, d->m_ALSource, AL_GAIN, 1.0f); - alCall(alSource3f, d->m_ALSource, AL_POSITION, 0, 0, 0); - alCall(alSource3f, d->m_ALSource, AL_VELOCITY, 0, 0, 0); + alCall(alSource3f, d->m_ALSource, AL_POSITION, 0.f, 0.f, 0.f); + alCall(alSource3f, d->m_ALSource, AL_VELOCITY, 0.f, 0.f, 0.f); alCall(alSourcei, d->m_ALSource, AL_LOOPING, AL_FALSE); alCall(alSourcei, d->m_ALSource, AL_BUFFER, 0); @@ -244,8 +244,10 @@ namespace AVQt { { QMutexLocker lock(&d->m_swrContextMutex); if (!d->m_pSwrContext && frame->format != AV_SAMPLE_FMT_S16) { - d->m_pSwrContext = swr_alloc_set_opts(nullptr, frame->channel_layout, AV_SAMPLE_FMT_S16, frame->sample_rate, - frame->channel_layout, static_cast<AVSampleFormat>(frame->format), frame->sample_rate, + d->m_pSwrContext = swr_alloc_set_opts(nullptr, static_cast<int64_t>(frame->channel_layout), AV_SAMPLE_FMT_S16, + frame->sample_rate, + static_cast<int64_t>(frame->channel_layout), + static_cast<AVSampleFormat>(frame->format), frame->sample_rate, 0, nullptr); swr_init(d->m_pSwrContext); } @@ -307,16 +309,17 @@ namespace AVQt { d->m_clock.store(renderer->getClock()); clockIntervalChanged(d->m_clock.load()->getInterval()); - int newBufferCount = static_cast<int>(std::ceil((1000 * 1.0 / static_cast<double>(d->m_clockInterval) * static_cast<double>(d->m_sampleRate) / 1536))); + int newBufferCount = static_cast<int>(std::ceil( + (1000 * 1.0 / static_cast<double>(d->m_clockInterval) * static_cast<double>(d->m_sampleRate) / 1536))); if (d->m_ALBuffers.size() != newBufferCount) { ALCboolean contextCurrent = ALC_FALSE; alcCall(alcMakeContextCurrent, contextCurrent, d->m_ALCDevice, d->m_ALCContext); if (d->m_ALBuffers.size() > newBufferCount) { - auto overhead = d->m_ALBuffers.size() - newBufferCount; + int overhead = static_cast<int>(d->m_ALBuffers.size() - newBufferCount); alCall(alDeleteBuffers, overhead, d->m_ALBuffers.data() + d->m_ALBuffers.size() - overhead); d->m_ALBuffers.resize(newBufferCount); } else if (d->m_ALBuffers.size() < newBufferCount) { - auto extraBuffers = newBufferCount - d->m_ALBuffers.size(); + int extraBuffers = static_cast<int>(newBufferCount - d->m_ALBuffers.size()); d->m_ALBuffers.resize(newBufferCount); alCall(alGenBuffers, extraBuffers, d->m_ALBuffers.data() + d->m_ALBuffers.size() - extraBuffers); } @@ -369,24 +372,28 @@ namespace AVQt { } if (!d->m_ALBufferQueue.isEmpty()) { QMutexLocker lock3(&d->m_ALBufferQueueMutex); - alCall(alSourceQueueBuffers, d->m_ALSource, std::min(d->m_ALBufferQueue.size(), static_cast<typeof (d->m_ALBufferQueue.size())>(4)), d->m_ALBufferQueue.toVector().data()); - for (const auto &buf: QList(d->m_ALBufferQueue.end() - std::min(d->m_ALBufferQueue.size(), static_cast<typeof (d->m_ALBufferQueue.size())>(4)), d->m_ALBufferQueue.end())) { + alCall(alSourceQueueBuffers, d->m_ALSource, static_cast<int>(qMin(d->m_ALBufferQueue.size(), 4)), + d->m_ALBufferQueue.toVector().data()); + for (const auto &buf: QList(d->m_ALBufferQueue.end() - static_cast<int>(qMin(d->m_ALBufferQueue.size(), 4)), + d->m_ALBufferQueue.end())) { d->m_queuedSamples += d->m_ALBufferSampleMap[buf]; } if (d->m_ALBufferQueue.size() < 4) { - alCall(alSourceQueueBuffers, d->m_ALSource, std::min(buffers.size(), 4 - d->m_ALBufferQueue.size()), buffers.data()); - for (qint64 i = buffers.size() - std::min(buffers.size(), 4 - d->m_ALBufferQueue.size()); i < buffers.size(); ++i) { + alCall(alSourceQueueBuffers, d->m_ALSource, static_cast<int>(qMin(buffers.size(), 4 - d->m_ALBufferQueue.size())), + buffers.data()); + for (qint64 i = static_cast<int>(buffers.size() - qMin(buffers.size(), 4 - d->m_ALBufferQueue.size())); + i < buffers.size(); ++i) { d->m_queuedSamples += d->m_ALBufferSampleMap[buffers[i]]; } - buffers.remove(buffers.size() - std::min(buffers.size(), 4 - d->m_ALBufferQueue.size()), - std::min(buffers.size(), 4 - d->m_ALBufferQueue.size())); + buffers.remove(buffers.size() - qMin(buffers.size(), 4 - d->m_ALBufferQueue.size()), + qMin(buffers.size(), 4 - d->m_ALBufferQueue.size())); d->m_ALBufferQueue.append(buffers.toList()); } d->m_ALBufferQueue.clear(); } else { QMutexLocker lock3(&d->m_ALBufferQueueMutex); - alCall(alSourceQueueBuffers, d->m_ALSource, std::min(buffers.size(), static_cast<typeof (d->m_ALBufferQueue.size())>(4)), buffers.data()); - buffers.remove(buffers.size() - std::min(buffers.size(), static_cast<typeof (d->m_ALBufferQueue.size())>(4)), std::min(buffers.size(), static_cast<typeof (d->m_ALBufferQueue.size())>(4))); + alCall(alSourceQueueBuffers, d->m_ALSource, static_cast<int>(qMin(buffers.size(), 4)), buffers.data()); + buffers.remove(buffers.size() - qMin(buffers.size(), 4), qMin(buffers.size(), 4)); d->m_ALBufferQueue.append(buffers.toList()); } } else { @@ -461,7 +468,8 @@ namespace AVQt { } while (!d->m_inputQueue.isEmpty() && !d->m_ALBufferQueue.isEmpty()) { - if (d->m_queuedSamples * 1.0 / d->m_inputQueue.front().first->sample_rate < d->m_clockInterval * 1.5) { + if (static_cast<double>(d->m_queuedSamples) * 1.0 / d->m_inputQueue.front().first->sample_rate < + static_cast<double>(d->m_clockInterval) * 1.5) { lock.relock(); QMutexLocker lock1(&d->m_inputQueueMutex); QMutexLocker lock2(&d->m_ALBufferSampleMapMutex); @@ -482,7 +490,7 @@ namespace AVQt { // } else { frame = d->m_inputQueue.dequeue(); // } - duration += frame.first->nb_samples * 1000.0 / frame.first->sample_rate; + duration += static_cast<int64_t>(std::round(frame.first->nb_samples * 1000.0 / frame.first->sample_rate)); lock1.unlock(); auto buf = d->m_ALBufferQueue.dequeue(); lock.unlock(); diff --git a/AVQt/output/OpenALAudioOutput.h b/AVQt/output/OpenALAudioOutput.h index 476bcf076196d722070f2b05d96f04f3482e2593..2e05a19dbfce87d2e65f7b3e9e1626adfafc9afd 100644 --- a/AVQt/output/OpenALAudioOutput.h +++ b/AVQt/output/OpenALAudioOutput.h @@ -24,6 +24,12 @@ namespace AVQt { public: explicit OpenALAudioOutput(QObject *parent = nullptr); + OpenALAudioOutput(OpenALAudioOutput &&other) noexcept; + + OpenALAudioOutput(const OpenALAudioOutput &) = delete; + + void operator=(const OpenALAudioOutput &) = delete; + Q_INVOKABLE bool isPaused() Q_DECL_OVERRIDE; void run() Q_DECL_OVERRIDE; @@ -66,4 +72,4 @@ namespace AVQt { } -#endif //LIBAVQT_OPENALAUDIOOUTPUT_H +#endif //LIBAVQT_OPENALAUDIOOUTPUT_H \ No newline at end of file diff --git a/AVQt/output/OpenGLRenderer.cpp b/AVQt/output/OpenGLRenderer.cpp index 1a696ba9f72d46779734620cd1ea6eaad4e46d88..b1e9c2cc784c5bab54b281fac179a8e47d8392f7 100644 --- a/AVQt/output/OpenGLRenderer.cpp +++ b/AVQt/output/OpenGLRenderer.cpp @@ -6,7 +6,6 @@ #include "OpenGLRenderer.h" #include <QtGui> -#include <iostream> extern "C" { #include <libavutil/frame.h> @@ -27,6 +26,11 @@ namespace AVQt { [[maybe_unused]] [[maybe_unused]] OpenGLRenderer::OpenGLRenderer(OpenGLRendererPrivate &p) : d_ptr(&p) { } + OpenGLRenderer::OpenGLRenderer(OpenGLRenderer &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; + } + OpenGLRenderer::~OpenGLRenderer() noexcept { Q_D(AVQt::OpenGLRenderer); @@ -37,14 +41,9 @@ namespace AVQt { Q_UNUSED(framerate) // Don't use framerate, because it is not always specified in stream information Q_UNUSED(source) Q_D(AVQt::OpenGLRenderer); - int64_t h = duration / 3600000; - int64_t m = (duration - h * 3600000) / 60000; - int64_t s = (duration - h * 3600000 - m * 60000) / 1000; - int64_t ms = duration - h * 3600000 - m * 60000 - s * 1000; - d->m_duration = QTime(static_cast<int>(h), static_cast<int>(m), static_cast<int>(s), static_cast<int>(ms)); - d->m_position = QTime(0, 0, 0, 0); - qDebug() << "Duration:" << d->m_duration.toString("hh:mm:ss"); + d->m_duration = OpenGLRendererPrivate::timeFromMillis(duration); + qDebug() << "Duration:" << d->m_duration.toString("hh:mm:ss.zzz"); d->m_clock = new RenderClock; d->m_clock->setInterval(16); @@ -104,20 +103,18 @@ namespace AVQt { d->m_vbo.destroy(); d->m_vao.destroy(); - if (d->m_yTexture) { // d->m_yTexture->destroy(); - delete d->m_yTexture; - } + delete d->m_yTexture; + - if (d->m_uTexture) { // d->m_uTexture->destroy(); - delete d->m_uTexture; - } + delete d->m_uTexture; + + - if (d->m_vTexture) { // d->m_yTexture->destroy(); - delete d->m_vTexture; - } + delete d->m_vTexture; + stopped(); return 0; @@ -510,7 +507,12 @@ namespace AVQt { // qDebug() << "Current timestamp:" << d->m_position.toString("hh:mm:ss.zzz"); - QString overlay(d->m_position.toString("hh:mm:ss") + "/" + d->m_duration.toString("hh:mm:ss")); + QTime position{0, 0, 0, 0}; + if (d->m_currentFrame) { + position = OpenGLRendererPrivate::timeFromMillis(d->m_currentFrame->pts / 1000); + } + + QString overlay(position.toString("hh:mm:ss.zzz") + "/" + d->m_duration.toString("hh:mm:ss.zzz")); QFontMetrics fm(roboto); p.fillRect(fm.boundingRect(overlay).translated(static_cast<int>(textPosX), static_cast<int>(textPosY)).adjusted(-5, -5, 5, 5), QColor(0xFF, 0xFF, 0xFF, 0x48)); @@ -528,14 +530,6 @@ namespace AVQt { } } - void OpenGLRenderer::triggerUpdate(qint64 timestamp) { - Q_UNUSED(timestamp) - Q_D(AVQt::OpenGLRenderer); - -// d->m_updateRequired.store(true); -// d->m_updateTimestamp.store(timestamp); - } - RenderClock *OpenGLRenderer::getClock() { Q_D(AVQt::OpenGLRenderer); return d->m_clock; @@ -552,7 +546,7 @@ namespace AVQt { transformPoint(out, model, in); transformPoint(in, proj, out); - if (in[3] == 0.0) + if (in[3] < 0.0001) return GL_FALSE; in[0] /= in[3]; @@ -575,4 +569,12 @@ namespace AVQt { #undef M } + QTime OpenGLRendererPrivate::timeFromMillis(int64_t ts) { + int ms = static_cast<int>(ts % 1000); + int s = static_cast<int>((ts / 1000) % 60); + int m = static_cast<int>((ts / 1000 / 60) % 60); + int h = static_cast<int>(ts / 1000 / 60 / 60); + return QTime(h, m, s, ms); + } + } \ No newline at end of file diff --git a/AVQt/output/OpenGLRenderer.h b/AVQt/output/OpenGLRenderer.h index 96216b70d6e902930edc78c59b1ddee910841f8e..a872577af3fb93025e832149b43dc68b52218841 100644 --- a/AVQt/output/OpenGLRenderer.h +++ b/AVQt/output/OpenGLRenderer.h @@ -29,6 +29,12 @@ namespace AVQt { public: explicit OpenGLRenderer(QWindow *parent = nullptr); + OpenGLRenderer(OpenGLRenderer &&other) noexcept; + + OpenGLRenderer(const OpenGLRenderer &) = delete; + + void operator=(const OpenGLRenderer &) = delete; + ~OpenGLRenderer() noexcept; bool isPaused() Q_DECL_OVERRIDE; @@ -88,11 +94,6 @@ namespace AVQt { */ Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) Q_DECL_OVERRIDE; - /*! - * \private - */ - void triggerUpdate(qint64 timestamp); - signals: void started() Q_DECL_OVERRIDE; @@ -115,4 +116,4 @@ namespace AVQt { } -#endif //LIBAVQT_OPENGLRENDERER_H +#endif //LIBAVQT_OPENGLRENDERER_H \ No newline at end of file diff --git a/AVQt/output/RenderClock.cpp b/AVQt/output/RenderClock.cpp index 723b01d6e8a30b26537ea60df2ca9ce2fe8158fe..2d19d3edea4d93af669e2a22dff2158f7e8a7e06 100644 --- a/AVQt/output/RenderClock.cpp +++ b/AVQt/output/RenderClock.cpp @@ -24,6 +24,11 @@ namespace AVQt { connect(d->m_timer, &QTimer::timeout, this, &RenderClock::timerTimeout); } + RenderClock::RenderClock(RenderClock &&other) noexcept: d_ptr(other.d_ptr) { + other.d_ptr = nullptr; + d_ptr->q_ptr = this; + } + RenderClock::~RenderClock() { Q_D(AVQt::RenderClock); @@ -78,13 +83,13 @@ namespace AVQt { } } - void RenderClock::setInterval(int64_t interval) { + void RenderClock::setInterval(int interval) { Q_D(AVQt::RenderClock); - if (interval > 0 && interval != d->m_interval.load()) { + if (interval > 0 && interval != d->m_interval) { d->m_interval.store(interval); - d->m_timer->setInterval(d->m_interval.load()); + d->m_timer->setInterval(d->m_interval); d->m_timer->stop(); d->m_timer->start(); diff --git a/AVQt/output/RenderClock.h b/AVQt/output/RenderClock.h index 6e1ee39d1ddda44555ea7db5519717fc26aa0c7f..3cb95b65c0d25fa3348e511ad2a1e134365b9360 100644 --- a/AVQt/output/RenderClock.h +++ b/AVQt/output/RenderClock.h @@ -18,9 +18,15 @@ namespace AVQt { public: explicit RenderClock(QObject *parent = nullptr); + RenderClock(RenderClock &&other) noexcept; + + RenderClock(const RenderClock &) = delete; + + void operator=(const RenderClock &) = delete; + ~RenderClock(); - void setInterval(int64_t interval); + void setInterval(int interval); int64_t getInterval(); @@ -55,6 +61,7 @@ namespace AVQt { RenderClockPrivate *d_ptr; private slots: + void timerTimeout(); }; diff --git a/AVQt/output/private/Muxer_p.h b/AVQt/output/private/Muxer_p.h new file mode 100644 index 0000000000000000000000000000000000000000..8b0fa50e776d45afcf836ab1f1f58fb10414b188 --- /dev/null +++ b/AVQt/output/private/Muxer_p.h @@ -0,0 +1,53 @@ +// +// Created by silas on 5/24/21. +// + +#include "../Muxer.h" + +extern "C" { +#include <libavformat/avformat.h> +#include <libavcodec/packet.h> +} + +#include <QtCore> + +#ifndef LIBAVQT_MUXER_P_H +#define LIBAVQT_MUXER_P_H + +namespace AVQt { + class MuxerPrivate { + public: + MuxerPrivate(const MuxerPrivate &) = delete; + + void operator=(const MuxerPrivate &) = delete; + + private: + explicit MuxerPrivate(Muxer *q) : q_ptr(q) {}; + + Muxer *q_ptr; + + QIODevice *m_outputDevice{nullptr}; + + QMutex m_initMutex{}; + static constexpr size_t IOBUF_SIZE{4 * 1024}; // 4 KB + uint8_t *m_pIOBuffer{nullptr}; + AVIOContext *m_pIOContext{nullptr}; + AVFormatContext *m_pFormatContext{nullptr}; + QMap<IPacketSource *, QList<AVStream *>> m_sourceStreamMap{}; + + QMutex m_inputQueueMutex{}; + QQueue<QPair<AVPacket *, AVStream *>> m_inputQueue{}; + + std::atomic_bool m_running{false}; + std::atomic_bool m_paused{false}; + std::atomic_bool m_headerWritten{false}; + + friend class Muxer; + + static int64_t seekIO(void *opaque, int64_t offset, int whence); + + static int writeToIO(void *opaque, uint8_t *buf, int buf_size); + }; +} + +#endif //LIBAVQT_MUXER_P_H \ No newline at end of file diff --git a/AVQt/output/private/OpenALAudioOutput_p.h b/AVQt/output/private/OpenALAudioOutput_p.h index 04b678b8fdd56cff826e5571793fa7cbf9480a8b..c9330cc3f612f87cec1604f446b2f19db0c5cd70 100644 --- a/AVQt/output/private/OpenALAudioOutput_p.h +++ b/AVQt/output/private/OpenALAudioOutput_p.h @@ -22,43 +22,49 @@ namespace AVQt { class OpenALAudioOutput; class OpenALAudioOutputPrivate { + public: + OpenALAudioOutputPrivate(const OpenALAudioOutputPrivate &) = delete; + + void operator=(const OpenALAudioOutputPrivate &) = delete; + + private: explicit OpenALAudioOutputPrivate(OpenALAudioOutput *q) : q_ptr(q) {}; - [[maybe_unused]] OpenALAudioOutput *q_ptr; + OpenALAudioOutput *q_ptr; - QMutex m_inputQueueMutex; - QQueue<QPair<AVFrame *, int64_t>> m_inputQueue; + QMutex m_inputQueueMutex{}; + QQueue<QPair<AVFrame *, int64_t>> m_inputQueue{}; // AVFrame *m_partialFrame {nullptr}; // size_t m_partialFrameOffset {0}; - QMutex m_outputQueueMutex; - QQueue<QPair<AVFrame *, int64_t>> m_outputQueue; - std::atomic_bool m_outputSliceDurationChanged {false}; - int64_t m_duration = 0, m_clockInterval = 0, m_sampleRate {0}; - - std::atomic<RenderClock *> m_clock {nullptr}; - - QMutex m_swrContextMutex; - SwrContext *m_pSwrContext {nullptr}; - - int m_ALBufferCount = 5; - std::atomic_size_t m_playingBuffers {0}; - QVector<ALuint> m_ALBuffers; - QRecursiveMutex m_ALBufferQueueMutex; - QQueue<ALuint> m_ALBufferQueue; - QRecursiveMutex m_ALBufferSampleMapMutex; - QMap<ALuint, int64_t> m_ALBufferSampleMap; - int64_t m_queuedSamples {0}; - ALCdevice *m_ALCDevice {nullptr}; - ALCcontext *m_ALCContext {nullptr}; - - ALuint m_ALSource {0}; + QMutex m_outputQueueMutex{}; + QQueue<QPair<AVFrame *, int64_t>> m_outputQueue{}; + std::atomic_bool m_outputSliceDurationChanged{false}; + int64_t m_duration{0}, m_clockInterval{0}, m_sampleRate{0}; + + std::atomic<RenderClock *> m_clock{nullptr}; + + QMutex m_swrContextMutex{}; + SwrContext *m_pSwrContext{nullptr}; + + int m_ALBufferCount{5}; + std::atomic_int64_t m_playingBuffers{0}; + QVector<ALuint> m_ALBuffers{}; + QRecursiveMutex m_ALBufferQueueMutex{}; + QQueue<ALuint> m_ALBufferQueue{}; + QRecursiveMutex m_ALBufferSampleMapMutex{}; + QMap<ALuint, int64_t> m_ALBufferSampleMap{}; + int64_t m_queuedSamples{0}; + ALCdevice *m_ALCDevice{nullptr}; + ALCcontext *m_ALCContext{nullptr}; + + ALuint m_ALSource{0}; // Threading stuff - std::atomic_bool m_running {false}; - std::atomic_bool m_paused {false}; + std::atomic_bool m_running{false}; + std::atomic_bool m_paused{false}; - std::atomic_bool m_wasPaused {false}; - std::atomic_int64_t m_lastUpdate {0}; - std::atomic_size_t m_audioFrame {0}; + std::atomic_bool m_wasPaused{false}; + std::atomic_int64_t m_lastUpdate{0}; + std::atomic_size_t m_audioFrame{0}; friend class OpenALAudioOutput; }; diff --git a/AVQt/output/private/OpenGLRenderer_p.h b/AVQt/output/private/OpenGLRenderer_p.h index c5a00e6385b256621adcef570ba54c42575366ab..5092f6e284c40b8a3d33d5d49fef90e9298a8d6a 100644 --- a/AVQt/output/private/OpenGLRenderer_p.h +++ b/AVQt/output/private/OpenGLRenderer_p.h @@ -24,6 +24,12 @@ namespace AVQt { * \internal */ class OpenGLRendererPrivate { + public: + OpenGLRendererPrivate(const OpenGLRendererPrivate &) = delete; + + void operator=(const OpenGLRendererPrivate &) = delete; + + private: explicit OpenGLRendererPrivate(OpenGLRenderer *q) : q_ptr(q) {}; static GLint @@ -32,30 +38,31 @@ namespace AVQt { static inline void transformPoint(GLdouble out[4], const GLdouble m[16], const GLdouble in[4]); + static QTime timeFromMillis(int64_t ts); - OpenGLRenderer *q_ptr {nullptr}; + OpenGLRenderer *q_ptr{nullptr}; - QMutex m_renderQueueMutex; - QQueue<QPair<AVFrame *, int64_t>> m_renderQueue; + QMutex m_renderQueueMutex{}; + QQueue<QPair<AVFrame *, int64_t>> m_renderQueue{}; - RenderClock *m_clock {nullptr}; - int64_t m_currentFrameTimeout = 1; - QTime m_duration; - QTime m_position; - std::atomic_bool m_updateRequired {true}, m_paused {false}, m_running {false}, m_firstFrame {true}; - std::atomic<qint64> m_updateTimestamp {0}; - std::chrono::time_point<std::chrono::high_resolution_clock> m_lastFrame; + RenderClock *m_clock{nullptr}; + int64_t m_currentFrameTimeout{1}; + QTime m_duration{}; + QTime m_position{}; + std::atomic_bool m_updateRequired{true}, m_paused{false}, m_running{false}, m_firstFrame{true}; + std::atomic<qint64> m_updateTimestamp{0}; + std::chrono::time_point<std::chrono::high_resolution_clock> m_lastFrame{}; - QMutex m_currentFrameMutex; - AVFrame *m_currentFrame {nullptr}; + QMutex m_currentFrameMutex{}; + AVFrame *m_currentFrame{nullptr}; - QOpenGLVertexArrayObject m_vao; - QOpenGLBuffer m_vbo, m_ibo; - QOpenGLShaderProgram *m_program {nullptr}; - QOpenGLTexture *m_yTexture {nullptr}, *m_uTexture {nullptr}, *m_vTexture {nullptr}; + QOpenGLVertexArrayObject m_vao{}; + QOpenGLBuffer m_vbo{}, m_ibo{}; + QOpenGLShaderProgram *m_program{nullptr}; + QOpenGLTexture *m_yTexture{nullptr}, *m_uTexture{nullptr}, *m_vTexture{nullptr}; - static constexpr uint PROGRAM_VERTEX_ATTRIBUTE {0}; - static constexpr uint PROGRAM_TEXCOORD_ATTRIBUTE {1}; + static constexpr uint PROGRAM_VERTEX_ATTRIBUTE{0}; + static constexpr uint PROGRAM_TEXCOORD_ATTRIBUTE{1}; friend class OpenGLRenderer; }; diff --git a/AVQt/output/private/RenderClock_p.h b/AVQt/output/private/RenderClock_p.h index de66bdc9fcb5f6225787723e8556e4dea51de646..71ff96a97a5d9006b64bd2b44718e3b50b7158ed 100644 --- a/AVQt/output/private/RenderClock_p.h +++ b/AVQt/output/private/RenderClock_p.h @@ -9,15 +9,21 @@ namespace AVQt { class RenderClockPrivate { + public: + RenderClockPrivate(const RenderClockPrivate &) = delete; + + void operator=(const RenderClockPrivate &) = delete; + + private: explicit RenderClockPrivate(RenderClock *q) : q_ptr(q) {}; RenderClock *q_ptr; - QTimer *m_timer {nullptr}; - std::atomic_int64_t m_interval {1}; - std::atomic_bool m_active {false}; - std::atomic_bool m_paused {false}; - QElapsedTimer *m_elapsedTime {nullptr}; - qint64 m_lastPauseTimestamp {0}; + QTimer *m_timer{nullptr}; + std::atomic_int m_interval{1}; + std::atomic_bool m_active{false}; + std::atomic_bool m_paused{false}; + QElapsedTimer *m_elapsedTime{nullptr}; + qint64 m_lastPauseTimestamp{0}; friend class RenderClock; };