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 "videodecoder.h"
0009 
0010 #include "videoplayer/backend/ffplayer.h"
0011 #include "videoplayer/backend/videostate.h"
0012 
0013 extern "C" {
0014 #include "libavutil/rational.h"
0015 }
0016 
0017 using namespace SubtitleComposer;
0018 
0019 VideoDecoder::VideoDecoder(VideoState *state, QObject *parent)
0020     : Decoder(parent),
0021       m_vs(state),
0022       m_timeBase(0.),
0023       m_frameDropsEarly(0)
0024 {
0025 }
0026 
0027 int
0028 VideoDecoder::getVideoFrame(AVFrame *frame)
0029 {
0030     const int gotPicture = decodeFrame(frame, nullptr);
0031     if(gotPicture <= 0)
0032         return gotPicture;
0033 
0034     frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(m_vs->fmtContext, m_vs->vidStream, frame);
0035 
0036     if(frame->pts != AV_NOPTS_VALUE) {
0037         const double dPts = m_timeBase * frame->pts;
0038         if(m_vs->seekDecoder > 0. && !std::isnan(dPts) && m_vs->seekDecoder > dPts) {
0039             m_frameDropsEarly++;
0040             av_frame_unref(frame);
0041             return 0;
0042         }
0043         if(m_vs->framedrop > 0 || (m_vs->framedrop && m_vs->masterSyncType() != AV_SYNC_VIDEO_MASTER)) {
0044             const double diff = dPts - m_vs->masterTime();
0045             if(!std::isnan(diff) && diff < 0 && fabs(diff) < AV_NOSYNC_THRESHOLD
0046             && pktSerial() == m_vs->vidClk.serial() && m_queue->nbPackets()) {
0047                 m_frameDropsEarly++;
0048                 av_frame_unref(frame);
0049                 return 0;
0050             }
0051         }
0052     }
0053 
0054     return gotPicture;
0055 }
0056 
0057 int
0058 VideoDecoder::queuePicture(AVFrame *srcFrame, double pts, double duration, int64_t pos, int serial)
0059 {
0060 #if defined(DEBUG_SYNC)
0061     printf("frame_type=%c pts=%0.3f\n", av_get_picture_type_char(src_frame->pict_type), pts);
0062 #endif
0063 
0064     Frame *vp = m_frameQueue->peekWritable();
0065     if(!vp)
0066         return -1;
0067 
0068     vp->sar = srcFrame->sample_aspect_ratio;
0069     vp->uploaded = false;
0070 
0071     vp->width = srcFrame->width;
0072     vp->height = srcFrame->height;
0073     vp->format = srcFrame->format;
0074 
0075     vp->pts = pts;
0076     vp->duration = duration;
0077     vp->pos = pos;
0078     vp->serial = serial;
0079 
0080     av_frame_move_ref(vp->frame, srcFrame);
0081     m_frameQueue->push();
0082     return 0;
0083 }
0084 
0085 void
0086 VideoDecoder::run()
0087 {
0088     AVFrame *frame = av_frame_alloc();
0089     m_timeBase = av_q2d(m_vs->vidStream->time_base);
0090 
0091     if(!frame)
0092         return;
0093 
0094     const AVRational fps = av_guess_frame_rate(m_vs->fmtContext, m_vs->vidStream, nullptr);
0095     const double frameDuration = fps.num ? double(fps.den) / fps.num : 0.0;
0096 
0097     for(;;) {
0098         int ret = getVideoFrame(frame);
0099         if(ret < 0)
0100             break;
0101         if(!ret)
0102             continue;
0103 
0104         double pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * m_timeBase;
0105         ret = queuePicture(frame, pts, frameDuration, frame->pkt_pos, pktSerial());
0106         av_frame_unref(frame);
0107 
0108         if(ret < 0)
0109             break;
0110     }
0111 
0112     av_frame_free(&frame);
0113 }