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(©); 0636 goto cleanup; 0637 } 0638 m_vs->vidPQ.put(©); 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 }