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 <yoann.lopes@theqtcompany.com>
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "avfcameraviewfindersettingscontrol.h"
|
#include "avfcameraviewfindersettingscontrol.h"
|
||||||
|
#include "private/qabstractvideobuffer_p.h"
|
||||||
#include "avfcamerarenderercontrol.h"
|
#include "avfcamerarenderercontrol.h"
|
||||||
#include "avfcamerasession.h"
|
#include "avfcamerasession.h"
|
||||||
#include "avfcameraservice.h"
|
#include "avfcameraservice.h"
|
||||||
@@ -39,15 +40,17 @@
|
|||||||
|
|
||||||
#include <QtMultimedia/qabstractvideosurface.h>
|
#include <QtMultimedia/qabstractvideosurface.h>
|
||||||
#include <QtMultimedia/qabstractvideobuffer.h>
|
#include <QtMultimedia/qabstractvideobuffer.h>
|
||||||
|
|
||||||
#include <QtMultimedia/qvideosurfaceformat.h>
|
#include <QtMultimedia/qvideosurfaceformat.h>
|
||||||
|
|
||||||
QT_USE_NAMESPACE
|
QT_USE_NAMESPACE
|
||||||
|
|
||||||
class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer
|
class CVPixelBufferVideoBuffer : public QAbstractPlanarVideoBuffer
|
||||||
{
|
{
|
||||||
|
friend class CVPixelBufferVideoBufferPrivate;
|
||||||
public:
|
public:
|
||||||
CVPixelBufferVideoBuffer(CVPixelBufferRef buffer)
|
CVPixelBufferVideoBuffer(CVPixelBufferRef buffer)
|
||||||
: QAbstractVideoBuffer(NoHandle)
|
: QAbstractPlanarVideoBuffer(NoHandle)
|
||||||
, m_buffer(buffer)
|
, m_buffer(buffer)
|
||||||
, m_mode(NotMapped)
|
, m_mode(NotMapped)
|
||||||
{
|
{
|
||||||
@@ -61,6 +64,42 @@ public:
|
|||||||
|
|
||||||
MapMode mapMode() const { return m_mode; }
|
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)
|
uchar *map(MapMode mode, int *numBytes, int *bytesPerLine)
|
||||||
{
|
{
|
||||||
if (mode != NotMapped && m_mode == NotMapped) {
|
if (mode != NotMapped && m_mode == NotMapped) {
|
||||||
@@ -73,7 +112,6 @@ public:
|
|||||||
*bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer);
|
*bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer);
|
||||||
|
|
||||||
m_mode = mode;
|
m_mode = mode;
|
||||||
|
|
||||||
return (uchar*)CVPixelBufferGetBaseAddress(m_buffer);
|
return (uchar*)CVPixelBufferGetBaseAddress(m_buffer);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -93,6 +131,7 @@ private:
|
|||||||
MapMode m_mode;
|
MapMode m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@interface AVFCaptureFramesDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
|
@interface AVFCaptureFramesDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
|
||||||
{
|
{
|
||||||
@private
|
@private
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ private:
|
|||||||
void setFramerate(qreal minFPS, qreal maxFPS, bool useActive);
|
void setFramerate(qreal minFPS, qreal maxFPS, bool useActive);
|
||||||
void setPixelFormat(QVideoFrame::PixelFormat newFormat);
|
void setPixelFormat(QVideoFrame::PixelFormat newFormat);
|
||||||
AVCaptureDeviceFormat *findBestFormatMatch(const QCameraViewfinderSettings &settings) const;
|
AVCaptureDeviceFormat *findBestFormatMatch(const QCameraViewfinderSettings &settings) const;
|
||||||
|
QVector<QVideoFrame::PixelFormat> viewfinderPixelFormats() const;
|
||||||
bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const;
|
bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const;
|
||||||
void applySettings();
|
void applySettings();
|
||||||
QCameraViewfinderSettings requestedSettings() const;
|
QCameraViewfinderSettings requestedSettings() const;
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
#include "avfcameraservice.h"
|
#include "avfcameraservice.h"
|
||||||
#include "avfcameradebug.h"
|
#include "avfcameradebug.h"
|
||||||
|
|
||||||
|
#include <QtMultimedia/qabstractvideosurface.h>
|
||||||
|
|
||||||
#include <QtCore/qvariant.h>
|
#include <QtCore/qvariant.h>
|
||||||
#include <QtCore/qsysinfo.h>
|
#include <QtCore/qsysinfo.h>
|
||||||
#include <QtCore/qvector.h>
|
#include <QtCore/qvector.h>
|
||||||
@@ -52,28 +54,6 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
QVector<QVideoFrame::PixelFormat> qt_viewfinder_pixel_formats(AVCaptureVideoDataOutput *videoOutput)
|
|
||||||
{
|
|
||||||
Q_ASSERT(videoOutput);
|
|
||||||
|
|
||||||
QVector<QVideoFrame::PixelFormat> qtFormats;
|
|
||||||
|
|
||||||
NSArray *pixelFormats = [videoOutput availableVideoCVPixelFormatTypes];
|
|
||||||
for (NSObject *obj in pixelFormats) {
|
|
||||||
if (![obj isKindOfClass:[NSNumber class]])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
NSNumber *formatAsNSNumber = static_cast<NSNumber *>(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)
|
bool qt_framerates_sane(const QCameraViewfinderSettings &settings)
|
||||||
{
|
{
|
||||||
const qreal minFPS = settings.minimumFrameRate();
|
const qreal minFPS = settings.minimumFrameRate();
|
||||||
@@ -269,7 +249,8 @@ QList<QCameraViewfinderSettings> AVFCameraViewfinderSettingsControl2::supportedV
|
|||||||
|
|
||||||
QVector<AVFPSRange> framerates;
|
QVector<AVFPSRange> framerates;
|
||||||
|
|
||||||
QVector<QVideoFrame::PixelFormat> pixelFormats(qt_viewfinder_pixel_formats(m_videoOutput));
|
QVector<QVideoFrame::PixelFormat> pixelFormats(viewfinderPixelFormats());
|
||||||
|
|
||||||
if (!pixelFormats.size())
|
if (!pixelFormats.size())
|
||||||
pixelFormats << QVideoFrame::Format_Invalid; // The default value.
|
pixelFormats << QVideoFrame::Format_Invalid; // The default value.
|
||||||
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
|
#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;
|
return QVideoFrame::Format_RGB24;
|
||||||
case kCVPixelFormatType_24BGR:
|
case kCVPixelFormatType_24BGR:
|
||||||
return QVideoFrame::Format_BGR24;
|
return QVideoFrame::Format_BGR24;
|
||||||
|
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
|
||||||
|
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
|
||||||
|
return QVideoFrame::Format_NV12;
|
||||||
default:
|
default:
|
||||||
return QVideoFrame::Format_Invalid;
|
return QVideoFrame::Format_Invalid;
|
||||||
}
|
}
|
||||||
@@ -414,6 +398,9 @@ bool AVFCameraViewfinderSettingsControl2::CVPixelFormatFromQtFormat(QVideoFrame:
|
|||||||
case QVideoFrame::Format_BGRA32:
|
case QVideoFrame::Format_BGRA32:
|
||||||
conv = kCVPixelFormatType_32ARGB;
|
conv = kCVPixelFormatType_32ARGB;
|
||||||
break;
|
break;
|
||||||
|
case QVideoFrame::Format_NV12:
|
||||||
|
conv = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
|
||||||
|
break;
|
||||||
// These two formats below are not supported
|
// These two formats below are not supported
|
||||||
// by QSGVideoNodeFactory_RGB, so for now I have to
|
// by QSGVideoNodeFactory_RGB, so for now I have to
|
||||||
// disable them.
|
// disable them.
|
||||||
@@ -467,7 +454,37 @@ AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFrame::PixelFormat qtFormat, unsigned &avfFormat)const
|
QVector<QVideoFrame::PixelFormat> AVFCameraViewfinderSettingsControl2::viewfinderPixelFormats() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_videoOutput);
|
||||||
|
|
||||||
|
QVector<QVideoFrame::PixelFormat> qtFormats;
|
||||||
|
QList<QVideoFrame::PixelFormat> 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<NSNumber *>(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);
|
Q_ASSERT(m_videoOutput);
|
||||||
|
|
||||||
@@ -479,17 +496,25 @@ bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFr
|
|||||||
if (!formats || !formats.count)
|
if (!formats || !formats.count)
|
||||||
return false;
|
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) {
|
for (NSObject *obj in formats) {
|
||||||
if (![obj isKindOfClass:[NSNumber class]])
|
if (![obj isKindOfClass:[NSNumber class]])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
NSNumber *nsNum = static_cast<NSNumber *>(obj);
|
NSNumber *nsNum = static_cast<NSNumber *>(obj);
|
||||||
if ([nsNum unsignedIntValue] == conv) {
|
if ([nsNum unsignedIntValue] == conv) {
|
||||||
avfFormat = conv;
|
avfFormat = conv;
|
||||||
return true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFCameraViewfinderSettingsControl2::applySettings()
|
void AVFCameraViewfinderSettingsControl2::applySettings()
|
||||||
|
|||||||
Reference in New Issue
Block a user