Difference between revisions of "GstSEIMetadata/Examples/C Example"

From RidgeRun Developer Connection
Jump to: navigation, search
m
 
(13 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
<noinclude>
 
<noinclude>
{{GStreamer H264 - H265 Metadata/Head|previous=Examples/Using Gstd|next=Performance|keywords=}}
+
{{GstSEIMetadata/Head|previous=Examples/Using Gstd|next=Examples/Latency Measurement Example|metakeywords=}}
 
</noinclude>
 
</noinclude>
 +
=Inserting metadata as binary using a C application=
 
The following is an example that shows how to insert metadata as binary through a C application.
 
The following is an example that shows how to insert metadata as binary through a C application.
<pre>
+
<syntaxhighlight lang="C">
 
/**
 
/**
 
   * Copyright (C) 2021 RidgeRun, LLC (http://www.ridgerun.com)
 
   * Copyright (C) 2021 RidgeRun, LLC (http://www.ridgerun.com)
Line 21: Line 22:
  
 
#define PIPELINE_DESCRIPTION                                                  \
 
#define PIPELINE_DESCRIPTION                                                  \
   "videotestsrc num-buffers=1 ! video/x-raw,width=16,height=240 ! x264enc ! video/x-h264,stream-format=avc ! "      \
+
   "videotestsrc num-buffers=10 ! video/x-raw,width=16,height=240 ! x264enc ! video/x-h264,stream-format=avc ! "      \
 
   "seiinject name=inject ! filesink name=sink location=seiinject_metadata_binary_videotestsrc_avc.h264"
 
   "seiinject name=inject ! filesink name=sink location=seiinject_metadata_binary_videotestsrc_avc.h264"
  
 
#define FILE_LOCATION "./seiinject_metadata_binary_videotestsrc_avc.h264"
 
#define FILE_LOCATION "./seiinject_metadata_binary_videotestsrc_avc.h264"
  
/*
+
static guint8 binary_metadata[] = {
KLV taken from:
+
     /*This is "Hello World!!" in hexadecimal*/
https://www.researchgate.net/figure/Example-of-a-metadata-Key-Length-Value-KLV-packet-It-is-formed-by-a-key-in-green_fig3_313416345
+
     0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x21,
 
 
Ruano, Susana & Cuevas, Carlos & Gallego, Guillermo & García, Narciso. (2017).
 
Augmented Reality Tool for the Situational Awareness Improvement of UAV Operators. Sensors.
 
17. 297. 10.3390/s17020297.
 
*/
 
static guint8 klv_metadata[] = {
 
     /*Sample KLV metadata*/
 
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
 
    0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
 
 
};
 
};
  
Line 154: Line 146:
  
 
   /*Prepare metadata*/
 
   /*Prepare metadata*/
   metalen = sizeof(klv_metadata);
+
   metalen = sizeof(binary_metadata);
   barray = g_byte_array_new_take(klv_metadata, metalen);
+
   barray = g_byte_array_new_take(binary_metadata, metalen);
 
   g_object_set(seiinject, "metadata-binary", barray, NULL);
 
   g_object_set(seiinject, "metadata-binary", barray, NULL);
 
   g_boxed_free(G_TYPE_BYTE_ARRAY, barray);
 
   g_boxed_free(G_TYPE_BYTE_ARRAY, barray);
Line 216: Line 208:
 
   return TRUE;
 
   return TRUE;
 
}
 
}
</pre>
+
</syntaxhighlight>
 +
 
 
== Application Walk-through ==  
 
== Application Walk-through ==  
  
Line 225: Line 218:
 
<syntaxhighlight lang="C" highlight="3">
 
<syntaxhighlight lang="C" highlight="3">
 
#define PIPELINE_DESCRIPTION                                                  \
 
#define PIPELINE_DESCRIPTION                                                  \
   "videotestsrc num-buffers=1 ! video/x-raw,width=16,height=240 ! x264enc ! video/x-h264,stream-format=avc ! "      \
+
   "videotestsrc num-buffers=10 ! video/x-raw,width=16,height=240 ! x264enc ! video/x-h264,stream-format=avc ! "      \
 
   "seiinject name=inject ! filesink name=sink location=seiinject_metadata_binary_videotestsrc_avc.h264"
 
   "seiinject name=inject ! filesink name=sink location=seiinject_metadata_binary_videotestsrc_avc.h264"
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 234: Line 227:
  
 
<syntaxhighlight lang="C">
 
<syntaxhighlight lang="C">
/*
 
KLV taken from:
 
https://www.researchgate.net/figure/Example-of-a-metadata-Key-Length-Value-KLV-packet-It-is-formed-by-a-key-in-green_fig3_313416345
 
  
Ruano, Susana & Cuevas, Carlos & Gallego, Guillermo & García, Narciso. (2017).
+
static guint8 binary_metadata[] = {
Augmented Reality Tool for the Situational Awareness Improvement of UAV Operators. Sensors.
+
     /*This is "Hello World!!" in hexadecimal*/
