summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoris Verria <doris.verria@qt.io>2021-06-18 13:11:21 +0200
committerDoris Verria <doris.verria@qt.io>2021-06-23 13:11:09 +0200
commitc91afc21c068d8c68d51bf3acb98e8a385b7db8c (patch)
tree28d3f65f5dc1f0cef0e88376eb61de65b9dfcd16
parenta6e014eb088cb9b7bf55bf87c814e75cd4037dc2 (diff)
Add metadata to audio and video capturing on darwin
Add and retrieve common and format specific meta data. Pick-to: 6.2 Change-Id: I3e3f0ffdff52b8cf6e2079fdc1536b130c65773f Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/multimedia/CMakeLists.txt2
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm8
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaencoder.mm10
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaencoder_p.h6
-rw-r--r--src/multimedia/platform/darwin/common/avfmetadata.mm370
-rw-r--r--src/multimedia/platform/darwin/common/avfmetadata_p.h (renamed from src/multimedia/platform/darwin/mediaplayer/avfmetadata_p.h)6
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm2
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfmetadata.mm140
-rw-r--r--tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp89
9 files changed, 488 insertions, 145 deletions
diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt
index ad9eb2767..145740410 100644
--- a/src/multimedia/CMakeLists.txt
+++ b/src/multimedia/CMakeLists.txt
@@ -360,7 +360,7 @@ qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT WATCHOS
platform/darwin/audio/qcoreaudioutils.mm platform/darwin/audio/qcoreaudioutils_p.h
platform/darwin/mediaplayer/avfdisplaylink.mm platform/darwin/mediaplayer/avfdisplaylink_p.h
platform/darwin/mediaplayer/avfmediaplayer.mm platform/darwin/mediaplayer/avfmediaplayer_p.h
- platform/darwin/mediaplayer/avfmetadata.mm platform/darwin/mediaplayer/avfmetadata_p.h
+ platform/darwin/common/avfmetadata.mm platform/darwin/common/avfmetadata_p.h
platform/darwin/mediaplayer/avfvideorenderercontrol.mm platform/darwin/mediaplayer/avfvideorenderercontrol_p.h
platform/darwin/avfvideosink.mm platform/darwin/avfvideosink_p.h
platform/darwin/avfvideobuffer.mm platform/darwin/avfvideobuffer_p.h
diff --git a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
index b7a3b3def..0523a7931 100644
--- a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
+++ b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
@@ -44,6 +44,7 @@
#include "avfcamerasession_p.h"
#include "avfcameradebug_p.h"
#include <private/qdarwinformatsinfo_p.h>
+#include <private/avfmetadata_p.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qatomic.h>
@@ -201,10 +202,17 @@ using AVFAtomicInt64 = QAtomicInteger<qint64>;
if (m_cameraWriterInput)
m_cameraWriterInput.data().transform = transform;
+ [self setMetaData:fileType];
+
// Ready to start ...
return true;
}
+- (void)setMetaData:(AVFileType)fileType
+{
+ m_assetWriter.data().metadata = AVFMetaData::toAVMetadataForFormat(m_delegate->metaData(), fileType);
+}
+
- (void)start
{
[self setQueues];
diff --git a/src/multimedia/platform/darwin/camera/avfmediaencoder.mm b/src/multimedia/platform/darwin/camera/avfmediaencoder.mm
index 96fa82503..ac182fe00 100644
--- a/src/multimedia/platform/darwin/camera/avfmediaencoder.mm
+++ b/src/multimedia/platform/darwin/camera/avfmediaencoder.mm
@@ -414,6 +414,16 @@ QMediaEncoderSettings AVFMediaEncoder::encoderSettings() const
return s;
}
+void AVFMediaEncoder::setMetaData(const QMediaMetaData &metaData)
+{
+ m_metaData = metaData;
+}
+
+QMediaMetaData AVFMediaEncoder::metaData() const
+{
+ return m_metaData;
+}
+
void AVFMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *session)
{
AVFCameraService *captureSession = static_cast<AVFCameraService *>(session);
diff --git a/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h b/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h
index d76df772f..7c57768b0 100644
--- a/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h
+++ b/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h
@@ -58,6 +58,7 @@
#include <private/qplatformmediaencoder_p.h>
#include <private/qvideooutputorientationhandler_p.h>
+#include <QtMultimedia/qmediametadata.h>
#include <QtCore/qglobal.h>
#include <QtCore/qurl.h>
@@ -90,6 +91,9 @@ public:
void setEncoderSettings(const QMediaEncoderSettings &settings) override;
QMediaEncoderSettings encoderSettings() const;
+ void setMetaData(const QMediaMetaData &) override;
+ QMediaMetaData metaData() const override;
+
AVFCameraService *cameraService() const { return m_service; }
void setCaptureSession(QPlatformMediaCaptureSession *session);
@@ -119,6 +123,8 @@ private:
QMediaRecorder::Status m_lastStatus;
QMediaEncoderSettings m_settings;
+ QMediaMetaData m_metaData;
+
NSDictionary *m_audioSettings;
NSDictionary *m_videoSettings;
QVideoOutputOrientationHandler m_orientationHandler;
diff --git a/src/multimedia/platform/darwin/common/avfmetadata.mm b/src/multimedia/platform/darwin/common/avfmetadata.mm
new file mode 100644
index 000000000..dac28143d
--- /dev/null
+++ b/src/multimedia/platform/darwin/common/avfmetadata.mm
@@ -0,0 +1,370 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "avfmetadata_p.h"
+#include <private/qdarwinformatsinfo_p.h>
+
+#include <QtCore/qbuffer.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qlocale.h>
+#include <QtCore/qurl.h>
+#include <QImage>
+
+#if QT_HAS_INCLUDE(<AppKit/AppKit.h>)
+#include <AppKit/AppKit.h>
+#endif
+
+#include <CoreFoundation/CoreFoundation.h>
+
+QT_USE_NAMESPACE
+
+struct AVMetadataIDs {
+ AVMetadataIdentifier common;
+ AVMetadataIdentifier iTunes;
+ AVMetadataIdentifier quickTime;
+ AVMetadataIdentifier ID3;
+};
+
+const AVMetadataIDs keyToAVMetaDataID[] = {
+ // Title
+ { AVMetadataCommonIdentifierTitle, AVMetadataIdentifieriTunesMetadataSongName,
+ AVMetadataIdentifierQuickTimeMetadataTitle,
+ AVMetadataIdentifierID3MetadataTitleDescription },
+ // Author
+ { AVMetadataCommonIdentifierAuthor,AVMetadataIdentifieriTunesMetadataAuthor,
+ AVMetadataIdentifierQuickTimeMetadataAuthor, nil },
+ // Comment
+ { nil, AVMetadataIdentifieriTunesMetadataUserComment,
+ AVMetadataIdentifierQuickTimeMetadataComment, AVMetadataIdentifierID3MetadataComments },
+ // Description
+ { AVMetadataCommonIdentifierDescription,AVMetadataIdentifieriTunesMetadataDescription,
+ AVMetadataIdentifierQuickTimeMetadataDescription, nil },
+ // Genre
+ { nil, AVMetadataIdentifieriTunesMetadataUserGenre,
+ AVMetadataIdentifierQuickTimeMetadataGenre, nil },
+ // Date
+ { AVMetadataCommonIdentifierCreationDate, AVMetadataIdentifieriTunesMetadataReleaseDate,
+ AVMetadataIdentifierQuickTimeMetadataCreationDate, AVMetadataIdentifierID3MetadataDate },
+ // Language
+ { AVMetadataCommonIdentifierLanguage, nil, nil, AVMetadataIdentifierID3MetadataLanguage },
+ // Publisher
+ { AVMetadataCommonIdentifierPublisher, AVMetadataIdentifieriTunesMetadataPublisher,
+ AVMetadataIdentifierQuickTimeMetadataPublisher, AVMetadataIdentifierID3MetadataPublisher },
+ // Copyright
+ { AVMetadataCommonIdentifierCopyrights, AVMetadataIdentifieriTunesMetadataCopyright,
+ AVMetadataIdentifierQuickTimeMetadataCopyright, AVMetadataIdentifierID3MetadataCopyright },
+ // Url
+ { nil, nil, nil, AVMetadataIdentifierID3MetadataOfficialAudioSourceWebpage },
+ // Duration
+ { nil, nil, nil, AVMetadataIdentifierID3MetadataLength },
+ // MediaType
+ { AVMetadataCommonIdentifierType, nil, nil, AVMetadataIdentifierID3MetadataContentType },
+ // FileFormat
+ { nil, nil, nil, AVMetadataIdentifierID3MetadataFileType },
+ // AudioBitRate
+ { nil, nil, nil, nil },
+ // AudioCodec
+ { nil, nil, nil, nil },
+ // VideoBitRate
+ { nil, nil, nil, nil },
+ // VideoCodec
+ { nil, nil, nil, nil },
+ // VideoFrameRate
+ { nil, nil, AVMetadataIdentifierQuickTimeMetadataCameraFrameReadoutTime, nil },
+ // AlbumTitle
+ { AVMetadataCommonIdentifierAlbumName, AVMetadataIdentifieriTunesMetadataAlbum,
+ AVMetadataIdentifierQuickTimeMetadataAlbum, AVMetadataIdentifierID3MetadataAlbumTitle },
+ // AlbumArtist
+ { nil, AVMetadataIdentifieriTunesMetadataAlbumArtist, nil, nil },
+ // ContributingArtist
+ { AVMetadataCommonIdentifierArtist, AVMetadataIdentifieriTunesMetadataArtist,
+ AVMetadataIdentifierQuickTimeMetadataArtist, nil },
+ // TrackNumber
+ { nil, AVMetadataIdentifieriTunesMetadataTrackNumber,
+ nil, AVMetadataIdentifierID3MetadataTrackNumber },
+ // Composer
+ { nil, AVMetadataIdentifieriTunesMetadataComposer,
+ AVMetadataIdentifierQuickTimeMetadataComposer, AVMetadataIdentifierID3MetadataComposer },
+ // LeadPerformer
+ { nil, AVMetadataIdentifieriTunesMetadataPerformer,
+ AVMetadataIdentifierQuickTimeMetadataPerformer, AVMetadataIdentifierID3MetadataLeadPerformer },
+ // ThumbnailImage
+ { nil, nil, nil, AVMetadataIdentifierID3MetadataAttachedPicture},
+ // CoverArtImage
+ { AVMetadataCommonIdentifierArtwork, AVMetadataIdentifieriTunesMetadataCoverArt,
+ AVMetadataIdentifierQuickTimeMetadataArtwork, nil },
+ // Orientation
+ { nil, nil, AVMetadataIdentifierQuickTimeMetadataDirectionFacing, nil },
+ // Resolution
+ { nil, nil, nil, nil }
+};
+
+static AVMetadataIdentifier toIdentifier(QMediaMetaData::Key key, AVMetadataKeySpace keySpace)
+{
+ static_assert(sizeof(keyToAVMetaDataID)/sizeof(AVMetadataIDs) == QMediaMetaData::Key::Resolution + 1);
+
+ AVMetadataIdentifier identifier = nil;
+ if ([keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
+ identifier = keyToAVMetaDataID[key].iTunes;
+ } else if ([keySpace isEqualToString:AVMetadataKeySpaceID3]) {
+ identifier = keyToAVMetaDataID[key].ID3;
+ } else if ([keySpace isEqualToString:AVMetadataKeySpaceQuickTimeMetadata]) {
+ identifier = keyToAVMetaDataID[key].quickTime;
+ } else {
+ identifier = keyToAVMetaDataID[key].common;
+ }
+ return identifier;
+}
+
+static std::optional<QMediaMetaData::Key> toKey(AVMetadataItem *item)
+{
+ static_assert(sizeof(keyToAVMetaDataID)/sizeof(AVMetadataIDs) == QMediaMetaData::Key::Resolution + 1);
+
+ // The item identifier may be different than the ones we support,
+ // so check by common key first, as it will get the metadata
+ // irrespective of the format.
+ AVMetadataKey commonKey = item.commonKey;
+ if (commonKey.length != 0) {
+ if ([commonKey isEqualToString:AVMetadataCommonKeyTitle]) {
+ return QMediaMetaData::Title;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyDescription]) {
+ return QMediaMetaData::Description;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyPublisher]) {
+ return QMediaMetaData::Publisher;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyCreationDate]) {
+ return QMediaMetaData::Date;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyType]) {
+ return QMediaMetaData::MediaType;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyLanguage]) {
+ return QMediaMetaData::Language;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyCopyrights]) {
+ return QMediaMetaData::Copyright;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyAlbumName]) {
+ return QMediaMetaData::AlbumTitle;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyAuthor]) {
+ return QMediaMetaData::Author;
+ } else if ([commonKey isEqualToString:AVMetadataCommonKeyArtist]) {
+ return QMediaMetaData::ContributingArtist;
+ }
+ }
+
+ // Check by identifier if no common key found
+ // No need to check for the common keySpace since there's no common key
+ enum keySpaces { iTunes, QuickTime, ID3, Other } itemKeySpace;
+ itemKeySpace = Other;
+ AVMetadataKeySpace keySpace = [item keySpace];
+ AVMetadataIdentifier identifier = [item identifier];
+
+ if ([keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
+ itemKeySpace = iTunes;
+ } else if ([keySpace isEqualToString:AVMetadataKeySpaceQuickTimeMetadata]) {
+ itemKeySpace = QuickTime;
+ } else if (([keySpace isEqualToString:AVMetadataKeySpaceID3])) {
+ itemKeySpace = ID3;
+ }
+
+ for (int key = 0; key < QMediaMetaData::Resolution + 1; key++) {
+ AVMetadataIdentifier idForKey = nil;
+ switch (itemKeySpace) {
+ case iTunes:
+ idForKey = keyToAVMetaDataID[key].iTunes;
+ break;
+ case QuickTime:
+ idForKey = keyToAVMetaDataID[key].quickTime;
+ break;
+ case ID3:
+ idForKey = keyToAVMetaDataID[key].ID3;
+ break;
+ default:
+ break;
+ }
+
+ if ([identifier isEqualToString:idForKey])
+ return QMediaMetaData::Key(key);
+ }
+
+ return std::nullopt;
+}
+
+static QMediaMetaData fromAVMetadata(NSArray *metadataItems)
+{
+ QMediaMetaData metadata;
+
+ for (AVMetadataItem* item in metadataItems) {
+ auto key = toKey(item);
+ if (!key)
+ continue;
+
+ const QString value = QString::fromNSString([item stringValue]);
+ if (!value.isNull())
+ metadata.insert(*key, value);
+ }
+ return metadata;
+}
+
+QMediaMetaData AVFMetaData::fromAsset(AVAsset *asset)
+{
+#ifdef QT_DEBUG_AVF
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QMediaMetaData metadata = fromAVMetadata([asset metadata]);
+
+ // add duration
+ const CMTime time = [asset duration];
+ const qint64 duration = static_cast<qint64>(float(time.value) / float(time.timescale) * 1000.0f);
+ metadata.insert(QMediaMetaData::Duration, duration);
+
+ return metadata;
+}
+
+QMediaMetaData AVFMetaData::fromAssetTrack(AVAssetTrack *asset)
+{
+ QMediaMetaData metadata = fromAVMetadata([asset metadata]);
+ if (metadata.value(QMediaMetaData::Language).isNull()) {
+ auto *lang = asset.languageCode;
+ if (lang)
+ metadata.insert(QMediaMetaData::Language, QString::fromNSString(lang));
+ }
+ return metadata;
+}
+
+static AVMutableMetadataItem *setAVMetadataItemForKey(QMediaMetaData::Key key, const QVariant &value,
+ AVMetadataKeySpace keySpace = AVMetadataKeySpaceCommon)
+{
+ AVMetadataIdentifier identifier = toIdentifier(key, keySpace);
+ if (!identifier.length)
+ return nil;
+
+ AVMutableMetadataItem *item = [AVMutableMetadataItem metadataItem];
+ item.keySpace = keySpace;
+ item.identifier = identifier;
+
+ switch (key) {
+ case QMediaMetaData::ThumbnailImage:
+ case QMediaMetaData::CoverArtImage: {
+#if defined(Q_OS_MACOS)
+ QImage img = value.value<QImage>();
+ if (!img.isNull()) {
+ QByteArray arr;
+ QBuffer buffer(&arr);
+ buffer.open(QIODevice::WriteOnly);
+ img.save(&buffer);
+ NSData *data = arr.toNSData();
+ NSImage *nsImg = [[NSImage alloc] initWithData:data];
+ item.value = nsImg;
+ [nsImg release];
+ }
+#endif
+ break;
+ }
+ case QMediaMetaData::FileFormat: {
+ QMediaFormat::FileFormat qtFormat = value.value<QMediaFormat::FileFormat>();
+ AVFileType avFormat = QDarwinFormatInfo::avFileTypeForContainerFormat(qtFormat);
+ item.value = avFormat;
+ break;
+ }
+ case QMediaMetaData::Language: {
+ QString lang = QLocale::languageToCode(value.value<QLocale::Language>());
+ if (!lang.isEmpty())
+ item.value = lang.toNSString();
+ break;
+ }
+ default: {
+ switch (value.typeId()) {
+ case QMetaType::QString: {
+ item.value = value.toString().toNSString();
+ break;
+ }
+ case QMetaType::Int: {
+ item.value = [NSNumber numberWithInt:value.toInt()];
+ break;
+ }
+ case QMetaType::LongLong: {
+ item.value = [NSNumber numberWithLongLong:value.toLongLong()];
+ break;
+ }
+ case QMetaType::Double: {
+ item.value = [NSNumber numberWithDouble:value.toDouble()];
+ break;
+ }
+ case QMetaType::QDate:
+ case QMetaType::QDateTime: {
+ item.value = value.toDateTime().toNSDate();
+ break;
+ }
+ case QMetaType::QUrl: {
+ item.value = value.toUrl().toNSURL();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ return item;
+}
+
+NSMutableArray<AVMetadataItem *> *AVFMetaData::toAVMetadataForFormat(QMediaMetaData metadata, AVFileType format)
+{
+ NSMutableArray<AVMetadataKeySpace> *keySpaces = [NSMutableArray<AVMetadataKeySpace> array];
+ if (format == AVFileTypeAppleM4A) {
+ [keySpaces addObject:AVMetadataKeySpaceiTunes];
+ } else if (format == AVFileTypeMPEGLayer3) {
+ [keySpaces addObject:AVMetadataKeySpaceID3];
+ [keySpaces addObject:AVMetadataKeySpaceiTunes];
+ } else if (format == AVFileTypeQuickTimeMovie) {
+ [keySpaces addObject:AVMetadataKeySpaceQuickTimeMetadata];
+ } else {
+ [keySpaces addObject:AVMetadataKeySpaceCommon];
+ }
+ NSMutableArray<AVMetadataItem *> *avMetaDataArr = [NSMutableArray array];
+ for (const auto &key : metadata.keys()) {
+ for (NSUInteger i = 0; i < [keySpaces count]; i++) {
+ const QVariant &value = metadata.value(key);
+ // set format-specific metadata
+ AVMetadataItem *item = setAVMetadataItemForKey(key, value, keySpaces[i]);
+ if (item)
+ [avMetaDataArr addObject:item];
+ }
+ }
+ return avMetaDataArr;
+}
+
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmetadata_p.h b/src/multimedia/platform/darwin/common/avfmetadata_p.h
index 5af50a8ba..e983be531 100644
--- a/src/multimedia/platform/darwin/mediaplayer/avfmetadata_p.h
+++ b/src/multimedia/platform/darwin/common/avfmetadata_p.h
@@ -54,18 +54,18 @@
#include <QtMultimedia/QMediaMetaData>
#include <QtCore/qvariant.h>
-Q_FORWARD_DECLARE_OBJC_CLASS(AVAsset);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVAssetTrack);
+#import <AVFoundation/AVFoundation.h>
QT_BEGIN_NAMESPACE
class AVFMediaPlayer;
-class AVFMetaData : public QMediaMetaData
+class AVFMetaData
{
public:
static QMediaMetaData fromAsset(AVAsset *asset);
static QMediaMetaData fromAssetTrack(AVAssetTrack *asset);
+ static NSMutableArray<AVMetadataItem *> *toAVMetadataForFormat(QMediaMetaData metaData, AVFileType format);
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
index f60c61261..2d87a3e18 100644
--- a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
+++ b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
@@ -41,7 +41,7 @@
#include "avfmediaplayer_p.h"
#include "avfvideorenderercontrol_p.h"
#include <private/avfvideosink_p.h>
-#include "avfmetadata_p.h"
+#include <private/avfmetadata_p.h>
#include "qaudiooutput.h"
#include "qplatformaudiooutput_p.h"
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmetadata.mm b/src/multimedia/platform/darwin/mediaplayer/avfmetadata.mm
deleted file mode 100644
index c61c81252..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfmetadata.mm
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfmetadata_p.h"
-
-#include <QtMultimedia/qmediametadata.h>
-
-#import <AVFoundation/AVFoundation.h>
-
-QT_USE_NAMESPACE
-
-static std::optional<QMediaMetaData::Key> itemKey(AVMetadataItem *item)
-{
- NSString *keyString = [item commonKey];
-// qDebug() << "metadatakey:" << QString::fromNSString(keyString)
-// << QString::fromNSString([item identifier]) << QString::fromNSString([item description]);
-
- if (keyString.length != 0) {
- if ([keyString isEqualToString:AVMetadataCommonKeyTitle]) {
- return QMediaMetaData::Title;
-// } else if ([keyString isEqualToString: AVMetadataCommonKeySubject]) {
-// return QMediaMetaData::SubTitle;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyDescription]) {
- return QMediaMetaData::Description;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyPublisher]) {
- return QMediaMetaData::Publisher;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyCreationDate]) {
- return QMediaMetaData::Date;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyType]) {
- return QMediaMetaData::MediaType;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyLanguage]) {
- return QMediaMetaData::Language;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyCopyrights]) {
- return QMediaMetaData::Copyright;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyAlbumName]) {
- return QMediaMetaData::AlbumTitle;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyAuthor]) {
- return QMediaMetaData::Author;
- } else if ([keyString isEqualToString: AVMetadataCommonKeyArtist]) {
- return QMediaMetaData::ContributingArtist;
-// } else if ([keyString isEqualToString: AVMetadataCommonKeyArtwork]) {
-// return QMediaMetaData::PosterUrl;
- }
- }
-
- // check by identifier
- NSString *id = [item identifier];
- if (!id)
- return std::nullopt;
-
- if ([id isEqualToString: AVMetadataIdentifieriTunesMetadataUserComment] ||
- [id isEqualToString: AVMetadataIdentifierID3MetadataComments] ||
- [id isEqualToString: AVMetadataIdentifierQuickTimeMetadataComment])
- return QMediaMetaData::Comment;
-
- if ([id isEqualToString: AVMetadataIdentifierID3MetadataDate] ||
- [id isEqualToString: AVMetadataIdentifierISOUserDataDate])
- return QMediaMetaData::Date;
-
-
- return std::nullopt;
-}
-
-static QMediaMetaData fromAVMetaData(NSArray *metaDataItems)
-{
- QMediaMetaData metaData;
-
- for (AVMetadataItem* item in metaDataItems) {
- auto key = itemKey(item);
- if (!key)
- continue;
-
- const QString value = QString::fromNSString([item stringValue]);
- if (!value.isNull())
- metaData.insert(*key, value);
- }
- return metaData;
-}
-
-QMediaMetaData AVFMetaData::fromAsset(AVAsset *asset)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- QMediaMetaData metaData = fromAVMetaData([asset metadata]);
-
- // add duration
- const CMTime time = [asset duration];
- const qint64 duration = static_cast<qint64>(float(time.value) / float(time.timescale) * 1000.0f);
- metaData.insert(QMediaMetaData::Duration, duration);
-
- return metaData;
-}
-
-QMediaMetaData AVFMetaData::fromAssetTrack(AVAssetTrack *asset)
-{
- QMediaMetaData metaData = fromAVMetaData([asset metadata]);
- if (metaData.value(QMediaMetaData::Language).isNull()) {
- auto *lang = asset.languageCode;
- if (lang)
- metaData.insert(QMediaMetaData::Language, QString::fromNSString(lang));
- }
- return metaData;
-}
diff --git a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp
index a656c1da0..4573c52b5 100644
--- a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp
+++ b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp
@@ -30,6 +30,8 @@
#include <QtTest/QtTest>
#include <QtGui/QImageReader>
+#include <QtCore/qurl.h>
+#include <QtCore/qlocale.h>
#include <QDebug>
#include <private/qplatformcamera_p.h>
@@ -41,6 +43,8 @@
#include <qobject.h>
#include <qmediadevices.h>
#include <qmediarecorder.h>
+#include <qmediaplayer.h>
+#include <qaudiooutput.h>
QT_USE_NAMESPACE
@@ -74,6 +78,9 @@ private slots:
void testVideoRecording_data();
void testVideoRecording();
+
+ void testNativeMetadata();
+
private:
bool noCamera = false;
};
@@ -456,6 +463,12 @@ void tst_QCameraBackend::testVideoRecording()
recorder.setVideoResolution(320, 240);
+ // Insert metadata
+ QMediaMetaData metaData;
+ metaData.insert(QMediaMetaData::Author, QString::fromUtf8("Author"));
+ metaData.insert(QMediaMetaData::Date, QDateTime(QDateTime::currentDateTime()));
+ recorder.setMetaData(metaData);
+
QCOMPARE(recorder.status(), QMediaRecorder::StoppedStatus);
camera->start();
@@ -474,6 +487,9 @@ void tst_QCameraBackend::testVideoRecording()
QTRY_COMPARE(recorder.status(), QMediaRecorder::RecordingStatus);
QCOMPARE(recorderStatusSignal.last().first().value<QMediaRecorder::Status>(), recorder.status());
QTest::qWait(200);
+
+ QCOMPARE(recorder.metaData(), metaData);
+
recorderStatusSignal.clear();
recorder.stop();
bool foundFinalizingStatus = false;
@@ -501,6 +517,79 @@ void tst_QCameraBackend::testVideoRecording()
}
}
+void tst_QCameraBackend::testNativeMetadata()
+{
+ if (noCamera)
+ QSKIP("No camera available");
+
+ QMediaCaptureSession session;
+ QCameraDevice device = QMediaDevices::defaultVideoInput();
+ QCamera camera(device);
+ session.setCamera(&camera);
+
+ QMediaRecorder recorder;
+ session.setEncoder(&recorder);
+
+ QSignalSpy errorSignal(&camera, SIGNAL(errorOccurred(QCamera::Error, const QString &)));
+ QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
+
+ QCOMPARE(recorder.status(), QMediaRecorder::StoppedStatus);
+
+ camera.start();
+ if (device.isNull()) {
+ QVERIFY(!camera.isActive());
+ return;
+ }
+
+ QTRY_VERIFY(camera.isActive());
+ QTRY_COMPARE(recorder.status(), QMediaRecorder::StoppedStatus);
+
+ // Insert common metadata supported on all platforms
+ QMediaMetaData metaData;
+ metaData.insert(QMediaMetaData::Title, QString::fromUtf8("Title"));
+ metaData.insert(QMediaMetaData::Date, QDate::currentDate());
+ metaData.insert(QMediaMetaData::Description, QString::fromUtf8("Description"));
+
+ recorder.setMetaData(metaData);
+
+ recorder.record();
+ QTRY_COMPARE(recorder.status(), QMediaRecorder::RecordingStatus);
+ QTest::qWait(200);
+
+ QCOMPARE(recorder.metaData(), metaData);
+
+ recorder.stop();
+ QTRY_COMPARE(recorder.status(), QMediaRecorder::StoppedStatus);
+
+ QVERIFY(errorSignal.isEmpty());
+ QVERIFY(recorderErrorSignal.isEmpty());
+
+ QString fileName = recorder.actualLocation().toLocalFile();
+ QVERIFY(!fileName.isEmpty());
+ QVERIFY(QFileInfo(fileName).size() > 0);
+
+ // QMediaRecorder::metaData() can only test that QMediaMetaData is set properly on the recorder.
+ // Use QMediaPlayer to test that the native metadata is properly set on the track
+ QMediaPlayer player;
+ QAudioOutput output;
+ player.setAudioOutput(&output);
+
+ QSignalSpy metadataChangedSpy(&player, SIGNAL(metaDataChanged()));
+
+ player.setSource(QUrl::fromLocalFile(fileName));
+
+ QTRY_VERIFY(metadataChangedSpy.count() > 0);
+
+ QCOMPARE(player.metaData().value(QMediaMetaData::Title).toString(), metaData.value(QMediaMetaData::Title).toString());
+ QCOMPARE(player.metaData().value(QMediaMetaData::Date).toDateTime(), metaData.value(QMediaMetaData::Date).toDateTime());
+ QCOMPARE(player.metaData().value(QMediaMetaData::Description).toString(), metaData.value(QMediaMetaData::Description).toString());
+
+ metadataChangedSpy.clear();
+
+ player.stop();
+ QFile(fileName).remove();
+}
+
QTEST_MAIN(tst_QCameraBackend)
#include "tst_qcamerabackend.moc"