diff --git a/AVQt/AVQt b/AVQt/AVQt index 876471bc02b7109fa473e60c7142796d7bf5acf8..7e31b527e2422a529bd1514167be7a47355ad16a 100644 --- a/AVQt/AVQt +++ b/AVQt/AVQt @@ -14,5 +14,4 @@ #include "output/IAudioSink.h" #include "output/OpenGLRenderer.h" #include "output/OpenALAudioOutput.h" -#include "output/Muxer.h" -//#include "output/FrameFileSaver.h" +//#include "output/FrameFileSaver.h" \ No newline at end of file diff --git a/AVQt/CMakeLists.txt b/AVQt/CMakeLists.txt index 4584f5d4d87f7aa088ef2044aa14346534f7e2a7..700bb739d2fbebf4f791fb1c913d9a9fd1626a4d 100644 --- a/AVQt/CMakeLists.txt +++ b/AVQt/CMakeLists.txt @@ -67,10 +67,6 @@ 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 diff --git a/AVQt/output/Muxer.cpp b/AVQt/output/Muxer.cpp deleted file mode 100644 index 935ff345d5ff7b3d7e615227e9d1b953608c5550..0000000000000000000000000000000000000000 --- a/AVQt/output/Muxer.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// -// 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].keys()) { - 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_pFormatContext->oformat = av_guess_format("mpegts", "", nullptr); - 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] = QMap<AVStream *, AVRational>(); - } - 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].insert(videoStream, timebase); - } 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].insert(audioStream, timebase); - } 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].insert(subtitleStream, timebase); - } - int ret = avformat_init_output(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)); - } - } - - void Muxer::deinit(IPacketSource *source) { - Q_D(AVQt::Muxer); - - stop(nullptr); - - 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)) { -// -// } - 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); - wait(); - { - QMutexLocker lock{&d->m_inputQueueMutex}; - while (!d->m_inputQueue.isEmpty()) { - auto packet = d->m_inputQueue.dequeue(); - av_packet_free(&packet.first); - } - } - 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].keys()) { - 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; - qDebug("[AVQt::Muxer] Getting packet with PTS: %lld", static_cast<long long>(packet->pts)); - av_packet_rescale_ts(queuePacket.first, d->m_sourceStreamMap[source][addStream], addStream->time_base); - - 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() && !d->m_inputQueue.isEmpty()) { - QPair<AVPacket *, AVStream *> packet; - { - QMutexLocker lock(&d->m_inputQueueMutex); - packet = d->m_inputQueue.dequeue(); - } -// av_packet_rescale_ts(packet.first, packet.second->time_base, av_make_q(1, AV_TIME_BASE)); - int ret = av_interleaved_write_frame(d->m_pFormatContext, packet.first); - qDebug("Written packet"); - 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 deleted file mode 100644 index a0ddeeda02cdf1b994ed35483680c2924d0fb902..0000000000000000000000000000000000000000 --- a/AVQt/output/Muxer.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Created by silas on 5/24/21. -// - -#include "IPacketSink.h" - -#include <QThread> -#include <QIODevice> - -#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 diff --git a/AVQt/output/private/Muxer_p.h b/AVQt/output/private/Muxer_p.h deleted file mode 100644 index cbe1523645755427e74bf816403d36950e46039d..0000000000000000000000000000000000000000 --- a/AVQt/output/private/Muxer_p.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Created by silas on 5/24/21. -// - -#include "../Muxer.h" - -extern "C" { -#include <libavformat/avformat.h> -#include <libavcodec/avcodec.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 *, QMap<AVStream *, AVRational>> 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