mpegtsmux: expose the vmethods necessary for ATSC E-AC-3 handling

This commit is contained in:
Mathieu Duponchelle 2019-04-26 00:01:31 +02:00 committed by Mathieu Duponchelle
parent ea011a3266
commit 4e7f94f5fa
7 changed files with 187 additions and 13 deletions

View file

@ -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 <mathieu@centricular.com>");
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

View file

@ -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);

View file

@ -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 {

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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);