diff --git a/gst/mpegtsmux/atscmux.c b/gst/mpegtsmux/atscmux.c index 93c803fc63..ffd4e4bb8d 100644 --- a/gst/mpegtsmux/atscmux.c +++ b/gst/mpegtsmux/atscmux.c @@ -26,10 +26,106 @@ GST_DEBUG_CATEGORY (atscmux_debug); G_DEFINE_TYPE (ATSCMux, atscmux, GST_TYPE_MPEG_TSMUX) #define parent_class atscmux_parent_class - static TsMuxStream *atscmux_create_new_stream (guint16 new_pid, +#define ATSCMUX_ST_PS_AUDIO_EAC3 0x87 + static GstStaticPadTemplate atscmux_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink_%d", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS ("video/mpeg, " + "parsed = (boolean) TRUE, " + "mpegversion = (int) 2, " + "systemstream = (boolean) false; " + "video/x-h264,stream-format=(string)byte-stream," + "alignment=(string){au, nal}; " + "audio/x-ac3, framed = (boolean) TRUE;" + "audio/x-eac3, framed = (boolean) TRUE;")); + + static void + atscmux_stream_get_es_descrs (TsMuxStream * stream, + GstMpegtsPMTStream * pmt_stream, MpegTsMux * mpegtsmux) +{ + GstMpegtsDescriptor *descriptor; + + tsmux_stream_default_get_es_descrs (stream, pmt_stream); + + if (stream->stream_type == ATSCMUX_ST_PS_AUDIO_EAC3) { + guint8 add_info[4]; + guint8 *pos; + + pos = add_info; + + /* audio_stream_descriptor () | ATSC A/52-2018 Annex G + * + * descriptor_tag 8 uimsbf + * descriptor_length 8 uimsbf + * reserved 1 '1' + * bsid_flag 1 bslbf + * mainid_flag 1 bslbf + * asvc_flag 1 bslbf + * mixinfoexists 1 bslbf + * substream1_flag 1 bslbf + * substream2_flag 1 bslbf + * substream3_flag 1 bslbf + * reserved 1 '1' + * full_service_flag 1 bslbf + * audio_service_type 3 uimsbf + * number_of_channels 3 uimsbf + * [...] + */ + + *pos++ = 0xCC; + *pos++ = 2; + + /* 1 bit reserved, all other flags unset */ + *pos++ = 0x80; + + /* 1 bit reserved, + * 1 bit set for full_service_flag, + * 3 bits hardcoded audio_service_type "Complete Main", + * 3 bits number_of_channels + */ + switch (stream->audio_channels) { + case 1: + *pos++ = 0xC0; /* Mono */ + break; + case 2: + *pos++ = 0xC0 | 0x2; /* 2-channel (stereo) */ + case 3: + case 4: + case 5: + *pos++ = 0xC0 | 0x4; /* Multichannel audio (> 2 channels; <= 3/2 + LFE channels) */ + break; + case 6: + default: + *pos++ = 0xC0 | 0x5; /* Multichannel audio(> 3/2 + LFE channels) */ + } + + descriptor = gst_mpegts_descriptor_from_registration ("EAC3", add_info, 4); + g_ptr_array_add (pmt_stream->descriptors, descriptor); + + descriptor = + gst_mpegts_descriptor_from_custom (GST_MTS_DESC_ATSC_EAC3, add_info, 4); + g_ptr_array_add (pmt_stream->descriptors, descriptor); + } +} + +static TsMuxStream * +atscmux_create_new_stream (guint16 new_pid, TsMuxStreamType stream_type, MpegTsMux * mpegtsmux) { - return tsmux_stream_new (new_pid, stream_type); + TsMuxStream *ret = tsmux_stream_new (new_pid, stream_type); + + if (stream_type == ATSCMUX_ST_PS_AUDIO_EAC3) { + ret->id = 0xBD; + ret->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER; + ret->is_audio = TRUE; + } + + tsmux_stream_set_get_es_descriptors_func (ret, + (TsMuxStreamGetESDescriptorsFunc) atscmux_stream_get_es_descrs, + mpegtsmux); + + return ret; } static TsMux * @@ -43,6 +139,19 @@ atscmux_create_ts_mux (MpegTsMux * mpegtsmux) return ret; } +static guint +atscmux_handle_media_type (MpegTsMux * mux, const gchar * media_type, + MpegTsPadData * ts_data) +{ + guint ret = TSMUX_ST_RESERVED; + + if (!g_strcmp0 (media_type, "audio/x-eac3")) { + ret = ATSCMUX_ST_PS_AUDIO_EAC3; + } + + return ret; +} + static void atscmux_class_init (ATSCMuxClass * klass) { @@ -57,6 +166,10 @@ atscmux_class_init (ATSCMuxClass * klass) "Mathieu Duponchelle "); mpegtsmux_class->create_ts_mux = atscmux_create_ts_mux; + mpegtsmux_class->handle_media_type = atscmux_handle_media_type; + + gst_element_class_add_static_pad_template (gstelement_class, + &atscmux_sink_factory); } static void diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c index c21d6865f8..47c6d865cc 100644 --- a/gst/mpegtsmux/mpegtsmux.c +++ b/gst/mpegtsmux/mpegtsmux.c @@ -624,7 +624,7 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data) GstCaps *caps; GstStructure *s; GstPad *pad; - TsMuxStreamType st = TSMUX_ST_RESERVED; + guint st = TSMUX_ST_RESERVED; const gchar *mt; const GValue *value = NULL; GstBuffer *codec_data = NULL; @@ -873,8 +873,15 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data) ts_data->prepare_func = mpegtsmux_prepare_jpeg2000; ts_data->prepare_data = private_data; ts_data->free_func = mpegtsmux_free_jpeg2000; + } else { + MpegTsMuxClass *klass = GST_MPEG_TSMUX_GET_CLASS (mux); + + if (klass->handle_media_type) { + st = klass->handle_media_type (mux, mt, ts_data); + } } + if (st != TSMUX_ST_RESERVED) { ts_data->stream = tsmux_create_stream (mux->tsmux, st, ts_data->pid, ts_data->language); diff --git a/gst/mpegtsmux/mpegtsmux.h b/gst/mpegtsmux/mpegtsmux.h index 1ec4107d97..d6272738ea 100644 --- a/gst/mpegtsmux/mpegtsmux.h +++ b/gst/mpegtsmux/mpegtsmux.h @@ -182,6 +182,7 @@ struct MpegTsMuxClass { GstElementClass parent_class; TsMux * (*create_ts_mux) (MpegTsMux *mux); + guint (*handle_media_type) (MpegTsMux *mux, const gchar *media_type, MpegTsPadData * ts_data); }; struct MpegTsPadData { diff --git a/gst/mpegtsmux/tsmux/tsmux.c b/gst/mpegtsmux/tsmux/tsmux.c index aa2cc436e1..a303e281e5 100644 --- a/gst/mpegtsmux/tsmux/tsmux.c +++ b/gst/mpegtsmux/tsmux/tsmux.c @@ -561,7 +561,7 @@ tsmux_get_new_pid (TsMux * mux) /** * tsmux_create_stream: * @mux: a #TsMux - * @stream_type: a #TsMuxStreamType + * @stream_type: the stream type * @pid: the PID of the new stream. * * Create a new stream of @stream_type in the muxer session @mux. @@ -572,7 +572,7 @@ tsmux_get_new_pid (TsMux * mux) * Returns: a new #TsMuxStream. */ TsMuxStream * -tsmux_create_stream (TsMux * mux, TsMuxStreamType stream_type, guint16 pid, +tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid, gchar * language) { TsMuxStream *stream; diff --git a/gst/mpegtsmux/tsmux/tsmux.h b/gst/mpegtsmux/tsmux/tsmux.h index 42b877593a..0f5713b4fa 100644 --- a/gst/mpegtsmux/tsmux/tsmux.h +++ b/gst/mpegtsmux/tsmux/tsmux.h @@ -102,7 +102,7 @@ typedef struct TsMux TsMux; typedef gboolean (*TsMuxWriteFunc) (GstBuffer * buf, void *user_data, gint64 new_pcr); typedef void (*TsMuxAllocFunc) (GstBuffer ** buf, void *user_data); -typedef TsMuxStream * (*TsMuxNewStreamFunc) (guint16 new_pid, TsMuxStreamType stream_type, void *user_data); +typedef TsMuxStream * (*TsMuxNewStreamFunc) (guint16 new_pid, guint stream_type, void *user_data); struct TsMuxSection { TsMuxPacketInfo pi; @@ -215,7 +215,7 @@ void tsmux_resend_si (TsMux *mux); gboolean tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection * section); /* stream management */ -TsMuxStream * tsmux_create_stream (TsMux *mux, TsMuxStreamType stream_type, guint16 pid, gchar *language); +TsMuxStream * tsmux_create_stream (TsMux *mux, guint stream_type, guint16 pid, gchar *language); TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid); void tsmux_program_add_stream (TsMuxProgram *program, TsMuxStream *stream); diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.c b/gst/mpegtsmux/tsmux/tsmuxstream.c index 7945fc0f91..12397717f5 100644 --- a/gst/mpegtsmux/tsmux/tsmuxstream.c +++ b/gst/mpegtsmux/tsmux/tsmuxstream.c @@ -122,7 +122,7 @@ struct TsMuxStreamBuffer * Returns: a new #TsMuxStream. */ TsMuxStream * -tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type) +tsmux_stream_new (guint16 pid, guint stream_type) { TsMuxStream *stream = g_slice_new0 (TsMuxStream); @@ -220,7 +220,7 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type) stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER; break; default: - g_critical ("Stream type 0x%0x not yet implemented", stream_type); + /* Might be a custom stream type implemented by a subclass */ break; } @@ -232,6 +232,10 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type) stream->pcr_ref = 0; stream->next_pcr = -1; + stream->get_es_descrs = + (TsMuxStreamGetESDescriptorsFunc) tsmux_stream_default_get_es_descrs; + stream->get_es_descrs_data = NULL; + return stream; } @@ -295,6 +299,25 @@ tsmux_stream_set_buffer_release_func (TsMuxStream * stream, stream->buffer_release = func; } +/** + * tsmux_stream_set_get_es_descriptors_func: + * @stream: a #TsMuxStream + * @func: a user callback function + * @user_data: user data passed to @func + * + * Set the callback function and user data to be called when @stream has + * to create Elementary Stream Descriptors. + */ +void +tsmux_stream_set_get_es_descriptors_func (TsMuxStream * stream, + TsMuxStreamGetESDescriptorsFunc func, void *user_data) +{ + g_return_if_fail (stream != NULL); + + stream->get_es_descrs = func; + stream->get_es_descrs_data = user_data; +} + /* Advance the current packet stream position by len bytes. * Mustn't consume more than available in the current packet */ static void @@ -727,7 +750,7 @@ tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len, } /** - * tsmux_stream_get_es_descrs: + * tsmux_stream_default_get_es_descrs: * @stream: a #TsMuxStream * @buf: a buffer to hold the ES descriptor * @len: the length used in @buf @@ -738,7 +761,7 @@ tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len, * @buf and @len must be at least #TSMUX_MIN_ES_DESC_LEN. */ void -tsmux_stream_get_es_descrs (TsMuxStream * stream, +tsmux_stream_default_get_es_descrs (TsMuxStream * stream, GstMpegtsPMTStream * pmt_stream) { GstMpegtsDescriptor *descriptor; @@ -1039,6 +1062,26 @@ tsmux_stream_get_es_descrs (TsMuxStream * stream, } } +/** + * tsmux_stream_get_es_descrs: + * @stream: a #TsMuxStream + * @buf: a buffer to hold the ES descriptor + * @len: the length used in @buf + * + * Write an Elementary Stream Descriptor for @stream into @buf. the number of + * bytes consumed in @buf will be updated in @len. + * + * @buf and @len must be at least #TSMUX_MIN_ES_DESC_LEN. + */ +void +tsmux_stream_get_es_descrs (TsMuxStream * stream, + GstMpegtsPMTStream * pmt_stream) +{ + g_return_if_fail (stream->get_es_descrs != NULL); + + return stream->get_es_descrs (stream, pmt_stream, stream->get_es_descrs_data); +} + /** * tsmux_stream_pcr_ref: * @stream: a #TsMuxStream diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.h b/gst/mpegtsmux/tsmux/tsmuxstream.h index 3b160207e6..4b60d1fed3 100644 --- a/gst/mpegtsmux/tsmux/tsmuxstream.h +++ b/gst/mpegtsmux/tsmux/tsmuxstream.h @@ -91,6 +91,7 @@ typedef enum TsMuxStreamState TsMuxStreamState; typedef struct TsMuxStreamBuffer TsMuxStreamBuffer; typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 *data, void *user_data); +typedef void (*TsMuxStreamGetESDescriptorsFunc) (TsMuxStream *stream, GstMpegtsPMTStream *pmt_stream, void *user_data); /* Stream type assignments * @@ -159,7 +160,7 @@ enum TsMuxStreamState { struct TsMuxStream { TsMuxStreamState state; TsMuxPacketInfo pi; - TsMuxStreamType stream_type; + guint stream_type; /* stream_id (13818-1) */ guint8 id; @@ -181,6 +182,10 @@ struct TsMuxStream { /* helper to release collected buffers */ TsMuxStreamBufferReleaseFunc buffer_release; + /* Override or extend the default Elementary Stream descriptors */ + TsMuxStreamGetESDescriptorsFunc get_es_descrs; + void *get_es_descrs_data; + /* optional fixed PES size for stream type */ guint16 pes_payload_size; /* current PES payload size being written */ @@ -232,7 +237,7 @@ struct TsMuxStream { }; /* stream management */ -TsMuxStream * tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type); +TsMuxStream * tsmux_stream_new (guint16 pid, guint stream_type); void tsmux_stream_free (TsMuxStream *stream); guint16 tsmux_stream_get_pid (TsMuxStream *stream); @@ -240,6 +245,10 @@ guint16 tsmux_stream_get_pid (TsMuxStream *stream); void tsmux_stream_set_buffer_release_func (TsMuxStream *stream, TsMuxStreamBufferReleaseFunc func); +void tsmux_stream_set_get_es_descriptors_func (TsMuxStream *stream, + TsMuxStreamGetESDescriptorsFunc func, + void *user_data); + /* Add a new buffer to the pool of available bytes. If pts or dts are not -1, they * indicate the PTS or DTS of the first access unit within this packet */ void tsmux_stream_add_data (TsMuxStream *stream, guint8 *data, guint len, @@ -252,6 +261,7 @@ gboolean tsmux_stream_is_pcr (TsMuxStream *stream); gboolean tsmux_stream_at_pes_start (TsMuxStream *stream); void tsmux_stream_get_es_descrs (TsMuxStream *stream, GstMpegtsPMTStream *pmt_stream); +void tsmux_stream_default_get_es_descrs (TsMuxStream * stream, GstMpegtsPMTStream * pmt_stream); gint tsmux_stream_bytes_in_buffer (TsMuxStream *stream); gint tsmux_stream_bytes_avail (TsMuxStream *stream);