pleora: add support for sending/receiving KLV metadata as chunk data

This attemps to partially implement MISB ST1608.1, "Transport of Motion
Imagery and Metadata over GigE Vision". This relies on GstKLVMeta, which
is currently a merge request 124 for gst-plugins-base. For now we
include it here. Currently all KLVMeta is packed into one chunk, no
special handling of timestamps is done. Testing has only been done
between pleorasink and pleorasrc, no other MISB-compliant stream.
This commit is contained in:
Joshua M. Doe 2019-11-21 11:47:42 -05:00
parent f6509a1b4d
commit a92281c965
9 changed files with 674 additions and 10 deletions

View File

@ -1,10 +1,12 @@
add_definitions(-D_XKEYCHECK_H)
set (SOURCES
klv.c
gstpleora.cpp
gstpleorasrc.cpp)
set (HEADERS
klv.h
gstpleorasrc.h)
if (Pleora_VERSION_MAJOR GREATER 5)

View File

@ -75,7 +75,8 @@ enum
PROP_VERSION,
PROP_INFO,
PROP_SERIAL,
PROP_MAC
PROP_MAC,
PROP_OUTPUT_KLV
};
#define DEFAULT_PROP_NUM_INTERNAL_BUFFERS 3
@ -86,6 +87,7 @@ enum
#define DEFAULT_PROP_INFO "Pleora eBUS GStreamer Sink"
#define DEFAULT_PROP_SERIAL "0001"
#define DEFAULT_PROP_MAC ""
#define DEFAULT_PROP_OUTPUT_KLV TRUE
/* pad templates */
@ -184,6 +186,12 @@ gst_pleorasink_class_init (GstPleoraSinkClass * klass)
DEFAULT_PROP_MAC,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
g_object_class_install_property (gobject_class, PROP_OUTPUT_KLV,
g_param_spec_boolean ("output-klv", "Output KLV",
"Whether to output KLV as chunk data according to MISB ST1608",
DEFAULT_PROP_OUTPUT_KLV,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
}
static void
@ -198,6 +206,7 @@ gst_pleorasink_init (GstPleoraSink * sink)
sink->info = g_strdup (DEFAULT_PROP_INFO);
sink->serial = g_strdup (DEFAULT_PROP_SERIAL);
sink->mac = g_strdup (DEFAULT_PROP_MAC);
sink->output_klv = DEFAULT_PROP_OUTPUT_KLV;
sink->camera_connected = FALSE;
@ -253,6 +262,10 @@ gst_pleorasink_set_property (GObject * object, guint property_id,
g_free (sink->mac);
sink->mac = g_strdup (g_value_get_string (value));
break;
case PROP_OUTPUT_KLV:
sink->output_klv = g_value_get_boolean (value);
sink->source->SetKlvEnabled (sink->output_klv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -293,6 +306,9 @@ gst_pleorasink_get_property (GObject * object, guint property_id,
case PROP_MAC:
g_value_set_string (value, sink->mac);
break;
case PROP_OUTPUT_KLV:
g_value_set_boolean (value, sink->output_klv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;

View File

@ -52,6 +52,7 @@ struct _GstPleoraSink
gchar *info;
gchar *serial;
gchar *mac;
gboolean output_klv;
gboolean camera_connected;
GstVideoInfo vinfo;

View File

@ -48,6 +48,9 @@
#include <PvSystem.h>
#include <PvVersion.h>
/* FIXME: include this for now until gst-plugins-base MR124 is accepted */
#include "klv.h"
GST_DEBUG_CATEGORY_STATIC (gst_pleorasrc_debug);
#define GST_CAT_DEFAULT gst_pleorasrc_debug
@ -83,7 +86,8 @@ enum
PROP_RECEIVER_ONLY,
PROP_PACKET_SIZE,
PROP_CONFIG_FILE,
PROP_CONFIG_FILE_CONNECT
PROP_CONFIG_FILE_CONNECT,
PROP_OUTPUT_KLV
};
#define DEFAULT_PROP_DEVICE ""
@ -97,6 +101,7 @@ enum
#define DEFAULT_PROP_PACKET_SIZE 0
#define DEFAULT_PROP_CONFIG_FILE ""
#define DEFAULT_PROP_CONFIG_FILE_CONNECT TRUE
#define DEFAULT_PROP_OUTPUT_KLV TRUE
#define VIDEO_CAPS_MAKE_BAYER8(format) \
"video/x-bayer, " \
@ -221,6 +226,12 @@ gst_pleorasrc_class_init (GstPleoraSrcClass * klass)
"connects using properties and then restores configuration",
DEFAULT_PROP_CONFIG_FILE_CONNECT,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
g_object_class_install_property (gobject_class, PROP_OUTPUT_KLV,
g_param_spec_boolean ("output-klv", "Output KLV",
"Whether to output MISB ST1608 KLV as buffer meta",
DEFAULT_PROP_OUTPUT_KLV,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
}
static void
@ -263,6 +274,7 @@ gst_pleorasrc_init (GstPleoraSrc * src)
src->receiver_only = DEFAULT_PROP_RECEIVER_ONLY;
src->config_file = g_strdup (DEFAULT_PROP_CONFIG_FILE);
src->config_file_connect = DEFAULT_PROP_CONFIG_FILE_CONNECT;
src->output_klv = DEFAULT_PROP_OUTPUT_KLV;
src->stop_requested = FALSE;
src->caps = NULL;
@ -317,6 +329,9 @@ gst_pleorasrc_set_property (GObject * object, guint property_id,
case PROP_CONFIG_FILE_CONNECT:
src->config_file_connect = g_value_get_boolean (value);
break;
case PROP_OUTPUT_KLV:
src->output_klv= g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -366,6 +381,9 @@ gst_pleorasrc_get_property (GObject * object, guint property_id,
case PROP_CONFIG_FILE_CONNECT:
g_value_set_boolean (value, src->config_file_connect);
break;
case PROP_OUTPUT_KLV:
g_value_set_boolean (value, src->output_klv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -1587,8 +1605,8 @@ gst_pleorasrc_create (GstPushSrc * psrc, GstBuffer ** buf)
return GST_FLOW_ERROR;
}
/* wrap or copy image data to buffer */
pvimage = pvbuffer->GetImage ();
gpointer data = pvimage->GetDataPointer ();
if (src->pleora_stride == src->gst_stride) {
VideoFrame *vf = g_new0 (VideoFrame, 1);
@ -1621,13 +1639,70 @@ gst_pleorasrc_create (GstPushSrc * psrc, GstBuffer ** buf)
memcpy (d + i * src->gst_stride, s + i * src->pleora_stride,
src->pleora_stride);
gst_buffer_unmap (*buf, &minfo);
src->pipeline->ReleaseBuffer (pvbuffer);
}
/* TODO: use PvBuffer timestamps */
clock = gst_element_get_clock (GST_ELEMENT (src));
clock_time = gst_clock_get_time (clock);
gst_object_unref (clock);
if (src->output_klv && pvbuffer->HasChunks ()) {
guint32 num_chunks;
num_chunks = pvbuffer->GetChunkCount ();
GST_LOG_OBJECT (src, "Buffer has %d chunk(s) with layout ID %d", num_chunks,
pvbuffer->GetChunkLayoutID ());
/* TODO: spec says "Image must be the first chunk", but that doesn't seem
to be true, so check every chunk */
for (guint i = 0; i < num_chunks; ++i) {
guint32 chunk_id, chunk_size;
const guint8 *chunk_data;
pvRes = pvbuffer->GetChunkIDByIndex (i, chunk_id);
if (!pvRes.IsOK ()) {
GST_WARNING_OBJECT (src, "Failed to get chunk ID for index %d: '%s'", i,
pvRes.GetDescription ().GetAscii ());
continue;
}
chunk_size = pvbuffer->GetChunkSizeByIndex (i);
if (chunk_size == 0) {
GST_WARNING_OBJECT (src, "Chunk size reported as zero for index %d", i);
continue;
}
chunk_data = pvbuffer->GetChunkRawDataByIndex (i);
if (chunk_data == NULL) {
GST_WARNING_OBJECT (src, "Chunk data is NULL for index %d", i);
continue;
}
GST_LOG_OBJECT (src,
"Found chunk at index %d with ID %04x of size %d bytes", i, chunk_id,
chunk_size);
GST_MEMDUMP_OBJECT (src, "Chunk data", chunk_data, chunk_size);
if (chunk_size < 17) {
GST_LOG_OBJECT (src, "Chunk data is too small to contain KLV");
continue;
}
if (GST_READ_UINT32_BE (chunk_data) != 0x060E2B34) {
GST_LOG_OBJECT (src, "Chunk doesn't contain KLV data");
continue;
}
GST_LOG_OBJECT (src, "Adding KLV meta to buffer");
/* TODO: do we need to exclude padding that may be present? */
gst_buffer_add_klv_meta_from_data (*buf, chunk_data, chunk_size);
}
}
if (src->pleora_stride != src->gst_stride) {
src->pipeline->ReleaseBuffer (pvbuffer);
pvbuffer = NULL;
}
/* check for dropped frames and disrupted signal */
//dropped_frames = (circ_handle.FrameCount - src->last_frame_count) - 1;
//if (dropped_frames > 0) {

View File

@ -60,6 +60,7 @@ struct _GstPleoraSrc
gint packet_size;
gchar *config_file;
gboolean config_file_connect;
gboolean output_klv;
guint32 last_frame_count;
guint32 total_dropped_frames;

330
sys/pleora/klv.c Normal file
View File

@ -0,0 +1,330 @@
/* GStreamer KLV Metadata Support Library
* Copyright (C) 2016-2019 Tim-Philipp Müller <tim@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:gsttagklv
* @short_description: KLV metadata support
* @title: KLV metadata support
*
* <refsect2>
* <para>
* Utility functions around KLV metadata support in GStreamer.
* </para>
* <para>
* See ITU Recommendation BT.1563-1 or SMPTE 336M for the KLV standard;
* see MISB EG 0902 (MISB Minimum Metadata Set) and other MISB standards
* and recommended practices for examples of KLV metadata local data sets
* for a variety of use cases (timestamps, GPS coordinates, speed, etc.).
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/tag/tag.h>
#include "klv.h"
/* We hide the implementation details, so that we have the option to implement
* different/more efficient storage in future (unfortunately we can't put the
* data inline with the meta allocation though since it's registered as fixed
* size, although that could probably be fixed in a backwards compatible way).
* GBytes means effectively two allocations, one for the GBytes, one for the
* data. Plus one for the KLV meta struct.
*
* For now we also assume that KLV data is always self-contained and one single
* chunk of data, but in future we may have use cases where we might want to
* relax that requirement. */
typedef struct
{
GstKLVMeta klv_meta;
GBytes *bytes;
} GstKLVMetaImpl;
GType
gst_klv_meta_api_get_type (void)
{
static volatile GType type;
static const gchar *tags[] = { NULL };
if (g_once_init_enter (&type)) {
GType _type = gst_meta_api_type_register ("GstKLVMetaAPI", tags);
g_once_init_leave (&type, _type);
}
return type;
}
static gboolean
gst_klv_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
{
GstKLVMetaImpl *impl = (GstKLVMetaImpl *) meta;
impl->bytes = NULL;
return TRUE;
}
static void
gst_klv_meta_clear (GstMeta * meta, GstBuffer * buffer)
{
GstKLVMetaImpl *impl = (GstKLVMetaImpl *) meta;
if (impl->bytes != NULL)
g_bytes_unref (impl->bytes);
}
static gboolean
gst_klv_meta_transform (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, GQuark type, gpointer data)
{
GstKLVMetaImpl *smeta;
GstKLVMeta *dmeta;
smeta = (GstKLVMetaImpl *) meta;
if (GST_META_TRANSFORM_IS_COPY (type)) {
dmeta = gst_buffer_add_klv_meta_from_bytes (dest, smeta->bytes);
if (!dmeta)
return FALSE;
} else {
return FALSE;
}
return TRUE;
}
const GstMetaInfo *
gst_klv_meta_get_info (void)
{
static const GstMetaInfo *klv_meta_info = NULL;
if (g_once_init_enter ((GstMetaInfo **) & klv_meta_info)) {
const GstMetaInfo *meta =
gst_meta_register (GST_KLV_META_API_TYPE, "GstKLVMeta",
sizeof (GstKLVMetaImpl), gst_klv_meta_init, gst_klv_meta_clear,
gst_klv_meta_transform);
g_once_init_leave ((GstMetaInfo **) & klv_meta_info, (GstMetaInfo *) meta);
}
return klv_meta_info;
}
/* Add KLV meta data to a buffer */
static GstKLVMeta *
gst_buffer_add_klv_meta_internal (GstBuffer * buffer, GBytes * bytes)
{
GstKLVMetaImpl *impl;
GstKLVMeta *meta;
gconstpointer data;
gsize size;
/* KLV coding shall use and only use a fixed 16-byte SMPTE-administered
* Universal Label, according to SMPTE 298M as Key (Rec. ITU R-BT.1653-1) */
data = g_bytes_get_data (bytes, &size);
if (size < 16 || GST_READ_UINT32_BE (data) != 0x060E2B34) {
GST_ERROR ("Trying to attach a invalid KLV meta data to buffer");
g_bytes_unref (bytes);
return NULL;
}
meta = (GstKLVMeta *) gst_buffer_add_meta (buffer, GST_KLV_META_INFO, NULL);
GST_TRACE ("Adding %u bytes of KLV data to buffer %p", (guint) size, buffer);
impl = (GstKLVMetaImpl *) meta;
impl->bytes = bytes;
return meta;
}
/**
* gst_buffer_add_klv_meta_from_data: (skip)
* @buffer: a #GstBuffer
* @data: (array length=size) (transfer none): KLV data with 16-byte KLV
* Universal Label prefix
* @size: size of @data in bytes
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Does not take ownership of @data.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_from_data (GstBuffer * buffer, const guint8 * data,
gsize size)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (data != NULL && size > 16, NULL);
return gst_buffer_add_klv_meta_internal (buffer, g_bytes_new (data, size));
}
/**
* gst_buffer_add_klv_meta_take_data: (skip)
* @buffer: a #GstBuffer
* @data: (array length=size) (transfer full): KLV data with 16-byte KLV
* Universal Label prefix
* @size: size of @data in bytes
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Take ownership of @data.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_take_data (GstBuffer * buffer, guint8 * data,
gsize size)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (data != NULL && size > 16, NULL);
return gst_buffer_add_klv_meta_internal (buffer, g_bytes_new_take (data,
size));
}
/**
* gst_buffer_add_klv_meta_from_bytes:
* @buffer: a #GstBuffer
* @bytes: (transfer none): KLV data with 16-byte KLV Universal Label prefix
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Does not take ownership of @bytes, you will need to unref @bytes.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_from_bytes (GstBuffer * buffer, GBytes * bytes)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
return gst_buffer_add_klv_meta_internal (buffer, g_bytes_ref (bytes));
}
/**
* gst_buffer_add_klv_meta_take_bytes:
* @buffer: a #GstBuffer
* @bytes: (transfer full): KLV data with 16-byte KLV Universal Label prefix
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Takes ownership of @bytes.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_take_bytes (GstBuffer * buffer, GBytes * bytes)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
return gst_buffer_add_klv_meta_internal (buffer, bytes);
}
/* Get KLV meta data from a buffer */
/**
* gst_buffer_get_klv_meta:
* @buffer: a #GstBuffer
*
* Returns: a #GstKLVMeta on the buffer, or %NULL if the buffer has none.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_get_klv_meta (GstBuffer * buffer)
{
return (GstKLVMeta *) gst_buffer_get_meta (buffer, GST_KLV_META_API_TYPE);
}
/**
* gst_klv_meta_get_data: (skip)
* @klv_meta: a #GstKLVMeta
* @size: the size of the returned data in bytes.
*
* Returns: (transfer none): the KLV data
*
* Since: 1.16
*/
const guint8 *
gst_klv_meta_get_data (GstKLVMeta * klv_meta, gsize * size)
{
GstKLVMetaImpl *impl;
g_return_val_if_fail (klv_meta != NULL, NULL);
g_return_val_if_fail (size != NULL, NULL);
impl = (GstKLVMetaImpl *) klv_meta;
return g_bytes_get_data (impl->bytes, size);
}
/**
* gst_klv_meta_get_bytes:
* @klv_meta: a #GstKLVMeta
*
* Returns: (transfer none): the KLV data as a #GBytes
*
* Since: 1.16
*/
GBytes *
gst_klv_meta_get_bytes (GstKLVMeta * klv_meta)
{
GstKLVMetaImpl *impl;
g_return_val_if_fail (klv_meta != NULL, NULL);
impl = (GstKLVMetaImpl *) klv_meta;
return impl->bytes;
}
/* Boxed type, so bindings can use the API */
static gpointer
gst_klv_meta_copy_boxed (gpointer boxed)
{
GstKLVMetaImpl *impl = boxed;
GstKLVMetaImpl *copy;
copy = g_new (GstKLVMetaImpl, 1);
copy->bytes = impl->bytes ? g_bytes_ref (impl->bytes) : NULL;
return copy;
}
static void
gst_klv_meta_free_boxed (gpointer boxed)
{
GstKLVMetaImpl *impl = boxed;
if (impl->bytes)
g_bytes_unref (impl->bytes);
g_free (impl);
}
G_DEFINE_BOXED_TYPE (GstKLVMeta, gst_klv_meta, gst_klv_meta_copy_boxed,
gst_klv_meta_free_boxed);

82
sys/pleora/klv.h Normal file
View File

@ -0,0 +1,82 @@
/* GStreamer KLV Metadata Support Library
* Copyright (C) 2016-2019 Tim-Philipp Müller <tim@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_TAG_KLV_H__
#define __GST_TAG_KLV_H__
#include <gst/gst.h>
// FIXME: include this for now until gst-plugins-base MR124 is accepted
#define GST_TAG_API
G_BEGIN_DECLS
/**
* GstKLVMeta:
*
* An opaque #GstMeta structure representing a self-contained KLV metadata
* block that can be attached to buffers.
*
* Since: 1.16
*/
typedef struct {
/*< private >*/
GstMeta meta;
} GstKLVMeta;
GST_TAG_API
GType gst_klv_meta_get_type (void);
#define GST_KLV_META_API_TYPE (gst_klv_meta_api_get_type())
#define GST_KLV_META_INFO (gst_klv_meta_get_info())
GST_TAG_API
GType gst_klv_meta_api_get_type (void);
GST_TAG_API
const GstMetaInfo * gst_klv_meta_get_info (void);
/* Add KLV meta data to a buffer */
GST_TAG_API
GstKLVMeta * gst_buffer_add_klv_meta_from_data (GstBuffer * buffer, const guint8 * data, gsize size);
GST_TAG_API
GstKLVMeta * gst_buffer_add_klv_meta_take_data (GstBuffer * buffer, guint8 * data, gsize size);
GST_TAG_API
GstKLVMeta * gst_buffer_add_klv_meta_from_bytes (GstBuffer * buffer, GBytes * bytes);
GST_TAG_API
GstKLVMeta * gst_buffer_add_klv_meta_take_bytes (GstBuffer * buffer, GBytes * bytes);
/* Get KLV meta data from a buffer */
GST_TAG_API
GstKLVMeta * gst_buffer_get_klv_meta (GstBuffer * buffer);
GST_TAG_API
const guint8 * gst_klv_meta_get_data (GstKLVMeta * klv_meta, gsize * size);
GST_TAG_API
GBytes * gst_klv_meta_get_bytes (GstKLVMeta * klv_meta);
G_END_DECLS
#endif /* __GST_TAG_KLV_H__ */

View File

@ -18,13 +18,19 @@
*/
#include "streamingchannelsource.h"
#include "klv.h"
/* setup debug */
GST_DEBUG_CATEGORY_EXTERN (pleorasink_debug);
#define GST_CAT_DEFAULT pleorasink_debug
/* these seem to be arbitrary */
#define CHUNKLAYOUTID 0xABCD
#define KLV_CHUNKID 0xFEDC
GstStreamingChannelSource::GstStreamingChannelSource ()
: mAcquisitionBuffer (NULL), mBufferCount (0), mBufferValid (FALSE)
: mAcquisitionBuffer (NULL), mBufferCount (0), mBufferValid (FALSE),
mChunkModeActive(TRUE), mChunkKlvEnabled(TRUE), mKlvChunkSize(0)
{
}
@ -58,6 +64,67 @@ PvResult GstStreamingChannelSource::GetSupportedPixelType (int aIndex,
return PvResult::Code::OK;
}
PvResult GstStreamingChannelSource::GetSupportedChunk (int aIndex, uint32_t &aID, PvString &aName) const
{
switch (aIndex) {
case 0:
aID = KLV_CHUNKID;
aName = "KLV";
return PvResult::Code::OK;
default:
break;
}
return PvResult::Code::INVALID_PARAMETER;
}
bool GstStreamingChannelSource::GetChunkEnable (uint32_t aChunkID) const
{
switch (aChunkID) {
case KLV_CHUNKID:
return mChunkKlvEnabled;
default:
break;
}
return false;
}
PvResult GstStreamingChannelSource::SetChunkEnable (uint32_t aChunkID, bool aEnabled)
{
switch (aChunkID) {
case KLV_CHUNKID:
mChunkKlvEnabled = aEnabled;
mSink->output_klv = mChunkKlvEnabled;
return PvResult::Code::OK;
default:
break;
}
return PvResult::Code::INVALID_PARAMETER;
}
uint32_t GstStreamingChannelSource::GetRequiredChunkSize() const
{
if (mChunkModeActive && mChunkKlvEnabled) {
/* chunk data must be multiple of 4 bytes, and 16 bytes extra seem
to be needed for chunk ID and length */
return GST_ROUND_UP_4 (mKlvChunkSize) + 16;
} else {
return 0;
}
}
void GstStreamingChannelSource::SetKlvEnabled (gboolean enable)
{
SetChunkEnable (KLV_CHUNKID, enable);
}
gboolean GstStreamingChannelSource::GetKlvEnabled()
{
return GetChunkEnable (KLV_CHUNKID);
}
PvBuffer * GstStreamingChannelSource::AllocBuffer ()
{
if (mBufferCount < mSink->num_internal_buffers) {
@ -154,12 +221,13 @@ GstStreamingChannelSource::SetCaps (GstCaps * caps)
void
GstStreamingChannelSource::ResizeBufferIfNeeded (PvBuffer * aBuffer)
{
uint32_t lRequiredChunkSize = 0;
uint32_t lRequiredChunkSize = GetRequiredChunkSize();
PvImage *lImage = aBuffer->GetImage ();
if ((lImage->GetWidth () != mWidth) ||
(lImage->GetHeight () != mHeight) ||
(lImage->GetPixelType () != mPixelType) ||
(lImage->GetMaximumChunkLength () != lRequiredChunkSize)) {
GST_LOG_OBJECT (mSink, "Width=%d, Height=%d, PixelType=%d, and/or ChunkLength=%d changed, reallocating buffer", mWidth, mHeight, mPixelType, lRequiredChunkSize);
lImage->Alloc (mWidth, mHeight, mPixelType, 0, 0, lRequiredChunkSize);
}
}
@ -167,7 +235,9 @@ GstStreamingChannelSource::ResizeBufferIfNeeded (PvBuffer * aBuffer)
void
GstStreamingChannelSource::SetBuffer (GstBuffer * buf)
{
GST_LOG ("SetBuffer");
GByteArray * klv_byte_array = NULL;
GST_LOG_OBJECT (mSink, "SetBuffer");
g_mutex_lock (&mSink->mutex);
@ -184,15 +254,25 @@ GstStreamingChannelSource::SetBuffer (GstBuffer * buf)
return;
}
if (mChunkKlvEnabled) {
klv_byte_array = GetKlvByteArray (buf);
if (klv_byte_array) {
mKlvChunkSize = klv_byte_array->len;
} else {
mKlvChunkSize = 0;
}
}
ResizeBufferIfNeeded (mAcquisitionBuffer);
/* TODO: avoid memcpy (when strides align) by attaching to PvBuffer */
GstMapInfo minfo;
gst_buffer_map (buf, &minfo, GST_MAP_READ);
ResizeBufferIfNeeded (mAcquisitionBuffer);
guint8 *dst = mAcquisitionBuffer->GetDataPointer ();
if (!dst) {
GST_ERROR ("Have buffer to fill, but data pointer is invalid");
GST_ERROR_OBJECT (mSink, "Have buffer to fill, but data pointer is invalid");
g_mutex_unlock (&mSink->mutex);
return;
}
@ -202,8 +282,68 @@ GstStreamingChannelSource::SetBuffer (GstBuffer * buf)
gst_buffer_unmap (buf, &minfo);
mAcquisitionBuffer->ResetChunks();
mAcquisitionBuffer->SetChunkLayoutID(CHUNKLAYOUTID);
if (mChunkKlvEnabled && klv_byte_array && klv_byte_array->len > 0) {
PvResult pvRes;
pvRes = mAcquisitionBuffer->AddChunk (KLV_CHUNKID, (uint8_t*)klv_byte_array->data, klv_byte_array->len);
if (pvRes.IsOK ()) {
GST_LOG_OBJECT (mSink, "Added KLV as chunk data (len=%d)", klv_byte_array->len);
} else {
GST_WARNING_OBJECT (mSink, "Failed to add KLV as chunk data (len=%d): %s",
klv_byte_array->len,
pvRes.GetDescription ().GetAscii ());
}
}
if (klv_byte_array) {
g_byte_array_unref (klv_byte_array);
}
mBufferValid = TRUE;
g_cond_signal (&mSink->cond);
g_mutex_unlock (&mSink->mutex);
}
GByteArray * GstStreamingChannelSource::GetKlvByteArray (GstBuffer * buf)
{
GstKLVMeta *klv_meta;
gpointer iter = NULL;
GByteArray *byte_array;
{
//FIXME put fake data for testing
const guint8 klv_header[18] =
{ 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x0b, 0x01, 0x01, 0x0e, 0x01, 0x03,
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0xFF };
buf = gst_buffer_make_writable (buf);
gst_buffer_add_klv_meta_from_data (buf, klv_header, sizeof (klv_header));
gst_buffer_add_klv_meta_from_data (buf, klv_header, sizeof (klv_header));
}
/* spec says KLV can all be in one chunk, or multiple chunks, we do one chunk */
byte_array = g_byte_array_new ();
while ((klv_meta = (GstKLVMeta *) gst_buffer_iterate_meta_filtered (buf,
&iter, GST_KLV_META_API_TYPE))) {
gsize klv_size;
const guint8 *klv_data;
klv_data = gst_klv_meta_get_data (klv_meta, &klv_size);
if (!klv_data) {
GST_WARNING_OBJECT (mSink, "Failed to get KLV data from meta");
break;
}
g_byte_array_append (byte_array, klv_data, klv_size);
}
/* chunk length must be multiple of 4 bytes */
if (byte_array->len % 4 != 0) {
const guint8 padding[4] = {0};
const guint padding_len = GST_ROUND_UP_4 (byte_array->len) - byte_array->len;
g_byte_array_append (byte_array, padding, padding_len);
}
return byte_array;
}

View File

@ -41,6 +41,18 @@ public:
void GetHeightInfo (uint32_t & aMin, uint32_t & aMax, uint32_t & aInc) const;
PvResult GetSupportedPixelType (int aIndex, PvPixelType & aPixelType) const;
PvResult GetSupportedChunk (int aIndex, uint32_t &aID, PvString &aName) const;
bool GetChunkEnable (uint32_t aChunkID) const;
PvResult SetChunkEnable (uint32_t aChunkID, bool aEnabled);
bool GetChunkModeActive() const { return mChunkModeActive; }
PvResult SetChunkModeActive( bool aEnabled ) { mChunkModeActive = aEnabled; return PvResult::Code::OK; }
uint32_t GetChunksSize() const { return GetRequiredChunkSize(); }
uint32_t GetRequiredChunkSize () const;
void SetKlvEnabled (gboolean enable = TRUE);
gboolean GetKlvEnabled ();
GByteArray * GetKlvByteArray (GstBuffer * buf);
private:
GstPleoraSink * mSink;
PvBuffer *mAcquisitionBuffer;
@ -50,4 +62,9 @@ private:
gint mWidth;
gint mHeight;
PvPixelType mPixelType;
bool mChunkModeActive;
bool mChunkKlvEnabled;
gint mKlvChunkSize;
};