Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qgstutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 <QtMultimedia/private/qtmultimediaglobal_p.h>
5#include "qgstutils_p.h"
6
7#include <QtCore/qdatetime.h>
8#include <QtCore/qdir.h>
9#include <QtCore/qbytearray.h>
10#include <QtCore/qvariant.h>
11#include <QtCore/qregularexpression.h>
12#include <QtCore/qsize.h>
13#include <QtCore/qset.h>
14#include <QtCore/qstringlist.h>
15#include <QtGui/qimage.h>
16#include <qaudioformat.h>
17#include <QtCore/qelapsedtimer.h>
18#include <QtMultimedia/qvideoframeformat.h>
19#include <private/qmultimediautils_p.h>
20
21#include <gst/audio/audio.h>
22#include <gst/video/video.h>
23
24template<typename T, int N> constexpr int lengthOf(const T (&)[N]) { return N; }
25
27
28
29namespace {
30
32 nullptr,
33#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
34 "U8",
35 "S16LE",
36 "S32LE",
37 "F32LE"
38#else
39 "U8",
40 "S16BE",
41 "S32BE",
42 "F32BE"
43#endif
44};
45
47{
48 if (fmt) {
49 for (int i = 1; i < QAudioFormat::NSampleFormats; ++i) {
50 if (strcmp(fmt, audioSampleFormatNames[i]))
51 continue;
53 }
54 }
56}
57
58}
59
60/*
61 Returns audio format for a sample \a sample.
62 If the buffer doesn't have a valid audio format, an empty QAudioFormat is returned.
63*/
65{
66 auto caps = QGstCaps(gst_sample_get_caps(sample), QGstCaps::NeedsRef);
67 if (caps.isNull())
68 return {};
69 return audioFormatForCaps(caps);
70}
71
73{
75 QGstStructure s = caps.at(0);
76 if (s.name() != "audio/x-raw")
77 return format;
78
79 auto rate = s["rate"].toInt();
80 auto channels = s["channels"].toInt();
81 QAudioFormat::SampleFormat fmt = gstSampleFormatToSampleFormat(s["format"].toString());
82 if (!rate || !channels || fmt == QAudioFormat::Unknown)
83 return format;
84
85 format.setSampleRate(*rate);
86 format.setChannelCount(*channels);
87 format.setSampleFormat(fmt);
88
89 return format;
90}
91
92/*
93 Builds GstCaps for an audio format \a format.
94 Returns 0 if the audio format is not valid.
95
96 \note Caller must unreference GstCaps.
97*/
98
100{
101 if (!format.isValid())
102 return {};
103
104 auto sampleFormat = format.sampleFormat();
105 auto caps = gst_caps_new_simple(
106 "audio/x-raw",
107 "format" , G_TYPE_STRING, audioSampleFormatNames[sampleFormat],
108 "rate" , G_TYPE_INT , format.sampleRate(),
109 "channels", G_TYPE_INT , format.channelCount(),
110 "layout" , G_TYPE_STRING, "interleaved",
111 nullptr);
112
113 return QGstCaps(caps, QGstCaps::HasRef);
114}
115
117{
118 if (!GST_VALUE_HOLDS_LIST(value))
119 return {};
120
122 guint nFormats = gst_value_list_get_size(value);
123 for (guint f = 0; f < nFormats; ++f) {
124 QGValue v = gst_value_list_get_value(value, f);
125 auto *name = v.toString();
126 QAudioFormat::SampleFormat fmt = gstSampleFormatToSampleFormat(name);
128 continue;;
129 formats.append(fmt);
130 }
131 return formats;
132}
133
134namespace {
135
136struct VideoFormat
137{
139 GstVideoFormat gstFormat;
140};
141
142static const VideoFormat qt_videoFormatLookup[] =
143{
144 { QVideoFrameFormat::Format_YUV420P, GST_VIDEO_FORMAT_I420 },
145 { QVideoFrameFormat::Format_YUV422P, GST_VIDEO_FORMAT_Y42B },
146 { QVideoFrameFormat::Format_YV12 , GST_VIDEO_FORMAT_YV12 },
147 { QVideoFrameFormat::Format_UYVY , GST_VIDEO_FORMAT_UYVY },
148 { QVideoFrameFormat::Format_YUYV , GST_VIDEO_FORMAT_YUY2 },
149 { QVideoFrameFormat::Format_NV12 , GST_VIDEO_FORMAT_NV12 },
150 { QVideoFrameFormat::Format_NV21 , GST_VIDEO_FORMAT_NV21 },
151 { QVideoFrameFormat::Format_AYUV , GST_VIDEO_FORMAT_AYUV },
152 { QVideoFrameFormat::Format_Y8 , GST_VIDEO_FORMAT_GRAY8 },
153 { QVideoFrameFormat::Format_XRGB8888 , GST_VIDEO_FORMAT_xRGB },
154 { QVideoFrameFormat::Format_XBGR8888 , GST_VIDEO_FORMAT_xBGR },
155 { QVideoFrameFormat::Format_RGBX8888 , GST_VIDEO_FORMAT_RGBx },
156 { QVideoFrameFormat::Format_BGRX8888 , GST_VIDEO_FORMAT_BGRx },
157 { QVideoFrameFormat::Format_ARGB8888, GST_VIDEO_FORMAT_ARGB },
158 { QVideoFrameFormat::Format_ABGR8888, GST_VIDEO_FORMAT_ABGR },
159 { QVideoFrameFormat::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA },
160 { QVideoFrameFormat::Format_BGRA8888, GST_VIDEO_FORMAT_BGRA },
161#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
162 { QVideoFrameFormat::Format_Y16 , GST_VIDEO_FORMAT_GRAY16_LE },
163 { QVideoFrameFormat::Format_P010 , GST_VIDEO_FORMAT_P010_10LE },
164#else
165 { QVideoFrameFormat::Format_Y16 , GST_VIDEO_FORMAT_GRAY16_BE },
166 { QVideoFrameFormat::Format_P010 , GST_VIDEO_FORMAT_P010_10BE },
167#endif
168};
169
170static int indexOfVideoFormat(QVideoFrameFormat::PixelFormat format)
171{
172 for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i)
173 if (qt_videoFormatLookup[i].pixelFormat == format)
174 return i;
175
176 return -1;
177}
178
179static int indexOfVideoFormat(GstVideoFormat format)
180{
181 for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i)
182 if (qt_videoFormatLookup[i].gstFormat == format)
183 return i;
184
185 return -1;
186}
187
188}
189
191{
192 GstVideoInfo vidInfo;
193 GstVideoInfo *infoPtr = info ? info : &vidInfo;
194
195 if (gst_video_info_from_caps(infoPtr, caps)) {
196 int index = indexOfVideoFormat(infoPtr->finfo->format);
197
198 if (index != -1) {
200 QSize(infoPtr->width, infoPtr->height),
201 qt_videoFormatLookup[index].pixelFormat);
202
203 if (infoPtr->fps_d > 0)
204 format.setFrameRate(qreal(infoPtr->fps_n) / infoPtr->fps_d);
205
207 switch (infoPtr->colorimetry.range) {
208 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
209 break;
210 case GST_VIDEO_COLOR_RANGE_0_255:
212 break;
213 case GST_VIDEO_COLOR_RANGE_16_235:
215 break;
216 }
217 format.setColorRange(range);
218
220 switch (infoPtr->colorimetry.matrix) {
221 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
222 case GST_VIDEO_COLOR_MATRIX_RGB:
223 case GST_VIDEO_COLOR_MATRIX_FCC:
224 break;
225 case GST_VIDEO_COLOR_MATRIX_BT709:
227 break;
228 case GST_VIDEO_COLOR_MATRIX_BT601:
230 break;
231 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
233 break;
234 case GST_VIDEO_COLOR_MATRIX_BT2020:
236 break;
237 }
238 format.setColorSpace(colorSpace);
239
241 switch (infoPtr->colorimetry.transfer) {
242 case GST_VIDEO_TRANSFER_UNKNOWN:
243 break;
244 case GST_VIDEO_TRANSFER_GAMMA10:
246 break;
247 case GST_VIDEO_TRANSFER_GAMMA22:
248 case GST_VIDEO_TRANSFER_SMPTE240M:
249 case GST_VIDEO_TRANSFER_SRGB:
250 case GST_VIDEO_TRANSFER_ADOBERGB:
252 break;
253 case GST_VIDEO_TRANSFER_GAMMA18:
254 case GST_VIDEO_TRANSFER_GAMMA20:
255 // not quite, but best fit
256 case GST_VIDEO_TRANSFER_BT709:
257 case GST_VIDEO_TRANSFER_BT2020_12:
259 break;
260 case GST_VIDEO_TRANSFER_GAMMA28:
262 break;
263 case GST_VIDEO_TRANSFER_LOG100:
264 case GST_VIDEO_TRANSFER_LOG316:
265 break;
266#if GST_CHECK_VERSION(1, 18, 0)
267 case GST_VIDEO_TRANSFER_SMPTE2084:
269 break;
270 case GST_VIDEO_TRANSFER_ARIB_STD_B67:
272 break;
273 case GST_VIDEO_TRANSFER_BT2020_10:
275 break;
276 case GST_VIDEO_TRANSFER_BT601:
278 break;
279#endif
280 }
281 format.setColorTransfer(transfer);
282
283 return format;
284 }
285 }
286 return QVideoFrameFormat();
287}
288
290{
291 if (!gst_caps_is_writable(caps))
292 caps = gst_caps_make_writable(caps);
293
294 GValue list = {};
295 g_value_init(&list, GST_TYPE_LIST);
296
298 int index = indexOfVideoFormat(format);
299 if (index == -1)
300 continue;
301 GValue item = {};
302
303 g_value_init(&item, G_TYPE_STRING);
304 g_value_set_string(&item, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat));
305 gst_value_list_append_value(&list, &item);
306 g_value_unset(&item);
307 }
308
309 auto *structure = gst_structure_new("video/x-raw",
310 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
311 "width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
312 "height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
313 nullptr);
314 gst_structure_set_value(structure, "format", &list);
315 gst_caps_append_structure(caps, structure);
316 g_value_unset(&list);
317
318 if (modifier)
319 gst_caps_set_features(caps, size() - 1, gst_caps_features_from_string(modifier));
320}
321
323{
324 QSize size = format.resolution();
325 GstStructure *structure = nullptr;
326 if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
327 structure = gst_structure_new("image/jpeg",
328 "width" , G_TYPE_INT, size.width(),
329 "height" , G_TYPE_INT, size.height(),
330 nullptr);
331 } else {
332 int index = indexOfVideoFormat(format.pixelFormat());
333 if (index < 0)
334 return {};
335 auto gstFormat = qt_videoFormatLookup[index].gstFormat;
336 structure = gst_structure_new("video/x-raw",
337 "format" , G_TYPE_STRING, gst_video_format_to_string(gstFormat),
338 "width" , G_TYPE_INT, size.width(),
339 "height" , G_TYPE_INT, size.height(),
340 nullptr);
341 }
342 auto caps = QGstCaps::create();
343 gst_caps_append_structure(caps.caps, structure);
344 return caps;
345}
346
348{
349 // GStreamer uses nanoseconds, Qt uses microseconds
350 qint64 startTime = GST_BUFFER_TIMESTAMP(buffer);
351 if (startTime >= 0) {
352 frame->setStartTime(startTime/G_GINT64_CONSTANT (1000));
353
354 qint64 duration = GST_BUFFER_DURATION(buffer);
355 if (duration >= 0)
356 frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000));
357 }
358}
359
361{
362 QSize size;
363
364 int w, h;
365 if (structure &&
366 gst_structure_get_int(structure, "width", &w) &&
367 gst_structure_get_int(structure, "height", &h)) {
368 size.rwidth() = w;
369 size.rheight() = h;
370 }
371
372 return size;
373}
374
376{
378
379 if (!structure)
380 return pixelFormat;
381
382 if (gst_structure_has_name(structure, "video/x-raw")) {
383 const gchar *s = gst_structure_get_string(structure, "format");
384 if (s) {
385 GstVideoFormat format = gst_video_format_from_string(s);
386 int index = indexOfVideoFormat(format);
387
388 if (index != -1)
389 pixelFormat = qt_videoFormatLookup[index].pixelFormat;
390 }
391 } else if (gst_structure_has_name(structure, "image/jpeg")) {
393 }
394
395 return pixelFormat;
396}
397
399{
400 float minRate = 0.;
401 float maxRate = 0.;
402
403 if (!structure)
404 return {0.f, 0.f};
405
406 auto extractFraction = [] (const GValue *v) -> float {
407 return (float)gst_value_get_fraction_numerator(v)/(float)gst_value_get_fraction_denominator(v);
408 };
409 auto extractFrameRate = [&] (const GValue *v) {
410 auto insert = [&] (float min, float max) {
411 if (max > maxRate)
412 maxRate = max;
413 if (min < minRate)
414 minRate = min;
415 };
416
417 if (GST_VALUE_HOLDS_FRACTION(v)) {
418 float rate = extractFraction(v);
419 insert(rate, rate);
420 } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) {
421 auto *min = gst_value_get_fraction_range_max(v);
422 auto *max = gst_value_get_fraction_range_max(v);
423 insert(extractFraction(min), extractFraction(max));
424 }
425 };
426
427 const GValue *gstFrameRates = gst_structure_get_value(structure, "framerate");
428 if (gstFrameRates) {
429 if (GST_VALUE_HOLDS_LIST(gstFrameRates)) {
430 guint nFrameRates = gst_value_list_get_size(gstFrameRates);
431 for (guint f = 0; f < nFrameRates; ++f) {
432 extractFrameRate(gst_value_list_get_value(gstFrameRates, f));
433 }
434 } else {
435 extractFrameRate(gstFrameRates);
436 }
437 } else {
438 const GValue *min = gst_structure_get_value(structure, "min-framerate");
439 const GValue *max = gst_structure_get_value(structure, "max-framerate");
440 if (min && max) {
441 minRate = extractFraction(min);
442 maxRate = extractFraction(max);
443 }
444 }
445
446 return {minRate, maxRate};
447}
448
450{
451 return gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK
452 | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO,
453 GST_RANK_MARGINAL);
454}
455
The QAudioFormat class stores audio stream parameter information.
SampleFormat
Qt will always expect and use samples in the endianness of the host platform.
The QCameraFormat class describes a video format supported by a camera device. \inmodule QtMultimedia...
Q_MULTIMEDIA_EXPORT QList< QAudioFormat::SampleFormat > getSampleFormats() const
@ NeedsRef
Definition qgst_p.h:163
@ HasRef
Definition qgst_p.h:163
void addPixelFormats(const QList< QVideoFrameFormat::PixelFormat > &formats, const char *modifier=nullptr)
int size() const
Definition qgst_p.h:200
static QGstCaps create()
Definition qgst_p.h:215
static QGstCaps fromCameraFormat(const QCameraFormat &format)
QGstStructure at(int index) const
Definition qgst_p.h:201
QVideoFrameFormat formatForCaps(GstVideoInfo *info) const
Q_MULTIMEDIA_EXPORT QSize resolution() const
const GstStructure * structure
Definition qgst_p.h:135
Q_MULTIMEDIA_EXPORT QGRange< float > frameRateRange() const
Q_MULTIMEDIA_EXPORT QVideoFrameFormat::PixelFormat pixelFormat() const
Definition qlist.h:74
\inmodule QtCore
Definition qsize.h:25
The QVideoFrameFormat class specifies the stream format of a video presentation surface.
ColorSpace
Enumerates the color space of video frames.
ColorTransfer
\value ColorTransfer_Unknown The color transfer function is unknown.
PixelFormat
Enumerates video data types.
ColorRange
Describes the color range used by the video data.
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:26
cache insert(employee->id(), employee)
EGLint EGLint * formats
void setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer)
Q_MULTIMEDIA_EXPORT QGstCaps capsForAudioFormat(const QAudioFormat &format)
Definition qgstutils.cpp:99
QAudioFormat audioFormatForCaps(const QGstCaps &caps)
Definition qgstutils.cpp:72
Q_MULTIMEDIA_EXPORT QAudioFormat audioFormatForSample(GstSample *sample)
Definition qgstutils.cpp:64
Combined button and popup list for selecting options.
static const char * audioSampleFormatNames[QAudioFormat::NSampleFormats]
Definition qgstutils.cpp:31
static QAudioFormat::SampleFormat gstSampleFormatToSampleFormat(const char *fmt)
Definition qgstutils.cpp:46
qint64 startTime
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GList * qt_gst_video_sinks()
constexpr int lengthOf(const T(&)[N])
Definition qgstutils.cpp:24
GLsizei const GLfloat * v
[13]
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLfloat GLfloat f
GLsizei range
GLenum GLuint buffer
GLuint name
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum * rate
GLdouble s
[6]
Definition qopenglext.h:235
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
QVideoFrameFormat::PixelFormat fmt
QList< int > list
[14]
QFileInfo info(fileName)
[8]
QGraphicsItem * item
QFrame frame
[0]
char * toString(const MyType &t)
[31]