LibMISB/Examples/Example Application
Example Application
This application comes from the other usage applications, but applied in an scenario where you want to codify some information, then a binary file that will be used as the input for a GStreamer application, and then stream the information over UDP by setting a IP Address and a port, to finally get the information in another GStreamer pipeline in a different terminal, using the network port set in the the execution of the GStreamer application.
Here is a graph of the generation of the coded binary file and the streaming process for a embeded metadata over a transport stream.
Links to buy RidgeRun products needed to run the example
LibMISB
GStreamer in-band metada support
The next steps will guide you to build the code and install the libraries
Libraries
Please install the following libraries:
sudo apt install -y gstreamer1.0-plugins-ugly gstreamer1.0-libav
Code
Create a file called main.c in the same place where the libmisb examples are located inside the builddir directory, the path might luck like this one:
~/your-directory/libmisb/builddir/examples/libmisb/
Then, use this code to fill out the main.c file:
/* Copyright (C) 2022 RidgeRun, LLC (http://www.ridgerun.com) * All Rights Reserved. * * The contents of this software are proprietary and confidential to RidgeRun, * LLC. No part of this program may be photocopied, reproduced or translated * into another programming language without prior written consent of * RidgeRun, LLC. The user is free to modify the source code after obtaining * a software license from RidgeRun. All source code changes must be provided * back to RidgeRun without any encumbrance. */ #include <glib.h> #include <glib-unix.h> #include <gst/gst.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #define METADATA_PERIOD_SECS 1 #define FILE_LOCATION "./metadata_misb_library.ts" static guint8 klv_metadata[61]; //const char* filename = "<PATH>/klv.bin"; const char* filename = "klv.bin"; typedef struct _GstMetaDemo GstMetaDemo; struct _GstMetaDemo { GstElement *pipeline; GstElement *metasrc; GstElement *filesink; GMainLoop *main_loop; }; static gboolean create_pipeline(GstMetaDemo *metademo, const char *ip, const char *port); static void start_pipeline(GstMetaDemo *metademot); static void stop_pipeline(GstMetaDemo *metademo); static void release_resources(GstMetaDemo *metademo); static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data); static gboolean handle_signal(gpointer data); int is_valid_ip(const char *ip) { struct sockaddr_in sa; return inet_pton(AF_INET, ip, &(sa.sin_addr)) != 0; } int is_valid_port(const char *port) { char *endptr; long port_num = strtol(port, &endptr, 10); // Check for conversion errors or if the number is out of valid port range return *endptr == '\0' && port_num > 0 && port_num <= 65535; } int main(int argc, char *argv[]) { struct stat sb; const char *ip = argv[1]; const char *port = argv[2]; printf("IP: %s\n", ip); printf("IP: %s\n", port); FILE* in_file = fopen(filename, "rb"); if (!in_file) { perror("fopen"); exit(EXIT_FAILURE); } if (stat(filename, &sb) == -1) { perror("stat"); exit(EXIT_FAILURE); } fread(klv_metadata, sizeof(klv_metadata), 1, in_file); for(uint i = 0; i<sizeof(klv_metadata); i++) printf("%u ", klv_metadata[i]); printf("\n"); fclose(in_file); GstMetaDemo *metademo = g_malloc(sizeof(GstMetaDemo)); if(!metademo){ g_print("Could not create demo\n"); return 1; } g_unix_signal_add(SIGINT, (GSourceFunc)handle_signal, metademo); /* Initialization */ gst_init(&argc, &argv); if (argc != 3) { fprintf(stderr, "Usage: %s <IP address> <Port number>\n", argv[0]); return 1; } if (!is_valid_ip(ip) && !is_valid_port(port)) { g_print("Invalid IP address or port number!\n"); g_print("Usage: %s <IP address> <Port number>\n", argv[0]); } if (!create_pipeline(metademo, ip, port)) { g_free(metademo); return 1; } /* Set the pipeline to "playing" state*/ g_print("Playing pipeline\n"); start_pipeline(metademo); /* Iterate */ g_print("Running...\n"); g_main_loop_run(metademo->main_loop); /* Out of the main loop, clean up nicely */ g_print("Returned, stopping playback\n"); release_resources(metademo); return 0; } static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) { GMainLoop *loop = (GMainLoop *)data; switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg, &error, &debug); g_free(debug); g_printerr("Error: %s\n", error->message); g_error_free(error); g_main_loop_quit(loop); break; } default: break; } return TRUE; } static gboolean create_pipeline(GstMetaDemo *metademo, const char *ip, const char *port) { GMainLoop *loop; GstElement *pipeline = NULL; GstElement *metasrc = NULL; GstElement *filesink = NULL; GstBus *bus = NULL; GByteArray *barray = NULL; guint8 *array_copy = NULL; guint metalen = 0; GError *error = NULL; if (!metademo) { return FALSE; } loop = g_main_loop_new(NULL, FALSE); char actual_pipeline[] = "metasrc name=meta ! meta/x-klv,stream_type=21 ! mpegtsmux name=mux ! " "filesink name=sink location=./metadata_misb_library.ts videotestsrc " "is-live=true ! video/x-raw,width=640,height=480,framerate=30/1 ! queue ! " "x264enc ! rtph264pay ! udpsink host=%s port=%s"; char modified_pipeline[1024]; // Adjust the size accordingly // Use snprintf to format the string with the new values snprintf(modified_pipeline, sizeof(modified_pipeline), actual_pipeline, ip, port); // Now modified_pipeline contains the modified GStreamer pipeline printf("Modified pipeline: %s\n", modified_pipeline); printf("IP: %s\n", ip); printf("IP: %s\n", port); pipeline = gst_parse_launch(modified_pipeline, &error); if (error) { g_printerr("Unable to build pipeline (%s)\n", error->message); g_clear_error(&error); return FALSE; } metasrc = gst_bin_get_by_name(GST_BIN(pipeline), "meta"); if (!metasrc) { g_printerr("Could not get metadata element\n"); return FALSE; } filesink = gst_bin_get_by_name(GST_BIN(pipeline), "sink"); if (!filesink) { g_printerr("Could not get filesink element\n"); return FALSE; } /*Prepare metadata*/ /*We need to copy the array since the GByteArray will be the new owner and free it for us*/ metalen = sizeof(klv_metadata); array_copy = g_malloc (metalen); memcpy (array_copy, klv_metadata, metalen); barray = g_byte_array_new_take(array_copy, metalen); g_object_set(metasrc, "metadata-binary", barray, NULL); g_boxed_free(G_TYPE_BYTE_ARRAY, barray); g_object_set(G_OBJECT(metasrc), "period", METADATA_PERIOD_SECS, NULL); g_object_set(G_OBJECT(filesink), "location", FILE_LOCATION, NULL); /* we add a message handler */ bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); gst_bus_add_watch(bus, bus_call, loop); gst_object_unref(bus); metademo->pipeline = pipeline; metademo->main_loop = loop; metademo->metasrc = metasrc; metademo->filesink = filesink; return TRUE; } static void start_pipeline(GstMetaDemo *metademo) { gst_element_set_state(metademo->pipeline, GST_STATE_PLAYING); } static void stop_pipeline(GstMetaDemo *metademo) { gst_element_set_state(metademo->pipeline, GST_STATE_NULL); } static void release_resources(GstMetaDemo *metademo) { if (!metademo) { return; } stop_pipeline(metademo); if (metademo->pipeline) { gst_object_unref(metademo->pipeline); metademo->pipeline = NULL; } if (metademo->metasrc) { gst_object_unref(metademo->metasrc); metademo->metasrc = NULL; } if (metademo->filesink) { gst_object_unref(metademo->filesink); metademo->filesink = NULL; } if (metademo->main_loop) { g_main_loop_unref(metademo->main_loop); metademo->main_loop = NULL; } } static gboolean handle_signal(gpointer data) { GstMetaDemo *metademo = (GstMetaDemo *)data; g_main_loop_quit(metademo->main_loop); return TRUE; }
To compile this code run:
gcc -Wall main.c -o main `pkg-config --cflags --libs gstreamer-1.0`