Merge branch '3485_support_pes_metadata' into 'main'

mpegtsmux: Support metadata in PES packets streams in TS

Closes #3485

See merge request gstreamer/gstreamer!6793
This commit is contained in:
Juan David Adarve 2024-05-03 21:26:56 +00:00
commit a35ac5636e
11 changed files with 290 additions and 2 deletions

View file

@ -23,6 +23,7 @@
#include "mpegts.h"
#include "gstmpegts-private.h"
#include <gst/base/gstbytewriter.h>
#define GST_CAT_DEFAULT mpegts_debug
@ -46,6 +47,46 @@ G_DEFINE_BOXED_TYPE (GstMpegtsMetadataDescriptor,
(GBoxedCopyFunc) _gst_mpegts_metadata_descriptor_copy,
(GFreeFunc) _gst_mpegts_metadata_descriptor_free);
GstMpegtsDescriptor *
gst_mpegts_descriptor_from_metadata (const GstMpegtsMetadataDescriptor *
metadata_descriptor)
{
g_return_val_if_fail (metadata_descriptor != NULL, NULL);
int wr_size = 0;
guint8 *add_info = NULL;
GstByteWriter writer;
// metadata_descriptor
gst_byte_writer_init_with_size (&writer, 32, FALSE);
gst_byte_writer_put_uint16_be (&writer,
metadata_descriptor->metadata_application_format);
if (metadata_descriptor->metadata_application_format == 0xFFFF) {
gst_byte_writer_put_uint32_be (&writer, metadata_descriptor->metadata_format_identifier); // metadata_application_format_identifier
}
gst_byte_writer_put_uint8 (&writer, metadata_descriptor->metadata_format);
if (metadata_descriptor->metadata_format ==
GST_MPEGTS_METADATA_FORMAT_IDENTIFIER_FIELD) {
gst_byte_writer_put_uint32_be (&writer, metadata_descriptor->metadata_format_identifier); // metadata_format_identifier
}
gst_byte_writer_put_uint8 (&writer, metadata_descriptor->metadata_service_id);
gst_byte_writer_put_uint8 (&writer, 0x0F); // decoder_config_flags = 000, DSM_CC_flag = 0, reserved = 1111
wr_size = gst_byte_writer_get_size (&writer);
add_info = gst_byte_writer_reset_and_get_data (&writer);
GstMpegtsDescriptor *descriptor =
gst_mpegts_descriptor_from_custom (GST_MTS_DESC_METADATA, add_info,
wr_size);
return descriptor;
}
/**
* gst_mpegts_descriptor_parse_metadata:
* @descriptor: a %GST_TYPE_MPEGTS_METADATA_DESCRIPTOR #GstMpegtsDescriptor

View file

@ -0,0 +1,92 @@
/* Gstreamer
* Copyright 2024 Juan Adarve <juanda0718@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mpegts.h"
#include "gstmpegts-private.h"
#include <gst/base/gstbytewriter.h>
#define GST_CAT_DEFAULT mpegts_debug
static GstMpegtsMetadataPointerDescriptor *
_gst_mpegts_metadata_pointer_descriptor_copy (GstMpegtsMetadataPointerDescriptor
* source)
{
GstMpegtsMetadataPointerDescriptor *copy =
g_memdup2 (source, sizeof (GstMpegtsMetadataPointerDescriptor));
return copy;
}
static void
_gst_mpegts_metadata_pointer_descriptor_free (GstMpegtsMetadataPointerDescriptor
* desc)
{
g_free (desc);
}
G_DEFINE_BOXED_TYPE (GstMpegtsMetadataPointerDescriptor,
gst_mpegts_metadata_pointer_descriptor,
(GBoxedCopyFunc) _gst_mpegts_metadata_pointer_descriptor_copy,
(GFreeFunc) _gst_mpegts_metadata_pointer_descriptor_free);
GstMpegtsDescriptor *
gst_mpegts_descriptor_from_metadata_pointer (const
GstMpegtsMetadataPointerDescriptor * metadata_pointer_descriptor)
{
g_return_val_if_fail (metadata_pointer_descriptor != NULL, NULL);
int wr_size = 0;
guint8 *add_info = NULL;
GstByteWriter writer;
// metadata_pointer_descriptor
gst_byte_writer_init_with_size (&writer, 32, FALSE);
gst_byte_writer_put_uint16_be (&writer,
metadata_pointer_descriptor->metadata_application_format);
if (metadata_pointer_descriptor->metadata_application_format == 0xFFFF) {
gst_byte_writer_put_uint32_be (&writer, metadata_pointer_descriptor->metadata_format_identifier); // metadata_application_format_identifier
}
gst_byte_writer_put_uint8 (&writer,
metadata_pointer_descriptor->metadata_format);
if (metadata_pointer_descriptor->metadata_format ==
GST_MPEGTS_METADATA_FORMAT_IDENTIFIER_FIELD) {
gst_byte_writer_put_uint32_be (&writer, metadata_pointer_descriptor->metadata_format_identifier); // metadata_format_identifier
}
gst_byte_writer_put_uint8 (&writer,
metadata_pointer_descriptor->metadata_service_id);
gst_byte_writer_put_uint8 (&writer, 0x1F); // metadata_locator_record_flag = 0, MPEG_carriage_flag = 00, reserved = 11111
gst_byte_writer_put_uint16_be (&writer, metadata_pointer_descriptor->program_number); // program_number
wr_size = gst_byte_writer_get_size (&writer);
add_info = gst_byte_writer_reset_and_get_data (&writer);
GstMpegtsDescriptor *descriptor =
gst_mpegts_descriptor_from_custom (GST_MTS_DESC_METADATA_POINTER,
add_info,
wr_size);
return descriptor;
}

View file

@ -0,0 +1,68 @@
/* Gstreamer
* Copyright 2024 Juan Adarve <juanda0718@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MPEGTS_METADATA_POINTER_DESCRIPTOR_H__
#define __GST_MPEGTS_METADATA_POINTER_DESCRIPTOR_H__
#include "gst/mpegts/gst-metadata-descriptor.h"
#include <gst/gst.h>
#include <gst/mpegts/mpegts-prelude.h>
G_BEGIN_DECLS
/* MPEG-TS Metadata Descriptor (0x25) */
typedef struct _GstMpegtsMetadataPointerDescriptor
GstMpegtsMetadataPointerDescriptor;
/**
* GstMpegtsMetadataPointerDescriptor:
* @metadata_application_format: specifies the application responsible for defining usage, syntax and semantics
* @metadata_format: indicates the format and coding of the metadata
* @metadata_format_identifier: format identifier (equivalent to registration descriptor), for example 0x4B4C4641 ('KLVA') to indicate SMPTE 336 KLV, or 0x49443320 ('ID3 ').
* @metadata_service_id: metadata service to which this metadata descriptor applies, typically 0x00
* @program_number: Indicates the program in which the metadata is carried.
*
* This structure is not complete. The following fields are missing in comparison to the standard (ISO/IEC 13818-1:2023 Section 2.6.58):
* * metadata_locator_record_flag: hardcoded to 0. Indicating no metadata_locator_record present in the descriptor.
* * MPEG_carriage_flags: hardcoded to 0b00, indicating the metadata is carried in the same transport steam.
* * metadata_locator_record_length.
* * transport_stream_location.
* * transport_stream_id.
*
* See also: gst_mpegts_descriptor_from_metadata_pointer
*
* Since: 1.24
*/
struct _GstMpegtsMetadataPointerDescriptor {
guint16 metadata_application_format;
GstMpegtsMetadataFormat metadata_format;
guint32 metadata_format_identifier;
guint8 metadata_service_id;
guint16 program_number;
};
#define GST_TYPE_MPEGTS_METADATA_POINTER_DESCRIPTOR \
(gst_mpegts_metadata_pointer_descriptor_get_type())
GST_MPEGTS_API
GType gst_mpegts_metadata_pointer_descriptor_get_type(void);
G_END_DECLS
#endif

