cudaipc: Add support for custom meta forwarding

Forward custom meta to peer ipcsrc elements

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6006>
This commit is contained in:
Seungha Yang 2024-01-29 21:37:26 +09:00 committed by GStreamer Marge Bot
parent c760c72f7a
commit 07ba225183
11 changed files with 387 additions and 62 deletions

View file

@ -38,7 +38,10 @@
constexpr guint GST_CUDA_IPC_PKT_HAVE_DATA_PAYLOAD_MIN_SIZE =
sizeof (GstClockTime) + sizeof (CUipcMemHandle) +
sizeof (GstCudaIpcMemLayout) + sizeof (guint8);
sizeof (GstCudaIpcMemLayout) + sizeof (guint) + sizeof (guint);
constexpr guint GST_CUDA_IPC_PKT_HAVE_MMAP_DATA_PAYLOAD_MIN_SIZE =
sizeof (GstClockTime) + sizeof (GstCudaSharableHandle) +
sizeof (GstCudaIpcMemLayout) + sizeof (guint) + sizeof (guint);
constexpr guint GST_CUDA_IPC_PKT_RELEASE_DATA_PAYLOAD_SIZE =
sizeof (CUipcMemHandle);
@ -150,26 +153,28 @@ gst_cuda_ipc_pkt_build_need_data (std::vector < guint8 > &buf)
/* *INDENT-OFF* */
bool
gst_cuda_ipc_pkt_build_have_data (std::vector < guint8 > &buf, GstClockTime pts,
const GstVideoInfo & info, const CUipcMemHandle & handle, GstCaps * caps)
const GstVideoInfo & info, const CUipcMemHandle & handle, GstCaps * caps,
const std::vector<guint8> & meta)
{
GstCudaIpcPacketHeader header;
GstCudaIpcMemLayout layout;
guint8 *ptr;
guint caps_len = 0;
gchar *caps_str = nullptr;
guint caps_size = 1;
if (caps) {
caps_str = gst_caps_serialize (caps, GST_SERIALIZE_FLAG_NONE);
if (!caps_str)
return false;
caps_size += strlen (caps_str) + 1;
caps_len = strlen (caps_str) + 1;
}
header.type = GstCudaIpcPktType::HAVE_DATA;
header.magic = GST_CUDA_IPC_MAGIC_NUMBER;
header.payload_size = sizeof (GstClockTime) + sizeof (CUipcMemHandle) +
sizeof (GstCudaIpcMemLayout) + caps_size;
sizeof (GstCudaIpcMemLayout) + sizeof (guint) + caps_len +
sizeof (guint) + meta.size ();
layout.size = layout.max_size = info.size;
layout.pitch = info.stride[0];
@ -191,35 +196,46 @@ gst_cuda_ipc_pkt_build_have_data (std::vector < guint8 > &buf, GstClockTime pts,
memcpy (ptr, &handle, sizeof (CUipcMemHandle));
ptr += sizeof (CUipcMemHandle);
if (caps) {
*ptr = 1;
ptr++;
*((guint *) ptr) = caps_len;
ptr += sizeof (guint);
if (caps_len > 0) {
strcpy ((char *) ptr, caps_str);
} else {
*ptr = 0;
ptr += caps_len;
}
*((guint *) ptr) = meta.size ();
ptr += sizeof (guint);
if (!meta.empty ())
memcpy (ptr, meta.data (), meta.size ());
g_free (caps_str);
return true;
}
/* *INDENT-ON* */
#define DO_OFFSET(p,r,s) G_STMT_START { \
(p) += s; \
(r) -= s; \
} G_STMT_END
bool
gst_cuda_ipc_pkt_parse_have_data (const std::vector < guint8 > &buf,
GstClockTime & pts, GstCudaIpcMemLayout & layout, CUipcMemHandle & handle,
GstCaps ** caps)
GstCaps ** caps, std::vector < guint8 > &meta)
{
GstCudaIpcPacketHeader header;
const guint8 *ptr;
std::string str;
size_t remaining;
g_return_val_if_fail (buf.size () >=
GST_CUDA_IPC_PKT_HEADER_SIZE +
GST_CUDA_IPC_PKT_HAVE_DATA_PAYLOAD_MIN_SIZE, false);
g_return_val_if_fail (caps, false);
meta.clear ();
remaining = buf.size ();
ptr = &buf[0];
memcpy (&header, ptr, GST_CUDA_IPC_PKT_HEADER_SIZE);
@ -228,25 +244,43 @@ gst_cuda_ipc_pkt_parse_have_data (const std::vector < guint8 > &buf,
header.payload_size < GST_CUDA_IPC_PKT_HAVE_DATA_PAYLOAD_MIN_SIZE) {
return false;
}
ptr += GST_CUDA_IPC_PKT_HEADER_SIZE;
DO_OFFSET (ptr, remaining, GST_CUDA_IPC_PKT_HEADER_SIZE);
memcpy (&pts, ptr, sizeof (GstClockTime));
ptr += sizeof (GstClockTime);
DO_OFFSET (ptr, remaining, sizeof (GstClockTime));
memcpy (&layout, ptr, sizeof (GstCudaIpcMemLayout));
ptr += sizeof (GstCudaIpcMemLayout);
DO_OFFSET (ptr, remaining, sizeof (GstCudaIpcMemLayout));
memcpy (&handle, ptr, sizeof (CUipcMemHandle));
ptr += sizeof (CUipcMemHandle);
DO_OFFSET (ptr, remaining, sizeof (CUipcMemHandle));
if (*ptr) {
ptr++;
auto caps_len = *((guint *) ptr);
DO_OFFSET (ptr, remaining, sizeof (guint));
if (caps_len > 0) {
if (remaining < caps_len + sizeof (guint))
return false;
*caps = gst_caps_from_string ((const gchar *) ptr);
if (*caps == nullptr)
return false;
}
DO_OFFSET (ptr, remaining, caps_len);
if (remaining < sizeof (guint))
return false;
auto meta_len = *((guint *) ptr);
DO_OFFSET (ptr, remaining, sizeof (guint));
if (meta_len > 0) {
if (remaining < meta_len)
return false;
meta.resize (meta_len);
memcpy (meta.data (), ptr, meta_len);
}
return true;
}
@ -254,26 +288,28 @@ gst_cuda_ipc_pkt_parse_have_data (const std::vector < guint8 > &buf,
bool
gst_cuda_ipc_pkt_build_have_mmap_data (std::vector<guint8> & buf,
GstClockTime pts, const GstVideoInfo & info, guint32 max_size,
GstCudaSharableHandle handle, GstCaps * caps)
GstCudaSharableHandle handle, GstCaps * caps,
const std::vector<guint8> & meta)
{
GstCudaIpcPacketHeader header;
GstCudaIpcMemLayout layout;
guint8 *ptr;
guint caps_len = 0;
gchar *caps_str = nullptr;
guint caps_size = 1;
if (caps) {
caps_str = gst_caps_serialize (caps, GST_SERIALIZE_FLAG_NONE);
if (!caps_str)
return false;
caps_size = strlen (caps_str) + 1;
caps_len = strlen (caps_str) + 1;
}
header.type = GstCudaIpcPktType::HAVE_MMAP_DATA;
header.magic = GST_CUDA_IPC_MAGIC_NUMBER;
header.payload_size = sizeof (GstClockTime) + sizeof (GstCudaIpcMemLayout) +
sizeof (GstCudaSharableHandle) + caps_size;
sizeof (GstCudaSharableHandle) + sizeof (guint) + caps_len +
sizeof (guint) + meta.size ();
layout.size = info.size;
layout.max_size = max_size;
@ -296,15 +332,18 @@ gst_cuda_ipc_pkt_build_have_mmap_data (std::vector<guint8> & buf,
*((GstCudaSharableHandle *) ptr) = handle;
ptr += sizeof (GstCudaSharableHandle);
if (caps) {
*ptr = 1;
ptr++;
*((guint *) ptr) = caps_len;
ptr += sizeof (guint);
if (caps_len > 0) {
strcpy ((char *) ptr, caps_str);
} else {
*ptr = 0;
ptr += caps_len;
}
*((guint *) ptr) = meta.size ();
ptr += sizeof (guint);
if (!meta.empty ())
memcpy (ptr, meta.data (), meta.size ());
g_free (caps_str);
return true;
@ -314,47 +353,66 @@ gst_cuda_ipc_pkt_build_have_mmap_data (std::vector<guint8> & buf,
bool
gst_cuda_ipc_pkt_parse_have_mmap_data (const std::vector < guint8 > &buf,
GstClockTime & pts, GstCudaIpcMemLayout & layout,
GstCudaSharableHandle * handle, GstCaps ** caps)
GstCudaSharableHandle * handle, GstCaps ** caps,
std::vector < guint8 > &meta)
{
GstCudaIpcPacketHeader header;
const guint8 *ptr;
std::string str;
size_t remaining;
g_return_val_if_fail (buf.size () >
g_return_val_if_fail (buf.size () >=
GST_CUDA_IPC_PKT_HEADER_SIZE +
sizeof (GstClockTime) + sizeof (GstCudaIpcMemLayout) +
sizeof (GstCudaSharableHandle), false);
GST_CUDA_IPC_PKT_HAVE_MMAP_DATA_PAYLOAD_MIN_SIZE, false);
g_return_val_if_fail (caps, false);
meta.clear ();
remaining = buf.size ();
ptr = &buf[0];
memcpy (&header, ptr, GST_CUDA_IPC_PKT_HEADER_SIZE);
if (header.type != GstCudaIpcPktType::HAVE_MMAP_DATA ||
header.magic != GST_CUDA_IPC_MAGIC_NUMBER ||
header.payload_size <=
sizeof (GstClockTime) + sizeof (GstCudaIpcMemLayout) +
sizeof (GstCudaSharableHandle)) {
header.payload_size < GST_CUDA_IPC_PKT_HAVE_MMAP_DATA_PAYLOAD_MIN_SIZE) {
return false;
}
ptr += GST_CUDA_IPC_PKT_HEADER_SIZE;
DO_OFFSET (ptr, remaining, GST_CUDA_IPC_PKT_HEADER_SIZE);
memcpy (&pts, ptr, sizeof (GstClockTime));
ptr += sizeof (GstClockTime);
DO_OFFSET (ptr, remaining, sizeof (GstClockTime));
memcpy (&layout, ptr, sizeof (GstCudaIpcMemLayout));
ptr += sizeof (GstCudaIpcMemLayout);
DO_OFFSET (ptr, remaining, sizeof (GstCudaIpcMemLayout));
*handle = *((GstCudaSharableHandle *) ptr);
ptr += sizeof (GstCudaSharableHandle);
DO_OFFSET (ptr, remaining, sizeof (GstCudaSharableHandle));
if (*ptr) {
ptr++;
auto caps_len = *((guint *) ptr);
DO_OFFSET (ptr, remaining, sizeof (guint));
if (caps_len > 0) {
if (remaining < caps_len + sizeof (guint))
return false;
*caps = gst_caps_from_string ((const gchar *) ptr);
if (*caps == nullptr)
return false;
}
DO_OFFSET (ptr, remaining, caps_len);
if (remaining < sizeof (guint))
return false;
auto meta_len = *((guint *) ptr);
DO_OFFSET (ptr, remaining, sizeof (guint));
if (meta_len > 0) {
if (remaining < meta_len)
return false;
meta.resize (meta_len);
memcpy (meta.data (), ptr, meta_len);
}
return true;
}

View file

@ -134,26 +134,30 @@ bool gst_cuda_ipc_pkt_build_have_data (std::vector<guint8> & buf,
GstClockTime pts,
const GstVideoInfo & info,
const CUipcMemHandle & handle,
GstCaps * caps);
GstCaps * caps,
const std::vector<guint8> & meta);
bool gst_cuda_ipc_pkt_parse_have_data (const std::vector<guint8> & buf,
GstClockTime & pts,
GstCudaIpcMemLayout & layout,
CUipcMemHandle & handle,
GstCaps ** caps);
GstCaps ** caps,
std::vector<guint8> & meta);
bool gst_cuda_ipc_pkt_build_have_mmap_data (std::vector<guint8> & buf,
GstClockTime pts,
const GstVideoInfo & info,
guint32 max_size,
GstCudaSharableHandle handle,
GstCaps * caps);
GstCaps * caps,
const std::vector<guint8> & meta);
bool gst_cuda_ipc_pkt_parse_have_mmap_data (const std::vector<guint8> & buf,
GstClockTime & pts,
GstCudaIpcMemLayout & layout,
GstCudaSharableHandle * handle,
GstCaps ** caps);
GstCaps ** caps,
std::vector<guint8> & meta);
void gst_cuda_ipc_pkt_build_read_done (std::vector<guint8> & buf);

View file

@ -659,9 +659,10 @@ gst_cuda_ipc_client_have_data (GstCudaIpcClient * self)
std::shared_ptr < GstCudaIpcImportData > import_data;
std::unique_lock < std::mutex > lk (priv->lock);
auto conn = priv->conn;
std::vector < guint8 > meta;
if (!gst_cuda_ipc_pkt_parse_have_data (conn->server_msg,
pts, layout, handle, &caps)) {
pts, layout, handle, &caps, meta)) {
GST_ERROR_OBJECT (self, "Couldn't parse HAVE-DATA packet");
return false;
}
@ -774,6 +775,16 @@ gst_cuda_ipc_client_have_data (GstCudaIpcClient * self)
GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
while (!meta.empty ()) {
guint32 consumed = 0;
if (!gst_meta_deserialize (buffer, meta.data (), meta.size (),
&consumed) || consumed == 0) {
break;
}
meta.erase (meta.begin (), meta.begin () + consumed);
}
sample = gst_sample_new (buffer, priv->caps, nullptr, nullptr);
gst_buffer_unref (buffer);
@ -1008,7 +1019,8 @@ gst_cuda_ipc_client_wait_msg_finish (GstCudaIpcClient * client, bool result)
void
gst_cuda_ipc_client_have_mmap_data (GstCudaIpcClient * client,
GstClockTime pts, const GstCudaIpcMemLayout & layout, GstCaps * caps,
GstCudaSharableHandle server_handle, GstCudaSharableHandle client_handle)
GstCudaSharableHandle server_handle, GstCudaSharableHandle client_handle,
std::vector < guint8 > &meta)
{
GstCudaIpcClientPrivate *priv = client->priv;
std::unique_lock < std::mutex > lk (priv->lock);
@ -1136,6 +1148,16 @@ gst_cuda_ipc_client_have_mmap_data (GstCudaIpcClient * client,
GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
while (!meta.empty ()) {
guint32 consumed = 0;
if (!gst_meta_deserialize (buffer, meta.data (), meta.size (),
&consumed) || consumed == 0) {
break;
}
meta.erase (meta.begin (), meta.begin () + consumed);
}
sample = gst_sample_new (buffer, priv->caps, nullptr, nullptr);
gst_buffer_unref (buffer);

View file

@ -111,7 +111,8 @@ void gst_cuda_ipc_client_have_mmap_data (GstCudaIpcClient * client
const GstCudaIpcMemLayout & layout,
GstCaps * caps,
GstCudaSharableHandle server_handle,
GstCudaSharableHandle client_handle);
GstCudaSharableHandle client_handle,
std::vector <guint8> & meta);
void gst_cuda_ipc_client_on_idle (GstCudaIpcClient * client);

View file

@ -188,9 +188,10 @@ gst_cuda_ipc_client_unix_finish_have_mmap_data (GstCudaIpcClient * client,
GstCudaSharableHandle client_handle = 0;
GstCaps *caps = nullptr;
GError *err = nullptr;
std::vector < guint8 > meta;
if (!gst_cuda_ipc_pkt_parse_have_mmap_data (conn->server_msg, pts,
layout, &server_handle, &caps)) {
layout, &server_handle, &caps, meta)) {
GST_ERROR_OBJECT (client, "Couldn't parse MMAP-DATA");
goto error;
}
@ -204,7 +205,7 @@ gst_cuda_ipc_client_unix_finish_have_mmap_data (GstCudaIpcClient * client,
}
gst_cuda_ipc_client_have_mmap_data (client, pts, layout, caps,
server_handle, client_handle);
server_handle, client_handle, meta);
return;
error:

