LibMISB/Examples/Example Application: Difference between revisions

From RidgeRun Developer Wiki
No edit summary
 
(32 intermediate revisions by 3 users not shown)
Line 1: Line 1:
===Example Application===
<noinclude>
{{LibMISB/Head|previous=Examples/GStreamer_Application|next=Evaluating|metakeywords=}}
</noinclude>


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.
==Example Application==
 
This application is based on the previous examples, but applied in an scenario where you want to encode the metadata in a JSON file and use it as input for a GStreamer application, and then, stream the information over UDP by setting an 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.
Here is a graph of the generation of the coded binary file and the streaming process for a embeded metadata over a transport stream.


[[Image:Create a binary file.jpg|thumb|center|900px]]
[[Image:Create_a_binary_file_2.jpg|thumb|center|900px]]
<div style="text-align: center;">'''Figure 1'''. Example flow diagram.</div>
<div style="text-align: center;">'''Figure 1'''. Example flow diagram.</div>


==== Links to buy RidgeRun products needed to run the example ====
<u>'''Links to buy RidgeRun products needed to run the example:'''</u>


[https://shop.ridgerun.com/products/libmisb LibMISB ] </br>
[https://shop.ridgerun.com/products/libmisb LibMISB ] </br>
Line 19: Line 23:
Please install the following libraries:
Please install the following libraries:
<pre>
<pre>
sudo apt install -y gstreamer1.0-plugins-ugly gstreamer1.0-libav
sudo apt install -y gstreamer1.0-plugins-ugly gstreamer1.0-plugins-bad gstreamer1.0-libav libglib2.0-dev
</pre>
</pre>


===Code===
===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:
Create a file called libmisb_app.cpp which contains the following code:
 
<pre>
~/your-directory/libmisb/builddir/examples/libmisb/
</pre>
 
Then, use this code to fill out the main.c file:


<syntaxhighlight lang="C">
<syntaxhighlight lang="C">
/* Copyright (C) 2022 RidgeRun, LLC (http://www.ridgerun.com)
/* Copyright (C) 2023 RidgeRun, LLC (http://www.ridgerun.com)
  * All Rights Reserved.
  * All Rights Reserved.
  *
  *
Line 51: Line 49:
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <iostream>
#include <string>
#include <libmisb/libmisb.hpp>
#include "libmisb/formatter/jsonformatter.hpp"


#include <arpa/inet.h>
#include <arpa/inet.h>


#define METADATA_PERIOD_SECS 1
#define METADATA_PERIOD_SECS 1
#define FILE_LOCATION "./metadata_misb_library.ts"


static guint8 klv_metadata[61];
static guint8 klv_metadata[61];
//const char* filename = "<PATH>/klv.bin";
const char* filename = "klv.bin";


typedef struct _GstMetaDemo GstMetaDemo;
typedef struct _GstMetaDemo GstMetaDemo;
Line 70: Line 68:
};
};


static gboolean create_pipeline(GstMetaDemo *metademo, const char *ip, const char *port);
static gboolean create_pipeline(GstMetaDemo *metademo, const char *ip, const char *port,
                                char *output_converter);
static void start_pipeline(GstMetaDemo *metademot);
static void start_pipeline(GstMetaDemo *metademot);
static void stop_pipeline(GstMetaDemo *metademo);
static void stop_pipeline(GstMetaDemo *metademo);
Line 90: Line 89:
}
}


int main(int argc, char *argv[]) {
std::string converter(const char *json_path){
struct stat sb;
 
   const char *ip = argv[1];
  /* Initialize MISB object*/
   const char *port = argv[2];
  std::string input_file;
  libmisb::LibMisb libmisb;
  libmisb.SetLogLevel(LIBMISB_DEBUG);
 
   std::shared_ptr<libmisb::formatter::iFormatter> json_formatter =
    std::make_shared<libmisb::formatter::JsonFormatter>();
  libmisb.SetFormatter(json_formatter);
 
   input_file = json_path;
 
  std::ifstream file(input_file);
  std::string data;
  std::stringstream buffer;


   printf("IP: %s\n", ip);
   if (file.is_open()) {
  printf("IP: %s\n", port);
    buffer << file.rdbuf();
    data = buffer.str();
    file.close();
  }


   FILE* in_file = fopen(filename, "rb");
   std::vector<unsigned char> packet_encoded = libmisb.Encode(data);
    if (!in_file) {
  if (packet_encoded.empty()) {
        perror("fopen");
    LOGGER.Log("Encode result packet is empty", LIBMISB_ERROR);
        exit(EXIT_FAILURE);
  }
    }
  std::string string_packet = "";
  std::string string_byte;


      
     for (uint i = 0; i < packet_encoded.size(); i++) {
    if (stat(filename, &sb) == -1) {
      string_byte = std::to_string(packet_encoded[i]);
        perror("stat");
      string_packet += string_byte;
        exit(EXIT_FAILURE);
      string_packet += " ";
     }
     }
    LOGGER.Log(string_packet, LIBMISB_INFO);
  return string_packet;
}


    fread(klv_metadata, sizeof(klv_metadata), 1, in_file);
int main(int argc, char *argv[]) {
  const char *ip = argv[1];
  const char *port = argv[2];
  const char *json_path = argv[3];


    for(uint i = 0; i<sizeof(klv_metadata); i++)
  printf("IP: %s\n", ip);
        printf("%u ", klv_metadata[i]);
  printf("Port: %s\n", port);
    printf("\n");
  printf("JSON Path: %s\n", json_path);
    fclose(in_file);


   GstMetaDemo *metademo = g_malloc(sizeof(GstMetaDemo));
   GstMetaDemo *metademo = static_cast<GstMetaDemo*>(g_malloc(sizeof(GstMetaDemo)));
   if(!metademo){
   if(!metademo){
     g_print("Could not create demo\n");
     g_print("Could not create demo\n");
Line 128: Line 148:
   gst_init(&argc, &argv);
   gst_init(&argc, &argv);


   if (argc != 3) {
   if (argc != 4) {
     fprintf(stderr, "Usage: %s <IP address> <Port number>\n", argv[0]);
     fprintf(stderr, "Usage: %s <IP address> <Port number> <JSON file path>\n", argv[0]);
     return 1;
     return 1;
   }
   }
Line 135: Line 155:
   if (!is_valid_ip(ip) && !is_valid_port(port)) {
   if (!is_valid_ip(ip) && !is_valid_port(port)) {
     g_print("Invalid IP address or port number!\n");
     g_print("Invalid IP address or port number!\n");
     g_print("Usage: %s <IP address> <Port number>\n", argv[0]);
     g_print("Usage: %s <IP address> <Port number> <JSON file path>\n", argv[0]);
   }
   }
   if (!create_pipeline(metademo, ip, port)) {
 
  std::string string_converter = converter(json_path);
  const int length = string_converter.length();
  char* output_converter = new char[length + 1];
 
  strcpy(output_converter, string_converter.c_str());
   if (!create_pipeline(metademo, ip, port, output_converter)) {
     g_free(metademo);
     g_free(metademo);
     return 1;
     return 1;
Line 187: Line 214:
}
}


static gboolean create_pipeline(GstMetaDemo *metademo, const char *ip, const char *port) {
static gboolean create_pipeline(GstMetaDemo *metademo, const char *ip, const char *port, char *output_converter ) {


   GMainLoop *loop;
   GMainLoop *loop;
Line 206: Line 233:
   loop = g_main_loop_new(NULL, FALSE);
   loop = g_main_loop_new(NULL, FALSE);


   char actual_pipeline[] = "metasrc name=meta ! meta/x-klv,stream_type=21 ! mpegtsmux name=mux ! "
   char actual_pipeline[] = "metasrc period=1 metadata='%s' ! meta/x-klv ! mpegtsmux name=mux ! "
                            "filesink name=sink location=./metadata_misb_library.ts videotestsrc "
                      "udpsink host=%s port=%s videotestsrc is-live=true ! "
                            "is-live=true ! video/x-raw,width=640,height=480,framerate=30/1 ! queue ! "
                      "video/x-raw,format=(string)I420,width=320,height=240,framerate=(fraction)30/1 ! x264enc ! mux.";
                            "x264enc ! rtph264pay ! udpsink host=%s port=%s";


   char modified_pipeline[1024]; // Adjust the size accordingly
   char modified_pipeline[1024];


   // Use snprintf to format the string with the new values
   // Use snprintf to format the string with the new values
   snprintf(modified_pipeline, sizeof(modified_pipeline), actual_pipeline, ip, port);
  output_converter[strlen(output_converter) - 1] = '\0';
   snprintf(modified_pipeline, sizeof(modified_pipeline), actual_pipeline, output_converter, ip, port);


   // Now modified_pipeline contains the modified GStreamer pipeline
   // 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);
   pipeline = gst_parse_launch(modified_pipeline, &error);


Line 226: Line 249:
     g_printerr("Unable to build pipeline (%s)\n", error->message);
     g_printerr("Unable to build pipeline (%s)\n", error->message);
     g_clear_error(&error);
     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;
     return FALSE;
   }
   }
Line 245: Line 256:
   /*We need to copy the array since the GByteArray will be the new owner and free it for us*/
   /*We need to copy the array since the GByteArray will be the new owner and free it for us*/
   metalen = sizeof(klv_metadata);
   metalen = sizeof(klv_metadata);
   array_copy = g_malloc (metalen);
   array_copy = static_cast<guint8*>(g_malloc(metalen));
   memcpy (array_copy, klv_metadata, metalen);
   memcpy (array_copy, klv_metadata, metalen);
    
    
Line 253: Line 264:


   g_object_set(G_OBJECT(metasrc), "period", METADATA_PERIOD_SECS, NULL);
   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 */
   /* we add a message handler */
Line 310: Line 320:
   return TRUE;
   return TRUE;
}
}
</syntaxhighlight>
</syntaxhighlight>


To compile this code run:
To compile this code run (the file is called libmisb_app.cpp in this example):
<pre>
<pre>
gcc -Wall main.c -o main `pkg-config --cflags --libs gstreamer-1.0`
g++ libmisb_app.cpp -o libmisb_app `pkg-config gstreamer-1.0 --cflags --libs glib-2.0 misb-0.0`
</pre>
</pre>


===How to execute the application===
===How to execute the application===


1. Execute the code to create the binary file to be streamed from the JSON file </br>
1. Open a terminal to run the GStreamer pipeline that will get the stream remotely from the application. </br>
1.1 Go to the same working directory where you created the main.c file.
Run this command:
1.2 Run this command:
<pre>
./misb-converter --verbose --encode -i misb_ST0601_sample.json -o klv.bin
</pre>
 
2. Open a terminal to run the GStreamer pipeline who will get the streaming from the application
2.1 Run this command:
<pre>
<pre>
gst-launch-1.0 udpscr port=5000 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" ! rtph254depay ! decodebin ! videoconvert ! autovideosink
gst-launch-1.0 -e udpsrc port=5000 ! 'video/mpegts, systemstream=(boolean)true, packetsize=(int)188' ! tsdemux name=demux demux. ! queue !  h264parse ! 'video/x-h264, stream-format=byte-stream, alignment=au' ! openh264dec ! autovideosink sync=false demux. ! queue ! 'meta/x-klv' ! metasink async=false
</pre>
</pre>


3. Open a different terminal to run the GStreamer application.
2. Open a different terminal to run the GStreamer application. </br>
3.1. To run it you must provide an IP address and port, for default we recommend to use 127.0.0.1 for the IP address, and 5000 for the port. The command to run it is:
To run it you must provide an IP address, port and the JSON file path where that you want to encode and send through the streaming, for default we recommend to use 127.0.0.1 for the IP address, and 5000 for the port. The command to run it is:
<pre>
<pre>
./main 127.0.0.1 5000
./libmisb_app 127.0.0.1 5000 misb_ST0601_sample.json
</pre>
</pre>


Line 344: Line 348:
<div style="text-align: center;">'''Figure 1'''. Video test source pattern.</div>
<div style="text-align: center;">'''Figure 1'''. Video test source pattern.</div>


If that is the case, congrats, you succesfully finished this guide.
[[Image:Screenshot from 2023-11-28 09-20-02.png|thumb|center|900px]]
<div style="text-align: center;">'''Figure 2'''. Output of the video and the commands output.</div>
 
As you can see in the left, you will find the encoded data streamed. To decode this data you can use the code in the extra section of this wiki. That code code will decode the file and create a file with an extension .bin, then you can decode that binary to get the JSON file by using the libmisb decoder.
 
If that is the case, congrats, you successfully finished this guide.
 
===Extra code===
 
<syntaxhighlight lang="C">
 
/* Copyright (C) 2023 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 <stdio.h>
#include <stdlib.h>
 
void printUsage() {
    printf("Usage: ./decoder -n <name_of_file> decimal_values...\n");
}
 
int main(int argc, char *argv[]) {
    if (argc < 4 || strcmp(argv[1], "-n") != 0) {
        // Incorrect number of arguments or missing -n flag
        printUsage();
        return 1;
    }
 
    char *outputFileName = argv[2];
    FILE *outputFile = fopen(outputFileName, "wb");
 
    if (outputFile == NULL) {
        perror("Error opening output file");
        return 1;
    }
 
    // Parse and write decimal values to binary file
    for (int i = 3; i < argc; i++) {
        int decimalValue = atoi(argv[i]);
        fputc(decimalValue, outputFile);
    }
 
    fclose(outputFile);
 
    printf("Conversion successful. Output file: %s\n", outputFileName);
 
    return 0;
}
</syntaxhighlight>
 
Save the file as decoder.c and then you can compile the code by using:
<pre>
gcc decoder.c -o decoder
</pre>
 
The usage is the following:
<pre>
decoder -n <name_of_binary_output.bin> <group of decimal values representation>
</pre>
 
Example:
<pre>
./decoder -n output.bin 6 14 43 52 2 11 1 1 14 1 3 1 1 0 0 0 44 2 8 0 4 89 249 174 32 34 168 3 9 77 73 83 83 73 79 78 48 49 4 6 65 70 45 49 48 49 5 2 113 194 15 2 194 33 65 1 17 1 2 164 125
</pre>
 
This will create a file called output.bin, to create the JSON file you can use:
<pre>
./misb-converter --decode -i output.bin -o output.json
</pre>
 
<noinclude>{{LibMISB/Foot|Examples/GStreamer_Application|Evaluating}}</noinclude>

Latest revision as of 14:47, 11 July 2024



Previous: Examples/GStreamer_Application Index Next: Evaluating





Example Application

This application is based on the previous examples, but applied in an scenario where you want to encode the metadata in a JSON file and use it as input for a GStreamer application, and then, stream the information over UDP by setting an 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.

Figure 1. Example flow diagram.

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-plugins-bad gstreamer1.0-libav libglib2.0-dev

Code

Create a file called libmisb_app.cpp which contains the following code:

/* Copyright (C) 2023 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 <iostream>
#include <string>
#include <libmisb/libmisb.hpp>
#include "libmisb/formatter/jsonformatter.hpp"

#include <arpa/inet.h>

#define METADATA_PERIOD_SECS 1

static guint8 klv_metadata[61];

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, 
                                char *output_converter);
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;
}

std::string converter(const char *json_path){

  /* Initialize MISB object*/
  std::string input_file;
  libmisb::LibMisb libmisb;
  libmisb.SetLogLevel(LIBMISB_DEBUG);

  std::shared_ptr<libmisb::formatter::iFormatter> json_formatter =
    std::make_shared<libmisb::formatter::JsonFormatter>();
  libmisb.SetFormatter(json_formatter);

  input_file = json_path;
  
  std::ifstream file(input_file);
  std::string data;
  std::stringstream buffer;

  if (file.is_open()) {
    buffer << file.rdbuf();
    data = buffer.str();
    file.close();
  }

  std::vector<unsigned char> packet_encoded = libmisb.Encode(data);
  if (packet_encoded.empty()) {
    LOGGER.Log("Encode result packet is empty", LIBMISB_ERROR);
  }
  std::string string_packet = "";
  std::string string_byte;

    for (uint i = 0; i < packet_encoded.size(); i++) {
      string_byte = std::to_string(packet_encoded[i]);
      string_packet += string_byte;
      string_packet += " ";
    }
    LOGGER.Log(string_packet, LIBMISB_INFO);
  return string_packet;
}

int main(int argc, char *argv[]) {
  const char *ip = argv[1];
  const char *port = argv[2];
  const char *json_path = argv[3];

  printf("IP: %s\n", ip);
  printf("Port: %s\n", port);
  printf("JSON Path: %s\n", json_path);

  GstMetaDemo *metademo = static_cast<GstMetaDemo*>(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 != 4) {
    fprintf(stderr, "Usage: %s <IP address> <Port number> <JSON file path>\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> <JSON file path>\n", argv[0]);
  }

  std::string string_converter = converter(json_path); 
  const int length = string_converter.length(); 
  char* output_converter = new char[length + 1]; 

  strcpy(output_converter, string_converter.c_str()); 
 
  if (!create_pipeline(metademo, ip, port, output_converter)) {
    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, char *output_converter ) {

  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 period=1 metadata='%s' ! meta/x-klv ! mpegtsmux name=mux ! "
                      "udpsink host=%s port=%s videotestsrc is-live=true ! "
                      "video/x-raw,format=(string)I420,width=320,height=240,framerate=(fraction)30/1 ! x264enc ! mux.";

  char modified_pipeline[1024];

  // Use snprintf to format the string with the new values
  output_converter[strlen(output_converter) - 1] = '\0';
  snprintf(modified_pipeline, sizeof(modified_pipeline), actual_pipeline, output_converter, ip, port);

  // Now modified_pipeline contains the modified GStreamer pipeline
  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;
  }

  /*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 = static_cast<guint8*>(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);

  /* 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 (the file is called libmisb_app.cpp in this example):

g++ libmisb_app.cpp -o libmisb_app `pkg-config gstreamer-1.0 --cflags --libs glib-2.0 misb-0.0`

How to execute the application

1. Open a terminal to run the GStreamer pipeline that will get the stream remotely from the application.
Run this command:

gst-launch-1.0 -e udpsrc port=5000 ! 'video/mpegts, systemstream=(boolean)true, packetsize=(int)188' ! tsdemux name=demux demux. ! queue !  h264parse ! 'video/x-h264, stream-format=byte-stream, alignment=au' ! openh264dec ! autovideosink sync=false demux. ! queue ! 'meta/x-klv' ! metasink async=false

2. Open a different terminal to run the GStreamer application.
To run it you must provide an IP address, port and the JSON file path where that you want to encode and send through the streaming, for default we recommend to use 127.0.0.1 for the IP address, and 5000 for the port. The command to run it is:

./libmisb_app 127.0.0.1 5000 misb_ST0601_sample.json

Expected results

You will see a new Window with a videotestsrc pattern as this one:

Figure 1. Video test source pattern.
Figure 2. Output of the video and the commands output.

As you can see in the left, you will find the encoded data streamed. To decode this data you can use the code in the extra section of this wiki. That code code will decode the file and create a file with an extension .bin, then you can decode that binary to get the JSON file by using the libmisb decoder.

If that is the case, congrats, you successfully finished this guide.

Extra code


/* Copyright (C) 2023 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 <stdio.h>
#include <stdlib.h>

void printUsage() {
    printf("Usage: ./decoder -n <name_of_file> decimal_values...\n");
}

int main(int argc, char *argv[]) {
    if (argc < 4 || strcmp(argv[1], "-n") != 0) {
        // Incorrect number of arguments or missing -n flag
        printUsage();
        return 1;
    }

    char *outputFileName = argv[2];
    FILE *outputFile = fopen(outputFileName, "wb");

    if (outputFile == NULL) {
        perror("Error opening output file");
        return 1;
    }

    // Parse and write decimal values to binary file
    for (int i = 3; i < argc; i++) {
        int decimalValue = atoi(argv[i]);
        fputc(decimalValue, outputFile);
    }

    fclose(outputFile);

    printf("Conversion successful. Output file: %s\n", outputFileName);

    return 0;
}

Save the file as decoder.c and then you can compile the code by using:

gcc decoder.c -o decoder

The usage is the following:

decoder -n <name_of_binary_output.bin> <group of decimal values representation>

Example:

./decoder -n output.bin 6 14 43 52 2 11 1 1 14 1 3 1 1 0 0 0 44 2 8 0 4 89 249 174 32 34 168 3 9 77 73 83 83 73 79 78 48 49 4 6 65 70 45 49 48 49 5 2 113 194 15 2 194 33 65 1 17 1 2 164 125

This will create a file called output.bin, to create the JSON file you can use:

./misb-converter --decode -i output.bin -o output.json


Previous: Examples/GStreamer_Application Index Next: Evaluating