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 "videostate.h"
0009 
0010 #include <KLocalizedString>
0011 #include "helpers/languagecode.h"
0012 #include "videoplayer/backend/ffplayer.h"
0013 
0014 using namespace SubtitleComposer;
0015 
0016 VideoState::VideoState()
0017     : audDec(this),
0018 #ifdef AUDIO_VISUALIZATION
0019       sample_array(8 * 65536),
0020 #endif
0021       vidDec(this)
0022 {
0023 }
0024 
0025 int
0026 VideoState::masterSyncType() {
0027     if(av_sync_type == AV_SYNC_VIDEO_MASTER)
0028         return vidStream ? AV_SYNC_VIDEO_MASTER : AV_SYNC_AUDIO_MASTER;
0029     if(av_sync_type == AV_SYNC_AUDIO_MASTER)
0030         return audStream ? AV_SYNC_AUDIO_MASTER : AV_SYNC_EXTERNAL_CLOCK;
0031     return AV_SYNC_EXTERNAL_CLOCK;
0032 }
0033 
0034 Clock *
0035 VideoState::masterClock()
0036 {
0037     switch(masterSyncType()) {
0038     case AV_SYNC_VIDEO_MASTER: return &vidClk;
0039     case AV_SYNC_AUDIO_MASTER: return &audClk;
0040     default: return &extClk;
0041     }
0042 }
0043 
0044 
0045 double
0046 VideoState::masterTime()
0047 {
0048     switch(masterSyncType()) {
0049     case AV_SYNC_VIDEO_MASTER: return vidClk.get();
0050     case AV_SYNC_AUDIO_MASTER: return audClk.get();
0051     default: return extClk.get();
0052     }
0053 }
0054 
0055 void
0056 VideoState::checkExternalClockSpeed()
0057 {
0058     if((vidStreamIdx >= 0 && vidPQ.nbPackets() <= EXTERNAL_CLOCK_MIN_FRAMES) || (audStreamIdx >= 0 && audPQ.nbPackets() <= EXTERNAL_CLOCK_MIN_FRAMES)) {
0059         extClk.setSpeed(FFMAX(EXTERNAL_CLOCK_SPEED_MIN, extClk.speed() - EXTERNAL_CLOCK_SPEED_STEP));
0060     } else if((vidStreamIdx < 0 || vidPQ.nbPackets() > EXTERNAL_CLOCK_MAX_FRAMES) && (audStreamIdx < 0 || audPQ.nbPackets() > EXTERNAL_CLOCK_MAX_FRAMES)) {
0061         extClk.setSpeed(FFMIN(EXTERNAL_CLOCK_SPEED_MAX, extClk.speed() + EXTERNAL_CLOCK_SPEED_STEP));
0062     } else {
0063         const double speed = extClk.speed();
0064         if(speed != 1.0)
0065             extClk.setSpeed(speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
0066     }
0067 }
0068 
0069 void
0070 VideoState::notifyState()
0071 {
0072     if(abortRequested)
0073         emit player->stateChanged(FFPlayer::Stopped);
0074     else if(paused || step)
0075         emit player->stateChanged(FFPlayer::Paused);
0076     else
0077         emit player->stateChanged(FFPlayer::Playing);
0078 }
0079 
0080 void
0081 VideoState::notifySpeed()
0082 {
0083     const double speed = audDec.pitch();
0084     masterClock()->setSpeed(speed);
0085     emit player->speedChanged(speed);
0086 }
0087 
0088 void
0089 VideoState::notifyLoaded()
0090 {
0091     emit player->mediaLoaded();
0092 
0093     const AVStream *st = audStream ? audStream : vidStream;
0094     const double streamDuration = double(st->duration) * st->time_base.num / st->time_base.den;
0095     const double containerDuration = double(fmtContext->duration) / AV_TIME_BASE;
0096     emit player->durationChanged(qMax(streamDuration, containerDuration));
0097 
0098     notifySpeed();
0099     emit player->volumeChanged(player->volume());
0100     emit player->muteChanged(player->muted());
0101 
0102     QStringList audioStreams, videoStreams, subtitleStreams;
0103     const AVCodecDescriptor *desc;
0104     for(unsigned int i = 0; i < fmtContext->nb_streams; i++) {
0105         AVStream *stream = fmtContext->streams[i];
0106         QString *streamName;
0107 
0108         switch(stream->codecpar->codec_type) {
0109         case AVMEDIA_TYPE_VIDEO:
0110             videoStreams.append(i18n("Video Stream #%1", videoStreams.size() + 1));
0111             streamName = &videoStreams.last();
0112             break;
0113         case AVMEDIA_TYPE_AUDIO:
0114             audioStreams.append(i18n("Audio Stream #%1", audioStreams.size() + 1));
0115             streamName = &audioStreams.last();
0116             break;
0117         case AVMEDIA_TYPE_SUBTITLE:
0118             desc = avcodec_descriptor_get(stream->codecpar->codec_id);
0119             if(desc && (desc->props & AV_CODEC_PROP_TEXT_SUB)) {
0120                 subtitleStreams.append(i18n("Subtitle Stream #%1", subtitleStreams.size() + 1));
0121                 streamName = &subtitleStreams.last();
0122             } else {
0123                 streamName = nullptr;
0124             }
0125             break;
0126         default:
0127             streamName = nullptr;
0128             break;
0129         }
0130         if(!streamName)
0131             continue;
0132 
0133         *streamName += QStringLiteral(": ");
0134         AVDictionaryEntry *tag = av_dict_get(stream->metadata, "lang", nullptr, AV_DICT_IGNORE_SUFFIX);
0135         *streamName += tag ? QString("%2 (%3)").arg(LanguageCode::nameFromIso(tag->value)).arg(tag->value) : QStringLiteral("Unknown");
0136 
0137         if((tag = av_dict_get(stream->metadata, "title", nullptr, 0)) != nullptr)
0138             *streamName += QStringLiteral(": ") + QString::fromUtf8(tag->value);
0139 
0140         *streamName += QStringLiteral(" [") + QString::fromUtf8(avcodec_descriptor_get(stream->codecpar->codec_id)->name) + QStringLiteral("]");
0141 //      if(stream->codecpar->extradata)
0142 //          QByteArray((const char*)stream->codecpar->extradata, stream->codecpar->extradata_size);
0143     }
0144     emit player->videoStreamsChanged(videoStreams);
0145     emit player->audioStreamsChanged(audioStreams);
0146     emit player->subtitleStreamsChanged(subtitleStreams);
0147 
0148     notifyState();
0149 }