Joshua M. Doe ec20592591 klv: add klv library, klvinject and klvinspect elements
Create as a separate library until gst-plugins-base MR124 is merged into tag
2020-02-06 13:33:56 -05:00

331 lines
8.6 KiB
C

/* GStreamer KLV Metadata Support Library
* Copyright (C) 2016-2019 Tim-Philipp Müller <tim@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:gsttagklv
* @short_description: KLV metadata support
* @title: KLV metadata support
*
* <refsect2>
* <para>
* Utility functions around KLV metadata support in GStreamer.
* </para>
* <para>
* See ITU Recommendation BT.1563-1 or SMPTE 336M for the KLV standard;
* see MISB EG 0902 (MISB Minimum Metadata Set) and other MISB standards
* and recommended practices for examples of KLV metadata local data sets
* for a variety of use cases (timestamps, GPS coordinates, speed, etc.).
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/tag/tag.h>
#include "klv.h"
/* We hide the implementation details, so that we have the option to implement
* different/more efficient storage in future (unfortunately we can't put the
* data inline with the meta allocation though since it's registered as fixed
* size, although that could probably be fixed in a backwards compatible way).
* GBytes means effectively two allocations, one for the GBytes, one for the
* data. Plus one for the KLV meta struct.
*
* For now we also assume that KLV data is always self-contained and one single
* chunk of data, but in future we may have use cases where we might want to
* relax that requirement. */
typedef struct
{
GstKLVMeta klv_meta;
GBytes *bytes;
} GstKLVMetaImpl;
GType
gst_klv_meta_api_get_type (void)
{
static volatile GType type;
static const gchar *tags[] = { NULL };
if (g_once_init_enter (&type)) {
GType _type = gst_meta_api_type_register ("GstKLVMetaAPI", tags);
g_once_init_leave (&type, _type);
}
return type;
}
static gboolean
gst_klv_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
{
GstKLVMetaImpl *impl = (GstKLVMetaImpl *) meta;
impl->bytes = NULL;
return TRUE;
}
static void
gst_klv_meta_clear (GstMeta * meta, GstBuffer * buffer)
{
GstKLVMetaImpl *impl = (GstKLVMetaImpl *) meta;
if (impl->bytes != NULL)
g_bytes_unref (impl->bytes);
}
static gboolean
gst_klv_meta_transform (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, GQuark type, gpointer data)
{
GstKLVMetaImpl *smeta;
GstKLVMeta *dmeta;
smeta = (GstKLVMetaImpl *) meta;
if (GST_META_TRANSFORM_IS_COPY (type)) {
dmeta = gst_buffer_add_klv_meta_from_bytes (dest, smeta->bytes);
if (!dmeta)
return FALSE;
} else {
return FALSE;
}
return TRUE;
}
const GstMetaInfo *
gst_klv_meta_get_info (void)
{
static const GstMetaInfo *klv_meta_info = NULL;
if (g_once_init_enter ((GstMetaInfo **) & klv_meta_info)) {
const GstMetaInfo *meta =
gst_meta_register (GST_KLV_META_API_TYPE, "GstKLVMeta",
sizeof (GstKLVMetaImpl), gst_klv_meta_init, gst_klv_meta_clear,
gst_klv_meta_transform);
g_once_init_leave ((GstMetaInfo **) & klv_meta_info, (GstMetaInfo *) meta);
}
return klv_meta_info;
}
/* Add KLV meta data to a buffer */
static GstKLVMeta *
gst_buffer_add_klv_meta_internal (GstBuffer * buffer, GBytes * bytes)
{
GstKLVMetaImpl *impl;
GstKLVMeta *meta;
gconstpointer data;
gsize size;
/* KLV coding shall use and only use a fixed 16-byte SMPTE-administered
* Universal Label, according to SMPTE 298M as Key (Rec. ITU R-BT.1653-1) */
data = g_bytes_get_data (bytes, &size);
if (size < 16 || GST_READ_UINT32_BE (data) != 0x060E2B34) {
GST_ERROR ("Trying to attach a invalid KLV meta data to buffer");
g_bytes_unref (bytes);
return NULL;
}
meta = (GstKLVMeta *) gst_buffer_add_meta (buffer, GST_KLV_META_INFO, NULL);
GST_TRACE ("Adding %u bytes of KLV data to buffer %p", (guint) size, buffer);
impl = (GstKLVMetaImpl *) meta;
impl->bytes = bytes;
return meta;
}
/**
* gst_buffer_add_klv_meta_from_data: (skip)
* @buffer: a #GstBuffer
* @data: (array length=size) (transfer none): KLV data with 16-byte KLV
* Universal Label prefix
* @size: size of @data in bytes
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Does not take ownership of @data.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_from_data (GstBuffer * buffer, const guint8 * data,
gsize size)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (data != NULL && size > 16, NULL);
return gst_buffer_add_klv_meta_internal (buffer, g_bytes_new (data, size));
}
/**
* gst_buffer_add_klv_meta_take_data: (skip)
* @buffer: a #GstBuffer
* @data: (array length=size) (transfer full): KLV data with 16-byte KLV
* Universal Label prefix
* @size: size of @data in bytes
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Take ownership of @data.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_take_data (GstBuffer * buffer, guint8 * data,
gsize size)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (data != NULL && size > 16, NULL);
return gst_buffer_add_klv_meta_internal (buffer, g_bytes_new_take (data,
size));
}
/**
* gst_buffer_add_klv_meta_from_bytes:
* @buffer: a #GstBuffer
* @bytes: (transfer none): KLV data with 16-byte KLV Universal Label prefix
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Does not take ownership of @bytes, you will need to unref @bytes.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_from_bytes (GstBuffer * buffer, GBytes * bytes)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
return gst_buffer_add_klv_meta_internal (buffer, g_bytes_ref (bytes));
}
/**
* gst_buffer_add_klv_meta_take_bytes:
* @buffer: a #GstBuffer
* @bytes: (transfer full): KLV data with 16-byte KLV Universal Label prefix
*
* Attaches #GstKLVMeta metadata to @buffer with the given parameters,
* Takes ownership of @bytes.
*
* Returns: (transfer none): the #GstKLVMeta on @buffer.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_add_klv_meta_take_bytes (GstBuffer * buffer, GBytes * bytes)
{
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
return gst_buffer_add_klv_meta_internal (buffer, bytes);
}
/* Get KLV meta data from a buffer */
/**
* gst_buffer_get_klv_meta:
* @buffer: a #GstBuffer
*
* Returns: a #GstKLVMeta on the buffer, or %NULL if the buffer has none.
*
* Since: 1.16
*/
GstKLVMeta *
gst_buffer_get_klv_meta (GstBuffer * buffer)
{
return (GstKLVMeta *) gst_buffer_get_meta (buffer, GST_KLV_META_API_TYPE);
}
/**
* gst_klv_meta_get_data: (skip)
* @klv_meta: a #GstKLVMeta
* @size: the size of the returned data in bytes.
*
* Returns: (transfer none): the KLV data
*
* Since: 1.16
*/
const guint8 *
gst_klv_meta_get_data (GstKLVMeta * klv_meta, gsize * size)
{
GstKLVMetaImpl *impl;
g_return_val_if_fail (klv_meta != NULL, NULL);
g_return_val_if_fail (size != NULL, NULL);
impl = (GstKLVMetaImpl *) klv_meta;
return g_bytes_get_data (impl->bytes, size);
}
/**
* gst_klv_meta_get_bytes:
* @klv_meta: a #GstKLVMeta
*
* Returns: (transfer none): the KLV data as a #GBytes
*
* Since: 1.16
*/
GBytes *
gst_klv_meta_get_bytes (GstKLVMeta * klv_meta)
{
GstKLVMetaImpl *impl;
g_return_val_if_fail (klv_meta != NULL, NULL);
impl = (GstKLVMetaImpl *) klv_meta;
return impl->bytes;
}
/* Boxed type, so bindings can use the API */
static gpointer
gst_klv_meta_copy_boxed (gpointer boxed)
{
GstKLVMetaImpl *impl = boxed;
GstKLVMetaImpl *copy;
copy = g_new (GstKLVMetaImpl, 1);
copy->bytes = impl->bytes ? g_bytes_ref (impl->bytes) : NULL;
return copy;
}
static void
gst_klv_meta_free_boxed (gpointer boxed)
{
GstKLVMetaImpl *impl = boxed;
if (impl->bytes)
g_bytes_unref (impl->bytes);
g_free (impl);
}
G_DEFINE_BOXED_TYPE (GstKLVMeta, gst_klv_meta, gst_klv_meta_copy_boxed,
gst_klv_meta_free_boxed);