mpegtsmux: add stream-number property on GstBaseTsMuxPad

This new property allows setting of PES stream number for AAC audio
and AVC video streams.

The stream number is subject to the following constraints:

1. it must be between 0 and 15 for video
2. it must be between 0 and 31 for audio

Currently the PES stream number is hard-coded to zero for these
stream types.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4822>
This commit is contained in:
Aaron Boxer 2023-06-09 14:05:58 -04:00 committed by GStreamer Marge Bot
parent 4c92d4096e
commit a72ca72a27
8 changed files with 123 additions and 18 deletions

View file

@ -214420,7 +214420,22 @@
"GObject" "GObject"
], ],
"kind": "object", "kind": "object",
"properties": {}, "properties": {
"stream-number": {
"blurb": "stream number",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "0",
"max": "31",
"min": "0",
"mutable": "null",
"readable": true,
"type": "gint",
"writable": true
}
},
"signals": {} "signals": {}
} }
}, },

View file

@ -292,9 +292,9 @@ gst_atsc_mux_stream_get_es_descrs (TsMuxStream * stream,
static TsMuxStream * static TsMuxStream *
gst_atsc_mux_create_new_stream (guint16 new_pid, gst_atsc_mux_create_new_stream (guint16 new_pid,
TsMuxStreamType stream_type, GstBaseTsMux * mpegtsmux) TsMuxStreamType stream_type, guint stream_number, GstBaseTsMux * mpegtsmux)
{ {
TsMuxStream *ret = tsmux_stream_new (new_pid, stream_type); TsMuxStream *ret = tsmux_stream_new (new_pid, stream_type, stream_number);
if (stream_type == ATSCMUX_ST_PS_AUDIO_EAC3) { if (stream_type == ATSCMUX_ST_PS_AUDIO_EAC3) {
ret->id = 0xBD; ret->id = 0xBD;

View file

@ -93,6 +93,15 @@ GST_DEBUG_CATEGORY (gst_base_ts_mux_debug);
G_DEFINE_TYPE (GstBaseTsMuxPad, gst_base_ts_mux_pad, GST_TYPE_AGGREGATOR_PAD); G_DEFINE_TYPE (GstBaseTsMuxPad, gst_base_ts_mux_pad, GST_TYPE_AGGREGATOR_PAD);
#define DEFAULT_PAD_STREAM_NUMBER 0
enum
{
PAD_PROP_0,
PAD_PROP_STREAM_NUMBER,
};
/* Internals */ /* Internals */
static void static void
@ -163,6 +172,38 @@ gst_base_ts_mux_pad_dispose (GObject * obj)
G_OBJECT_CLASS (gst_base_ts_mux_pad_parent_class)->dispose (obj); G_OBJECT_CLASS (gst_base_ts_mux_pad_parent_class)->dispose (obj);
} }
static void
gst_base_ts_mux_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (object);
switch (prop_id) {
case PAD_PROP_STREAM_NUMBER:
ts_pad->stream_number = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_base_ts_mux_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (object);
switch (prop_id) {
case PAD_PROP_STREAM_NUMBER:
g_value_set_int (value, ts_pad->stream_number);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void static void
gst_base_ts_mux_pad_class_init (GstBaseTsMuxPadClass * klass) gst_base_ts_mux_pad_class_init (GstBaseTsMuxPadClass * klass)
{ {
@ -170,9 +211,30 @@ gst_base_ts_mux_pad_class_init (GstBaseTsMuxPadClass * klass)
GstAggregatorPadClass *gstaggpad_class = GST_AGGREGATOR_PAD_CLASS (klass); GstAggregatorPadClass *gstaggpad_class = GST_AGGREGATOR_PAD_CLASS (klass);
gobject_class->dispose = gst_base_ts_mux_pad_dispose; gobject_class->dispose = gst_base_ts_mux_pad_dispose;
gobject_class->set_property = gst_base_ts_mux_pad_set_property;
gobject_class->get_property = gst_base_ts_mux_pad_get_property;
gstaggpad_class->flush = gst_base_ts_mux_pad_flush; gstaggpad_class->flush = gst_base_ts_mux_pad_flush;
gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX, 0); gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX, 0);
/**
* GstBaseTsMuxPad:stream-number:
*
* Set stream number for AVC video stream
* or AAC audio streams.
*
* video stream number is stored in 4 bits
* audio stream number is stored in 5 bits.
* See Table 2-22 of ITU-T H222.0 for details on AAC and AVC stream numbers
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class, PAD_PROP_STREAM_NUMBER,
g_param_spec_int ("stream-number", "stream number",
"stream number", 0x0, 0x1F, DEFAULT_PAD_STREAM_NUMBER,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} }
static void static void
@ -728,9 +790,12 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
} }
if (ts_pad->stream == NULL) { if (ts_pad->stream == NULL) {
gint stream_number = DEFAULT_PAD_STREAM_NUMBER;
g_object_get (ts_pad, "stream-number", &stream_number, NULL);
ts_pad->stream = ts_pad->stream =
tsmux_create_stream (mux->tsmux, st, ts_pad->pid, ts_pad->language, tsmux_create_stream (mux->tsmux, st, stream_number, ts_pad->pid,
ts_pad->bitrate, ts_pad->max_bitrate); ts_pad->language, ts_pad->bitrate, ts_pad->max_bitrate);
if (ts_pad->stream == NULL) if (ts_pad->stream == NULL)
goto error; goto error;
} }

View file

@ -130,6 +130,7 @@ struct _GstBaseTsMuxPad
gchar *language; gchar *language;
gint bitrate; gint bitrate;
gint max_bitrate; gint max_bitrate;
gint stream_number;
}; };
struct _GstBaseTsMuxPadClass struct _GstBaseTsMuxPadClass

View file

@ -703,9 +703,10 @@ tsmux_get_new_pid (TsMux * mux)
* tsmux_create_stream: * tsmux_create_stream:
* @mux: a #TsMux * @mux: a #TsMux
* @stream_type: the stream type * @stream_type: the stream type
* @stream_number: stream number
* @pid: the PID of the new stream. * @pid: the PID of the new stream.
* *
* Create a new stream of @stream_type in the muxer session @mux. * Create a new stream of @stream_type with @stream_number in the muxer session @mux.
* *
* When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically * When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically
* be allocated for the new stream. * be allocated for the new stream.
@ -713,8 +714,8 @@ tsmux_get_new_pid (TsMux * mux)
* Returns: a new #TsMuxStream. * Returns: a new #TsMuxStream.
*/ */
TsMuxStream * TsMuxStream *
tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid, tsmux_create_stream (TsMux * mux, guint stream_type, guint stream_number,
gchar * language, guint bitrate, guint max_bitrate) guint16 pid, gchar * language, guint bitrate, guint max_bitrate)
{ {
TsMuxStream *stream; TsMuxStream *stream;
guint16 new_pid; guint16 new_pid;
@ -732,7 +733,9 @@ tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid,
if (tsmux_find_stream (mux, new_pid)) if (tsmux_find_stream (mux, new_pid))
return NULL; return NULL;
stream = mux->new_stream_func (new_pid, stream_type, mux->new_stream_data); stream =
mux->new_stream_func (new_pid, stream_type, stream_number,
mux->new_stream_data);
mux->streams = g_list_prepend (mux->streams, stream); mux->streams = g_list_prepend (mux->streams, stream);
mux->nb_streams++; mux->nb_streams++;

View file

@ -84,7 +84,7 @@ typedef struct TsMux TsMux;
typedef gboolean (*TsMuxWriteFunc) (GstBuffer * buf, void *user_data, gint64 new_pcr); typedef gboolean (*TsMuxWriteFunc) (GstBuffer * buf, void *user_data, gint64 new_pcr);
typedef void (*TsMuxAllocFunc) (GstBuffer ** buf, void *user_data); typedef void (*TsMuxAllocFunc) (GstBuffer ** buf, void *user_data);
typedef TsMuxStream * (*TsMuxNewStreamFunc) (guint16 new_pid, guint stream_type, void *user_data); typedef TsMuxStream * (*TsMuxNewStreamFunc) (guint16 new_pid, guint stream_type, guint stream_number, void *user_data);
struct TsMuxSection { struct TsMuxSection {
TsMuxPacketInfo pi; TsMuxPacketInfo pi;
@ -223,7 +223,7 @@ gboolean tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection *
gboolean tsmux_send_section (TsMux *mux, GstMpegtsSection *section); gboolean tsmux_send_section (TsMux *mux, GstMpegtsSection *section);
/* stream management */ /* stream management */
TsMuxStream * tsmux_create_stream (TsMux *mux, guint stream_type, guint16 pid, gchar *language, guint bitrate, guint max_bitrate); TsMuxStream * tsmux_create_stream (TsMux *mux, guint stream_type, guint stream_number, guint16 pid, gchar *language, guint bitrate, guint max_bitrate);
TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid); TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid);
gboolean tsmux_remove_stream (TsMux *mux, guint16 pid, TsMuxProgram *program); gboolean tsmux_remove_stream (TsMux *mux, guint16 pid, TsMuxProgram *program);

View file

@ -100,15 +100,18 @@ struct TsMuxStreamBuffer
* tsmux_stream_new: * tsmux_stream_new:
* @pid: a PID * @pid: a PID
* @stream_type: the stream type * @stream_type: the stream type
* @stream_number: stream number
* *
* Create a new stream with PID of @pid and @stream_type. * Create a new stream with PID of @pid and @stream_type,
* with stream number @stream_number.
* *
* Returns: a new #TsMuxStream. * Returns: a new #TsMuxStream.
*/ */
TsMuxStream * TsMuxStream *
tsmux_stream_new (guint16 pid, guint stream_type) tsmux_stream_new (guint16 pid, guint stream_type, guint stream_number)
{ {
TsMuxStream *stream = g_new0 (TsMuxStream, 1); TsMuxStream *stream = g_new0 (TsMuxStream, 1);
gboolean supports_user_specified_stream_number = FALSE;
stream->state = TSMUX_STREAM_STATE_HEADER; stream->state = TSMUX_STREAM_STATE_HEADER;
stream->pi.pid = pid; stream->pi.pid = pid;
@ -125,10 +128,16 @@ tsmux_stream_new (guint16 pid, guint stream_type)
case TSMUX_ST_VIDEO_MPEG4: case TSMUX_ST_VIDEO_MPEG4:
case TSMUX_ST_VIDEO_H264: case TSMUX_ST_VIDEO_H264:
case TSMUX_ST_VIDEO_HEVC: case TSMUX_ST_VIDEO_HEVC:
/* FIXME: Assign sequential IDs? */ if (stream_number > 0xF) {
stream->id = 0xE0; GST_WARNING
("video stream number %d is greater than 0xF. Setting to 0.",
stream_number);
stream_number = 0;
}
stream->id = 0xE0 | stream_number;
stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER; stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
stream->is_video_stream = TRUE; stream->is_video_stream = TRUE;
supports_user_specified_stream_number = TRUE;
break; break;
case TSMUX_ST_VIDEO_JP2K: case TSMUX_ST_VIDEO_JP2K:
stream->id = 0xBD; stream->id = 0xBD;
@ -138,10 +147,16 @@ tsmux_stream_new (guint16 pid, guint stream_type)
case TSMUX_ST_AUDIO_AAC: case TSMUX_ST_AUDIO_AAC:
case TSMUX_ST_AUDIO_MPEG1: case TSMUX_ST_AUDIO_MPEG1:
case TSMUX_ST_AUDIO_MPEG2: case TSMUX_ST_AUDIO_MPEG2:
/* FIXME: Assign sequential IDs? */ if (stream_number > 0x1F) {
GST_WARNING
("audio stream number %d is greater than 0x1F. Setting to 0.",
stream_number);
stream_number = 0;
}
stream->is_audio = TRUE; stream->is_audio = TRUE;
stream->id = 0xC0; stream->id = 0xC0 | stream_number;
stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER; stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
supports_user_specified_stream_number = TRUE;
break; break;
case TSMUX_ST_VIDEO_DIRAC: case TSMUX_ST_VIDEO_DIRAC:
case TSMUX_ST_PS_AUDIO_LPCM: case TSMUX_ST_PS_AUDIO_LPCM:
@ -209,6 +224,12 @@ tsmux_stream_new (guint16 pid, guint stream_type)
break; break;
} }
if (!supports_user_specified_stream_number && stream_number != 0) {
GST_WARNING
("Attempt to set stream number %d for unsupported stream type %d",
stream_number, stream_type);
}
stream->first_ts = GST_CLOCK_STIME_NONE; stream->first_ts = GST_CLOCK_STIME_NONE;
stream->last_pts = GST_CLOCK_STIME_NONE; stream->last_pts = GST_CLOCK_STIME_NONE;

View file

@ -225,7 +225,7 @@ struct TsMuxStream {
}; };
/* stream management */ /* stream management */
TsMuxStream * tsmux_stream_new (guint16 pid, guint stream_type); TsMuxStream * tsmux_stream_new (guint16 pid, guint stream_type, guint stream_number);
void tsmux_stream_free (TsMuxStream *stream); void tsmux_stream_free (TsMuxStream *stream);
guint16 tsmux_stream_get_pid (TsMuxStream *stream); guint16 tsmux_stream_get_pid (TsMuxStream *stream);