17. 297. 10.3390/s17020297.
+
     0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x21,
*/
 
static guint8 klv_metadata[] = {
 
     /*Sample KLV metadata*/
 
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
 
    0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
 
 
};
 
};
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 267: Line 252:
  
 
   /*Prepare metadata*/
 
   /*Prepare metadata*/
   metalen = sizeof(klv_metadata);
+
   metalen = sizeof(binary_metadata);
   barray = g_byte_array_new_take(klv_metadata, metalen);
+
   barray = g_byte_array_new_take(binary_metadata, metalen);
 
   g_object_set(seiinject, "metadata-binary", barray, NULL);
 
   g_object_set(seiinject, "metadata-binary", barray, NULL);
 
   g_boxed_free(G_TYPE_BYTE_ARRAY, barray);
 
   g_boxed_free(G_TYPE_BYTE_ARRAY, barray);
Line 296: Line 281:
  
 
This will create a file called '''seiinject_metadata_binary_videotestsrc_avc.h264''' in the same directory where the application is running.
 
This will create a file called '''seiinject_metadata_binary_videotestsrc_avc.h264''' in the same directory where the application is running.
 +
 +
To check the data was inserted correctly you can run:
 +
<pre>
 +
GST_DEBUG=*seiextract*:MEMDUMP gst-launch-1.0 filesrc location=seiinject_metadata_binary_videotestsrc_avc.h264 ! video/x-h264,stream-format=avc ! seiextract ! fakesink
 +
</pre>
 +
And you will see something like this:
 +
<pre>
 +
Setting pipeline to PAUSED ...
 +
Pipeline is PREROLLING ...
 +
0:00:00.017574482  7940 0x55ba08c160a0 DEBUG            seiextract gstseiextract.c:251:gst_sei_extract_set_caps:<seiextract0> set_caps
 +
0:00:00.017615098  7940 0x55ba08c160a0 DEBUG            seiextract gstseiextract.c:257:gst_sei_extract_set_caps: parsing caps: video/x-h264, stream-format=(string)avc
 +
0:00:00.017748013  7940 0x55ba08c160a0 LOG              seiextract gstseiextract.c:295:gst_sei_extract_prepare_output_buffer:<seiextract0> prepare_output_buffer
 +
0:00:00.017781023  7940 0x55ba08c160a0 LOG              seiextract gstseiextract.c:345:gst_sei_extract_prepare_output_buffer:<seiextract0> Not the expected payload type: 5
 +
 +
0:00:00.017789475  7940 0x55ba08c160a0 LOG              seiextract gstseiextract.c:352:gst_sei_extract_prepare_output_buffer:<seiextract0> The extracted data is: Hello World!!
 +
...
 +
</pre>
 +
Where you can see the "Hello World!!" message we inserted as binary.
  
 
<noinclude>
 
<noinclude>
{{GStreamer H264 - H265 Metadata/Foot|Examples/Using Gstd|Performance}}
+
{{GstSEIMetadata/Foot|Examples/Using Gstd|Examples/Latency Measurement Example}}
 
</noinclude>
 
</noinclude>

Latest revision as of 12:57, 7 March 2023


Previous: Examples/Using Gstd Index Next: Examples/Latency Measurement Example




Inserting metadata as binary using a C application

The following is an example that shows how to insert metadata as binary through a C application.

/**
  * Copyright (C) 2021 RidgeRun, LLC (http://www.ridgerun.com)
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License version 2 as
  * published by the Free Software Foundation.
  */

#include <glib.h>
#include <glib-unix.h>
#include <gst/gst.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PIPELINE_DESCRIPTION                                                   \
  "videotestsrc num-buffers=10 ! video/x-raw,width=16,height=240 ! x264enc ! video/x-h264,stream-format=avc ! "      \
  "seiinject name=inject ! filesink name=sink location=seiinject_metadata_binary_videotestsrc_avc.h264"

#define FILE_LOCATION "./seiinject_metadata_binary_videotestsrc_avc.h264"

static guint8 binary_metadata[] = {
    /*This is "Hello World!!" in hexadecimal*/
    0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x21,
};

typedef struct _GstMetaDemo GstMetaDemo;
struct _GstMetaDemo {
  GstElement *pipeline;
  GstElement *seiinject;
  GstElement *filesink;
  GMainLoop *main_loop;
};

static gboolean create_pipeline(GstMetaDemo *metademo);
static void start_pipeline(GstMetaDemo *metademo);
static void stop_pipeline(GstMetaDemo *metademo);
static void release_resources(GstMetaDemo *metademo);
static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data);

