Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
avfmediaencoder.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
5#include "avfmediaencoder_p.h"
8#include "avfcamera_p.h"
10#include "avfcameradebug_p.h"
11#include "avfcamerautility_p.h"
12#include "qaudiodevice.h"
13
14#include "qmediadevices.h"
15#include "private/qmediastoragelocation_p.h"
16#include "private/qmediarecorder_p.h"
18#include "private/qplatformaudiooutput_p.h"
19#include <private/qplatformaudioinput_p.h>
20
21#include <QtCore/qmath.h>
22#include <QtCore/qdebug.h>
23#include <QtCore/qmimetype.h>
24
25#include <private/qcoreaudioutils_p.h>
26
28
29namespace {
30
31bool qt_is_writable_file_URL(NSURL *fileURL)
32{
33 Q_ASSERT(fileURL);
34
35 if (![fileURL isFileURL])
36 return false;
37
38 if (NSString *path = [[fileURL path] stringByExpandingTildeInPath]) {
39 return [[NSFileManager defaultManager]
40 isWritableFileAtPath:[path stringByDeletingLastPathComponent]];
41 }
42
43 return false;
44}
45
46bool qt_file_exists(NSURL *fileURL)
47{
48 Q_ASSERT(fileURL);
49
50 if (NSString *path = [[fileURL path] stringByExpandingTildeInPath])
51 return [[NSFileManager defaultManager] fileExistsAtPath:path];
52
53 return false;
54}
55
56}
57
59 : QObject(parent)
61 , m_state(QMediaRecorder::StoppedState)
62 , m_duration(0)
63 , m_audioSettings(nil)
64 , m_videoSettings(nil)
65 //, m_restoreFPS(-1, -1)
66{
67 m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithDelegate:this]);
68 if (!m_writer) {
69 qCDebug(qLcCamera) << Q_FUNC_INFO << "failed to create an asset writer";
70 return;
71 }
72}
73
75{
76 [m_writer abort];
77
78 if (m_audioSettings)
79 [m_audioSettings release];
80 if (m_videoSettings)
81 [m_videoSettings release];
82}
83
85{
86 return location.scheme() == QLatin1String("file") || location.scheme().isEmpty();
87}
88
90{
91 return m_state;
92}
93
95{
96 return m_duration;
97}
98
100{
101 m_duration = duration;
102 durationChanged(m_duration);
103}
104
105static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettings, const QAudioFormat &format)
106{
107 NSMutableDictionary *settings = [NSMutableDictionary dictionary];
108
109 // Codec
111 [settings setObject:[NSNumber numberWithInt:codecId] forKey:AVFormatIDKey];
112
113 // Setting AVEncoderQualityKey is not allowed when format ID is alac or lpcm
114 if (codecId != kAudioFormatAppleLossless && codecId != kAudioFormatLinearPCM
116 // AudioQuality
117 int quality;
118 switch (encoderSettings.quality()) {
120 quality = AVAudioQualityMin;
121 break;
123 quality = AVAudioQualityLow;
124 break;
126 quality = AVAudioQualityHigh;
127 break;
129 quality = AVAudioQualityMax;
130 break;
132 default:
133 quality = AVAudioQualityMedium;
134 break;
135 }
136 [settings setObject:[NSNumber numberWithInt:quality] forKey:AVEncoderAudioQualityKey];
137 } else {
138 // BitRate
139 bool isBitRateSupported = false;
140 int bitRate = encoderSettings.audioBitRate();
141 if (bitRate > 0) {
142 QList<AudioValueRange> bitRates = qt_supported_bit_rates_for_format(codecId);
143 for (int i = 0; i < bitRates.count(); i++) {
144 if (bitRate >= bitRates[i].mMinimum &&
145 bitRate <= bitRates[i].mMaximum) {
146 isBitRateSupported = true;
147 break;
148 }
149 }
150 if (isBitRateSupported)
151 [settings setObject:[NSNumber numberWithInt:encoderSettings.audioBitRate()]
152 forKey:AVEncoderBitRateKey];
153 }
154 }
155
156 // SampleRate
157 int sampleRate = encoderSettings.audioSampleRate();
158 bool isSampleRateSupported = false;
159 if (sampleRate >= 8000 && sampleRate <= 192000) {
160 QList<AudioValueRange> sampleRates = qt_supported_sample_rates_for_format(codecId);
161 for (int i = 0; i < sampleRates.count(); i++) {
162 if (sampleRate >= sampleRates[i].mMinimum && sampleRate <= sampleRates[i].mMaximum) {
163 isSampleRateSupported = true;
164 break;
165 }
166 }
167 }
168 if (!isSampleRateSupported)
169 sampleRate = 44100;
170 [settings setObject:[NSNumber numberWithInt:sampleRate] forKey:AVSampleRateKey];
171
172 // Channels
173 int channelCount = encoderSettings.audioChannelCount();
174 bool isChannelCountSupported = false;
175 if (channelCount > 0) {
176 std::optional<QList<UInt32>> channelCounts = qt_supported_channel_counts_for_format(codecId);
177 // An std::nullopt result indicates that
178 // any number of channels can be encoded.
179 if (channelCounts == std::nullopt) {
180 isChannelCountSupported = true;
181 } else {
182 for (int i = 0; i < channelCounts.value().count(); i++) {
183 if ((UInt32)channelCount == channelCounts.value()[i]) {
184 isChannelCountSupported = true;
185 break;
186 }
187 }
188 }
189
190 // if channel count is provided and it's bigger than 2
191 // provide a supported channel layout
192 if (isChannelCountSupported && channelCount > 2) {
193 AudioChannelLayout channelLayout;
194 memset(&channelLayout, 0, sizeof(AudioChannelLayout));
195 auto channelLayoutTags = qt_supported_channel_layout_tags_for_format(codecId, channelCount);
196 if (channelLayoutTags.size()) {
197 channelLayout.mChannelLayoutTag = channelLayoutTags.first();
198 [settings setObject:[NSData dataWithBytes: &channelLayout length: sizeof(channelLayout)] forKey:AVChannelLayoutKey];
199 } else {
200 isChannelCountSupported = false;
201 }
202 }
203
204 if (isChannelCountSupported)
205 [settings setObject:[NSNumber numberWithInt:channelCount] forKey:AVNumberOfChannelsKey];
206 }
207
208 if (!isChannelCountSupported) {
209 // fallback to providing channel layout if channel count is not specified or supported
210 UInt32 size = 0;
211 if (format.isValid()) {
213 [settings setObject:[NSData dataWithBytes:layout.get() length:sizeof(AudioChannelLayout)] forKey:AVChannelLayoutKey];
214 } else {
215 // finally default to setting channel count to 1
216 [settings setObject:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
217 }
218 }
219
220 if (codecId == kAudioFormatAppleLossless)
221 [settings setObject:[NSNumber numberWithInt:24] forKey:AVEncoderBitDepthHintKey];
222
223 if (codecId == kAudioFormatLinearPCM) {
224 [settings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
225 [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsBigEndianKey];
226 [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsFloatKey];
227 [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsNonInterleaved];
228 }
229
230 return settings;
231}
232
233NSDictionary *avfVideoSettings(QMediaEncoderSettings &encoderSettings, AVCaptureDevice *device, AVCaptureConnection *connection, QSize nativeSize)
234{
235 if (!device)
236 return nil;
237
238
239 // ### re-add needFpsChange
240// AVFPSRange currentFps = qt_current_framerates(device, connection);
241
242 NSMutableDictionary *videoSettings = [NSMutableDictionary dictionary];
243
244 // -- Codec
245
246 // AVVideoCodecKey is the only mandatory key
247 auto codec = encoderSettings.mediaFormat().videoCodec();
249 [videoSettings setObject:c forKey:AVVideoCodecKey];
250 [c release];
251
252 // -- Resolution
253
254 int w = encoderSettings.videoResolution().width();
255 int h = encoderSettings.videoResolution().height();
256
257 if (AVCaptureDeviceFormat *currentFormat = device.activeFormat) {
258 CMFormatDescriptionRef formatDesc = currentFormat.formatDescription;
259 CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
260 FourCharCode formatCodec = CMVideoFormatDescriptionGetCodecType(formatDesc);
261
262 // We have to change the device's activeFormat in 3 cases:
263 // - the requested recording resolution is higher than the current device resolution
264 // - the requested recording resolution has a different aspect ratio than the current device aspect ratio
265 // - the requested frame rate is not available for the current device format
266 AVCaptureDeviceFormat *newFormat = nil;
267 if ((w <= 0 || h <= 0)
268 && encoderSettings.videoFrameRate() > 0
269 && !qt_format_supports_framerate(currentFormat, encoderSettings.videoFrameRate())) {
270
272 formatCodec,
273 encoderSettings.videoFrameRate());
274
275 } else if (w > 0 && h > 0) {
276 AVCaptureDeviceFormat *f = qt_find_best_resolution_match(device,
277 encoderSettings.videoResolution(),
278 formatCodec);
279
280 if (f) {
281 CMVideoDimensions d = CMVideoFormatDescriptionGetDimensions(f.formatDescription);
282 qreal fAspectRatio = qreal(d.width) / d.height;
283
284 if (w > dim.width || h > dim.height
285 || qAbs((qreal(dim.width) / dim.height) - fAspectRatio) > 0.01) {
286 newFormat = f;
287 }
288 }
289 }
290
291 if (qt_set_active_format(device, newFormat, false /*### !needFpsChange*/)) {
292 formatDesc = newFormat.formatDescription;
293 dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
294 }
295
296 if (w < 0 || h < 0) {
297 w = dim.width;
298 h = dim.height;
299 }
300
301
302 if (w > 0 && h > 0) {
303 // Make sure the recording resolution has the same aspect ratio as the device's
304 // current resolution
305 qreal deviceAspectRatio = qreal(dim.width) / dim.height;
306 qreal recAspectRatio = qreal(w) / h;
307 if (qAbs(deviceAspectRatio - recAspectRatio) > 0.01) {
308 if (recAspectRatio > deviceAspectRatio)
309 w = qRound(h * deviceAspectRatio);
310 else
311 h = qRound(w / deviceAspectRatio);
312 }
313
314 // recording resolution can't be higher than the device's active resolution
315 w = qMin(w, dim.width);
316 h = qMin(h, dim.height);
317 }
318 }
319
320 if (w > 0 && h > 0) {
321 // Width and height must be divisible by 2
322 w += w & 1;
323 h += h & 1;
324
325 bool isPortrait = nativeSize.width() < nativeSize.height();
326 // Make sure the video has the right aspect ratio
327 if (isPortrait && h < w)
328 qSwap(w, h);
329 else if (!isPortrait && w < h)
330 qSwap(w, h);
331
332 encoderSettings.setVideoResolution(QSize(w, h));
333 } else {
334 w = nativeSize.width();
335 h = nativeSize.height();
336 encoderSettings.setVideoResolution(nativeSize);
337 }
338 [videoSettings setObject:[NSNumber numberWithInt:w] forKey:AVVideoWidthKey];
339 [videoSettings setObject:[NSNumber numberWithInt:h] forKey:AVVideoHeightKey];
340
341 // -- FPS
342
343 if (true /*needFpsChange*/) {
344 const qreal fps = encoderSettings.videoFrameRate();
346 }
348
349 // -- Codec Settings
350
351 NSMutableDictionary *codecProperties = [NSMutableDictionary dictionary];
352 int bitrate = -1;
353 float quality = -1.f;
354
355 if (encoderSettings.encodingMode() == QMediaRecorder::ConstantQualityEncoding) {
356 if (encoderSettings.quality() != QMediaRecorder::NormalQuality) {
358 qWarning("ConstantQualityEncoding is not supported for MotionJPEG");
359 } else {
360 switch (encoderSettings.quality()) {
362 quality = 0.f;
363 break;
365 quality = 0.25f;
366 break;
368 quality = 0.75f;
369 break;
371 quality = 1.f;
372 break;
373 default:
374 quality = -1.f; // NormalQuality, let the system decide
375 break;
376 }
377 }
378 }
379 } else if (encoderSettings.encodingMode() == QMediaRecorder::AverageBitRateEncoding){
381 qWarning() << "AverageBitRateEncoding is not supported for codec" << QMediaFormat::videoCodecName(codec);
382 else
383 bitrate = encoderSettings.videoBitRate();
384 } else {
385 qWarning("Encoding mode is not supported");
386 }
387
388 if (bitrate != -1)
389 [codecProperties setObject:[NSNumber numberWithInt:bitrate] forKey:AVVideoAverageBitRateKey];
390 if (quality != -1.f)
391 [codecProperties setObject:[NSNumber numberWithFloat:quality] forKey:AVVideoQualityKey];
392
393 [videoSettings setObject:codecProperties forKey:AVVideoCompressionPropertiesKey];
394
395 return videoSettings;
396}
397
398void AVFMediaEncoder::applySettings(QMediaEncoderSettings &settings)
399{
400 unapplySettings();
401
402 AVFCameraSession *session = m_service->session();
403
404 // audio settings
405 const auto audioInput = m_service->audioInput();
406 const QAudioFormat audioFormat = audioInput ? audioInput->device.preferredFormat() : QAudioFormat();
407 m_audioSettings = avfAudioSettings(settings, audioFormat);
408 if (m_audioSettings)
409 [m_audioSettings retain];
410
411 // video settings
412 AVCaptureDevice *device = session->videoCaptureDevice();
413 if (!device)
414 return;
415 const AVFConfigurationLock lock(device); // prevents activeFormat from being overridden
416 AVCaptureConnection *conn = [session->videoOutput()->videoDataOutput() connectionWithMediaType:AVMediaTypeVideo];
417 auto nativeSize = session->videoOutput()->nativeSize();
418 m_videoSettings = avfVideoSettings(settings, device, conn, nativeSize);
419 if (m_videoSettings)
420 [m_videoSettings retain];
421}
422
423void AVFMediaEncoder::unapplySettings()
424{
425 if (m_audioSettings) {
426 [m_audioSettings release];
427 m_audioSettings = nil;
428 }
429 if (m_videoSettings) {
430 [m_videoSettings release];
431 m_videoSettings = nil;
432 }
433}
434
436{
437 m_metaData = metaData;
438}
439
441{
442 return m_metaData;
443}
444
446{
447 AVFCameraService *captureSession = static_cast<AVFCameraService *>(session);
448 if (m_service == captureSession)
449 return;
450
451 if (m_service)
452 stop();
453
454 m_service = captureSession;
455 if (!m_service)
456 return;
457
458 connect(m_service, &AVFCameraService::cameraChanged, this, &AVFMediaEncoder::onCameraChanged);
459 onCameraChanged();
460}
461
463{
464 if (!m_service || !m_service->session()) {
465 qWarning() << Q_FUNC_INFO << "Encoder is not set to a capture session";
466 return;
467 }
468
469 if (!m_writer) {
470 qCDebug(qLcCamera) << Q_FUNC_INFO << "Invalid recorder";
471 return;
472 }
473
474 if (QMediaRecorder::RecordingState == m_state)
475 return;
476
477 AVFCamera *cameraControl = m_service->avfCameraControl();
478 auto audioInput = m_service->audioInput();
479
480 if (!cameraControl && !audioInput) {
481 qWarning() << Q_FUNC_INFO << "Cannot record without any inputs";
482 updateError(QMediaRecorder::ResourceError, tr("No inputs specified"));
483 return;
484 }
485
486 m_service->session()->setActive(true);
487 const bool audioOnly = settings.videoCodec() == QMediaFormat::VideoCodec::Unspecified;
488 AVCaptureSession *session = m_service->session()->captureSession();
489 float rotation = 0;
490
491 if (!audioOnly) {
492 if (!cameraControl || !cameraControl->isActive()) {
493 qCDebug(qLcCamera) << Q_FUNC_INFO << "can not start record while camera is not active";
496 return;
497 }
498 }
499
500 const QString path(outputLocation().scheme() == QLatin1String("file") ?
504 settings.mimeType().preferredSuffix())));
505
506 NSURL *nsFileURL = fileURL.toNSURL();
507 if (!nsFileURL) {
508 qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL;
509 updateError(QMediaRecorder::ResourceError, tr("Invalid output file URL"));
510 return;
511 }
512 if (!qt_is_writable_file_URL(nsFileURL)) {
513 qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
514 << "(the location is not writable)";
515 updateError(QMediaRecorder::ResourceError, tr("Non-writeable file location"));
516 return;
517 }
518 if (qt_file_exists(nsFileURL)) {
519 // We test for/handle this error here since AWAssetWriter will raise an
520 // Objective-C exception, which is not good at all.
521 qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
522 << "(file already exists)";
523 updateError(QMediaRecorder::ResourceError, tr("File already exists"));
524 return;
525 }
526
527 applySettings(settings);
528
530
531 // We stop session now so that no more frames for renderer's queue
532 // generated, will restart in assetWriterStarted.
533 [session stopRunning];
534
535 if ([m_writer setupWithFileURL:nsFileURL
536 cameraService:m_service
537 audioSettings:m_audioSettings
538 videoSettings:m_videoSettings
539 fileFormat:settings.fileFormat()
540 transform:CGAffineTransformMakeRotation(qDegreesToRadians(rotation))]) {
541
543
545 Q_EMIT stateChanged(m_state);
546
547 // Apple recommends to call startRunning and do all
548 // setup on a special queue, and that's what we had
549 // initially (dispatch_async to writerQueue). Unfortunately,
550 // writer's queue is not the only queue/thread that can
551 // access/modify the session, and as a result we have
552 // all possible data/race-conditions with Obj-C exceptions
553 // at best and something worse in general.
554 // Now we try to only modify session on the same thread.
555 [m_writer start];
556 } else {
557 [session startRunning];
559 }
560}
561
563{
564 if (!m_service || !m_service->session() || state() != QMediaRecorder::RecordingState)
565 return;
566
567 toggleRecord(false);
569 stateChanged(m_state);
570}
571
573{
574 if (!m_service || !m_service->session() || state() != QMediaRecorder::PausedState)
575 return;
576
577 toggleRecord(true);
579 stateChanged(m_state);
580}
581
583{
584 if (m_state != QMediaRecorder::StoppedState) {
585 // Do not check the camera status, we can stop if we started.
586 stopWriter();
587 }
589}
590
591
593{
594 if (!m_service || !m_service->session())
595 return;
596
597 if (!enable)
598 [m_writer pause];
599 else
600 [m_writer resume];
601}
602
603void AVFMediaEncoder::assetWriterStarted()
604{
605}
606
607void AVFMediaEncoder::assetWriterFinished()
608{
609
610 const QMediaRecorder::RecorderState lastState = m_state;
611
612 unapplySettings();
613
614 if (m_service) {
615 AVFCameraSession *session = m_service->session();
616
617 if (session->videoOutput()) {
618 session->videoOutput()->resetCaptureDelegate();
619 }
620 if (session->audioPreviewDelegate()) {
621 [session->audioPreviewDelegate() resetAudioPreviewDelegate];
622 }
623 if (session->videoOutput() || session->audioPreviewDelegate())
624 [session->captureSession() startRunning];
625 }
626
628 if (m_state != lastState)
629 Q_EMIT stateChanged(m_state);
630}
631
632void AVFMediaEncoder::assetWriterError(QString err)
633{
635 if (m_state != QMediaRecorder::StoppedState)
636 stopWriter();
637}
638
639void AVFMediaEncoder::onCameraChanged()
640{
641 if (m_service && m_service->avfCameraControl()) {
642 AVFCamera *cameraControl = m_service->avfCameraControl();
643 connect(cameraControl, SIGNAL(activeChanged(bool)),
644 SLOT(cameraActiveChanged(bool)));
645 }
646}
647
648void AVFMediaEncoder::cameraActiveChanged(bool active)
649{
650 Q_ASSERT(m_service);
651 AVFCamera *cameraControl = m_service->avfCameraControl();
652 Q_ASSERT(cameraControl);
653
654 if (!active) {
655 return stopWriter();
656 }
657}
658
659void AVFMediaEncoder::stopWriter()
660{
661 [m_writer stop];
662}
663
664#include "moc_avfmediaencoder_p.cpp"
AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection)
std::optional< QList< UInt32 > > qt_supported_channel_counts_for_format(int codecId)
QList< AudioValueRange > qt_supported_sample_rates_for_format(int codecId)
QList< UInt32 > qt_supported_channel_layout_tags_for_format(int codecId, int noChannels)
AVCaptureDeviceFormat * qt_find_best_framerate_match(AVCaptureDevice *captureDevice, FourCharCode filter, Float64 fps)
QList< AudioValueRange > qt_supported_bit_rates_for_format(int codecId)
bool qt_set_active_format(AVCaptureDevice *captureDevice, AVCaptureDeviceFormat *format, bool preserveFps)
void qt_set_framerate_limits(AVCaptureConnection *videoConnection, qreal minFPS, qreal maxFPS)
AVCaptureDeviceFormat * qt_find_best_resolution_match(AVCaptureDevice *captureDevice, const QSize &request, FourCharCode filter, bool stillImage)
bool qt_format_supports_framerate(AVCaptureDeviceFormat *format, qreal fps)
NSDictionary * avfVideoSettings(QMediaEncoderSettings &encoderSettings, AVCaptureDevice *device, AVCaptureConnection *connection, QSize nativeSize)
static NSDictionary * avfAudioSettings(const QMediaEncoderSettings &encoderSettings, const QAudioFormat &format)
IOBluetoothDevice * device
AVCaptureVideoDataOutput * videoDataOutput() const
void resetCaptureDelegate() const
AVFCamera * avfCameraControl() const
AVFCameraSession * session() const
QPlatformAudioInput * audioInput()
void setActive(bool active)
AVCaptureSession * captureSession() const
AVCaptureDevice * videoCaptureDevice() const
AVFCameraRenderer * videoOutput() const
AVFAudioPreviewDelegate * audioPreviewDelegate() const
QMediaMetaData metaData() const override
void setMetaData(const QMediaMetaData &) override
void updateDuration(qint64 duration)
qint64 duration() const override
void stop() override
void resume() override
void toggleRecord(bool enable)
AVFMediaEncoder(QMediaRecorder *parent)
bool isLocationWritable(const QUrl &location) const override
void record(QMediaEncoderSettings &settings) override
~AVFMediaEncoder() override
AVFCameraService * cameraService() const
QMediaRecorder::RecorderState state() const override
void pause() override
void setCaptureSession(QPlatformMediaCaptureSession *session)
QSize nativeSize() const
static Q_MULTIMEDIA_EXPORT std::unique_ptr< AudioChannelLayout > toAudioChannelLayout(const QAudioFormat &format, UInt32 *size)
The QAudioFormat class stores audio stream parameter information.
static int audioFormatForCodec(QMediaFormat::AudioCodec codec)
static NSString * videoFormatForCodec(QMediaFormat::VideoCodec codec)
constexpr bool isEmpty() const noexcept
QMediaRecorder::Quality quality() const
QMediaRecorder::EncodingMode encodingMode() const
QMediaFormat mediaFormat() const
void setVideoResolution(const QSize &size)
static Q_INVOKABLE QString videoCodecName(VideoCodec codec)
\qmlmethod string QtMultimedia::mediaFormat::videoCodecName(codec) Returns a string based name for co...
VideoCodec videoCodec
The video codec of the media.
AudioCodec audioCodec
The audio codec of the media.
\inmodule QtMultimedia
static QString msgFailedStartRecording()
\inmodule QtMultimedia
RecorderState
\qmlproperty enumeration QtMultimedia::MediaRecorder::recorderState
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void actualLocationChanged(const QUrl &location)
void updateError(QMediaRecorder::Error error, const QString &errorString)
void stateChanged(QMediaRecorder::RecorderState state)
void durationChanged(qint64 position)
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
Q_MULTIMEDIA_EXPORT QString generateFileName(const QString &requestedName, QStandardPaths::StandardLocation type, const QString &extension)
bool qt_is_writable_file_URL(NSURL *fileURL)
bool qt_file_exists(NSURL *fileURL)
#define Q_FUNC_INFO
DBusConnection * connection
QMediaFormat::AudioCodec codec
static AVCodecID codecId(QMediaFormat::VideoCodec codec)
QMediaFormat::FileFormat fileFormat
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLint location
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLboolean enable
GLuint start
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
const GLubyte * c
GLsizei const GLchar *const * path
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define QT_MANGLE_NAMESPACE(name)
#define tr(X)
#define Q_EMIT
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QFuture< QSet< QString > > dictionary
QSettings settings("MySoft", "Star Runner")
[0]
QVBoxLayout * layout
sem release()
QReadWriteLock lock
[0]