diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.cpp index f7c24a2a9f..5a33dc54c6 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.cpp @@ -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 & 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 & buf, GstClockTime pts, const GstVideoInfo & info, guint32 max_size, - GstCudaSharableHandle handle, GstCaps * caps) + GstCudaSharableHandle handle, GstCaps * caps, + const std::vector & 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 & 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 & 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; } diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.h index ea7ba1314c..38e8529b3e 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipc.h @@ -134,26 +134,30 @@ bool gst_cuda_ipc_pkt_build_have_data (std::vector & buf, GstClockTime pts, const GstVideoInfo & info, const CUipcMemHandle & handle, - GstCaps * caps); + GstCaps * caps, + const std::vector & meta); bool gst_cuda_ipc_pkt_parse_have_data (const std::vector & buf, GstClockTime & pts, GstCudaIpcMemLayout & layout, CUipcMemHandle & handle, - GstCaps ** caps); + GstCaps ** caps, + std::vector & meta); bool gst_cuda_ipc_pkt_build_have_mmap_data (std::vector & buf, GstClockTime pts, const GstVideoInfo & info, guint32 max_size, GstCudaSharableHandle handle, - GstCaps * caps); + GstCaps * caps, + const std::vector & meta); bool gst_cuda_ipc_pkt_parse_have_mmap_data (const std::vector & buf, GstClockTime & pts, GstCudaIpcMemLayout & layout, GstCudaSharableHandle * handle, - GstCaps ** caps); + GstCaps ** caps, + std::vector & meta); void gst_cuda_ipc_pkt_build_read_done (std::vector & buf); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.cpp index 089d47e6ea..45d9c0bfc9 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.cpp @@ -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); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.h index 28a48b779b..00a56f5f0e 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient.h @@ -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 & meta); void gst_cuda_ipc_client_on_idle (GstCudaIpcClient * client); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_unix.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_unix.cpp index 0c4c59f4bb..0e2a8c2d71 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_unix.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_unix.cpp @@ -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: diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_win32.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_win32.cpp index 1735fdfede..a609cc8c59 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_win32.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcclient_win32.cpp @@ -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: diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.cpp index 64b6d8a2a5..5d0f616391 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.cpp @@ -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); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.h index d759638a85..ae0f6c61fb 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcserver.h @@ -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 meta; guint64 seq_num; }; diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcsink.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcsink.cpp index 8b82411920..cb4420050b 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcsink.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstcudaipcsink.cpp @@ -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; diff --git a/subprojects/gst-plugins-bad/tests/examples/nvcodec/cudaipc.c b/subprojects/gst-plugins-bad/tests/examples/nvcodec/cudaipc.c new file mode 100644 index 0000000000..0583ae0402 --- /dev/null +++ b/subprojects/gst-plugins-bad/tests/examples/nvcodec/cudaipc.c @@ -0,0 +1,189 @@ +/* GStreamer + * Copyright (C) 2024 Seungha Yang + * + * 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 +#endif + +#include + +#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; +} diff --git a/subprojects/gst-plugins-bad/tests/examples/nvcodec/meson.build b/subprojects/gst-plugins-bad/tests/examples/nvcodec/meson.build index 2bd4cb95b1..0c02e8647e 100644 --- a/subprojects/gst-plugins-bad/tests/examples/nvcodec/meson.build +++ b/subprojects/gst-plugins-bad/tests/examples/nvcodec/meson.build @@ -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) +