GstSEIMetadata - Examples - C Example

From RidgeRun Developer Connection
Jump to: navigation, search


Previous: Examples/Using Gstd Index Next: Performance




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=1 ! 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"

/*
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). 
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,
};

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(klv_metadata);
  barray = g_byte_array_new_take(klv_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=1 ! 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

/*
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). 
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,
};

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(klv_metadata);
15   barray = g_byte_array_new_take(klv_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.


Previous: Examples/Using Gstd Index Next: Performance