View file

@ -195,6 +195,7 @@ gst_cuda_ipc_client_win32_finish_have_mmap_data (GstCudaIpcClient * client,
GstCudaSharableHandle server_handle = nullptr;
GstCudaSharableHandle client_handle = nullptr;
GstCaps *caps = nullptr;
std::vector < guint8 > meta;
if (!priv->server_process) {
GST_ERROR_OBJECT (self, "Server process handle is not available");
@ -202,7 +203,7 @@ gst_cuda_ipc_client_win32_finish_have_mmap_data (GstCudaIpcClient * client,
}
if (!gst_cuda_ipc_pkt_parse_have_mmap_data (win32_conn->server_msg, pts,
layout, &server_handle, &caps)) {
layout, &server_handle, &caps, meta)) {
GST_ERROR_OBJECT (self, "Couldn't parse MMAP-DATA");
goto error;
}
@ -218,7 +219,7 @@ gst_cuda_ipc_client_win32_finish_have_mmap_data (GstCudaIpcClient * client,
}
gst_cuda_ipc_client_have_mmap_data (client, pts, layout, caps,
server_handle, client_handle);
server_handle, client_handle, meta);
return;
error:

View file

@ -123,7 +123,8 @@ gst_cuda_ipc_server_finalize (GObject * object)
GstFlowReturn
gst_cuda_ipc_server_send_data (GstCudaIpcServer * server, GstSample * sample,
const GstVideoInfo & info, const CUipcMemHandle & handle, GstClockTime pts)
const GstVideoInfo & info, const CUipcMemHandle & handle, GstClockTime pts,
GByteArray * meta)
{
GstCudaIpcServerPrivate *priv;
GstCudaIpcServerClass *klass;
@ -153,6 +154,10 @@ gst_cuda_ipc_server_send_data (GstCudaIpcServer * server, GstSample * sample,
data->handle = handle;
data->pts = pts;
data->seq_num = priv->seq_num;
if (meta && meta->len) {
data->meta.resize (meta->len);
memcpy (data->meta.data (), meta->data, meta->len);
}
priv->seq_num++;
priv->data = data;
@ -166,7 +171,7 @@ gst_cuda_ipc_server_send_data (GstCudaIpcServer * server, GstSample * sample,
GstFlowReturn
gst_cuda_ipc_server_send_mmap_data (GstCudaIpcServer * server,
GstSample * sample, const GstVideoInfo & info, GstCudaSharableHandle handle,
GstClockTime pts)
GstClockTime pts, GByteArray * meta)
{
GstCudaIpcServerPrivate *priv;
GstCudaIpcServerClass *klass;
@ -196,6 +201,10 @@ gst_cuda_ipc_server_send_mmap_data (GstCudaIpcServer * server,
data->os_handle = handle;
data->pts = pts;
data->seq_num = priv->seq_num;
if (meta && meta->len) {
data->meta.resize (meta->len);
memcpy (data->meta.data (), meta->data, meta->len);
}
priv->seq_num++;
priv->data = data;
@ -373,7 +382,7 @@ gst_cuda_ipc_server_have_data (GstCudaIpcServer * self,
handle_dump.c_str (), conn->id);
if (!gst_cuda_ipc_pkt_build_have_data (conn->server_msg, conn->data->pts,
conn->data->info, conn->data->handle, caps)) {
conn->data->info, conn->data->handle, caps, conn->data->meta)) {
GST_ERROR_OBJECT (self, "Couldn't build HAVE-DATA pkt, conn-id: %u",
conn->id);
gst_cuda_ipc_server_close_connection (self, conn);
@ -388,7 +397,7 @@ gst_cuda_ipc_server_have_data (GstCudaIpcServer * self,
conn->id);
if (!gst_cuda_ipc_pkt_build_have_mmap_data (conn->server_msg,
conn->data->pts, conn->data->info, max_size, conn->data->os_handle,
caps)) {
caps, conn->data->meta)) {
GST_ERROR_OBJECT (self, "Couldn't build HAVE-MMAP-DATA pkt, conn-id: %u",
conn->id);
gst_cuda_ipc_server_close_connection (self, conn);

View file

@ -86,13 +86,15 @@ GstFlowReturn gst_cuda_ipc_server_send_data (GstCudaIpcServer * server,
GstSample * sample,
const GstVideoInfo & info,
const CUipcMemHandle & handle,
GstClockTime pts);
GstClockTime pts,
GByteArray * meta);
GstFlowReturn gst_cuda_ipc_server_send_mmap_data (GstCudaIpcServer * server,
GstSample * sample,
const GstVideoInfo & info,
GstCudaSharableHandle handle,
GstClockTime pts);
GstClockTime pts,
GByteArray * meta);
void gst_cuda_ipc_server_stop (GstCudaIpcServer * server);
@ -133,6 +135,7 @@ struct GstCudaIpcServerData
CUipcMemHandle handle;
GstCudaSharableHandle os_handle;
GstClockTime pts;
std::vector<guint8> meta;
guint64 seq_num;
};

View file

@ -79,6 +79,16 @@ enum
/* *INDENT-OFF* */
struct GstCudaIpcSinkPrivate
{
GstCudaIpcSinkPrivate ()
{
meta = g_byte_array_new ();
}
~GstCudaIpcSinkPrivate ()
{
g_byte_array_unref (meta);
}
GstCudaContext *context = nullptr;
GstCudaStream *stream = nullptr;
@ -91,6 +101,7 @@ struct GstCudaIpcSinkPrivate
GstVideoInfo mem_info;
CUipcMemHandle prepared_handle;
GstCudaSharableHandle prepared_os_handle;
GByteArray *meta;
std::mutex lock;
@ -542,6 +553,20 @@ gst_cuda_ipc_sink_query (GstBaseSink * sink, GstQuery * query)
return GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
}
static gboolean
gst_cuda_ipc_sink_foreach_meta (GstBuffer * buffer, GstMeta ** meta,
GstCudaIpcSink * self)
{
auto priv = self->priv;
if (!gst_meta_info_is_custom ((*meta)->info))
return TRUE;
gst_meta_serialize_simple (*meta, priv->meta);
return TRUE;
}
static GstFlowReturn
gst_cuda_ipc_sink_prepare (GstBaseSink * sink, GstBuffer * buf)
{
@ -642,6 +667,10 @@ gst_cuda_ipc_sink_prepare (GstBaseSink * sink, GstBuffer * buf)
priv->prepared_sample = gst_sample_new (cuda_buf,
priv->caps, nullptr, nullptr);
g_byte_array_set_size (priv->meta, 0);
gst_buffer_foreach_meta (buf,
(GstBufferForeachMetaFunc) gst_cuda_ipc_sink_foreach_meta, self);
if (cuda_buf != buf)
gst_buffer_unref (cuda_buf);
@ -706,10 +735,11 @@ gst_cuda_ipc_sink_render (GstBaseSink * sink, GstBuffer * buf)
if (priv->ipc_mode == GST_CUDA_IPC_LEGACY) {
ret = gst_cuda_ipc_server_send_data (priv->server, priv->prepared_sample,
priv->mem_info, priv->prepared_handle, pts);
priv->mem_info, priv->prepared_handle, pts, priv->meta);
} else {
ret = gst_cuda_ipc_server_send_mmap_data (priv->server,
priv->prepared_sample, priv->mem_info, priv->prepared_os_handle, pts);
priv->prepared_sample, priv->mem_info, priv->prepared_os_handle, pts,
priv->meta);
}
return ret;

