Skip to content
Snippets Groups Projects
Commit 40e21078 authored by Silas Della Contrada's avatar Silas Della Contrada
Browse files

Fixed some mistakes in the repository

parent 1387e8e5
Branches
No related tags found
No related merge requests found
......@@ -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
......@@ -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
......
//
// 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
//
// 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
//
// 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment