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) G_DEFINE_TYPE (ATSCMux, atscmux, GST_TYPE_MPEG_TSMUX)
#define parent_class atscmux_parent_class #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) 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 * static TsMux *
@ -43,6 +139,19 @@ atscmux_create_ts_mux (MpegTsMux * mpegtsmux)
return ret; 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 static void
atscmux_class_init (ATSCMuxClass * klass) atscmux_class_init (ATSCMuxClass * klass)
{ {
@ -57,6 +166,10 @@ atscmux_class_init (ATSCMuxClass * klass)
"Mathieu Duponchelle <mathieu@centricular.com>"); "Mathieu Duponchelle <mathieu@centricular.com>");
mpegtsmux_class->create_ts_mux = atscmux_create_ts_mux; 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 static void

View File

@ -624,7 +624,7 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
GstCaps *caps; GstCaps *caps;
GstStructure *s; GstStructure *s;
GstPad *pad; GstPad *pad;
TsMuxStreamType st = TSMUX_ST_RESERVED; guint st = TSMUX_ST_RESERVED;
const gchar *mt; const gchar *mt;
const GValue *value = NULL; const GValue *value = NULL;
GstBuffer *codec_data = 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_func = mpegtsmux_prepare_jpeg2000;
ts_data->prepare_data = private_data; ts_data->prepare_data = private_data;
ts_data->free_func = mpegtsmux_free_jpeg2000; 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) { if (st != TSMUX_ST_RESERVED) {
ts_data->stream = tsmux_create_stream (mux->tsmux, st, ts_data->pid, ts_data->stream = tsmux_create_stream (mux->tsmux, st, ts_data->pid,
ts_data->language); ts_data->language);

View File

@ -182,6 +182,7 @@ struct MpegTsMuxClass {
GstElementClass parent_class; GstElementClass parent_class;
TsMux * (*create_ts_mux) (MpegTsMux *mux); TsMux * (*create_ts_mux) (MpegTsMux *mux);
guint (*handle_media_type) (MpegTsMux *mux, const gchar *media_type, MpegTsPadData * ts_data);
}; };
struct MpegTsPadData { struct MpegTsPadData {

View File

@ -561,7 +561,7 @@ tsmux_get_new_pid (TsMux * mux)
/** /**
* tsmux_create_stream: * tsmux_create_stream:
* @mux: a #TsMux * @mux: a #TsMux
* @stream_type: a #TsMuxStreamType * @stream_type: the stream type
* @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 in the muxer session @mux.
@ -572,7 +572,7 @@ tsmux_get_new_pid (TsMux * mux)
* Returns: a new #TsMuxStream. * Returns: a new #TsMuxStream.
*/ */
TsMuxStream * TsMuxStream *
tsmux_create_stream (TsMux * mux, TsMuxStreamType stream_type, guint16 pid, tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid,
gchar * language) gchar * language)
{ {
TsMuxStream *stream; TsMuxStream *stream;

View File

@ -102,7 +102,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, TsMuxStreamType stream_type, void *user_data); typedef TsMuxStream * (*TsMuxNewStreamFunc) (guint16 new_pid, guint stream_type, void *user_data);
struct TsMuxSection { struct TsMuxSection {
TsMuxPacketInfo pi; TsMuxPacketInfo pi;
@ -215,7 +215,7 @@ void tsmux_resend_si (TsMux *mux);
gboolean tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection * section); gboolean tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection * section);
/* stream management */ /* 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); TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid);
void tsmux_program_add_stream (TsMuxProgram *program, TsMuxStream *stream); void tsmux_program_add_stream (TsMuxProgram *program, TsMuxStream *stream);

View File

@ -122,7 +122,7 @@ struct TsMuxStreamBuffer
* Returns: a new #TsMuxStream. * Returns: a new #TsMuxStream.
*/ */
TsMuxStream * TsMuxStream *
tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type) tsmux_stream_new (guint16 pid, guint stream_type)
{ {
TsMuxStream *stream = g_slice_new0 (TsMuxStream); 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; stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
break; break;
default: default:
g_critical ("Stream type 0x%0x not yet implemented", stream_type); /* Might be a custom stream type implemented by a subclass */
break; break;
} }
@ -232,6 +232,10 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type)
stream->pcr_ref = 0; stream->pcr_ref = 0;
stream->next_pcr = -1; stream->next_pcr = -1;
stream->get_es_descrs =
(TsMuxStreamGetESDescriptorsFunc) tsmux_stream_default_get_es_descrs;
stream->get_es_descrs_data = NULL;
return stream; return stream;
} }
@ -295,6 +299,25 @@ tsmux_stream_set_buffer_release_func (TsMuxStream * stream,
stream->buffer_release = func; 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. /* Advance the current packet stream position by len bytes.
* Mustn't consume more than available in the current packet */ * Mustn't consume more than available in the current packet */
static void 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 * @stream: a #TsMuxStream
* @buf: a buffer to hold the ES descriptor * @buf: a buffer to hold the ES descriptor
* @len: the length used in @buf * @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. * @buf and @len must be at least #TSMUX_MIN_ES_DESC_LEN.
*/ */
void void
tsmux_stream_get_es_descrs (TsMuxStream * stream, tsmux_stream_default_get_es_descrs (TsMuxStream * stream,
GstMpegtsPMTStream * pmt_stream) GstMpegtsPMTStream * pmt_stream)
{ {
GstMpegtsDescriptor *descriptor; 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: * tsmux_stream_pcr_ref:
* @stream: a #TsMuxStream * @stream: a #TsMuxStream

View File

@ -91,6 +91,7 @@ typedef enum TsMuxStreamState TsMuxStreamState;
typedef struct TsMuxStreamBuffer TsMuxStreamBuffer; typedef struct TsMuxStreamBuffer TsMuxStreamBuffer;
typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 *data, void *user_data); typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 *data, void *user_data);
typedef void (*TsMuxStreamGetESDescriptorsFunc) (TsMuxStream *stream, GstMpegtsPMTStream *pmt_stream, void *user_data);
/* Stream type assignments /* Stream type assignments
* *
@ -159,7 +160,7 @@ enum TsMuxStreamState {
struct TsMuxStream { struct TsMuxStream {
TsMuxStreamState state; TsMuxStreamState state;
TsMuxPacketInfo pi; TsMuxPacketInfo pi;
TsMuxStreamType stream_type; guint stream_type;
/* stream_id (13818-1) */ /* stream_id (13818-1) */
guint8 id; guint8 id;
@ -181,6 +182,10 @@ struct TsMuxStream {
/* helper to release collected buffers */ /* helper to release collected buffers */
TsMuxStreamBufferReleaseFunc buffer_release; 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 */ /* optional fixed PES size for stream type */
guint16 pes_payload_size; guint16 pes_payload_size;
/* current PES payload size being written */ /* current PES payload size being written */
@ -232,7 +237,7 @@ struct TsMuxStream {
}; };
/* stream management */ /* 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); void tsmux_stream_free (TsMuxStream *stream);
guint16 tsmux_stream_get_pid (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, void tsmux_stream_set_buffer_release_func (TsMuxStream *stream,
TsMuxStreamBufferReleaseFunc func); 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 /* 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 */ * indicate the PTS or DTS of the first access unit within this packet */
void tsmux_stream_add_data (TsMuxStream *stream, guint8 *data, guint len, 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); gboolean tsmux_stream_at_pes_start (TsMuxStream *stream);
void tsmux_stream_get_es_descrs (TsMuxStream *stream, GstMpegtsPMTStream *pmt_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_in_buffer (TsMuxStream *stream);
gint tsmux_stream_bytes_avail (TsMuxStream *stream); gint tsmux_stream_bytes_avail (TsMuxStream *stream);