1 /*
2     SPDX-FileCopyrightText: 2003 Fabrice Bellard
3     SPDX-FileCopyrightText: 2020 Mladen Milinkovic <max@smoothware.net>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #ifndef VIDEOSTATE_H
9 #define VIDEOSTATE_H
10 
11 #include <cmath>
12 
13 #include "videoplayer/backend/videodecoder.h"
14 #include "videoplayer/backend/audiodecoder.h"
15 #include "videoplayer/backend/subtitledecoder.h"
16 #include "videoplayer/backend/framequeue.h"
17 #include "videoplayer/backend/packetqueue.h"
18 #include "videoplayer/backend/streamdemuxer.h"
19 #include "videoplayer/backend/clock.h"
20 
21 #include <QString>
22 #include <QWaitCondition>
23 
24 extern "C" {
25 #include "libavformat/avformat.h"
26 #include "libavcodec/avfft.h"
27 }
28 
29 
30 #define MAX_VOLUME 1.0
31 
32 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
33 #define MIN_FRAMES 25
34 #define EXTERNAL_CLOCK_MIN_FRAMES 2
35 #define EXTERNAL_CLOCK_MAX_FRAMES 10
36 
37 // no AV sync correction is done if below the minimum AV sync threshold
38 #define AV_SYNC_THRESHOLD_MIN 0.04
39 // AV sync correction is done if above the maximum AV sync threshold
40 #define AV_SYNC_THRESHOLD_MAX 0.1
41 // If a frame duration is longer than this, it will not be duplicated to compensate AV sync
42 #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
43 
44 // external clock speed adjustment constants for realtime sources based on buffer fullness
45 #define EXTERNAL_CLOCK_SPEED_MIN  0.900
46 #define EXTERNAL_CLOCK_SPEED_MAX  1.010
47 #define EXTERNAL_CLOCK_SPEED_STEP 0.001
48 
49 // polls for possible required screen refresh at least this often, should be less than 1/fps
50 #define REFRESH_RATE 0.01
51 
52 #define CURSOR_HIDE_DELAY 1000000
53 
54 #define USE_ONEPASS_SUBTITLE_RENDER 1
55 
56 // TODO: support audio and subtitle rendering
57 #undef AUDIO_VISUALIZATION
58 #undef VIDEO_SUBTITLE
59 
60 namespace SubtitleComposer {
61 class RenderThread;
62 class GLRenderer;
63 
64 enum {
65 	AV_SYNC_AUDIO_MASTER,
66 	AV_SYNC_VIDEO_MASTER,
67 	AV_SYNC_EXTERNAL_CLOCK
68 };
69 
70 enum ShowMode {
71 	SHOW_MODE_NONE = -1,
72 	SHOW_MODE_VIDEO = 0,
73 #ifdef AUDIO_VISUALIZATION
74 	SHOW_MODE_WAVES,
75 	SHOW_MODE_RDFT,
76 #endif
77 	SHOW_MODE_NB
78 };
79 
80 class VideoState {
81 	friend class FFPlayer;
82 	friend class RenderThread;
83 	friend class AudioDecoder;
84 	friend class VideoDecoder;
85 	friend class SubtitleDecoder;
86 	friend class PacketQueue;
87 	friend class FrameQueue;
88 	friend class StreamDemuxer;
89 
90 private:
91 	VideoState();
92 
streamHasEnoughPackets(AVStream * st,int streamId,PacketQueue * q)93 	inline bool streamHasEnoughPackets(AVStream *st, int streamId, PacketQueue *q) {
94 		return streamId < 0
95 			|| q->abortRequested()
96 			|| (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
97 			|| (q->nbPackets() > MIN_FRAMES && (!q->duration() || av_q2d(st->time_base) * q->duration() > 1.0));
98 	}
99 
streamsHaveEnoughPackets()100 	inline bool streamsHaveEnoughPackets() {
101 		return audPQ.size() + vidPQ.size() + subPQ.size() > MAX_QUEUE_SIZE
102 			|| (streamHasEnoughPackets(audStream, audStreamIdx, &audPQ)
103 				&& streamHasEnoughPackets(vidStream, vidStreamIdx, &vidPQ)
104 				&& streamHasEnoughPackets(subStream, subStreamIdx, &subPQ));
105 	}
106 
reachedEOF()107 	inline bool reachedEOF() {
108 		return (!audStream || (audDec.finished() == audPQ.serial()))
109 			&& (!vidStream || (vidDec.finished() == vidPQ.serial() && vidFQ.nbRemaining() == 0));
110 	}
111 
position()112 	inline double position() {
113 		const double pos = masterTime();
114 		return std::isnan(pos) ? double(seekPos) / AV_TIME_BASE : pos;
115 	}
116 
117 	int masterSyncType();
118 	Clock * masterClock();
119 	double masterTime();
120 	void checkExternalClockSpeed();
121 
122 	void notifyLoaded();
123 	void notifySpeed();
124 	void notifyState();
125 
126 private: // settings
127 	int seek_by_bytes = -1;
128 	int av_sync_type = AV_SYNC_AUDIO_MASTER;
129 	int64_t start_time = AV_NOPTS_VALUE;
130 	int fast = 0;
131 	int genpts = 0;
132 	int lowres = 0;
133 	int framedrop = -1;
134 	int infinite_buffer = -1;
135 	double rdftspeed = 0.02;
136 	int autorotate = 1;
137 
138 private:
139 	bool abortRequested = false;
140 	bool paused = false;
141 	bool lastPaused = false;
142 	int step = 0;
143 	int readPauseReturn = 0;
144 	bool queueAttachmentsReq = false;
145 	bool seekReq = false;
146 	double seekDecoder = 0.;
147 	int seekFlags = 0;
148 	int64_t seekPos = 0;
149 	AVFormatContext *fmtContext = nullptr;
150 	bool realTime = false;
151 
152 	FFPlayer *player = nullptr;
153 	StreamDemuxer *demuxer = nullptr;
154 	GLRenderer *glRenderer = nullptr;
155 	RenderThread *renderThread = nullptr;
156 
157 	ShowMode showMode = SHOW_MODE_NONE;
158 	bool forceRefresh = true;
159 
160 	Clock audClk;
161 	AudioDecoder audDec;
162 	int audStreamIdx = -1;
163 	AVStream *audStream = nullptr;
164 	PacketQueue audPQ;
165 	int frameDropsLate = 0;
166 
167 #ifdef AUDIO_VISUALIZATION
168 	QVector<int16_t> sample_array;
169 	int sample_array_index = 0;
170 	int last_i_start = 0;
171 	RDFTContext *rdft = nullptr;
172 	int rdft_bits = 0;
173 	FFTSample *rdft_data = nullptr;
174 	double last_vis_time = 0.;
175 #endif
176 
177 	Clock extClk;
178 
179 	SubtitleDecoder subDec;
180 	int subStreamIdx = -1;
181 	AVStream *subStream = nullptr;
182 	PacketQueue subPQ;
183 	FrameQueue subFQ;
184 #ifdef VIDEO_SUBTITLE
185 	SwsContext *subConvertCtx = nullptr;
186 #endif
187 
188 	Clock vidClk;
189 	VideoDecoder vidDec;
190 	double frameTimer = 0.;
191 	double frameLastReturnedTime = 0.;
192 	int vidStreamIdx = -1;
193 	AVStream *vidStream = nullptr;
194 	PacketQueue vidPQ;
195 	FrameQueue vidFQ;
196 	double maxFrameDuration = 0.; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
197 	bool eof = false;
198 
199 	QString filename;
200 
201 	int lastVideoStream = -1;
202 	int lastAudioStream = -1;
203 	int lastSubtitleStream = -1;
204 
205 	QWaitCondition *continueReadThread = nullptr;
206 };
207 }
208 
209 #endif // VIDEOSTATE_H
210