Skip to content

Commit a45f727

Browse files
authored
Add: Gstreamer ST20 RX zero copy (#1169)
Add to GStreamer ST20 RX plugin zero-copy MTL implementation, Initial testing shows performance gains. Introduce 2 paths, as the path without conversion in put_frame is "aligning" the memory for the zero-copy path to work, without It we need to do the memory alignment in the element. The memcpy path should not be hit unless we unlock the caps for the rfc4175_422be10 that allows for transfer without translation.
1 parent 0714034 commit a45f727

File tree

2 files changed

+155
-56
lines changed

2 files changed

+155
-56
lines changed

ecosystem/gstreamer_plugin/gst_mtl_st20p_rx.c

Lines changed: 153 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ enum {
100100
PROP_MAX
101101
};
102102

103+
typedef struct {
104+
GstBuffer* buf;
105+
GstMapInfo dest_info;
106+
} GstSt20pRxExternalData;
107+
103108
/* pad template */
104109
static GstStaticPadTemplate gst_mtl_st20p_rx_src_pad_template =
105110
GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
@@ -125,8 +130,15 @@ static void gst_mtl_st20p_rx_finalize(GObject* object);
125130

126131
static gboolean gst_mtl_st20p_rx_start(GstBaseSrc* basesrc);
127132
static gboolean gst_mtl_st20p_rx_negotiate(GstBaseSrc* basesrc);
128-
static GstFlowReturn gst_mtl_st20p_rx_create(GstBaseSrc* basesrc, guint64 offset,
129-
guint length, GstBuffer** buffer);
133+
static GstFlowReturn gst_mtl_st20p_rx_chain(GstBaseSrc* basesrc, guint64 offset,
134+
guint length, GstBuffer** buffer);
135+
136+
static GstFlowReturn gst_mtl_st20p_rx_get_external_frame(Gst_Mtl_St20p_Rx* src,
137+
GstBuffer** buffer);
138+
static GstFlowReturn gst_mtl_st20p_rx_get_internal_frame(Gst_Mtl_St20p_Rx* src,
139+
GstBuffer** buffer);
140+
static int gst_mtl_st20p_rx_query_ext_frame(void* priv, struct st_ext_frame* ext_frame,
141+
struct st20_rx_frame_meta* meta);
130142

131143
static void gst_mtl_st20p_rx_class_init(Gst_Mtl_St20p_RxClass* klass) {
132144
GObjectClass* gobject_class;
@@ -151,7 +163,7 @@ static void gst_mtl_st20p_rx_class_init(Gst_Mtl_St20p_RxClass* klass) {
151163

152164
gstbasesrc_class->start = GST_DEBUG_FUNCPTR(gst_mtl_st20p_rx_start);
153165
gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR(gst_mtl_st20p_rx_negotiate);
154-
gstbasesrc_class->create = GST_DEBUG_FUNCPTR(gst_mtl_st20p_rx_create);
166+
gstbasesrc_class->create = GST_DEBUG_FUNCPTR(gst_mtl_st20p_rx_chain);
155167

156168
gst_mtl_common_init_general_arguments(gobject_class);
157169

@@ -196,10 +208,9 @@ static void gst_mtl_st20p_rx_class_init(Gst_Mtl_St20p_RxClass* klass) {
196208
}
197209

198210
static gboolean gst_mtl_st20p_rx_start(GstBaseSrc* basesrc) {
199-
struct st20p_rx_ops* ops_rx;
211+
struct st20p_rx_ops ops_rx = {0};
200212

201213
Gst_Mtl_St20p_Rx* src = GST_MTL_ST20P_RX(basesrc);
202-
ops_rx = &src->ops_rx;
203214

204215
GST_DEBUG_OBJECT(src, "start");
205216
GST_DEBUG("Media Transport Initialization start");
@@ -223,42 +234,62 @@ static gboolean gst_mtl_st20p_rx_start(GstBaseSrc* basesrc) {
223234
return FALSE;
224235
}
225236

226-
ops_rx->name = "st20src";
227-
ops_rx->device = ST_PLUGIN_DEVICE_AUTO;
228-
ops_rx->width = src->width;
229-
ops_rx->height = src->height;
230-
ops_rx->transport_fmt = ST20_FMT_YUV_422_10BIT;
231-
ops_rx->interlaced = src->interlaced;
232-
ops_rx->flags |= ST20P_RX_FLAG_BLOCK_GET;
237+
ops_rx.name = "st20src";
238+
ops_rx.device = ST_PLUGIN_DEVICE_AUTO;
239+
ops_rx.width = src->width;
240+
ops_rx.height = src->height;
241+
ops_rx.transport_fmt = ST20_FMT_YUV_422_10BIT;
242+
ops_rx.interlaced = src->interlaced;
243+
ops_rx.flags |= ST20P_RX_FLAG_BLOCK_GET;
233244

234-
ops_rx->fps = st_frame_rate_to_st_fps((double)src->fps_n / src->fps_d);
235-
if (ops_rx->fps == ST_FPS_MAX) {
245+
ops_rx.fps = st_frame_rate_to_st_fps((double)src->fps_n / src->fps_d);
246+
if (ops_rx.fps == ST_FPS_MAX) {
236247
GST_ERROR("Invalid framerate: %d/%d", src->fps_n, src->fps_d);
237248
return FALSE;
238249
}
239250

240251
if (src->framebuffer_num) {
241-
ops_rx->framebuff_cnt = src->framebuffer_num;
252+
ops_rx.framebuff_cnt = src->framebuffer_num;
242253
} else {
243-
ops_rx->framebuff_cnt = 3;
254+
ops_rx.framebuff_cnt = 3;
244255
}
245256

246-
if (!gst_mtl_common_parse_pixel_format(src->pixel_format, &ops_rx->output_fmt)) {
257+
if (!gst_mtl_common_parse_pixel_format(src->pixel_format, &ops_rx.output_fmt)) {
247258
GST_ERROR("Failed to parse input format \"%s\"", src->pixel_format);
248-
ops_rx = NULL;
249259
return FALSE;
250260
}
251261

262+
switch (ops_rx.output_fmt) {
263+
case ST_FRAME_FMT_V210:
264+
src->format = GST_VIDEO_FORMAT_v210;
265+
break;
266+
case ST_FRAME_FMT_YUV422PLANAR10LE:
267+
src->format = GST_VIDEO_FORMAT_I422_10LE;
268+
break;
269+
default:
270+
GST_ERROR("Unsupported pixel format");
271+
return FALSE;
272+
}
273+
274+
src->zero_copy = (ops_rx.transport_fmt != st_frame_fmt_to_transport(ops_rx.output_fmt));
275+
if (src->zero_copy) {
276+
ops_rx.flags |= ST20P_RX_FLAG_EXT_FRAME;
277+
ops_rx.query_ext_frame = gst_mtl_st20p_rx_query_ext_frame;
278+
ops_rx.priv = src;
279+
} else {
280+
GST_WARNING("Using memcpy path");
281+
}
282+
252283
gst_mtl_common_copy_general_to_session_args(&(src->generalArgs), &(src->portArgs));
253284

254-
ops_rx->port.num_port =
255-
gst_mtl_common_parse_rx_port_arguments(&ops_rx->port, &src->portArgs);
256-
if (!ops_rx->port.num_port) {
285+
ops_rx.port.num_port =
286+
gst_mtl_common_parse_rx_port_arguments(&ops_rx.port, &src->portArgs);
287+
if (!ops_rx.port.num_port) {
257288
GST_ERROR("Failed to parse port arguments");
258289
return FALSE;
259290
}
260291

261-
src->rx_handle = st20p_rx_create(src->mtl_lib_handle, &src->ops_rx);
292+
src->rx_handle = st20p_rx_create(src->mtl_lib_handle, &ops_rx);
262293
if (!src->rx_handle) {
263294
GST_ERROR("Failed to create st20p rx handle");
264295
return FALSE;
@@ -372,7 +403,6 @@ static void gst_mtl_st20p_rx_get_property(GObject* object, guint prop_id, GValue
372403
static gboolean gst_mtl_st20p_rx_negotiate(GstBaseSrc* basesrc) {
373404
GstVideoInfo* info;
374405
Gst_Mtl_St20p_Rx* src = GST_MTL_ST20P_RX(basesrc);
375-
struct st20p_rx_ops* ops_rx = &src->ops_rx;
376406
gint ret;
377407
GstCaps* caps;
378408

@@ -393,18 +423,7 @@ static gboolean gst_mtl_st20p_rx_negotiate(GstBaseSrc* basesrc) {
393423
info->fps_n = src->fps_n;
394424
info->fps_d = src->fps_d;
395425

396-
switch (ops_rx->output_fmt) {
397-
case ST_FRAME_FMT_V210:
398-
info->finfo = gst_video_format_get_info(GST_VIDEO_FORMAT_v210);
399-
break;
400-
case ST20_FMT_YUV_422_10BIT:
401-
info->finfo = gst_video_format_get_info(GST_VIDEO_FORMAT_I422_10LE);
402-
break;
403-
default:
404-
GST_ERROR("Unsupported pixel format");
405-
gst_video_info_free(info);
406-
return FALSE;
407-
}
426+
info->finfo = gst_video_format_get_info(src->format);
408427

409428
caps = gst_caps_new_simple(
410429
"video/x-raw", "format", G_TYPE_STRING,
@@ -433,26 +452,47 @@ static gboolean gst_mtl_st20p_rx_negotiate(GstBaseSrc* basesrc) {
433452
return TRUE;
434453
}
435454

436-
static GstFlowReturn gst_mtl_st20p_rx_create(GstBaseSrc* basesrc, guint64 offset,
437-
guint length, GstBuffer** buffer) {
438-
GstBuffer* buf;
439-
Gst_Mtl_St20p_Rx* src = GST_MTL_ST20P_RX(basesrc);
455+
static GstFlowReturn gst_mtl_st20p_rx_get_external_frame(Gst_Mtl_St20p_Rx* src,
456+
GstBuffer** buffer) {
457+
struct st_frame* frame;
458+
GstSt20pRxExternalData* ext_data;
459+
460+
for (guint i = 0; i < src->retry_frame; i++) {
461+
frame = st20p_rx_get_frame(src->rx_handle);
462+
if (frame) {
463+
break;
464+
}
465+
}
466+
467+
if (!frame) {
468+
GST_INFO("Failed to get frame EOS");
469+
return GST_FLOW_EOS;
470+
}
471+
472+
ext_data = frame->opaque;
473+
*buffer = ext_data->buf;
474+
GST_BUFFER_PTS(*buffer) = frame->timestamp;
475+
476+
gst_buffer_unmap(ext_data->buf, &ext_data->dest_info);
477+
st20p_rx_put_frame(src->rx_handle, frame);
478+
free(ext_data);
479+
480+
return GST_FLOW_OK;
481+
}
482+
483+
static GstFlowReturn gst_mtl_st20p_rx_get_internal_frame(Gst_Mtl_St20p_Rx* src,
484+
GstBuffer** buffer) {
440485
struct st_frame* frame;
441486
GstMapInfo dest_info;
442-
gint ret;
443487
gsize fill_size;
444488

445-
buf = gst_buffer_new_allocate(NULL, src->frame_size, NULL);
446-
if (!buf) {
489+
*buffer = gst_buffer_new_allocate(NULL, src->frame_size, NULL);
490+
if (!*buffer) {
447491
GST_ERROR("Failed to allocate buffer");
448492
return GST_FLOW_ERROR;
449493
}
450494

451-
*buffer = buf;
452-
453-
GST_OBJECT_LOCK(src);
454-
455-
for (int i = 0; i < src->retry_frame; i++) {
495+
for (guint i = 0; i < src->retry_frame; i++) {
456496
frame = st20p_rx_get_frame(src->rx_handle);
457497
if (frame) {
458498
break;
@@ -461,25 +501,39 @@ static GstFlowReturn gst_mtl_st20p_rx_create(GstBaseSrc* basesrc, guint64 offset
461501

462502
if (!frame) {
463503
GST_INFO("Failed to get frame EOS");
464-
GST_OBJECT_UNLOCK(src);
465504
return GST_FLOW_EOS;
466505
}
467506

468-
gst_buffer_map(buf, &dest_info, GST_MAP_WRITE);
507+
gst_buffer_map(*buffer, &dest_info, GST_MAP_WRITE);
469508

470-
fill_size = gst_buffer_fill(buf, 0, frame->addr[0], src->frame_size);
471-
GST_BUFFER_PTS(buf) = frame->timestamp;
509+
fill_size = gst_buffer_fill(*buffer, 0, frame->addr[0], src->frame_size);
510+
GST_BUFFER_PTS(*buffer) = frame->timestamp;
472511

473-
gst_buffer_unmap(buf, &dest_info);
512+
gst_buffer_unmap(*buffer, &dest_info);
474513

475514
if (fill_size != src->frame_size) {
476515
GST_ERROR("Failed to fill buffer");
477-
ret = GST_FLOW_ERROR;
478-
} else {
479-
ret = GST_FLOW_OK;
516+
return GST_FLOW_ERROR;
480517
}
481518

482519
st20p_rx_put_frame(src->rx_handle, frame);
520+
521+
return GST_FLOW_OK;
522+
}
523+
524+
static GstFlowReturn gst_mtl_st20p_rx_chain(GstBaseSrc* basesrc, guint64 offset,
525+
guint length, GstBuffer** buffer) {
526+
Gst_Mtl_St20p_Rx* src = GST_MTL_ST20P_RX(basesrc);
527+
gint ret = GST_FLOW_OK;
528+
529+
GST_OBJECT_LOCK(src);
530+
531+
if (src->zero_copy) {
532+
ret = gst_mtl_st20p_rx_get_external_frame(src, buffer);
533+
} else {
534+
ret = gst_mtl_st20p_rx_get_internal_frame(src, buffer);
535+
}
536+
483537
GST_OBJECT_UNLOCK(src);
484538
return ret;
485539
}
@@ -511,3 +565,47 @@ GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, mtl_st20p_rx,
511565
"software-based solution designed for high-throughput transmission",
512566
plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME,
513567
GST_PACKAGE_ORIGIN)
568+
569+
static int gst_mtl_st20p_rx_query_ext_frame(void* priv, struct st_ext_frame* ext_frame,
570+
struct st20_rx_frame_meta* meta) {
571+
GstVideoMeta* video_meta;
572+
guint8 planes;
573+
Gst_Mtl_St20p_Rx* s = (Gst_Mtl_St20p_Rx*)priv;
574+
575+
GstSt20pRxExternalData* ext_data =
576+
(GstSt20pRxExternalData*)malloc(sizeof(GstSt20pRxExternalData));
577+
if (!ext_data) {
578+
GST_ERROR("Failed to allocate memory for external data");
579+
return GST_FLOW_ERROR;
580+
}
581+
582+
ext_data->buf = gst_buffer_new_allocate(NULL, s->frame_size, NULL);
583+
if (!ext_data->buf) {
584+
GST_ERROR("Failed to allocate buffer");
585+
free(ext_data);
586+
return GST_FLOW_ERROR;
587+
}
588+
589+
video_meta = gst_buffer_add_video_meta(ext_data->buf, GST_VIDEO_FRAME_FLAG_NONE,
590+
s->format, s->width, s->height);
591+
if (!video_meta) {
592+
GST_ERROR("Failed to add video meta to buffer");
593+
gst_buffer_unref(ext_data->buf);
594+
free(ext_data);
595+
return GST_FLOW_ERROR;
596+
}
597+
598+
gst_buffer_map(ext_data->buf, &ext_data->dest_info, GST_MAP_WRITE);
599+
600+
/* fill the ext frame */
601+
planes = st_frame_fmt_planes(video_meta->n_planes);
602+
for (guint8 i = 0; i < planes; i++) {
603+
ext_frame->addr[i] = ext_data->dest_info.data + video_meta->offset[i];
604+
ext_frame->linesize[i] = video_meta->stride[i];
605+
ext_frame->iova[i] = 0;
606+
}
607+
ext_frame->size = s->frame_size;
608+
ext_frame->opaque = ext_data;
609+
610+
return GST_FLOW_OK;
611+
}

ecosystem/gstreamer_plugin/gst_mtl_st20p_rx.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ struct _Gst_Mtl_St20p_Rx {
6161
GstBuffer* buffer;
6262

6363
/*< private >*/
64-
struct st20p_rx_ops ops_rx; /* needed for caps negotiation */
6564
guint log_level;
6665
mtl_handle mtl_lib_handle;
6766
st20p_rx_handle rx_handle;
6867
guint retry_frame;
6968
guint frame_size;
69+
gboolean zero_copy;
70+
GstVideoFormat format;
7071

7172
GeneralArgs generalArgs; /* imtl initialization arguments */
7273
SessionPortArgs portArgs; /* imtl session device */

0 commit comments

Comments
 (0)