mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
tsdemux: Set mpegversion for AAC ADTS stream based on parsed ADTS header
Both 2 and 4 are supported version of AAC ADTS format stream. So we need to set correct version to help negotiation especially for non-autopluggable pipeline.
This commit is contained in:
parent
49604d8fbe
commit
085f10340e
1 changed files with 93 additions and 2 deletions
|
@ -121,6 +121,7 @@ typedef struct _TSDemuxStream TSDemuxStream;
|
||||||
|
|
||||||
typedef struct _TSDemuxH264ParsingInfos TSDemuxH264ParsingInfos;
|
typedef struct _TSDemuxH264ParsingInfos TSDemuxH264ParsingInfos;
|
||||||
typedef struct _TSDemuxJP2KParsingInfos TSDemuxJP2KParsingInfos;
|
typedef struct _TSDemuxJP2KParsingInfos TSDemuxJP2KParsingInfos;
|
||||||
|
typedef struct _TSDemuxADTSParsingInfos TSDemuxADTSParsingInfos;
|
||||||
|
|
||||||
/* Returns TRUE if a keyframe was found */
|
/* Returns TRUE if a keyframe was found */
|
||||||
typedef gboolean (*GstTsDemuxKeyFrameScanFunction) (TSDemuxStream * stream,
|
typedef gboolean (*GstTsDemuxKeyFrameScanFunction) (TSDemuxStream * stream,
|
||||||
|
@ -147,6 +148,12 @@ struct _TSDemuxJP2KParsingInfos
|
||||||
/* J2K parsing data */
|
/* J2K parsing data */
|
||||||
gboolean interlace;
|
gboolean interlace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _TSDemuxADTSParsingInfos
|
||||||
|
{
|
||||||
|
guint mpegversion;
|
||||||
|
};
|
||||||
|
|
||||||
struct _TSDemuxStream
|
struct _TSDemuxStream
|
||||||
{
|
{
|
||||||
MpegTSBaseStream stream;
|
MpegTSBaseStream stream;
|
||||||
|
@ -215,6 +222,7 @@ struct _TSDemuxStream
|
||||||
GstTsDemuxKeyFrameScanFunction scan_function;
|
GstTsDemuxKeyFrameScanFunction scan_function;
|
||||||
TSDemuxH264ParsingInfos h264infos;
|
TSDemuxH264ParsingInfos h264infos;
|
||||||
TSDemuxJP2KParsingInfos jp2kInfos;
|
TSDemuxJP2KParsingInfos jp2kInfos;
|
||||||
|
TSDemuxADTSParsingInfos atdsInfos;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VIDEO_CAPS \
|
#define VIDEO_CAPS \
|
||||||
|
@ -239,7 +247,7 @@ struct _TSDemuxStream
|
||||||
"audio/mpeg, " \
|
"audio/mpeg, " \
|
||||||
"mpegversion = (int) 1;" \
|
"mpegversion = (int) 1;" \
|
||||||
"audio/mpeg, " \
|
"audio/mpeg, " \
|
||||||
"mpegversion = (int) 2, " \
|
"mpegversion = (int) { 2, 4 }, " \
|
||||||
"stream-format = (string) adts; " \
|
"stream-format = (string) adts; " \
|
||||||
"audio/mpeg, " \
|
"audio/mpeg, " \
|
||||||
"mpegversion = (int) 4, " \
|
"mpegversion = (int) 4, " \
|
||||||
|
@ -1530,9 +1538,12 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
|
||||||
break;
|
break;
|
||||||
case GST_MPEGTS_STREAM_TYPE_AUDIO_AAC_ADTS:
|
case GST_MPEGTS_STREAM_TYPE_AUDIO_AAC_ADTS:
|
||||||
is_audio = TRUE;
|
is_audio = TRUE;
|
||||||
|
/* prefer mpegversion 4 since it's more commonly supported one */
|
||||||
caps = gst_caps_new_simple ("audio/mpeg",
|
caps = gst_caps_new_simple ("audio/mpeg",
|
||||||
"mpegversion", G_TYPE_INT, 2,
|
"mpegversion", G_TYPE_INT, 4,
|
||||||
"stream-format", G_TYPE_STRING, "adts", NULL);
|
"stream-format", G_TYPE_STRING, "adts", NULL);
|
||||||
|
/* we will set caps later once parsing adts header is done */
|
||||||
|
stream->atdsInfos.mpegversion = 4;
|
||||||
break;
|
break;
|
||||||
case GST_MPEGTS_STREAM_TYPE_AUDIO_AAC_LATM:
|
case GST_MPEGTS_STREAM_TYPE_AUDIO_AAC_LATM:
|
||||||
is_audio = TRUE;
|
is_audio = TRUE;
|
||||||
|
@ -2602,6 +2613,7 @@ push_new_segment:
|
||||||
|
|
||||||
if (demux->segment_event) {
|
if (demux->segment_event) {
|
||||||
GST_DEBUG_OBJECT (stream->pad, "Pushing newsegment event");
|
GST_DEBUG_OBJECT (stream->pad, "Pushing newsegment event");
|
||||||
|
|
||||||
gst_event_ref (demux->segment_event);
|
gst_event_ref (demux->segment_event);
|
||||||
gst_pad_push_event (stream->pad, demux->segment_event);
|
gst_pad_push_event (stream->pad, demux->segment_event);
|
||||||
}
|
}
|
||||||
|
@ -2937,6 +2949,79 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
parse_aac_adts_frame (TSDemuxStream * stream)
|
||||||
|
{
|
||||||
|
gint data_location = -1;
|
||||||
|
guint frame_len;
|
||||||
|
guint crc_size;
|
||||||
|
guint mpegversion = 4;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
if (stream->current_size < 6) {
|
||||||
|
GST_DEBUG_OBJECT (stream->pad, "Not enough data for header");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check syncword */
|
||||||
|
for (i = 0; i < stream->current_size - 2; i++) {
|
||||||
|
if ((stream->data[i] == 0xff) && ((stream->data[i + 1] & 0xf6) == 0xf0)) {
|
||||||
|
data_location = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_TRACE_OBJECT (stream->pad, "data location %d", data_location);
|
||||||
|
|
||||||
|
if (data_location == -1) {
|
||||||
|
GST_DEBUG_OBJECT (stream->pad, "Stream does not contain adts syncword");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->current_size - data_location < 6) {
|
||||||
|
GST_DEBUG_OBJECT (stream->pad, "Not enough data for header");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_len = ((stream->data[data_location + 3] & 0x03) << 11) |
|
||||||
|
(stream->data[data_location + 4] << 3) | ((stream->data[data_location +
|
||||||
|
5] & 0xe0) >> 5);
|
||||||
|
|
||||||
|
crc_size = (stream->data[data_location + 1] & 0x01) ? 0 : 2;
|
||||||
|
|
||||||
|
if (frame_len < 7 + crc_size) {
|
||||||
|
GST_DEBUG_OBJECT (stream->pad, "Invalid frame len %d", frame_len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this seems to be valid adts header, check mpeg version now
|
||||||
|
*
|
||||||
|
* TODO: check channels, rate, and profile and then update caps too?
|
||||||
|
*/
|
||||||
|
mpegversion = (stream->data[data_location + 1] & 0x08) ? 2 : 4;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (mpegversion != stream->atdsInfos.mpegversion) {
|
||||||
|
GstCaps *caps;
|
||||||
|
MpegTSBaseStream *bstream = (MpegTSBaseStream *) stream;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (stream->pad, "Update mpegversion from %d to %d",
|
||||||
|
stream->atdsInfos.mpegversion, mpegversion);
|
||||||
|
stream->atdsInfos.mpegversion = mpegversion;
|
||||||
|
|
||||||
|
caps = gst_stream_get_caps (bstream->stream_object);
|
||||||
|
caps = gst_caps_make_writable (caps);
|
||||||
|
|
||||||
|
gst_caps_set_simple (caps, "mpegversion", G_TYPE_INT, mpegversion, NULL);
|
||||||
|
gst_stream_set_caps (bstream->stream_object, caps);
|
||||||
|
gst_pad_set_caps (stream->pad, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gst_buffer_new_wrapped (stream->data, stream->current_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream,
|
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream,
|
||||||
MpegTSBaseProgram * target_program)
|
MpegTSBaseProgram * target_program)
|
||||||
|
@ -3041,6 +3126,12 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream,
|
||||||
res = GST_FLOW_ERROR;
|
res = GST_FLOW_ERROR;
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
} else if (bs->stream_type == GST_MPEGTS_STREAM_TYPE_AUDIO_AAC_ADTS) {
|
||||||
|
buffer = parse_aac_adts_frame (stream);
|
||||||
|
if (!buffer) {
|
||||||
|
res = GST_FLOW_ERROR;
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer = gst_buffer_new_wrapped (stream->data, stream->current_size);
|
buffer = gst_buffer_new_wrapped (stream->data, stream->current_size);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue