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

@@ -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) {