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> ¤tStreams) 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