View file

@ -33,6 +33,7 @@
#define GST_MPEGTS_DESCRIPTOR_H
#include "gst-metadata-descriptor.h"
#include "gst-metadata-pointer-descriptor.h"
#include <gst/gst.h>
#include <gst/mpegts/mpegts-prelude.h>
@ -344,6 +345,9 @@ guint gst_mpegts_descriptor_parse_iso_639_language_nb (const GstMpegtsDescriptor
GST_MPEGTS_API
GstMpegtsDescriptor * gst_mpegts_descriptor_from_iso_639_language (const gchar * language);
GST_MPEGTS_API
GstMpegtsDescriptor *gst_mpegts_descriptor_from_metadata(const GstMpegtsMetadataDescriptor *metadata_descriptor);
GST_MPEGTS_API
gboolean gst_mpegts_descriptor_parse_metadata (const GstMpegtsDescriptor *descriptor, GstMpegtsMetadataDescriptor **res);
@ -353,6 +357,9 @@ gboolean gst_mpegts_descriptor_parse_metadata_std (const GstMpegtsDescriptor *de
guint32 *metadata_buffer_size,
guint32 *metadata_output_leak_rate);
GST_MPEGTS_API
GstMpegtsDescriptor *gst_mpegts_descriptor_from_metadata_pointer(const GstMpegtsMetadataPointerDescriptor *metadata_pointer_descriptor);
/* GST_MTS_DESC_DTG_LOGICAL_CHANNEL (0x83) */
typedef struct _GstMpegtsLogicalChannelDescriptor GstMpegtsLogicalChannelDescriptor;
typedef struct _GstMpegtsLogicalChannel GstMpegtsLogicalChannel;

View file

@ -7,7 +7,8 @@ mpegts_sources = files(
'gst-atsc-section.c',
'gst-scte-section.c',
'gst-mpegtspesmetadatameta.c',
'gst-metadata-descriptor.c'
'gst-metadata-descriptor.c',
'gst-metadata-pointer-descriptor.c',
)
mpegts_headers = files(
@ -22,6 +23,7 @@ mpegts_headers = files(
'gst-isdb-descriptor.h',
'gst-mpegtspesmetadatameta.h',
'gst-metadata-descriptor.h',
'gst-metadata-pointer-descriptor.h',
'mpegts-prelude.h',
'mpegts.h',
)
@ -47,7 +49,7 @@ gstmpegts = library('gstmpegts-' + api_version,
soversion : soversion,
darwin_versions : osxversion,
install : true,
dependencies : [gst_dep],
dependencies : [gst_dep, gstbase_dep],
)
library_def = {'lib': gstmpegts}

View file

@ -42,6 +42,7 @@
#include <gst/mpegts/gst-hdmv-section.h>
#include <gst/mpegts/gst-mpegtspesmetadatameta.h>
#include <gst/mpegts/gst-metadata-descriptor.h>
#include <gst/mpegts/gst-metadata-pointer-descriptor.h>
G_BEGIN_DECLS

View file

@ -674,6 +674,8 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
ts_pad->prepare_func = gst_base_ts_mux_prepare_opus;
} else if (strcmp (mt, "meta/x-klv") == 0) {
st = TSMUX_ST_PS_KLV;
} else if (strcmp (mt, "application/x-metadata") == 0) {
st = TSMUX_ST_PES_METADATA;
} else if (strcmp (mt, "image/x-jpc") == 0) {
/*
* See this document for more details on standard:
@ -826,6 +828,10 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
gst_structure_get_int (s, "width", &ts_pad->stream->horizontal_size);
gst_structure_get_int (s, "height", &ts_pad->stream->vertical_size);
// metadata caps
gst_structure_get_uint (s, "metadata-format-identifier",
&ts_pad->stream->metadata_format_identifier);
ts_pad->stream->color_spec = color_spec;
ts_pad->stream->max_bitrate = max_rate;
ts_pad->stream->profile_and_level = profile | main_level;

View file

@ -125,6 +125,7 @@ static GstStaticPadTemplate gst_mpeg_ts_mux_sink_factory =
"audio/x-opus, "
"channels = (int) [1, 255];"
"subpicture/x-dvb; application/x-teletext; meta/x-klv, parsed=true;"
"application/x-metadata;"
"image/x-jpc, alignment = (string) frame, profile = (int)[0, 49151];"));
static GstStaticPadTemplate gst_mpeg_ts_mux_src_factory =

View file

@ -68,6 +68,7 @@
#include <string.h>
#include <gst/mpegts/mpegts.h>
#include <gst/base/gstbytewriter.h>
#include "tsmux.h"
#include "tsmuxstream.h"
@ -1853,6 +1854,28 @@ tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
g_ptr_array_add (pmt->descriptors, descriptor);
}
/* Scan the streams looking for metadata streams */
for (i = 0; i < program->streams->len; i++) {
TsMuxStream *stream = g_ptr_array_index (program->streams, i);
if (stream->is_application_metadata == TRUE) {
// metadata_descriptor_pointer
GstMpegtsMetadataPointerDescriptor metadata_pointer_descriptor;
metadata_pointer_descriptor.metadata_application_format = 0xFFFF;
metadata_pointer_descriptor.metadata_format =
GST_MPEGTS_METADATA_FORMAT_IDENTIFIER_FIELD;
metadata_pointer_descriptor.metadata_format_identifier =
stream->metadata_format_identifier;
metadata_pointer_descriptor.metadata_service_id = 0;
metadata_pointer_descriptor.program_number = program->pgm_number;
descriptor =
gst_mpegts_descriptor_from_metadata_pointer
(&metadata_pointer_descriptor);
g_ptr_array_add (pmt->descriptors, descriptor);
}
}
/* Write out the entries */
for (i = 0; i < program->streams->len; i++) {
GstMpegtsPMTStream *pmt_stream;

View file

@ -72,6 +72,7 @@
#include "tsmuxcommon.h"
#include "tsmuxstream.h"
#include "tsmux.h"
#define GST_CAT_DEFAULT gst_base_ts_mux_debug
@ -218,6 +219,15 @@ tsmux_stream_new (guint16 pid, guint stream_type, guint stream_number)
TSMUX_PACKET_FLAG_PES_FULL_HEADER |
TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT;
break;
case TSMUX_ST_PES_METADATA:
stream->id = 0xBD; // private stream
stream->stream_type = TSMUX_ST_PES_METADATA;
stream->is_meta = TRUE;
stream->is_application_metadata = TRUE;
stream->metadata_format_identifier = 0;
stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER |
TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT;
break;
case TSMUX_ST_PS_OPUS:
/* FIXME: assign sequential extended IDs? */
stream->id = 0xBD;
@ -494,6 +504,12 @@ tsmux_stream_initialize_pes_packet (TsMuxStream * stream)
if ((stream->cur_pes_payload_size + hdr_len - 6) > G_MAXUINT16)
stream->cur_pes_payload_size = 0;
}
// stream_type specific flags
switch (stream->stream_type) {
case TSMUX_ST_PES_METADATA:
stream->pi.flags |= TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT;
break;
}
return TRUE;
}
@ -909,6 +925,33 @@ tsmux_stream_default_get_es_descrs (TsMuxStream * stream,
gst_mpegts_descriptor_from_custom (GST_MTS_DESC_DVB_TELETEXT, 0, 1);
g_ptr_array_add (pmt_stream->descriptors, descriptor);
break;
case TSMUX_ST_PES_METADATA:
// metadata_descriptor
GstMpegtsMetadataDescriptor metadata_descriptor;
metadata_descriptor.metadata_application_format = 0xFFFF;
metadata_descriptor.metadata_format =
GST_MPEGTS_METADATA_FORMAT_IDENTIFIER_FIELD;
metadata_descriptor.metadata_format_identifier =
stream->metadata_format_identifier;
metadata_descriptor.metadata_service_id = 0;
metadata_descriptor.decoder_config_flags = 0x00;
metadata_descriptor.dsm_cc_flag = FALSE;
descriptor = gst_mpegts_descriptor_from_metadata (&metadata_descriptor);
g_ptr_array_add (pmt_stream->descriptors, descriptor);
// registration_descriptor
guint32 format_identifier = 0;
GST_WRITE_UINT32_BE (&format_identifier,
metadata_descriptor.metadata_format_identifier);
descriptor = gst_mpegts_descriptor_from_registration ((const char *)
&format_identifier, NULL, 0);
g_ptr_array_add (pmt_stream->descriptors, descriptor);
break;
case TSMUX_ST_PS_DVB_SUBPICTURE:
/* fallthrough ...

View file

@ -118,6 +118,7 @@ enum TsMuxStreamType {
/* later extensions */
TSMUX_ST_AUDIO_AAC = 0x0f,
TSMUX_ST_VIDEO_MPEG4 = 0x10,
TSMUX_ST_PES_METADATA = 0x15,
TSMUX_ST_VIDEO_H264 = 0x1b,
TSMUX_ST_VIDEO_HEVC = 0x24,
TSMUX_ST_VIDEO_JP2K = 0x21,
@ -226,6 +227,9 @@ struct TsMuxStream {
guint16 profile_and_level;
gboolean interlace_mode;
guint8 color_spec;
gboolean is_application_metadata;
guint32 metadata_format_identifier;
};
/* stream management */