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 "playbackengine/qffmpegplaybackenginedefs_p.h"
49#include "playbackengine/qffmpegtimecontroller_p.h"
50#include "playbackengine/qffmpegmediadataholder_p.h"
51#include "playbackengine/qffmpegcodec_p.h"
52#include "playbackengine/qffmpegpositionwithoffset_p.h"
53
54#include <QtCore/qpointer.h>
55
56#include <unordered_map>
57
58QT_BEGIN_NAMESPACE
59
60class QAudioSink;
61class QVideoSink;
62class QAudioOutput;
63class QAudioBufferOutput;
64class QFFmpegMediaPlayer;
65
66namespace QFFmpeg
67{
68
69class PlaybackEngine : public QObject
70{
71 Q_OBJECT
72public:
73 PlaybackEngine();
74
75 ~PlaybackEngine() override;
76
77 void setMedia(MediaDataHolder media);
78
79 void setVideoSink(QVideoSink *sink);
80
81 void setAudioSink(QAudioOutput *output);
82
83 void setAudioSink(QPlatformAudioOutput *output);
84
85 void setAudioBufferOutput(QAudioBufferOutput *output);
86
87 void setState(QMediaPlayer::PlaybackState state);
88
89 void play() {
90 setState(QMediaPlayer::PlayingState);
91 }
92 void pause() {
93 setState(QMediaPlayer::PausedState);
94 }
95 void stop() {
96 setState(QMediaPlayer::StoppedState);
97 }
98
99 void seek(qint64 pos);
100
101 void setLoops(int loopsCount);
102
103 void setPlaybackRate(float rate);
104
105 float playbackRate() const;
106
107 void setActiveTrack(QPlatformMediaPlayer::TrackType type, int streamNumber);
108
109 qint64 currentPosition(bool topPos = true) const;
110
111 qint64 duration() const;
112
113 bool isSeekable() const;
114
115 const QList<MediaDataHolder::StreamInfo> &
116 streamInfo(QPlatformMediaPlayer::TrackType trackType) const;
117
118 const QMediaMetaData &metaData() const;
119
120 int activeTrack(QPlatformMediaPlayer::TrackType type) const;
121
122signals:
123 void endOfStream();
124 void errorOccured(int, const QString &);
125 void loopChanged();
126 void buffered();
127
128protected: // objects managing
129 struct ObjectDeleter
130 {
131 void operator()(PlaybackEngineObject *) const;
132
133 PlaybackEngine *engine = nullptr;
134 };
135
136 template<typename T>
137 using ObjectPtr = std::unique_ptr<T, ObjectDeleter>;
138
139 using RendererPtr = ObjectPtr<Renderer>;
140 using StreamPtr = ObjectPtr<StreamDecoder>;
141
142 template<typename T, typename... Args>
143 ObjectPtr<T> createPlaybackEngineObject(Args &&...args);
144
145 virtual RendererPtr createRenderer(QPlatformMediaPlayer::TrackType trackType);
146
147 template <typename AudioOutput>
148 void updateActiveAudioOutput(AudioOutput *output);
149
150 void updateActiveVideoOutput(QVideoSink *sink, bool cleanOutput = false);
151
152private:
153 void createStreamAndRenderer(QPlatformMediaPlayer::TrackType trackType);
154
155 void createDemuxer();
156
157 void registerObject(PlaybackEngineObject &object);
158
159 template<typename C, typename Action>
160 void forEachExistingObject(Action &&action);
161
162 template<typename Action>
163 void forEachExistingObject(Action &&action);
164
165 void forceUpdate();
166
167 void recreateObjects();
168
169 void createObjectsIfNeeded();
170
171 void updateObjectsPausedState();
172
173 void deleteFreeThreads();
174
175 void onRendererSynchronized(quint64 id, std::chrono::steady_clock::time_point time,
176 qint64 trackTime);
177
178 void onRendererFinished();
179
180 void onRendererLoopChanged(quint64 id, qint64 offset, int loopIndex);
181
182 void triggerStepIfNeeded();
183
184 static QString objectThreadName(const PlaybackEngineObject &object);
185
186 std::optional<Codec> codecForTrack(QPlatformMediaPlayer::TrackType trackType);
187
188 bool hasMediaStream() const;
189
190 void finilizeTime(qint64 pos);
191
192 void finalizeOutputs();
193
194 bool hasRenderer(quint64 id) const;
195
196 void updateVideoSinkSize(QVideoSink *prevSink = nullptr);
197
198 qint64 boundPosition(qint64 position) const;
199
200private:
201 MediaDataHolder m_media;
202
203 TimeController m_timeController;
204
205 std::unordered_map<QString, std::unique_ptr<QThread>> m_threads;
206 bool m_threadsDirty = false;
207
208 QPointer<QVideoSink> m_videoSink;
209 QPointer<QAudioOutput> m_audioOutput;
210 QPointer<QAudioBufferOutput> m_audioBufferOutput;
211
212 QMediaPlayer::PlaybackState m_state = QMediaPlayer::StoppedState;
213
214 ObjectPtr<Demuxer> m_demuxer;
215 std::array<StreamPtr, QPlatformMediaPlayer::NTrackTypes> m_streams;
216 std::array<RendererPtr, QPlatformMediaPlayer::NTrackTypes> m_renderers;
217
218 std::array<std::optional<Codec>, QPlatformMediaPlayer::NTrackTypes> m_codecs;
219 int m_loops = QMediaPlayer::Once;
220 LoopOffset m_currentLoopOffset;
221};
222
223template<typename T, typename... Args>
224PlaybackEngine::ObjectPtr<T> PlaybackEngine::createPlaybackEngineObject(Args &&...args)
225{
226 auto result = ObjectPtr<T>(new T(std::forward<Args>(args)...), { this });
227 registerObject(object&: *result);
228 return result;
229}
230}
231
232QT_END_NAMESPACE
233
234#endif // QFFMPEGPLAYBACKENGINE_P_H
235

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