diff options
author | Doris Verria <doris.verria@qt.io> | 2021-12-05 23:44:42 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-12-08 15:32:03 +0000 |
commit | 306a07f13d9c72cc89621d317abe7b3cf029105c (patch) | |
tree | 2acfe4c37c6bd7366fb3d3549bbea6e5cce8c1ed | |
parent | ba9f36c76c2ed42811ed2685daf666cab524f711 (diff) |
AVFVideoRenderer: Add frame orientation information from video track
Set video orientation and mirrored flag based on the track's preferred
transformation matrix.
Fixes: QTBUG-98306
Change-Id: I57e49884408f4f905f982da07eb7eb345764dc31
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit 82695e3160f3d2d3198973a24e5480e2ebc1c7d9)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
4 files changed, 78 insertions, 2 deletions
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm index a7dab5e37..0b71880aa 100644 --- a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm +++ b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm @@ -38,7 +38,6 @@ ****************************************************************************/ #include "avfmediaplayer_p.h" -#include "avfmediaplayer_p.h" #include "avfvideorenderercontrol_p.h" #include <private/avfvideosink_p.h> #include <private/avfmetadata_p.h> @@ -48,6 +47,7 @@ #include <qpointer.h> #include <QFileInfo> +#include <QtCore/qmath.h> #import <AVFoundation/AVFoundation.h> @@ -583,6 +583,7 @@ void AVFMediaPlayer::setMedia(const QUrl &content, QIODevice *stream) setVideoAvailable(false); setSeekable(false); m_requestedPosition = -1; + orientationChanged(QVideoFrame::Rotation0, false); Q_EMIT positionChanged(position()); if (m_duration != 0) { m_duration = 0; @@ -1116,8 +1117,13 @@ void AVFMediaPlayer::updateTracks() } else if ([assetTrack.mediaType isEqualToString:AVMediaTypeVideo]) { qtTrack = QPlatformMediaPlayer::VideoStream; setVideoAvailable(true); - if (!m_observer.videoTrack) + if (m_observer.videoTrack != track) { m_observer.videoTrack = track; + bool isMirrored = false; + QVideoFrame::RotationAngle orientation = QVideoFrame::Rotation0; + videoOrientationForAssetTrack(assetTrack, orientation, isMirrored); + orientationChanged(orientation, isMirrored); + } } else if ([assetTrack.mediaType isEqualToString:AVMediaTypeSubtitle]) { qtTrack = QPlatformMediaPlayer::SubtitleStream; @@ -1202,3 +1208,48 @@ void AVFMediaPlayer::nativeSizeChanged(QSize size) return; m_videoSink->setNativeSize(size); } + +void AVFMediaPlayer::orientationChanged(QVideoFrame::RotationAngle rotation, bool mirrored) +{ + if (!m_videoOutput) + return; + + m_videoOutput->setVideoRotation(rotation); + m_videoOutput->setVideoMirrored(mirrored); +} + +void AVFMediaPlayer::videoOrientationForAssetTrack(AVAssetTrack *videoTrack, + QVideoFrame::RotationAngle &angle, + bool &mirrored) +{ + angle = QVideoFrame::Rotation0; + if (videoTrack) { + CGAffineTransform transform = videoTrack.preferredTransform; + if (CGAffineTransformIsIdentity(transform)) + return; + qreal delta = transform.a * transform.d - transform.b * transform.c; + qreal radians = qAtan2(transform.b, transform.a); + qreal degrees = qRadiansToDegrees(radians); + qreal scaleX = (transform.a/qAbs(transform.a)) * qSqrt(qPow(transform.a, 2) + qPow(transform.c, 2)); + qreal scaleY = (transform.d/abs(transform.d)) * qSqrt(qPow(transform.b, 2) + qPow(transform.d, 2)); + + if (delta < 0.0) { // flipped + if (scaleX < 0.0) { + // vertical flip + degrees = -degrees; + } else if (scaleY < 0.0) { + // horizontal flip + degrees = (180 + (int)degrees) % 360; + } + mirrored = true; + } + + if (qFuzzyCompare(degrees, qreal(90)) || qFuzzyCompare(degrees, qreal(-270))) { + angle = QVideoFrame::Rotation270; + } else if (qFuzzyCompare(degrees, qreal(-90)) || qFuzzyCompare(degrees, qreal(270))) { + angle = QVideoFrame::Rotation90; + } else if (qFuzzyCompare(degrees, qreal(180)) || qFuzzyCompare(degrees, qreal(-180))) { + angle = QVideoFrame::Rotation180; + } + } +} diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h index 4bd082c1c..348c070ab 100644 --- a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h +++ b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h @@ -60,10 +60,12 @@ #include <private/qplatformmediaplayer_p.h> #include <QtMultimedia/QMediaPlayer> +#include <QtMultimedia/QVideoFrame> Q_FORWARD_DECLARE_OBJC_CLASS(AVAsset); Q_FORWARD_DECLARE_OBJC_CLASS(AVPlayerItemTrack); Q_FORWARD_DECLARE_OBJC_CLASS(AVFMediaPlayerObserver); +Q_FORWARD_DECLARE_OBJC_CLASS(AVAssetTrack); QT_BEGIN_NAMESPACE @@ -107,6 +109,10 @@ public: QMediaMetaData metaData() const override; + void videoOrientationForAssetTrack(AVAssetTrack *track, + QVideoFrame::RotationAngle &angle, + bool &mirrored); + public Q_SLOTS: void setPlaybackRate(qreal rate) override; void nativeSizeChanged(QSize size); @@ -151,6 +157,8 @@ private: void setSeekable(bool seekable); void resetStream(QIODevice *stream = nullptr); + void orientationChanged(QVideoFrame::RotationAngle rotation, bool mirrored); + AVFVideoRendererControl *m_videoOutput = nullptr; AVFVideoSink *m_videoSink = nullptr; diff --git a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm b/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm index 9cee8da3b..e7bf42395 100644 --- a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm +++ b/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm @@ -154,6 +154,16 @@ void AVFVideoRendererControl::setLayer(CALayer *layer) AVFVideoSinkInterface::setLayer(layer); } +void AVFVideoRendererControl::setVideoRotation(QVideoFrame::RotationAngle rotation) +{ + m_rotation = rotation; +} + +void AVFVideoRendererControl::setVideoMirrored(bool mirrored) +{ + m_mirrored = mirrored; +} + void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts) { Q_UNUSED(ts); @@ -182,6 +192,8 @@ void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts) QVideoFrameFormat format(QSize(width, height), fmt); frame = QVideoFrame(buffer, format); + frame.setRotationAngle(m_rotation); + frame.setMirrored(m_mirrored); m_sink->setVideoFrame(frame); } diff --git a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h b/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h index ce0ec0738..24b5815d7 100644 --- a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h +++ b/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h @@ -80,6 +80,9 @@ public: void reconfigure() override; void setLayer(CALayer *layer) override; + void setVideoRotation(QVideoFrame::RotationAngle); + void setVideoMirrored(bool mirrored); + void setSubtitleText(const QString &subtitle) { m_sink->setSubtitleText(subtitle); @@ -96,6 +99,8 @@ private: AVPlayerItemVideoOutput *m_videoOutput = nullptr; AVPlayerItemLegibleOutput *m_subtitleOutput = nullptr; SubtitleDelegate *m_subtitleDelegate = nullptr; + QVideoFrame::RotationAngle m_rotation = QVideoFrame::Rotation0; + bool m_mirrored = false; }; QT_END_NAMESPACE |