mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
tsdemux: Add support for Opus
Code partially based on https://git.videolan.org/?p=ffmpeg.git;a=commit;h=74141f693ded2fbf75af56fff309d2db35183635 and based on the spec draft at https://wiki.xiph.org/OpusTS Makes it possible to demux http://www.obe.tv/Downloads/opus.ts https://bugzilla.gnome.org/show_bug.cgi?id=757049
This commit is contained in:
parent
23a9e4323a
commit
1e785a3778
3 changed files with 393 additions and 25 deletions
|
@ -16,7 +16,7 @@ libgstmpegtsdemux_la_LIBADD = \
|
||||||
$(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_API_VERSION).la \
|
$(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_API_VERSION).la \
|
||||||
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \
|
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \
|
||||||
-lgstpbutils-@GST_API_VERSION@ \
|
-lgstpbutils-@GST_API_VERSION@ \
|
||||||
$(GST_BASE_LIBS) $(GST_LIBS)
|
$(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
|
||||||
libgstmpegtsdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstmpegtsdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstmpegtsdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
libgstmpegtsdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||||
|
|
||||||
|
|
|
@ -232,5 +232,6 @@
|
||||||
#define DRF_ID_ETV1 0x45545631
|
#define DRF_ID_ETV1 0x45545631
|
||||||
#define DRF_ID_HEVC 0x48455643
|
#define DRF_ID_HEVC 0x48455643
|
||||||
#define DRF_ID_KLVA 0x4b4c5641 /* defined in RP217 */
|
#define DRF_ID_KLVA 0x4b4c5641 /* defined in RP217 */
|
||||||
|
#define DRF_ID_OPUS 0x4f707573
|
||||||
|
|
||||||
#endif /* __GST_MPEG_DESC_H__ */
|
#endif /* __GST_MPEG_DESC_H__ */
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gst/tag/tag.h>
|
#include <gst/tag/tag.h>
|
||||||
#include <gst/pbutils/pbutils.h>
|
#include <gst/pbutils/pbutils.h>
|
||||||
|
#include <gst/base/base.h>
|
||||||
|
|
||||||
#include "mpegtsbase.h"
|
#include "mpegtsbase.h"
|
||||||
#include "tsdemux.h"
|
#include "tsdemux.h"
|
||||||
|
@ -46,7 +47,8 @@
|
||||||
#include "pesparse.h"
|
#include "pesparse.h"
|
||||||
#include <gst/codecparsers/gsth264parser.h>
|
#include <gst/codecparsers/gsth264parser.h>
|
||||||
#include <gst/codecparsers/gstmpegvideoparser.h>
|
#include <gst/codecparsers/gstmpegvideoparser.h>
|
||||||
#include <gst/base/gstbytewriter.h>
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tsdemux
|
* tsdemux
|
||||||
|
@ -230,6 +232,7 @@ struct _TSDemuxStream
|
||||||
"mute = (boolean) { FALSE, TRUE }; " \
|
"mute = (boolean) { FALSE, TRUE }; " \
|
||||||
"audio/x-ac3; audio/x-eac3;" \
|
"audio/x-ac3; audio/x-eac3;" \
|
||||||
"audio/x-dts;" \
|
"audio/x-dts;" \
|
||||||
|
"audio/x-opus;" \
|
||||||
"audio/x-private-ts-lpcm" \
|
"audio/x-private-ts-lpcm" \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1189,6 +1192,211 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
|
||||||
is_audio = TRUE;
|
is_audio = TRUE;
|
||||||
caps = gst_caps_new_empty_simple ("audio/x-smpte-302m");
|
caps = gst_caps_new_empty_simple ("audio/x-smpte-302m");
|
||||||
break;
|
break;
|
||||||
|
case DRF_ID_OPUS:
|
||||||
|
desc = mpegts_get_descriptor_from_stream (bstream,
|
||||||
|
GST_MTS_DESC_DVB_EXTENSION);
|
||||||
|
if (desc != NULL && desc->tag_extension == 0x80 && desc->length >= 1) { /* User defined (provisional Opus) */
|
||||||
|
guint8 channel_config_code;
|
||||||
|
GstByteReader br;
|
||||||
|
|
||||||
|
/* skip tag, length and tag_extension */
|
||||||
|
gst_byte_reader_init (&br, desc->data + 3, desc->length - 1);
|
||||||
|
channel_config_code = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
|
||||||
|
if ((channel_config_code & 0x8f) <= 8) {
|
||||||
|
static const guint8 coupled_stream_counts[9] = {
|
||||||
|
1, 0, 1, 1, 2, 2, 2, 3, 3
|
||||||
|
};
|
||||||
|
static const guint8 channel_map_a[8][8] = {
|
||||||
|
{0},
|
||||||
|
{0, 1},
|
||||||
|
{0, 2, 1},
|
||||||
|
{0, 1, 2, 3},
|
||||||
|
{0, 4, 1, 2, 3},
|
||||||
|
{0, 4, 1, 2, 3, 5},
|
||||||
|
{0, 4, 1, 2, 3, 5, 6},
|
||||||
|
{0, 6, 1, 2, 3, 4, 5, 7},
|
||||||
|
};
|
||||||
|
static const guint8 channel_map_b[8][8] = {
|
||||||
|
{0},
|
||||||
|
{0, 1},
|
||||||
|
{0, 1, 2},
|
||||||
|
{0, 1, 2, 3},
|
||||||
|
{0, 1, 2, 3, 4},
|
||||||
|
{0, 1, 2, 3, 4, 5},
|
||||||
|
{0, 1, 2, 3, 4, 5, 6},
|
||||||
|
{0, 1, 2, 3, 4, 5, 6, 7},
|
||||||
|
};
|
||||||
|
|
||||||
|
guint8 codecdata[22 + 256] = {
|
||||||
|
'O', 'p', 'u', 's',
|
||||||
|
'H', 'e', 'a', 'd',
|
||||||
|
1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0,
|
||||||
|
};
|
||||||
|
GstBuffer *codec_data_buf;
|
||||||
|
guint channels;
|
||||||
|
GValue v_arr = G_VALUE_INIT;
|
||||||
|
GValue v_buf = G_VALUE_INIT;
|
||||||
|
GstTagList *tags;
|
||||||
|
gint codecdata_len = -1;
|
||||||
|
|
||||||
|
channels = channel_config_code ? (channel_config_code & 0x0f) : 2;
|
||||||
|
codecdata[9] = channels;
|
||||||
|
if (channel_config_code == 0 || channel_config_code == 0x80) {
|
||||||
|
/* Dual Mono */
|
||||||
|
codecdata[18] = 255;
|
||||||
|
if (channel_config_code == 0) {
|
||||||
|
codecdata[19] = 1;
|
||||||
|
codecdata[20] = 1;
|
||||||
|
} else {
|
||||||
|
codecdata[19] = 2;
|
||||||
|
codecdata[20] = 0;
|
||||||
|
}
|
||||||
|
memcpy (&codecdata[21], channel_map_a[1], channels);
|
||||||
|
codecdata_len = 24;
|
||||||
|
} else if (channel_config_code <= 8) {
|
||||||
|
codecdata[18] = (channels > 2) ? 1 : 0;
|
||||||
|
codecdata[19] =
|
||||||
|
channel_config_code -
|
||||||
|
coupled_stream_counts[channel_config_code];
|
||||||
|
codecdata[20] = coupled_stream_counts[channel_config_code];
|
||||||
|
memcpy (&codecdata[21], channel_map_a[channels - 1], channels);
|
||||||
|
if (codecdata[18] == 0)
|
||||||
|
codecdata_len = 19;
|
||||||
|
else
|
||||||
|
codecdata_len = 21 + channels;
|
||||||
|
} else if (channel_config_code >= 0x82
|
||||||
|
&& channel_config_code <= 0x88) {
|
||||||
|
codecdata[18] = 1;
|
||||||
|
codecdata[19] = channels;
|
||||||
|
codecdata[20] = 0;
|
||||||
|
memcpy (&codecdata[21], channel_map_b[channels - 1], channels);
|
||||||
|
codecdata_len = 21 + channels;
|
||||||
|
} else if (channel_config_code == 0x81) {
|
||||||
|
guint8 channel_count, mapping_family;
|
||||||
|
|
||||||
|
if (gst_byte_reader_get_remaining (&br) < 2) {
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"Invalid Opus descriptor with extended channel configuration");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_count = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
mapping_family = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
|
||||||
|
/* Overwrite values from above */
|
||||||
|
if (channel_count == 0) {
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"Invalid Opus descriptor with extended channel configuration");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
channels = channel_count;
|
||||||
|
codecdata[9] = channels;
|
||||||
|
if (mapping_family == 0 && channel_count <= 2) {
|
||||||
|
codecdata[18] = 0;
|
||||||
|
codecdata[19] =
|
||||||
|
channel_count - coupled_stream_counts[channel_count];
|
||||||
|
codecdata[20] = coupled_stream_counts[channel_count];
|
||||||
|
codecdata_len = 19;
|
||||||
|
} else {
|
||||||
|
GstBitReader breader;
|
||||||
|
guint8 stream_count_minus_one, coupled_stream_count;
|
||||||
|
gint stream_count_minus_one_len, coupled_stream_count_len;
|
||||||
|
gint channel_mapping_len, i;
|
||||||
|
|
||||||
|
codecdata[18] = mapping_family;
|
||||||
|
|
||||||
|
gst_bit_reader_init (&breader,
|
||||||
|
gst_byte_reader_get_data_unchecked
|
||||||
|
(&br, gst_byte_reader_get_remaining
|
||||||
|
(&br)), gst_byte_reader_get_remaining (&br));
|
||||||
|
|
||||||
|
stream_count_minus_one_len = ceil (log2 (channel_count));
|
||||||
|
if (!gst_bit_reader_get_bits_uint8 (&breader,
|
||||||
|
&stream_count_minus_one,
|
||||||
|
stream_count_minus_one_len)) {
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"Invalid Opus descriptor with extended channel configuration");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
codecdata[19] = stream_count_minus_one + 1;
|
||||||
|
coupled_stream_count_len =
|
||||||
|
ceil (log2 (stream_count_minus_one_len + 2));
|
||||||
|
|
||||||
|
if (!gst_bit_reader_get_bits_uint8 (&breader,
|
||||||
|
&coupled_stream_count, coupled_stream_count_len)) {
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"Invalid Opus descriptor with extended channel configuration");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
codecdata[20] = coupled_stream_count;
|
||||||
|
|
||||||
|
channel_mapping_len =
|
||||||
|
ceil (log2 (stream_count_minus_one + 1 +
|
||||||
|
coupled_stream_count + 1));
|
||||||
|
for (i = 0; i < channel_count; i++) {
|
||||||
|
if (!gst_bit_reader_get_bits_uint8 (&breader,
|
||||||
|
&codecdata[21 + i], channel_mapping_len)) {
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"Invalid Opus descriptor with extended channel configuration");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* error above */
|
||||||
|
if (i != channel_count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
codecdata_len = 22 + channel_count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codecdata_len != -1) {
|
||||||
|
is_audio = TRUE;
|
||||||
|
template = gst_static_pad_template_get (&audio_template);
|
||||||
|
name = g_strdup_printf ("audio_%04x", bstream->pid);
|
||||||
|
caps = gst_caps_new_empty_simple ("audio/x-opus");
|
||||||
|
|
||||||
|
g_value_init (&v_arr, GST_TYPE_ARRAY);
|
||||||
|
g_value_init (&v_buf, GST_TYPE_BUFFER);
|
||||||
|
codec_data_buf =
|
||||||
|
gst_buffer_new_wrapped (g_memdup (codecdata, codecdata_len),
|
||||||
|
codecdata_len);
|
||||||
|
gst_value_take_buffer (&v_buf, codec_data_buf);
|
||||||
|
gst_value_array_append_and_take_value (&v_arr, &v_buf);
|
||||||
|
|
||||||
|
|
||||||
|
tags = gst_tag_list_new_empty ();
|
||||||
|
g_value_init (&v_buf, GST_TYPE_BUFFER);
|
||||||
|
codec_data_buf =
|
||||||
|
gst_tag_list_to_vorbiscomment_buffer (tags,
|
||||||
|
(const guint8 *) "OpusTags", 8, "No comments");
|
||||||
|
gst_tag_list_unref (tags);
|
||||||
|
gst_value_take_buffer (&v_buf, codec_data_buf);
|
||||||
|
gst_value_array_append_and_take_value (&v_arr, &v_buf);
|
||||||
|
|
||||||
|
gst_caps_set_value (caps, "streamheader", &v_arr);
|
||||||
|
|
||||||
|
g_value_unset (&v_arr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (demux,
|
||||||
|
"unexpected channel config code 0x%02x", channel_config_code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (demux, "Opus, but no extension descriptor");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case DRF_ID_HEVC:
|
case DRF_ID_HEVC:
|
||||||
is_video = TRUE;
|
is_video = TRUE;
|
||||||
caps = gst_caps_new_simple ("video/x-h265",
|
caps = gst_caps_new_simple ("video/x-h265",
|
||||||
|
@ -2116,14 +2324,108 @@ gst_ts_demux_check_and_sync_streams (GstTSDemux * demux, GstClockTime time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBufferList *
|
||||||
|
parse_opus_access_unit (TSDemuxStream * stream)
|
||||||
|
{
|
||||||
|
GstByteReader reader;
|
||||||
|
GstBufferList *buffer_list = NULL;
|
||||||
|
|
||||||
|
buffer_list = gst_buffer_list_new ();
|
||||||
|
gst_byte_reader_init (&reader, stream->data, stream->current_size);
|
||||||
|
|
||||||
|
do {
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint16 id;
|
||||||
|
guint au_size = 0;
|
||||||
|
guint8 b;
|
||||||
|
gboolean start_trim_flag, end_trim_flag, control_extension_flag;
|
||||||
|
guint16 start_trim = 0, end_trim = 0;
|
||||||
|
guint8 *packet_data;
|
||||||
|
guint packet_size;
|
||||||
|
|
||||||
|
if (!gst_byte_reader_get_uint16_be (&reader, &id))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* No control header */
|
||||||
|
if ((id >> 5) != 0x3ff)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!gst_byte_reader_get_uint8 (&reader, &b))
|
||||||
|
goto error;
|
||||||
|
au_size += b;
|
||||||
|
} while (b == 0xff);
|
||||||
|
|
||||||
|
start_trim_flag = (id >> 4) & 0x1;
|
||||||
|
end_trim_flag = (id >> 3) & 0x1;
|
||||||
|
control_extension_flag = (id >> 2) & 0x1;
|
||||||
|
|
||||||
|
if (start_trim_flag) {
|
||||||
|
if (!gst_byte_reader_get_uint16_be (&reader, &start_trim))
|
||||||
|
goto error;
|
||||||
|
start_trim >>= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_trim_flag) {
|
||||||
|
if (!gst_byte_reader_get_uint16_be (&reader, &end_trim))
|
||||||
|
goto error;
|
||||||
|
end_trim >>= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control_extension_flag) {
|
||||||
|
if (!gst_byte_reader_get_uint8 (&reader, &b))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!gst_byte_reader_skip (&reader, b))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_size = au_size;
|
||||||
|
|
||||||
|
/* FIXME: this should be
|
||||||
|
* packet_size = au_size - gst_byte_reader_get_pos (&reader);
|
||||||
|
* but ffmpeg and the only available sample stream from obe.tv
|
||||||
|
* are not including the control header size in au_size
|
||||||
|
*/
|
||||||
|
if (gst_byte_reader_get_remaining (&reader) < packet_size)
|
||||||
|
goto error;
|
||||||
|
if (!gst_byte_reader_dup_data (&reader, packet_size, &packet_data))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
buffer = gst_buffer_new_wrapped (packet_data, packet_size);
|
||||||
|
gst_buffer_list_add (buffer_list, buffer);
|
||||||
|
|
||||||
|
/* FIXME: Do something with start_trim and end_trim */
|
||||||
|
if (start_trim != 0 || end_trim != 0)
|
||||||
|
GST_FIXME
|
||||||
|
("Handling of Opus start_trim (%u) and end_trim (%u) not implemented",
|
||||||
|
start_trim, end_trim);
|
||||||
|
} while (gst_byte_reader_get_remaining (&reader) > 0);
|
||||||
|
|
||||||
|
g_free (stream->data);
|
||||||
|
stream->data = NULL;
|
||||||
|
stream->current_size = 0;
|
||||||
|
|
||||||
|
return buffer_list;
|
||||||
|
|
||||||
|
error:
|
||||||
|
{
|
||||||
|
GST_ERROR ("Failed to parse Opus access unit");
|
||||||
|
g_free (stream->data);
|
||||||
|
stream->data = NULL;
|
||||||
|
stream->current_size = 0;
|
||||||
|
gst_buffer_list_unref (buffer_list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
||||||
{
|
{
|
||||||
GstFlowReturn res = GST_FLOW_OK;
|
GstFlowReturn res = GST_FLOW_OK;
|
||||||
#ifndef GST_DISABLE_GST_DEBUG
|
|
||||||
MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
|
MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
|
||||||
#endif
|
|
||||||
GstBuffer *buffer = NULL;
|
GstBuffer *buffer = NULL;
|
||||||
|
GstBufferList *buffer_list = NULL;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad,
|
GST_DEBUG_OBJECT (stream->pad,
|
||||||
"stream:%p, pid:0x%04x stream_type:%d state:%d", stream, bs->pid,
|
"stream:%p, pid:0x%04x stream_type:%d state:%d", stream, bs->pid,
|
||||||
|
@ -2158,7 +2460,24 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
||||||
GST_DEBUG_OBJECT (stream->pad,
|
GST_DEBUG_OBJECT (stream->pad,
|
||||||
"Got Keyframe, ready to go at %" GST_TIME_FORMAT,
|
"Got Keyframe, ready to go at %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (stream->pts));
|
GST_TIME_ARGS (stream->pts));
|
||||||
buffer = gst_buffer_new_wrapped (stream->data, stream->current_size);
|
|
||||||
|
if (bs->stream_type == GST_MPEGTS_STREAM_TYPE_PRIVATE_PES_PACKETS &&
|
||||||
|
bs->registration_id == DRF_ID_OPUS) {
|
||||||
|
buffer_list = parse_opus_access_unit (stream);
|
||||||
|
if (!buffer_list) {
|
||||||
|
res = GST_FLOW_ERROR;
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_buffer_list_length (buffer_list) == 1) {
|
||||||
|
buffer = gst_buffer_ref (gst_buffer_list_get (buffer_list, 0));
|
||||||
|
gst_buffer_list_unref (buffer_list);
|
||||||
|
buffer_list = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer = gst_buffer_new_wrapped (stream->data, stream->current_size);
|
||||||
|
}
|
||||||
|
|
||||||
stream->seeked_pts = stream->pts;
|
stream->seeked_pts = stream->pts;
|
||||||
stream->seeked_dts = stream->dts;
|
stream->seeked_dts = stream->dts;
|
||||||
stream->needs_keyframe = FALSE;
|
stream->needs_keyframe = FALSE;
|
||||||
|
@ -2176,15 +2495,45 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer = gst_buffer_new_wrapped (stream->data, stream->current_size);
|
if (bs->stream_type == GST_MPEGTS_STREAM_TYPE_PRIVATE_PES_PACKETS &&
|
||||||
|
bs->registration_id == DRF_ID_OPUS) {
|
||||||
|
buffer_list = parse_opus_access_unit (stream);
|
||||||
|
if (!buffer_list) {
|
||||||
|
res = GST_FLOW_ERROR;
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_buffer_list_length (buffer_list) == 1) {
|
||||||
|
buffer = gst_buffer_ref (gst_buffer_list_get (buffer_list, 0));
|
||||||
|
gst_buffer_list_unref (buffer_list);
|
||||||
|
buffer_list = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer = gst_buffer_new_wrapped (stream->data, stream->current_size);
|
||||||
|
}
|
||||||
|
|
||||||
if (G_UNLIKELY (stream->pending_ts && !check_pending_buffers (demux))) {
|
if (G_UNLIKELY (stream->pending_ts && !check_pending_buffers (demux))) {
|
||||||
PendingBuffer *pend;
|
if (buffer) {
|
||||||
pend = g_slice_new0 (PendingBuffer);
|
PendingBuffer *pend;
|
||||||
pend->buffer = buffer;
|
pend = g_slice_new0 (PendingBuffer);
|
||||||
pend->pts = stream->raw_pts;
|
pend->buffer = buffer;
|
||||||
pend->dts = stream->raw_dts;
|
pend->pts = stream->raw_pts;
|
||||||
stream->pending = g_list_append (stream->pending, pend);
|
pend->dts = stream->raw_dts;
|
||||||
|
stream->pending = g_list_append (stream->pending, pend);
|
||||||
|
} else {
|
||||||
|
guint i, n;
|
||||||
|
|
||||||
|
n = gst_buffer_list_length (buffer_list);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
PendingBuffer *pend;
|
||||||
|
pend = g_slice_new0 (PendingBuffer);
|
||||||
|
pend->buffer = gst_buffer_ref (gst_buffer_list_get (buffer_list, i));
|
||||||
|
pend->pts = i == 0 ? stream->raw_pts : -1;
|
||||||
|
pend->dts = i == 0 ? stream->raw_dts : -1;
|
||||||
|
stream->pending = g_list_append (stream->pending, pend);
|
||||||
|
}
|
||||||
|
gst_buffer_list_unref (buffer_list);
|
||||||
|
}
|
||||||
GST_DEBUG ("Not enough information to push buffers yet, storing buffer");
|
GST_DEBUG ("Not enough information to push buffers yet, storing buffer");
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
@ -2226,34 +2575,52 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
||||||
"(seeked PTS: %" GST_TIME_FORMAT " DTS: %" GST_TIME_FORMAT ")",
|
"(seeked PTS: %" GST_TIME_FORMAT " DTS: %" GST_TIME_FORMAT ")",
|
||||||
GST_TIME_ARGS (stream->pts), GST_TIME_ARGS (stream->dts),
|
GST_TIME_ARGS (stream->pts), GST_TIME_ARGS (stream->dts),
|
||||||
GST_TIME_ARGS (stream->seeked_pts), GST_TIME_ARGS (stream->seeked_dts));
|
GST_TIME_ARGS (stream->seeked_pts), GST_TIME_ARGS (stream->seeked_dts));
|
||||||
gst_buffer_unref (buffer);
|
if (buffer)
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
if (buffer_list)
|
||||||
|
gst_buffer_list_unref (buffer_list);
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad, "stream->pts %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (stream->pad, "stream->pts %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (stream->pts));
|
GST_TIME_ARGS (stream->pts));
|
||||||
|
|
||||||
|
/* Decorate buffer or first buffer of the buffer list */
|
||||||
|
if (buffer_list)
|
||||||
|
buffer = gst_buffer_list_get (buffer_list, 0);
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (stream->pts))
|
if (GST_CLOCK_TIME_IS_VALID (stream->pts))
|
||||||
GST_BUFFER_PTS (buffer) = stream->pts;
|
GST_BUFFER_PTS (buffer) = stream->pts;
|
||||||
if (GST_CLOCK_TIME_IS_VALID (stream->dts))
|
if (GST_CLOCK_TIME_IS_VALID (stream->dts))
|
||||||
GST_BUFFER_DTS (buffer) = stream->dts;
|
GST_BUFFER_DTS (buffer) = stream->dts;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad,
|
|
||||||
"Pushing buffer with PTS: %" GST_TIME_FORMAT " , DTS: %" GST_TIME_FORMAT,
|
|
||||||
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
|
|
||||||
GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
|
|
||||||
|
|
||||||
if (stream->discont)
|
if (stream->discont)
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||||
stream->discont = FALSE;
|
stream->discont = FALSE;
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buffer)))
|
if (buffer_list)
|
||||||
demux->segment.position = GST_BUFFER_DTS (buffer);
|
buffer = NULL;
|
||||||
else if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)))
|
|
||||||
demux->segment.position = GST_BUFFER_PTS (buffer);
|
|
||||||
|
|
||||||
res = gst_pad_push (stream->pad, buffer);
|
GST_DEBUG_OBJECT (stream->pad,
|
||||||
/* Record that a buffer was pushed */
|
"Pushing buffer%s with PTS: %" GST_TIME_FORMAT " , DTS: %"
|
||||||
stream->nb_out_buffers += 1;
|
GST_TIME_FORMAT, (buffer_list ? "list" : ""), GST_TIME_ARGS (stream->pts),
|
||||||
|
GST_TIME_ARGS (stream->dts));
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (stream->dts))
|
||||||
|
demux->segment.position = stream->dts;
|
||||||
|
else if (GST_CLOCK_TIME_IS_VALID (stream->pts))
|
||||||
|
demux->segment.position = stream->pts;
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
res = gst_pad_push (stream->pad, buffer);
|
||||||
|
/* Record that a buffer was pushed */
|
||||||
|
stream->nb_out_buffers += 1;
|
||||||
|
} else {
|
||||||
|
guint n = gst_buffer_list_length (buffer_list);
|
||||||
|
res = gst_pad_push_list (stream->pad, buffer_list);
|
||||||
|
/* Record that a buffer was pushed */
|
||||||
|
stream->nb_out_buffers += n;
|
||||||
|
}
|
||||||
GST_DEBUG_OBJECT (stream->pad, "Returned %s", gst_flow_get_name (res));
|
GST_DEBUG_OBJECT (stream->pad, "Returned %s", gst_flow_get_name (res));
|
||||||
res = gst_flow_combiner_update_flow (demux->flowcombiner, res);
|
res = gst_flow_combiner_update_flow (demux->flowcombiner, res);
|
||||||
GST_DEBUG_OBJECT (stream->pad, "combined %s", gst_flow_get_name (res));
|
GST_DEBUG_OBJECT (stream->pad, "combined %s", gst_flow_get_name (res));
|
||||||
|
|
Loading…
Reference in a new issue