GstSEIMetadata - Examples - C Example
GstSEIMetadata |
---|
GstSEIMetadata Basics |
Getting Started |
User Guide |
Examples |
Performance |
Contact Us |
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
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);
- 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:
GST_DEBUG="2,*obu*:MEMDUMP" ./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.