From 09afe9377d41171368c083b7cb79fd888f6d8979 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 17 Mar 2015 09:48:54 +0100 Subject: AVFCameraViewfinderSettings - add NV12 format Add QVideoFrame::Format_NV12 (AVFoundation has kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange and kCVPixelFormatType_420YpCbCr8BiPlanarFullRange). Report it (set it) only if it's supported by renderer's surface. Add bi-planar format support into CVPixelBufferVideoBuffer. Change-Id: Ibc1c2be056bddf5cf3b595570fc40c626ee3ccf5 Reviewed-by: Yoann Lopes --- .../camera/avfcamerarenderercontrol.mm | 45 ++++++++++++- .../camera/avfcameraviewfindersettingscontrol.h | 1 + .../camera/avfcameraviewfindersettingscontrol.mm | 77 ++++++++++++++-------- 3 files changed, 94 insertions(+), 29 deletions(-) diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index 87bfeb82a..cf13635f0 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -32,6 +32,7 @@ ****************************************************************************/ #include "avfcameraviewfindersettingscontrol.h" +#include "private/qabstractvideobuffer_p.h" #include "avfcamerarenderercontrol.h" #include "avfcamerasession.h" #include "avfcameraservice.h" @@ -39,15 +40,17 @@ #include #include + #include QT_USE_NAMESPACE -class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer +class CVPixelBufferVideoBuffer : public QAbstractPlanarVideoBuffer { + friend class CVPixelBufferVideoBufferPrivate; public: CVPixelBufferVideoBuffer(CVPixelBufferRef buffer) - : QAbstractVideoBuffer(NoHandle) + : QAbstractPlanarVideoBuffer(NoHandle) , m_buffer(buffer) , m_mode(NotMapped) { @@ -61,6 +64,42 @@ public: MapMode mapMode() const { return m_mode; } + int map(QAbstractVideoBuffer::MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) + { + // We only support RGBA or NV12 (or Apple's version of NV12), + // they are either 0 planes or 2. + const size_t nPlanes = CVPixelBufferGetPlaneCount(m_buffer); + Q_ASSERT(nPlanes <= 2); + + if (!nPlanes) { + data[0] = map(mode, numBytes, bytesPerLine); + return data[0] ? 1 : 0; + } + + // For a bi-planar format we have to set the parameters correctly: + if (mode != QAbstractVideoBuffer::NotMapped && m_mode == QAbstractVideoBuffer::NotMapped) { + CVPixelBufferLockBaseAddress(m_buffer, 0); + + if (numBytes) + *numBytes = CVPixelBufferGetDataSize(m_buffer); + + if (bytesPerLine) { + // At the moment we handle only bi-planar format. + bytesPerLine[0] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, 0); + bytesPerLine[1] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, 1); + } + + if (data) { + data[0] = (uchar *)CVPixelBufferGetBaseAddressOfPlane(m_buffer, 0); + data[1] = (uchar *)CVPixelBufferGetBaseAddressOfPlane(m_buffer, 1); + } + + m_mode = mode; + } + + return nPlanes; + } + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) { if (mode != NotMapped && m_mode == NotMapped) { @@ -73,7 +112,6 @@ public: *bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer); m_mode = mode; - return (uchar*)CVPixelBufferGetBaseAddress(m_buffer); } else { return 0; @@ -93,6 +131,7 @@ private: MapMode m_mode; }; + @interface AVFCaptureFramesDelegate : NSObject { @private diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h index fccc938a9..cf2f512a7 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h @@ -74,6 +74,7 @@ private: void setFramerate(qreal minFPS, qreal maxFPS, bool useActive); void setPixelFormat(QVideoFrame::PixelFormat newFormat); AVCaptureDeviceFormat *findBestFormatMatch(const QCameraViewfinderSettings &settings) const; + QVector viewfinderPixelFormats() const; bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const; void applySettings(); QCameraViewfinderSettings requestedSettings() const; diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index 250aae9c1..60df1e2ed 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -38,6 +38,8 @@ #include "avfcameraservice.h" #include "avfcameradebug.h" +#include + #include #include #include @@ -52,28 +54,6 @@ QT_BEGIN_NAMESPACE namespace { -QVector qt_viewfinder_pixel_formats(AVCaptureVideoDataOutput *videoOutput) -{ - Q_ASSERT(videoOutput); - - QVector qtFormats; - - NSArray *pixelFormats = [videoOutput availableVideoCVPixelFormatTypes]; - for (NSObject *obj in pixelFormats) { - if (![obj isKindOfClass:[NSNumber class]]) - continue; - - NSNumber *formatAsNSNumber = static_cast(obj); - // It's actually FourCharCode (== UInt32): - const QVideoFrame::PixelFormat qtFormat(AVFCameraViewfinderSettingsControl2:: - QtPixelFormatFromCVFormat([formatAsNSNumber unsignedIntValue])); - if (qtFormat != QVideoFrame::Format_Invalid) - qtFormats << qtFormat; - } - - return qtFormats; -} - bool qt_framerates_sane(const QCameraViewfinderSettings &settings) { const qreal minFPS = settings.minimumFrameRate(); @@ -269,7 +249,8 @@ QList AVFCameraViewfinderSettingsControl2::supportedV QVector framerates; - QVector pixelFormats(qt_viewfinder_pixel_formats(m_videoOutput)); + QVector pixelFormats(viewfinderPixelFormats()); + if (!pixelFormats.size()) pixelFormats << QVideoFrame::Format_Invalid; // The default value. #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) @@ -397,6 +378,9 @@ QVideoFrame::PixelFormat AVFCameraViewfinderSettingsControl2::QtPixelFormatFromC return QVideoFrame::Format_RGB24; case kCVPixelFormatType_24BGR: return QVideoFrame::Format_BGR24; + case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: + case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: + return QVideoFrame::Format_NV12; default: return QVideoFrame::Format_Invalid; } @@ -414,6 +398,9 @@ bool AVFCameraViewfinderSettingsControl2::CVPixelFormatFromQtFormat(QVideoFrame: case QVideoFrame::Format_BGRA32: conv = kCVPixelFormatType_32ARGB; break; + case QVideoFrame::Format_NV12: + conv = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange; + break; // These two formats below are not supported // by QSGVideoNodeFactory_RGB, so for now I have to // disable them. @@ -467,7 +454,37 @@ AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch( return nil; } -bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFrame::PixelFormat qtFormat, unsigned &avfFormat)const +QVector AVFCameraViewfinderSettingsControl2::viewfinderPixelFormats() const +{ + Q_ASSERT(m_videoOutput); + + QVector qtFormats; + QList filter; + + NSArray *pixelFormats = [m_videoOutput availableVideoCVPixelFormatTypes]; + const QAbstractVideoSurface *surface = m_service->videoOutput() ? m_service->videoOutput()->surface() : 0; + + if (surface) + filter = surface->supportedPixelFormats(); + + for (NSObject *obj in pixelFormats) { + if (![obj isKindOfClass:[NSNumber class]]) + continue; + + NSNumber *formatAsNSNumber = static_cast(obj); + // It's actually FourCharCode (== UInt32): + const QVideoFrame::PixelFormat qtFormat(QtPixelFormatFromCVFormat([formatAsNSNumber unsignedIntValue])); + if (qtFormat != QVideoFrame::Format_Invalid && (!surface || filter.contains(qtFormat)) + && !qtFormats.contains(qtFormat)) { // Can happen, for example, with 8BiPlanar existing in video/full range. + qtFormats << qtFormat; + } + } + + return qtFormats; +} + +bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFrame::PixelFormat qtFormat, + unsigned &avfFormat)const { Q_ASSERT(m_videoOutput); @@ -479,17 +496,25 @@ bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFr if (!formats || !formats.count) return false; + if (m_service->videoOutput() && m_service->videoOutput()->surface()) { + const QAbstractVideoSurface *surface = m_service->videoOutput()->surface(); + if (!surface->supportedPixelFormats().contains(qtFormat)) + return false; + } + + bool found = false; for (NSObject *obj in formats) { if (![obj isKindOfClass:[NSNumber class]]) continue; + NSNumber *nsNum = static_cast(obj); if ([nsNum unsignedIntValue] == conv) { avfFormat = conv; - return true; + found = true; } } - return false; + return found; } void AVFCameraViewfinderSettingsControl2::applySettings() -- cgit v1.2.3