1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QFFMPEGPLAYBACKENGINE_P_H
4#define QFFMPEGPLAYBACKENGINE_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17/* Playback engine design description.
18 *
19 *
20 * PLAYBACK ENGINE OBJECTS
21 *
22 * - Playback engine manages 7 objects inside, each one works in a separate thread.
23 * Each object inherits PlaybackEngineObject. The objects are:
24 * Demuxer
25 * Stream Decoders: audio, video, subtitles
26 * Renderers: audio, video, subtitles
27 *
28 *
29 * THREADS:
30 *
31 * - By default, each object works in a separate thread. It's easy to reconfigure
32 * to using several objects in thread.
33 * - New thread is allocated if a new object is created and the engine doesn't
34 * have free threads. If it does, the thread is to be reused.
35 * - If all objects for some thread are deleted, the thread becomes free and the engine
36 * postpones its termination.
37 *
38 * OBJECTS WEAK CONNECTIVITY
39 *
40 * - The objects know nothing about others and about PlaybackEngine.
41 * For any interactions the objects use slots/signals.
42 *
43 * - PlaybackEngine knows the objects object and is able to create/delete them and
44 * call their public methods.
45 *
46 */
47
48#include <QtFFmpegMediaPluginImpl/private/qffmpegplaybackenginedefs_p.h>
49#include <QtFFmpegMediaPluginImpl/private/qffmpegtimecontroller_p.h>
50#include <QtFFmpegMediaPluginImpl/private/qffmpegmediadataholder_p.h>
51#include <QtFFmpegMediaPluginImpl/private/qffmpegcodeccontext_p.h>
52#include <QtFFmpegMediaPluginImpl/private/qffmpegplaybackutils_p.h>
53#include <QtFFmpegMediaPluginImpl/private/qffmpegtime_p.h>
54
55#include <QtCore/qpointer.h>
56
57#include <unordered_map>
58
59QT_BEGIN_NAMESPACE
60
61class QAudioSink;
62class QVideoSink;
63class QAudioOutput;
64class QAudioBufferOutput;
65class QFFmpegMediaPlayer;
66
67namespace QFFmpeg
68{
69
70class PlaybackEngine : public QObject
71{
72 Q_OBJECT
73public:
74 PlaybackEngine();
75
76 ~PlaybackEngine() override;
77
78 void setMedia(MediaDataHolder media);
79
80 void setVideoSink(QVideoSink *sink);
81
82 void setAudioSink(QAudioOutput *output);
83
84 void setAudioSink(QPlatformAudioOutput *output);
85
86 void setAudioBufferOutput(QAudioBufferOutput *output);
87
88 void setState(QMediaPlayer::PlaybackState state);
89
90 void play() {
91 setState(QMediaPlayer::PlayingState);
92 }
93 void pause() {
94 setState(QMediaPlayer::PausedState);
95 }
96 void stop() {
97 setState(QMediaPlayer::StoppedState);
98 }
99
100 void seek(TrackPosition pos);
101
102 void setLoops(int loopsCount);
103
104 void setPlaybackRate(float rate);
105
106 float playbackRate() const;
107
108 void setActiveTrack(QPlatformMediaPlayer::TrackType type, int streamNumber);
109
110 TrackPosition currentPosition(bool topPos = true) const;
111
112 TrackDuration duration() const;
113
114 bool isSeekable() const;
115
116 const QList<MediaDataHolder::StreamInfo> &
117 streamInfo(QPlatformMediaPlayer::TrackType trackType) const;
118
119 const QMediaMetaData &metaData() const;
120
121 int activeTrack(QPlatformMediaPlayer::TrackType type) const;
122
123signals:
124 void endOfStream();
125 void errorOccured(int, const QString &);
126 void loopChanged();
127 void buffered();
128
129protected: // objects managing
130 struct ObjectDeleter
131 {
132 void operator()(PlaybackEngineObject *) const;
133
134 PlaybackEngine *engine = nullptr;
135 };
136
137 template<typename T>
138 using ObjectPtr = std::unique_ptr<T, ObjectDeleter>;
139
140 using RendererPtr = ObjectPtr<Renderer>;
141 using StreamPtr = ObjectPtr<StreamDecoder>;
142
143 template<typename T, typename... Args>
144 ObjectPtr<T> createPlaybackEngineObject(Args &&...args);
145
146 virtual RendererPtr createRenderer(QPlatformMediaPlayer::TrackType trackType);
147
148 template <typename AudioOutput>
149 void updateActiveAudioOutput(AudioOutput *output);
150
151 void updateActiveVideoOutput(QVideoSink *sink, bool cleanOutput = false);
152
153private:
154 void createStreamAndRenderer(QPlatformMediaPlayer::TrackType trackType);
155
156 void createDemuxer();
157
158 void registerObject(PlaybackEngineObject &object);
159
160 template<typename C, typename Action>
161 void forEachExistingObject(Action &&action);
162
163 template<typename Action>
164 void forEachExistingObject(Action &&action);
165
166 void forceUpdate();
167
168 void recreateObjects();
169
170 void createObjectsIfNeeded();
171
172 void updateObjectsPausedState();
173
174 void deleteFreeThreads();
175
176 void onFirsPacketFound(quint64 id, TrackPosition absSeekPos);
177
178 void onRendererSynchronized(quint64 id, RealClock::time_point timePoint,
179 TrackPosition trackPosition);
180
181 void onRendererFinished();
182
183 void onRendererLoopChanged(quint64 id, TrackPosition offset, int loopIndex);
184
185 void triggerStepIfNeeded();
186
187 static QString objectThreadName(const PlaybackEngineObject &object);
188
189 std::optional<CodecContext> codecContextForTrack(QPlatformMediaPlayer::TrackType trackType);
190
191 bool hasMediaStream() const;
192
193 void finilizeTime(TrackPosition pos);
194
195 void finalizeOutputs();
196
197 bool hasRenderer(quint64 id) const;
198
199 void updateVideoSinkSize(QVideoSink *prevSink = nullptr);
200
201 TrackPosition boundPosition(TrackPosition position) const;
202
203private:
204 MediaDataHolder m_media;
205
206 TimeController m_timeController;
207
208 std::unordered_map<QString, std::unique_ptr<QThread>> m_threads;
209 bool m_threadsDirty = false;
210
211 QPointer<QVideoSink> m_videoSink;
212 QPointer<QAudioOutput> m_audioOutput;
213 QPointer<QAudioBufferOutput> m_audioBufferOutput;
214
215 QMediaPlayer::PlaybackState m_state = QMediaPlayer::StoppedState;
216
217 ObjectPtr<Demuxer> m_demuxer;
218 std::array<StreamPtr, QPlatformMediaPlayer::NTrackTypes> m_streams;
219 std::array<RendererPtr, QPlatformMediaPlayer::NTrackTypes> m_renderers;
220
221 bool m_shouldUpdateTimeOnFirstPacket = false;
222 bool m_seekPending = false;
223
224 std::array<std::optional<CodecContext>, QPlatformMediaPlayer::NTrackTypes> m_codecContexts;
225 int m_loops = QMediaPlayer::Once;
226 LoopOffset m_currentLoopOffset;
227};
228
229template<typename T, typename... Args>
230PlaybackEngine::ObjectPtr<T> PlaybackEngine::createPlaybackEngineObject(Args &&...args)
231{
232 auto result = ObjectPtr<T>(new T(std::forward<Args>(args)...), { this });
233 registerObject(object&: *result);
234 return result;
235}
236} // namespace QFFmpeg
237
238QT_END_NAMESPACE
239
240#endif // QFFMPEGPLAYBACKENGINE_P_H
241

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtmultimedia/src/plugins/multimedia/ffmpeg/qffmpegplaybackengine_p.h