File indexing completed on 2024-06-16 04:38:30

0001 /*
0002     SPDX-FileCopyrightText: 2003 Fabrice Bellard
0003     SPDX-FileCopyrightText: 2020-2022 Mladen Milinkovic <max@smoothware.net>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "streamdemuxer.h"
0009 
0010 #include <QMutex>
0011 #include <QWaitCondition>
0012 
0013 #include "videoplayer/backend/ffplayer.h"
0014 #include "videoplayer/backend/packetqueue.h"
0015 #include "videoplayer/backend/videostate.h"
0016 #include "videoplayer/videoplayer.h"
0017 
0018 extern "C" {
0019 #include "libavutil/time.h"
0020 #include "libavformat/avformat.h"
0021 }
0022 
0023 
0024 using namespace SubtitleComposer;
0025 
0026 static void
0027 print_error(const char *filename, int err)
0028 {
0029     char errbuf[128];
0030     const char *errbuf_ptr = errbuf;
0031 
0032     if(av_strerror(err, errbuf, sizeof(errbuf)) < 0)
0033         errbuf_ptr = strerror(AVUNERROR(err));
0034     av_log(nullptr, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr);
0035 }
0036 
0037 
0038 static bool
0039 isRealTime(AVFormatContext *s)
0040 {
0041     if(!strcmp(s->iformat->name, "rtp") || !strcmp(s->iformat->name, "rtsp") || !strcmp(s->iformat->name, "sdp"))
0042         return 1;
0043 #if LIBAVFORMAT_VERSION_MAJOR < 58
0044     const char *url = s->filename;
0045 #else
0046     const char *url = s->url;
0047 #endif
0048     if(s->pb && url && (!strncmp(url, "rtp:", 4) || !strncmp(url, "udp:", 4)))
0049         return 1;
0050     return 0;
0051 }
0052 
0053 StreamDemuxer::StreamDemuxer(VideoState *vs, QObject *parent)
0054     : QThread(parent),
0055       m_vs(vs)
0056 {
0057 }
0058 
0059 VideoState *
0060 StreamDemuxer::open(const char *filename)
0061 {
0062     VideoState *vs = new VideoState();
0063     if(!vs)
0064         return nullptr;
0065     vs->lastVideoStream = vs->vidStreamIdx = -1;
0066     vs->lastAudioStream = vs->audStreamIdx = -1;
0067     vs->lastSubtitleStream = vs->subStreamIdx = -1;
0068     vs->filename = filename;
0069 
0070     if(vs->vidFQ.init(&vs->vidPQ, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
0071         goto fail;
0072     if(vs->subFQ.init(&vs->subPQ, SUBPICTURE_QUEUE_SIZE, 0) < 0)
0073         goto fail;
0074     if(vs->vidPQ.init() < 0 || vs->audPQ.init() < 0 || vs->subPQ.init() < 0)
0075         goto fail;
0076 
0077     vs->continueReadThread = new QWaitCondition();
0078 
0079     vs->vidClk.init(&vs->vidPQ);
0080     vs->audClk.init(&vs->audPQ);
0081     vs->extClk.init(nullptr);
0082 
0083     vs->demuxer = new StreamDemuxer(vs);
0084     vs->demuxer->start();
0085     return vs;
0086 
0087 fail:
0088     close(vs);
0089     return nullptr;
0090 }
0091 
0092 void
0093 StreamDemuxer::close(VideoState *vs)
0094 {
0095     // XXX: use a special url_shutdown call to abort parse cleanly
0096     vs->abortRequested = true;
0097     vs->demuxer->wait();
0098 
0099     // close each stream
0100     if(vs->audStreamIdx >= 0)
0101         vs->demuxer->componentClose(vs->audStreamIdx);
0102     if(vs->vidStreamIdx >= 0)
0103         vs->demuxer->componentClose(vs->vidStreamIdx);
0104     if(vs->subStreamIdx >= 0)
0105         vs->demuxer->componentClose(vs->subStreamIdx);
0106 
0107     delete vs->demuxer;
0108 
0109     avformat_close_input(&vs->fmtContext);
0110 
0111     vs->vidPQ.destroy();
0112     vs->audPQ.destroy();
0113     vs->subPQ.destroy();
0114 
0115     vs->vidFQ.destory();
0116     vs->subFQ.destory();
0117     delete vs->continueReadThread;
0118 #ifdef VIDEO_SUBTITLE
0119     sws_freeContext(vs->subConvertCtx);
0120 #endif
0121     delete vs;
0122 }
0123 
0124 void
0125 StreamDemuxer::componentClose(int streamIndex)
0126 {
0127     AVFormatContext *ic = m_vs->fmtContext;
0128     AVCodecParameters *codecPar;
0129 
0130     if(streamIndex < 0 || streamIndex >= (int)ic->nb_streams)
0131         return;
0132     codecPar = ic->streams[streamIndex]->codecpar;
0133 
0134     switch(codecPar->codec_type) {
0135     case AVMEDIA_TYPE_AUDIO:
0136         m_vs->audDec.abort();
0137         m_vs->audDec.destroy();
0138 
0139 #ifdef AUDIO_VISUALIZATION
0140         if(m_vs->rdft) {
0141             av_rdft_end(m_vs->rdft);
0142             av_freep(&m_vs->rdft_data);
0143             m_vs->rdft = nullptr;
0144             m_vs->rdft_bits = 0;
0145         }
0146 #endif
0147         break;
0148     case AVMEDIA_TYPE_VIDEO:
0149         m_vs->vidDec.abort();
0150         m_vs->vidDec.destroy();
0151         break;
0152     case AVMEDIA_TYPE_SUBTITLE:
0153         m_vs->subDec.abort();
0154         m_vs->subDec.destroy();
0155         break;
0156     default:
0157         break;
0158     }
0159 
0160     ic->streams[streamIndex]->discard = AVDISCARD_ALL;
0161     switch(codecPar->codec_type) {
0162     case AVMEDIA_TYPE_AUDIO:
0163         m_vs->audStream = nullptr;
0164         m_vs->audStreamIdx = -1;
0165         break;
0166     case AVMEDIA_TYPE_VIDEO:
0167         m_vs->vidStream = nullptr;
0168         m_vs->vidStreamIdx = -1;
0169         break;
0170     case AVMEDIA_TYPE_SUBTITLE:
0171         m_vs->subStream = nullptr;
0172         m_vs->subStreamIdx = -1;
0173         break;
0174     default:
0175         break;
0176     }
0177 }
0178 
0179 void
0180 StreamDemuxer::pauseToggle()
0181 {
0182     if(m_vs->paused) {
0183         m_vs->frameTimer += av_gettime_relative() / double(AV_TIME_BASE) - m_vs->vidClk.lastUpdated();
0184         if(m_vs->readPauseReturn != AVERROR(ENOSYS))
0185             m_vs->vidClk.pause(0);
0186         m_vs->vidClk.set(m_vs->vidClk.get(), m_vs->vidClk.serial());
0187         m_vs->audDec.play();
0188     } else {
0189         m_vs->audDec.pause();
0190     }
0191     m_vs->extClk.set(m_vs->extClk.get(), m_vs->extClk.serial());
0192     m_vs->paused = !m_vs->paused;
0193     m_vs->audClk.pause(m_vs->paused);
0194     m_vs->vidClk.pause(m_vs->paused);
0195     m_vs->extClk.pause(m_vs->paused);
0196 }
0197 
0198 void
0199 StreamDemuxer::seek(qint64 time)
0200 {
0201     m_vs->seekFlags &= ~AVSEEK_FLAG_BYTE;
0202     if(m_vs->seek_by_bytes) {
0203         m_vs->seekFlags |= AVSEEK_FLAG_BYTE;
0204         m_vs->seekPos = double(time) * (m_vs->fmtContext->bit_rate ? double(m_vs->fmtContext->bit_rate) / 8. : 180000.);
0205     } else {
0206         m_vs->seekPos = time;
0207     }
0208     m_vs->seekReq = true;
0209     m_vs->audDec.flush();
0210     m_vs->continueReadThread->wakeOne();
0211 }
0212 
0213 void
0214 StreamDemuxer::stepFrame()
0215 {
0216     if(m_vs->paused)
0217         pauseToggle();
0218     m_vs->step = 1;
0219 }
0220 
0221 bool
0222 StreamDemuxer::abortRequested()
0223 {
0224     return m_vs->abortRequested;
0225 }
0226 
0227 // open a given stream. Return 0 if OK
0228 int
0229 StreamDemuxer::componentOpen(int streamIndex)
0230 {
0231     AVFormatContext *ic = m_vs->fmtContext;
0232     AVCodecContext *avCtx;
0233     const AVCodec *codec;
0234     AVDictionary *opts = nullptr;
0235     AVDictionaryEntry *t = nullptr;
0236     int sampleRate, nbChannels;
0237     int64_t channelLayout;
0238     int ret = 0;
0239     int stream_lowres = m_vs->lowres;
0240 
0241     if(streamIndex < 0 || streamIndex >= (int)ic->nb_streams)
0242         return -1;
0243 
0244     avCtx = avcodec_alloc_context3(nullptr);
0245     if(!avCtx)
0246         return AVERROR(ENOMEM);
0247 
0248     ret = avcodec_parameters_to_context(avCtx, ic->streams[streamIndex]->codecpar);
0249     if(ret < 0)
0250         goto fail;
0251     avCtx->pkt_timebase = ic->streams[streamIndex]->time_base;
0252 
0253     codec = avcodec_find_decoder(avCtx->codec_id);
0254 
0255     switch(avCtx->codec_type) {
0256     case AVMEDIA_TYPE_AUDIO   :
0257         m_vs->lastAudioStream = streamIndex;
0258         break;
0259     case AVMEDIA_TYPE_SUBTITLE:
0260         m_vs->lastSubtitleStream = streamIndex;
0261         break;
0262     case AVMEDIA_TYPE_VIDEO   :
0263         m_vs->lastVideoStream = streamIndex;
0264         break;
0265     default:
0266         break;
0267     }
0268     if(!codec) {
0269         av_log(nullptr, AV_LOG_WARNING, "No decoder could be found for codec %s\n", avcodec_get_name(avCtx->codec_id));
0270         ret = AVERROR(EINVAL);
0271         goto fail;
0272     }
0273 
0274     avCtx->codec_id = codec->id;
0275     if(stream_lowres > codec->max_lowres) {
0276         av_log(avCtx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
0277                codec->max_lowres);
0278         stream_lowres = codec->max_lowres;
0279     }
0280     avCtx->lowres = stream_lowres;
0281 
0282     if(m_vs->fast)
0283         avCtx->flags2 |= AV_CODEC_FLAG2_FAST;
0284 
0285     if(!av_dict_get(opts, "threads", nullptr, 0))
0286         av_dict_set(&opts, "threads", "auto", 0);
0287     if(stream_lowres)
0288         av_dict_set_int(&opts, "lowres", stream_lowres, 0);
0289     if((ret = avcodec_open2(avCtx, codec, &opts)) < 0) {
0290         char e[AV_ERROR_MAX_STRING_SIZE];
0291         av_log(nullptr, AV_LOG_ERROR, "Failed opening codec err:%d - %s.\n", ret, av_make_error_string(e, sizeof(e), ret));
0292         goto fail;
0293     }
0294     if((t = av_dict_get(opts, "", nullptr, AV_DICT_IGNORE_SUFFIX))) {
0295         av_log(nullptr, AV_LOG_WARNING, "AVCodec option %s not found.\n", t->key);
0296     }
0297 
0298     m_vs->eof = false;
0299     ic->streams[streamIndex]->discard = AVDISCARD_DEFAULT;
0300     switch(avCtx->codec_type) {
0301     case AVMEDIA_TYPE_AUDIO:
0302         sampleRate = avCtx->sample_rate;
0303         nbChannels = avCtx->channels;
0304         channelLayout = avCtx->channel_layout;
0305 
0306         // prepare audio output
0307         if(!m_vs->audDec.open(channelLayout, nbChannels, sampleRate))
0308             goto fail;
0309 
0310         m_vs->audStreamIdx = streamIndex;
0311         m_vs->audStream = ic->streams[streamIndex];
0312 
0313         m_vs->audDec.init(avCtx, &m_vs->audPQ, nullptr, m_vs->continueReadThread);
0314         if((m_vs->fmtContext->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) &&
0315            !m_vs->fmtContext->iformat->read_seek) {
0316             m_vs->audDec.startPts(m_vs->audStream->start_time, m_vs->audStream->time_base);
0317         }
0318         m_vs->audDec.start();
0319         m_vs->audDec.pause();
0320         break;
0321     case AVMEDIA_TYPE_VIDEO:
0322         m_vs->vidStreamIdx = streamIndex;
0323         m_vs->vidStream = ic->streams[streamIndex];
0324 
0325         m_vs->vidDec.init(avCtx, &m_vs->vidPQ, &m_vs->vidFQ, m_vs->continueReadThread);
0326         m_vs->vidDec.start();
0327         m_vs->queueAttachmentsReq = true;
0328         break;
0329     case AVMEDIA_TYPE_SUBTITLE:
0330         m_vs->subStreamIdx = streamIndex;
0331         m_vs->subStream = ic->streams[streamIndex];
0332 
0333         m_vs->subDec.init(avCtx, &m_vs->subPQ, &m_vs->subFQ, m_vs->continueReadThread);
0334         m_vs->subDec.start();
0335         break;
0336     default:
0337         break;
0338     }
0339     goto out;
0340 
0341 fail:
0342     avcodec_free_context(&avCtx);
0343 out:
0344     av_dict_free(&opts);
0345 
0346     return ret;
0347 }
0348 
0349 void
0350 StreamDemuxer::cycleStream(int codecType)
0351 {
0352     int startIndex, oldIndex;
0353     if(codecType == AVMEDIA_TYPE_VIDEO) {
0354         startIndex = m_vs->lastVideoStream;
0355         oldIndex = m_vs->vidStreamIdx;
0356     } else if(codecType == AVMEDIA_TYPE_AUDIO) {
0357         startIndex = m_vs->lastAudioStream;
0358         oldIndex = m_vs->audStreamIdx;
0359     } else {
0360         startIndex = m_vs->lastSubtitleStream;
0361         oldIndex = m_vs->subStreamIdx;
0362     }
0363     int streamIndex = startIndex;
0364 
0365     AVProgram *p = nullptr;
0366     AVFormatContext *ic = m_vs->fmtContext;
0367     int nbStreams = m_vs->fmtContext->nb_streams;
0368     if(codecType != AVMEDIA_TYPE_VIDEO && m_vs->vidStreamIdx != -1) {
0369         p = av_find_program_from_stream(ic, nullptr, m_vs->vidStreamIdx);
0370         if(p) {
0371             nbStreams = p->nb_stream_indexes;
0372             for(startIndex = 0; startIndex < nbStreams; startIndex++)
0373                 if((int)p->stream_index[startIndex] == streamIndex)
0374                     break;
0375             if(startIndex == nbStreams)
0376                 startIndex = -1;
0377             streamIndex = startIndex;
0378         }
0379     }
0380 
0381     for(;;) {
0382         if(++streamIndex >= nbStreams) {
0383             if(codecType == AVMEDIA_TYPE_SUBTITLE) {
0384                 streamIndex = -1;
0385                 m_vs->lastSubtitleStream = -1;
0386                 goto the_end;
0387             }
0388             if(startIndex == -1)
0389                 return;
0390             streamIndex = 0;
0391         }
0392         if(streamIndex == startIndex)
0393             return;
0394         AVStream *st = m_vs->fmtContext->streams[p ? p->stream_index[streamIndex] : streamIndex];
0395         if(st->codecpar->codec_type == codecType) {
0396             /* check that parameters are OK */
0397             switch(codecType) {
0398             case AVMEDIA_TYPE_AUDIO:
0399                 if(st->codecpar->sample_rate != 0 &&
0400                    st->codecpar->channels != 0)
0401                     goto the_end;
0402                 break;
0403             case AVMEDIA_TYPE_VIDEO:
0404             case AVMEDIA_TYPE_SUBTITLE:
0405                 goto the_end;
0406             default:
0407                 break;
0408             }
0409         }
0410     }
0411 the_end:
0412     if(p && streamIndex != -1)
0413         streamIndex = p->stream_index[streamIndex];
0414     av_log(nullptr, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
0415            av_get_media_type_string((AVMediaType)codecType),
0416            oldIndex, streamIndex);
0417 
0418     componentClose(oldIndex);
0419     componentOpen(streamIndex);
0420 }
0421 
0422 int
0423 StreamDemuxer::relativeStreamIndex(int codecType, int absoluteIndex)
0424 {
0425     int idx = 0;
0426     for(int i = 0; i < int(m_vs->fmtContext->nb_streams); i++) {
0427         if(m_vs->fmtContext->streams[i]->codecpar->codec_type != codecType)
0428             continue;
0429         if(i == absoluteIndex)
0430             return idx;
0431         idx++;
0432     }
0433     return -1;
0434 }
0435 
0436 int
0437 StreamDemuxer::absoluteStreamIndex(int codecType, int relativeIndex)
0438 {
0439     int idx = 0;
0440     for(int i = 0; i < int(m_vs->fmtContext->nb_streams); i++) {
0441         if(m_vs->fmtContext->streams[i]->codecpar->codec_type != codecType)
0442             continue;
0443         if(idx == relativeIndex)
0444             return i;
0445         idx++;
0446     }
0447     return -1;
0448 }
0449 
0450 void
0451 StreamDemuxer::selectStream(int codecType, int streamIndex)
0452 {
0453     int oldIndex;
0454     if(codecType == AVMEDIA_TYPE_VIDEO)
0455         oldIndex = m_vs->vidStreamIdx;
0456     else if(codecType == AVMEDIA_TYPE_AUDIO)
0457         oldIndex = m_vs->audStreamIdx;
0458     else
0459         oldIndex = m_vs->subStreamIdx;
0460 
0461     if(streamIndex < 0)
0462         streamIndex = -1;
0463 
0464     av_log(nullptr, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
0465            av_get_media_type_string((AVMediaType)codecType), oldIndex, streamIndex);
0466 
0467     componentClose(oldIndex);
0468     componentOpen(streamIndex);
0469 }
0470 
0471 void
0472 StreamDemuxer::run()
0473 {
0474     AVFormatContext *ic = nullptr;
0475     int err, i;
0476     int strIndex[AVMEDIA_TYPE_NB];
0477     QMutex wait_mutex;
0478     AVPacket *pkt = nullptr;
0479 
0480     memset(strIndex, -1, sizeof(strIndex));
0481     m_vs->eof = false;
0482 
0483     ic = avformat_alloc_context();
0484     if(!ic) {
0485         av_log(nullptr, AV_LOG_FATAL, "Could not allocate context.\n");
0486         goto cleanup;
0487     }
0488     ic->interrupt_callback.opaque = m_vs;
0489     ic->interrupt_callback.callback = [](void *ctx)->int {
0490         VideoState *is = (VideoState *)ctx;
0491         return is->abortRequested;
0492     };
0493     err = avformat_open_input(&ic, m_vs->filename.toUtf8(), nullptr, nullptr/*&format_opts*/);
0494     if(err < 0) {
0495         print_error(m_vs->filename.toUtf8(), err);
0496         goto cleanup;
0497     }
0498     m_vs->fmtContext = ic;
0499 
0500     if(m_vs->genpts)
0501         ic->flags |= AVFMT_FLAG_GENPTS;
0502 
0503     av_format_inject_global_side_data(ic);
0504 
0505     { // find_stream_info
0506         const int origNbStreams = ic->nb_streams;
0507         AVDictionary **opts = (AVDictionary **)av_calloc(origNbStreams, sizeof(*opts));
0508         if(!opts) {
0509             av_log(nullptr, AV_LOG_ERROR, "Could not alloc memory for stream options.\n");
0510             goto cleanup;
0511         }
0512 
0513         err = avformat_find_stream_info(ic, opts);
0514 
0515         for(i = 0; i < origNbStreams; i++)
0516             av_dict_free(&opts[i]);
0517         av_freep(&opts);
0518 
0519         if(err < 0) {
0520             av_log(nullptr, AV_LOG_WARNING, "%s: could not find codec parameters\n", m_vs->filename.toUtf8().data());
0521             goto cleanup;
0522         }
0523     }
0524 
0525     if(ic->pb)
0526         ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end
0527 
0528     if(m_vs->seek_by_bytes < 0)
0529         m_vs->seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name);
0530 
0531     m_vs->maxFrameDuration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;
0532 
0533     // seeking requested, execute it
0534     if(m_vs->start_time != AV_NOPTS_VALUE) {
0535         int64_t timestamp = m_vs->start_time;
0536         // add the stream start time
0537         if(ic->start_time != AV_NOPTS_VALUE)
0538             timestamp += ic->start_time;
0539         if(avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0) < 0)
0540             av_log(nullptr, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n", m_vs->filename.toUtf8().data(), double(timestamp) / AV_TIME_BASE);
0541     }
0542 
0543     m_vs->realTime = isRealTime(ic);
0544 
0545     av_dump_format(ic, 0, m_vs->filename.toUtf8(), 0);
0546 
0547     for(i = 0; i < (int)ic->nb_streams; i++)
0548         ic->streams[i]->discard = AVDISCARD_ALL;
0549 
0550     strIndex[AVMEDIA_TYPE_VIDEO] = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, strIndex[AVMEDIA_TYPE_VIDEO], -1, nullptr, 0);
0551     strIndex[AVMEDIA_TYPE_AUDIO] = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, strIndex[AVMEDIA_TYPE_AUDIO], strIndex[AVMEDIA_TYPE_VIDEO], nullptr, 0);
0552 
0553     // open the streams
0554     if(strIndex[AVMEDIA_TYPE_AUDIO] >= 0)
0555         componentOpen(strIndex[AVMEDIA_TYPE_AUDIO]);
0556 
0557     {
0558         const int vidMode = strIndex[AVMEDIA_TYPE_VIDEO] >= 0 ? componentOpen(strIndex[AVMEDIA_TYPE_VIDEO]) : -1;
0559         m_vs->showMode = vidMode >= 0 ? SHOW_MODE_VIDEO :
0560 #ifdef AUDIO_VISUALIZATION
0561                                 SHOW_MODE_RDFT
0562 #else
0563                                 SHOW_MODE_NB
0564 #endif
0565                                 ;
0566     }
0567 
0568     if(strIndex[AVMEDIA_TYPE_SUBTITLE] >= 0)
0569         componentOpen(strIndex[AVMEDIA_TYPE_SUBTITLE]);
0570 
0571     if(m_vs->vidStreamIdx < 0 && m_vs->audStreamIdx < 0) {
0572         av_log(nullptr, AV_LOG_FATAL, "Failed to open file '%s'\n", m_vs->filename.toUtf8().data());
0573         goto cleanup;
0574     }
0575 
0576     if(m_vs->infinite_buffer < 0 && m_vs->realTime)
0577         m_vs->infinite_buffer = 1;
0578 
0579     m_vs->notifyLoaded();
0580 
0581     for(;;) {
0582         if(m_vs->abortRequested)
0583             break;
0584         if(m_vs->paused != m_vs->lastPaused) {
0585             m_vs->lastPaused = m_vs->paused;
0586             if(m_vs->paused)
0587                 m_vs->readPauseReturn = av_read_pause(ic);
0588             else
0589                 av_read_play(ic);
0590         }
0591         if(m_vs->seekReq) {
0592             const int64_t seekTarget = m_vs->seekPos;
0593             // seeks are inaccurate so seek to previous keyframe and then retrive/decode frames until is->seek_pos
0594             m_vs->seekDecoder = seekTarget / double(AV_TIME_BASE);
0595             if(av_seek_frame(m_vs->fmtContext, -1, seekTarget, m_vs->seekFlags | AVSEEK_FLAG_BACKWARD) < 0) {
0596                 m_vs->seekDecoder = 0.;
0597                 av_log(nullptr, AV_LOG_ERROR, "%s: error while seeking\n",
0598 #if LIBAVFORMAT_VERSION_MAJOR < 58
0599                        m_vs->fmtContext->filename
0600 #else
0601                        m_vs->fmtContext->url
0602 #endif
0603                        );
0604             } else {
0605                 if(m_vs->audStreamIdx >= 0) {
0606                     m_vs->audPQ.flush();
0607                     m_vs->audPQ.putFlushPacket();
0608                 }
0609                 if(m_vs->subStreamIdx >= 0) {
0610                     m_vs->subPQ.flush();
0611                     m_vs->subPQ.putFlushPacket();
0612                 }
0613                 if(m_vs->vidStreamIdx >= 0) {
0614                     m_vs->vidPQ.flush();
0615                     m_vs->vidPQ.putFlushPacket();
0616                 }
0617                 if(m_vs->seekFlags & AVSEEK_FLAG_BYTE) {
0618                     m_vs->extClk.set(NAN, 0);
0619                 } else {
0620                     m_vs->extClk.set(seekTarget / (double)AV_TIME_BASE, 0);
0621                 }
0622                 m_vs->vidClk.set(NAN, 0);
0623                 m_vs->audClk.set(NAN, 0);
0624             }
0625             m_vs->seekReq = false;
0626             m_vs->queueAttachmentsReq = true;
0627             m_vs->eof = false;
0628             if(m_vs->paused)
0629                 stepFrame();
0630         }
0631         if(m_vs->queueAttachmentsReq) {
0632             if(m_vs->vidStream && m_vs->vidStream->disposition & AV_DISPOSITION_ATTACHED_PIC) {
0633                 AVPacket *copy = av_packet_alloc();
0634                 if(av_packet_ref(copy, &m_vs->vidStream->attached_pic) < 0) {
0635                     av_packet_free(&copy);
0636                     goto cleanup;
0637                 }
0638                 m_vs->vidPQ.put(&copy);
0639                 m_vs->vidPQ.putNullPacket(m_vs->vidStreamIdx);
0640             }
0641             m_vs->queueAttachmentsReq = false;
0642         }
0643 
0644         // wait 10 ms if queues are full
0645         if(m_vs->infinite_buffer < 1 && m_vs->streamsHaveEnoughPackets()) {
0646             wait_mutex.lock();
0647             m_vs->continueReadThread->wait(&wait_mutex, 10);
0648             wait_mutex.unlock();
0649             continue;
0650         }
0651         // pause when EOF reached
0652         if(!m_vs->paused && m_vs->reachedEOF()) {
0653             m_vs->step = 0;
0654             pauseToggle();
0655             m_vs->notifyState();
0656         }
0657         if(!pkt)
0658             pkt = av_packet_alloc();
0659         if(int ret = av_read_frame(ic, pkt) < 0) {
0660             if((ret == AVERROR_EOF || avio_feof(ic->pb)) && !m_vs->eof) {
0661                 if(m_vs->vidStreamIdx >= 0)
0662                     m_vs->vidPQ.putNullPacket(m_vs->vidStreamIdx);
0663                 if(m_vs->audStreamIdx >= 0)
0664                     m_vs->audPQ.putNullPacket(m_vs->audStreamIdx);
0665                 if(m_vs->subStreamIdx >= 0)
0666                     m_vs->subPQ.putNullPacket(m_vs->subStreamIdx);
0667                 m_vs->eof = true;
0668             }
0669             if(ic->pb && ic->pb->error)
0670                 break;
0671             wait_mutex.lock();
0672             m_vs->continueReadThread->wait(&wait_mutex, 10);
0673             wait_mutex.unlock();
0674             continue;
0675         } else {
0676             m_vs->eof = false;
0677         }
0678         if(pkt->stream_index == m_vs->audStreamIdx) {
0679             m_vs->audPQ.put(&pkt);
0680         } else if(pkt->stream_index == m_vs->vidStreamIdx && m_vs->vidStream && !(m_vs->vidStream->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
0681             m_vs->vidPQ.put(&pkt);
0682         } else if(pkt->stream_index == m_vs->subStreamIdx) {
0683             m_vs->subPQ.put(&pkt);
0684         } else {
0685             av_packet_unref(pkt);
0686         }
0687     }
0688     m_vs->notifyState();
0689 
0690 cleanup:
0691     if(ic && !m_vs->fmtContext)
0692         avformat_close_input(&ic);
0693 }