File indexing completed on 2025-01-19 03:57:03

0001 /*********************************************************
0002  * Copyright (C) 2020, Val Doroshchuk <valbok@gmail.com> *
0003  *                                                       *
0004  * This file is part of QtAVPlayer.                      *
0005  * Free Qt Media Player based on FFmpeg.                 *
0006  *********************************************************/
0007 
0008 #include "qavdemuxer_p.h"
0009 #include "qavvideocodec_p.h"
0010 #include "qavaudiocodec_p.h"
0011 #include "qavsubtitlecodec_p.h"
0012 #include "qavhwdevice_p.h"
0013 #include "qaviodevice.h"
0014 #include <QtAVPlayer/qtavplayerglobal.h>
0015 
0016 #if defined(QT_AVPLAYER_VA_X11) && QT_CONFIG(opengl)
0017 #include "qavhwdevice_vaapi_x11_glx_p.h"
0018 #endif
0019 
0020 #if defined(QT_AVPLAYER_VA_DRM) && QT_CONFIG(egl)
0021 #include "qavhwdevice_vaapi_drm_egl_p.h"
0022 #endif
0023 
0024 #if defined(QT_AVPLAYER_VDPAU)
0025 #include "qavhwdevice_vdpau_p.h"
0026 #endif
0027 
0028 #if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
0029 #include "qavhwdevice_videotoolbox_p.h"
0030 #endif
0031 
0032 #if defined(Q_OS_WIN)
0033 #include "qavhwdevice_d3d11_p.h"
0034 #endif
0035 
0036 #if defined(Q_OS_ANDROID)
0037 #include "qavhwdevice_mediacodec_p.h"
0038 #include <QtCore/private/qjnihelpers_p.h>
0039 extern "C" {
0040 #include "libavcodec/jni.h"
0041 }
0042 #endif
0043 
0044 #include <QDir>
0045 #include <QSharedPointer>
0046 #include <QMutexLocker>
0047 #include <atomic>
0048 #include <QDebug>
0049 
0050 extern "C" {
0051 #include <libavformat/avformat.h>
0052 #include <libavdevice/avdevice.h>
0053 #include <libavcodec/avcodec.h>
0054 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 0, 0)
0055 #include <libavcodec/bsf.h>
0056 #endif
0057 }
0058 
0059 QT_BEGIN_NAMESPACE
0060 
0061 class QAVDemuxerPrivate
0062 {
0063     Q_DECLARE_PUBLIC(QAVDemuxer)
0064 public:
0065     QAVDemuxerPrivate(QAVDemuxer *q)
0066         : q_ptr(q)
0067     {
0068     }
0069 
0070     QAVDemuxer *q_ptr = nullptr;
0071     AVFormatContext *ctx = nullptr;
0072     AVBSFContext *bsf_ctx = nullptr;
0073 
0074     std::atomic_bool abortRequest = false;
0075     mutable QMutex mutex;
0076 
0077     bool seekable = false;
0078     QList<QAVStream> availableStreams;
0079     QList<QAVStream> currentVideoStreams;
0080     QList<QAVStream> currentAudioStreams;
0081     QList<QAVStream> currentSubtitleStreams;
0082     QList<QAVStream::Progress> progress;
0083     QString inputFormat;
0084     QString inputVideoCodec;
0085     QMap<QString, QString> inputOptions;
0086 
0087     bool eof = false;
0088     QList<QAVPacket> packets;
0089     QString bsfs;
0090 };
0091 
0092 static int decode_interrupt_cb(void *ctx)
0093 {
0094     auto d = reinterpret_cast<QAVDemuxerPrivate *>(ctx);
0095     return d ? int(d->abortRequest) : 0;
0096 }
0097 
0098 QAVDemuxer::QAVDemuxer()
0099     : d_ptr(new QAVDemuxerPrivate(this))
0100 {
0101     static bool loaded = false;
0102     if (!loaded) {
0103 #if (LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58,9,100))
0104         av_register_all();
0105         avcodec_register_all();
0106 #endif
0107         avdevice_register_all();
0108         loaded = true;
0109     }
0110 }
0111 
0112 QAVDemuxer::~QAVDemuxer()
0113 {
0114     abort(false);
0115     unload();
0116 }
0117 
0118 void QAVDemuxer::abort(bool stop)
0119 {
0120     Q_D(QAVDemuxer);
0121     d->abortRequest = stop;
0122 }
0123 
0124 static int setup_video_codec(const QString &inputVideoCodec, AVStream *stream, QAVVideoCodec &codec)
0125 {
0126     const AVCodec *videoCodec = nullptr;
0127     if (!inputVideoCodec.isEmpty()) {
0128         qDebug() << "Loading: -vcodec" << inputVideoCodec;
0129         videoCodec = avcodec_find_decoder_by_name(inputVideoCodec.toUtf8().constData());
0130         if (!videoCodec) {
0131             qWarning() << "Could not find decoder:" << inputVideoCodec;
0132             return AVERROR(EINVAL);
0133         }
0134     }
0135 
0136     if (videoCodec)
0137         codec.setCodec(videoCodec);
0138 
0139     QList<QSharedPointer<QAVHWDevice>> devices;
0140     AVDictionary *opts = NULL;
0141     Q_UNUSED(opts);
0142 
0143 #if defined(QT_AVPLAYER_VA_X11) && QT_CONFIG(opengl)
0144     devices.append(QSharedPointer<QAVHWDevice>(new QAVHWDevice_VAAPI_X11_GLX));
0145     av_dict_set(&opts, "connection_type", "x11", 0);
0146 #endif
0147 #if defined(QT_AVPLAYER_VDPAU)
0148     devices.append(QSharedPointer<QAVHWDevice>(new QAVHWDevice_VDPAU));
0149 #endif
0150 #if defined(QT_AVPLAYER_VA_DRM) && QT_CONFIG(egl)
0151     devices.append(QSharedPointer<QAVHWDevice>(new QAVHWDevice_VAAPI_DRM_EGL));
0152 #endif
0153 #if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
0154     devices.append(QSharedPointer<QAVHWDevice>(new QAVHWDevice_VideoToolbox));
0155 #endif
0156 #if defined(Q_OS_WIN)
0157     devices.append(QSharedPointer<QAVHWDevice>(new QAVHWDevice_D3D11));
0158 #endif
0159 #if defined(Q_OS_ANDROID)
0160     devices.append(QSharedPointer<QAVHWDevice>(new QAVHWDevice_MediaCodec));
0161     if (!codec.codec())
0162         codec.setCodec(avcodec_find_decoder_by_name("h264_mediacodec"));
0163     auto vm = QtAndroidPrivate::javaVM();
0164     av_jni_set_java_vm(vm, NULL);
0165 #endif
0166 
0167     const bool ignoreHW = qEnvironmentVariableIsSet("QT_AVPLAYER_NO_HWDEVICE");
0168     if (!ignoreHW) {
0169         AVBufferRef *hw_device_ctx = nullptr;
0170         for (auto &device : devices) {
0171             auto deviceName = av_hwdevice_get_type_name(device->type());
0172             qDebug() << "Creating hardware device context:" << deviceName;
0173             if (av_hwdevice_ctx_create(&hw_device_ctx, device->type(), nullptr, opts, 0) >= 0) {
0174                 qDebug() << "Using hardware device context:" << deviceName;
0175                 codec.avctx()->hw_device_ctx = hw_device_ctx;
0176                 codec.avctx()->pix_fmt = device->format();
0177                 codec.setDevice(device);
0178                 break;
0179             }
0180             av_buffer_unref(&hw_device_ctx);
0181         }
0182     }
0183 
0184     // Open codec after hwdevices
0185     if (!codec.open(stream)) {
0186         qWarning() << "Could not open video codec for stream";
0187         return AVERROR(EINVAL);
0188     }
0189 
0190     return 0;
0191 }
0192 
0193 static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
0194 {
0195     if (level > av_log_get_level())
0196         return;
0197 
0198     va_list vl2;
0199     char line[1024];
0200     static int print_prefix = 1;
0201 
0202     va_copy(vl2, vl);
0203     av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
0204     va_end(vl2);
0205 
0206     qDebug() << "FFmpeg:" << line;
0207 }
0208 
0209 QStringList QAVDemuxer::supportedFormats()
0210 {
0211     static QStringList values;
0212     if (values.isEmpty()) {
0213 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 0, 0)
0214         const AVInputFormat *fmt = nullptr;
0215         void *it = nullptr;
0216         while ((fmt = av_demuxer_iterate(&it))) {
0217             if (fmt->name)
0218                 values << QString::fromLatin1(fmt->name).split(QLatin1Char(','),
0219 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
0220                     QString::SkipEmptyParts
0221 #else
0222                     Qt::SkipEmptyParts
0223 #endif
0224                 );
0225         }
0226 #endif
0227     }
0228 
0229     return values;
0230 }
0231 
0232 QStringList QAVDemuxer::supportedVideoCodecs()
0233 {
0234     static QStringList values;
0235     if (values.isEmpty()) {
0236         const AVCodec *c = nullptr;
0237         void *it = nullptr;
0238         while ((c = av_codec_iterate(&it))) {
0239             if (!av_codec_is_decoder(c) || c->type != AVMEDIA_TYPE_VIDEO)
0240                 continue;
0241             values.append(QString::fromLatin1(c->name));
0242         }
0243     }
0244 
0245     return values;
0246 }
0247 
0248 QStringList QAVDemuxer::supportedProtocols()
0249 {
0250     static QStringList values;
0251     if (values.isEmpty()) {
0252         void *opq = 0;
0253         const char *value = nullptr;
0254         while ((value = avio_enum_protocols(&opq, 0)))
0255             values << QString::fromUtf8(value);
0256     }
0257 
0258     return values;
0259 }
0260 
0261 static int init_output_bsfs(AVBSFContext *ctx, AVStream *st)
0262 {
0263     if (!ctx)
0264         return 0;
0265 
0266     int ret = avcodec_parameters_copy(ctx->par_in, st->codecpar);
0267     if (ret < 0)
0268         return ret;
0269 
0270     ctx->time_base_in = st->time_base;
0271 
0272     ret = av_bsf_init(ctx);
0273     if (ret < 0) {
0274         qWarning() << "Error initializing bitstream filter:" << ctx->filter->name;
0275         return ret;
0276     }
0277 
0278     ret = avcodec_parameters_copy(st->codecpar, ctx->par_out);
0279     if (ret < 0)
0280         return ret;
0281 
0282     st->time_base = ctx->time_base_out;
0283     return 0;
0284 }
0285 
0286 static int apply_bsf(const QString &bsf, AVFormatContext *ctx, AVBSFContext *&bsf_ctx)
0287 {
0288     int ret = !bsf.isEmpty() ? av_bsf_list_parse_str(bsf.toUtf8().constData(), &bsf_ctx) : 0;
0289     if (ret < 0) {
0290         qWarning() << "Error parsing bitstream filter sequence:" << bsf;
0291         return ret;
0292     }
0293 
0294     for (std::size_t i = 0; i < ctx->nb_streams; ++i) {
0295         switch (ctx->streams[i]->codecpar->codec_type) {
0296             case AVMEDIA_TYPE_VIDEO:
0297             case AVMEDIA_TYPE_AUDIO:
0298                 ret = init_output_bsfs(bsf_ctx, ctx->streams[i]);
0299                 break;
0300             default:
0301                 break;
0302         }
0303     }
0304 
0305     return ret;
0306 }
0307 
0308 int QAVDemuxer::load(const QString &url, QAVIODevice *dev)
0309 {
0310     Q_D(QAVDemuxer);
0311     QMutexLocker locker(&d->mutex);
0312 
0313     if (!d->ctx)
0314         d->ctx = avformat_alloc_context();
0315 
0316     d->ctx->flags |= AVFMT_FLAG_GENPTS;
0317     d->ctx->interrupt_callback.callback = decode_interrupt_cb;
0318     d->ctx->interrupt_callback.opaque = d;
0319     if (dev) {
0320         d->ctx->pb = dev->ctx();
0321         d->ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
0322     }
0323 
0324 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 0, 0)
0325     const
0326 #endif
0327     AVInputFormat *inputFormat = nullptr;
0328     if (!d->inputFormat.isEmpty()) {
0329         qDebug() << "Loading: -f" << d->inputFormat;
0330         inputFormat = av_find_input_format(d->inputFormat.toUtf8().constData());
0331         if (!inputFormat) {
0332             qWarning() << "Could not find input format:" << d->inputFormat;
0333             return AVERROR(EINVAL);
0334         }
0335     }
0336 
0337     AVDictionary *opts = nullptr;
0338     for (const auto & key: d->inputOptions.keys())
0339         av_dict_set(&opts, key.toUtf8().constData(), d->inputOptions[key].toUtf8().constData(), 0);
0340     locker.unlock();
0341     int ret = avformat_open_input(&d->ctx, url.toUtf8().constData(), inputFormat, &opts);
0342     if (ret < 0)
0343         return ret;
0344 
0345     ret = avformat_find_stream_info(d->ctx, NULL);
0346     if (ret < 0)
0347         return ret;
0348 
0349     locker.relock();
0350     av_log_set_callback(log_callback);
0351 
0352     d->seekable = d->ctx->iformat->read_seek || d->ctx->iformat->read_seek2;
0353     if (d->ctx->pb)
0354         d->seekable |= bool(d->ctx->pb->seekable);
0355 
0356     ret = resetCodecs();
0357     if (ret < 0)
0358         return ret;
0359 
0360     const int videoStreamIndex = av_find_best_stream(
0361         d->ctx,
0362         AVMEDIA_TYPE_VIDEO,
0363         -1,
0364         -1,
0365         nullptr,
0366         0);
0367     if (videoStreamIndex >= 0)
0368         d->currentVideoStreams.push_back(d->availableStreams[videoStreamIndex]);
0369 
0370     const int audioStreamIndex = av_find_best_stream(
0371         d->ctx,
0372         AVMEDIA_TYPE_AUDIO,
0373         -1,
0374         videoStreamIndex,
0375         nullptr,
0376         0);
0377     if (audioStreamIndex >= 0)
0378         d->currentAudioStreams.push_back(d->availableStreams[audioStreamIndex]);
0379 
0380     const int subtitleStreamIndex = av_find_best_stream(
0381         d->ctx,
0382         AVMEDIA_TYPE_SUBTITLE,
0383         -1,
0384         audioStreamIndex >= 0 ? audioStreamIndex : videoStreamIndex,
0385         nullptr,
0386         0);
0387     if (subtitleStreamIndex >= 0)
0388         d->currentSubtitleStreams.push_back(d->availableStreams[subtitleStreamIndex]);
0389 
0390     if (ret < 0)
0391         return ret;
0392 
0393     if (!d->bsfs.isEmpty())
0394         return apply_bsf(d->bsfs, d->ctx, d->bsf_ctx);
0395 
0396     return 0;
0397 }
0398 
0399 int QAVDemuxer::resetCodecs()
0400 {
0401     Q_D(QAVDemuxer);
0402     int ret = 0;
0403     for (std::size_t i = 0; i < d->ctx->nb_streams && ret >= 0; ++i) {
0404         if (!d->ctx->streams[i]->codecpar) {
0405             qWarning() << "Could not find codecpar";
0406             return AVERROR(EINVAL);
0407         }
0408         const AVMediaType type = d->ctx->streams[i]->codecpar->codec_type;
0409         switch (type) {
0410             case AVMEDIA_TYPE_VIDEO:
0411             {
0412                 QSharedPointer<QAVCodec> codec(new QAVVideoCodec);
0413                 d->availableStreams.push_back({ int(i), d->ctx, codec });
0414                 ret = setup_video_codec(d->inputVideoCodec, d->ctx->streams[i], *static_cast<QAVVideoCodec *>(codec.data()));
0415             } break;
0416             case AVMEDIA_TYPE_AUDIO:
0417                 d->availableStreams.push_back({ int(i), d->ctx, QSharedPointer<QAVCodec>(new QAVAudioCodec) });
0418                 if (!d->availableStreams.last().codec()->open(d->ctx->streams[i]))
0419                     qWarning() << "Could not open audio codec for stream:" << i;
0420                 break;
0421             case AVMEDIA_TYPE_SUBTITLE:
0422                 d->availableStreams.push_back({ int(i), d->ctx, QSharedPointer<QAVCodec>(new QAVSubtitleCodec) });
0423                 if (!d->availableStreams.last().codec()->open(d->ctx->streams[i]))
0424                     qWarning() << "Could not open subtitle codec for stream:" << i;
0425                 break;
0426             default:
0427                 // Adding default stream
0428                 d->availableStreams.push_back({ int(i), d->ctx, nullptr });
0429                 break;
0430         }
0431         auto &s = d->availableStreams[int(i)];
0432         d->progress.push_back({ s.duration(), s.framesCount(), s.frameRate() });
0433     }
0434 
0435     return ret;
0436 }
0437 
0438 static bool findStream(
0439     const QList<QAVStream> &streams,
0440     int index)
0441 {
0442     for (const auto &stream: streams) {
0443         if (index == stream.index())
0444             return true;
0445     }
0446     return false;
0447 }
0448 
0449 AVMediaType QAVDemuxer::currentCodecType(int index) const
0450 {
0451     Q_D(const QAVDemuxer);
0452     QMutexLocker locker(&d->mutex);
0453     // TODO:
0454     if (findStream(d->currentVideoStreams, index))
0455         return AVMEDIA_TYPE_VIDEO;
0456     if (findStream(d->currentAudioStreams, index))
0457         return AVMEDIA_TYPE_AUDIO;
0458     if (findStream(d->currentSubtitleStreams, index))
0459         return AVMEDIA_TYPE_SUBTITLE;
0460     return AVMEDIA_TYPE_UNKNOWN;
0461 }
0462 
0463 static QList<QAVStream> availableStreamsByType(
0464     const QList<QAVStream> &streams,
0465     AVMediaType type)
0466 {
0467     QList<QAVStream> ret;
0468     for (auto &stream : streams) {
0469         if (stream.stream()->codecpar->codec_type == type)
0470             ret.push_back(stream);
0471     }
0472 
0473     return ret;
0474 }
0475 
0476 QList<QAVStream> QAVDemuxer::availableVideoStreams() const
0477 {
0478     Q_D(const QAVDemuxer);
0479     QMutexLocker locker(&d->mutex);
0480     return availableStreamsByType(d->availableStreams, AVMEDIA_TYPE_VIDEO);
0481 }
0482 
0483 QList<QAVStream> QAVDemuxer::currentVideoStreams() const
0484 {
0485     Q_D(const QAVDemuxer);
0486     QMutexLocker locker(&d->mutex);
0487     return d->currentVideoStreams;
0488 }
0489 
0490 static bool setCurrentStreams(
0491     const QList<QAVStream> &streams,
0492     const QList<QAVStream> &availableStreams,
0493     AVMediaType type,
0494     QList<QAVStream> &currentStreams)
0495 {
0496     QList<QAVStream> ret;
0497     for (const auto &stream: streams) {
0498         if (stream.index() >= 0
0499             && stream.index() < availableStreams.size()
0500             && availableStreams[stream.index()].stream()->codecpar->codec_type == type)
0501         {
0502             ret.push_back(availableStreams[stream.index()]);
0503         }
0504     }
0505     if (!ret.isEmpty() || streams.isEmpty()) {
0506         currentStreams = ret;
0507         return true;
0508     }
0509 
0510     return false;
0511 }
0512 
0513 bool QAVDemuxer::setVideoStreams(const QList<QAVStream> &streams)
0514 {
0515     Q_D(QAVDemuxer);
0516     QMutexLocker locker(&d->mutex);
0517     return setCurrentStreams(
0518         streams,
0519         d->availableStreams,
0520         AVMEDIA_TYPE_VIDEO,
0521         d->currentVideoStreams);
0522 }
0523 
0524 QList<QAVStream> QAVDemuxer::availableAudioStreams() const
0525 {
0526     Q_D(const QAVDemuxer);
0527     QMutexLocker locker(&d->mutex);
0528     return availableStreamsByType(
0529         d->availableStreams,
0530         AVMEDIA_TYPE_AUDIO);
0531 }
0532 
0533 QList<QAVStream> QAVDemuxer::currentAudioStreams() const
0534 {
0535     Q_D(const QAVDemuxer);
0536     QMutexLocker locker(&d->mutex);
0537     return d->currentAudioStreams;
0538 }
0539 
0540 bool QAVDemuxer::setAudioStreams(const QList<QAVStream> &streams)
0541 {
0542     Q_D(QAVDemuxer);
0543     QMutexLocker locker(&d->mutex);
0544     return setCurrentStreams(
0545         streams,
0546         d->availableStreams,
0547         AVMEDIA_TYPE_AUDIO,
0548         d->currentAudioStreams);
0549 }
0550 
0551 QList<QAVStream> QAVDemuxer::availableSubtitleStreams() const
0552 {
0553     Q_D(const QAVDemuxer);
0554     QMutexLocker locker(&d->mutex);
0555     return availableStreamsByType(
0556         d->availableStreams,
0557         AVMEDIA_TYPE_SUBTITLE);
0558 }
0559 
0560 QList<QAVStream> QAVDemuxer::currentSubtitleStreams() const
0561 {
0562     Q_D(const QAVDemuxer);
0563     QMutexLocker locker(&d->mutex);
0564     return d->currentSubtitleStreams;
0565 }
0566 
0567 bool QAVDemuxer::setSubtitleStreams(const QList<QAVStream> &streams)
0568 {
0569     Q_D(QAVDemuxer);
0570     QMutexLocker locker(&d->mutex);
0571     return setCurrentStreams(
0572         streams,
0573         d->availableStreams,
0574         AVMEDIA_TYPE_SUBTITLE,
0575         d->currentSubtitleStreams);
0576 }
0577 
0578 void QAVDemuxer::unload()
0579 {
0580     Q_D(QAVDemuxer);
0581     QMutexLocker locker(&d->mutex);
0582     if (d->ctx) {
0583         avformat_close_input(&d->ctx);
0584         avformat_free_context(d->ctx);
0585     }
0586     d->ctx = nullptr;
0587     d->eof = false;
0588     d->abortRequest = 0;
0589     d->currentVideoStreams.clear();
0590     d->currentAudioStreams.clear();
0591     d->currentSubtitleStreams.clear();
0592     d->availableStreams.clear();
0593     d->progress.clear();
0594     av_bsf_free(&d->bsf_ctx);
0595     d->bsf_ctx = nullptr;
0596 }
0597 
0598 bool QAVDemuxer::eof() const
0599 {
0600     Q_D(const QAVDemuxer);
0601     QMutexLocker locker(&d->mutex);
0602     return d->eof;
0603 }
0604 
0605 QAVPacket QAVDemuxer::read()
0606 {
0607     Q_D(QAVDemuxer);
0608     QMutexLocker locker(&d->mutex);
0609     if (!d->packets.isEmpty())
0610         return d->packets.takeFirst();
0611 
0612     if (!d->ctx || d->eof)
0613         return {};
0614 
0615     QAVPacket pkt;
0616     locker.unlock();
0617     int ret = av_read_frame(d->ctx, pkt.packet());
0618     if (ret < 0) {
0619         if (ret == AVERROR_EOF || avio_feof(d->ctx->pb)) {
0620             locker.relock();
0621             d->eof = true;
0622             locker.unlock();
0623         }
0624     }
0625     locker.relock();
0626 
0627     QAVStream stream = pkt.packet()->stream_index < d->availableStreams.size()
0628                        ? d->availableStreams[pkt.packet()->stream_index]
0629                        : QAVStream();
0630     Q_ASSERT(stream.stream());
0631     pkt.setStream(stream);
0632 
0633     if (d->bsf_ctx) {
0634         ret = av_bsf_send_packet(d->bsf_ctx, d->eof ? NULL : pkt.packet());
0635         if (ret >= 0) {
0636             while ((ret = av_bsf_receive_packet(d->bsf_ctx, pkt.packet())) >= 0)
0637                 d->packets.append(pkt);
0638         }
0639         if (ret < 0 && ret != AVERROR_EOF && ret != AVERROR(EAGAIN)) {
0640             qWarning() << "Error applying bitstream filters to an output:" << ret;
0641             return {};
0642         }
0643     } else {
0644         d->packets.append(pkt);
0645     }
0646 
0647     return !d->packets.isEmpty() ? d->packets.takeFirst() : QAVPacket{};
0648 }
0649 
0650 void QAVDemuxer::decode(const QAVPacket &pkt, QList<QAVFrame> &frames) const
0651 {
0652     if (!pkt.stream())
0653         return;
0654     int sent = 0;
0655     do {
0656         sent = pkt.send();
0657         // AVERROR(EAGAIN): input is not accepted in the current state - user must read output with avcodec_receive_frame()
0658         // (once all output is read, the packet should be resent, and the call will not fail with EAGAIN)
0659         if (sent < 0 && sent != AVERROR(EAGAIN))
0660             return;
0661 
0662         while (true) {
0663             QAVFrame frame;
0664             frame.setStream(pkt.stream());
0665             // AVERROR(EAGAIN): output is not available in this state - user must try to send new input
0666             int received = frame.receive();
0667             if (received < 0)
0668                 break;
0669             frames.push_back(frame);
0670         }
0671     } while (sent == AVERROR(EAGAIN));
0672 }
0673 
0674 void QAVDemuxer::decode(const QAVPacket &pkt, QList<QAVSubtitleFrame> &frames) const
0675 {
0676     if (!pkt.stream())
0677         return;
0678     int sent = pkt.send();
0679     if (sent < 0 && sent != AVERROR(EAGAIN))
0680         return;
0681 
0682     QAVSubtitleFrame frame;
0683     frame.setStream(pkt.stream());
0684     if (frame.receive() >= 0)
0685         frames.push_back(frame);
0686 }
0687 
0688 void QAVDemuxer::flushCodecBuffers()
0689 {
0690     Q_D(QAVDemuxer);
0691     QMutexLocker locker(&d->mutex);
0692     for (auto &s: d->availableStreams) {
0693         auto c = s.codec();
0694         if (c)
0695             c->flushBuffers();
0696     }
0697 }
0698 
0699 bool QAVDemuxer::seekable() const
0700 {
0701     return d_func()->seekable;
0702 }
0703 
0704 int QAVDemuxer::seek(double sec)
0705 {
0706     Q_D(QAVDemuxer);
0707     QMutexLocker locker(&d->mutex);
0708     if (!d->ctx || !d->seekable)
0709         return AVERROR(EINVAL);
0710 
0711     d->eof = false;
0712     locker.unlock();
0713 
0714     int flags = AVSEEK_FLAG_BACKWARD;
0715     int64_t target = sec * AV_TIME_BASE;
0716     int64_t min = INT_MIN;
0717     int64_t max = target;
0718     return avformat_seek_file(d->ctx, -1, min, target, max, flags);
0719 }
0720 
0721 double QAVDemuxer::duration() const
0722 {
0723     Q_D(const QAVDemuxer);
0724     if (!d->ctx || d->ctx->duration == AV_NOPTS_VALUE)
0725         return 0.0;
0726 
0727     return d->ctx->duration * av_q2d({1, AV_TIME_BASE});
0728 }
0729 
0730 double QAVDemuxer::videoFrameRate() const
0731 {
0732     Q_D(const QAVDemuxer);
0733     QMutexLocker locker(&d->mutex);
0734     if (d->currentVideoStreams.isEmpty())
0735         return 0.0;
0736     // TODO:
0737     double ret = std::numeric_limits<double>::max();
0738     for (const auto &stream: d->currentVideoStreams) {
0739         AVRational fr = av_guess_frame_rate(d->ctx, d->ctx->streams[stream.index()], NULL);
0740         double rate = fr.num && fr.den ? av_q2d({fr.den, fr.num}) : 0.0;
0741         if (rate < ret)
0742             ret = rate;
0743     }
0744 
0745     return ret;
0746 }
0747 
0748 QMap<QString, QString> QAVDemuxer::metadata() const
0749 {
0750     Q_D(const QAVDemuxer);
0751     QMap<QString, QString> result;
0752     if (d->ctx == nullptr)
0753         return result;
0754 
0755     AVDictionaryEntry *tag = nullptr;
0756     while ((tag = av_dict_get(d->ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
0757         result[QString::fromUtf8(tag->key)] = QString::fromUtf8(tag->value);
0758 
0759     return result;
0760 }
0761 
0762 QString QAVDemuxer::bitstreamFilter() const
0763 {
0764     Q_D(const QAVDemuxer);
0765     QMutexLocker locker(&d->mutex);
0766     return d->bsfs;
0767 }
0768 
0769 int QAVDemuxer::applyBitstreamFilter(const QString &bsfs)
0770 {
0771     Q_D(QAVDemuxer);
0772     QMutexLocker locker(&d->mutex);
0773     d->bsfs = bsfs;
0774     int ret = 0;
0775     if (d->ctx) {
0776         av_bsf_free(&d->bsf_ctx);
0777         d->bsf_ctx = nullptr;
0778         ret = apply_bsf(d->bsfs, d->ctx, d->bsf_ctx);
0779     }
0780     return ret;
0781 }
0782 
0783 QString QAVDemuxer::inputFormat() const
0784 {
0785     Q_D(const QAVDemuxer);
0786     QMutexLocker locker(&d->mutex);
0787     return d->inputFormat;
0788 }
0789 
0790 void QAVDemuxer::setInputFormat(const QString &format)
0791 {
0792     Q_D(QAVDemuxer);
0793     QMutexLocker locker(&d->mutex);
0794     d->inputFormat = format;
0795 }
0796 
0797 QString QAVDemuxer::inputVideoCodec() const
0798 {
0799     Q_D(const QAVDemuxer);
0800     QMutexLocker locker(&d->mutex);
0801     return d->inputVideoCodec;
0802 }
0803 
0804 void QAVDemuxer::setInputVideoCodec(const QString &codec)
0805 {
0806     Q_D(QAVDemuxer);
0807     QMutexLocker locker(&d->mutex);
0808     d->inputVideoCodec = codec;
0809 }
0810 
0811 QMap<QString, QString> QAVDemuxer::inputOptions() const
0812 {
0813     Q_D(const QAVDemuxer);
0814     QMutexLocker locker(&d->mutex);
0815     return d->inputOptions;
0816 }
0817 
0818 void QAVDemuxer::setInputOptions(const QMap<QString, QString> &opts)
0819 {
0820     Q_D(QAVDemuxer);
0821     QMutexLocker locker(&d->mutex);
0822     d->inputOptions = opts;
0823 }
0824 
0825 void QAVDemuxer::onFrameSent(const QAVStreamFrame &frame)
0826 {
0827     Q_D(QAVDemuxer);
0828     QMutexLocker locker(&d->mutex);
0829     int index = frame.stream().index();
0830     if (index >= 0 && index < d->progress.size())
0831         d->progress[index].onFrameSent(frame.pts());
0832 }
0833 
0834 bool QAVDemuxer::isMasterStream(const QAVStream &stream) const
0835 {
0836     auto s = stream.stream();
0837     switch (s->codecpar->codec_type) {
0838         case AVMEDIA_TYPE_VIDEO:
0839             return s->disposition != AV_DISPOSITION_ATTACHED_PIC;
0840         case AVMEDIA_TYPE_AUDIO:
0841             // Check if there are any video streams available
0842             for (const auto &vs: currentVideoStreams()) {
0843                 if (vs.stream()->disposition != AV_DISPOSITION_ATTACHED_PIC)
0844                     return false;
0845             }
0846             return true;
0847         default:
0848             Q_ASSERT(false);
0849             return false;
0850     }
0851 }
0852 
0853 QAVStream::Progress QAVDemuxer::progress(const QAVStream &s) const
0854 {
0855     Q_D(const QAVDemuxer);
0856     QMutexLocker locker(&d->mutex);
0857     int index = s.index();
0858     if (index >= 0 && index < d->progress.size())
0859         return d->progress[index];
0860     return {};
0861 }
0862 
0863 QStringList QAVDemuxer::supportedBitstreamFilters()
0864 {
0865     QStringList result;
0866 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 0, 0)
0867     const AVBitStreamFilter *bsf = NULL;
0868     void *opaque = NULL;
0869 
0870     while ((bsf = av_bsf_iterate(&opaque)))
0871         result.append(QString::fromUtf8(bsf->name));
0872 #endif
0873     return result;
0874 }
0875 
0876 QT_END_NAMESPACE