15#include "private/qmediastoragelocation_p.h"
16#include "private/qmediarecorder_p.h"
18#include "private/qplatformaudiooutput_p.h"
19#include <private/qplatformaudioinput_p.h>
21#include <QtCore/qmath.h>
22#include <QtCore/qdebug.h>
23#include <QtCore/qmimetype.h>
25#include <private/qcoreaudioutils_p.h>
35 if (![fileURL isFileURL])
38 if (NSString *
path = [[fileURL
path] stringByExpandingTildeInPath]) {
39 return [[NSFileManager defaultManager]
40 isWritableFileAtPath:[
path stringByDeletingLastPathComponent]];
50 if (NSString *
path = [[fileURL
path] stringByExpandingTildeInPath])
51 return [[NSFileManager defaultManager] fileExistsAtPath:
path];
63 , m_audioSettings(nil)
64 , m_videoSettings(nil)
111 [
settings setObject:[NSNumber numberWithInt:
codecId] forKey:AVFormatIDKey];
114 if (
codecId != kAudioFormatAppleLossless &&
codecId != kAudioFormatLinearPCM
118 switch (encoderSettings.
quality()) {
120 quality = AVAudioQualityMin;
123 quality = AVAudioQualityLow;
126 quality = AVAudioQualityHigh;
129 quality = AVAudioQualityMax;
133 quality = AVAudioQualityMedium;
136 [
settings setObject:[NSNumber numberWithInt:quality] forKey:AVEncoderAudioQualityKey];
139 bool isBitRateSupported =
false;
143 for (
int i = 0;
i < bitRates.
count();
i++) {
144 if (bitRate >= bitRates[
i].mMinimum &&
145 bitRate <= bitRates[
i].mMaximum) {
146 isBitRateSupported =
true;
150 if (isBitRateSupported)
152 forKey:AVEncoderBitRateKey];
158 bool isSampleRateSupported =
false;
159 if (sampleRate >= 8000 && sampleRate <= 192000) {
161 for (
int i = 0;
i < sampleRates.
count();
i++) {
162 if (sampleRate >= sampleRates[
i].mMinimum && sampleRate <= sampleRates[
i].mMaximum) {
163 isSampleRateSupported =
true;
168 if (!isSampleRateSupported)
170 [
settings setObject:[NSNumber numberWithInt:sampleRate] forKey:AVSampleRateKey];
174 bool isChannelCountSupported =
false;
175 if (channelCount > 0) {
179 if (channelCounts == std::nullopt) {
180 isChannelCountSupported =
true;
182 for (
int i = 0;
i < channelCounts.value().
count();
i++) {
183 if ((UInt32)channelCount == channelCounts.value()[
i]) {
184 isChannelCountSupported =
true;
192 if (isChannelCountSupported && channelCount > 2) {
193 AudioChannelLayout channelLayout;
194 memset(&channelLayout, 0,
sizeof(AudioChannelLayout));
196 if (channelLayoutTags.size()) {
197 channelLayout.mChannelLayoutTag = channelLayoutTags.first();
198 [
settings setObject:[NSData dataWithBytes: &channelLayout
length:
sizeof(channelLayout)] forKey:AVChannelLayoutKey];
200 isChannelCountSupported =
false;
204 if (isChannelCountSupported)
205 [
settings setObject:[NSNumber numberWithInt:channelCount] forKey:AVNumberOfChannelsKey];
208 if (!isChannelCountSupported) {
213 [
settings setObject:[NSData dataWithBytes:
layout.get()
length:
sizeof(AudioChannelLayout)] forKey:AVChannelLayoutKey];
216 [
settings setObject:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
220 if (
codecId == kAudioFormatAppleLossless)
221 [
settings setObject:[NSNumber numberWithInt:24] forKey:AVEncoderBitDepthHintKey];
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];
242 NSMutableDictionary *videoSettings = [NSMutableDictionary
dictionary];
249 [videoSettings setObject:
c forKey:AVVideoCodecKey];
257 if (AVCaptureDeviceFormat *currentFormat =
device.activeFormat) {
258 CMFormatDescriptionRef formatDesc = currentFormat.formatDescription;
259 CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
260 FourCharCode formatCodec = CMVideoFormatDescriptionGetCodecType(formatDesc);
266 AVCaptureDeviceFormat *newFormat = nil;
267 if ((
w <= 0 ||
h <= 0)
275 }
else if (
w > 0 &&
h > 0) {
281 CMVideoDimensions
d = CMVideoFormatDescriptionGetDimensions(
f.formatDescription);
284 if (
w > dim.width ||
h > dim.height
285 ||
qAbs((
qreal(dim.width) / dim.height) - fAspectRatio) > 0.01) {
292 formatDesc = newFormat.formatDescription;
293 dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
296 if (
w < 0 ||
h < 0) {
302 if (
w > 0 &&
h > 0) {
305 qreal deviceAspectRatio =
qreal(dim.width) / dim.height;
307 if (
qAbs(deviceAspectRatio - recAspectRatio) > 0.01) {
308 if (recAspectRatio > deviceAspectRatio)
320 if (
w > 0 &&
h > 0) {
325 bool isPortrait = nativeSize.
width() < nativeSize.
height();
327 if (isPortrait &&
h <
w)
329 else if (!isPortrait &&
w <
h)
338 [videoSettings setObject:[NSNumber numberWithInt:
w] forKey:AVVideoWidthKey];
339 [videoSettings setObject:[NSNumber numberWithInt:
h] forKey:AVVideoHeightKey];
351 NSMutableDictionary *codecProperties = [NSMutableDictionary
dictionary];
353 float quality = -1.f;
358 qWarning(
"ConstantQualityEncoding is not supported for MotionJPEG");
360 switch (encoderSettings.
quality()) {
385 qWarning(
"Encoding mode is not supported");
389 [codecProperties setObject:[NSNumber numberWithInt:bitrate] forKey:AVVideoAverageBitRateKey];
391 [codecProperties setObject:[NSNumber numberWithFloat:quality] forKey:AVVideoQualityKey];
393 [videoSettings setObject:codecProperties forKey:AVVideoCompressionPropertiesKey];
395 return videoSettings;
405 const auto audioInput = m_service->
audioInput();
409 [m_audioSettings retain];
420 [m_videoSettings retain];
423void AVFMediaEncoder::unapplySettings()
425 if (m_audioSettings) {
427 m_audioSettings = nil;
429 if (m_videoSettings) {
431 m_videoSettings = nil;
448 if (m_service == captureSession)
454 m_service = captureSession;
464 if (!m_service || !m_service->
session()) {
480 if (!cameraControl && !audioInput) {
492 if (!cameraControl || !cameraControl->
isActive()) {
493 qCDebug(qLcCamera) <<
Q_FUNC_INFO <<
"can not start record while camera is not active";
504 settings.mimeType().preferredSuffix())));
506 NSURL *nsFileURL = fileURL.toNSURL();
512 if (!qt_is_writable_file_URL(nsFileURL)) {
514 <<
"(the location is not writable)";
518 if (qt_file_exists(nsFileURL)) {
522 <<
"(file already exists)";
533 [session stopRunning];
535 if ([m_writer setupWithFileURL:nsFileURL
537 audioSettings:m_audioSettings
538 videoSettings:m_videoSettings
557 [session startRunning];
595 if (!m_service || !m_service->
session())
604void AVFMediaEncoder::assetWriterStarted()
608void AVFMediaEncoder::assetWriterFinished()
628 if (m_state != lastState)
632void AVFMediaEncoder::assetWriterError(
QString err)
639void AVFMediaEncoder::onCameraChanged()
644 SLOT(cameraActiveChanged(
bool)));
648void AVFMediaEncoder::cameraActiveChanged(
bool active)
659void AVFMediaEncoder::stopWriter()
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)
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
static Q_MULTIMEDIA_EXPORT std::unique_ptr< AudioChannelLayout > toAudioChannelLayout(const QAudioFormat &format, UInt32 *size)
bool isActive() const override
constexpr bool isEmpty() const noexcept
qsizetype count() const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
static void setIsRecording(bool isRecording)
bool qt_is_writable_file_URL(NSURL *fileURL)
bool qt_file_exists(NSURL *fileURL)
DBusConnection * connection
int qRound(qfloat16 d) noexcept
#define qCDebug(category,...)
constexpr float qDegreesToRadians(float degrees)
constexpr const T & qMin(const T &a, const T &b)
constexpr T qAbs(const T &t)
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLsizei const GLchar *const * path
QLatin1StringView QLatin1String
#define QT_MANGLE_NAMESPACE(name)
QFuture< QSet< QString > > dictionary
QSettings settings("MySoft", "Star Runner")
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent