267
edits
No edit summary |
No edit summary |
||
Line 29: | Line 29: | ||
./misb-converter --decode -i klv.bin -o output.json | ./misb-converter --decode -i klv.bin -o output.json | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Reference application == | |||
In the following example, we show you how to use Gstreamer In-Band metadata to add a KLV packet (generated by MISB Library) into a Transport Stream. Based on [https://developer.ridgerun.com/wiki/index.php/GStreamer_In-Band_Metadata_for_MPEG_Transport_Stream/Examples/_C/C%2B%2B GStreamer In-Band Metadata for MPEG Transport Stream - Examples - C - C++] | |||
<syntaxhighlight lang="C"> | |||
/* 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> | |||
#define PIPELINE_DESCRIPTION \ | |||
"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 ! mux." | |||
#define METADATA_PERIOD_SECS 1 | |||
#define FILE_LOCATION "./metadata_misb_library.ts" | |||
static guint8 klv_metadata[61]; | |||
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); | |||
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); | |||
static gboolean handle_signal(gpointer data); | |||
int main(int argc, char *argv[]) { | |||
struct stat sb; | |||
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 (!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 *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); | |||
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; | |||
} | |||
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; | |||
} | |||
</syntaxhighlight> | |||
== Building the application == | |||
In order to build the appication, copy the example into a file called '''main.c''' and build using the following command: | |||
<pre> | |||
gcc -Wall main.c -o main `pkg-config --cflags --libs gstreamer-1.0` | |||
</pre> | |||
After this you will end up with a binary called main. | |||
== Running the application == | |||
Execute the application with the following command: | |||
<pre> | |||
./main | |||
</pre> | |||
This will create a file called 'metadata_misb_library.ts''' in the same directory where the application is running. | |||
Stop the application with '''Ctrl + C'''. |
edits