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 "private/qabstractvideobuffer_p.h"
|
||||
#include "avfcamerarenderercontrol.h"
|
||||
#include "avfcamerasession.h"
|
||||
#include "avfcameraservice.h"
|
||||
@@ -39,15 +40,17 @@
|
||||
|
||||
#include <QtMultimedia/qabstractvideosurface.h>
|
||||
#include <QtMultimedia/qabstractvideobuffer.h>
|
||||
|
||||
#include <QtMultimedia/qvideosurfaceformat.h>
|
||||
|
||||
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 <AVCaptureVideoDataOutputSampleBufferDelegate>
|
||||
{
|
||||
@private
|
||||
|
||||
@@ -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<QVideoFrame::PixelFormat> viewfinderPixelFormats() const;
|
||||
bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const;
|
||||
void applySettings();
|
||||
QCameraViewfinderSettings requestedSettings() const;
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "avfcameraservice.h"
|
||||
#include "avfcameradebug.h"
|
||||
|
||||
#include <QtMultimedia/qabstractvideosurface.h>
|
||||
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qsysinfo.h>
|
||||
#include <QtCore/qvector.h>
|
||||
@@ -52,28 +54,6 @@ QT_BEGIN_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)
|
||||
{
|
||||
const qreal minFPS = settings.minimumFrameRate();
|
||||
@@ -269,7 +249,8 @@ QList<QCameraViewfinderSettings> AVFCameraViewfinderSettingsControl2::supportedV
|
||||
|
||||
QVector<AVFPSRange> framerates;
|
||||
|
||||
QVector<QVideoFrame::PixelFormat> pixelFormats(qt_viewfinder_pixel_formats(m_videoOutput));
|
||||
QVector<QVideoFrame::PixelFormat> 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<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);
|
||||
|
||||
@@ -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<NSNumber *>(obj);
|
||||
if ([nsNum unsignedIntValue] == conv) {
|
||||
avfFormat = conv;
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return found;
|
||||
}
|
||||
|
||||
void AVFCameraViewfinderSettingsControl2::applySettings()
|
||||
|
||||
Reference in New Issue
Block a user