Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qffmpegmediaintegration.cpp
Go to the documentation of this file.
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
4#include <QtFFmpegMediaPluginImpl/private/qffmpegmediaintegration_p.h>
5
6#include <QtFFmpegMediaPluginImpl/private/qffmpegaudiodecoder_p.h>
7#include <QtFFmpegMediaPluginImpl/private/qffmpegaudioinput_p.h>
8#include <QtFFmpegMediaPluginImpl/private/qffmpegconverter_p.h>
9#include <QtFFmpegMediaPluginImpl/private/qffmpegimagecapture_p.h>
10#include <QtFFmpegMediaPluginImpl/private/qffmpegmediacapturesession_p.h>
11#include <QtFFmpegMediaPluginImpl/private/qffmpegmediaformatinfo_p.h>
12#include <QtFFmpegMediaPluginImpl/private/qffmpegmediaplayer_p.h>
13#include <QtFFmpegMediaPluginImpl/private/qffmpegmediarecorder_p.h>
14#include <QtFFmpegMediaPluginImpl/private/qffmpegresampler_p.h>
15#include <QtFFmpegMediaPluginImpl/private/qffmpegvideosink_p.h>
16#include <QtFFmpegMediaPluginImpl/private/qgrabwindowsurfacecapture_p.h>
17
18#include <QtMultimedia/private/qplatformmediaplugin_p.h>
19#include <QtMultimedia/qcameradevice.h>
20
21#ifdef Q_OS_MACOS
22#include <QtFFmpegMediaPluginImpl/private/qcgcapturablewindows_p.h>
23#include <QtFFmpegMediaPluginImpl/private/qcgwindowcapture_p.h>
24#include <QtFFmpegMediaPluginImpl/private/qavfscreencapture_p.h>
25#endif
26
27#ifdef Q_OS_DARWIN
28#include <QtFFmpegMediaPluginImpl/private/qavfcamerafactory_p.h>
29#include <QtFFmpegMediaPluginImpl/private/qavfimagecapture_p.h>
30#include <QtMultimedia/private/qdarwinintegrationfactory_p.h>
31#endif
32
33#ifdef Q_OS_WINDOWS
34# include <QtMultimedia/private/qwindowsresampler_p.h>
35# include <QtMultimedia/private/qwindowsvideodevices_p.h>
36# include "qwindowscamera_p.h"
37# include "qffmpegscreencapture_dxgi_p.h"
38# include "qwincapturablewindows_p.h"
39# include "qgdiwindowcapture_p.h"
40#endif
41
42#ifdef Q_OS_ANDROID
43#include <QtFFmpegMediaPluginImpl/private/qandroidcamera_p.h>
44#include <QtFFmpegMediaPluginImpl/private/qandroidimagecapture_p.h>
45#include <QtFFmpegMediaPluginImpl/private/qandroidscreencapture_p.h>
46#include <QtFFmpegMediaPluginImpl/private/qandroidvideodevices_p.h>
47#include <jni.h>
48extern "C" {
49# include <libavutil/log.h>
50# include <libavcodec/jni.h>
51}
52#endif
53
54#if QT_CONFIG(linux_v4l)
55#include "qv4l2camera_p.h"
56#include "qv4l2cameradevices_p.h"
57#endif
58
59#if QT_CONFIG(cpp_winrt)
60#include "qffmpegwindowcapture_uwp_p.h"
61#endif
62
63#if QT_CONFIG(xlib)
64#include "qx11surfacecapture_p.h"
65#include "qx11capturablewindows_p.h"
66#endif
67
68#if QT_CONFIG(pipewire_screencapture)
69# include <QtMultimedia/private/qpipewire_screencapture_p.h>
70#endif
71
72#if QT_CONFIG(eglfs)
73#include "qeglfsscreencapture_p.h"
74#endif
75
76#include <QtCore/qloggingcategory.h>
77
79
80Q_STATIC_LOGGING_CATEGORY(qLcFFmpeg, "qt.multimedia.ffmpeg");
81
82bool thread_local FFmpegLogsEnabledInThread = true;
83static bool UseCustomFFmpegLogger = false;
84
85static void qffmpegLogCallback(void *ptr, int level, const char *fmt, va_list vl)
86{
88 return;
89
91 return av_log_default_callback(ptr, level, fmt, vl);
92
93 // filter logs above the chosen level and AV_LOG_QUIET (negative level)
94 if (level < 0 || level > av_log_get_level())
95 return;
96
97 QString message = QStringLiteral("FFmpeg log: %1").arg(QString::vasprintf(fmt, vl));
98 if (message.endsWith(u"\n"))
99 message.removeLast();
100
101 if (level == AV_LOG_DEBUG || level == AV_LOG_TRACE)
102 qDebug() << message;
103 else if (level == AV_LOG_VERBOSE || level == AV_LOG_INFO)
104 qInfo() << message;
105 else if (level == AV_LOG_WARNING)
106 qWarning() << message;
107 else if (level == AV_LOG_ERROR || level == AV_LOG_FATAL || level == AV_LOG_PANIC)
108 qCritical() << message;
109}
110
111static void setupFFmpegLogger()
112{
113 if (qEnvironmentVariableIsSet("QT_FFMPEG_DEBUG")) {
114 av_log_set_level(AV_LOG_DEBUG);
116 }
117
118 av_log_set_callback(&qffmpegLogCallback);
119}
120
122{
123 if (backend == u"grabwindow")
124 return new QGrabWindowSurfaceCapture(QPlatformSurfaceCapture::ScreenSource{});
125
126#if QT_CONFIG(eglfs)
127 if (backend == u"eglfs")
128 return new QEglfsScreenCapture;
129#endif
130
131#if QT_CONFIG(xlib)
132 if (backend == u"x11")
133 return new QX11SurfaceCapture(QPlatformSurfaceCapture::ScreenSource{});
134#elif defined(Q_OS_WINDOWS)
135 if (backend == u"dxgi")
136 return new QFFmpegScreenCaptureDxgi;
137#elif defined(Q_OS_MACOS)
138 if (backend == u"avf")
139 return new QAVFScreenCapture;
140#endif
141 return nullptr;
142}
143
145{
146 if (backend == u"grabwindow")
147 return new QGrabWindowSurfaceCapture(QPlatformSurfaceCapture::WindowSource{});
148
149#if QT_CONFIG(xlib)
150 if (backend == u"x11")
151 return new QX11SurfaceCapture(QPlatformSurfaceCapture::WindowSource{});
152#elif defined(Q_OS_WINDOWS)
153 if (backend == u"gdi")
154 return new QGdiWindowCapture;
155#if QT_CONFIG(cpp_winrt)
156 if (backend == u"uwp")
157 return new QFFmpegWindowCaptureUwp;
158#endif
159#elif defined(Q_OS_MACOS)
160 if (backend == u"cg")
161 return new QCGWindowCapture;
162#endif
163 return nullptr;
164}
165
166QFFmpegMediaIntegration::QFFmpegMediaIntegration()
167 : QPlatformMediaIntegration(QLatin1String("ffmpeg"))
168{
169 setupFFmpegLogger();
170
171 qCInfo(qLcFFmpeg) << "Using Qt multimedia with FFmpeg version" << av_version_info()
172 << avutil_license();
173
174 qCDebug(qLcFFmpeg) << "Available HW decoding frameworks:";
175 for (auto type : QFFmpeg::HWAccel::decodingDeviceTypes())
176 qCDebug(qLcFFmpeg) << " " << av_hwdevice_get_type_name(type);
177
178 qCDebug(qLcFFmpeg) << "Available HW encoding frameworks:";
179 for (auto type : QFFmpeg::HWAccel::encodingDeviceTypes())
180 qCDebug(qLcFFmpeg) << " " << av_hwdevice_get_type_name(type);
181}
182
183q23::expected<QPlatformAudioDecoder *, QString>
184QFFmpegMediaIntegration::createAudioDecoder(QAudioDecoder *decoder)
185{
186 return new QFFmpegAudioDecoder(decoder);
187}
188
189q23::expected<std::unique_ptr<QPlatformAudioResampler>, QString>
190QFFmpegMediaIntegration::createAudioResampler(const QAudioFormat &inputFormat,
191 const QAudioFormat &outputFormat)
192{
193 auto ffmpegResampler = QFFmpegResampler::createFromInputFormat(inputFormat, outputFormat);
194 if (ffmpegResampler)
195 return ffmpegResampler;
196
197#ifdef Q_OS_WINDOWS
198 auto windowsResampler = std::make_unique<QWindowsResampler>();
199 if (windowsResampler->setup(inputFormat, outputFormat))
200 return std::move(windowsResampler);
201
202#endif
203
204 return q23::unexpected{ notAvailable };
205}
206
207q23::expected<QPlatformMediaCaptureSession *, QString>
208QFFmpegMediaIntegration::createCaptureSession()
209{
210 return new QFFmpegMediaCaptureSession();
211}
212
213q23::expected<QPlatformMediaPlayer *, QString>
214QFFmpegMediaIntegration::createPlayer(QMediaPlayer *player)
215{
216 return new QFFmpegMediaPlayer(player);
217}
218
219q23::expected<QPlatformCamera *, QString> QFFmpegMediaIntegration::createCamera(QCamera *camera)
220{
221 Q_ASSERT(camera);
222#ifdef Q_OS_DARWIN
223 return QFFmpeg::makeQAvfCamera(*camera).release();
224#elif defined(Q_OS_ANDROID)
225 return new QFFmpeg::QAndroidCamera(camera);
226#elif QT_CONFIG(linux_v4l)
227 return new QV4L2Camera(camera);
228#elif defined(Q_OS_WINDOWS)
229 return new QFFmpeg::QWindowsCamera(camera);
230#else
231 Q_UNUSED(camera);
232 return q23::unexpected{ notAvailable };
233#endif
234}
235
236QPlatformSurfaceCapture *QFFmpegMediaIntegration::createScreenCapture(QScreenCapture *)
237{
238 static const QString screenCaptureBackend =
239 QString::fromLocal8Bit(qgetenv("QT_SCREEN_CAPTURE_BACKEND")).toLower();
240
241 if (!screenCaptureBackend.isEmpty()) {
242 if (auto screenCapture = createScreenCaptureByBackend(screenCaptureBackend))
243 return screenCapture;
244
245 qWarning() << "Not supported QT_SCREEN_CAPTURE_BACKEND:" << screenCaptureBackend;
246 }
247
248#if QT_CONFIG(xlib)
249 if (QX11SurfaceCapture::isSupported())
250 return new QX11SurfaceCapture(QPlatformSurfaceCapture::ScreenSource{});
251#endif
252
253#if QT_CONFIG(pipewire_screencapture)
254 if (QtPipeWire::QPipeWireCapture::isSupported())
255 return new QtPipeWire::QPipeWireCapture(QPlatformSurfaceCapture::ScreenSource{});
256#endif
257
258#if QT_CONFIG(eglfs)
259 if (QEglfsScreenCapture::isSupported())
260 return new QEglfsScreenCapture;
261#endif
262
263#if defined(Q_OS_WINDOWS)
264 return new QFFmpegScreenCaptureDxgi;
265#elif defined(Q_OS_MACOS) // TODO: probably use it for iOS as well
266 return new QAVFScreenCapture;
267#elif defined(Q_OS_ANDROID)
268 return new QAndroidScreenCapture;
269#else
270 return new QGrabWindowSurfaceCapture(QPlatformSurfaceCapture::ScreenSource{});
271#endif
272}
273
274QPlatformSurfaceCapture *QFFmpegMediaIntegration::createWindowCapture(QWindowCapture *)
275{
276 static const QString windowCaptureBackend =
277 QString::fromLocal8Bit(qgetenv("QT_WINDOW_CAPTURE_BACKEND")).toLower();
278
279 if (!windowCaptureBackend.isEmpty()) {
280 if (auto windowCapture = createWindowCaptureByBackend(windowCaptureBackend))
281 return windowCapture;
282
283 qWarning() << "Not supported QT_WINDOW_CAPTURE_BACKEND:" << windowCaptureBackend;
284 }
285
286#if QT_CONFIG(xlib)
287 if (QX11SurfaceCapture::isSupported())
288 return new QX11SurfaceCapture(QPlatformSurfaceCapture::WindowSource{});
289#endif
290
291#if defined(Q_OS_WINDOWS)
292# if QT_CONFIG(cpp_winrt)
293 if (QFFmpegWindowCaptureUwp::isSupported())
294 return new QFFmpegWindowCaptureUwp;
295# endif
296
297 return new QGdiWindowCapture;
298#elif defined(Q_OS_MACOS) // TODO: probably use it for iOS as well
299 return new QCGWindowCapture;
300#else
301 return new QGrabWindowSurfaceCapture(QPlatformSurfaceCapture::WindowSource{});
302#endif
303}
304
305q23::expected<QPlatformMediaRecorder *, QString>
306QFFmpegMediaIntegration::createRecorder(QMediaRecorder *recorder)
307{
308 return new QFFmpegMediaRecorder(recorder);
309}
310
311q23::expected<QPlatformImageCapture *, QString>
312QFFmpegMediaIntegration::createImageCapture(QImageCapture *imageCapture)
313{
314#if defined(Q_OS_ANDROID)
315 return new QFFmpeg::QAndroidImageCapture(imageCapture);
316#elif defined(Q_OS_DARWIN)
317 return new QFFmpeg::QAVFImageCapture(imageCapture);
318#else
319 return new QFFmpegImageCapture(imageCapture);
320#endif
321}
322
323q23::expected<QPlatformVideoSink *, QString>
324QFFmpegMediaIntegration::createVideoSink(QVideoSink *sink)
325{
326 return new QFFmpegVideoSink(sink);
327}
328
329q23::expected<QPlatformAudioInput *, QString>
330QFFmpegMediaIntegration::createAudioInput(QAudioInput *input)
331{
332 return new QFFmpegAudioInput(input);
333}
334
335QVideoFrame QFFmpegMediaIntegration::convertVideoFrame(QVideoFrame &srcFrame,
336 const QVideoFrameFormat &destFormat)
337{
338 return convertFrame(srcFrame, destFormat);
339}
340
341QPlatformMediaFormatInfo *QFFmpegMediaIntegration::createFormatInfo()
342{
343 return new QFFmpegMediaFormatInfo;
344}
345
346QPlatformVideoDevices *QFFmpegMediaIntegration::createVideoDevices()
347{
348#if defined(Q_OS_ANDROID)
349 return new QAndroidVideoDevices(this);
350#elif QT_CONFIG(linux_v4l)
351 return new QV4L2CameraDevices(this);
352#elif defined Q_OS_DARWIN
353 return makeQAvfVideoDevices(
354 *this,
355 &QFFmpeg::isCVFormatSupported).release();
356#elif defined(Q_OS_WINDOWS)
357 return new QWindowsVideoDevices(this);
358#else
359 return nullptr;
360#endif
361}
362
363QPlatformCapturableWindows *QFFmpegMediaIntegration::createCapturableWindows()
364{
365#if QT_CONFIG(xlib)
366 if (QX11SurfaceCapture::isSupported())
367 return new QX11CapturableWindows;
368#elif defined Q_OS_MACOS
369 return new QCGCapturableWindows;
370#elif defined(Q_OS_WINDOWS)
371 return new QWinCapturableWindows;
372#endif
373 return nullptr;
374}
375
376#ifdef Q_OS_ANDROID
377
378Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
379{
380 static bool initialized = false;
381 if (initialized)
382 return JNI_VERSION_1_6;
383 initialized = true;
384
385 QT_USE_NAMESPACE
386 void *environment;
387 if (vm->GetEnv(&environment, JNI_VERSION_1_6))
388 return JNI_ERR;
389
390 // setting our javavm into ffmpeg.
391 if (av_jni_set_java_vm(vm, nullptr))
392 return JNI_ERR;
393
394 if (!QFFmpeg::QAndroidCamera::registerNativeMethods()
395 ||!QAndroidScreenCapture::registerNativeMethods()) {
396 return JNI_ERR;
397 }
398
399 return JNI_VERSION_1_6;
400}
401#endif
402
403QT_END_NAMESPACE
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
static QPlatformSurfaceCapture * createScreenCaptureByBackend(QString backend)
static QPlatformSurfaceCapture * createWindowCaptureByBackend(QString backend)
bool thread_local FFmpegLogsEnabledInThread
static bool UseCustomFFmpegLogger
static void qffmpegLogCallback(void *ptr, int level, const char *fmt, va_list vl)
static void setupFFmpegLogger()