int main(int argc, char *argv[]) {

  GstMetaDemo *metademo = g_malloc(sizeof(GstMetaDemo));
  if(!metademo){
    g_print("Could not create demo\n");
    return 1;
  }

  /* Initialization */
  gst_init(&argc, &argv);

  if (!create_pipeline(metademo)) {
    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) {

  GMainLoop *loop;

  GstElement *pipeline = NULL;
  GstElement *seiinject = NULL;
  GstElement *filesink = NULL;
  GstBus *bus = NULL;
  GByteArray *barray = NULL;
  guint metalen = 0;
  GError *error = NULL;

  if (!metademo) {
    return FALSE;
  }

  loop = g_main_loop_new(NULL, FALSE);

  pipeline = gst_parse_launch(PIPELINE_DESCRIPTION, &error);

  if (error) {
    g_printerr("Unable to build pipeline (%s)\n", error->message);
    g_clear_error(&error);
    return FALSE;
  }

  seiinject = gst_bin_get_by_name(GST_BIN(pipeline), "inject");
  if (!seiinject) {
    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*/
  metalen = sizeof(binary_metadata);
  barray = g_byte_array_new_take(binary_metadata, metalen);
  g_object_set(seiinject, "metadata-binary", barray, NULL);
  g_boxed_free(G_TYPE_BYTE_ARRAY, barray);

  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->seiinject = seiinject;
  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->seiinject) {
    gst_object_unref(metademo->seiinject);
    metademo->seiinject = 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;
}

Application Walk-through

This is a quick walk-trough to better understand the process of creating the pipeline and injecting the metadata in the previous example.

Pipeline description

#define PIPELINE_DESCRIPTION                                                   \
  "videotestsrc num-buffers=10 ! video/x-raw,width=16,height=240 ! x264enc ! video/x-h264,stream-format=avc ! "      \
  "seiinject name=inject ! filesink name=sink location=seiinject_metadata_binary_videotestsrc_avc.h264"

As seen above, all we need to inject the metadata is the seiinject element, which will take the provided metadata, inject it into the encoded stream and then store it in the file seiinject_metadata_binary_videotestsrc_avc.h264

Metadata packet

static guint8 binary_metadata[] = {
    /*This is "Hello World!!" in hexadecimal*/
    0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x21,
};

Note that this could have been any array of bytes, the above one is just an example.

Metadata injection

 1   seiinject = gst_bin_get_by_name(GST_BIN(pipeline), "inject");
 2   if (!seiinject) {
 3     g_printerr("Could not get metadata element\n");
 4     return FALSE;
 5   }
 6 
 7   filesink = gst_bin_get_by_name(GST_BIN(pipeline), "sink");
 8   if (!filesink) {
 9     g_printerr("Could not get filesink element\n");
10     return FALSE;
11   }
12 
13   /*Prepare metadata*/
14   metalen = sizeof(binary_metadata);
15   barray = g_byte_array_new_take(binary_metadata, metalen);
16   g_object_set(seiinject, "metadata-binary", barray, NULL);
17   g_boxed_free(G_TYPE_BYTE_ARRAY, barray);
18 
19   g_object_set(G_OBJECT(filesink), "location", FILE_LOCATION, NULL);
  • metadata binary: In line 16, the metadata binary is injected using the metadata-binary property.

Building the application

In order to build the appication, copy the example into a file called main.c and build using the following command:

gcc -Wall main.c -o main `pkg-config --cflags --libs gstreamer-1.0`

After this you will end up with a binary called main.

Running the application

Execute the application with the following command:

./main

This will create a file called seiinject_metadata_binary_videotestsrc_avc.h264 in the same directory where the application is running.

To check the data was inserted correctly you can run:

GST_DEBUG=*seiextract*:MEMDUMP gst-launch-1.0 filesrc location=seiinject_metadata_binary_videotestsrc_avc.h264 ! video/x-h264,stream-format=avc ! seiextract ! fakesink

And you will see something like this:

Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
0:00:00.017574482  7940 0x55ba08c160a0 DEBUG             seiextract gstseiextract.c:251:gst_sei_extract_set_caps:<seiextract0> set_caps
0:00:00.017615098  7940 0x55ba08c160a0 DEBUG             seiextract gstseiextract.c:257:gst_sei_extract_set_caps: parsing caps: video/x-h264, stream-format=(string)avc
0:00:00.017748013  7940 0x55ba08c160a0 LOG               seiextract gstseiextract.c:295:gst_sei_extract_prepare_output_buffer:<seiextract0> prepare_output_buffer
0:00:00.017781023  7940 0x55ba08c160a0 LOG               seiextract gstseiextract.c:345:gst_sei_extract_prepare_output_buffer:<seiextract0> Not the expected payload type: 5

0:00:00.017789475  7940 0x55ba08c160a0 LOG               seiextract gstseiextract.c:352:gst_sei_extract_prepare_output_buffer:<seiextract0> The extracted data is: Hello World!!
...

Where you can see the "Hello World!!" message we inserted as binary.


Previous: Examples/Using Gstd Index Next: Examples/Latency Measurement Example