mpegtsmux: Allow writing arbitrary Opus channel mapping families and up to 255 channels

And fix writing of dual-mono special cases.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4180>
This commit is contained in:
Sebastian Dröge 2023-03-16 14:05:43 +02:00 committed by GStreamer Marge Bot
parent b1cb36e74c
commit 9d2ac6e90b
5 changed files with 50 additions and 13 deletions

View file

@ -214237,7 +214237,7 @@
"long-name": "MPEG Transport Stream Muxer",
"pad-templates": {
"sink_%%d": {
"caps": "video/mpeg:\n parsed: true\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\nvideo/x-dirac:\nimage/x-jpc:\n alignment: frame\nvideo/x-h264:\n stream-format: byte-stream\n alignment: { (string)au, (string)nal }\nvideo/x-h265:\n stream-format: byte-stream\n alignment: { (string)au, (string)nal }\naudio/mpeg:\n parsed: true\n mpegversion: 1\naudio/mpeg:\n framed: true\n mpegversion: { (int)2, (int)4 }\n stream-format: { (string)adts, (string)raw }\naudio/x-lpcm:\n width: { (int)16, (int)20, (int)24 }\n rate: { (int)48000, (int)96000 }\n channels: [ 1, 8 ]\n dynamic_range: [ 0, 255 ]\n emphasis: { (boolean)false, (boolean)true }\n mute: { (boolean)false, (boolean)true }\naudio/x-ac3:\n framed: true\naudio/x-dts:\n framed: true\naudio/x-opus:\n channels: [ 1, 8 ]\nchannel-mapping-family: { (int)0, (int)1 }\nsubpicture/x-dvb:\napplication/x-teletext:\nmeta/x-klv:\n parsed: true\nimage/x-jpc:\n alignment: frame\n profile: [ 0, 49151 ]\n",
"caps": "video/mpeg:\n parsed: true\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\nvideo/x-dirac:\nimage/x-jpc:\n alignment: frame\nvideo/x-h264:\n stream-format: byte-stream\n alignment: { (string)au, (string)nal }\nvideo/x-h265:\n stream-format: byte-stream\n alignment: { (string)au, (string)nal }\naudio/mpeg:\n parsed: true\n mpegversion: 1\naudio/mpeg:\n framed: true\n mpegversion: { (int)2, (int)4 }\n stream-format: { (string)adts, (string)raw }\naudio/x-lpcm:\n width: { (int)16, (int)20, (int)24 }\n rate: { (int)48000, (int)96000 }\n channels: [ 1, 8 ]\n dynamic_range: [ 0, 255 ]\n emphasis: { (boolean)false, (boolean)true }\n mute: { (boolean)false, (boolean)true }\naudio/x-ac3:\n framed: true\naudio/x-dts:\n framed: true\naudio/x-opus:\n channels: [ 1, 255 ]\nsubpicture/x-dvb:\napplication/x-teletext:\nmeta/x-klv:\n parsed: true\nimage/x-jpc:\n alignment: frame\n profile: [ 0, 49151 ]\n",
"direction": "sink",
"presence": "request",
"type": "GstBaseTsMuxPad"

View file

@ -78,6 +78,7 @@
#include <gst/pbutils/pbutils.h>
#include <gst/videoparsers/gstjpeg2000parse.h>
#include <gst/video/video-color.h>
#include <gst/base/base.h>
#include "gstbasetsmux.h"
#include "gstbasetsmuxaac.h"
@ -384,7 +385,8 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
const gchar *mt;
const GValue *value = NULL;
GstBuffer *codec_data = NULL;
guint8 opus_channel_config_code = 0;
guint8 opus_channel_config[1 + 2 + 1 + 1 + 255] = { 0, };
gsize opus_channel_config_len = 0;
guint16 profile = GST_JPEG2000_PARSE_PROFILE_NONE;
guint8 main_level = 0;
guint32 max_rate = 0;
@ -524,11 +526,14 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
}
if (channels <= 2 && mapping_family == 0) {
opus_channel_config_code = channels;
} else if (channels == 2 && mapping_family == 255 && stream_count == 1
&& coupled_count == 1) {
opus_channel_config[0] = channels;
opus_channel_config_len = 1;
} else if (channels == 2 && mapping_family == 255 && ((stream_count == 1
&& coupled_count == 1) || (stream_count == 2
&& coupled_count == 0))) {
/* Dual mono */
opus_channel_config_code = 0;
opus_channel_config[0] = coupled_count == 0 ? 0x80 : 0x00;
opus_channel_config_len = 1;
} else if (channels >= 2 && channels <= 8 && mapping_family == 1) {
static const guint8 coupled_stream_counts[9] = {
1, 0, 1, 1, 2, 2, 2, 3, 3
@ -559,16 +564,45 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
coupled_count == coupled_stream_counts[channels] &&
memcmp (channel_mapping, channel_map_a[channels - 1],
channels) == 0) {
opus_channel_config_code = channels;
opus_channel_config[0] = channels;
opus_channel_config_len = 1;
} else if (stream_count == channels - coupled_stream_counts[channels] &&
coupled_count == coupled_stream_counts[channels] &&
memcmp (channel_mapping, channel_map_b[channels - 1],
channels) == 0) {
opus_channel_config_code = channels | 0x80;
opus_channel_config[0] = channels | 0x80;
opus_channel_config_len = 1;
} else {
GST_FIXME_OBJECT (ts_pad, "Opus channel mapping not handled");
goto not_negotiated;
}
} else {
GstBitWriter writer;
guint i;
guint n_bits;
gst_bit_writer_init_with_data (&writer, opus_channel_config,
sizeof (opus_channel_config), FALSE);
gst_bit_writer_put_bits_uint8_unchecked (&writer, 0x81, 8);
gst_bit_writer_put_bits_uint8_unchecked (&writer, channels, 8);
gst_bit_writer_put_bits_uint8_unchecked (&writer, mapping_family, 8);
n_bits = g_bit_storage (channels);
gst_bit_writer_put_bits_uint8_unchecked (&writer, stream_count - 1,
n_bits);
n_bits = g_bit_storage (stream_count + 1);
gst_bit_writer_put_bits_uint8_unchecked (&writer, coupled_count, n_bits);
n_bits = g_bit_storage (stream_count + coupled_count + 1);
for (i = 0; i < channels; i++) {
gst_bit_writer_put_bits_uint8_unchecked (&writer, channel_mapping[i],
n_bits);
}
gst_bit_writer_align_bytes_unchecked (&writer, 0);
g_assert (writer.bit_size % 8 == 0);
opus_channel_config_len = writer.bit_size / 8;
}
st = TSMUX_ST_PS_OPUS;
@ -727,7 +761,9 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
ts_pad->stream->max_bitrate = max_rate;
ts_pad->stream->profile_and_level = profile | main_level;
ts_pad->stream->opus_channel_config_code = opus_channel_config_code;
memcpy (ts_pad->stream->opus_channel_config, opus_channel_config,
sizeof (opus_channel_config));
ts_pad->stream->opus_channel_config_len = opus_channel_config_len;
tsmux_stream_set_buffer_release_func (ts_pad->stream, release_buffer_cb);

View file

@ -123,8 +123,7 @@ static GstStaticPadTemplate gst_mpeg_ts_mux_sink_factory =
"audio/x-ac3, framed = (boolean) TRUE;"
"audio/x-dts, framed = (boolean) TRUE;"
"audio/x-opus, "
"channels = (int) [1, 8], "
"channel-mapping-family = (int) {0, 1};"
"channels = (int) [1, 255];"
"subpicture/x-dvb; application/x-teletext; meta/x-klv, parsed=true;"
"image/x-jpc, alignment = (string) frame, profile = (int)[0, 49151];"));

View file

@ -1033,7 +1033,7 @@ tsmux_stream_default_get_es_descrs (TsMuxStream * stream,
descriptor =
gst_mpegts_descriptor_from_custom_with_extension
(GST_MTS_DESC_DVB_EXTENSION, 0x80,
&stream->opus_channel_config_code, 1);
stream->opus_channel_config, stream->opus_channel_config_len);
g_ptr_array_add (pmt_stream->descriptors, descriptor);
}

View file

@ -209,7 +209,9 @@ struct TsMuxStream {
/* Opus */
gboolean is_opus;
guint8 opus_channel_config_code;
guint8 opus_channel_config[1 + 2 + 1 + 1 + 255];
gsize opus_channel_config_len;
/* Jpeg2000 */
gint32 horizontal_size;
gint32 vertical_size;