GStreamer: port to 1.0.
0.10 is still used by default. To enable GStreamer 1.0, pass GST_VERSION=1.0 to qmake for qtmultimedia.pro. Contributions from: Andrew den Exter <andrew.den.exter@qinetic.com.au> Ilya Smelykh <ilya@videoexpertsgroup.com> Jim Hodapp <jim.hodapp@canonical.com> Sergio Schvezov <sergio.schvezov@canonical.com> Change-Id: I72a46d1170a8794a149bdb5e20767afcc5b7587c Reviewed-by: Andrew den Exter <andrew.den.exter@qinetic.com.au>
This commit is contained in:
committed by
Andrew den Exter
parent
7e3d69668e
commit
108dda7a90
@@ -41,8 +41,13 @@
|
||||
#include <private/qmediapluginloader_p.h>
|
||||
#include "qgstvideobuffer_p.h"
|
||||
|
||||
#include "qgstutils_p.h"
|
||||
#include "qvideosurfacegstsink_p.h"
|
||||
|
||||
#if GST_VERSION_MAJOR >=1
|
||||
#include <gst/video/video.h>
|
||||
#endif
|
||||
|
||||
//#define DEBUG_VIDEO_SURFACE_SINK
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@@ -62,10 +67,12 @@ QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(
|
||||
if (m_surface) {
|
||||
foreach (QObject *instance, bufferPoolLoader()->instances(QGstBufferPoolPluginKey)) {
|
||||
QGstBufferPoolInterface* plugin = qobject_cast<QGstBufferPoolInterface*>(instance);
|
||||
|
||||
if (plugin) {
|
||||
m_pools.append(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
updateSupportedFormats();
|
||||
connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(updateSupportedFormats()));
|
||||
}
|
||||
@@ -191,13 +198,15 @@ GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
|
||||
m_format.frameSize(),
|
||||
m_format.pixelFormat());
|
||||
|
||||
QVideoSurfaceGstSink::setFrameTimeStamps(&m_frame, buffer);
|
||||
QGstUtils::setFrameTimeStamps(&m_frame, buffer);
|
||||
|
||||
m_renderReturn = GST_FLOW_OK;
|
||||
|
||||
if (QThread::currentThread() == thread()) {
|
||||
if (!m_surface.isNull())
|
||||
m_surface->present(m_frame);
|
||||
else
|
||||
qWarning() << "m_surface.isNull().";
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this, "queuedRender", Qt::QueuedConnection);
|
||||
m_renderCondition.wait(&m_mutex, 300);
|
||||
@@ -283,90 +292,6 @@ void QVideoSurfaceGstDelegate::updateSupportedFormats()
|
||||
}
|
||||
}
|
||||
|
||||
struct YuvFormat
|
||||
{
|
||||
QVideoFrame::PixelFormat pixelFormat;
|
||||
guint32 fourcc;
|
||||
int bitsPerPixel;
|
||||
};
|
||||
|
||||
static const YuvFormat qt_yuvColorLookup[] =
|
||||
{
|
||||
{ QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 },
|
||||
{ QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 },
|
||||
{ QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 16 },
|
||||
{ QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 16 },
|
||||
{ QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 },
|
||||
{ QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 },
|
||||
{ QVideoFrame::Format_AYUV444, GST_MAKE_FOURCC('A','Y','U','V'), 32 }
|
||||
};
|
||||
|
||||
static int indexOfYuvColor(QVideoFrame::PixelFormat format)
|
||||
{
|
||||
const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (qt_yuvColorLookup[i].pixelFormat == format)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int indexOfYuvColor(guint32 fourcc)
|
||||
{
|
||||
const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (qt_yuvColorLookup[i].fourcc == fourcc)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct RgbFormat
|
||||
{
|
||||
QVideoFrame::PixelFormat pixelFormat;
|
||||
int bitsPerPixel;
|
||||
int depth;
|
||||
int endianness;
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
int alpha;
|
||||
};
|
||||
|
||||
static const RgbFormat qt_rgbColorLookup[] =
|
||||
{
|
||||
{ QVideoFrame::Format_RGB32 , 32, 24, 4321, 0x0000FF00, 0x00FF0000, int(0xFF000000), 0x00000000 },
|
||||
{ QVideoFrame::Format_RGB32 , 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 },
|
||||
{ QVideoFrame::Format_BGR32 , 32, 24, 4321, int(0xFF000000), 0x00FF0000, 0x0000FF00, 0x00000000 },
|
||||
{ QVideoFrame::Format_BGR32 , 32, 24, 1234, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 },
|
||||
{ QVideoFrame::Format_ARGB32, 32, 24, 4321, 0x0000FF00, 0x00FF0000, int(0xFF000000), 0x000000FF },
|
||||
{ QVideoFrame::Format_ARGB32, 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, int(0xFF000000) },
|
||||
{ QVideoFrame::Format_RGB24 , 24, 24, 4321, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 },
|
||||
{ QVideoFrame::Format_BGR24 , 24, 24, 4321, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 },
|
||||
{ QVideoFrame::Format_RGB565, 16, 16, 1234, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }
|
||||
};
|
||||
|
||||
static int indexOfRgbColor(
|
||||
int bits, int depth, int endianness, int red, int green, int blue, int alpha)
|
||||
{
|
||||
const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (qt_rgbColorLookup[i].bitsPerPixel == bits
|
||||
&& qt_rgbColorLookup[i].depth == depth
|
||||
&& qt_rgbColorLookup[i].endianness == endianness
|
||||
&& qt_rgbColorLookup[i].red == red
|
||||
&& qt_rgbColorLookup[i].green == green
|
||||
&& qt_rgbColorLookup[i].blue == blue
|
||||
&& qt_rgbColorLookup[i].alpha == alpha) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static GstVideoSinkClass *sink_parent_class;
|
||||
|
||||
#define VO_SINK(s) QVideoSurfaceGstSink *sink(reinterpret_cast<QVideoSurfaceGstSink *>(s))
|
||||
@@ -494,8 +419,6 @@ GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)
|
||||
{
|
||||
VO_SINK(base);
|
||||
|
||||
GstCaps *caps = gst_caps_new_empty();
|
||||
|
||||
// Find the supported pixel formats
|
||||
// with buffer pool specific formats listed first
|
||||
QList<QVideoFrame::PixelFormat> supportedFormats;
|
||||
@@ -503,6 +426,7 @@ GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)
|
||||
QList<QVideoFrame::PixelFormat> poolHandleFormats;
|
||||
sink->delegate->poolMutex()->lock();
|
||||
QGstBufferPoolInterface *pool = sink->delegate->pool();
|
||||
|
||||
if (pool)
|
||||
poolHandleFormats = sink->delegate->supportedPixelFormats(pool->handleType());
|
||||
sink->delegate->poolMutex()->unlock();
|
||||
@@ -513,47 +437,7 @@ GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)
|
||||
supportedFormats.append(format);
|
||||
}
|
||||
|
||||
foreach (QVideoFrame::PixelFormat format, supportedFormats) {
|
||||
int index = indexOfYuvColor(format);
|
||||
|
||||
if (index != -1) {
|
||||
gst_caps_append_structure(caps, gst_structure_new(
|
||||
"video/x-raw-yuv",
|
||||
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
|
||||
"width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
|
||||
"height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
|
||||
"format" , GST_TYPE_FOURCC, qt_yuvColorLookup[index].fourcc,
|
||||
NULL));
|
||||
continue;
|
||||
}
|
||||
|
||||
const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (qt_rgbColorLookup[i].pixelFormat == format) {
|
||||
GstStructure *structure = gst_structure_new(
|
||||
"video/x-raw-rgb",
|
||||
"framerate" , GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
|
||||
"width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
|
||||
"height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
|
||||
"bpp" , G_TYPE_INT, qt_rgbColorLookup[i].bitsPerPixel,
|
||||
"depth" , G_TYPE_INT, qt_rgbColorLookup[i].depth,
|
||||
"endianness", G_TYPE_INT, qt_rgbColorLookup[i].endianness,
|
||||
"red_mask" , G_TYPE_INT, qt_rgbColorLookup[i].red,
|
||||
"green_mask", G_TYPE_INT, qt_rgbColorLookup[i].green,
|
||||
"blue_mask" , G_TYPE_INT, qt_rgbColorLookup[i].blue,
|
||||
NULL);
|
||||
|
||||
if (qt_rgbColorLookup[i].alpha != 0) {
|
||||
gst_structure_set(
|
||||
structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, NULL);
|
||||
}
|
||||
gst_caps_append_structure(caps, structure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return caps;
|
||||
return QGstUtils::capsForFormats(supportedFormats);
|
||||
}
|
||||
|
||||
gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps)
|
||||
@@ -575,7 +459,7 @@ gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps)
|
||||
QAbstractVideoBuffer::HandleType handleType =
|
||||
pool ? pool->handleType() : QAbstractVideoBuffer::NoHandle;
|
||||
|
||||
QVideoSurfaceFormat format = formatForCaps(caps, &bytesPerLine, handleType);
|
||||
QVideoSurfaceFormat format = QGstUtils::formatForCaps(caps, &bytesPerLine, handleType);
|
||||
|
||||
if (sink->delegate->isActive()) {
|
||||
QVideoSurfaceFormat surfaceFormst = sink->delegate->surfaceFormat();
|
||||
@@ -592,7 +476,7 @@ gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps)
|
||||
sink->lastRequestedCaps = 0;
|
||||
|
||||
#ifdef DEBUG_VIDEO_SURFACE_SINK
|
||||
qDebug() << "Staring video surface, format:";
|
||||
qDebug() << "Starting video surface, format:";
|
||||
qDebug() << format;
|
||||
qDebug() << "bytesPerLine:" << bytesPerLine;
|
||||
#endif
|
||||
@@ -606,87 +490,6 @@ gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
QVideoSurfaceFormat QVideoSurfaceGstSink::formatForCaps(GstCaps *caps, int *bytesPerLine, QAbstractVideoBuffer::HandleType handleType)
|
||||
{
|
||||
const GstStructure *structure = gst_caps_get_structure(caps, 0);
|
||||
|
||||
QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid;
|
||||
int bitsPerPixel = 0;
|
||||
|
||||
QSize size;
|
||||
gst_structure_get_int(structure, "width", &size.rwidth());
|
||||
gst_structure_get_int(structure, "height", &size.rheight());
|
||||
|
||||
if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) {
|
||||
guint32 fourcc = 0;
|
||||
gst_structure_get_fourcc(structure, "format", &fourcc);
|
||||
|
||||
int index = indexOfYuvColor(fourcc);
|
||||
if (index != -1) {
|
||||
pixelFormat = qt_yuvColorLookup[index].pixelFormat;
|
||||
bitsPerPixel = qt_yuvColorLookup[index].bitsPerPixel;
|
||||
}
|
||||
} else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) {
|
||||
int depth = 0;
|
||||
int endianness = 0;
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int alpha = 0;
|
||||
|
||||
gst_structure_get_int(structure, "bpp", &bitsPerPixel);
|
||||
gst_structure_get_int(structure, "depth", &depth);
|
||||
gst_structure_get_int(structure, "endianness", &endianness);
|
||||
gst_structure_get_int(structure, "red_mask", &red);
|
||||
gst_structure_get_int(structure, "green_mask", &green);
|
||||
gst_structure_get_int(structure, "blue_mask", &blue);
|
||||
gst_structure_get_int(structure, "alpha_mask", &alpha);
|
||||
|
||||
int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha);
|
||||
|
||||
if (index != -1)
|
||||
pixelFormat = qt_rgbColorLookup[index].pixelFormat;
|
||||
}
|
||||
|
||||
if (pixelFormat != QVideoFrame::Format_Invalid) {
|
||||
QVideoSurfaceFormat format(size, pixelFormat, handleType);
|
||||
|
||||
QPair<int, int> rate;
|
||||
gst_structure_get_fraction(structure, "framerate", &rate.first, &rate.second);
|
||||
|
||||
if (rate.second)
|
||||
format.setFrameRate(qreal(rate.first)/rate.second);
|
||||
|
||||
gint aspectNum = 0;
|
||||
gint aspectDenum = 0;
|
||||
if (gst_structure_get_fraction(
|
||||
structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) {
|
||||
if (aspectDenum > 0)
|
||||
format.setPixelAspectRatio(aspectNum, aspectDenum);
|
||||
}
|
||||
|
||||
if (bytesPerLine)
|
||||
*bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3;
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
return QVideoSurfaceFormat();
|
||||
}
|
||||
|
||||
void QVideoSurfaceGstSink::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer)
|
||||
{
|
||||
// GStreamer uses nanoseconds, Qt uses microseconds
|
||||
qint64 startTime = GST_BUFFER_TIMESTAMP(buffer);
|
||||
if (startTime >= 0) {
|
||||
frame->setStartTime(startTime/G_GINT64_CONSTANT (1000));
|
||||
|
||||
qint64 duration = GST_BUFFER_DURATION(buffer);
|
||||
if (duration >= 0)
|
||||
frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000));
|
||||
}
|
||||
}
|
||||
|
||||
GstFlowReturn QVideoSurfaceGstSink::buffer_alloc(
|
||||
GstBaseSink *base, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer)
|
||||
{
|
||||
@@ -731,7 +534,7 @@ GstFlowReturn QVideoSurfaceGstSink::buffer_alloc(
|
||||
|
||||
if (sink->delegate->isActive()) {
|
||||
//if format was changed, restart the surface
|
||||
QVideoSurfaceFormat format = formatForCaps(intersection);
|
||||
QVideoSurfaceFormat format = QGstUtils::formatForCaps(intersection);
|
||||
QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat();
|
||||
|
||||
if (format.pixelFormat() != surfaceFormat.pixelFormat() ||
|
||||
@@ -749,7 +552,7 @@ GstFlowReturn QVideoSurfaceGstSink::buffer_alloc(
|
||||
QAbstractVideoBuffer::HandleType handleType =
|
||||
pool ? pool->handleType() : QAbstractVideoBuffer::NoHandle;
|
||||
|
||||
QVideoSurfaceFormat format = formatForCaps(intersection, &bytesPerLine, handleType);
|
||||
QVideoSurfaceFormat format = QGstUtils::formatForCaps(intersection, &bytesPerLine, handleType);
|
||||
|
||||
if (!sink->delegate->start(format, bytesPerLine)) {
|
||||
qWarning() << "failed to start video surface";
|
||||
@@ -763,7 +566,7 @@ GstFlowReturn QVideoSurfaceGstSink::buffer_alloc(
|
||||
QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat();
|
||||
|
||||
if (!pool->isFormatSupported(surfaceFormat)) {
|
||||
//qDebug() << "sink doesn't support native pool format, skip custom buffers allocation";
|
||||
qDebug() << "sink doesn't support native pool format, skip custom buffers allocation";
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
@@ -787,7 +590,6 @@ GstFlowReturn QVideoSurfaceGstSink::buffer_alloc(
|
||||
gboolean QVideoSurfaceGstSink::start(GstBaseSink *base)
|
||||
{
|
||||
Q_UNUSED(base);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user