View file

@ -0,0 +1,189 @@
/* GStreamer
* Copyright (C) 2024 Seungha Yang <seungha@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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gst/gst.h>
#define CUSTOM_META_NAME "GstCudaIpcTestMeta"
static GstPadProbeReturn
server_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstBuffer *buf;
GstCustomMeta *meta;
GstStructure *s;
gchar *str;
buf = GST_PAD_PROBE_INFO_BUFFER (info);
meta = gst_buffer_add_custom_meta (buf, CUSTOM_META_NAME);
s = gst_custom_meta_get_structure (meta);
gst_structure_set (s, "foo", G_TYPE_STRING, "bar", "timestamp",
G_TYPE_UINT64, GST_BUFFER_PTS (buf), NULL);
str = gst_structure_serialize (s, GST_SERIALIZE_FLAG_NONE);
gst_println ("Added custom meta %s", str);
return GST_PAD_PROBE_OK;
}
static GstElement *
server_process (const gchar * address)
{
GError *error = NULL;
GstPad *sinkpad;
GstElement *sink;
GstElement *pipeline =
gst_parse_launch
("videotestsrc ! video/x-raw,format=RGBA,framerate=1/1 ! "
"queue ! cudaupload ! cudaipcsink name=sink", &error);
if (!pipeline) {
gst_printerrln ("couldn't create pipeline, err: %s", error->message);
g_clear_error (&error);
return NULL;
}
sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
g_assert (sink);
if (address)
g_object_set (sink, "address", address, NULL);
sinkpad = gst_element_get_static_pad (sink, "sink");
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER,
(GstPadProbeCallback) server_probe_cb, NULL, NULL);
gst_object_unref (sinkpad);
return pipeline;
}
static GstPadProbeReturn
client_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstBuffer *buf;
GstCustomMeta *meta;
buf = GST_PAD_PROBE_INFO_BUFFER (info);
meta = gst_buffer_get_custom_meta (buf, CUSTOM_META_NAME);
if (!meta) {
gst_printerrln ("Buffer without meta");
} else {
GstStructure *s;
gchar *str;
s = gst_custom_meta_get_structure (meta);
str = gst_structure_serialize (s, GST_SERIALIZE_FLAG_NONE);
gst_println ("Found custom meta \"%s\"", str);
g_free (str);
}
return GST_PAD_PROBE_OK;
}
static GstElement *
client_process (const gchar * address)
{
GError *error = NULL;
GstPad *srcpad;
GstElement *src;
GstElement *pipeline =
gst_parse_launch ("cudaipcsrc name=src ! fakesink", &error);
if (!pipeline) {
gst_printerrln ("couldn't create pipeline, err: %s", error->message);
g_clear_error (&error);
return NULL;
}
src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
g_assert (src);
if (address)
g_object_set (src, "address", address, NULL);
srcpad = gst_element_get_static_pad (src, "src");
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER,
(GstPadProbeCallback) client_probe_cb, NULL, NULL);
gst_object_unref (srcpad);
return pipeline;
}
gint
main (gint argc, gchar ** argv)
{
GstElement *pipeline = NULL;
GstStateChangeReturn sret;
GError *error = NULL;
GOptionContext *option_ctx;
gboolean is_server = FALSE;
gchar *address = NULL;
gboolean ret;
static const gchar *tags[] = { NULL };
GOptionEntry options[] = {
{"server", 0, 0, G_OPTION_ARG_NONE, &is_server,
"Launch server process", NULL},
{"address", 0, 0, G_OPTION_ARG_STRING, &address,
"IPC communication address"},
{NULL}
};
GMainLoop *loop;
option_ctx = g_option_context_new ("CUDA IPC example");
g_option_context_add_main_entries (option_ctx, options, NULL);
g_option_context_add_group (option_ctx, gst_init_get_option_group ());
ret = g_option_context_parse (option_ctx, &argc, &argv, &error);
g_option_context_free (option_ctx);
if (!ret) {
g_printerr ("option parsing failed: %s\n", error->message);
g_clear_error (&error);
return 1;
}
loop = g_main_loop_new (NULL, FALSE);
gst_meta_register_custom ("GstCudaIpcTestMeta", tags, NULL, NULL, NULL);
if (is_server)
pipeline = server_process (address);
else
pipeline = client_process (address);
if (!pipeline)
return 1;
sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (sret == GST_STATE_CHANGE_FAILURE) {
g_printerr ("Pipeline doesn't want to playing\n");
} else {
g_main_loop_run (loop);
}
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
g_main_loop_unref (loop);
g_free (address);
return 0;
}

View file

@ -4,3 +4,10 @@ executable('nvcodec',
dependencies: [gst_dep, gstbase_dep, gstvideo_dep],
c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'],
install: false)
executable('cudaipc', ['cudaipc.c'],
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies: [gst_dep, gstbase_dep, gstvideo_dep],
install: false)