summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2012-03-29 17:41:53 +0200
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2012-03-29 17:41:53 +0200
commit860ccd414dbb313fabf065b92838f0f39037584b (patch)
tree0d5c0d3510db3ca3d7e6487420e8d09f74ae1961 /gst
parenta9ec4d62a89dd53aa295af02c7d5f57ef936359b (diff)
parentd84d98943af42ce645ee022207bcf04e747d2d4a (diff)
downloadgstreamer-plugins-bad-860ccd414dbb313fabf065b92838f0f39037584b.tar.gz
Merge remote-tracking branch 'origin/0.10'
Conflicts: NEWS RELEASE common configure.ac docs/libs/gst-plugins-bad-libs-sections.txt docs/plugins/gst-plugins-bad-plugins.args docs/plugins/gst-plugins-bad-plugins.hierarchy docs/plugins/gst-plugins-bad-plugins.interfaces docs/plugins/inspect/plugin-adpcmdec.xml docs/plugins/inspect/plugin-adpcmenc.xml docs/plugins/inspect/plugin-assrender.xml docs/plugins/inspect/plugin-audiovisualizers.xml docs/plugins/inspect/plugin-autoconvert.xml docs/plugins/inspect/plugin-bayer.xml docs/plugins/inspect/plugin-bz2.xml docs/plugins/inspect/plugin-camerabin2.xml docs/plugins/inspect/plugin-celt.xml docs/plugins/inspect/plugin-dataurisrc.xml docs/plugins/inspect/plugin-debugutilsbad.xml docs/plugins/inspect/plugin-dtmf.xml docs/plugins/inspect/plugin-dtsdec.xml docs/plugins/inspect/plugin-dvbsuboverlay.xml docs/plugins/inspect/plugin-dvdspu.xml docs/plugins/inspect/plugin-faac.xml docs/plugins/inspect/plugin-faad.xml docs/plugins/inspect/plugin-gsm.xml docs/plugins/inspect/plugin-h264parse.xml docs/plugins/inspect/plugin-mms.xml docs/plugins/inspect/plugin-modplug.xml docs/plugins/inspect/plugin-mpeg2enc.xml docs/plugins/inspect/plugin-mpegdemux2.xml docs/plugins/inspect/plugin-mpegtsdemux.xml docs/plugins/inspect/plugin-mpegvideoparse.xml docs/plugins/inspect/plugin-mplex.xml docs/plugins/inspect/plugin-pcapparse.xml docs/plugins/inspect/plugin-rawparse.xml docs/plugins/inspect/plugin-rtpmux.xml docs/plugins/inspect/plugin-rtpvp8.xml docs/plugins/inspect/plugin-scaletempo.xml docs/plugins/inspect/plugin-schro.xml docs/plugins/inspect/plugin-sdp.xml docs/plugins/inspect/plugin-segmentclip.xml docs/plugins/inspect/plugin-shm.xml docs/plugins/inspect/plugin-videomaxrate.xml docs/plugins/inspect/plugin-videoparsersbad.xml docs/plugins/inspect/plugin-vp8.xml docs/plugins/inspect/plugin-y4mdec.xml ext/celt/gstceltdec.c ext/dts/gstdtsdec.c ext/modplug/gstmodplug.cc ext/opus/gstopusenc.c gst-libs/gst/video/gstbasevideocodec.c gst-libs/gst/video/gstbasevideocodec.h gst-libs/gst/video/gstbasevideodecoder.c gst-libs/gst/video/gstbasevideodecoder.h gst-libs/gst/video/gstbasevideoencoder.c gst-libs/gst/video/gstbasevideoencoder.h gst/adpcmdec/Makefile.am gst/audiovisualizers/gstbaseaudiovisualizer.c gst/h264parse/gsth264parse.c gst/mpegdemux/mpegtsparse.c gst/mpegtsdemux/mpegtsbase.c gst/mpegtsdemux/mpegtspacketizer.c gst/mpegtsdemux/mpegtsparse.c gst/mpegtsdemux/tsdemux.c gst/mpegtsdemux/tsdemux.h gst/mxf/mxfdemux.c gst/rawparse/gstaudioparse.c gst/videoparsers/gsth263parse.c gst/videoparsers/gsth264parse.c sys/d3dvideosink/d3dvideosink.c sys/decklink/gstdecklinksink.cpp sys/dvb/gstdvbsrc.c sys/shm/gstshmsrc.c sys/vdpau/h264/gstvdph264dec.c sys/vdpau/mpeg/gstvdpmpegdec.c tests/examples/opencv/gst_element_print_properties.c win32/common/config.h
Diffstat (limited to 'gst')
-rw-r--r--gst/adpcmdec/Makefile.am5
-rw-r--r--gst/aiff/aiffmux.c33
-rw-r--r--gst/audiovisualizers/README7
-rw-r--r--gst/audiovisualizers/gstbaseaudiovisualizer.c2
-rw-r--r--gst/camerabin2/gstwrappercamerabinsrc.c12
-rw-r--r--gst/dccp/gstdccp.c11
-rw-r--r--gst/faceoverlay/gstfaceoverlay.c358
-rw-r--r--gst/faceoverlay/gstfaceoverlay.h9
-rw-r--r--gst/geometrictransform/gstgeometrictransform.c18
-rw-r--r--gst/hls/gsthlsdemux.c13
-rw-r--r--gst/hls/m3u8.c58
-rw-r--r--gst/hls/m3u8.h4
-rw-r--r--gst/inter/gstinteraudiosink.c46
-rw-r--r--gst/inter/gstinteraudiosink.h1
-rw-r--r--gst/inter/gstinteraudiosrc.c100
-rw-r--r--gst/inter/gstinteraudiosrc.h1
-rw-r--r--gst/inter/gstintersubsink.c45
-rw-r--r--gst/inter/gstintersubsink.h1
-rw-r--r--gst/inter/gstintersubsrc.c51
-rw-r--r--gst/inter/gstintersubsrc.h1
-rw-r--r--gst/inter/gstintertest.c14
-rw-r--r--gst/inter/gstintervideosink.c21
-rw-r--r--gst/inter/gstintervideosrc.c33
-rw-r--r--gst/jp2kdecimator/jp2kcodestream.c18
-rw-r--r--gst/mpegdemux/flutspmtinfo.c4
-rw-r--r--gst/mpegdemux/flutspmtstreaminfo.c4
-rw-r--r--gst/mpegdemux/gstmpegdemux.c2
-rw-r--r--gst/mpegdemux/gstmpegtsdemux.c6
-rw-r--r--gst/mpegdemux/mpegtspacketizer.c4
-rw-r--r--gst/mpegdemux/mpegtsparse.c2
-rw-r--r--gst/mpegtsdemux/Makefile.am2
-rw-r--r--gst/mpegtsdemux/TODO114
-rw-r--r--gst/mpegtsdemux/gstmpegdefs.h2
-rw-r--r--gst/mpegtsdemux/gstmpegdesc.h193
-rw-r--r--gst/mpegtsdemux/mpegtsbase.c287
-rw-r--r--gst/mpegtsdemux/mpegtsbase.h19
-rw-r--r--gst/mpegtsdemux/mpegtspacketizer.c538
-rw-r--r--gst/mpegtsdemux/mpegtspacketizer.h48
-rw-r--r--gst/mpegtsdemux/payload_parsers.c313
-rw-r--r--gst/mpegtsdemux/payload_parsers.h36
-rw-r--r--gst/mpegtsdemux/tsdemux.c1429
-rw-r--r--gst/mpegtsdemux/tsdemux.h29
-rw-r--r--gst/mxf/mxfdemux.c2
-rw-r--r--gst/mxf/mxfmpeg.c24
-rw-r--r--gst/removesilence/vad_private.c2
-rw-r--r--gst/rtpvp8/gstrtpvp8depay.c4
-rw-r--r--gst/rtpvp8/gstrtpvp8pay.c2
-rw-r--r--gst/siren/Makefile.am2
-rw-r--r--gst/siren/gstsirendec.c223
-rw-r--r--gst/siren/gstsirendec.h12
-rw-r--r--gst/siren/gstsirenenc.c198
-rw-r--r--gst/siren/gstsirenenc.h12
-rw-r--r--gst/videoparsers/gsth263parse.c7
-rw-r--r--gst/videoparsers/gsth264parse.c20
-rw-r--r--gst/videoparsers/gstmpegvideoparse.c4
55 files changed, 1951 insertions, 2455 deletions
diff --git a/gst/adpcmdec/Makefile.am b/gst/adpcmdec/Makefile.am
index 23dbfb247..f82cb9b46 100644
--- a/gst/adpcmdec/Makefile.am
+++ b/gst/adpcmdec/Makefile.am
@@ -6,8 +6,9 @@ libgstadpcmdec_la_SOURCES = adpcmdec.c
# flags used to compile this plugin
# add other _CFLAGS and _LIBS as needed
libgstadpcmdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
-libgstadpcmdec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ \
- $(GST_LIBS)
+libgstadpcmdec_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ \
+ $(GST_BASE_LIBS) $(GST_LIBS)
libgstadpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstadpcmdec_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/gst/aiff/aiffmux.c b/gst/aiff/aiffmux.c
index a2d99f587..14f802daa 100644
--- a/gst/aiff/aiffmux.c
+++ b/gst/aiff/aiffmux.c
@@ -165,11 +165,14 @@ gst_aiff_mux_write_form_header (GstAiffMux * aiffmux, guint32 audio_data_size,
GstByteWriter * writer)
{
/* ckID == 'FORM' */
- gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('F', 'O', 'R', 'M'));
+ gst_byte_writer_put_uint32_le_unchecked (writer,
+ GST_MAKE_FOURCC ('F', 'O', 'R', 'M'));
/* ckSize is currently bogus but we'll know what it is later */
- gst_byte_writer_put_uint32_be (writer, audio_data_size + AIFF_HEADER_LEN - 8);
+ gst_byte_writer_put_uint32_be_unchecked (writer,
+ audio_data_size + AIFF_HEADER_LEN - 8);
/* formType == 'AIFF' */
- gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('A', 'I', 'F', 'F'));
+ gst_byte_writer_put_uint32_le_unchecked (writer,
+ GST_MAKE_FOURCC ('A', 'I', 'F', 'F'));
}
/*
@@ -220,8 +223,8 @@ gst_aiff_mux_write_ext (GstByteWriter * writer, double d)
if (d < 0)
ext.exponent[0] |= 0x80;
- gst_byte_writer_put_data (writer, ext.exponent, 2);
- gst_byte_writer_put_data (writer, ext.mantissa, 8);
+ gst_byte_writer_put_data_unchecked (writer, ext.exponent, 2);
+ gst_byte_writer_put_data_unchecked (writer, ext.mantissa, 8);
}
/*
@@ -232,13 +235,14 @@ static void
gst_aiff_mux_write_comm_header (GstAiffMux * aiffmux, guint32 audio_data_size,
GstByteWriter * writer)
{
- gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('C', 'O', 'M', 'M'));
- gst_byte_writer_put_uint32_be (writer, 18);
- gst_byte_writer_put_uint16_be (writer, aiffmux->channels);
+ gst_byte_writer_put_uint32_le_unchecked (writer,
+ GST_MAKE_FOURCC ('C', 'O', 'M', 'M'));
+ gst_byte_writer_put_uint32_be_unchecked (writer, 18);
+ gst_byte_writer_put_uint16_be_unchecked (writer, aiffmux->channels);
/* numSampleFrames value will be overwritten when known */
- gst_byte_writer_put_uint32_be (writer,
+ gst_byte_writer_put_uint32_be_unchecked (writer,
audio_data_size / (aiffmux->width / 8 * aiffmux->channels));
- gst_byte_writer_put_uint16_be (writer, aiffmux->depth);
+ gst_byte_writer_put_uint16_be_unchecked (writer, aiffmux->depth);
gst_aiff_mux_write_ext (writer, aiffmux->rate);
}
@@ -246,13 +250,14 @@ static void
gst_aiff_mux_write_ssnd_header (GstAiffMux * aiffmux, guint32 audio_data_size,
GstByteWriter * writer)
{
- gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('S', 'S', 'N', 'D'));
+ gst_byte_writer_put_uint32_le_unchecked (writer,
+ GST_MAKE_FOURCC ('S', 'S', 'N', 'D'));
/* ckSize will be overwritten when known */
- gst_byte_writer_put_uint32_be (writer,
+ gst_byte_writer_put_uint32_be_unchecked (writer,
audio_data_size + AIFF_SSND_HEADER_LEN - 8);
/* offset and blockSize are set to 0 as we don't support block-aligned sample data yet */
- gst_byte_writer_put_uint32_be (writer, 0);
- gst_byte_writer_put_uint32_be (writer, 0);
+ gst_byte_writer_put_uint32_be_unchecked (writer, 0);
+ gst_byte_writer_put_uint32_be_unchecked (writer, 0);
}
static GstFlowReturn
diff --git a/gst/audiovisualizers/README b/gst/audiovisualizers/README
index be2491e06..3c59f0e01 100644
--- a/gst/audiovisualizers/README
+++ b/gst/audiovisualizers/README
@@ -58,6 +58,11 @@ xxxscope
- element maker template
- test for baseclass
+- actors
+ - we use the wave, filtered waves, balance and fft so far
+ - we could have narrow filters over harmonic frequencies
+ - we could use loudness like determined in level-meter
+
- we probably want a VisBin like the gnome video effects
- this way we can specify pipeline fragments
- VisBin can use a videomixer to switch effects based on time or song
@@ -82,3 +87,5 @@ GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.
GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! tee name=t ! queue ! audioconvert ! synaesthesia ! ximagesink t. ! queue ! synaescope shade-amount=0x00040404 ! colorspace ! ximagesink
+gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! tee name=t ! queue ! audioconvert ! wavescope style=color-lines shade-amount=0x00080402 ! alpha alpha=0.5 ! videomixer2 name=m background=black ! colorspace ! vertigotv ! ximagesink t. ! queue ! audioconvert ! spacescope style=color-lines shade-amount=0x00080402 ! alpha alpha=0.5 ! m. t. ! queue ! pulsesink
+
diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.c b/gst/audiovisualizers/gstbaseaudiovisualizer.c
index 7a76a99ce..b36dd328f 100644
--- a/gst/audiovisualizers/gstbaseaudiovisualizer.c
+++ b/gst/audiovisualizers/gstbaseaudiovisualizer.c
@@ -913,7 +913,7 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstObject * parent,
if (avail - sbpf >= sbpf) {
gst_adapter_flush (scope->adapter, sbpf);
gst_adapter_unmap (scope->adapter);
- } else if (avail - sbpf >= 0) {
+ } else if (avail >= sbpf) {
/* just flush a bit and stop */
gst_adapter_flush (scope->adapter, (avail - sbpf));
gst_adapter_unmap (scope->adapter);
diff --git a/gst/camerabin2/gstwrappercamerabinsrc.c b/gst/camerabin2/gstwrappercamerabinsrc.c
index 7b2a6d5cb..6ffe0843a 100644
--- a/gst/camerabin2/gstwrappercamerabinsrc.c
+++ b/gst/camerabin2/gstwrappercamerabinsrc.c
@@ -154,6 +154,18 @@ gst_wrapper_camera_bin_reset_video_src_caps (GstWrapperCameraBinSrc * self,
GST_DEBUG_OBJECT (self, "Resetting src caps to %" GST_PTR_FORMAT, caps);
if (self->src_vid_src) {
+ GstCaps *old_caps;
+
+ g_object_get (G_OBJECT (self->src_filter), "caps", &old_caps, NULL);
+ if (gst_caps_is_equal (caps, old_caps)) {
+ GST_DEBUG_OBJECT (self, "old and new caps are same, do not reset it");
+ if (old_caps)
+ gst_caps_unref (old_caps);
+ return;
+ }
+ if (old_caps)
+ gst_caps_unref (old_caps);
+
clock = gst_element_get_clock (self->src_vid_src);
base_time = gst_element_get_base_time (self->src_vid_src);
diff --git a/gst/dccp/gstdccp.c b/gst/dccp/gstdccp.c
index af652f2de..cbe7c4689 100644
--- a/gst/dccp/gstdccp.c
+++ b/gst/dccp/gstdccp.c
@@ -333,7 +333,7 @@ gst_dccp_socket_write (GstElement * element, int socket, const void *buf,
size_t size, int packet_size)
{
size_t bytes_written = 0;
- ssize_t wrote;
+ ssize_t wrote = 0;
#ifndef G_OS_WIN32
struct iovec iov;
@@ -362,11 +362,14 @@ gst_dccp_socket_write (GstElement * element, int socket, const void *buf,
} while (wrote == SOCKET_ERROR && errorCode == EAGAIN);
#endif
- /* TODO print the send error */
- bytes_written += wrote;
+ /* give up on error */
+ if (wrote >= 0)
+ bytes_written += wrote;
+ else
+ break;
}
- if (bytes_written < 0)
+ if (wrote < 0)
GST_WARNING ("Error while writing.");
else
GST_LOG_OBJECT (element, "Wrote %" G_GSIZE_FORMAT " bytes succesfully.",
diff --git a/gst/faceoverlay/gstfaceoverlay.c b/gst/faceoverlay/gstfaceoverlay.c
index feb07b5bd..01c8f1b72 100644
--- a/gst/faceoverlay/gstfaceoverlay.c
+++ b/gst/faceoverlay/gstfaceoverlay.c
@@ -1,5 +1,4 @@
-/*
- * GStreamer faceoverlay plugin
+/* GStreamer faceoverlay plugin
* Copyright (C) 2011 Laura Lucas Alday <lauralucas@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -52,7 +51,6 @@
* <title>Example launch line</title>
* |[
* gst-launch autovideosrc ! ffmpegcolorspace ! faceoverlay location=/path/to/gnome-video-effects/pixmaps/bow.svg x=-5 y=-15 w=0.3 h=0.1 ! ffmpegcolorspace ! autovideosink
-
* ]|
* </refsect2>
*/
@@ -70,19 +68,6 @@
GST_DEBUG_CATEGORY_STATIC (gst_face_overlay_debug);
#define GST_CAT_DEFAULT gst_face_overlay_debug
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-#define GST_STR_VIDEO_CAPS GST_VIDEO_CAPS_BGRA
-#else
-#define GST_STR_VIDEO_CAPS GST_VIDEO_CAPS_ARGB
-#endif
-
-/* Filter signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
enum
{
PROP_0,
@@ -93,17 +78,16 @@ enum
PROP_H
};
-/* the capabilities of the inputs and outputs. */
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_STR_VIDEO_CAPS)
+ GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_STR_VIDEO_CAPS)
+ GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
);
GST_BOILERPLATE (GstFaceOverlay, gst_face_overlay, GstBin, GST_TYPE_BIN);
@@ -117,121 +101,62 @@ static void gst_face_overlay_message_handler (GstBin * bin,
static GstStateChangeReturn gst_face_overlay_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_face_overlay_create_children (GstFaceOverlay * filter);
-static gboolean gst_face_overlay_reset (GstFaceOverlay * filter);
-static gboolean gst_face_overlay_create_pad (GstFaceOverlay * filter,
- GstPad * filter_pad, const char *pad_name, GstElement * child_element);
-static gboolean toggle_pads_link_state (GstPad * pad1, GstPad * pad2);
-
-
-static gboolean
-toggle_pads_link_state (GstPad * pad1, GstPad * pad2)
-{
- gboolean ok = TRUE;
- if (gst_pad_is_linked (pad1)) {
- if (gst_pad_get_direction (pad1) == GST_PAD_SINK)
- gst_pad_unlink (pad2, pad1);
- else
- gst_pad_unlink (pad1, pad2);
- } else {
- if (gst_pad_get_direction (pad1) == GST_PAD_SINK)
- ok &= (gst_pad_link (pad2, pad1) == 0);
- else
- ok &= (gst_pad_link (pad1, pad2) == 0);
- }
-
- return ok;
-}
-
-/* Unlinks and removes the pad that was created in gst_face_overlay_init ()
- * and adds the internal element ghost pad instead */
static gboolean
-gst_face_overlay_create_pad (GstFaceOverlay * filter, GstPad * filter_pad,
- const char *pad_name, GstElement * child_element)
+gst_face_overlay_create_children (GstFaceOverlay * filter)
{
- GstPad *peer = NULL;
- GstPad *pad = NULL;
- gboolean ok = TRUE;
+ GstElement *csp, *face_detect, *overlay;
+ GstPad *pad;
- /* get the outside world pad connected to faceoverlay src/sink pad */
- peer = gst_pad_get_peer (filter_pad);
+ csp = gst_element_factory_make ("ffmpegcolorspace", NULL);
+ face_detect = gst_element_factory_make ("facedetect", NULL);
+ overlay = gst_element_factory_make ("rsvgoverlay", NULL);
- /* unlink and remove the faceoverlay src/sink pad */
- toggle_pads_link_state (peer, filter_pad);
+ /* FIXME: post missing-plugin messages on NULL->READY if needed */
+ if (csp == NULL || face_detect == NULL || overlay == NULL)
+ goto missing_element;
- gst_element_remove_pad (GST_ELEMENT (filter), filter_pad);
+ g_object_set (face_detect, "display", FALSE, NULL);
- /* add a ghost pad pointing to the child element pad (facedetect sink or
- * svg_overlay src depending on filter_pad direction) and add it to
- * faceoverlay bin */
- pad = gst_element_get_static_pad (child_element, pad_name);
- filter_pad = gst_ghost_pad_new (pad_name, pad);
- gst_object_unref (GST_OBJECT (pad));
+ gst_bin_add_many (GST_BIN (filter), face_detect, csp, overlay, NULL);
+ filter->svg_overlay = overlay;
- gst_element_add_pad (GST_ELEMENT (filter), filter_pad);
+ if (!gst_element_link_many (face_detect, csp, overlay, NULL))
+ GST_ERROR_OBJECT (filter, "couldn't link elements");
- /* link the child element pad to the outside world thru the ghost pad */
- toggle_pads_link_state (peer, filter_pad);
+ pad = gst_element_get_static_pad (face_detect, "sink");
+ if (!gst_ghost_pad_set_target (GST_GHOST_PAD (filter->sinkpad), pad))
+ GST_ERROR_OBJECT (filter->sinkpad, "couldn't set sinkpad target");
+ gst_object_unref (pad);
- g_object_unref (peer);
-
- return ok;
-}
-
-static gboolean
-gst_face_overlay_reset (GstFaceOverlay * filter)
-{
- gst_element_set_state (filter->face_detect, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (filter), filter->face_detect);
- filter->face_detect = NULL;
-
- gst_element_set_state (filter->svg_overlay, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (filter), filter->svg_overlay);
- filter->svg_overlay = NULL;
-
- gst_element_set_state (filter->colorspace, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (filter), filter->colorspace);
- filter->colorspace = NULL;
+ pad = gst_element_get_static_pad (overlay, "src");
+ if (!gst_ghost_pad_set_target (GST_GHOST_PAD (filter->srcpad), pad))
+ GST_ERROR_OBJECT (filter->srcpad, "couldn't set srcpad target");
+ gst_object_unref (pad);
return TRUE;
-}
-static gboolean
-gst_face_overlay_create_children (GstFaceOverlay * filter)
-{
- gboolean ret = TRUE;
+/* ERRORS */
+missing_element:
+ {
+ /* clean up */
+ if (csp == NULL)
+ GST_ERROR_OBJECT (filter, "ffmpegcolorspace element not found");
+ else
+ gst_object_unref (csp);
- if ((filter->colorspace = gst_element_factory_make ("ffmpegcolorspace",
- NULL)) == NULL) {
- return FALSE;
- }
+ if (face_detect == NULL)
+ GST_ERROR_OBJECT (filter, "facedetect element not found (opencv plugin)");
+ else
+ gst_object_unref (face_detect);
- if ((filter->face_detect = gst_element_factory_make ("facedetect",
- NULL)) == NULL) {
- return FALSE;
- }
- g_object_set (filter->face_detect, "display", 0, NULL);
+ if (overlay == NULL)
+ GST_ERROR_OBJECT (filter, "rsvgoverlay element not found (rsvg plugin)");
+ else
+ gst_object_unref (overlay);
- if ((filter->svg_overlay = gst_element_factory_make ("rsvgoverlay",
- NULL)) == NULL) {
return FALSE;
}
-
- gst_bin_add_many (GST_BIN (filter),
- filter->face_detect, filter->colorspace, filter->svg_overlay, NULL);
-
- ret &= gst_element_link_pads (filter->face_detect, "src",
- filter->colorspace, "sink");
- ret &= gst_element_link_pads (filter->colorspace, "src",
- filter->svg_overlay, "sink");
-
- ret &= gst_face_overlay_create_pad (filter, filter->sinkpad, "sink",
- filter->face_detect);
- ret &= gst_face_overlay_create_pad (filter, filter->srcpad, "src",
- filter->svg_overlay);
-
- return ret;
-
}
static GstStateChangeReturn
@@ -242,8 +167,13 @@ gst_face_overlay_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
- if (!gst_face_overlay_create_children (filter))
+ if (filter->svg_overlay == NULL) {
+ GST_ELEMENT_ERROR (filter, CORE, MISSING_PLUGIN, (NULL),
+ ("Some required plugins are missing, probably either the opencv "
+ "facedetect element or rsvgoverlay"));
return GST_STATE_CHANGE_FAILURE;
+ }
+ filter->update_svg = TRUE;
break;
default:
break;
@@ -252,9 +182,6 @@ gst_face_overlay_change_state (GstElement * element, GstStateChange transition)
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
- case GST_STATE_CHANGE_READY_TO_NULL:
- gst_face_overlay_reset (filter);
- break;
default:
break;
}
@@ -263,65 +190,91 @@ gst_face_overlay_change_state (GstElement * element, GstStateChange transition)
}
static void
+gst_face_overlay_handle_faces (GstFaceOverlay * filter, const GstStructure * s)
+{
+ guint x, y, width, height;
+ gint svg_x, svg_y, svg_width, svg_height;
+ const GstStructure *face;
+ const GValue *faces_list, *face_val;
+ gchar *new_location = NULL;
+ gint face_count;
+
+#if 0
+ /* optionally draw the image once every two messages for better performance */
+ filter->process_message = !filter->process_message;
+ if (!filter->process_message)
+ return;
+#endif
+
+ faces_list = gst_structure_get_value (s, "faces");
+ face_count = gst_value_list_get_size (faces_list);
+ GST_LOG_OBJECT (filter, "face count: %d", face_count);
+
+ if (face_count == 0) {
+ GST_DEBUG_OBJECT (filter, "no face, clearing overlay");
+ g_object_set (filter->svg_overlay, "location", NULL, NULL);
+ GST_OBJECT_LOCK (filter);
+ filter->update_svg = TRUE;
+ GST_OBJECT_UNLOCK (filter);
+ return;
+ }
+
+ /* The last face in the list seems to be the right one, objects mistakenly
+ * detected as faces for a couple of frames seem to be in the list
+ * beginning. TODO: needs confirmation. */
+ face_val = gst_value_list_get_value (faces_list, face_count - 1);
+ face = gst_value_get_structure (face_val);
+ gst_structure_get_uint (face, "x", &x);
+ gst_structure_get_uint (face, "y", &y);
+ gst_structure_get_uint (face, "width", &width);
+ gst_structure_get_uint (face, "height", &height);
+
+ /* Apply x and y offsets relative to face position and size.
+ * Set image width and height as a fraction of face width and height.
+ * Cast to int since face position and size will never be bigger than
+ * G_MAX_INT and we may have negative values as svg_x or svg_y */
+
+ GST_OBJECT_LOCK (filter);
+
+ svg_x = (gint) x + (gint) (filter->x * width);
+ svg_y = (gint) y + (gint) (filter->y * height);
+
+ svg_width = (gint) (filter->w * width);
+ svg_height = (gint) (filter->h * height);
+
+ if (filter->update_svg) {
+ new_location = g_strdup (filter->location);
+ filter->update_svg = FALSE;
+ }
+ GST_OBJECT_UNLOCK (filter);
+
+ if (new_location != NULL) {
+ GST_DEBUG_OBJECT (filter, "set rsvgoverlay location=%s", new_location);
+ g_object_set (filter->svg_overlay, "location", new_location, NULL);
+ g_free (new_location);
+ }
+
+ GST_LOG_OBJECT (filter, "overlay dimensions: %d x %d @ %d,%d",
+ svg_width, svg_height, svg_x, svg_y);
+
+ g_object_set (filter->svg_overlay,
+ "x", svg_x, "y", svg_y, "width", svg_width, "height", svg_height, NULL);
+}
+
+static void
gst_face_overlay_message_handler (GstBin * bin, GstMessage * message)
{
- if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT &&
- strcmp (gst_structure_get_name (message->structure), "facedetect") == 0) {
- GstFaceOverlay *filter = GST_FACEOVERLAY (bin);
-
- /* optionally draw the image once every two messages for better performance
- * filter->process_message = !filter->process_message;
- * if(!filter->process_message)
- * return;
- */
-
- guint x, y, width, height;
- int delta_x, delta_y, svg_x, svg_y, svg_width, svg_height;
- const GstStructure *face;
- int face_count;
-
- face_count =
- gst_value_list_get_size (gst_structure_get_value (message->structure,
- "faces"));
-
- /* The last face in the list seems to be the right one, objects mistakenly
- * detected as faces for a couple of frames seem to be in the list
- * beginning. TODO: needs confirmation. */
- face =
- gst_value_get_structure (gst_value_list_get_value
- (gst_structure_get_value (message->structure, "faces"),
- face_count - 1));
- gst_structure_get_uint (face, "x", &x);
- gst_structure_get_uint (face, "y", &y);
- gst_structure_get_uint (face, "width", &width);
- gst_structure_get_uint (face, "height", &height);
-
- /* Apply x and y offsets relative to face position and size.
- * Set image width and height as a fraction of face width and height.
- * Cast to int since face position and size will never be bigger than
- * G_MAX_INT and we may have negative values as svg_x or svg_y */
-
- delta_x = (int) (filter->x * (int) width);
- svg_x = (int) x + delta_x;
-
- delta_y = (int) (filter->y * (int) height);
- svg_y = (int) y + delta_y;
-
- svg_width = (int) width *filter->w;
- svg_height = (int) height *filter->h;
-
- g_object_set (filter->svg_overlay,
- "location", filter->location,
- "x", svg_x, "y", svg_y, "width", svg_width, "height", svg_height, NULL);
+ if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) {
+ const GstStructure *s = gst_message_get_structure (message);
+ if (gst_structure_has_name (s, "facedetect")) {
+ gst_face_overlay_handle_faces (GST_FACEOVERLAY (bin), s);
+ }
}
GST_BIN_CLASS (parent_class)->handle_message (bin, message);
}
-/* GObject vmethod implementations */
-/* the _base_init() function is meant to initialize class and child class
- * properties during each new child class creation */
static void
gst_face_overlay_base_init (gpointer gclass)
{
@@ -339,10 +292,6 @@ gst_face_overlay_base_init (gpointer gclass)
gst_static_pad_template_get (&sink_factory));
}
-/* initialize the faceoverlay's class */
-/* the _class_init() function is used to initialise the class only once
- * (specifying what signals, arguments and virtual functions the class has and
- * setting up global state) */
static void
gst_face_overlay_class_init (GstFaceOverlayClass * klass)
{
@@ -382,34 +331,32 @@ gst_face_overlay_class_init (GstFaceOverlayClass * klass)
GST_DEBUG_FUNCPTR (gst_face_overlay_message_handler);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_face_overlay_change_state);
-
}
-/* initialize the new element
- * instantiate pads and add them to element
- * set pad calback functions
- * initialize instance structure
- * the _init() function is used to initialise a specific instance of this type.
- */
static void
gst_face_overlay_init (GstFaceOverlay * filter, GstFaceOverlayClass * gclass)
{
+ GstPadTemplate *tmpl;
+
filter->x = 0;
filter->y = 0;
filter->w = 1;
filter->h = 1;
- filter->colorspace = NULL;
filter->svg_overlay = NULL;
- filter->face_detect = NULL;
filter->location = NULL;
filter->process_message = TRUE;
- filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
+ tmpl = gst_static_pad_template_get (&sink_factory);
+ filter->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", tmpl);
+ gst_object_unref (tmpl);
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
- filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+ tmpl = gst_static_pad_template_get (&src_factory);
+ filter->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
+ gst_object_unref (tmpl);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+ gst_face_overlay_create_children (filter);
}
static void
@@ -420,19 +367,31 @@ gst_face_overlay_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_LOCATION:
+ GST_OBJECT_LOCK (filter);
+ g_free (filter->location);
filter->location = g_value_dup_string (value);
+ filter->update_svg = TRUE;
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_X:
+ GST_OBJECT_LOCK (filter);
filter->x = g_value_get_float (value);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_Y:
+ GST_OBJECT_LOCK (filter);
filter->y = g_value_get_float (value);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_W:
+ GST_OBJECT_LOCK (filter);
filter->w = g_value_get_float (value);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_H:
+ GST_OBJECT_LOCK (filter);
filter->h = g_value_get_float (value);
+ GST_OBJECT_UNLOCK (filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -448,19 +407,29 @@ gst_face_overlay_get_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_LOCATION:
+ GST_OBJECT_LOCK (filter);
g_value_set_string (value, filter->location);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_X:
+ GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->x);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_Y:
+ GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->y);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_W:
+ GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->w);
+ GST_OBJECT_UNLOCK (filter);
break;
case PROP_H:
+ GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->h);
+ GST_OBJECT_UNLOCK (filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -468,14 +437,9 @@ gst_face_overlay_get_property (GObject * object, guint prop_id,
}
}
-/* entry point to initialize the plug-in
- * initialize the plug-in itself
- * register the element factories and other features
- */
static gboolean
faceoverlay_init (GstPlugin * faceoverlay)
{
- /* debug category for fltering log messages */
GST_DEBUG_CATEGORY_INIT (gst_face_overlay_debug, "faceoverlay",
0, "SVG Face Overlay");
@@ -483,18 +447,8 @@ faceoverlay_init (GstPlugin * faceoverlay)
GST_TYPE_FACEOVERLAY);
}
-/* PACKAGE: this is usually set by autotools depending on some _INIT macro
- * in configure.ac and then written into and defined in config.h, but we can
- * just set it ourselves here in case someone doesn't use autotools to
- * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.
- */
-#ifndef PACKAGE
-#define PACKAGE "faceoverlay"
-#endif
-
-/* gstreamer looks for this structure to register plugins */
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"faceoverlay",
"SVG Face Overlay",
- faceoverlay_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
+ faceoverlay_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/faceoverlay/gstfaceoverlay.h b/gst/faceoverlay/gstfaceoverlay.h
index 7b8e50c00..c21327b11 100644
--- a/gst/faceoverlay/gstfaceoverlay.h
+++ b/gst/faceoverlay/gstfaceoverlay.h
@@ -1,5 +1,4 @@
-/*
- * GStreamer faceoverlay plugin
+/* GStreamer faceoverlay plugin
* Copyright (C) 2011 Laura Lucas Alday <lauralucas@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -47,7 +46,7 @@
#include <gst/gst.h>
G_BEGIN_DECLS
-/* #defines don't like whitespacey bits */
+
#define GST_TYPE_FACEOVERLAY \
(gst_face_overlay_get_type())
#define GST_FACEOVERLAY(obj) \
@@ -58,6 +57,7 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FACEOVERLAY))
#define GST_IS_FACEOVERLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FACEOVERLAY))
+
typedef struct _GstFaceOverlay GstFaceOverlay;
typedef struct _GstFaceOverlayClass GstFaceOverlayClass;
@@ -73,6 +73,8 @@ struct _GstFaceOverlay
gboolean process_message;
+ gboolean update_svg;
+
gchar *location;
gfloat x;
gfloat y;
@@ -88,4 +90,5 @@ struct _GstFaceOverlayClass
GType gst_face_overlay_get_type (void);
G_END_DECLS
+
#endif /* __GST_FACEOVERLAY_H__ */
diff --git a/gst/geometrictransform/gstgeometrictransform.c b/gst/geometrictransform/gstgeometrictransform.c
index 11e45fb50..4fceaef52 100644
--- a/gst/geometrictransform/gstgeometrictransform.c
+++ b/gst/geometrictransform/gstgeometrictransform.c
@@ -113,6 +113,8 @@ gst_geometric_transform_generate_map (GstGeometricTransform * gt)
GstGeometricTransformClass *klass;
gdouble *ptr;
+ GST_INFO_OBJECT (gt, "Generating new transform map");
+
/* cleanup old map */
g_free (gt->map);
gt->map = NULL;
@@ -143,9 +145,11 @@ gst_geometric_transform_generate_map (GstGeometricTransform * gt)
}
end:
- if (!ret)
+ if (!ret) {
+ GST_WARNING_OBJECT (gt, "Generating transform map failed");
g_free (gt->map);
- else
+ gt->map = NULL;
+ } else
gt->needs_remap = FALSE;
return ret;
}
@@ -174,8 +178,8 @@ gst_geometric_transform_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
/* regenerate the map */
GST_OBJECT_LOCK (gt);
- if (old_width == 0 || old_height == 0 || gt->width != old_width ||
- gt->height != old_height) {
+ if (gt->map == NULL || old_width == 0 || old_height == 0
+ || gt->width != old_width || gt->height != old_height) {
if (klass->prepare_func)
if (!klass->prepare_func (gt)) {
GST_OBJECT_UNLOCK (gt);
@@ -347,7 +351,13 @@ gst_geometric_transform_stop (GstBaseTransform * trans)
{
GstGeometricTransform *gt = GST_GEOMETRIC_TRANSFORM_CAST (trans);
+ GST_INFO_OBJECT (gt, "Deleting transform map");
+
+ gt->width = 0;
+ gt->height = 0;
+
g_free (gt->map);
+ gt->map = NULL;
return TRUE;
}
diff --git a/gst/hls/gsthlsdemux.c b/gst/hls/gsthlsdemux.c
index eeb2ff38a..5e9ebb595 100644
--- a/gst/hls/gsthlsdemux.c
+++ b/gst/hls/gsthlsdemux.c
@@ -343,9 +343,8 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
GstSeekType start_type, stop_type;
gint64 start, stop;
GList *walk;
- gint current_pos;
+ GstClockTime current_pos, target_pos;
gint current_sequence;
- gint target_second;
GstM3U8MediaFile *file;
GST_INFO_OBJECT (demux, "Received GST_EVENT_SEEK");
@@ -369,14 +368,13 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data);
current_sequence = file->sequence;
current_pos = 0;
- target_second = start / GST_SECOND;
- GST_DEBUG_OBJECT (demux, "Target seek to %d", target_second);
+ target_pos = (GstClockTime) start;
for (walk = demux->client->current->files; walk; walk = walk->next) {
file = walk->data;
current_sequence = file->sequence;
- if (current_pos <= target_second
- && target_second < current_pos + file->duration) {
+ if (current_pos <= target_pos
+ && target_pos < current_pos + file->duration) {
break;
}
current_pos += file->duration;
@@ -847,7 +845,6 @@ gst_hls_demux_make_fetcher_locked (GstHLSDemux * demux, const gchar * uri)
demux->stopping_fetcher = FALSE;
gst_element_set_bus (GST_ELEMENT (demux->fetcher), demux->fetcher_bus);
- g_object_set (G_OBJECT (demux->fetcher), "location", uri, NULL);
pad = gst_element_get_static_pad (demux->fetcher, "src");
if (pad) {
gst_pad_link (pad, demux->fetcherpad);
@@ -1069,6 +1066,8 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
gst_m3u8_client_get_target_duration (demux->client)
/ GST_SECOND * G_USEC_PER_SEC);
if (!gst_hls_demux_get_next_fragment (demux)) {
+ if (demux->end_of_playlist)
+ break;
if (!demux->cancelled)
GST_ERROR_OBJECT (demux, "Error caching the first fragments");
return FALSE;
diff --git a/gst/hls/m3u8.c b/gst/hls/m3u8.c
index c27f159b5..eecb467e2 100644
--- a/gst/hls/m3u8.c
+++ b/gst/hls/m3u8.c
@@ -20,6 +20,7 @@
*/
#include <stdlib.h>
+#include <math.h>
#include <errno.h>
#include <glib.h>
@@ -34,7 +35,7 @@ static void gst_m3u8_free (GstM3U8 * m3u8);
static gboolean gst_m3u8_update (GstM3U8 * m3u8, gchar * data,
gboolean * updated);
static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri,
- gchar * title, gint duration, guint sequence);
+ gchar * title, GstClockTime duration, guint sequence);
static void gst_m3u8_media_file_free (GstM3U8MediaFile * self);
static GstM3U8 *
@@ -77,7 +78,7 @@ gst_m3u8_free (GstM3U8 * self)
}
static GstM3U8MediaFile *
-gst_m3u8_media_file_new (gchar * uri, gchar * title, gint duration,
+gst_m3u8_media_file_new (gchar * uri, gchar * title, GstClockTime duration,
guint sequence)
{
GstM3U8MediaFile *file;
@@ -132,6 +133,36 @@ int_from_string (gchar * ptr, gchar ** endptr, gint * val)
}
static gboolean
+double_from_string (gchar * ptr, gchar ** endptr, gdouble * val)
+{
+ gchar *end;
+ gdouble ret;
+
+ g_return_val_if_fail (ptr != NULL, FALSE);
+ g_return_val_if_fail (val != NULL, FALSE);
+
+ errno = 0;
+ ret = strtod (ptr, &end);
+ if ((errno == ERANGE && (ret == HUGE_VAL || ret == -HUGE_VAL))
+ || (errno != 0 && ret == 0)) {
+ GST_WARNING ("%s", g_strerror (errno));
+ return FALSE;
+ }
+
+ if (!isfinite (ret)) {
+ GST_WARNING ("%s", g_strerror (ERANGE));
+ return FALSE;
+ }
+
+ if (endptr)
+ *endptr = end;
+
+ *val = (gint) ret;
+
+ return end != ptr;
+}
+
+static gboolean
parse_attributes (gchar ** ptr, gchar ** a, gchar ** v)
{
gchar *end, *p;
@@ -186,7 +217,8 @@ gst_m3u8_compare_playlist_by_bitrate (gconstpointer a, gconstpointer b)
static gboolean
gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
{
- gint val, duration;
+ gint val;
+ GstClockTime duration;
gchar *title, *end;
// gboolean discontinuity;
GstM3U8 *list;
@@ -222,7 +254,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
}
list = NULL;
- duration = -1;
+ duration = 0;
title = NULL;
data += 7;
while (TRUE) {
@@ -233,7 +265,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
if (data[0] != '#') {
gchar *r;
- if (duration < 0 && list == NULL) {
+ if (duration <= 0 && list == NULL) {
GST_LOG ("%s: got line without EXTINF or EXTSTREAMINF, dropping", data);
goto next_line;
}
@@ -277,7 +309,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
file =
gst_m3u8_media_file_new (data, title, duration,
self->mediasequence++);
- duration = -1;
+ duration = 0;
title = NULL;
self->files = g_list_append (self->files, file);
}
@@ -321,7 +353,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
}
} else if (g_str_has_prefix (data, "#EXT-X-TARGETDURATION:")) {
if (int_from_string (data + 22, &data, &val))
- self->targetduration = val;
+ self->targetduration = val * GST_SECOND;
} else if (g_str_has_prefix (data, "#EXT-X-MEDIA-SEQUENCE:")) {
if (int_from_string (data + 22, &data, &val))
self->mediasequence = val;
@@ -334,11 +366,12 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
g_free (self->allowcache);
self->allowcache = g_strdup (data + 19);
} else if (g_str_has_prefix (data, "#EXTINF:")) {
- if (!int_from_string (data + 8, &data, &val)) {
+ gdouble fval;
+ if (!double_from_string (data + 8, &data, &fval)) {
GST_WARNING ("Can't read EXTINF duration");
goto next_line;
}
- duration = val;
+ duration = fval * (gdouble) GST_SECOND;
if (duration > self->targetduration)
GST_WARNING ("EXTINF duration > TARGETDURATION");
if (!data || *data != ',')
@@ -485,7 +518,6 @@ gst_m3u8_client_get_current_position (GstM3U8Client * client,
break;
*timestamp += GST_M3U8_MEDIA_FILE (walk->data)->duration;
}
- *timestamp *= GST_SECOND;
}
gboolean
@@ -517,7 +549,7 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
client->sequence = file->sequence + 1;
*uri = file->uri;
- *duration = file->duration * GST_SECOND;
+ *duration = file->duration;
GST_M3U8_CLIENT_UNLOCK (client);
return TRUE;
@@ -545,7 +577,7 @@ gst_m3u8_client_get_duration (GstM3U8Client * client)
g_list_foreach (client->current->files, (GFunc) _sum_duration, &duration);
GST_M3U8_CLIENT_UNLOCK (client);
- return duration * GST_SECOND;
+ return duration;
}
GstClockTime
@@ -558,7 +590,7 @@ gst_m3u8_client_get_target_duration (GstM3U8Client * client)
GST_M3U8_CLIENT_LOCK (client);
duration = client->current->targetduration;
GST_M3U8_CLIENT_UNLOCK (client);
- return duration * GST_SECOND;
+ return duration;
}
const gchar *
diff --git a/gst/hls/m3u8.h b/gst/hls/m3u8.h
index a428a67a4..a03828716 100644
--- a/gst/hls/m3u8.h
+++ b/gst/hls/m3u8.h
@@ -41,7 +41,7 @@ struct _GstM3U8
gboolean endlist; /* if ENDLIST has been reached */
gint version; /* last EXT-X-VERSION */
- gint targetduration; /* last EXT-X-TARGETDURATION */
+ GstClockTime targetduration; /* last EXT-X-TARGETDURATION */
gchar *allowcache; /* last EXT-X-ALLOWCACHE */
gint bandwidth;
@@ -62,7 +62,7 @@ struct _GstM3U8
struct _GstM3U8MediaFile
{
gchar *title;
- gint duration;
+ GstClockTime duration;
gchar *uri;
guint sequence; /* the sequence nb of this file */
};
diff --git a/gst/inter/gstinteraudiosink.c b/gst/inter/gstinteraudiosink.c
index e5ba92687..fd5987e35 100644
--- a/gst/inter/gstinteraudiosink.c
+++ b/gst/inter/gstinteraudiosink.c
@@ -19,14 +19,21 @@
/**
* SECTION:element-gstinteraudiosink
*
- * The interaudiosink element does FIXME stuff.
+ * The interaudiosink element is an audio sink element. It is used
+ * in connection with a interaudiosrc element in a different pipeline,
+ * similar to intervideosink and intervideosrc.
*
* <refsect2>
* <title>Example launch line</title>
* |[
- * gst-launch -v fakesrc ! interaudiosink ! FIXME ! fakesink
+ * gst-launch -v audiotestsrc ! queue ! interaudiosink
* ]|
- * FIXME Describe what the pipeline does.
+ *
+ * The interaudiosink element cannot be used effectively with gst-launch,
+ * as it requires a second pipeline in the application to receive the
+ * audio.
+ * See the gstintertest.c example in the gst-plugins-bad source code for
+ * more details.
* </refsect2>
*/
@@ -91,8 +98,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"endianness = (int) BYTE_ORDER, "
"signed = (boolean) true, "
"width = (int) 16, "
- "depth = (int) 16, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
+ "depth = (int) 16, " "rate = (int) 48000, " "channels = (int) 2")
);
@@ -113,8 +119,11 @@ gst_inter_audio_sink_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_inter_audio_sink_sink_template));
- gst_element_class_set_details_simple (element_class, "FIXME Long name",
- "Generic", "FIXME Description", "FIXME <fixme@example.com>");
+ gst_element_class_set_details_simple (element_class,
+ "Internal audio sink",
+ "Sink/Audio",
+ "Virtual audio sink for internal process communication",
+ "David Schleef <ds@schleef.org>");
}
static void
@@ -151,26 +160,32 @@ gst_inter_audio_sink_class_init (GstInterAudioSinkClass * klass)
base_sink_class->unlock_stop =
GST_DEBUG_FUNCPTR (gst_inter_audio_sink_unlock_stop);
+#if 0
g_object_class_install_property (gobject_class, PROP_CHANNEL,
g_param_spec_string ("channel", "Channel",
"Channel name to match inter src and sink elements",
"default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
}
static void
gst_inter_audio_sink_init (GstInterAudioSink * interaudiosink,
GstInterAudioSinkClass * interaudiosink_class)
{
- interaudiosink->surface = gst_inter_surface_get ("default");
+ interaudiosink->channel = g_strdup ("default");
}
void
gst_inter_audio_sink_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
- /* GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object); */
+ GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_free (interaudiosink->channel);
+ interaudiosink->channel = g_value_dup_string (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -181,9 +196,12 @@ void
gst_inter_audio_sink_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
- /* GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object); */
+ GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_value_set_string (value, interaudiosink->channel);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -259,6 +277,11 @@ gst_inter_audio_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
static gboolean
gst_inter_audio_sink_start (GstBaseSink * sink)
{
+ GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink);
+
+ GST_DEBUG ("start");
+
+ interaudiosink->surface = gst_inter_surface_get (interaudiosink->channel);
return TRUE;
}
@@ -274,6 +297,9 @@ gst_inter_audio_sink_stop (GstBaseSink * sink)
gst_adapter_clear (interaudiosink->surface->audio_adapter);
g_mutex_unlock (interaudiosink->surface->mutex);
+ gst_inter_surface_unref (interaudiosink->surface);
+ interaudiosink->surface = NULL;
+
return TRUE;
}
diff --git a/gst/inter/gstinteraudiosink.h b/gst/inter/gstinteraudiosink.h
index b0a32769e..5ea09997a 100644
--- a/gst/inter/gstinteraudiosink.h
+++ b/gst/inter/gstinteraudiosink.h
@@ -39,6 +39,7 @@ struct _GstInterAudioSink
GstBaseSink base_interaudiosink;
GstInterSurface *surface;
+ char *channel;
int fps_n;
int fps_d;
diff --git a/gst/inter/gstinteraudiosrc.c b/gst/inter/gstinteraudiosrc.c
index e659bf024..de2b2687a 100644
--- a/gst/inter/gstinteraudiosrc.c
+++ b/gst/inter/gstinteraudiosrc.c
@@ -19,14 +19,19 @@
/**
* SECTION:element-gstinteraudiosrc
*
- * The interaudiosrc element does FIXME stuff.
+ * The interaudiosrc element is an audio source element. It is used
+ * in connection with a interaudiosink element in a different pipeline.
*
* <refsect2>
* <title>Example launch line</title>
* |[
- * gst-launch -v fakesrc ! interaudiosrc ! FIXME ! fakesink
+ * gst-launch -v interaudiosrc ! queue ! audiosink
* ]|
- * FIXME Describe what the pipeline does.
+ *
+ * The interaudiosrc element cannot be used effectively with gst-launch,
+ * as it requires a second pipeline in the application to send audio.
+ * See the gstintertest.c example in the gst-plugins-bad source code for
+ * more details.
* </refsect2>
*/
@@ -93,8 +98,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
"endianness = (int) BYTE_ORDER, "
"signed = (boolean) true, "
"width = (int) 16, "
- "depth = (int) 16, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
+ "depth = (int) 16, " "rate = (int) 48000, " "channels = (int) 2")
);
@@ -115,8 +119,11 @@ gst_inter_audio_src_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_inter_audio_src_src_template));
- gst_element_class_set_details_simple (element_class, "FIXME Long name",
- "Generic", "FIXME Description", "FIXME <fixme@example.com>");
+ gst_element_class_set_details_simple (element_class,
+ "Internal audio source",
+ "Source/Audio",
+ "Virtual audio source for internal process communication",
+ "David Schleef <ds@schleef.org>");
}
static void
@@ -159,11 +166,12 @@ gst_inter_audio_src_class_init (GstInterAudioSrcClass * klass)
base_src_class->prepare_seek_segment =
GST_DEBUG_FUNCPTR (gst_inter_audio_src_prepare_seek_segment);
+#if 0
g_object_class_install_property (gobject_class, PROP_CHANNEL,
g_param_spec_string ("channel", "Channel",
"Channel name to match inter src and sink elements",
"default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
+#endif
}
static void
@@ -174,16 +182,20 @@ gst_inter_audio_src_init (GstInterAudioSrc * interaudiosrc,
gst_base_src_set_live (GST_BASE_SRC (interaudiosrc), TRUE);
gst_base_src_set_blocksize (GST_BASE_SRC (interaudiosrc), -1);
- interaudiosrc->surface = gst_inter_surface_get ("default");
+ interaudiosrc->channel = g_strdup ("default");
}
void
gst_inter_audio_src_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
- /* GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object); */
+ GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_free (interaudiosrc->channel);
+ interaudiosrc->channel = g_value_dup_string (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -194,9 +206,12 @@ void
gst_inter_audio_src_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
- /* GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object); */
+ GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_value_set_string (value, interaudiosrc->channel);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -281,6 +296,8 @@ gst_inter_audio_src_start (GstBaseSrc * src)
GST_DEBUG_OBJECT (interaudiosrc, "start");
+ interaudiosrc->surface = gst_inter_surface_get (interaudiosrc->channel);
+
return TRUE;
}
@@ -291,6 +308,9 @@ gst_inter_audio_src_stop (GstBaseSrc * src)
GST_DEBUG_OBJECT (interaudiosrc, "stop");
+ gst_inter_surface_unref (interaudiosrc->surface);
+ interaudiosrc->surface = NULL;
+
return TRUE;
}
@@ -345,12 +365,20 @@ static gboolean
gst_inter_audio_src_event (GstBaseSrc * src, GstEvent * event)
{
GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
+ gboolean ret;
GST_DEBUG_OBJECT (interaudiosrc, "event");
- return TRUE;
+ switch (GST_EVENT_TYPE (event)) {
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
+ }
+
+ return ret;
}
+#define SIZE 1600
+
static GstFlowReturn
gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size,
GstBuffer ** buf)
@@ -365,31 +393,31 @@ gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size,
g_mutex_lock (interaudiosrc->surface->mutex);
n = gst_adapter_available (interaudiosrc->surface->audio_adapter) / 4;
- if (n > 1600 * 2) {
- GST_DEBUG ("flushing %d samples", 800);
- gst_adapter_flush (interaudiosrc->surface->audio_adapter, 800 * 4);
- n -= 800;
+ if (n > SIZE * 2) {
+ GST_DEBUG ("flushing %d samples", SIZE / 2);
+ gst_adapter_flush (interaudiosrc->surface->audio_adapter, (SIZE / 2) * 4);
+ n -= (SIZE / 2);
}
- if (n > 1600)
- n = 1600;
+ if (n > SIZE)
+ n = SIZE;
if (n > 0) {
buffer = gst_adapter_take_buffer (interaudiosrc->surface->audio_adapter,
n * 4);
}
g_mutex_unlock (interaudiosrc->surface->mutex);
- if (n < 1600) {
- GstBuffer *newbuf = gst_buffer_new_and_alloc (1600 * 4);
+ if (n < SIZE) {
+ GstBuffer *newbuf = gst_buffer_new_and_alloc (SIZE * 4);
- GST_DEBUG ("creating %d samples of silence", 1600 - n);
- memset (GST_BUFFER_DATA (newbuf) + n * 4, 0, 1600 * 4 - n * 4);
+ GST_DEBUG ("creating %d samples of silence", SIZE - n);
+ memset (GST_BUFFER_DATA (newbuf) + n * 4, 0, SIZE * 4 - n * 4);
if (buffer) {
memcpy (GST_BUFFER_DATA (newbuf), GST_BUFFER_DATA (buffer), n * 4);
gst_buffer_unref (buffer);
}
buffer = newbuf;
}
- n = 1600;
+ n = SIZE;
GST_BUFFER_OFFSET (buffer) = interaudiosrc->n_samples;
GST_BUFFER_OFFSET_END (buffer) = interaudiosrc->n_samples + n;
@@ -429,10 +457,34 @@ static gboolean
gst_inter_audio_src_query (GstBaseSrc * src, GstQuery * query)
{
GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
+ gboolean ret;
GST_DEBUG_OBJECT (interaudiosrc, "query");
- return TRUE;
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:{
+ GstClockTime min_latency, max_latency;
+
+ min_latency = 30 * gst_util_uint64_scale_int (GST_SECOND, SIZE, 48000);
+
+ max_latency = min_latency;
+
+ GST_ERROR_OBJECT (src,
+ "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+ gst_query_set_latency (query,
+ gst_base_src_is_live (src), min_latency, max_latency);
+
+ ret = TRUE;
+ break;
+ }
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
+ break;
+ }
+
+ return ret;
}
static gboolean
diff --git a/gst/inter/gstinteraudiosrc.h b/gst/inter/gstinteraudiosrc.h
index 958a1a53d..4ccc7f5c5 100644
--- a/gst/inter/gstinteraudiosrc.h
+++ b/gst/inter/gstinteraudiosrc.h
@@ -39,6 +39,7 @@ struct _GstInterAudioSrc
GstBaseSrc base_interaudiosrc;
GstInterSurface *surface;
+ char *channel;
guint64 n_samples;
int sample_rate;
diff --git a/gst/inter/gstintersubsink.c b/gst/inter/gstintersubsink.c
index 1328b18a5..a42b3e573 100644
--- a/gst/inter/gstintersubsink.c
+++ b/gst/inter/gstintersubsink.c
@@ -19,14 +19,19 @@
/**
* SECTION:element-gstintersubsink
*
- * The intersubsink element does FIXME stuff.
+ * The intersubsink element is a subtitle sink element. It is used
+ * in connection with a intersubsrc element in a different pipeline.
*
* <refsect2>
* <title>Example launch line</title>
* |[
- * gst-launch -v fakesrc ! intersubsink ! FIXME ! fakesink
+ * gst-launch -v ... ! intersubsink
* ]|
- * FIXME Describe what the pipeline does.
+ *
+ * The intersubsink element cannot be used effectively with gst-launch,
+ * as it requires a second pipeline in the application to send audio.
+ * See the gstintertest.c example in the gst-plugins-bad source code for
+ * more details.
* </refsect2>
*/
@@ -73,7 +78,8 @@ static gboolean gst_inter_sub_sink_unlock_stop (GstBaseSink * sink);
enum
{
- PROP_0
+ PROP_0,
+ PROP_CHANNEL
};
/* pad templates */
@@ -103,8 +109,11 @@ gst_inter_sub_sink_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_inter_sub_sink_sink_template));
- gst_element_class_set_details_simple (element_class, "FIXME Long name",
- "Generic", "FIXME Description", "FIXME <fixme@example.com>");
+ gst_element_class_set_details_simple (element_class,
+ "Internal subtitle sink",
+ "Sink/Subtitle",
+ "Virtual subtitle sink for internal process communication",
+ "David Schleef <ds@schleef.org>");
}
static void
@@ -139,6 +148,11 @@ gst_inter_sub_sink_class_init (GstInterSubSinkClass * klass)
base_sink_class->unlock_stop =
GST_DEBUG_FUNCPTR (gst_inter_sub_sink_unlock_stop);
+ g_object_class_install_property (gobject_class, PROP_CHANNEL,
+ g_param_spec_string ("channel", "Channel",
+ "Channel name to match inter src and sink elements",
+ "default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
}
static void
@@ -146,7 +160,7 @@ gst_inter_sub_sink_init (GstInterSubSink * intersubsink,
GstInterSubSinkClass * intersubsink_class)
{
- intersubsink->surface = gst_inter_surface_get ("default");
+ intersubsink->channel = g_strdup ("default");
intersubsink->fps_n = 1;
intersubsink->fps_d = 1;
@@ -156,9 +170,13 @@ void
gst_inter_sub_sink_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
- /* GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object); */
+ GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_free (intersubsink->channel);
+ intersubsink->channel = g_value_dup_string (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -169,9 +187,12 @@ void
gst_inter_sub_sink_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
- /* GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object); */
+ GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_value_set_string (value, intersubsink->channel);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -247,6 +268,9 @@ gst_inter_sub_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
static gboolean
gst_inter_sub_sink_start (GstBaseSink * sink)
{
+ GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
+
+ intersubsink->surface = gst_inter_surface_get (intersubsink->channel);
return TRUE;
}
@@ -263,6 +287,9 @@ gst_inter_sub_sink_stop (GstBaseSink * sink)
intersubsink->surface->sub_buffer = NULL;
g_mutex_unlock (intersubsink->surface->mutex);
+ gst_inter_surface_unref (intersubsink->surface);
+ intersubsink->surface = NULL;
+
return TRUE;
}
diff --git a/gst/inter/gstintersubsink.h b/gst/inter/gstintersubsink.h
index be2da9b3b..33b48f78f 100644
--- a/gst/inter/gstintersubsink.h
+++ b/gst/inter/gstintersubsink.h
@@ -40,6 +40,7 @@ struct _GstInterSubSink
GstPad *sinkpad;
GstInterSurface *surface;
+ char *channel;
int fps_n;
int fps_d;
diff --git a/gst/inter/gstintersubsrc.c b/gst/inter/gstintersubsrc.c
index 60a29b3d7..437a3e1ea 100644
--- a/gst/inter/gstintersubsrc.c
+++ b/gst/inter/gstintersubsrc.c
@@ -31,6 +31,8 @@
*
* The intersubsrc element cannot be used effectively with gst-launch,
* as it requires a second pipeline in the application to send subtitles.
+ * See the gstintertest.c example in the gst-plugins-bad source code for
+ * more details.
* </refsect2>
*/
@@ -82,7 +84,8 @@ gst_inter_sub_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek,
enum
{
- PROP_0
+ PROP_0,
+ PROP_CHANNEL
};
/* pad templates */
@@ -113,9 +116,10 @@ gst_inter_sub_src_base_init (gpointer g_class)
gst_static_pad_template_get (&gst_inter_sub_src_src_template));
gst_element_class_set_details_simple (element_class,
- "Inter-pipeline subtitle source",
- "Source/Subtitle", "Inter-pipeline subtitle source",
- "David Schleef <ds@entropywave.com>");
+ "Internal subtitle source",
+ "Source/Subtitle",
+ "Virtual subtitle source for internal process communication",
+ "David Schleef <ds@schleef.org>");
}
static void
@@ -159,7 +163,10 @@ gst_inter_sub_src_class_init (GstInterSubSrcClass * klass)
base_src_class->prepare_seek_segment =
GST_DEBUG_FUNCPTR (gst_inter_sub_src_prepare_seek_segment);
-
+ g_object_class_install_property (gobject_class, PROP_CHANNEL,
+ g_param_spec_string ("channel", "Channel",
+ "Channel name to match inter src and sink elements",
+ "default", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
@@ -173,16 +180,20 @@ gst_inter_sub_src_init (GstInterSubSrc * intersubsrc,
gst_base_src_set_format (GST_BASE_SRC (intersubsrc), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (intersubsrc), TRUE);
- intersubsrc->surface = gst_inter_surface_get ("default");
+ intersubsrc->channel = g_strdup ("default");
}
void
gst_inter_sub_src_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
- /* GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object); */
+ GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_free (intersubsrc->channel);
+ intersubsrc->channel = g_value_dup_string (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -193,9 +204,12 @@ void
gst_inter_sub_src_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
- /* GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object); */
+ GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object);
switch (property_id) {
+ case PROP_CHANNEL:
+ g_value_set_string (value, intersubsrc->channel);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -270,6 +284,8 @@ gst_inter_sub_src_start (GstBaseSrc * src)
GST_DEBUG_OBJECT (intersubsrc, "start");
+ intersubsrc->surface = gst_inter_surface_get (intersubsrc->channel);
+
return TRUE;
}
@@ -280,6 +296,9 @@ gst_inter_sub_src_stop (GstBaseSrc * src)
GST_DEBUG_OBJECT (intersubsrc, "stop");
+ gst_inter_surface_unref (intersubsrc->surface);
+ intersubsrc->surface = NULL;
+
return TRUE;
}
@@ -334,10 +353,16 @@ static gboolean
gst_inter_sub_src_event (GstBaseSrc * src, GstEvent * event)
{
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
+ gboolean ret;
GST_DEBUG_OBJECT (intersubsrc, "event");
- return TRUE;
+ switch (GST_EVENT_TYPE (event)) {
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
+ }
+
+ return ret;
}
static GstFlowReturn
@@ -409,10 +434,16 @@ static gboolean
gst_inter_sub_src_query (GstBaseSrc * src, GstQuery * query)
{
GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
+ gboolean ret;
GST_DEBUG_OBJECT (intersubsrc, "query");
- return TRUE;
+ switch (GST_QUERY_TYPE (query)) {
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
+ }
+
+ return ret;
}
static gboolean
diff --git a/gst/inter/gstintersubsrc.h b/gst/inter/gstintersubsrc.h
index 74bfed1e7..38f7a6696 100644
--- a/gst/inter/gstintersubsrc.h
+++ b/gst/inter/gstintersubsrc.h
@@ -40,6 +40,7 @@ struct _GstInterSubSrc
GstPad *srcpad;
GstInterSurface *surface;
+ char *channel;
int rate;
int n_frames;
diff --git a/gst/inter/gstintertest.c b/gst/inter/gstintertest.c
index ff4c65f47..269d64279 100644
--- a/gst/inter/gstintertest.c
+++ b/gst/inter/gstintertest.c
@@ -1,5 +1,5 @@
/* GstInterTest
- * Copyright (C) 2011 FIXME <fixme@example.com>
+ * Copyright (C) 2011 David Schleef <ds@schleef.org>
* Copyright (C) 2010 Entropy Wave Inc
*
* Redistribution and use in source and binary forms, with or without
@@ -86,7 +86,7 @@ main (int argc, char *argv[])
g_thread_init (NULL);
#endif
- context = g_option_context_new ("- FIXME");
+ context = g_option_context_new ("- Internal src/sink test");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_add_group (context, gst_init_get_option_group ());
if (!g_option_context_parse (context, &argc, &argv, &error)) {
@@ -188,14 +188,14 @@ gst_inter_test_create_pipeline_vts (GstInterTest * intertest)
pipe_desc = g_string_new ("");
- g_string_append (pipe_desc, "videotestsrc name=source num-buffers=10000 ! ");
+ g_string_append (pipe_desc, "videotestsrc name=source num-buffers=100 ! ");
g_string_append (pipe_desc,
"video/x-raw-yuv,format=(fourcc)I420,width=320,height=240 ! ");
g_string_append (pipe_desc, "timeoverlay ! ");
g_string_append (pipe_desc, "intervideosink name=sink sync=true ");
g_string_append (pipe_desc,
- "audiotestsrc samplesperbuffer=1600 num-buffers=100 ! ");
- g_string_append (pipe_desc, "interaudiosink ");
+ "audiotestsrc samplesperbuffer=1600 num-buffers=100 ! audioconvert ! ");
+ g_string_append (pipe_desc, "interaudiosink sync=true ");
if (verbose)
g_print ("pipeline: %s\n", pipe_desc->str);
@@ -232,7 +232,7 @@ gst_inter_test_create_pipeline_server (GstInterTest * intertest)
g_string_append (pipe_desc, "intervideosrc ! queue ! ");
g_string_append (pipe_desc, "xvimagesink name=sink ");
g_string_append (pipe_desc, "interaudiosrc ! queue ! ");
- g_string_append (pipe_desc, "alsasink latency-time=100000000 ");
+ g_string_append (pipe_desc, "alsasink ");
if (verbose)
g_print ("pipeline: %s\n", pipe_desc->str);
@@ -337,7 +337,7 @@ gst_inter_test_handle_paused_to_ready (GstInterTest * intertest)
static void
gst_inter_test_handle_ready_to_null (GstInterTest * intertest)
{
- g_main_loop_quit (intertest->main_loop);
+ //g_main_loop_quit (intertest->main_loop);
}
diff --git a/gst/inter/gstintervideosink.c b/gst/inter/gstintervideosink.c
index b6be4e99a..d80047e0d 100644
--- a/gst/inter/gstintervideosink.c
+++ b/gst/inter/gstintervideosink.c
@@ -19,14 +19,20 @@
/**
* SECTION:element-gstintervideosink
*
- * The intervideosink element does FIXME stuff.
+ * The intervideosink element is a video sink element. It is used
+ * in connection with an intervideosrc element in a different pipeline,
+ * similar to interaudiosink and interaudiosrc.
*
* <refsect2>
* <title>Example launch line</title>
* |[
- * gst-launch -v fakesrc ! intervideosink ! FIXME ! fakesink
+ * gst-launch -v videotestsrc ! intervideosink
* ]|
- * FIXME Describe what the pipeline does.
+ *
+ * The intervideosink element cannot be used effectively with gst-launch,
+ * as it requires a second pipeline in the application to send video to.
+ * See the gstintertest.c example in the gst-plugins-bad source code for
+ * more details.
* </refsect2>
*/
@@ -107,8 +113,11 @@ gst_inter_video_sink_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_inter_video_sink_sink_template));
- gst_element_class_set_details_simple (element_class, "FIXME Long name",
- "Generic", "FIXME Description", "FIXME <fixme@example.com>");
+ gst_element_class_set_details_simple (element_class,
+ "Internal video sink",
+ "Sink/Video",
+ "Virtual video sink for internal process communication",
+ "David Schleef <ds@schleef.org>");
}
static void
@@ -155,8 +164,6 @@ static void
gst_inter_video_sink_init (GstInterVideoSink * intervideosink,
GstInterVideoSinkClass * intervideosink_class)
{
- intervideosink->surface = gst_inter_surface_get ("default");
-
intervideosink->channel = g_strdup ("default");
}
diff --git a/gst/inter/gstintervideosrc.c b/gst/inter/gstintervideosrc.c
index 65fc7f0e5..ec323e372 100644
--- a/gst/inter/gstintervideosrc.c
+++ b/gst/inter/gstintervideosrc.c
@@ -19,14 +19,18 @@
/**
* SECTION:element-gstintervideosrc
*
- * The intervideosrc element does FIXME stuff.
+ * The intervideosrc element is a video source element. It is used
+ * in connection with a intervideosink element in a different pipeline,
+ * similar to interaudiosink and interaudiosrc.
*
* <refsect2>
* <title>Example launch line</title>
* |[
- * gst-launch -v fakesrc ! intervideosrc ! FIXME ! fakesink
+ * gst-launch -v intervideosrc ! queue ! xvimagesink
* ]|
- * FIXME Describe what the pipeline does.
+ *
+ * The intersubsrc element cannot be used effectively with gst-launch,
+ * as it requires a second pipeline in the application to send subtitles.
* </refsect2>
*/
@@ -111,8 +115,11 @@ gst_inter_video_src_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_inter_video_src_src_template));
- gst_element_class_set_details_simple (element_class, "FIXME Long name",
- "Generic", "FIXME Description", "FIXME <fixme@example.com>");
+ gst_element_class_set_details_simple (element_class,
+ "Internal video source",
+ "Source/Video",
+ "Virtual video source for internal process communication",
+ "David Schleef <ds@schleef.org>");
}
static void
@@ -361,10 +368,16 @@ static gboolean
gst_inter_video_src_event (GstBaseSrc * src, GstEvent * event)
{
GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (src);
+ gboolean ret;
GST_DEBUG_OBJECT (intervideosrc, "event");
- return TRUE;
+ switch (GST_EVENT_TYPE (event)) {
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
+ }
+
+ return ret;
}
static GstFlowReturn
@@ -450,10 +463,16 @@ static gboolean
gst_inter_video_src_query (GstBaseSrc * src, GstQuery * query)
{
GstInterVideoSrc *intervideosrc = GST_INTER_VIDEO_SRC (src);
+ gboolean ret;
GST_DEBUG_OBJECT (intervideosrc, "query");
- return TRUE;
+ switch (GST_QUERY_TYPE (query)) {
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
+ }
+
+ return ret;
}
static gboolean
diff --git a/gst/jp2kdecimator/jp2kcodestream.c b/gst/jp2kdecimator/jp2kcodestream.c
index cbff65414..9c85a0bd7 100644
--- a/gst/jp2kdecimator/jp2kcodestream.c
+++ b/gst/jp2kdecimator/jp2kcodestream.c
@@ -574,8 +574,8 @@ parse_cod (GstJP2kDecimator * self, GstByteReader * reader,
}
Scod = gst_byte_reader_get_uint8_unchecked (reader);
- cod->sop = !!(Scod & 0x02);
- cod->eph = !!(Scod & 0x04);
+ cod->sop = ! !(Scod & 0x02);
+ cod->eph = ! !(Scod & 0x04);
/* SGcod */
cod->progression_order = gst_byte_reader_get_uint8_unchecked (reader);
@@ -828,7 +828,11 @@ write_plt (GstJP2kDecimator * self, GstByteWriter * writer,
plt_end_pos = gst_byte_writer_get_pos (writer);
gst_byte_writer_set_pos (writer, plt_start_pos);
- gst_byte_writer_put_uint16_be (writer, plt_end_pos - plt_start_pos);
+ if (!gst_byte_writer_put_uint16_be (writer, plt_end_pos - plt_start_pos)) {
+ GST_ERROR_OBJECT (self, "Not enough space to write plt size");
+ return GST_FLOW_ERROR;
+ }
+
gst_byte_writer_set_pos (writer, plt_end_pos);
return GST_FLOW_OK;
@@ -1328,9 +1332,9 @@ write_packet (GstJP2kDecimator * self, GstByteWriter * writer,
}
if (packet->sop) {
- gst_byte_writer_put_uint16_be (writer, MARKER_SOP);
- gst_byte_writer_put_uint16_be (writer, 4);
- gst_byte_writer_put_uint16_be (writer, packet->seqno);
+ gst_byte_writer_put_uint16_be_unchecked (writer, MARKER_SOP);
+ gst_byte_writer_put_uint16_be_unchecked (writer, 4);
+ gst_byte_writer_put_uint16_be_unchecked (writer, packet->seqno);
}
if (packet->data) {
@@ -1696,7 +1700,7 @@ write_main_header (GstJP2kDecimator * self, GstByteWriter * writer,
return GST_FLOW_ERROR;
}
- gst_byte_writer_put_uint16_be (writer, MARKER_SOC);
+ gst_byte_writer_put_uint16_be_unchecked (writer, MARKER_SOC);
ret = write_siz (self, writer, &header->siz);
if (ret != GST_FLOW_OK)
diff --git a/gst/mpegdemux/flutspmtinfo.c b/gst/mpegdemux/flutspmtinfo.c
index 65402e738..5b25e258c 100644
--- a/gst/mpegdemux/flutspmtinfo.c
+++ b/gst/mpegdemux/flutspmtinfo.c
@@ -45,6 +45,10 @@
#include "config.h"
#endif
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include <gst/gst.h>
#include "flutspmtinfo.h"
diff --git a/gst/mpegdemux/flutspmtstreaminfo.c b/gst/mpegdemux/flutspmtstreaminfo.c
index 7ab5ba43c..95177f82f 100644
--- a/gst/mpegdemux/flutspmtstreaminfo.c
+++ b/gst/mpegdemux/flutspmtstreaminfo.c
@@ -45,6 +45,10 @@
#include "config.h"
#endif
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include <gst/gst.h>
#include "flutspmtstreaminfo.h"
diff --git a/gst/mpegdemux/gstmpegdemux.c b/gst/mpegdemux/gstmpegdemux.c
index 1b67ce0d0..e87642d67 100644
--- a/gst/mpegdemux/gstmpegdemux.c
+++ b/gst/mpegdemux/gstmpegdemux.c
@@ -662,7 +662,7 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
/* Store the language codes event on the element, then iterate over the
* streams it specifies and retrieve them. The stream creation code then
* creates the pad appropriately and sends tag events as needed */
- p_ev = &demux->lang_codes, event;
+ p_ev = &demux->lang_codes;
gst_event_replace (p_ev, event);
GST_DEBUG_OBJECT (demux, "Handling language codes event");
diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c
index 012c1cc71..78bf6568d 100644
--- a/gst/mpegdemux/gstmpegtsdemux.c
+++ b/gst/mpegdemux/gstmpegtsdemux.c
@@ -45,6 +45,10 @@
#include "config.h"
#endif
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include <string.h>
#include <stdlib.h>
@@ -3547,7 +3551,7 @@ gboolean
gst_mpegts_demux_plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "mpegtsdemux",
- GST_RANK_PRIMARY, GST_TYPE_MPEGTS_DEMUX))
+ GST_RANK_SECONDARY, GST_TYPE_MPEGTS_DEMUX))
return FALSE;
return TRUE;
diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c
index ed1d0ac0e..089254d2f 100644
--- a/gst/mpegdemux/mpegtspacketizer.c
+++ b/gst/mpegdemux/mpegtspacketizer.c
@@ -22,6 +22,10 @@
* Boston, MA 02111-1307, USA.
*/
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include <string.h>
#include "mpegtspacketizer.h"
diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c
index bac482462..f7ba07b0f 100644
--- a/gst/mpegdemux/mpegtsparse.c
+++ b/gst/mpegdemux/mpegtsparse.c
@@ -1042,7 +1042,7 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
MpegTSParseProgram *program;
guint program_number;
guint pcr_pid;
- guint pid;
+ guint pid = 0;
guint stream_type;
GstStructure *stream;
gint i;
diff --git a/gst/mpegtsdemux/Makefile.am b/gst/mpegtsdemux/Makefile.am
index 10e3f39e0..fb68be463 100644
--- a/gst/mpegtsdemux/Makefile.am
+++ b/gst/mpegtsdemux/Makefile.am
@@ -9,7 +9,6 @@ libgstmpegtsdemux_la_SOURCES = \
mpegtsbase.c \
mpegtspacketizer.c \
mpegtsparse.c \
- payload_parsers.c \
tsdemux.c \
pesparse.c
@@ -28,7 +27,6 @@ noinst_HEADERS = \
mpegtsbase.h \
mpegtspacketizer.h \
mpegtsparse.h \
- payload_parsers.h \
tsdemux.h \
pesparse.h
diff --git a/gst/mpegtsdemux/TODO b/gst/mpegtsdemux/TODO
index 66e1d5f1f..d4d2563a7 100644
--- a/gst/mpegtsdemux/TODO
+++ b/gst/mpegtsdemux/TODO
@@ -1,35 +1,30 @@
tsdemux/tsparse TODO
--------------------
-* clock for live streams
- In order for playback to happen at the same rate as on the producer,
- we need to estimate the remote clock based on capture time and PCR
- values.
- For this estimation to be as accurate as possible, the capture time
- needs to happen on the sources.
- => Ensure live sources actually timestamp their buffers
- Once we have accurate timestamps, we can use an algorithm to
- calculate the PCR/local-clock skew.
- => Use the EPTLA algorithm as used in -good/rtp/rtpmanager/
- gstrtpjitterbuffer
-
-* Seeking
- => Split out in a separate file/object. It is polluting tsdemux for
- code readability/clarity.
-
-* Perfomance : Creation/Destruction of buffers is slow
- * => This is due to g_type_instance_create using a dogslow rwlock
- which take up to 50% of gst_adapter_take_buffer()
- => Bugzilla #585375 (performance and contention problems)
-
-* mpegtspacketizer
- * offset/timestamp of incoming buffers need to be carried on to the
- sub-buffers in order for several demuxer features to work correctly.
+* Perfomance
+ * Bufferlist : Creating/Destroying very small buffers is too
+ costly. Switch to pre-/re-allocating outgoing buffers in which we
+ copy the data.
+ * Adapter : Use gst_adapter_peek()/_flush() instead of constantly
+ creating buffers.
+
+* Latency
+ * Calculate the actual latency instead of returning a fixed
+ value. The latency (for live streams) is the difference between the
+ currently inputted buffer timestamp (can be stored in the
+ packetizer) and the buffer we're pushing out.
+ This value should be reported/updated (leave a bit of extra margin
+ in addition to the calculated value).
* mpegtsparser
- * SERIOUS room for improvement performance-wise (see callgrind)
-
+ * SERIOUS room for improvement performance-wise (see callgrind),
+ mostly related to performance issues mentionned above.
+* Random-access seeking
+ * Do minimal parsing of video headers to detect keyframes and use
+ that to compute the keyframe intervals. Use that interval to offset
+ the seek position in order to maximize the chance of pushing out the
+ requested frames.
Synchronization, Scheduling and Timestamping
@@ -50,6 +45,9 @@ pay extra attention to the outgoing NEWSEGMENT event and buffer
timestamps in order to guarantee proper playback and synchronization
of the stream.
+ In the following, 'timestamps' correspond to GStreamer
+ buffer/segment values. The mpeg-ts PCR/DTS/PTS values are indicated
+ with their actual name.
1) Live push-based scheduling
@@ -60,26 +58,25 @@ of the stream.
the outgoing buffer timestamps need to correspond to the incoming
buffer timestamp values.
- => A delta, DTS_delta between incoming buffer timestamp and
- DTS/PTS needs to be computed.
+ => mpegtspacketizer keeps track of PCR and input timestamp and
+ extrapolates a clock skew using the EPTLA algorithm.
=> The outgoing buffers will be timestamped with their PTS values
- (overflow corrected) offseted by that initial DTS_delta.
+ (overflow corrected) corrected by that calculated clock skew.
A latency is introduced between the time the buffer containing the
first bit of a Access Unit is received in the demuxer and the moment
the demuxer pushed out the buffer corresponding to that Access Unit.
- => That latency needs to be reported. It corresponds to the
- biggest Access Unit spacing, in this case 1/video-framerate.
+ => That latency needs to be reported.
According to the ISO/IEC 13818-1:2007 specifications, D.0.1 Timing
mode, the "coded audio and video that represent sound and pictures
that are to be presented simultaneously may be separated in time
within the coded bit stream by ==>as much as one second<=="
- => The demuxer will therefore report an added latency of 1s to
- handle this interleave.
+ => The algorithm to calculate the latency should take that into
+ account.
2) Non-live push-based scheduling
@@ -97,11 +94,22 @@ of the stream.
do not have capture timestamps, we need to ensure the first buffer
we push out corresponds to the base segment start runing time.
- => A delta between the first DTS to output and the segment start
- position needs to be computed.
+ => The packetizer keeps track of PCR locations and offsets in
+ addition to the clock skew (in the case of upstream buffers
+ being timestamped, which is the case for HLS).
+
+ => The demuxer indicates to the packetizer when he sees the
+ 'beginning' of the program (i.e. the first valid PAT/PMT
+ combination). The packetizer will then use that location as
+ "timestamp 0", or "reference position/PCR".
+
+ => The lowest DTS is passed to the packetizer to be converted to
+ timestamp. That value is computed in the same way as live
+ streams if upstream buffers have timestamps, or will be
+ subtracted from the reference PCR.
=> The outgoing buffers will be timestamped with their PTS values
- (overflow corrected) offseted by that initial delta.
+ (overflow corrected) adjusted by the packetizer.
Latency is reported just as with the live use-case.
@@ -111,37 +119,13 @@ of the stream.
We do not get a NEWSEGMENT event from upstream, we therefore need to
compute the outgoing values.
- The base stream/running time corresponds to the DTS of the first
- buffer we will output. The DTS_delta becomes that earliest DTS.
-
- => FILLME
-
- X) General notes
-
- It is assumed that PTS/DTS rollovers are detected and corrected such
- as the outgoing timestamps never rollover. This can be easily
- handled by correcting the DTS_delta when such rollovers are
- detected. The maximum value of a GstClockTimeDiff is almost 3
- centuries, we therefore have enough margin to handle a decent number
- of rollovers.
-
- The generic equation for calculating outgoing buffer timestamps
- therefore becomes:
-
- D = DTS_delta, with rollover corrections
- PTS = PTS of the buffer we are going to push out
- TS = Timestamp of the outgoing buffer
-
- ==> TS = PTS + D
+ => The outgoing values for the newsegment are calculated like for
+ the non-live push-based mode when upstream doesn't provide
+ timestamp'ed buffers.
- If seeking is handled upstream for push-based cases, whether live or
- not, no extra modification is required.
+ => The outgoing buffer timestamps are timestamped with their PTS
+ values (overflow corrected) adjusted by the packetizer.
- If seeking is handled by the demuxer in the non-live push-based
- cases (converting from TIME to BYTES), the demuxer will need to
- set the segment start/time values to the requested seek position.
- The DTS_delta will also have to be recomputed to take into account
- the seek position.
[0] When talking about live sources, we mean this in the GStreamer
diff --git a/gst/mpegtsdemux/gstmpegdefs.h b/gst/mpegtsdemux/gstmpegdefs.h
index 66f922b71..62d98c75b 100644
--- a/gst/mpegtsdemux/gstmpegdefs.h
+++ b/gst/mpegtsdemux/gstmpegdefs.h
@@ -206,6 +206,8 @@
GST_MSECOND/10, CLOCK_BASE))
#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \
CLOCK_BASE, GST_MSECOND/10))
+#define GSTTIME_TO_PCRTIME(time) (gst_util_uint64_scale ((time), \
+ 300 * CLOCK_BASE, GST_MSECOND/10))
#define MPEG_MUX_RATE_MULT 50
diff --git a/gst/mpegtsdemux/gstmpegdesc.h b/gst/mpegtsdemux/gstmpegdesc.h
index 06aa17b95..c4ae91c0a 100644
--- a/gst/mpegtsdemux/gstmpegdesc.h
+++ b/gst/mpegtsdemux/gstmpegdesc.h
@@ -29,6 +29,7 @@
#define __GST_MPEG_DESC_H__
#include <glib.h>
+
/*
* descriptor_tag TS PS Identification
* 0 n/a n/a Reserved
@@ -53,93 +54,94 @@
* 19-63 n/a n/a ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved
* 64-255 n/a n/a User Private
*/
-#define DESC_VIDEO_STREAM 2
-#define DESC_AUDIO_STREAM 3
-#define DESC_HIERARCHY 4
-#define DESC_REGISTRATION 5
-#define DESC_DATA_STREAM_ALIGNMENT 6
-#define DESC_TARGET_BACKGROUND_GRID 7
-#define DESC_VIDEO_WINDOW 8
-#define DESC_CA 9
-#define DESC_ISO_639_LANGUAGE 10
-#define DESC_SYSTEM_CLOCK 11
-#define DESC_MULTIPLEX_BUFFER_UTILISATION 12
-#define DESC_COPYRIGHT 13
-#define DESC_MAXIMUM_BITRATE 14
-#define DESC_PRIVATE_DATA_INDICATOR 15
-#define DESC_SMOOTHING_BUFFER 16
-#define DESC_STD 17
-#define DESC_IBP 18
-
-#define DESC_DIRAC_TC_PRIVATE 0xAC
+#define DESC_VIDEO_STREAM 0x02
+#define DESC_AUDIO_STREAM 0x03
+#define DESC_HIERARCHY 0x04
+#define DESC_REGISTRATION 0x05
+#define DESC_DATA_STREAM_ALIGNMENT 0x06
+#define DESC_TARGET_BACKGROUND_GRID 0x07
+#define DESC_VIDEO_WINDOW 0x08
+#define DESC_CA 0x09
+#define DESC_ISO_639_LANGUAGE 0x0A
+#define DESC_SYSTEM_CLOCK 0x0B
+#define DESC_MULTIPLEX_BUFFER_UTILISATION 0x0C
+#define DESC_COPYRIGHT 0x0D
+#define DESC_MAXIMUM_BITRATE 0x0E
+#define DESC_PRIVATE_DATA_INDICATOR 0x0F
+#define DESC_SMOOTHING_BUFFER 0x10
+#define DESC_STD 0x11
+#define DESC_IBP 0x12
+
+#define DESC_DIRAC_TC_PRIVATE 0xAC
/* DVB tags */
-#define DESC_DVB_CAROUSEL_IDENTIFIER 0x13
-#define DESC_DVB_NETWORK_NAME 0x40
-#define DESC_DVB_SERVICE_LIST 0x41
-#define DESC_DVB_STUFFING 0x42
+#define DESC_DVB_CAROUSEL_IDENTIFIER 0x13
+#define DESC_DVB_NETWORK_NAME 0x40
+#define DESC_DVB_SERVICE_LIST 0x41
+#define DESC_DVB_STUFFING 0x42
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM 0x43
-#define DESC_DVB_CABLE_DELIVERY_SYSTEM 0x44
-#define DESC_DVB_VBI_DATA 0x45
-#define DESC_DVB_VBI_TELETEXT 0x46
-#define DESC_DVB_BOUQUET_NAME 0x47
-#define DESC_DVB_SERVICE 0x48
-#define DESC_DVB_COUNTRY_AVAILABILITY 0x49
-#define DESC_DVB_LINKAGE 0x4A
-#define DESC_DVB_NVOD_REFERENCE 0x4B
-#define DESC_DVB_TIME_SHIFTED_SERVICE 0x4C
-#define DESC_DVB_SHORT_EVENT 0x4D
-#define DESC_DVB_EXTENDED_EVENT 0x4E
-#define DESC_DVB_TIME_SHIFTED_EVENT 0x4F
-#define DESC_DVB_COMPONENT 0x50
-#define DESC_DVB_MOSAIC 0x51
-#define DESC_DVB_STREAM_IDENTIFIER 0x52
-#define DESC_DVB_CA_IDENTIFIER 0x53
-#define DESC_DVB_CONTENT 0x54
-#define DESC_DVB_PARENTAL_RATING 0x55
-#define DESC_DVB_TELETEXT 0x56
-#define DESC_DVB_TELEPHONE 0x57
-#define DESC_DVB_LOCAL_TIME_OFFSET 0x58
-#define DESC_DVB_SUBTITLING 0x59
+#define DESC_DVB_CABLE_DELIVERY_SYSTEM 0x44
+#define DESC_DVB_VBI_DATA 0x45
+#define DESC_DVB_VBI_TELETEXT 0x46
+#define DESC_DVB_BOUQUET_NAME 0x47
+#define DESC_DVB_SERVICE 0x48
+#define DESC_DVB_COUNTRY_AVAILABILITY 0x49
+#define DESC_DVB_LINKAGE 0x4A
+#define DESC_DVB_NVOD_REFERENCE 0x4B
+#define DESC_DVB_TIME_SHIFTED_SERVICE 0x4C
+#define DESC_DVB_SHORT_EVENT 0x4D
+#define DESC_DVB_EXTENDED_EVENT 0x4E
+#define DESC_DVB_TIME_SHIFTED_EVENT 0x4F
+#define DESC_DVB_COMPONENT 0x50
+#define DESC_DVB_MOSAIC 0x51
+#define DESC_DVB_STREAM_IDENTIFIER 0x52
+#define DESC_DVB_CA_IDENTIFIER 0x53
+#define DESC_DVB_CONTENT 0x54
+#define DESC_DVB_PARENTAL_RATING 0x55
+#define DESC_DVB_TELETEXT 0x56
+#define DESC_DVB_TELEPHONE 0x57
+#define DESC_DVB_LOCAL_TIME_OFFSET 0x58
+#define DESC_DVB_SUBTITLING 0x59
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM 0x5A
#define DESC_DVB_MULTILINGUAL_NETWORK_NAME 0x5B
#define DESC_DVB_MULTILINGUAL_BOUQUET_NAME 0x5C
#define DESC_DVB_MULTILINGUAL_SERVICE_NAME 0x5D
-#define DESC_DVB_MULTILINGUAL_COMPONENT 0x5E
-#define DESC_DVB_PRIVATE_DATA 0x5F
-#define DESC_DVB_SERVICE_MOVE 0x60
-#define DESC_DVB_SHORT_SMOOTHING_BUFFER 0x61
-#define DESC_DVB_FREQUENCY_LIST 0x62
-#define DESC_DVB_PARTIAL_TRANSPORT_STREAM 0x63
-#define DESC_DVB_DATA_BROADCAST 0x64
-#define DESC_DVB_SCRAMBLING 0x65
-#define DESC_DVB_DATA_BROADCAST_ID 0x66
-#define DESC_DVB_TRANSPORT_STREAM 0x67
-#define DESC_DVB_DSNG 0x68
-#define DESC_DVB_PDC 0x69
-#define DESC_DVB_AC3 0x6A
-#define DESC_DVB_ANCILLARY_DATA 0x6B
-#define DESC_DVB_CELL_LIST 0x6C
-#define DESC_DVB_CELL_FREQUENCY_LINK 0x6D
-#define DESC_DVB_ANNOUNCEMENT_SUPPORT 0x6E
-#define DESC_DVB_APPLICATION_SIGNALLING 0x6F
-#define DESC_DVB_ADAPTATION_FIELD_DATA 0x70
-#define DESC_DVB_SERVICE_IDENTIFIER 0x71
-#define DESC_DVB_SERVICE_AVAILABILITY 0x72
-#define DESC_DVB_DEFAULT_AUTHORITY 0x73
-#define DESC_DVB_RELATED_CONTENT 0x74
-#define DESC_DVB_TVA_ID 0x75
-#define DESC_DVB_CONTENT_IDENTIFIER 0x76
-#define DESC_DVB_TIMESLICE_FEC_IDENTIFIER 0x77
-#define DESC_DVB_ECM_REPETITION_RATE 0x78
-#define DESC_DVB_S2_SATELLITE_DELIVERY_SYSTEM 0x79
-#define DESC_DVB_ENHANCED_AC3 0x7A
-#define DESC_DVB_DTS 0x7B
-#define DESC_DVB_AAC 0x7C
+#define DESC_DVB_MULTILINGUAL_COMPONENT 0x5E
+#define DESC_DVB_PRIVATE_DATA 0x5F
+#define DESC_DVB_SERVICE_MOVE 0x60
+#define DESC_DVB_SHORT_SMOOTHING_BUFFER 0x61
+#define DESC_DVB_FREQUENCY_LIST 0x62
+#define DESC_DVB_PARTIAL_TRANSPORT_STREAM 0x63
+#define DESC_DVB_DATA_BROADCAST 0x64
+#define DESC_DVB_SCRAMBLING 0x65
+#define DESC_DVB_DATA_BROADCAST_ID 0x66
+#define DESC_DVB_TRANSPORT_STREAM 0x67
+#define DESC_DVB_DSNG 0x68
+#define DESC_DVB_PDC 0x69
+#define DESC_DVB_AC3 0x6A
+#define DESC_DVB_ANCILLARY_DATA 0x6B
+#define DESC_DVB_CELL_LIST 0x6C
+#define DESC_DVB_CELL_FREQUENCY_LINK 0x6D
+#define DESC_DVB_ANNOUNCEMENT_SUPPORT 0x6E
+#define DESC_DVB_APPLICATION_SIGNALLING 0x6F
+#define DESC_DVB_ADAPTATION_FIELD_DATA 0x70
+#define DESC_DVB_SERVICE_IDENTIFIER 0x71
+#define DESC_DVB_SERVICE_AVAILABILITY 0x72
+#define DESC_DVB_DEFAULT_AUTHORITY 0x73
+#define DESC_DVB_RELATED_CONTENT 0x74
+#define DESC_DVB_TVA_ID 0x75
+#define DESC_DVB_CONTENT_IDENTIFIER 0x76
+#define DESC_DVB_TIMESLICE_FEC_IDENTIFIER 0x77
+#define DESC_DVB_ECM_REPETITION_RATE 0x78
+#define DESC_DVB_S2_SATELLITE_DELIVERY_SYSTEM 0x79
+#define DESC_DVB_ENHANCED_AC3 0x7A
+#define DESC_DVB_DTS 0x7B
+#define DESC_DVB_AAC 0x7C
/* 0x7D and 0x7E are reserved for future use */
-#define DESC_DVB_EXTENSION 0x7F
+#define DESC_DVB_EXTENSION 0x7F
/* 0x80 - 0xFE are user defined */
-#define DESC_DTG_LOGICAL_CHANNEL 0x83 /* from DTG D-Book */
+#define DESC_AC3_AUDIO_STREAM 0x81
+#define DESC_DTG_LOGICAL_CHANNEL 0x83 /* from DTG D-Book */
/* 0xFF is forbidden */
/* common for all descriptors */
@@ -196,7 +198,7 @@
#define DESC_ISO_639_LANGUAGE_language_code_nth(desc,i) (&(desc[2 + (4*i)]))
#define DESC_ISO_639_LANGUAGE_audio_type_nth(desc,i) ((desc)[5 + (4*i)])
-/* system_clock_descriptor */
+/* system_clock_descriptor */
#define DESC_SYSTEM_CLOCK_external_clock_reference_indicator(desc) (((desc)[2] & 0x80) == 0x80)
#define DESC_SYSTEM_CLOCK_clock_accuracy_integer(desc) ((desc)[2] & 0x3f)
#define DESC_SYSTEM_CLOCK_clock_accuracy_exponent(desc) (((desc)[3] & 0xe0) >> 5)
@@ -213,7 +215,7 @@
/* maximum_bitrate_descriptor */
#define DESC_MAXIMUM_BITRAT_maximum_bitrate(desc) (((((guint32)desc[2]) & 0x3f) << 16) | \
- GST_READ_UINT16_BE ((desc)+3))
+ GST_READ_UINT16_BE ((desc)+3))
/* private_data_indicator_descriptor */
#define DESC_PRIVATE_DATA_INDICATOR_indicator(desc) (GST_READ_UINT32_BE(&desc[2]))
@@ -268,7 +270,7 @@
#define DESC_DVB_EXTENDED_EVENT_last_descriptor_number(desc) (desc[2] & 0x0F)
#define DESC_DVB_EXTENDED_EVENT_iso639_language_code(desc) (desc + 3)
#define DESC_DVB_EXTENDED_EVENT_items_length(desc) (desc[6])
-#define DESC_DVB_EXTENDED_EVENT_items(desc) (desc + 7)
+#define DESC_DVB_EXTENDED_EVENT_items(desc) (desc + 7)
#define DESC_DVB_EXTENDED_EVENT_text_length(desc) (desc[7 + DESC_DVB_EXTENDED_EVENT_items_length(desc)])
#define DESC_DVB_EXTENDED_EVENT_text(desc) (desc + 7 + DESC_DVB_EXTENDED_EVENT_items_length(desc) + 1)
@@ -315,24 +317,31 @@
/* DVB Carousel Identifier Descriptor */
#define DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id(desc) (GST_READ_UINT32_BE((desc) + 2))
+/* AC3_audio_stream_descriptor */
+#define DESC_AC_AUDIO_STREAM_bsid(desc) ((desc)[2] & 0x1f)
+
/* registration_descriptor format IDs */
#define DRF_ID_HDMV 0x48444d56
#define DRF_ID_VC1 0x56432D31 /* defined in RP227 */
-
-typedef struct {
- guint n_desc;
- guint8 data_length;
- guint8 *data;
+#define DRF_ID_DTS1 0x44545331
+#define DRF_ID_DTS2 0x44545332
+#define DRF_ID_DTS3 0x44545333
+
+typedef struct
+{
+ guint n_desc;
+ guint8 data_length;
+ guint8 *data;
} GstMPEGDescriptor;
void gst_mpegtsdesc_init_debug (void);
-GstMPEGDescriptor* gst_mpeg_descriptor_parse (guint8 *data, guint size);
-void gst_mpeg_descriptor_free (GstMPEGDescriptor *desc);
+GstMPEGDescriptor *gst_mpeg_descriptor_parse (guint8 * data, guint size);
+void gst_mpeg_descriptor_free (GstMPEGDescriptor * desc);
-guint gst_mpeg_descriptor_n_desc (GstMPEGDescriptor *desc);
-guint8* gst_mpeg_descriptor_find (GstMPEGDescriptor *desc, gint tag);
-GArray* gst_mpeg_descriptor_find_all (GstMPEGDescriptor * desc, gint tag);
+guint gst_mpeg_descriptor_n_desc (GstMPEGDescriptor * desc);
+guint8 *gst_mpeg_descriptor_find (GstMPEGDescriptor * desc, gint tag);
+GArray *gst_mpeg_descriptor_find_all (GstMPEGDescriptor * desc, gint tag);
-guint8* gst_mpeg_descriptor_nth (GstMPEGDescriptor *desc, guint i);
+guint8 *gst_mpeg_descriptor_nth (GstMPEGDescriptor * desc, guint i);
#endif /* __GST_MPEG_DESC_H__ */
diff --git a/gst/mpegtsdemux/mpegtsbase.c b/gst/mpegtsdemux/mpegtsbase.c
index 2e4fcedb5..863c5ec19 100644
--- a/gst/mpegtsdemux/mpegtsbase.c
+++ b/gst/mpegtsdemux/mpegtsbase.c
@@ -217,9 +217,10 @@ mpegts_base_reset (MpegTSBase * base)
base->mode = BASE_MODE_STREAMING;
base->seen_pat = FALSE;
- base->first_pat_offset = -1;
- base->in_gap = 0;
- base->first_buf_ts = GST_CLOCK_TIME_NONE;
+ base->seek_offset = -1;
+
+ base->upstream_live = FALSE;
+ base->queried_latency = FALSE;
base->upstream_live = FALSE;
base->query_latency = FALSE;
@@ -574,6 +575,74 @@ mpegts_base_program_remove_stream (MpegTSBase * base,
program->streams[pid] = NULL;
}
+/* Return TRUE if programs are equal */
+static gboolean
+mpegts_base_is_same_program (MpegTSBase * base, MpegTSBaseProgram * oldprogram,
+ guint16 new_pmt_pid, GstStructure * new_pmt_info)
+{
+ guint i, nbstreams;
+ guint pcr_pid;
+ guint pid;
+ guint stream_type;
+ GstStructure *stream;
+ MpegTSBaseStream *oldstream;
+ gboolean sawpcrpid = FALSE;
+ const GValue *new_streams;
+ const GValue *value;
+
+ if (oldprogram->pmt_pid != new_pmt_pid) {
+ GST_DEBUG ("Different pmt_pid (new:0x%04x, old:0x%04x)", new_pmt_pid,
+ oldprogram->pmt_pid);
+ return FALSE;
+ }
+
+ gst_structure_id_get (new_pmt_info, QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid,
+ NULL);
+ if (oldprogram->pcr_pid != pcr_pid) {
+ GST_DEBUG ("Different pcr_pid (new:0x%04x, old:0x%04x)",
+ pcr_pid, oldprogram->pcr_pid);
+ return FALSE;
+ }
+
+ /* Check the streams */
+ new_streams = gst_structure_id_get_value (new_pmt_info, QUARK_STREAMS);
+ nbstreams = gst_value_list_get_size (new_streams);
+
+ for (i = 0; i < nbstreams; ++i) {
+ value = gst_value_list_get_value (new_streams, i);
+ stream = g_value_get_boxed (value);
+
+ gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
+ QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
+ oldstream = oldprogram->streams[pid];
+ if (!oldstream) {
+ GST_DEBUG ("New stream 0x%04x not present in old program", pid);
+ return FALSE;
+ }
+ if (oldstream->stream_type != stream_type) {
+ GST_DEBUG
+ ("New stream 0x%04x has a different stream type (new:%d, old:%d)",
+ pid, stream_type, oldstream->stream_type);
+ return FALSE;
+ }
+ if (pid == oldprogram->pcr_pid)
+ sawpcrpid = TRUE;
+ }
+
+ /* If the pcr is not shared with an existing stream, we'll have one extra stream */
+ if (!sawpcrpid)
+ nbstreams += 1;
+
+ if (nbstreams != g_list_length (oldprogram->stream_list)) {
+ GST_DEBUG ("Different number of streams (new:%d, old:%d)",
+ nbstreams, g_list_length (oldprogram->stream_list));
+ return FALSE;
+ }
+
+ GST_DEBUG ("Programs are equal");
+ return TRUE;
+}
+
static void
mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program)
{
@@ -624,7 +693,7 @@ mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program)
static void
mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program,
- guint16 pmt_pid, GstStructure * pmt_info)
+ guint16 pmt_pid, GstStructure * pmt_info, gboolean initial_program)
{
guint i, nbstreams;
guint pcr_pid;
@@ -669,8 +738,8 @@ mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program,
mpegts_base_program_add_stream (base, program, (guint16) pcr_pid, -1, NULL);
MPEGTS_BIT_SET (base->is_pes, pcr_pid);
-
program->active = TRUE;
+ program->initial_program = initial_program;
klass = GST_MPEGTS_BASE_GET_CLASS (base);
if (klass->program_started != NULL)
@@ -683,7 +752,7 @@ gboolean
mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet)
{
gboolean retval = FALSE;
- guint8 table_id;
+ guint8 *data, table_id, pointer;
int i;
static const guint8 si_tables[] =
{ 0x00, 0x01, 0x02, 0x03, 0x40, 0x41, 0x42, 0x46, 0x4A,
@@ -702,6 +771,18 @@ mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet)
if (!retval) {
if (packet->payload_unit_start_indicator) {
+ data = packet->data;
+ pointer = *data++;
+ data += pointer;
+ /* 'pointer' value may be invalid on malformed packet
+ * so we need to avoid out of range
+ */
+ if (!(data < packet->data_end)) {
+ GST_WARNING_OBJECT (base,
+ "Wrong offset when retrieving table id: 0x%x", pointer);
+ return FALSE;
+ }
+
table_id = *(packet->data);
i = 0;
while (si_tables[i] != TABLE_ID_UNSET) {
@@ -846,6 +927,7 @@ mpegts_base_apply_pmt (MpegTSBase * base,
{
MpegTSBaseProgram *program, *old_program;
guint program_number;
+ gboolean initial_program = TRUE;
/* FIXME : not so sure this is valid anymore */
if (G_UNLIKELY (base->seen_pat == FALSE)) {
@@ -870,6 +952,10 @@ mpegts_base_apply_pmt (MpegTSBase * base,
if (G_UNLIKELY (old_program == NULL))
goto no_program;
+ if (G_UNLIKELY (mpegts_base_is_same_program (base, old_program, pmt_pid,
+ pmt_info)))
+ goto same_program;
+
/* If the current program is active, this means we have a new program */
if (old_program->active) {
old_program = mpegts_base_steal_program (base, program_number);
@@ -880,11 +966,13 @@ mpegts_base_apply_pmt (MpegTSBase * base,
/* Desactivate the old program */
mpegts_base_deactivate_program (base, old_program);
mpegts_base_free_program (old_program);
+ initial_program = FALSE;
} else
program = old_program;
/* First activate program */
- mpegts_base_activate_program (base, program, pmt_pid, pmt_info);
+ mpegts_base_activate_program (base, program, pmt_pid, pmt_info,
+ initial_program);
/* if (program->pmt_info) */
/* gst_structure_free (program->pmt_info); */
@@ -901,6 +989,12 @@ no_program:
GST_ERROR ("Attempted to apply a PMT on a program that wasn't created");
return;
}
+
+same_program:
+ {
+ GST_DEBUG ("Not applying identical program");
+ return;
+ }
}
static void
@@ -959,8 +1053,6 @@ mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
{
gboolean res = TRUE;
GstStructure *structure = NULL;
- gint program_number;
- MpegTSBaseProgram *program = NULL;
/* table ids 0x70 - 0x73 do not have a crc */
if (G_LIKELY (section->table_id < 0x70 || section->table_id > 0x73)) {
@@ -983,9 +1075,10 @@ mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
mpegts_base_apply_pat (base, structure);
if (base->seen_pat == FALSE) {
base->seen_pat = TRUE;
- base->first_pat_offset = GST_BUFFER_OFFSET (section->buffer);
GST_DEBUG ("First PAT offset: %" G_GUINT64_FORMAT,
- base->first_pat_offset);
+ GST_BUFFER_OFFSET (section->buffer));
+ mpegts_packetizer_set_reference_offset (base->packetizer,
+ GST_BUFFER_OFFSET (section->buffer));
}
} else
@@ -994,22 +1087,10 @@ mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
break;
case 0x02:
structure = mpegts_packetizer_parse_pmt (base->packetizer, section);
- if (G_UNLIKELY (structure == NULL))
- return FALSE;
-
- gst_structure_id_get (structure, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
- &program_number, NULL);
- program = mpegts_base_get_program (base, program_number);
-
- /* We already have the same PMT for the current program in use, so we do
- * not need to reset it */
- if (program && program->active && program->pmt_pid == section->pid) {
- GST_DEBUG ("Already have the PMT %u for program %i, not applying again",
- program->pmt_pid, program_number);
- res = TRUE;
- } else {
+ if (G_LIKELY (structure))
mpegts_base_apply_pmt (base, section->pid, structure);
- }
+ else
+ res = FALSE;
break;
case 0x40:
@@ -1213,14 +1294,9 @@ mpegts_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEGMENT:
- {
gst_event_copy_segment (event, &base->segment);
gst_event_unref (event);
-
- base->in_gap = GST_CLOCK_TIME_NONE;
- base->first_buf_ts = GST_CLOCK_TIME_NONE;
- }
break;
case GST_EVENT_EOS:
res = gst_mpegts_base_handle_eos (base);
@@ -1239,7 +1315,6 @@ mpegts_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
case GST_EVENT_FLUSH_STOP:
gst_segment_init (&base->segment, GST_FORMAT_UNDEFINED);
base->seen_pat = FALSE;
- base->first_pat_offset = -1;
/* Passthrough */
default:
res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
@@ -1263,7 +1338,7 @@ query_upstream_latency (MpegTSBase * base)
} else
GST_WARNING_OBJECT (base, "Failed to query upstream latency");
gst_query_unref (query);
- base->query_latency = TRUE;
+ base->queried_latency = TRUE;
}
static inline GstFlowReturn
@@ -1294,17 +1369,10 @@ mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
base = GST_MPEGTS_BASE (parent);
packetizer = base->packetizer;
- if (G_UNLIKELY (base->query_latency == FALSE)) {
+ if (G_UNLIKELY (base->queried_latency == FALSE)) {
query_upstream_latency (base);
}
- if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (base->first_buf_ts)) &&
- GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
- base->first_buf_ts = GST_BUFFER_TIMESTAMP (buf);
- GST_DEBUG_OBJECT (base, "first buffer timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (base->first_buf_ts));
- }
-
mpegts_packetizer_push (base->packetizer, buf);
while (res == GST_FLOW_OK) {
@@ -1364,18 +1432,20 @@ mpegts_base_scan (MpegTSBase * base)
GstFlowReturn ret;
GstBuffer *buf;
guint i;
- MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
+ gboolean done = FALSE;
+ MpegTSPacketizerPacketReturn pret;
+ gint64 tmpval;
+ guint64 upstream_size, seek_pos;
+ GstFormat format;
+ guint initial_pcr_seen;
GST_DEBUG ("Scanning for initial sync point");
- /* Find initial sync point */
- for (i = 0; i < 10; i++) {
- GST_DEBUG ("Grabbing %d => %d", i * 50 * MPEGTS_MAX_PACKETSIZE,
- 50 * MPEGTS_MAX_PACKETSIZE);
+ /* Find initial sync point and at least 5 PCR values */
+ for (i = 0; i < 10 && !done; i++) {
+ GST_DEBUG ("Grabbing %d => %d", i * 65536, 65536);
- buf = NULL;
- ret = gst_pad_pull_range (base->sinkpad, i * 50 * MPEGTS_MAX_PACKETSIZE,
- 50 * MPEGTS_MAX_PACKETSIZE, &buf);
+ ret = gst_pad_pull_range (base->sinkpad, i * 65536, 65536, &buf);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto beach;
@@ -1383,34 +1453,81 @@ mpegts_base_scan (MpegTSBase * base)
mpegts_packetizer_push (base->packetizer, buf);
if (mpegts_packetizer_has_packets (base->packetizer)) {
- /* Mark the initial sync point and remember the packetsize */
- base->initial_sync_point = base->seek_offset = base->packetizer->offset;
- GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset);
- base->packetsize = base->packetizer->packet_size;
+ if (base->seek_offset == -1) {
+ /* Mark the initial sync point and remember the packetsize */
+ base->seek_offset = base->packetizer->offset;
+ GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset);
+ base->packetsize = base->packetizer->packet_size;
+ }
+ while (1) {
+ /* Eat up all packets */
+ pret = mpegts_packetizer_process_next_packet (base->packetizer);
+ if (pret == PACKET_NEED_MORE)
+ break;
+ if (pret != PACKET_BAD &&
+ mpegts_packetizer_get_seen_pcr (base->packetizer) >= 5) {
+ GST_DEBUG ("Got enough initial PCR");
+ done = TRUE;
+ break;
+ }
+ }
+ }
+ }
- /* If the subclass can seek for timestamps, do that */
- if (klass->find_timestamps) {
- guint64 offset;
- mpegts_packetizer_clear (base->packetizer);
+ initial_pcr_seen = mpegts_packetizer_get_seen_pcr (base->packetizer);
+ if (G_UNLIKELY (initial_pcr_seen == 0))
+ goto no_initial_pcr;
+ GST_DEBUG ("Seen %d initial PCR", initial_pcr_seen);
- ret = klass->find_timestamps (base, 0, &offset);
+ /* Now send data from the end */
+ mpegts_packetizer_clear (base->packetizer);
- base->initial_sync_point = base->seek_offset =
- base->packetizer->offset = base->first_pat_offset;
- GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset);
- }
+ /* Get the size of upstream */
+ format = GST_FORMAT_BYTES;
+ if (!gst_pad_query_peer_duration (base->sinkpad, &format, &tmpval))
+ goto beach;
+ upstream_size = tmpval;
+ done = FALSE;
+
+ /* Find last PCR value */
+ for (seek_pos = MAX (0, upstream_size - 655360);
+ seek_pos < upstream_size && !done; seek_pos += 65536) {
+ GST_DEBUG ("Grabbing %" G_GUINT64_FORMAT " => %d", seek_pos, 65536);
+
+ ret = gst_pad_pull_range (base->sinkpad, seek_pos, 65536, &buf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
goto beach;
+
+ /* Push to packetizer */
+ mpegts_packetizer_push (base->packetizer, buf);
+
+ if (mpegts_packetizer_has_packets (base->packetizer)) {
+ while (1) {
+ /* Eat up all packets */
+ pret = mpegts_packetizer_process_next_packet (base->packetizer);
+ if (pret == PACKET_NEED_MORE)
+ break;
+ if (pret != PACKET_BAD &&
+ mpegts_packetizer_get_seen_pcr (base->packetizer) >
+ initial_pcr_seen) {
+ GST_DEBUG ("Got last PCR");
+ done = TRUE;
+ break;
+ }
+ }
}
}
- GST_WARNING ("Didn't find initial sync point");
- ret = GST_FLOW_ERROR;
-
beach:
GST_DEBUG ("Returning %s", gst_flow_get_name (ret));
mpegts_packetizer_clear (base->packetizer);
return ret;
+no_initial_pcr:
+ mpegts_packetizer_clear (base->packetizer);
+ GST_WARNING_OBJECT (base, "Couldn't find any PCR within the first %d bytes",
+ 10 * 65536);
+ return GST_FLOW_ERROR;
}
@@ -1429,7 +1546,7 @@ mpegts_base_loop (MpegTSBase * base)
GST_DEBUG ("Changing to Streaming");
break;
case BASE_MODE_SEEKING:
- /* FIXME : yes, we should do something here */
+ /* FIXME : unclear if we still need mode_seeking... */
base->mode = BASE_MODE_STREAMING;
break;
case BASE_MODE_STREAMING:
@@ -1460,9 +1577,16 @@ error:
const gchar *reason = gst_flow_get_name (ret);
GST_DEBUG_OBJECT (base, "Pausing task, reason %s", reason);
- if (ret == GST_FLOW_EOS)
- GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ());
- else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+ if (ret == GST_FLOW_EOS) {
+ /* Push EOS downstream */
+ if (!GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
+ gst_event_new_eos ())) {
+ /* If that failed, emit an error so the pipeline can be stopped */
+ GST_ELEMENT_ERROR (base, STREAM, DEMUX, (NULL),
+ ("got eos but no streams (yet)"));
+
+ }
+ } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
GST_ELEMENT_ERROR (base, STREAM, FAILED,
(_("Internal data stream error.")),
("stream stopped, reason %s", reason));
@@ -1485,8 +1609,6 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
GstSeekFlags flags;
GstSeekType start_type, stop_type;
gint64 start, stop;
- gchar *pad_name;
- guint16 pid = 0;
gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
&stop_type, &stop);
@@ -1505,20 +1627,11 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
" stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
GST_TIME_ARGS (stop));
- /* extract the pid from the pad name */
- pad_name = gst_pad_get_name (pad);
- if (pad_name) {
- gchar *pidstr = g_strrstr (pad_name, "_");
- if (pidstr) {
- pidstr++;
- pid = g_ascii_strtoull (pidstr, NULL, 16);
- }
- g_free (pad_name);
- }
-
flush = flags & GST_SEEK_FLAG_FLUSH;
if (base->mode == BASE_MODE_PUSHING) {
+ /* FIXME : Actually ... it is supported, we just need to convert
+ * the seek event to BYTES */
GST_ERROR ("seeking in push mode not supported");
goto push_mode;
}
@@ -1532,6 +1645,7 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
gst_event_new_flush_start ());
} else
gst_pad_pause_task (base->sinkpad);
+
/* wait for streaming to finish */
GST_PAD_STREAM_LOCK (base->sinkpad);
@@ -1539,6 +1653,9 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
/* send a FLUSH_STOP for the sinkpad, since we need data for seeking */
GST_DEBUG_OBJECT (base, "sending flush stop");
gst_pad_push_event (base->sinkpad, gst_event_new_flush_stop (TRUE));
+ /* And actually flush our pending data */
+ mpegts_base_flush (base);
+ mpegts_packetizer_flush (base->packetizer);
}
if (flags & (GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_SKIP)) {
@@ -1550,14 +1667,12 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
if (format == GST_FORMAT_TIME) {
/* If the subclass can seek, do that */
if (klass->seek) {
- ret = klass->seek (base, event, pid);
+ ret = klass->seek (base, event);
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
- goto done;
}
} else {
GST_WARNING ("subclass has no seek implementation");
- goto done;
}
}
@@ -1616,11 +1731,13 @@ mpegts_base_sink_activate_mode (GstPad * pad, GstObject * parent,
switch (mode) {
case GST_PAD_MODE_PUSH:
base->mode = BASE_MODE_PUSHING;
+ base->packetizer->calculate_skew = TRUE;
res = TRUE;
break;
case GST_PAD_MODE_PULL:
if (active) {
base->mode = BASE_MODE_SCANNING;
+ base->packetizer->calculate_offset = TRUE;
res =
gst_pad_start_task (pad, (GstTaskFunction) mpegts_base_loop, base);
} else
diff --git a/gst/mpegtsdemux/mpegtsbase.h b/gst/mpegtsdemux/mpegtsbase.h
index 499ea6a31..8521b5786 100644
--- a/gst/mpegtsdemux/mpegtsbase.h
+++ b/gst/mpegtsdemux/mpegtsbase.h
@@ -48,6 +48,8 @@ G_BEGIN_DECLS
#define GST_MPEGTS_BASE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MPEGTS_BASE, MpegTSBaseClass))
+#define MPEG_TS_BASE_PACKETIZER(b) (((MpegTSBase*)b)->packetizer)
+
typedef struct _MpegTSBase MpegTSBase;
typedef struct _MpegTSBaseClass MpegTSBaseClass;
typedef struct _MpegTSBaseStream MpegTSBaseStream;
@@ -76,6 +78,8 @@ struct _MpegTSBaseProgram
/* TRUE if the program is currently being used */
gboolean active;
+ /* TRUE if this is the first program created */
+ gboolean initial_program;
};
typedef enum {
@@ -96,9 +100,6 @@ struct _MpegTSBase {
/* pull-based behaviour */
MpegTSBaseMode mode;
- /* location of first sync point */
- guint64 initial_sync_point;
-
/* Current pull offset (also set by seek handler) */
guint64 seek_offset;
@@ -130,12 +131,10 @@ struct _MpegTSBase {
/* Whether we saw a PAT yet */
gboolean seen_pat;
- /* Offset from the origin to the first PAT (pullmode) */
- guint64 first_pat_offset;
-
- /* interpolation gap between the upstream timestamp and the pts */
- GstClockTime in_gap;
- GstClockTime first_buf_ts;
+ /* Whether upstream is live or not */
+ gboolean upstream_live;
+ /* Whether we queried the upstream latency or not */
+ gboolean queried_latency;
/* Whether upstream is live or not */
gboolean upstream_live;
@@ -168,7 +167,7 @@ struct _MpegTSBaseClass {
GstFlowReturn (*find_timestamps) (MpegTSBase * base, guint64 initoff, guint64 *offset);
/* seek is called to wait for seeking */
- GstFlowReturn (*seek) (MpegTSBase * base, GstEvent * event, guint16 pid);
+ GstFlowReturn (*seek) (MpegTSBase * base, GstEvent * event);
/* flush all streams */
void (*flush) (MpegTSBase * base);
diff --git a/gst/mpegtsdemux/mpegtspacketizer.c b/gst/mpegtsdemux/mpegtspacketizer.c
index f79bdfe4e..bf6e4afaf 100644
--- a/gst/mpegtsdemux/mpegtspacketizer.c
+++ b/gst/mpegtsdemux/mpegtspacketizer.c
@@ -28,6 +28,12 @@
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
+/* Skew calculation pameters */
+#define MAX_TIME (2 * GST_SECOND)
+
+/* maximal PCR time */
+#define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298)
+#define PTS_DTS_MAX_VALUE (((guint64)1) << 33)
#include "mpegtspacketizer.h"
#include "gstmpegdesc.h"
@@ -67,10 +73,37 @@ static GQuark QUARK_SEGMENT_LAST_SECTION_NUMBER;
static GQuark QUARK_LAST_TABLE_ID;
static GQuark QUARK_EVENTS;
+
+#define MPEGTS_PACKETIZER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_MPEGTS_PACKETIZER, MpegTSPacketizerPrivate))
+
static void _init_local (void);
G_DEFINE_TYPE_EXTENDED (MpegTSPacketizer2, mpegts_packetizer, G_TYPE_OBJECT, 0,
_init_local ());
+typedef struct
+{
+ guint64 offset; /* offset in upstream */
+ guint64 pcr; /* pcr (wraparound not fixed) */
+} MpegTSPacketizerOffset;
+
+struct _MpegTSPacketizerPrivate
+{
+ /* Used for bitrate calculation */
+ /* FIXME : Replace this later on with a balanced tree or sequence */
+ guint64 first_offset;
+ guint64 first_pcr;
+ GstClockTime first_pcr_ts;
+ guint64 last_offset;
+ guint64 last_pcr;
+ GstClockTime last_pcr_ts;
+
+ /* Reference offset */
+ guint64 refoffset;
+
+ guint nb_seen_offsets;
+};
+
static void mpegts_packetizer_dispose (GObject * object);
static void mpegts_packetizer_finalize (GObject * object);
static gchar *convert_to_utf8 (const gchar * text, gint length, guint start,
@@ -78,6 +111,11 @@ static gchar *convert_to_utf8 (const gchar * text, gint length, guint start,
static gchar *get_encoding (const gchar * text, guint * start_text,
gboolean * is_multibyte);
static gchar *get_encoding_and_convert (const gchar * text, guint length);
+static GstClockTime calculate_skew (MpegTSPacketizer2 * packetizer,
+ guint64 pcrtime, GstClockTime time);
+static void record_pcr (MpegTSPacketizer2 * packetizer, guint64 pcr,
+ guint64 offset);
+static void mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer);
#define CONTINUITY_UNSET 255
#define MAX_CONTINUITY 15
@@ -151,6 +189,8 @@ mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass)
{
GObjectClass *gobject_class;
+ g_type_class_add_private (klass, sizeof (MpegTSPacketizerPrivate));
+
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = mpegts_packetizer_dispose;
@@ -160,11 +200,24 @@ mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass)
static void
mpegts_packetizer_init (MpegTSPacketizer2 * packetizer)
{
+ packetizer->priv = MPEGTS_PACKETIZER_GET_PRIVATE (packetizer);
packetizer->adapter = gst_adapter_new ();
packetizer->offset = 0;
packetizer->empty = TRUE;
packetizer->streams = g_new0 (MpegTSPacketizerStream *, 8192);
packetizer->know_packet_size = FALSE;
+ packetizer->calculate_skew = FALSE;
+ packetizer->calculate_offset = FALSE;
+ mpegts_packetizer_reset_skew (packetizer);
+
+ packetizer->priv->first_offset = -1;
+ packetizer->priv->first_pcr = -1;
+ packetizer->priv->first_pcr_ts = GST_CLOCK_TIME_NONE;
+ packetizer->priv->last_offset = -1;
+ packetizer->priv->last_pcr = -1;
+ packetizer->priv->last_pcr_ts = GST_CLOCK_TIME_NONE;
+ packetizer->priv->nb_seen_offsets = 0;
+ packetizer->priv->refoffset = -1;
}
static void
@@ -205,7 +258,7 @@ mpegts_packetizer_finalize (GObject * object)
G_OBJECT_CLASS (mpegts_packetizer_parent_class)->finalize (object);
}
-guint64
+static inline guint64
mpegts_packetizer_compute_pcr (const guint8 * data)
{
guint32 pcr1;
@@ -263,12 +316,23 @@ mpegts_packetizer_parse_adaptation_field_control (MpegTSPacketizer2 *
if (afcflags & MPEGTS_AFC_PCR_FLAG) {
packet->pcr = mpegts_packetizer_compute_pcr (data);
*data += 6;
+ GST_DEBUG ("pcr %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
+ packet->pcr, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (packet->pcr)));
+
+ if (packetizer->calculate_skew)
+ GST_BUFFER_TIMESTAMP (packet->buffer) =
+ calculate_skew (packetizer, packet->pcr,
+ GST_BUFFER_TIMESTAMP (packet->buffer));
+ if (packetizer->calculate_offset)
+ record_pcr (packetizer, packet->pcr, packet->offset);
}
/* OPCR */
if (afcflags & MPEGTS_AFC_OPCR_FLAG) {
packet->opcr = mpegts_packetizer_compute_pcr (data);
- *data += 6;
+ /* *data += 6; */
+ GST_DEBUG ("opcr %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
+ packet->pcr, GST_TIME_ARGS (PCRTIME_TO_GSTTIME (packet->pcr)));
}
return TRUE;
@@ -2316,6 +2380,8 @@ mpegts_packetizer_next_packet (MpegTSPacketizer2 * packetizer,
packetizer->offset += packetizer->packet_size;
GST_MEMDUMP ("buffer", bufdata, 16);
GST_MEMDUMP ("data_start", packet->data_start, 16);
+ GST_BUFFER_TIMESTAMP (packet->buffer) =
+ gst_adapter_prev_timestamp (packetizer->adapter, NULL);
/* Check sync byte */
if (G_LIKELY (packet->data_start[0] == 0x47))
@@ -2360,6 +2426,14 @@ got_valid_packet:
return mpegts_packetizer_parse_packet (packetizer, packet);
}
+MpegTSPacketizerPacketReturn
+mpegts_packetizer_process_next_packet (MpegTSPacketizer2 * packetizer)
+{
+ MpegTSPacketizerPacket packet;
+
+ return mpegts_packetizer_next_packet (packetizer, &packet);
+}
+
void
mpegts_packetizer_clear_packet (MpegTSPacketizer2 * packetizer,
MpegTSPacketizerPacket * packet)
@@ -2400,6 +2474,12 @@ mpegts_packetizer_push_section (MpegTSPacketizer2 * packetizer,
if (packet->pid == 0x14) {
table_id = data[0];
section->section_length = GST_READ_UINT24_BE (data) & 0x000FFF;
+ if (data - packet->bufmap.data + section->section_length + 3 >
+ packet->bufmap.size) {
+ GST_WARNING ("PID %dd PSI section length extends past the end "
+ "of the buffer", packet->pid);
+ goto out;
+ }
section->buffer =
gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
data - packet->bufmap.data, section->section_length + 3);
@@ -2588,13 +2668,22 @@ get_encoding (const gchar * text, guint * start_text, gboolean * is_multibyte)
*start_text = 1;
*is_multibyte = TRUE;
} else if (firstbyte == 0x12) {
- /* That's korean encoding.
- * The spec says it's encoded in KSC 5601, but iconv only knows KSC 5636.
- * Couldn't find any information about either of them.
- */
- encoding = NULL;
+ /* EUC-KR implements KSX1001 */
+ encoding = g_strdup ("EUC-KR");
*start_text = 1;
*is_multibyte = TRUE;
+ } else if (firstbyte == 0x13) {
+ encoding = g_strdup ("GB2312");
+ *start_text = 1;
+ *is_multibyte = FALSE;
+ } else if (firstbyte == 0x14) {
+ encoding = g_strdup ("UTF-16BE");
+ *start_text = 1;
+ *is_multibyte = TRUE;
+ } else if (firstbyte == 0x15) {
+ encoding = g_strdup ("ISO-10646/UTF8");
+ *start_text = 1;
+ *is_multibyte = FALSE;
} else {
/* reserved */
encoding = NULL;
@@ -2646,7 +2735,7 @@ convert_to_utf8 (const gchar * text, gint length, guint start,
/* skip it */
break;
case 0xE08A:{
- guint8 nl[] = { 0x0A, 0x00 }; /* new line */
+ guint8 nl[] = { 0x00, 0x0A }; /* new line */
g_byte_array_append (sb, nl, 2);
break;
}
@@ -2667,7 +2756,7 @@ convert_to_utf8 (const gchar * text, gint length, guint start,
/* skip it */
break;
case 0xE08A:{
- guint8 nl[] = { 0x0A, 0x00 }; /* new line */
+ guint8 nl[] = { 0x00, 0x0A }; /* new line */
g_byte_array_append (sb, nl, 2);
break;
}
@@ -2795,3 +2884,434 @@ failed:
return g_strndup (text, length - start_text);
}
}
+
+/**
+ * mpegts_packetizer_reset_skew:
+ * @packetizer: an #MpegTSPacketizer2
+ *
+ * Reset the skew calculations in @packetizer.
+ */
+static void
+mpegts_packetizer_reset_skew (MpegTSPacketizer2 * packetizer)
+{
+ /* FIXME : These variables should be *per* PCR PID */
+ packetizer->base_time = GST_CLOCK_TIME_NONE;
+ packetizer->base_pcrtime = GST_CLOCK_TIME_NONE;
+ packetizer->last_pcrtime = GST_CLOCK_TIME_NONE;
+ packetizer->window_pos = 0;
+ packetizer->window_filling = TRUE;
+ packetizer->window_min = 0;
+ packetizer->skew = 0;
+ packetizer->prev_send_diff = GST_CLOCK_TIME_NONE;
+ packetizer->prev_out_time = GST_CLOCK_TIME_NONE;
+ GST_DEBUG ("reset skew correction");
+}
+
+static void
+mpegts_packetizer_resync (MpegTSPacketizer2 * packetizer, GstClockTime time,
+ GstClockTime gstpcrtime, gboolean reset_skew)
+{
+ /* FIXME : These variables should be *per* PCR PID */
+ packetizer->base_time = time;
+ packetizer->base_pcrtime = gstpcrtime;
+ packetizer->prev_out_time = GST_CLOCK_TIME_NONE;
+ packetizer->prev_send_diff = GST_CLOCK_TIME_NONE;
+ if (reset_skew) {
+ packetizer->window_filling = TRUE;
+ packetizer->window_pos = 0;
+ packetizer->window_min = 0;
+ packetizer->window_size = 0;
+ packetizer->skew = 0;
+ }
+}
+
+
+/* Code mostly copied from -good/gst/rtpmanager/rtpjitterbuffer.c */
+
+/* For the clock skew we use a windowed low point averaging algorithm as can be
+ * found in Fober, Orlarey and Letz, 2005, "Real Time Clock Skew Estimation
+ * over Network Delays":
+ * http://www.grame.fr/Ressources/pub/TR-050601.pdf
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.1546
+ *
+ * The idea is that the jitter is composed of:
+ *
+ * J = N + n
+ *
+ * N : a constant network delay.
+ * n : random added noise. The noise is concentrated around 0
+ *
+ * In the receiver we can track the elapsed time at the sender with:
+ *
+ * send_diff(i) = (Tsi - Ts0);
+ *
+ * Tsi : The time at the sender at packet i
+ * Ts0 : The time at the sender at the first packet
+ *
+ * This is the difference between the RTP timestamp in the first received packet
+ * and the current packet.
+ *
+ * At the receiver we have to deal with the jitter introduced by the network.
+ *
+ * recv_diff(i) = (Tri - Tr0)
+ *
+ * Tri : The time at the receiver at packet i
+ * Tr0 : The time at the receiver at the first packet
+ *
+ * Both of these values contain a jitter Ji, a jitter for packet i, so we can
+ * write:
+ *
+ * recv_diff(i) = (Cri + D + ni) - (Cr0 + D + n0))
+ *
+ * Cri : The time of the clock at the receiver for packet i
+ * D + ni : The jitter when receiving packet i
+ *
+ * We see that the network delay is irrelevant here as we can elliminate D:
+ *
+ * recv_diff(i) = (Cri + ni) - (Cr0 + n0))
+ *
+ * The drift is now expressed as:
+ *
+ * Drift(i) = recv_diff(i) - send_diff(i);
+ *
+ * We now keep the W latest values of Drift and find the minimum (this is the
+ * one with the lowest network jitter and thus the one which is least affected
+ * by it). We average this lowest value to smooth out the resulting network skew.
+ *
+ * Both the window and the weighting used for averaging influence the accuracy
+ * of the drift estimation. Finding the correct parameters turns out to be a
+ * compromise between accuracy and inertia.
+ *
+ * We use a 2 second window or up to 512 data points, which is statistically big
+ * enough to catch spikes (FIXME, detect spikes).
+ * We also use a rather large weighting factor (125) to smoothly adapt. During
+ * startup, when filling the window, we use a parabolic weighting factor, the
+ * more the window is filled, the faster we move to the detected possible skew.
+ *
+ * Returns: @time adjusted with the clock skew.
+ */
+static GstClockTime
+calculate_skew (MpegTSPacketizer2 * packetizer, guint64 pcrtime,
+ GstClockTime time)
+{
+ guint64 send_diff, recv_diff;
+ gint64 delta;
+ gint64 old;
+ gint pos, i;
+ GstClockTime gstpcrtime, out_time;
+ guint64 slope;
+
+ gstpcrtime = PCRTIME_TO_GSTTIME (pcrtime);
+
+ /* keep track of the last extended pcrtime */
+ packetizer->last_pcrtime = gstpcrtime;
+
+ /* first time, lock on to time and gstpcrtime */
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (packetizer->base_time))) {
+ packetizer->base_time = time;
+ packetizer->prev_out_time = GST_CLOCK_TIME_NONE;
+ GST_DEBUG ("Taking new base time %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
+ }
+
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (packetizer->base_pcrtime))) {
+ packetizer->base_pcrtime = gstpcrtime;
+ packetizer->prev_send_diff = -1;
+ GST_DEBUG ("Taking new base pcrtime %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (gstpcrtime));
+ }
+
+ if (G_LIKELY (gstpcrtime >= packetizer->base_pcrtime))
+ send_diff = gstpcrtime - packetizer->base_pcrtime;
+ else if (GST_CLOCK_TIME_IS_VALID (time)) {
+ /* elapsed time at sender, timestamps can go backwards and thus be smaller
+ * than our base time, take a new base time in that case. */
+ GST_WARNING ("backward timestamps at server, taking new base time");
+ mpegts_packetizer_resync (packetizer, time, gstpcrtime, FALSE);
+ send_diff = 0;
+ } else {
+ GST_WARNING ("backward timestamps at server but no timestamps");
+ send_diff = 0;
+ /* at least try to get a new timestamp.. */
+ packetizer->base_time = -1;
+ }
+
+ GST_DEBUG ("gstpcr %" GST_TIME_FORMAT ", buftime %" GST_TIME_FORMAT ", base %"
+ GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (gstpcrtime), GST_TIME_ARGS (time),
+ GST_TIME_ARGS (packetizer->base_pcrtime), GST_TIME_ARGS (send_diff));
+
+ /* we don't have an arrival timestamp so we can't do skew detection. we
+ * should still apply a timestamp based on RTP timestamp and base_time */
+ if (!GST_CLOCK_TIME_IS_VALID (time)
+ || !GST_CLOCK_TIME_IS_VALID (packetizer->base_time))
+ goto no_skew;
+
+ /* elapsed time at receiver, includes the jitter */
+ recv_diff = time - packetizer->base_time;
+
+ /* Ignore packets received at 100% the same time (i.e. from the same input buffer) */
+ if (G_UNLIKELY (time == packetizer->prev_in_time
+ && GST_CLOCK_TIME_IS_VALID (packetizer->prev_in_time)))
+ goto no_skew;
+
+ /* measure the diff */
+ delta = ((gint64) recv_diff) - ((gint64) send_diff);
+
+ /* measure the slope, this gives a rought estimate between the sender speed
+ * and the receiver speed. This should be approximately 8, higher values
+ * indicate a burst (especially when the connection starts) */
+ slope = recv_diff > 0 ? (send_diff * 8) / recv_diff : 8;
+
+ GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", recv_diff %"
+ GST_TIME_FORMAT ", slope %" G_GUINT64_FORMAT, GST_TIME_ARGS (time),
+ GST_TIME_ARGS (packetizer->base_time), GST_TIME_ARGS (recv_diff), slope);
+
+ /* if the difference between the sender timeline and the receiver timeline
+ * changed too quickly we have to resync because the server likely restarted
+ * its timestamps. */
+ if (ABS (delta - packetizer->skew) > GST_SECOND) {
+ GST_WARNING ("delta - skew: %" GST_TIME_FORMAT " too big, reset skew",
+ GST_TIME_ARGS (delta - packetizer->skew));
+ mpegts_packetizer_resync (packetizer, time, gstpcrtime, TRUE);
+ send_diff = 0;
+ delta = 0;
+ }
+
+ pos = packetizer->window_pos;
+
+ if (G_UNLIKELY (packetizer->window_filling)) {
+ /* we are filling the window */
+ GST_DEBUG ("filling %d, delta %" G_GINT64_FORMAT, pos, delta);
+ packetizer->window[pos++] = delta;
+ /* calc the min delta we observed */
+ if (G_UNLIKELY (pos == 1 || delta < packetizer->window_min))
+ packetizer->window_min = delta;
+
+ if (G_UNLIKELY (send_diff >= MAX_TIME || pos >= MAX_WINDOW)) {
+ packetizer->window_size = pos;
+
+ /* window filled */
+ GST_DEBUG ("min %" G_GINT64_FORMAT, packetizer->window_min);
+
+ /* the skew is now the min */
+ packetizer->skew = packetizer->window_min;
+ packetizer->window_filling = FALSE;
+ } else {
+ gint perc_time, perc_window, perc;
+
+ /* figure out how much we filled the window, this depends on the amount of
+ * time we have or the max number of points we keep. */
+ perc_time = send_diff * 100 / MAX_TIME;
+ perc_window = pos * 100 / MAX_WINDOW;
+ perc = MAX (perc_time, perc_window);
+
+ /* make a parabolic function, the closer we get to the MAX, the more value
+ * we give to the scaling factor of the new value */
+ perc = perc * perc;
+
+ /* quickly go to the min value when we are filling up, slowly when we are
+ * just starting because we're not sure it's a good value yet. */
+ packetizer->skew =
+ (perc * packetizer->window_min + ((10000 -
+ perc) * packetizer->skew)) / 10000;
+ packetizer->window_size = pos + 1;
+ }
+ } else {
+ /* pick old value and store new value. We keep the previous value in order
+ * to quickly check if the min of the window changed */
+ old = packetizer->window[pos];
+ packetizer->window[pos++] = delta;
+
+ if (G_UNLIKELY (delta <= packetizer->window_min)) {
+ /* if the new value we inserted is smaller or equal to the current min,
+ * it becomes the new min */
+ packetizer->window_min = delta;
+ } else if (G_UNLIKELY (old == packetizer->window_min)) {
+ gint64 min = G_MAXINT64;
+
+ /* if we removed the old min, we have to find a new min */
+ for (i = 0; i < packetizer->window_size; i++) {
+ /* we found another value equal to the old min, we can stop searching now */
+ if (packetizer->window[i] == old) {
+ min = old;
+ break;
+ }
+ if (packetizer->window[i] < min)
+ min = packetizer->window[i];
+ }
+ packetizer->window_min = min;
+ }
+ /* average the min values */
+ packetizer->skew =
+ (packetizer->window_min + (124 * packetizer->skew)) / 125;
+ GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT, delta,
+ packetizer->window_min);
+ }
+ /* wrap around in the window */
+ if (G_UNLIKELY (pos >= packetizer->window_size))
+ pos = 0;
+
+ packetizer->window_pos = pos;
+
+no_skew:
+ /* the output time is defined as the base timestamp plus the PCR time
+ * adjusted for the clock skew .*/
+ if (packetizer->base_time != -1) {
+ out_time = packetizer->base_time + send_diff;
+ /* skew can be negative and we don't want to make invalid timestamps */
+ if (packetizer->skew < 0 && out_time < -packetizer->skew) {
+ out_time = 0;
+ } else {
+ out_time += packetizer->skew;
+ }
+ /* check if timestamps are not going backwards, we can only check this if we
+ * have a previous out time and a previous send_diff */
+ if (G_LIKELY (packetizer->prev_out_time != -1
+ && packetizer->prev_send_diff != -1)) {
+ /* now check for backwards timestamps */
+ if (G_UNLIKELY (
+ /* if the server timestamps went up and the out_time backwards */
+ (send_diff > packetizer->prev_send_diff
+ && out_time < packetizer->prev_out_time) ||
+ /* if the server timestamps went backwards and the out_time forwards */
+ (send_diff < packetizer->prev_send_diff
+ && out_time > packetizer->prev_out_time) ||
+ /* if the server timestamps did not change */
+ send_diff == packetizer->prev_send_diff)) {
+ GST_DEBUG ("backwards timestamps, using previous time");
+ out_time = GSTTIME_TO_MPEGTIME (out_time);
+ }
+ }
+ } else {
+ /* We simply use the pcrtime without applying any skew compensation */
+ out_time = time;
+ }
+
+ packetizer->prev_out_time = out_time;
+ packetizer->prev_in_time = time;
+ packetizer->prev_send_diff = send_diff;
+
+ GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
+ packetizer->skew, GST_TIME_ARGS (out_time));
+
+ return out_time;
+}
+
+static void
+record_pcr (MpegTSPacketizer2 * packetizer, guint64 pcr, guint64 offset)
+{
+ MpegTSPacketizerPrivate *priv = packetizer->priv;
+
+ /* Check against first PCR */
+ if (priv->first_pcr == -1 || priv->first_offset > offset) {
+ GST_DEBUG ("Recording first value. PCR:%" G_GUINT64_FORMAT " offset:%"
+ G_GUINT64_FORMAT, pcr, offset);
+ priv->first_pcr = pcr;
+ priv->first_pcr_ts = PCRTIME_TO_GSTTIME (pcr);
+ priv->first_offset = offset;
+ priv->nb_seen_offsets++;
+ } else
+ /* If we didn't update the first PCR, let's check against last PCR */
+ if (priv->last_pcr == -1 || priv->last_offset < offset) {
+ GST_DEBUG ("Recording last value. PCR:%" G_GUINT64_FORMAT " offset:%"
+ G_GUINT64_FORMAT, pcr, offset);
+ if (G_UNLIKELY (priv->first_pcr != -1 && pcr < priv->first_pcr)) {
+ GST_DEBUG ("rollover detected");
+ pcr += PCR_MAX_VALUE;
+ }
+ priv->last_pcr = pcr;
+ priv->last_pcr_ts = PCRTIME_TO_GSTTIME (pcr);
+ priv->last_offset = offset;
+ priv->nb_seen_offsets++;
+ }
+}
+
+guint
+mpegts_packetizer_get_seen_pcr (MpegTSPacketizer2 * packetizer)
+{
+ return packetizer->priv->nb_seen_offsets;
+}
+
+GstClockTime
+mpegts_packetizer_offset_to_ts (MpegTSPacketizer2 * packetizer, guint64 offset)
+{
+ MpegTSPacketizerPrivate *priv = packetizer->priv;
+ GstClockTime res;
+
+ if (G_UNLIKELY (!packetizer->calculate_offset))
+ return GST_CLOCK_TIME_NONE;
+
+ if (G_UNLIKELY (priv->refoffset == -1))
+ return GST_CLOCK_TIME_NONE;
+
+ if (G_UNLIKELY (offset < priv->refoffset))
+ return GST_CLOCK_TIME_NONE;
+
+ /* Convert byte difference into time difference */
+ res = PCRTIME_TO_GSTTIME (gst_util_uint64_scale (offset - priv->refoffset,
+ priv->last_pcr - priv->first_pcr,
+ priv->last_offset - priv->first_offset));
+ GST_DEBUG ("Returning timestamp %" GST_TIME_FORMAT " for offset %"
+ G_GUINT64_FORMAT, GST_TIME_ARGS (res), offset);
+
+ return res;
+}
+
+GstClockTime
+mpegts_packetizer_pts_to_ts (MpegTSPacketizer2 * packetizer, GstClockTime pts)
+{
+ GstClockTime res = GST_CLOCK_TIME_NONE;
+
+ /* Use clock skew if present */
+ if (packetizer->calculate_skew
+ && GST_CLOCK_TIME_IS_VALID (packetizer->base_time)) {
+ GST_DEBUG ("pts %" G_GUINT64_FORMAT " base_pcrtime:%" G_GUINT64_FORMAT
+ " base_time:%" GST_TIME_FORMAT, pts, packetizer->base_pcrtime,
+ GST_TIME_ARGS (packetizer->base_time));
+ res = pts - packetizer->base_pcrtime + packetizer->base_time +
+ packetizer->skew;
+ } else
+ /* If not, use pcr observations */
+ if (packetizer->calculate_offset && packetizer->priv->first_pcr != -1) {
+ /* Rollover */
+ if (G_UNLIKELY (pts < packetizer->priv->first_pcr_ts))
+ pts += MPEGTIME_TO_GSTTIME (PTS_DTS_MAX_VALUE);
+ res = pts - packetizer->priv->first_pcr_ts;
+ }
+
+ GST_DEBUG ("Returning timestamp %" GST_TIME_FORMAT " for pts %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (res), GST_TIME_ARGS (pts));
+ return res;
+}
+
+guint64
+mpegts_packetizer_ts_to_offset (MpegTSPacketizer2 * packetizer, GstClockTime ts)
+{
+ MpegTSPacketizerPrivate *priv = packetizer->priv;
+ guint64 res;
+
+ if (!packetizer->calculate_offset || packetizer->priv->first_pcr == -1)
+ return -1;
+
+ GST_DEBUG ("ts(pcr) %" G_GUINT64_FORMAT " first_pcr:%" G_GUINT64_FORMAT,
+ GSTTIME_TO_MPEGTIME (ts), priv->first_pcr);
+
+ /* Convert ts to PCRTIME */
+ res = gst_util_uint64_scale (GSTTIME_TO_PCRTIME (ts),
+ priv->last_offset - priv->first_offset, priv->last_pcr - priv->first_pcr);
+ res += priv->first_offset + priv->refoffset;
+
+ GST_DEBUG ("Returning offset %" G_GUINT64_FORMAT " for ts %" GST_TIME_FORMAT,
+ res, GST_TIME_ARGS (ts));
+
+ return res;
+}
+
+void
+mpegts_packetizer_set_reference_offset (MpegTSPacketizer2 * packetizer,
+ guint64 refoffset)
+{
+ GST_DEBUG ("Setting reference offset to %" G_GUINT64_FORMAT, refoffset);
+
+ packetizer->priv->refoffset = refoffset;
+}
diff --git a/gst/mpegtsdemux/mpegtspacketizer.h b/gst/mpegtsdemux/mpegtspacketizer.h
index ab6db621a..243d9561a 100644
--- a/gst/mpegtsdemux/mpegtspacketizer.h
+++ b/gst/mpegtsdemux/mpegtspacketizer.h
@@ -28,6 +28,8 @@
#include <gst/base/gstadapter.h>
#include <glib.h>
+#include "gstmpegdefs.h"
+
#define MPEGTS_NORMAL_PACKETSIZE 188
#define MPEGTS_M2TS_PACKETSIZE 192
#define MPEGTS_DVB_ASI_PACKETSIZE 204
@@ -39,6 +41,8 @@
#define MPEGTS_AFC_PCR_FLAG 0x10
#define MPEGTS_AFC_OPCR_FLAG 0x08
+#define MAX_WINDOW 512
+
G_BEGIN_DECLS
#define GST_TYPE_MPEGTS_PACKETIZER \
@@ -54,6 +58,7 @@ G_BEGIN_DECLS
typedef struct _MpegTSPacketizer2 MpegTSPacketizer2;
typedef struct _MpegTSPacketizer2Class MpegTSPacketizer2Class;
+typedef struct _MpegTSPacketizerPrivate MpegTSPacketizerPrivate;
typedef struct
{
@@ -70,6 +75,7 @@ struct _MpegTSPacketizer2 {
GstAdapter *adapter;
/* streams hashed by pid */
+ /* FIXME : be more memory efficient (see how it's done in mpegtsbase) */
MpegTSPacketizerStream **streams;
gboolean disposed;
gboolean know_packet_size;
@@ -79,6 +85,30 @@ struct _MpegTSPacketizer2 {
/* current offset of the tip of the adapter */
guint64 offset;
gboolean empty;
+
+ /* clock skew calculation */
+ gboolean calculate_skew;
+
+ /* Following variables are only active/used when
+ * calculate_skew is TRUE */
+ /* FIXME : These variables should be *per* PCR PID */
+ GstClockTime base_time;
+ GstClockTime base_pcrtime;
+ GstClockTime prev_out_time;
+ GstClockTime prev_in_time;
+ GstClockTime last_pcrtime;
+ gint64 window[MAX_WINDOW];
+ guint window_pos;
+ guint window_size;
+ gboolean window_filling;
+ gint64 window_min;
+ gint64 skew;
+ gint64 prev_send_diff;
+
+ /* offset/bitrate calculator */
+ gboolean calculate_offset;
+
+ MpegTSPacketizerPrivate *priv;
};
struct _MpegTSPacketizer2Class {
@@ -146,6 +176,8 @@ void mpegts_packetizer_push (MpegTSPacketizer2 *packetizer, GstBuffer *buffer);
gboolean mpegts_packetizer_has_packets (MpegTSPacketizer2 *packetizer);
MpegTSPacketizerPacketReturn mpegts_packetizer_next_packet (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerPacket *packet);
+MpegTSPacketizerPacketReturn
+mpegts_packetizer_process_next_packet(MpegTSPacketizer2 * packetizer);
void mpegts_packetizer_clear_packet (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerPacket *packet);
void mpegts_packetizer_remove_stream(MpegTSPacketizer2 *packetizer,
@@ -165,8 +197,22 @@ GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
-guint64 mpegts_packetizer_compute_pcr(const guint8 * data);
+/* Only valid if calculate_offset is TRUE */
+guint mpegts_packetizer_get_seen_pcr (MpegTSPacketizer2 *packetizer);
+
+GstClockTime
+mpegts_packetizer_offset_to_ts (MpegTSPacketizer2 * packetizer,
+ guint64 offset);
+guint64
+mpegts_packetizer_ts_to_offset (MpegTSPacketizer2 * packetizer,
+ GstClockTime ts);
+GstClockTime
+mpegts_packetizer_pts_to_ts (MpegTSPacketizer2 * packetizer,
+ GstClockTime pts);
+void
+mpegts_packetizer_set_reference_offset (MpegTSPacketizer2 * packetizer,
+ guint64 refoffset);
G_END_DECLS
#endif /* GST_MPEGTS_PACKETIZER_H */
diff --git a/gst/mpegtsdemux/payload_parsers.c b/gst/mpegtsdemux/payload_parsers.c
deleted file mode 100644
index ca2c75efd..000000000
--- a/gst/mpegtsdemux/payload_parsers.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * payload_parsers.c
- * Copyright (C) 2011 Janne Grunau
- *
- * Authors:
- * Janne Grunau <janne.grunau@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "payload_parsers.h"
-#include <gst/base/gstbitreader.h>
-
-#define PICTURE_START_CODE 0x00000100
-#define GROUP_START_CODE 0x000001B8
-
-#define SLICE_NAL_UNIT_TYPE 0x01
-#define SLICE_IDR_NAL_UNIT_TYPE 0x05
-#define SEI_NAL_UNIT_TYPE 0x06
-
-#define SEI_TYPE_RECOVERY_POINT 0x06
-
-typedef struct Mpeg2PictureHeader
-{
- guint16 temporal_reference;
- guint8 picture_coding_type;
- guint16 vbv_delay;
-
- /* picture_coding_type == 2 || picture_coding_type */
- guint8 full_pel_forward_vector;
- guint8 forward_f_code;
-
- /* picture_coding_type == 3 */
- guint8 full_pel_backward_vector;
- guint8 backward_f_code;
-} Mpeg2PictureHeader;
-
-/* shortened slice header */
-typedef struct H264SliceHeader
-{
- guint32 first_mb_in_slice;
- guint8 slice_type;
-} H264SliceHeader;
-
-
-static guint8 *
-find_start_code (guint32 * start_code, guint8 * buffer, guint8 * buffer_end)
-{
- if (G_UNLIKELY (buffer == NULL) || G_UNLIKELY (buffer_end == NULL)
- || G_UNLIKELY (start_code == NULL))
- return NULL;
-
- while (buffer <= buffer_end) {
-
- *start_code <<= 8;
- *start_code |= *buffer++;
-
- if ((*start_code & 0xffffff00) == 0x00000100)
- return buffer;
- }
-
- return NULL;
-}
-
-static gboolean
-parse_mpeg2_picture_header (Mpeg2PictureHeader * hdr, guint8 * buffer,
- guint8 * buffer_end)
-{
- GstBitReader br = GST_BIT_READER_INIT (buffer, buffer_end - buffer);
-
- if (gst_bit_reader_get_remaining (&br) < 40)
- return FALSE;
-
- hdr->temporal_reference = gst_bit_reader_get_bits_uint16_unchecked (&br, 10);
- hdr->picture_coding_type = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
- hdr->vbv_delay = gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
-
- if (hdr->picture_coding_type == 2 || hdr->picture_coding_type == 3) {
- hdr->full_pel_forward_vector =
- gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
- hdr->forward_f_code = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
- }
- if (hdr->picture_coding_type == 3) {
- hdr->full_pel_backward_vector =
- gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
- hdr->backward_f_code = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
- }
- return TRUE;
-}
-
-gboolean
-gst_tsdemux_has_mpeg2_keyframe (guint32 * state,
- MpegTSPacketizerPacket * packet, gboolean * need_more)
-{
- guint8 *data = packet->payload;
- guint8 *data_end = packet->data_end;
-
- GST_LOG ("state: 0x%08x", *state);
-
- while (data <= data_end) {
-
- data = find_start_code (state, data, data_end);
-
- if (!data)
- return FALSE;
-
- GST_LOG ("found start code: 0x%08x", *state);
-
- if (*state == GROUP_START_CODE) {
- GST_DEBUG ("found group start code");
- *state = 0xffffffff;
- *need_more = FALSE;
- return TRUE;
- } else if (*state == PICTURE_START_CODE) {
- Mpeg2PictureHeader hdr = { 0 };
- gboolean success;
-
- success = parse_mpeg2_picture_header (&hdr, data, data_end);
- GST_DEBUG ("found picture start code, %sparsed, picture coding type: %d",
- success ? "" : "not ", hdr.picture_coding_type);
-
- *state = 0xffffffff;
- *need_more = FALSE;
- return success && hdr.picture_coding_type == 1;
- }
- }
-
- return FALSE;
-}
-
-/* variable length Exp-Golomb parsing according to H.264 spec 9.1*/
-static gboolean
-read_golomb (GstBitReader * br, guint32 * value)
-{
- guint8 b, leading_zeros = -1;
- *value = 1;
-
- for (b = 0; !b; leading_zeros++) {
- if (!gst_bit_reader_get_bits_uint8 (br, &b, 1))
- return FALSE;
- *value *= 2;
- }
-
- *value = (*value >> 1) - 1;
- if (leading_zeros > 0) {
- guint32 tmp = 0;
- if (!gst_bit_reader_get_bits_uint32 (br, &tmp, leading_zeros))
- return FALSE;
- *value += tmp;
- }
-
- return TRUE;
-}
-
-/* just parse the requirred bits of the slice header */
-static gboolean
-parse_h264_slice_header (H264SliceHeader * hdr, guint8 * buffer,
- guint8 * buffer_end)
-{
- guint32 value;
- GstBitReader br = GST_BIT_READER_INIT (buffer, buffer_end - buffer);
-
- if (!read_golomb (&br, &value))
- return FALSE;
- hdr->first_mb_in_slice = value;
-
- if (!read_golomb (&br, &value))
- return FALSE;
- hdr->slice_type = value;
-
- return TRUE;
-}
-
-enum H264SliceTypes
-{
- h264_p_slice = 0,
- h264_b_slice,
- h264_i_slice,
- h264_sp_slice,
- h264_si_slice,
- h264_p_slice_a,
- h264_b_slice_a,
- h264_i_slice_a,
- h264_sp_slice_a,
- h264_si_slice_a,
-};
-
-static gboolean
-is_key_slice (guint8 slice_type)
-{
- switch (slice_type) {
- case h264_i_slice:
- case h264_si_slice:
- case h264_i_slice_a:
- case h264_si_slice_a:
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-gst_tsdemux_has_h264_keyframe (guint32 * state, MpegTSPacketizerPacket * packet,
- gboolean * need_more)
-{
- guint8 *data = packet->payload;
- guint8 *data_end = packet->data_end;
-
- GST_LOG ("state: 0x%08x", *state);
-
- while (data <= data_end) {
- guint8 nal_unit_type;
- guint8 *next_data = NULL;
-
- data = find_start_code (state, data, data_end);
-
- if (!data)
- goto beach;
-
- GST_LOG ("found start code: 0x%08x", *state);
-
- /* determine length */
- nal_unit_type = *state & 0x1f;
- next_data = find_start_code (state, data, data_end);
-
- if (nal_unit_type == SEI_NAL_UNIT_TYPE && !next_data) {
- GST_WARNING ("NAL unit 0x%02x not completely in ts packet",
- nal_unit_type);
- goto beach;
- }
- next_data -= 4;
-
- switch (nal_unit_type) {
- case SLICE_IDR_NAL_UNIT_TYPE:
- GST_DEBUG ("found SLICE_IDR NAL unit type");
- *state = 0xffffffff;
- *need_more = FALSE;
- return TRUE;
- case SLICE_NAL_UNIT_TYPE:
- {
- H264SliceHeader hdr = { 0 };
- gboolean success;
-
- success = parse_h264_slice_header (&hdr, data, data_end);
- GST_DEBUG ("found SLICE NAL unit type with slice type %d",
- hdr.slice_type);
-
- *state = 0xffffffff;
- *need_more = FALSE;
- return success && is_key_slice (hdr.slice_type);
- }
- case SEI_NAL_UNIT_TYPE:
- {
- guint32 recovery_frame_count;
- GstBitReader br = GST_BIT_READER_INIT (data, next_data - data);
-
- break;
-
- /* SEI message is at least 24 bit long */
- while (gst_bit_reader_get_remaining (&br) >= 24) {
- gint type = 0, size = 0;
- guint8 tmp = 0;
-
- do {
- if (!gst_bit_reader_get_bits_uint8 (&br, &tmp, 8))
- goto beach;
- type += tmp;
- } while (tmp == 255);
-
- do {
- if (!gst_bit_reader_get_bits_uint8 (&br, &tmp, 8))
- goto beach;
- size += tmp;
- } while (tmp == 255);
-
-
- GST_LOG ("found SEI msg type: %d, len: %d", type, size);
-
- switch (type) {
- case SEI_TYPE_RECOVERY_POINT:
- if (!read_golomb (&br, &recovery_frame_count))
- return FALSE;
- gst_bit_reader_skip (&br, 1); /* exact_match */
- gst_bit_reader_skip (&br, 1); /* broken_link_flag */
- gst_bit_reader_skip (&br, 2); /* changing_slice_group_idc */
- GST_DEBUG ("found SEI with recovery point message, "
- "recovery_frame_count: %d", recovery_frame_count);
- return TRUE;
- default:
- /* skip all other sei messages */
- gst_bit_reader_skip (&br, size * 8);
- }
- }
- }
- data = next_data;
- *state = 0xffffffff;
- }
- }
-beach:
- return FALSE;
-}
diff --git a/gst/mpegtsdemux/payload_parsers.h b/gst/mpegtsdemux/payload_parsers.h
deleted file mode 100644
index 7f7a48005..000000000
--- a/gst/mpegtsdemux/payload_parsers.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * payload_parsers.h
- * Copyright (C) 2011 Janne Grunau
- *
- * Authors:
- * Janne Grunau <janne.grunau@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "mpegtspacketizer.h"
-
-typedef gboolean (*payload_parse_keyframe) (guint32 *state,
- MpegTSPacketizerPacket * packet,
- gboolean *need_more);
-
-gboolean gst_tsdemux_has_mpeg2_keyframe (guint32 *state,
- MpegTSPacketizerPacket * packet,
- gboolean *need_more);
-
-gboolean gst_tsdemux_has_h264_keyframe (guint32 *state,
- MpegTSPacketizerPacket * packet,
- gboolean *need_more);
diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c
index 06f813910..cf68672e2 100644
--- a/gst/mpegtsdemux/tsdemux.c
+++ b/gst/mpegtsdemux/tsdemux.c
@@ -41,7 +41,6 @@
#include "gstmpegdesc.h"
#include "gstmpegdefs.h"
#include "mpegtspacketizer.h"
-#include "payload_parsers.h"
#include "pesparse.h"
/*
@@ -65,10 +64,23 @@
#define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298)
#define PTS_DTS_MAX_VALUE (((guint64)1) << 33)
+/* Seeking/Scanning related variables */
+
/* seek to SEEK_TIMESTAMP_OFFSET before the desired offset and search then
* either accurately or for the next timestamp
*/
-#define SEEK_TIMESTAMP_OFFSET (1000 * GST_MSECOND)
+#define SEEK_TIMESTAMP_OFFSET (500 * GST_MSECOND)
+
+#define SEGMENT_FORMAT "[format:%s, rate:%f, start:%" \
+ GST_TIME_FORMAT", stop:%"GST_TIME_FORMAT", time:%"GST_TIME_FORMAT \
+ ", accum:%"GST_TIME_FORMAT", last_stop:%"GST_TIME_FORMAT \
+ ", duration:%"GST_TIME_FORMAT"]"
+
+#define SEGMENT_ARGS(a) gst_format_get_name((a).format), (a).rate, \
+ GST_TIME_ARGS((a).start), GST_TIME_ARGS((a).stop), \
+ GST_TIME_ARGS((a).time), GST_TIME_ARGS((a).accum), \
+ GST_TIME_ARGS((a).last_stop), GST_TIME_ARGS((a).duration)
+
GST_DEBUG_CATEGORY_STATIC (ts_demux_debug);
#define GST_CAT_DEFAULT ts_demux_debug
@@ -102,6 +114,8 @@ struct _TSDemuxStream
MpegTSBaseStream stream;
GstPad *pad;
+ /* Whether the pad was added or not */
+ gboolean active;
/* the return of the latest push */
GstFlowReturn flow_return;
@@ -114,6 +128,11 @@ struct _TSDemuxStream
GstBuffer *pendingbuffers[TS_MAX_PENDING_BUFFERS];
guint8 nbpending;
+ /* Size of data to push (if known) */
+ guint expected_size;
+ /* Size of currently queued data */
+ guint current_size;
+
/* Current data to be pushed out */
GList *currentlist;
@@ -123,9 +142,15 @@ struct _TSDemuxStream
/* Raw value of current PTS/DTS */
guint64 raw_pts;
guint64 raw_dts;
+ /* PTS/DTS with rollover fixed */
+ guint64 fixed_pts;
+ guint64 fixed_dts;
/* Number of rollover seen for PTS/DTS (default:0) */
guint nb_pts_rollover;
guint nb_dts_rollover;
+
+ /* Whether this stream needs to send a newsegment */
+ gboolean need_newsegment;
};
#define VIDEO_CAPS \
@@ -146,8 +171,11 @@ struct _TSDemuxStream
"audio/mpeg, " \
"mpegversion = (int) 1;" \
"audio/mpeg, " \
+ "mpegversion = (int) 2, " \
+ "stream-format = (string) adts; " \
+ "audio/mpeg, " \
"mpegversion = (int) 4, " \
- "stream-format = (string) {adts, loas}; " \
+ "stream-format = (string) latm; " \
"audio/x-lpcm, " \
"width = (int) { 16, 20, 24 }, " \
"rate = (int) { 48000, 96000 }, " \
@@ -196,9 +224,6 @@ enum
};
/* Pad functions */
-static gboolean gst_ts_demux_srcpad_query (GstPad * pad, GstObject * parent,
- GstQuery * query);
-
/* mpegtsbase methods */
static void
@@ -213,20 +238,11 @@ gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * stream,
MpegTSBaseProgram * program);
static void
gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * stream);
-static GstFlowReturn gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event,
- guint16 pid);
-static GstFlowReturn find_pcr_packet (MpegTSBase * base, guint64 offset,
- gint64 length, TSPcrOffset * pcroffset);
-static GstFlowReturn find_timestamps (MpegTSBase * base, guint64 initoff,
- guint64 * offset);
+static GstFlowReturn gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event);
static void gst_ts_demux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_ts_demux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static void gst_ts_demux_finalize (GObject * object);
-static GstFlowReturn
-process_pcr (MpegTSBase * base, guint64 initoff, TSPcrOffset * pcroffset,
- guint numpcr, gboolean isinitial);
static void gst_ts_demux_flush_streams (GstTSDemux * tsdemux);
static GstFlowReturn
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream);
@@ -259,7 +275,6 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_ts_demux_set_property;
gobject_class->get_property = gst_ts_demux_get_property;
- gobject_class->finalize = gst_ts_demux_finalize;
g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBER,
g_param_spec_int ("program-number", "Program number",
@@ -295,58 +310,37 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
ts_class->program_started = GST_DEBUG_FUNCPTR (gst_ts_demux_program_started);
ts_class->stream_added = gst_ts_demux_stream_added;
ts_class->stream_removed = gst_ts_demux_stream_removed;
- ts_class->find_timestamps = GST_DEBUG_FUNCPTR (find_timestamps);
ts_class->seek = GST_DEBUG_FUNCPTR (gst_ts_demux_do_seek);
ts_class->flush = GST_DEBUG_FUNCPTR (gst_ts_demux_flush);
}
static void
-gst_ts_demux_init (GstTSDemux * demux)
-{
- demux->need_newsegment = TRUE;
- demux->program_number = -1;
- demux->duration = GST_CLOCK_TIME_NONE;
- demux->pts_delta = GST_CLOCK_TIME_NONE;
- GST_MPEGTS_BASE (demux)->stream_size = sizeof (TSDemuxStream);
- gst_segment_init (&demux->segment, GST_FORMAT_TIME);
- demux->first_pcr = (TSPcrOffset) {
- GST_CLOCK_TIME_NONE, 0, 0};
- demux->cur_pcr = (TSPcrOffset) {
- 0};
- demux->last_pcr = (TSPcrOffset) {
- 0};
-}
-
-static void
gst_ts_demux_reset (MpegTSBase * base)
{
GstTSDemux *demux = (GstTSDemux *) base;
- if (demux->index) {
- g_array_free (demux->index, TRUE);
- demux->index = NULL;
- }
- demux->index_size = 0;
- demux->need_newsegment = TRUE;
demux->program_number = -1;
- demux->duration = GST_CLOCK_TIME_NONE;
- demux->pts_delta = GST_CLOCK_TIME_NONE;
+ demux->calculate_update_segment = FALSE;
+
gst_segment_init (&demux->segment, GST_FORMAT_TIME);
- demux->first_pcr = (TSPcrOffset) {
- GST_CLOCK_TIME_NONE, 0, 0};
- demux->cur_pcr = (TSPcrOffset) {
- 0};
- demux->last_pcr = (TSPcrOffset) {
- 0};
+ if (demux->segment_event) {
+ gst_event_unref (demux->segment_event);
+ demux->segment_event = NULL;
+ }
+
+ if (demux->update_segment) {
+ gst_event_unref (demux->update_segment);
+ demux->update_segment = NULL;
+ }
}
static void
-gst_ts_demux_finalize (GObject * object)
+gst_ts_demux_init (GstTSDemux * demux, GstTSDemuxClass * klass)
{
- if (G_OBJECT_CLASS (parent_class)->finalize)
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
+ GST_MPEGTS_BASE (demux)->stream_size = sizeof (TSDemuxStream);
+ gst_ts_demux_reset ((MpegTSBase *) demux);
+}
static void
@@ -387,6 +381,19 @@ gst_ts_demux_get_property (GObject * object, guint prop_id,
}
}
+static const GstQueryType *
+gst_ts_demux_srcpad_query_types (GstPad * pad)
+{
+ static const GstQueryType query_types[] = {
+ GST_QUERY_DURATION,
+ GST_QUERY_SEEKING,
+ GST_QUERY_LATENCY,
+ 0
+ };
+
+ return query_types;
+}
+
static gboolean
gst_ts_demux_srcpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
@@ -400,17 +407,31 @@ gst_ts_demux_srcpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
+ {
GST_DEBUG ("query duration");
gst_query_parse_duration (query, &format, NULL);
if (format == GST_FORMAT_TIME) {
- if (!gst_pad_peer_query (base->sinkpad, query))
- gst_query_set_duration (query, GST_FORMAT_TIME,
- demux->segment.duration);
+ if (!gst_pad_peer_query (base->sinkpad, query)) {
+ gint64 val;
+
+ format = GST_FORMAT_BYTES;
+ if (!gst_pad_query_peer_duration (base->sinkpad, &format, &val))
+ res = FALSE;
+ else {
+ GstClockTime dur =
+ mpegts_packetizer_offset_to_ts (base->packetizer, val);
+ if (GST_CLOCK_TIME_IS_VALID (dur))
+ gst_query_set_duration (query, GST_FORMAT_TIME, dur);
+ else
+ res = FALSE;
+ }
+ }
} else {
GST_DEBUG_OBJECT (demux, "only query duration on TIME is supported");
res = FALSE;
}
break;
+ }
case GST_QUERY_LATENCY:
{
GST_DEBUG ("query latency");
@@ -433,9 +454,10 @@ gst_ts_demux_srcpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
max_lat += 700 * GST_MSECOND;
gst_query_set_latency (query, live, min_lat, max_lat);
}
- }
break;
+ }
case GST_QUERY_SEEKING:
+ {
GST_DEBUG ("query seeking");
gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
if (format == GST_FORMAT_TIME) {
@@ -455,6 +477,7 @@ gst_ts_demux_srcpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
res = FALSE;
}
break;
+ }
default:
res = gst_pad_query_default (pad, parent, query);
}
@@ -463,376 +486,8 @@ gst_ts_demux_srcpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
}
-static inline GstClockTime
-calculate_gsttime (TSPcrOffset * start, guint64 pcr)
-{
-
- GstClockTime time = start->gsttime;
-
- if (start->pcr > pcr)
- time += PCRTIME_TO_GSTTIME (PCR_MAX_VALUE - start->pcr) +
- PCRTIME_TO_GSTTIME (pcr);
- else
- time += PCRTIME_TO_GSTTIME (pcr - start->pcr);
-
- return time;
-}
-
-static GstFlowReturn
-gst_ts_demux_parse_pes_header_pts (GstTSDemux * demux,
- MpegTSPacketizerPacket * packet, guint64 * time)
-{
- PESHeader header;
- gint offset = 0;
-
- if (mpegts_parse_pes_header (packet->payload,
- packet->data_end - packet->payload, &header, &offset))
- return GST_FLOW_ERROR;
-
- *time = header.PTS;
- return GST_FLOW_OK;
-}
-
-/* performs a accurate/key_unit seek */
-static GstFlowReturn
-gst_ts_demux_perform_auxiliary_seek (MpegTSBase * base, GstClockTime seektime,
- TSPcrOffset * pcroffset, gint64 length, gint16 pid, GstSeekFlags flags,
- payload_parse_keyframe auxiliary_seek_fn)
-{
- GstTSDemux *demux = (GstTSDemux *) base;
- GstFlowReturn res = GST_FLOW_ERROR;
- gboolean done = FALSE;
- gboolean found_keyframe = FALSE, found_accurate = FALSE, need_more = TRUE;
- GstBuffer *buf;
- MpegTSPacketizerPacket packet;
- MpegTSPacketizerPacketReturn pret;
- gint64 offset = pcroffset->offset;
- gint64 scan_offset = MIN (length, 50 * MPEGTS_MAX_PACKETSIZE);
- guint32 state = 0xffffffff;
- TSPcrOffset key_pos = { 0 };
-
- GST_DEBUG ("auxiliary seek for %" GST_TIME_FORMAT " from offset: %"
- G_GINT64_FORMAT " in %" G_GINT64_FORMAT " bytes for PID: %d "
- "%s %s", GST_TIME_ARGS (seektime), pcroffset->offset, length, pid,
- (flags & GST_SEEK_FLAG_ACCURATE) ? "accurate" : "",
- (flags & GST_SEEK_FLAG_KEY_UNIT) ? "key_unit" : "");
-
- mpegts_packetizer_flush (base->packetizer);
-
- if (base->packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE)
- offset -= 4;
-
- while (!done && scan_offset <= length) {
- buf = NULL;
- res =
- gst_pad_pull_range (base->sinkpad, offset + scan_offset,
- 50 * MPEGTS_MAX_PACKETSIZE, &buf);
- if (res != GST_FLOW_OK)
- goto beach;
- mpegts_packetizer_push (base->packetizer, buf);
-
- while ((!done)
- && ((pret =
- mpegts_packetizer_next_packet (base->packetizer,
- &packet)) != PACKET_NEED_MORE)) {
- if (G_UNLIKELY (pret == PACKET_BAD))
- /* bad header, skip the packet */
- goto next;
-
- if (packet.payload_unit_start_indicator)
- GST_DEBUG ("found packet for PID: %d with pcr: %" GST_TIME_FORMAT
- " at offset: %" G_GINT64_FORMAT, packet.pid,
- GST_TIME_ARGS (packet.pcr), packet.offset);
-
- if (packet.payload != NULL && packet.pid == pid) {
-
- if (packet.payload_unit_start_indicator) {
- guint64 pts = 0;
- GstFlowReturn ok =
- gst_ts_demux_parse_pes_header_pts (demux, &packet, &pts);
- if (ok == GST_FLOW_OK) {
- GstClockTime time = calculate_gsttime (pcroffset, pts * 300);
-
- GST_DEBUG ("packet has PTS: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (time));
-
- if (time <= seektime) {
- pcroffset->gsttime = time;
- pcroffset->pcr = packet.pcr;
- pcroffset->offset = packet.offset;
- } else
- found_accurate = TRUE;
- } else
- goto next;
- /* reset state for new packet */
- state = 0xffffffff;
- need_more = TRUE;
- }
-
- if (auxiliary_seek_fn) {
- if (need_more) {
- if (auxiliary_seek_fn (&state, &packet, &need_more)) {
- found_keyframe = TRUE;
- key_pos = *pcroffset;
- GST_DEBUG ("found keyframe: time: %" GST_TIME_FORMAT " pcr: %"
- GST_TIME_FORMAT " offset %" G_GINT64_FORMAT,
- GST_TIME_ARGS (pcroffset->gsttime),
- GST_TIME_ARGS (pcroffset->pcr), pcroffset->offset);
- }
- }
- } else {
- /* if we don't have a payload parsing function
- * every frame is a keyframe */
- found_keyframe = TRUE;
- }
- }
- if (flags & GST_SEEK_FLAG_ACCURATE)
- done = found_accurate && found_keyframe;
- else
- done = found_keyframe;
- if (done)
- *pcroffset = key_pos;
- next:
- mpegts_packetizer_clear_packet (base->packetizer, &packet);
- }
- scan_offset += 50 * MPEGTS_MAX_PACKETSIZE;
- }
-
-beach:
- if (done)
- res = GST_FLOW_OK;
- else if (GST_FLOW_OK == res)
- res = GST_FLOW_CUSTOM_ERROR_1;
-
- mpegts_packetizer_flush (base->packetizer);
- return res;
-}
-
-static gint
-TSPcrOffset_find (gconstpointer a, gconstpointer b, gpointer user_data)
-{
-
-/* GST_INFO ("a: %" GST_TIME_FORMAT " offset: %" G_GINT64_FORMAT, */
-/* GST_TIME_ARGS (((TSPcrOffset *) a)->gsttime), ((TSPcrOffset *) a)->offset); */
-/* GST_INFO ("b: %" GST_TIME_FORMAT " offset: %" G_GINT64_FORMAT, */
-/* GST_TIME_ARGS (((TSPcrOffset *) b)->gsttime), ((TSPcrOffset *) b)->offset); */
-
- if (((TSPcrOffset *) a)->gsttime < ((TSPcrOffset *) b)->gsttime)
- return -1;
- else if (((TSPcrOffset *) a)->gsttime > ((TSPcrOffset *) b)->gsttime)
- return 1;
- else
- return 0;
-}
-
-static GstFlowReturn
-gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
-{
- GstTSDemux *demux = (GstTSDemux *) base;
- GstFlowReturn res = GST_FLOW_ERROR;
- int max_loop_cnt, loop_cnt = 0;
- gint64 seekpos = 0;
- gint64 time_diff;
- GstClockTime seektime;
- TSPcrOffset seekpcroffset, pcr_start, pcr_stop, *tmp;
-
- max_loop_cnt = (segment->flags & GST_SEEK_FLAG_ACCURATE) ? 25 : 10;
-
- seektime =
- MAX (0, segment->stop - SEEK_TIMESTAMP_OFFSET) + demux->first_pcr.gsttime;
- seekpcroffset.gsttime = seektime;
-
- GST_DEBUG ("seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (seektime));
-
- gst_ts_demux_flush_streams (demux);
-
- if (G_UNLIKELY (!demux->index)) {
- GST_ERROR ("no index");
- goto done;
- }
-
- /* get the first index entry before the seek position */
- tmp = gst_util_array_binary_search (demux->index->data, demux->index_size,
- sizeof (*tmp), TSPcrOffset_find, GST_SEARCH_MODE_BEFORE, &seekpcroffset,
- NULL);
-
- if (G_UNLIKELY (!tmp)) {
- GST_ERROR ("value not found");
- goto done;
- }
-
- pcr_start = *tmp;
- pcr_stop = *(++tmp);
-
- if (G_UNLIKELY (!pcr_stop.offset)) {
- GST_ERROR ("invalid entry");
- goto done;
- }
-
- /* check if the last recorded pcr can be used */
- if (pcr_start.offset < demux->cur_pcr.offset
- && demux->cur_pcr.offset < pcr_stop.offset) {
- demux->cur_pcr.gsttime = calculate_gsttime (&pcr_start, demux->cur_pcr.pcr);
- if (demux->cur_pcr.gsttime < seekpcroffset.gsttime)
- pcr_start = demux->cur_pcr;
- else
- pcr_stop = demux->cur_pcr;
- }
-
- GST_DEBUG ("start %" GST_TIME_FORMAT " offset: %" G_GINT64_FORMAT,
- GST_TIME_ARGS (pcr_start.gsttime), pcr_start.offset);
- GST_DEBUG ("stop %" GST_TIME_FORMAT " offset: %" G_GINT64_FORMAT,
- GST_TIME_ARGS (pcr_stop.gsttime), pcr_stop.offset);
-
- time_diff = seektime - pcr_start.gsttime;
- seekpcroffset = pcr_start;
-
- GST_DEBUG ("cur %" GST_TIME_FORMAT " offset: %" G_GINT64_FORMAT
- " time diff: %" G_GINT64_FORMAT,
- GST_TIME_ARGS (demux->cur_pcr.gsttime), demux->cur_pcr.offset, time_diff);
-
- /* seek loop */
- while (loop_cnt++ < max_loop_cnt && (time_diff > SEEK_TIMESTAMP_OFFSET >> 1)
- && (pcr_stop.gsttime - pcr_start.gsttime > SEEK_TIMESTAMP_OFFSET)) {
- gint64 duration = pcr_stop.gsttime - pcr_start.gsttime;
- gint64 size = pcr_stop.offset - pcr_start.offset;
-
- if (loop_cnt & 1)
- seekpos = pcr_start.offset + (size >> 1);
- else
- seekpos =
- pcr_start.offset + size * ((double) (seektime -
- pcr_start.gsttime) / duration);
-
- /* look a litle bit behind */
- seekpos =
- MAX (pcr_start.offset + 188, seekpos - 55 * MPEGTS_MAX_PACKETSIZE);
-
- GST_DEBUG ("looking for time: %" GST_TIME_FORMAT " .. %" GST_TIME_FORMAT
- " .. %" GST_TIME_FORMAT,
- GST_TIME_ARGS (pcr_start.gsttime),
- GST_TIME_ARGS (seektime), GST_TIME_ARGS (pcr_stop.gsttime));
- GST_DEBUG ("looking in bytes: %" G_GINT64_FORMAT " .. %" G_GINT64_FORMAT
- " .. %" G_GINT64_FORMAT, pcr_start.offset, seekpos, pcr_stop.offset);
-
- res =
- find_pcr_packet (&demux->parent, seekpos, 4000 * MPEGTS_MAX_PACKETSIZE,
- &seekpcroffset);
- if (G_UNLIKELY (res == GST_FLOW_EOS)) {
- seekpos =
- MAX ((gint64) pcr_start.offset,
- seekpos - 2000 * MPEGTS_MAX_PACKETSIZE) + 188;
- res =
- find_pcr_packet (&demux->parent, seekpos,
- 8000 * MPEGTS_MAX_PACKETSIZE, &seekpcroffset);
- }
- if (G_UNLIKELY (res != GST_FLOW_OK)) {
- GST_WARNING ("seeking failed %s", gst_flow_get_name (res));
- goto done;
- }
-
- seekpcroffset.gsttime = calculate_gsttime (&pcr_start, seekpcroffset.pcr);
-
- /* validate */
- if (G_UNLIKELY ((seekpcroffset.gsttime < pcr_start.gsttime) ||
- (seekpcroffset.gsttime > pcr_stop.gsttime))) {
- GST_ERROR ("Unexpected timestamp found, seeking failed! %"
- GST_TIME_FORMAT, GST_TIME_ARGS (seekpcroffset.gsttime));
- res = GST_FLOW_ERROR;
- goto done;
- }
-
- if (seekpcroffset.gsttime > seektime) {
- pcr_stop = seekpcroffset;
- } else {
- pcr_start = seekpcroffset;
- }
- time_diff = seektime - pcr_start.gsttime;
- GST_DEBUG ("seeking: %" GST_TIME_FORMAT " found: %" GST_TIME_FORMAT
- " diff = %" G_GINT64_FORMAT, GST_TIME_ARGS (seektime),
- GST_TIME_ARGS (seekpcroffset.gsttime), time_diff);
- }
-
- GST_DEBUG ("seeking finished after %d loops", loop_cnt);
-
- /* use correct seek position for the auxiliary search */
- seektime += SEEK_TIMESTAMP_OFFSET;
-
- {
- payload_parse_keyframe keyframe_seek = NULL;
- MpegTSBaseProgram *program = demux->program;
- guint64 avg_bitrate, length;
-
- if (program->streams[pid]) {
- switch (program->streams[pid]->stream_type) {
- case ST_VIDEO_MPEG1:
- case ST_VIDEO_MPEG2:
- keyframe_seek = gst_tsdemux_has_mpeg2_keyframe;
- break;
- case ST_VIDEO_H264:
- keyframe_seek = gst_tsdemux_has_h264_keyframe;
- break;
- case ST_VIDEO_MPEG4:
- case ST_VIDEO_DIRAC:
- GST_WARNING ("no payload parser for stream 0x%04x type: 0x%02x", pid,
- program->streams[pid]->stream_type);
- break;
- }
- } else
- GST_WARNING ("no stream info for PID: 0x%04x", pid);
-
- avg_bitrate =
- (pcr_stop.offset -
- pcr_start.offset) * 1000 * GST_MSECOND / (pcr_stop.gsttime -
- pcr_start.gsttime);
-
- seekpcroffset = pcr_start;
- /* search in 2500ms for a keyframe */
- length =
- MIN (demux->last_pcr.offset - pcr_start.offset,
- (avg_bitrate * 25) / 10);
- res =
- gst_ts_demux_perform_auxiliary_seek (base, seektime, &seekpcroffset,
- length, pid, segment->flags, keyframe_seek);
-
- if (res == GST_FLOW_CUSTOM_ERROR_1) {
- GST_ERROR ("no keyframe found in %" G_GUINT64_FORMAT
- " bytes starting from %" G_GUINT64_FORMAT, length,
- seekpcroffset.offset);
- res = GST_FLOW_ERROR;
- }
- if (res != GST_FLOW_OK)
- goto done;
- }
-
-
- /* update seektime to the actual timestamp of the found keyframe */
- if (segment->flags & GST_SEEK_FLAG_KEY_UNIT)
- seektime = seekpcroffset.gsttime;
-
- seektime -= demux->first_pcr.gsttime;
-
-#if 0
- segment->last_stop = seektime;
-#endif
- segment->time = seektime;
-
- /* we stop at the end */
- if (segment->stop == -1)
- segment->stop = demux->first_pcr.gsttime + segment->duration;
-
- demux->need_newsegment = TRUE;
- demux->parent.seek_offset = seekpcroffset.offset;
- GST_DEBUG ("seeked to postion:%" GST_TIME_FORMAT, GST_TIME_ARGS (seektime));
- res = GST_FLOW_OK;
-
-done:
- return res;
-}
-
-
static GstFlowReturn
-gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event, guint16 pid)
+gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event)
{
GstTSDemux *demux = (GstTSDemux *) base;
GstFlowReturn res = GST_FLOW_ERROR;
@@ -843,6 +498,7 @@ gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event, guint16 pid)
gint64 start, stop;
GstSegment seeksegment;
gboolean update;
+ guint64 start_offset;
gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
&stop_type, &stop);
@@ -863,28 +519,35 @@ gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event, guint16 pid)
/* copy segment, we need this because we still need the old
* segment when we close the current segment. */
memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
-
+ if (demux->segment_event) {
+ gst_event_unref (demux->segment_event);
+ demux->segment_event = NULL;
+ }
/* configure the segment with the seek variables */
GST_DEBUG_OBJECT (demux, "configuring seek");
- GST_DEBUG ("seeksegment: start: %" GST_TIME_FORMAT " stop: %"
- GST_TIME_FORMAT " time: %" GST_TIME_FORMAT
- " duration: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (seeksegment.stop),
- GST_TIME_ARGS (seeksegment.time), GST_TIME_ARGS (seeksegment.duration));
- gst_segment_do_seek (&seeksegment, rate, format, flags, start_type, start,
+ GST_DEBUG ("seeksegment before set_seek " SEGMENT_FORMAT,
+ SEGMENT_ARGS (seeksegment));
+
+ gst_segment_set_seek (&seeksegment, rate, format, flags, start_type, start,
stop_type, stop, &update);
- GST_DEBUG ("seeksegment: start: %" GST_TIME_FORMAT " stop: %"
- GST_TIME_FORMAT " time: %" GST_TIME_FORMAT
- " duration: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (seeksegment.stop),
- GST_TIME_ARGS (seeksegment.time), GST_TIME_ARGS (seeksegment.duration));
-
- res = gst_ts_demux_perform_seek (base, &seeksegment, pid);
- if (G_UNLIKELY (res != GST_FLOW_OK)) {
- GST_WARNING ("seeking failed %s", gst_flow_get_name (res));
+
+ GST_DEBUG ("seeksegment after set_seek " SEGMENT_FORMAT,
+ SEGMENT_ARGS (seeksegment));
+
+ /* Convert start/stop to offset */
+ start_offset =
+ mpegts_packetizer_ts_to_offset (base->packetizer, MAX (0,
+ start - SEEK_TIMESTAMP_OFFSET));
+
+ if (G_UNLIKELY (start_offset == -1)) {
+ GST_WARNING ("Couldn't convert start position to an offset");
goto done;
}
+ /* record offset */
+ base->seek_offset = start_offset;
+ res = GST_FLOW_OK;
+
/* commit the new segment */
memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
@@ -1012,8 +675,7 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
break;
case ST_PRIVATE_DATA:
GST_LOG ("private data");
- desc =
- mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
+ desc = mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
DESC_DVB_AC3);
if (desc) {
GST_LOG ("ac3 audio");
@@ -1023,8 +685,8 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
g_free (desc);
break;
}
- desc =
- mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
+
+ desc = mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
DESC_DVB_ENHANCED_AC3);
if (desc) {
GST_LOG ("ac3 audio");
@@ -1034,8 +696,7 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
g_free (desc);
break;
}
- desc =
- mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
+ desc = mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
DESC_DVB_TELETEXT);
if (desc) {
GST_LOG ("teletext");
@@ -1056,6 +717,26 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
g_free (desc);
break;
}
+
+ desc = mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
+ DESC_REGISTRATION);
+ if (desc) {
+ switch (DESC_REGISTRATION_format_identifier (desc)) {
+ case DRF_ID_DTS1:
+ case DRF_ID_DTS2:
+ case DRF_ID_DTS3:
+ /* SMPTE registered DTS */
+ GST_LOG ("subtitling");
+ template = gst_static_pad_template_get (&private_template);
+ name = g_strdup_printf ("private_%04x", bstream->pid);
+ caps = gst_caps_new_simple ("audio/x-dts", NULL);
+ break;
+ }
+ g_free (desc);
+ }
+ if (template)
+ break;
+
/* hack for itv hd (sid 10510, video pid 3401 */
if (program->program_number == 10510 && bstream->pid == 3401) {
template = gst_static_pad_template_get (&video_template);
@@ -1090,7 +771,7 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
template = gst_static_pad_template_get (&audio_template);
name = g_strdup_printf ("audio_%04x", bstream->pid);
caps = gst_caps_new_simple ("audio/mpeg",
- "mpegversion", G_TYPE_INT, 4,
+ "mpegversion", G_TYPE_INT, 2,
"stream-format", G_TYPE_STRING, "adts", NULL);
break;
case ST_AUDIO_AAC_LATM:
@@ -1098,7 +779,7 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
name = g_strdup_printf ("audio_%04x", bstream->pid);
caps = gst_caps_new_simple ("audio/mpeg",
"mpegversion", G_TYPE_INT, 4,
- "stream-format", G_TYPE_STRING, "loas", NULL);
+ "stream-format", G_TYPE_STRING, "latm", NULL);
break;
case ST_VIDEO_MPEG4:
template = gst_static_pad_template_get (&video_template);
@@ -1158,18 +839,34 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
desc = mpegts_get_descriptor_from_program (program, DESC_REGISTRATION);
if (desc) {
if (DESC_REGISTRATION_format_identifier (desc) == DRF_ID_HDMV) {
- template = gst_static_pad_template_get (&audio_template);
- name = g_strdup_printf ("audio_%04x", bstream->pid);
- caps = gst_caps_new_empty_simple ("audio/x-eac3");
+ guint8 *ac3_desc;
+
+ /* ATSC ac3 audio descriptor */
+ ac3_desc =
+ mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
+ DESC_AC3_AUDIO_STREAM);
+ if (ac3_desc && DESC_AC_AUDIO_STREAM_bsid (ac3_desc) != 16) {
+ GST_LOG ("ac3 audio");
+ template = gst_static_pad_template_get (&audio_template);
+ name = g_strdup_printf ("audio_%04x", bstream->pid);
+ caps = gst_caps_new_simple ("audio/x-ac3", NULL);
+
+ g_free (ac3_desc);
+ } else {
+ template = gst_static_pad_template_get (&audio_template);
+ name = g_strdup_printf ("audio_%04x", bstream->pid);
+ caps = gst_caps_new_simple ("audio/x-eac3", NULL);
+ }
}
+
g_free (desc);
}
if (template)
break;
+
/* DVB_ENHANCED_AC3 */
- desc =
- mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
+ desc = mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream,
DESC_DVB_ENHANCED_AC3);
if (desc) {
template = gst_static_pad_template_get (&audio_template);
@@ -1261,11 +958,15 @@ gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream,
/* Create the pad */
if (bstream->stream_type != 0xff)
stream->pad = create_pad_for_stream (base, bstream, program);
+ stream->active = FALSE;
+ stream->need_newsegment = TRUE;
stream->pts = GST_CLOCK_TIME_NONE;
stream->dts = GST_CLOCK_TIME_NONE;
stream->raw_pts = 0;
stream->raw_dts = 0;
+ stream->fixed_pts = 0;
+ stream->fixed_dts = 0;
stream->nb_pts_rollover = 0;
stream->nb_dts_rollover = 0;
}
@@ -1275,29 +976,20 @@ gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream,
static void
gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * bstream)
{
- GstTSDemux *demux = GST_TS_DEMUX (base);
TSDemuxStream *stream = (TSDemuxStream *) bstream;
if (stream->pad) {
- if (gst_pad_is_active (stream->pad)) {
- gboolean need_newsegment = demux->need_newsegment;
-
- /* We must not send the newsegment when flushing the pending data
- on the removed stream. We should only push it when the newly added
- stream finishes parsing its PTS */
- demux->need_newsegment = FALSE;
-
+ if (stream->active && gst_pad_is_active (stream->pad)) {
/* Flush out all data */
GST_DEBUG_OBJECT (stream->pad, "Flushing out pending data");
gst_ts_demux_push_pending_data ((GstTSDemux *) base, stream);
- demux->need_newsegment = need_newsegment;
-
GST_DEBUG_OBJECT (stream->pad, "Pushing out EOS");
gst_pad_push_event (stream->pad, gst_event_new_eos ());
GST_DEBUG_OBJECT (stream->pad, "Deactivating and removing pad");
gst_pad_set_active (stream->pad, FALSE);
gst_element_remove_pad (GST_ELEMENT_CAST (base), stream->pad);
+ stream->active = FALSE;
}
stream->pad = NULL;
}
@@ -1311,6 +1003,7 @@ activate_pad_for_stream (GstTSDemux * tsdemux, TSDemuxStream * stream)
GST_DEBUG_OBJECT (tsdemux, "Activating pad %s:%s for stream %p",
GST_DEBUG_PAD_NAME (stream->pad), stream);
gst_element_add_pad ((GstElement *) tsdemux, stream->pad);
+ stream->active = TRUE;
GST_DEBUG_OBJECT (stream->pad, "done adding pad");
} else
GST_WARNING_OBJECT (tsdemux,
@@ -1330,6 +1023,19 @@ gst_ts_demux_stream_flush (TSDemuxStream * stream)
gst_buffer_unref (stream->pendingbuffers[i]);
memset (stream->pendingbuffers, 0, TS_MAX_PENDING_BUFFERS);
stream->nbpending = 0;
+
+ stream->expected_size = 0;
+ stream->current_size = 0;
+ stream->current = NULL;
+ stream->need_newsegment = TRUE;
+ stream->pts = GST_CLOCK_TIME_NONE;
+ stream->dts = GST_CLOCK_TIME_NONE;
+ stream->raw_pts = 0;
+ stream->raw_dts = 0;
+ stream->fixed_pts = 0;
+ stream->fixed_dts = 0;
+ stream->nb_pts_rollover = 0;
+ stream->nb_dts_rollover = 0;
}
static void
@@ -1349,504 +1055,32 @@ gst_ts_demux_program_started (MpegTSBase * base, MpegTSBaseProgram * program)
if (demux->program_number == -1 ||
demux->program_number == program->program_number) {
- GList *tmp;
GST_LOG ("program %d started", program->program_number);
demux->program_number = program->program_number;
demux->program = program;
- /* Activate all stream pads, pads will already have been created */
- if (base->mode != BASE_MODE_SCANNING) {
- for (tmp = program->stream_list; tmp; tmp = tmp->next)
- activate_pad_for_stream (demux, (TSDemuxStream *) tmp->data);
- gst_element_no_more_pads ((GstElement *) demux);
+ /* If this is not the initial program, we need to calculate
+ * an update newsegment */
+ demux->calculate_update_segment = !program->initial_program;
+
+ /* If we have an upstream time segment and it's the initial program, just use that */
+ if (program->initial_program && base->segment.format == GST_FORMAT_TIME) {
+ demux->segment = base->segment;
+ demux->segment_event =
+ gst_event_new_new_segment_full (FALSE, base->segment.rate,
+ base->segment.applied_rate, GST_FORMAT_TIME, base->segment.start,
+ base->segment.stop, base->segment.time);
+ GST_EVENT_SRC (demux->segment_event) = gst_object_ref (demux);
}
+ /* FIXME : When do we emit no_more_pads ? */
+
/* Inform scanner we have got our program */
demux->current_program_number = program->program_number;
- demux->need_newsegment = TRUE;
}
}
-static gboolean
-process_section (MpegTSBase * base)
-{
- GstTSDemux *demux = GST_TS_DEMUX (base);
- gboolean based;
- gboolean done = FALSE;
- MpegTSPacketizerPacket packet;
- MpegTSPacketizerPacketReturn pret;
-
- while ((!done) &&
- ((pret = mpegts_packetizer_next_packet (base->packetizer, &packet))
- != PACKET_NEED_MORE)) {
-
- if (G_UNLIKELY (pret == PACKET_BAD))
- /* bad header, skip the packet */
- goto next;
-
- /* base PSI data */
- if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) {
- MpegTSPacketizerSection section;
-
- based = mpegts_packetizer_push_section (base->packetizer, &packet,
- &section);
-
- if (G_UNLIKELY (!based))
- /* bad section data */
- goto next;
-
- if (G_LIKELY (section.complete)) {
- /* section complete */
- GST_DEBUG ("Section Complete");
- based = mpegts_base_handle_psi (base, &section);
- gst_buffer_unref (section.buffer);
- if (G_UNLIKELY (!based))
- /* bad PSI table */
- goto next;
-
- }
-
- if (demux->program != NULL) {
- GST_DEBUG ("Got Program");
- done = TRUE;
- }
- }
- next:
- mpegts_packetizer_clear_packet (base->packetizer, &packet);
- }
-
- return done;
-}
-
-static gboolean
-process_pes (MpegTSBase * base, TSPcrOffset * pcroffset)
-{
- gboolean based, done = FALSE;
- MpegTSPacketizerPacket packet;
- MpegTSPacketizerPacketReturn pret;
- GstTSDemux *demux = GST_TS_DEMUX (base);
- guint16 pcr_pid = 0;
-
- while ((!done) &&
- ((pret = mpegts_packetizer_next_packet (base->packetizer, &packet))
- != PACKET_NEED_MORE)) {
- if (G_UNLIKELY (pret == PACKET_BAD))
- /* bad header, skip the packet */
- goto next;
-
- if (demux->program != NULL) {
- pcr_pid = demux->program->pcr_pid;
- }
-
- /* base PSI data */
- if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) {
- MpegTSPacketizerSection section;
-
- based = mpegts_packetizer_push_section (base->packetizer, &packet,
- &section);
-
- if (G_UNLIKELY (!based))
- /* bad section data */
- goto next;
-
- if (G_LIKELY (section.complete)) {
- /* section complete */
- GST_DEBUG ("Section Complete");
- based = mpegts_base_handle_psi (base, &section);
- gst_buffer_unref (section.buffer);
- if (G_UNLIKELY (!based))
- /* bad PSI table */
- goto next;
-
- }
- }
- if (packet.pid == pcr_pid && (packet.adaptation_field_control & 0x02)
- && (packet.afc_flags & MPEGTS_AFC_PCR_FLAG)) {
- GST_DEBUG ("PCR[0x%x]: %" G_GINT64_FORMAT, packet.pid, packet.pcr);
- pcroffset->pcr = packet.pcr;
- pcroffset->offset = packet.offset;
- done = TRUE;
- }
- next:
- mpegts_packetizer_clear_packet (base->packetizer, &packet);
- }
- return done;
-}
-
-static GstFlowReturn
-find_pcr_packet (MpegTSBase * base, guint64 offset, gint64 length,
- TSPcrOffset * pcroffset)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstTSDemux *demux = GST_TS_DEMUX (base);
- MpegTSBaseProgram *program;
- GstBuffer *buf;
- gboolean done = FALSE;
- guint64 scan_offset = 0;
-
- GST_DEBUG ("Scanning for PCR between:%" G_GINT64_FORMAT
- " and the end:%" G_GINT64_FORMAT, offset, offset + length);
-
- /* Get the program */
- program = demux->program;
- if (G_UNLIKELY (program == NULL))
- return GST_FLOW_ERROR;
-
- mpegts_packetizer_flush (base->packetizer);
- if (offset >= 4 && base->packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE)
- offset -= 4;
-
- while (!done && scan_offset < length) {
- buf = NULL;
- ret =
- gst_pad_pull_range (base->sinkpad, offset + scan_offset,
- 50 * MPEGTS_MAX_PACKETSIZE, &buf);
- if (ret != GST_FLOW_OK)
- goto beach;
- mpegts_packetizer_push (base->packetizer, buf);
- done = process_pes (base, pcroffset);
- scan_offset += 50 * MPEGTS_MAX_PACKETSIZE;
- }
-
- if (!done || scan_offset >= length) {
- GST_WARNING ("No PCR found!");
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
-beach:
- mpegts_packetizer_flush (base->packetizer);
- return ret;
-}
-
-static gboolean
-verify_timestamps (MpegTSBase * base, TSPcrOffset * first, TSPcrOffset * last)
-{
- GstTSDemux *demux = GST_TS_DEMUX (base);
- guint64 length = 4000 * MPEGTS_MAX_PACKETSIZE;
- guint64 offset = PCR_WRAP_SIZE_128KBPS;
-
- demux->index =
- g_array_sized_new (TRUE, TRUE, sizeof (*first),
- 2 + 1 + ((last->offset - first->offset) / PCR_WRAP_SIZE_128KBPS));
-
- first->gsttime = PCRTIME_TO_GSTTIME (first->pcr);
- demux->index = g_array_append_val (demux->index, *first);
- demux->index_size++;
- demux->first_pcr = *first;
- demux->index_pcr = *first;
- GST_DEBUG ("first time: %" GST_TIME_FORMAT " pcr: %" GST_TIME_FORMAT
- " offset: %" G_GINT64_FORMAT
- " last pcr: %" GST_TIME_FORMAT " offset: %" G_GINT64_FORMAT,
- GST_TIME_ARGS (first->gsttime),
- GST_TIME_ARGS (PCRTIME_TO_GSTTIME (first->pcr)), first->offset,
- GST_TIME_ARGS (PCRTIME_TO_GSTTIME (last->pcr)), last->offset);
-
- while (offset + length < last->offset) {
- TSPcrOffset half;
- GstFlowReturn ret;
- gint tries = 0;
-
- retry:
- ret = find_pcr_packet (base, offset, length, &half);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- GST_WARNING ("no pcr found, retrying");
- if (tries++ < 3) {
- offset += length;
- length *= 2;
- goto retry;
- }
- return FALSE;
- }
-
- half.gsttime = calculate_gsttime (first, half.pcr);
-
- GST_DEBUG ("add half time: %" GST_TIME_FORMAT " pcr: %" GST_TIME_FORMAT
- " offset: %" G_GINT64_FORMAT,
- GST_TIME_ARGS (half.gsttime),
- GST_TIME_ARGS (PCRTIME_TO_GSTTIME (half.pcr)), half.offset);
- demux->index = g_array_append_val (demux->index, half);
- demux->index_size++;
-
- length = 4000 * MPEGTS_MAX_PACKETSIZE;
- offset += PCR_WRAP_SIZE_128KBPS;
- *first = half;
- }
-
- last->gsttime = calculate_gsttime (first, last->pcr);
-
- GST_DEBUG ("add last time: %" GST_TIME_FORMAT " pcr: %" GST_TIME_FORMAT
- " offset: %" G_GINT64_FORMAT,
- GST_TIME_ARGS (last->gsttime),
- GST_TIME_ARGS (PCRTIME_TO_GSTTIME (last->pcr)), last->offset);
-
- demux->index = g_array_append_val (demux->index, *last);
- demux->index_size++;
-
- demux->last_pcr = *last;
- return TRUE;
-}
-
-static GstFlowReturn
-find_timestamps (MpegTSBase * base, guint64 initoff, guint64 * offset)
-{
-
- GstFlowReturn ret = GST_FLOW_OK;
- GstBuffer *buf;
- gboolean done = FALSE;
- gint64 total_bytes;
- guint64 scan_offset;
- guint i = 0;
- TSPcrOffset initial, final;
- GstTSDemux *demux = GST_TS_DEMUX (base);
-
- GST_DEBUG ("Scanning for timestamps");
-
- /* Start scanning from now PAT offset */
-
- while (!done) {
- buf = NULL;
- ret = gst_pad_pull_range (base->sinkpad, i * 50 * MPEGTS_MAX_PACKETSIZE,
- 50 * MPEGTS_MAX_PACKETSIZE, &buf);
-
- if (ret != GST_FLOW_OK)
- goto beach;
-
- mpegts_packetizer_push (base->packetizer, buf);
- done = process_section (base);
- i++;
- }
- mpegts_packetizer_clear (base->packetizer);
- done = FALSE;
- i = 1;
-
- *offset = base->seek_offset;
-
- /* Search for the first PCRs */
- ret = process_pcr (base, base->first_pat_offset, &initial, 10, TRUE);
-
- if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS) {
- GST_WARNING ("Problem getting initial PCRs");
- goto beach;
- }
-
- mpegts_packetizer_clear (base->packetizer);
- /* Remove current program so we ensure looking for a PAT when scanning
- * for the final PCR */
- gst_structure_free (base->pat);
- base->pat = NULL;
- mpegts_base_remove_program (base, demux->current_program_number);
- demux->program = NULL;
-
- /* Find end position */
- if (G_UNLIKELY (!gst_pad_peer_query_duration (base->sinkpad, GST_FORMAT_BYTES,
- &total_bytes))) {
- GST_WARNING_OBJECT (base, "Couldn't get upstream size in bytes");
- mpegts_packetizer_clear (base->packetizer);
-
- return GST_FLOW_ERROR;
- }
- GST_DEBUG ("Upstream is %" G_GINT64_FORMAT " bytes", total_bytes);
-
-
- /* Let's start scanning 4000 packets from the end */
- scan_offset = MAX (188, total_bytes - 4000 * MPEGTS_MAX_PACKETSIZE);
-
- GST_DEBUG ("Scanning for last sync point between:%" G_GINT64_FORMAT
- " and the end:%" G_GINT64_FORMAT, scan_offset, total_bytes);
-
- while ((!done) && (scan_offset < total_bytes)) {
- buf = NULL;
- ret = gst_pad_pull_range (base->sinkpad, scan_offset,
- 50 * MPEGTS_MAX_PACKETSIZE, &buf);
-
- if (ret != GST_FLOW_OK)
- goto beach;
-
- mpegts_packetizer_push (base->packetizer, buf);
- done = process_section (base);
- scan_offset += 50 * MPEGTS_MAX_PACKETSIZE;
- }
-
- mpegts_packetizer_clear (base->packetizer);
-
- ret = process_pcr (base, scan_offset - 50 * MPEGTS_MAX_PACKETSIZE, &final,
- 10, FALSE);
-
- if (ret != GST_FLOW_OK) {
- GST_DEBUG ("Problem getting last PCRs");
- goto beach;
- }
-
- verify_timestamps (base, &initial, &final);
-
- demux->duration = demux->segment.duration =
- demux->last_pcr.gsttime - demux->first_pcr.gsttime;
- GST_DEBUG ("Done, duration:%" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->duration));
-
-beach:
-
- mpegts_packetizer_clear (base->packetizer);
- /* Remove current program */
- if (base->pat) {
- gst_structure_free (base->pat);
- base->pat = NULL;
- }
- mpegts_base_remove_program (base, demux->current_program_number);
- demux->program = NULL;
-
- return ret;
-}
-
-static GstFlowReturn
-process_pcr (MpegTSBase * base, guint64 initoff, TSPcrOffset * pcroffset,
- guint numpcr, gboolean isinitial)
-{
- GstTSDemux *demux = GST_TS_DEMUX (base);
- GstFlowReturn ret = GST_FLOW_OK;
- MpegTSBaseProgram *program;
- GstBuffer *buf;
- guint i, nbpcr = 0;
- guint32 pcrmask, pcrpattern;
- guint64 pcrs[50];
- guint64 pcroffs[50];
- GstByteReader br;
-
- GST_DEBUG ("initoff:%" G_GUINT64_FORMAT ", numpcr:%d, isinitial:%d",
- initoff, numpcr, isinitial);
-
- /* Get the program */
- program = demux->program;
- if (G_UNLIKELY (program == NULL)) {
- GST_DEBUG ("No program set, can not keep processing pcr");
-
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
- /* First find the first X PCR */
- nbpcr = 0;
- /* Mask/pattern is PID:PCR_PID, AFC&0x02 */
- /* sync_byte (0x47) : 8bits => 0xff
- * transport_error_indicator : 1bit ACTIVATE
- * payload_unit_start_indicator : 1bit IGNORE
- * transport_priority : 1bit IGNORE
- * PID : 13bit => 0x9f 0xff
- * transport_scrambling_control : 2bit
- * adaptation_field_control : 2bit
- * continuity_counter : 4bit => 0x30
- */
- pcrmask = 0xff9fff20;
- pcrpattern = 0x47000020 | ((program->pcr_pid & 0x1fff) << 8);
-
- for (i = 0; (i < 20) && (nbpcr < numpcr); i++) {
- guint offset;
- GstMapInfo map;
- gsize size;
-
- buf = NULL;
- ret = gst_pad_pull_range (base->sinkpad,
- initoff + i * 500 * base->packetsize, 500 * base->packetsize, &buf);
-
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto beach;
-
- gst_buffer_map (buf, &map, GST_MAP_READ);
- size = map.size;
-
- gst_byte_reader_init (&br, map.data, map.size);
-
- offset = 0;
-
- resync:
- offset = gst_byte_reader_masked_scan_uint32 (&br, 0xff000000, 0x47000000,
- 0, base->packetsize);
-
- if (offset == -1) {
- gst_buffer_unmap (buf, &map);
- continue;
- }
-
- while ((nbpcr < numpcr) && (size >= base->packetsize)) {
-
- guint32 header = GST_READ_UINT32_BE (br.data + offset);
-
- if ((header >> 24) != 0x47)
- goto resync;
-
- if ((header & pcrmask) != pcrpattern) {
- /* Move offset forward by 1 packet */
- size -= base->packetsize;
- offset += base->packetsize;
- continue;
- }
-
- /* Potential PCR */
-/* GST_DEBUG ("offset %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf) + offset);
- GST_MEMDUMP ("something", GST_BUFFER_DATA (buf) + offset, 16);*/
- if ((*(br.data + offset + 5)) & MPEGTS_AFC_PCR_FLAG) {
- guint64 lpcr = mpegts_packetizer_compute_pcr (br.data + offset + 6);
-
- GST_INFO ("Found PCR %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT
- " at offset %" G_GUINT64_FORMAT, lpcr,
- GST_TIME_ARGS (PCRTIME_TO_GSTTIME (lpcr)),
- GST_BUFFER_OFFSET (buf) + offset);
- pcrs[nbpcr] = lpcr;
- pcroffs[nbpcr] = GST_BUFFER_OFFSET (buf) + offset;
- /* Safeguard against bogus PCR (by detecting if it's the same as the
- * previous one or wheter the difference with the previous one is
- * greater than 10mins */
- if (nbpcr > 1) {
- if (pcrs[nbpcr] == pcrs[nbpcr - 1]) {
- GST_WARNING ("Found same PCR at different offset");
- } else if (pcrs[nbpcr] < pcrs[nbpcr - 1]) {
- GST_WARNING ("Found PCR wraparound");
- nbpcr += 1;
- } else if ((pcrs[nbpcr] - pcrs[nbpcr - 1]) >
- (guint64) 10 * 60 * 27000000) {
- GST_WARNING ("PCR differs with previous PCR by more than 10 mins");
- } else
- nbpcr += 1;
- } else
- nbpcr += 1;
- }
- /* Move offset forward by 1 packet */
- size -= base->packetsize;
- offset += base->packetsize;
- }
- gst_buffer_unmap (buf, &map);
- }
-
-beach:
- GST_DEBUG ("Found %d PCR", nbpcr);
- if (nbpcr) {
- if (isinitial) {
- pcroffset->pcr = pcrs[0];
- pcroffset->offset = pcroffs[0];
- } else {
- pcroffset->pcr = pcrs[nbpcr - 1];
- pcroffset->offset = pcroffs[nbpcr - 1];
- }
- if (nbpcr > 1) {
- GST_DEBUG ("pcrdiff:%" GST_TIME_FORMAT " offsetdiff %" G_GUINT64_FORMAT,
- GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcrs[nbpcr - 1] - pcrs[0])),
- pcroffs[nbpcr - 1] - pcroffs[0]);
- GST_DEBUG ("Estimated bitrate %" G_GUINT64_FORMAT,
- gst_util_uint64_scale (GST_SECOND, pcroffs[nbpcr - 1] - pcroffs[0],
- PCRTIME_TO_GSTTIME (pcrs[nbpcr - 1] - pcrs[0])));
- GST_DEBUG ("Average PCR interval %" G_GUINT64_FORMAT,
- (pcroffs[nbpcr - 1] - pcroffs[0]) / nbpcr);
- }
- }
- /* Swallow any errors if it happened during the end scanning */
- if (!isinitial)
- ret = GST_FLOW_OK;
- return ret;
-}
-
-
static inline void
@@ -1859,17 +1093,7 @@ gst_ts_demux_record_pcr (GstTSDemux * demux, TSDemuxStream * stream,
G_GUINT64_FORMAT, bs->pid,
GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcr)), offset);
- if (G_LIKELY (bs->pid == demux->program->pcr_pid)) {
- demux->cur_pcr.gsttime = GST_CLOCK_TIME_NONE;
- demux->cur_pcr.offset = offset;
- demux->cur_pcr.pcr = pcr;
- /* set first_pcr in push mode */
- if (G_UNLIKELY (!demux->first_pcr.gsttime == GST_CLOCK_TIME_NONE)) {
- demux->first_pcr.gsttime = PCRTIME_TO_GSTTIME (pcr);
- demux->first_pcr.offset = offset;
- demux->first_pcr.pcr = pcr;
- }
- }
+ /* FIXME : packetizer should record this */
if (G_UNLIKELY (demux->emit_statistics)) {
GstStructure *st;
@@ -1893,6 +1117,8 @@ gst_ts_demux_record_opcr (GstTSDemux * demux, TSDemuxStream * stream,
G_GUINT64_FORMAT, bs->pid,
GST_TIME_ARGS (PCRTIME_TO_GSTTIME (opcr)), offset);
+ /* FIXME : packetizer should record this */
+
if (G_UNLIKELY (demux->emit_statistics)) {
GstStructure *st;
st = gst_structure_new_id_empty (QUARK_TSDEMUX);
@@ -1932,8 +1158,8 @@ gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream,
/* Compute PTS in GstClockTime */
stream->raw_pts = pts;
- stream->pts =
- MPEGTIME_TO_GSTTIME (pts + stream->nb_pts_rollover * PTS_DTS_MAX_VALUE);
+ stream->fixed_pts = pts + stream->nb_pts_rollover * PTS_DTS_MAX_VALUE;
+ stream->pts = MPEGTIME_TO_GSTTIME (stream->fixed_pts);
GST_LOG ("pid 0x%04x Stored PTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
bs->pid, stream->raw_pts, GST_TIME_ARGS (stream->pts));
@@ -1978,8 +1204,8 @@ gst_ts_demux_record_dts (GstTSDemux * demux, TSDemuxStream * stream,
/* Compute DTS in GstClockTime */
stream->raw_dts = dts;
- stream->dts =
- MPEGTIME_TO_GSTTIME (dts + stream->nb_dts_rollover * PTS_DTS_MAX_VALUE);
+ stream->fixed_dts = dts + stream->nb_dts_rollover * PTS_DTS_MAX_VALUE;
+ stream->dts = MPEGTIME_TO_GSTTIME (stream->fixed_dts);
GST_LOG ("pid 0x%04x Stored DTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
bs->pid, stream->raw_dts, GST_TIME_ARGS (stream->dts));
@@ -1996,32 +1222,6 @@ gst_ts_demux_record_dts (GstTSDemux * demux, TSDemuxStream * stream,
}
}
-static inline GstClockTime
-calc_gsttime_from_pts (TSPcrOffset * start, guint64 pts)
-{
- GstClockTime time = start->gsttime - PCRTIME_TO_GSTTIME (start->pcr);
-
- if (start->pcr > pts * 300)
- time += PCRTIME_TO_GSTTIME (PCR_MAX_VALUE) + MPEGTIME_TO_GSTTIME (pts);
- else
- time += MPEGTIME_TO_GSTTIME (pts);
-
- return time;
-}
-
-#if 0
-static gint
-TSPcrOffset_find_offset (gconstpointer a, gconstpointer b, gpointer user_data)
-{
- if (((TSPcrOffset *) a)->offset < ((TSPcrOffset *) b)->offset)
- return -1;
- else if (((TSPcrOffset *) a)->offset > ((TSPcrOffset *) b)->offset)
- return 1;
- else
- return 0;
-}
-#endif
-
static GstFlowReturn
gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
{
@@ -2057,83 +1257,19 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
if (header.PTS != -1) {
gst_ts_demux_record_pts (demux, stream, header.PTS, bufferoffset);
-#if 0
- /* WTH IS THIS ??? */
- if (demux->index_pcr.offset + PCR_WRAP_SIZE_128KBPS + 1000 * 128 < offset
- || (demux->index_pcr.offset > offset)) {
- /* find next entry */
- TSPcrOffset *next;
- demux->index_pcr.offset = offset;
- next = gst_util_array_binary_search (demux->index->data,
- demux->index_size, sizeof (*next), TSPcrOffset_find_offset,
- GST_SEARCH_MODE_BEFORE, &demux->index_pcr, NULL);
- if (next) {
- GST_INFO ("new index_pcr %" GST_TIME_FORMAT " offset: %"
- G_GINT64_FORMAT, GST_TIME_ARGS (next->gsttime), next->offset);
-
- demux->index_pcr = *next;
- }
- }
- time = calc_gsttime_from_pts (&demux->index_pcr, pts);
-#endif
-
GST_DEBUG_OBJECT (base,
"stream PTS %" GST_TIME_FORMAT " DTS %" GST_TIME_FORMAT,
GST_TIME_ARGS (stream->pts),
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (header.DTS)));
- /* FIXME : This will only work if the PES header is contained
- * at the beginning of an incoming GstBuffer */
- /* FIXME : Handle wrap-around ? */
- if (base->upstream_live && GST_CLOCK_TIME_IS_VALID (origts)
- && !GST_CLOCK_TIME_IS_VALID (demux->pts_delta)) {
- if (GST_CLOCK_TIME_IS_VALID (MPEGTIME_TO_GSTTIME (header.DTS)))
- demux->pts_delta = MPEGTIME_TO_GSTTIME (header.DTS) - origts;
- else
- demux->pts_delta = stream->pts - origts;
- GST_DEBUG_OBJECT (base, "buffer timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (origts));
- GST_DEBUG_OBJECT (base, "delta %" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->pts_delta));
- }
-
- /* safe default if insufficient upstream info */
- if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (base->in_gap) &&
- GST_CLOCK_TIME_IS_VALID (base->first_buf_ts) &&
- base->mode == BASE_MODE_PUSHING &&
- base->segment.format == GST_FORMAT_TIME)) {
- /* Find the earliest current PTS we're going to push */
- GstClockTime firstpts = GST_CLOCK_TIME_NONE;
- GList *tmp;
-
- for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) {
- TSDemuxStream *pstream = (TSDemuxStream *) tmp->data;
- if (!GST_CLOCK_TIME_IS_VALID (firstpts) || pstream->pts < firstpts)
- firstpts = pstream->pts;
- }
+ {
+ MpegTSPacketizer2 *packetizer = base->packetizer;
- base->in_gap = base->first_buf_ts - firstpts;
- GST_DEBUG_OBJECT (base, "upstream segment start %" GST_TIME_FORMAT
- ", first buffer timestamp: %" GST_TIME_FORMAT
- ", first PTS: %" GST_TIME_FORMAT
- ", interpolation gap: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (base->segment.start),
- GST_TIME_ARGS (base->first_buf_ts), GST_TIME_ARGS (firstpts),
- GST_TIME_ARGS (base->in_gap));
+ GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) =
+ mpegts_packetizer_pts_to_ts (packetizer, stream->pts);
}
-
- if (!GST_CLOCK_TIME_IS_VALID (base->in_gap))
- base->in_gap = 0;
-
- if (base->upstream_live) {
- if (GST_CLOCK_TIME_IS_VALID (demux->pts_delta))
- GST_BUFFER_TIMESTAMP (buf) = stream->pts - demux->pts_delta;
- else
- GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
- } else
- GST_BUFFER_TIMESTAMP (buf) = stream->pts + base->in_gap;
GST_DEBUG ("buf %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0])));
}
if (header.DTS != -1)
@@ -2142,7 +1278,10 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
gst_buffer_unmap (buf, &map);
/* Remove PES headers */
- GST_DEBUG ("Moving data forward by %d bytes", header.header_size);
+ GST_DEBUG ("Moving data forward by %d bytes (packet_size:%d, have:%d)",
+ header.header_size, header.packet_length,
+ GST_BUFFER_SIZE (stream->pendingbuffers[0]));
+ stream->expected_size = header.packet_length;
gst_buffer_resize (buf, header.header_size, map.size - header.header_size);
/* FIXME : responsible for switching to PENDING_PACKET_BUFFER and
@@ -2206,12 +1345,14 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream,
GST_LOG ("HEADER: appending data to array");
/* Append to the array */
stream->pendingbuffers[stream->nbpending++] = buf;
+ stream->current_size += GST_BUFFER_SIZE (buf);
/* parse the header */
gst_ts_demux_parse_pes_header (demux, stream);
} else if (stream->state == PENDING_PACKET_BUFFER) {
GST_LOG ("BUFFER: appending data to bufferlist");
stream->currentlist = g_list_prepend (stream->currentlist, buf);
+ stream->current_size += GST_BUFFER_SIZE (buf);
}
@@ -2222,86 +1363,73 @@ static void
calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream)
{
MpegTSBase *base = (MpegTSBase *) demux;
- GstEvent *newsegmentevent;
- gint64 start = 0, stop = GST_CLOCK_TIME_NONE, position = 0;
- GstClockTime firstpts = GST_CLOCK_TIME_NONE;
+ GstClockTime lowest_pts = GST_CLOCK_TIME_NONE;
+ GstClockTime firstts = 0;
GList *tmp;
GST_DEBUG ("Creating new newsegment for stream %p", stream);
- /* Outgoing newsegment values
- * start : The first/start PTS
- * stop : The last PTS (or -1)
- * position : The stream time corresponding to start
- *
- * Except for live mode with incoming GST_TIME_FORMAT newsegment where
- * it is the same values as that incoming newsegment (and we convert the
- * PTS to that remote clock).
- */
+ /* 1) If we need to calculate an update newsegment, do it
+ * 2) If we need to calculate a new newsegment, do it
+ * 3) If an update_segment is valid, push it
+ * 4) If a newsegment is valid, push it */
+
+ /* Speedup : if we don't need to calculate anything, go straight to pushing */
+ if (!demux->calculate_update_segment && demux->segment_event)
+ goto push_new_segment;
+ /* Calculate the 'new_start' value, used for both updates and newsegment */
for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) {
TSDemuxStream *pstream = (TSDemuxStream *) tmp->data;
- if (!GST_CLOCK_TIME_IS_VALID (firstpts) || pstream->pts < firstpts)
- firstpts = pstream->pts;
+ if (GST_CLOCK_TIME_IS_VALID (pstream->pts)) {
+ if (!GST_CLOCK_TIME_IS_VALID (lowest_pts) || pstream->pts < lowest_pts)
+ lowest_pts = pstream->pts;
+ }
+ if (GST_CLOCK_TIME_IS_VALID (pstream->dts)) {
+ if (!GST_CLOCK_TIME_IS_VALID (lowest_pts) || pstream->dts < lowest_pts)
+ lowest_pts = pstream->dts;
+ }
}
- if (base->mode == BASE_MODE_PUSHING) {
- /* FIXME : We're just ignore the upstream format for the time being */
- /* FIXME : We should use base->segment.format and a upstream latency query
- * to decide if we need to use live values or not */
- GST_DEBUG ("push-based. base Segment start:%" GST_TIME_FORMAT " duration:%"
- GST_TIME_FORMAT ", stop:%" GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT,
- GST_TIME_ARGS (base->segment.start),
- GST_TIME_ARGS (base->segment.duration),
- GST_TIME_ARGS (base->segment.stop), GST_TIME_ARGS (base->segment.time));
- GST_DEBUG ("push-based. demux Segment start:%" GST_TIME_FORMAT " duration:%"
- GST_TIME_FORMAT ", stop:%" GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->segment.start),
- GST_TIME_ARGS (demux->segment.duration),
- GST_TIME_ARGS (demux->segment.stop),
- GST_TIME_ARGS (demux->segment.time));
-
- GST_DEBUG ("stream pts: %" GST_TIME_FORMAT " first pts: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->pts), GST_TIME_ARGS (firstpts));
-
- if (base->segment.format == GST_FORMAT_TIME) {
- start = base->segment.start;
- stop = base->segment.stop;
- if (!base->upstream_live) {
- /* Shift the start depending on our position in the stream */
- start += firstpts + base->in_gap - base->first_buf_ts;
- }
+ if (GST_CLOCK_TIME_IS_VALID (lowest_pts))
+ firstts = mpegts_packetizer_pts_to_ts (base->packetizer, lowest_pts);
+ GST_DEBUG ("lowest_pts %" G_GUINT64_FORMAT " => clocktime %" GST_TIME_FORMAT,
+ lowest_pts, GST_TIME_ARGS (firstts));
+
+ if (demux->calculate_update_segment) {
+ GST_DEBUG ("Calculating update segment");
+ /* If we have a valid segment, create an update of that */
+ if (demux->segment.format == GST_FORMAT_TIME) {
+ GST_DEBUG ("Re-using segment " SEGMENT_FORMAT,
+ SEGMENT_ARGS (demux->segment));
+ demux->update_segment = gst_event_new_segment (&demux->segment);
+ GST_EVENT_SRC (demux->update_segment) = gst_object_ref (demux);
}
- position = start;
- } else {
- /* pull mode */
- GST_DEBUG ("pull-based. Segment start:%" GST_TIME_FORMAT " duration:%"
- GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->segment.start),
- GST_TIME_ARGS (demux->segment.duration),
- GST_TIME_ARGS (demux->segment.time));
-
- GST_DEBUG ("firstpcr gsttime : %" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->first_pcr.gsttime));
-
- /* FIXME : This is not entirely correct. We should be using the PTS time
- * realm and not the PCR one. Doesn't matter *too* much if PTS/PCR values
- * aren't too far apart, but still. */
- start = demux->first_pcr.gsttime + demux->segment.start;
- stop = demux->first_pcr.gsttime + demux->segment.duration;
- position = demux->segment.time;
+ demux->calculate_update_segment = FALSE;
}
- GST_DEBUG ("new segment: start: %" GST_TIME_FORMAT " stop: %"
- GST_TIME_FORMAT " time: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
- GST_TIME_ARGS (stop), GST_TIME_ARGS (position));
+ if (!demux->segment_event) {
+ GST_DEBUG ("Calculating actual segment");
+ /* FIXME : Set proper values */
+ demux->segment_event = gst_event_new_segment (&demux->segment);
+ GST_EVENT_SRC (demux->segment_event) = gst_object_ref (demux);
+ }
- newsegmentevent = gst_event_new_segment (&demux->segment);
+push_new_segment:
+ if (demux->update_segment) {
+ GST_DEBUG_OBJECT (stream->pad, "Pushing update segment");
+ gst_event_ref (demux->update_segment);
+ gst_pad_push_event (stream->pad, demux->update_segment);
+ }
- push_event ((MpegTSBase *) demux, newsegmentevent);
+ if (demux->segment_event) {
+ GST_DEBUG_OBJECT (stream->pad, "Pushing newsegment event");
+ gst_event_ref (demux->segment_event);
+ gst_pad_push_event (stream->pad, demux->segment_event);
+ }
- demux->need_newsegment = FALSE;
+ stream->need_newsegment = FALSE;
}
static GstFlowReturn
@@ -2310,8 +1438,9 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
GstFlowReturn res = GST_FLOW_OK;
GList *tmp;
MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
- GstBuffer *buf;
- GstClockTime ts;
+ /* MpegTSBase *base = (MpegTSBase*) demux; */
+ GstBuffer *firstbuffer = NULL;
+ MpegTSPacketizer2 *packetizer = MPEG_TS_BASE_PACKETIZER (demux);
GST_DEBUG_OBJECT (stream->pad,
"stream:%p, pid:0x%04x stream_type:%d state:%d", stream, bs->pid,
@@ -2330,6 +1459,9 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
if (G_UNLIKELY (stream->state != PENDING_PACKET_BUFFER))
goto beach;
+ if (G_UNLIKELY (!stream->active))
+ activate_pad_for_stream (demux, stream);
+
if (G_UNLIKELY (stream->pad == NULL)) {
g_list_foreach (stream->currentlist, (GFunc) gst_buffer_unref, NULL);
g_list_free (stream->currentlist);
@@ -2337,12 +1469,11 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
goto beach;
}
- if (G_UNLIKELY (demux->need_newsegment))
+ if (G_UNLIKELY (stream->need_newsegment))
calculate_and_push_newsegment (demux, stream);
/* We have a confirmed buffer, let's push it out */
- GST_LOG ("Putting pending data into GstBufferList");
-
+ GST_LOG_OBJECT (stream->pad, "Putting pending data into buffer list");
stream->currentlist = g_list_reverse (stream->currentlist);
buf = (GstBuffer *) stream->currentlist->data;
@@ -2363,10 +1494,18 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
buf = gst_buffer_append (buf, (GstBuffer *) tmp->data);
}
- GST_BUFFER_TIMESTAMP (buf) = ts;
+ firstbuffer = gst_buffer_list_get (stream->current, 0, 0);
+
+ GST_DEBUG_OBJECT (stream->pad, "stream->pts %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (stream->pts));
+ if (GST_CLOCK_TIME_IS_VALID (stream->pts)
+ && !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (firstbuffer)))
+ GST_BUFFER_TIMESTAMP (firstbuffer) =
+ mpegts_packetizer_pts_to_ts (packetizer, stream->pts);
+
GST_DEBUG_OBJECT (stream->pad,
- "Pushing buffer with timestamp: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+ "Pushing buffer list with timestamp: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (firstbuffer)));
res = gst_pad_push (stream->pad, buf);
GST_DEBUG_OBJECT (stream->pad, "Returned %s", gst_flow_get_name (res));
@@ -2375,13 +1514,13 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
beach:
/* Reset everything */
- GST_LOG ("Resetting to EMPTY");
+ GST_LOG ("Resetting to EMPTY, returning %s", gst_flow_get_name (res));
stream->state = PENDING_PACKET_EMPTY;
memset (stream->pendingbuffers, 0, TS_MAX_PENDING_BUFFERS);
stream->nbpending = 0;
- if (stream->currentlist)
- g_list_free (stream->currentlist);
- stream->currentlist = NULL;
+ stream->current = NULL;
+ stream->expected_size = 0;
+ stream->current_size = 0;
return res;
}
@@ -2422,9 +1561,14 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream,
GST_BUFFER_OFFSET (packet->buffer));
}
- if (packet->payload)
+ if (packet->payload && (res == GST_FLOW_OK || res == GST_FLOW_NOT_LINKED)) {
gst_ts_demux_queue_data (demux, stream, packet);
- else
+ GST_DEBUG ("current_size:%d, expected_size:%d",
+ stream->current_size, stream->expected_size);
+ /* Finally check if the data we queued completes a packet */
+ if (stream->expected_size && stream->current_size == stream->expected_size)
+ res = gst_ts_demux_push_pending_data (demux, stream);
+ } else
gst_buffer_unref (packet->buffer);
return res;
@@ -2435,7 +1579,6 @@ gst_ts_demux_flush (MpegTSBase * base)
{
GstTSDemux *demux = GST_TS_DEMUX_CAST (base);
- demux->need_newsegment = TRUE;
gst_ts_demux_flush_streams (demux);
}
@@ -2471,5 +1614,5 @@ gst_ts_demux_plugin_init (GstPlugin * plugin)
init_pes_parser ();
return gst_element_register (plugin, "tsdemux",
- GST_RANK_SECONDARY, GST_TYPE_TS_DEMUX);
+ GST_RANK_PRIMARY, GST_TYPE_TS_DEMUX);
}
diff --git a/gst/mpegtsdemux/tsdemux.h b/gst/mpegtsdemux/tsdemux.h
index 5eaaa0900..d23e9d2ee 100644
--- a/gst/mpegtsdemux/tsdemux.h
+++ b/gst/mpegtsdemux/tsdemux.h
@@ -48,14 +48,6 @@ G_BEGIN_DECLS
#define GST_TS_DEMUX_CAST(obj) ((GstTSDemux*) obj)
typedef struct _GstTSDemux GstTSDemux;
typedef struct _GstTSDemuxClass GstTSDemuxClass;
-typedef struct _TSPcrOffset TSPcrOffset;
-
-struct _TSPcrOffset
-{
- guint64 gsttime;
- guint64 pcr;
- guint64 offset;
-};
struct _GstTSDemux
{
@@ -69,23 +61,18 @@ struct _GstTSDemux
/*< private >*/
MpegTSBaseProgram *program; /* Current program */
guint current_program_number;
- gboolean need_newsegment;
- /* Downstream segment */
+ /* segments to be sent */
GstSegment segment;
- GstClockTime duration; /* Total duration */
+ GstEvent *segment_event;
- /* pcr wrap and seeking */
- GArray *index;
- gint index_size;
- TSPcrOffset first_pcr;
- TSPcrOffset last_pcr;
- TSPcrOffset cur_pcr;
- TSPcrOffset index_pcr;
+ /* Set when program change */
+ gboolean calculate_update_segment;
+ /* update segment is */
+ GstEvent *update_segment;
- /* LIVE MODE ONLY */
- /* Delta between incoming ts and PTS */
- GstClockTime pts_delta;
+ /* Full stream duration */
+ GstClockTime duration;
};
struct _GstTSDemuxClass
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
index 0be16b3b8..e11a568a4 100644
--- a/gst/mxf/mxfdemux.c
+++ b/gst/mxf/mxfdemux.c
@@ -2385,7 +2385,7 @@ gst_mxf_demux_find_essence_element (GstMXFDemux * demux,
GstFlowReturn ret = GST_FLOW_OK;
guint64 old_offset = demux->offset;
GstMXFDemuxPartition *old_partition = demux->current_partition;
- guint i;
+ gint i;
GST_DEBUG_OBJECT (demux, "Trying to find essence element %" G_GINT64_FORMAT
" of track %u with body_sid %u (keyframe %d)", *position,
diff --git a/gst/mxf/mxfmpeg.c b/gst/mxf/mxfmpeg.c
index f1b74f964..30142486e 100644
--- a/gst/mxf/mxfmpeg.c
+++ b/gst/mxf/mxfmpeg.c
@@ -441,7 +441,7 @@ mxf_mpeg_is_mpeg2_keyframe (GstBuffer * buffer)
guint8 type = 0;
/* Found sync code */
- gst_byte_reader_skip (&reader, 3);
+ gst_byte_reader_skip_unchecked (&reader, 3);
if (!gst_byte_reader_get_uint8 (&reader, &type))
break;
@@ -465,9 +465,8 @@ mxf_mpeg_is_mpeg2_keyframe (GstBuffer * buffer)
return FALSE;
}
}
- } else {
- gst_byte_reader_skip (&reader, 1);
- }
+ } else if (gst_byte_reader_skip (&reader, 1) == FALSE)
+ break;
}
return FALSE;
@@ -484,7 +483,7 @@ mxf_mpeg_is_mpeg4_keyframe (GstBuffer * buffer)
guint8 type = 0;
/* Found sync code */
- gst_byte_reader_skip (&reader, 3);
+ gst_byte_reader_skip_unchecked (&reader, 3);
if (!gst_byte_reader_get_uint8 (&reader, &type))
break;
@@ -502,9 +501,8 @@ mxf_mpeg_is_mpeg4_keyframe (GstBuffer * buffer)
return FALSE;
}
}
- } else {
- gst_byte_reader_skip (&reader, 1);
- }
+ } else if (gst_byte_reader_skip (&reader, 1) == FALSE)
+ break;
}
return FALSE;
@@ -1024,7 +1022,7 @@ mxf_mpeg_is_mpeg2_frame (GstBuffer * buffer)
guint8 type = 0;
/* Found sync code */
- gst_byte_reader_skip (&reader, 3);
+ gst_byte_reader_skip_unchecked (&reader, 3);
if (!gst_byte_reader_get_uint8 (&reader, &type))
break;
@@ -1034,7 +1032,8 @@ mxf_mpeg_is_mpeg2_frame (GstBuffer * buffer)
return TRUE;
}
} else {
- gst_byte_reader_skip (&reader, 1);
+ if (gst_byte_reader_skip (&reader, 1) == FALSE)
+ break;
}
}
@@ -1052,7 +1051,7 @@ mxf_mpeg_is_mpeg4_frame (GstBuffer * buffer)
guint8 type = 0;
/* Found sync code */
- gst_byte_reader_skip (&reader, 3);
+ gst_byte_reader_skip_unchecked (&reader, 3);
if (!gst_byte_reader_get_uint8 (&reader, &type))
break;
@@ -1062,7 +1061,8 @@ mxf_mpeg_is_mpeg4_frame (GstBuffer * buffer)
return TRUE;
}
} else {
- gst_byte_reader_skip (&reader, 1);
+ if (gst_byte_reader_skip (&reader, 1) == FALSE)
+ break;
}
}
diff --git a/gst/removesilence/vad_private.c b/gst/removesilence/vad_private.c
index f187a0614..0b8653103 100644
--- a/gst/removesilence/vad_private.c
+++ b/gst/removesilence/vad_private.c
@@ -74,7 +74,7 @@ vad_new (guint64 hysteresis)
void
vad_reset (VADFilter * vad)
{
- memset (vad, 0, sizeof (vad));
+ memset (vad, 0, sizeof (*vad));
vad->cqueue.base.s = vad->vad_buffer;
vad->cqueue.tail.a = vad->cqueue.head.a = 0;
vad->cqueue.size = VAD_BUFFER_SIZE;
diff --git a/gst/rtpvp8/gstrtpvp8depay.c b/gst/rtpvp8/gstrtpvp8depay.c
index 4c163fa70..48a17ab56 100644
--- a/gst/rtpvp8/gstrtpvp8depay.c
+++ b/gst/rtpvp8/gstrtpvp8depay.c
@@ -153,8 +153,8 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf)
/* Check L optional header */
if ((data[1] & 0x40) != 0)
offset++;
- /* Check T optional header */
- if ((data[1] & 0x20) != 0)
+ /* Check T or K optional headers */
+ if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0)
offset++;
}
diff --git a/gst/rtpvp8/gstrtpvp8pay.c b/gst/rtpvp8/gstrtpvp8pay.c
index 082de2c3e..8907552cc 100644
--- a/gst/rtpvp8/gstrtpvp8pay.c
+++ b/gst/rtpvp8/gstrtpvp8pay.c
@@ -323,7 +323,7 @@ gst_rtp_vp8_create_header_buffer (GstRtpVP8Pay * self, guint8 partid,
if (self->picture_id_mode != VP8_PAY_NO_PICTURE_ID) {
/* Enable X=1 */
p[0] |= 0x80;
- /* X: I=1,L=0,T=0,RSVA=0 */
+ /* X: I=1,L=0,T=0,K=0,RSV=0 */
p[1] = 0x80;
if (self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS) {
/* I: 7 bit picture_id */
diff --git a/gst/siren/Makefile.am b/gst/siren/Makefile.am
index 2be9ede49..c6d1d8cba 100644
--- a/gst/siren/Makefile.am
+++ b/gst/siren/Makefile.am
@@ -10,7 +10,7 @@ libgstsiren_la_SOURCES = gstsiren.c \
libgstsiren_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_CFLAGS)
-libgstsiren_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_MAJORMINOR@ \
+libgstsiren_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
libgstsiren_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstsiren_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/gst/siren/gstsirendec.c b/gst/siren/gstsirendec.c
index 2e517199f..9dd12c359 100644
--- a/gst/siren/gstsirendec.c
+++ b/gst/siren/gstsirendec.c
@@ -69,14 +69,14 @@ enum
ARG_0,
};
-static void gst_siren_dec_finalize (GObject * object);
-
-static GstStateChangeReturn
-gst_siren_change_state (GstElement * element, GstStateChange transition);
-
-static gboolean gst_siren_dec_sink_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_siren_dec_sink_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_siren_dec_chain (GstPad * pad, GstBuffer * buf);
+static gboolean gst_siren_dec_start (GstAudioDecoder * dec);
+static gboolean gst_siren_dec_stop (GstAudioDecoder * dec);
+static gboolean gst_siren_dec_set_format (GstAudioDecoder * dec,
+ GstCaps * caps);
+static gboolean gst_siren_dec_parse (GstAudioDecoder * dec,
+ GstAdapter * adapter, gint * offset, gint * length);
+static GstFlowReturn gst_siren_dec_handle_frame (GstAudioDecoder * dec,
+ GstBuffer * buffer);
static void
_do_init (GType type)
@@ -84,8 +84,8 @@ _do_init (GType type)
GST_DEBUG_CATEGORY_INIT (sirendec_debug, "sirendec", 0, "sirendec");
}
-GST_BOILERPLATE_FULL (GstSirenDec, gst_siren_dec, GstElement,
- GST_TYPE_ELEMENT, _do_init);
+GST_BOILERPLATE_FULL (GstSirenDec, gst_siren_dec, GstAudioDecoder,
+ GST_TYPE_AUDIO_DECODER, _do_init);
static void
gst_siren_dec_base_init (gpointer klass)
@@ -106,17 +106,15 @@ gst_siren_dec_base_init (gpointer klass)
static void
gst_siren_dec_class_init (GstSirenDecClass * klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
+ GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass);
GST_DEBUG ("Initializing Class");
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_siren_dec_finalize);
-
- gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_siren_change_state);
+ base_class->start = GST_DEBUG_FUNCPTR (gst_siren_dec_start);
+ base_class->stop = GST_DEBUG_FUNCPTR (gst_siren_dec_stop);
+ base_class->set_format = GST_DEBUG_FUNCPTR (gst_siren_dec_set_format);
+ base_class->parse = GST_DEBUG_FUNCPTR (gst_siren_dec_parse);
+ base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_siren_dec_handle_frame);
GST_DEBUG ("Class Init done");
}
@@ -124,119 +122,103 @@ gst_siren_dec_class_init (GstSirenDecClass * klass)
static void
gst_siren_dec_init (GstSirenDec * dec, GstSirenDecClass * klass)
{
+}
- GST_DEBUG_OBJECT (dec, "Initializing");
- dec->decoder = Siren7_NewDecoder (16000);;
-
- dec->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
- dec->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+static gboolean
+gst_siren_dec_start (GstAudioDecoder * dec)
+{
+ GstSirenDec *sdec = GST_SIREN_DEC (dec);
- gst_pad_set_setcaps_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (gst_siren_dec_sink_setcaps));
- gst_pad_set_event_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (gst_siren_dec_sink_event));
- gst_pad_set_chain_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (gst_siren_dec_chain));
+ GST_DEBUG_OBJECT (dec, "start");
- gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
- gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+ sdec->decoder = Siren7_NewDecoder (16000);;
- dec->adapter = gst_adapter_new ();
+ /* no flushing please */
+ gst_audio_decoder_set_drainable (dec, FALSE);
- GST_DEBUG_OBJECT (dec, "Init done");
+ return TRUE;
}
-static void
-gst_siren_dec_finalize (GObject * object)
+static gboolean
+gst_siren_dec_stop (GstAudioDecoder * dec)
{
- GstSirenDec *dec = GST_SIREN_DEC (object);
+ GstSirenDec *sdec = GST_SIREN_DEC (dec);
- GST_DEBUG_OBJECT (dec, "Finalize");
+ GST_DEBUG_OBJECT (dec, "stop");
- Siren7_CloseDecoder (dec->decoder);
- g_object_unref (dec->adapter);
+ Siren7_CloseDecoder (sdec->decoder);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ return TRUE;
}
static gboolean
-gst_siren_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
+gst_siren_dec_negotiate (GstSirenDec * dec)
{
- GstSirenDec *dec;
gboolean res;
GstCaps *outcaps;
- dec = GST_SIREN_DEC (GST_PAD_PARENT (pad));
-
outcaps = gst_static_pad_template_get_caps (&srctemplate);
- res = gst_pad_set_caps (dec->srcpad, outcaps);
+ res = gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), outcaps);
gst_caps_unref (outcaps);
return res;
}
static gboolean
-gst_siren_dec_sink_event (GstPad * pad, GstEvent * event)
+gst_siren_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
{
GstSirenDec *dec;
- gboolean res;
- dec = GST_SIREN_DEC (GST_PAD_PARENT (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- gst_adapter_clear (dec->adapter);
- res = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- gst_adapter_clear (dec->adapter);
- res = gst_pad_push_event (dec->srcpad, event);
- break;
- default:
- res = gst_pad_push_event (dec->srcpad, event);
- break;
+ dec = GST_SIREN_DEC (bdec);
+
+ return gst_siren_dec_negotiate (dec);
+}
+
+static GstFlowReturn
+gst_siren_dec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
+ gint * offset, gint * length)
+{
+ gint size;
+ GstFlowReturn ret;
+
+ size = gst_adapter_available (adapter);
+ g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
+
+ /* accept any multiple of frames */
+ if (size > 40) {
+ ret = GST_FLOW_OK;
+ *offset = 0;
+ *length = size - (size % 40);
+ } else {
+ ret = GST_FLOW_UNEXPECTED;
}
- return res;
+
+ return ret;
}
static GstFlowReturn
-gst_siren_dec_chain (GstPad * pad, GstBuffer * buf)
+gst_siren_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
{
GstSirenDec *dec;
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *out_buf;
guint8 *in_data, *out_data;
- guint8 *to_free = NULL;
guint i, size, num_frames;
gint out_size, in_size;
gint decode_ret;
- gboolean discont;
- GstClockTime timestamp;
- guint64 distance;
- GstCaps *outcaps;
-
- dec = GST_SIREN_DEC (GST_PAD_PARENT (pad));
- discont = GST_BUFFER_IS_DISCONT (buf);
- if (discont) {
- GST_DEBUG_OBJECT (dec, "received DISCONT, flush adapter");
- gst_adapter_clear (dec->adapter);
- dec->discont = TRUE;
- }
+ dec = GST_SIREN_DEC (bdec);
- gst_adapter_push (dec->adapter, buf);
+ size = GST_BUFFER_SIZE (buf);
- size = gst_adapter_available (dec->adapter);
+ GST_LOG_OBJECT (dec, "Received buffer of size %u", size);
- GST_LOG_OBJECT (dec, "Received buffer of size %u with adapter of size : %u",
- GST_BUFFER_SIZE (buf), size);
+ g_return_val_if_fail (size % 40 == 0, GST_FLOW_ERROR);
+ g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
/* process 40 input bytes into 640 output bytes */
num_frames = size / 40;
- if (num_frames == 0)
- goto done;
-
/* this is the input/output size */
in_size = num_frames * 40;
out_size = num_frames * 640;
@@ -244,32 +226,19 @@ gst_siren_dec_chain (GstPad * pad, GstBuffer * buf)
GST_LOG_OBJECT (dec, "we have %u frames, %u in, %u out", num_frames, in_size,
out_size);
- /* set output caps when needed */
- if ((outcaps = GST_PAD_CAPS (dec->srcpad)) == NULL) {
- outcaps = gst_static_pad_template_get_caps (&srctemplate);
- gst_pad_set_caps (dec->srcpad, outcaps);
- gst_caps_unref (outcaps);
+ /* allow and handle un-negotiated input */
+ if (G_UNLIKELY (GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)) == NULL)) {
+ gst_siren_dec_negotiate (dec);
}
/* get a buffer */
- ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, -1,
- out_size, outcaps, &out_buf);
+ ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), -1,
+ out_size, GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &out_buf);
if (ret != GST_FLOW_OK)
goto alloc_failed;
- /* get the timestamp for the output buffer */
- timestamp = gst_adapter_prev_timestamp (dec->adapter, &distance);
-
- /* add the amount of time taken by the distance, each frame is 20ms */
- if (timestamp != -1)
- timestamp += (distance / 40) * FRAME_DURATION;
-
- GST_LOG_OBJECT (dec,
- "timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT,
- GST_TIME_ARGS (timestamp), distance);
-
/* get the input data for all the frames */
- to_free = in_data = gst_adapter_take (dec->adapter, in_size);
+ in_data = GST_BUFFER_DATA (buf);
out_data = GST_BUFFER_DATA (out_buf);
for (i = 0; i < num_frames; i++) {
@@ -287,21 +256,11 @@ gst_siren_dec_chain (GstPad * pad, GstBuffer * buf)
GST_LOG_OBJECT (dec, "Finished decoding");
- /* mark discont */
- if (dec->discont) {
- GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT);
- dec->discont = FALSE;
- }
-
- GST_BUFFER_TIMESTAMP (out_buf) = timestamp;
- GST_BUFFER_DURATION (out_buf) = num_frames * FRAME_DURATION;
-
- ret = gst_pad_push (dec->srcpad, out_buf);
+ /* might really be multiple frames,
+ * but was treated as one for all purposes here */
+ ret = gst_audio_decoder_finish_frame (bdec, out_buf, 1);
done:
- if (to_free)
- g_free (to_free);
-
return ret;
/* ERRORS */
@@ -313,41 +272,15 @@ alloc_failed:
}
decode_error:
{
- GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
- ("Error decoding frame: %d", decode_ret));
- ret = GST_FLOW_ERROR;
+ GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL),
+ ("Error decoding frame: %d", decode_ret), ret);
+ if (ret == GST_FLOW_OK)
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
gst_buffer_unref (out_buf);
goto done;
}
}
-static GstStateChangeReturn
-gst_siren_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstSirenDec *dec = GST_SIREN_DEC (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- dec->discont = FALSE;
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_adapter_clear (dec->adapter);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
gboolean
gst_siren_dec_plugin_init (GstPlugin * plugin)
{
diff --git a/gst/siren/gstsirendec.h b/gst/siren/gstsirendec.h
index 7c020896f..4c42c4de7 100644
--- a/gst/siren/gstsirendec.h
+++ b/gst/siren/gstsirendec.h
@@ -24,7 +24,7 @@
#define __GST_SIREN_DEC_H__
#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
+#include <gst/audio/gstaudiodecoder.h>
#include "siren7.h"
@@ -48,21 +48,15 @@ typedef struct _GstSirenDecPrivate GstSirenDecPrivate;
struct _GstSirenDec
{
- GstElement parent;
+ GstAudioDecoder parent;
/* Protected by stream lock */
SirenDecoder decoder;
-
- GstAdapter *adapter;
- gboolean discont;
-
- GstPad *sinkpad;
- GstPad *srcpad;
};
struct _GstSirenDecClass
{
- GstElementClass parent_class;
+ GstAudioDecoderClass parent_class;
};
GType gst_siren_dec_get_type (void);
diff --git a/gst/siren/gstsirenenc.c b/gst/siren/gstsirenenc.c
index a78cdb8bc..6bcf20568 100644
--- a/gst/siren/gstsirenenc.c
+++ b/gst/siren/gstsirenenc.c
@@ -69,17 +69,12 @@ enum
ARG_0,
};
-
-
-static void gst_siren_enc_finalize (GObject * object);
-
-static gboolean gst_siren_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_siren_enc_sink_event (GstPad * pad, GstEvent * event);
-
-static GstFlowReturn gst_siren_enc_chain (GstPad * pad, GstBuffer * buf);
-static GstStateChangeReturn
-gst_siren_change_state (GstElement * element, GstStateChange transition);
-
+static gboolean gst_siren_enc_start (GstAudioEncoder * enc);
+static gboolean gst_siren_enc_stop (GstAudioEncoder * enc);
+static gboolean gst_siren_enc_set_format (GstAudioEncoder * enc,
+ GstAudioInfo * info);
+static GstFlowReturn gst_siren_enc_handle_frame (GstAudioEncoder * enc,
+ GstBuffer * in_buf);
static void
_do_init (GType type)
@@ -87,8 +82,8 @@ _do_init (GType type)
GST_DEBUG_CATEGORY_INIT (sirenenc_debug, "sirenenc", 0, "sirenenc");
}
-GST_BOILERPLATE_FULL (GstSirenEnc, gst_siren_enc, GstElement,
- GST_TYPE_ELEMENT, _do_init);
+GST_BOILERPLATE_FULL (GstSirenEnc, gst_siren_enc, GstAudioEncoder,
+ GST_TYPE_AUDIO_ENCODER, _do_init);
static void
gst_siren_enc_base_init (gpointer klass)
@@ -109,17 +104,14 @@ gst_siren_enc_base_init (gpointer klass)
static void
gst_siren_enc_class_init (GstSirenEncClass * klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
+ GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass);
GST_DEBUG ("Initializing Class");
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_siren_enc_finalize);
-
- gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_siren_change_state);
+ base_class->start = GST_DEBUG_FUNCPTR (gst_siren_enc_start);
+ base_class->stop = GST_DEBUG_FUNCPTR (gst_siren_enc_stop);
+ base_class->set_format = GST_DEBUG_FUNCPTR (gst_siren_enc_set_format);
+ base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_siren_enc_handle_frame);
GST_DEBUG ("Class Init done");
}
@@ -127,120 +119,81 @@ gst_siren_enc_class_init (GstSirenEncClass * klass)
static void
gst_siren_enc_init (GstSirenEnc * enc, GstSirenEncClass * klass)
{
+}
- GST_DEBUG_OBJECT (enc, "Initializing");
- enc->encoder = Siren7_NewEncoder (16000);
- enc->adapter = gst_adapter_new ();
-
- enc->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
- enc->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+static gboolean
+gst_siren_enc_start (GstAudioEncoder * enc)
+{
+ GstSirenEnc *senc = GST_SIREN_ENC (enc);
- gst_pad_set_setcaps_function (enc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_siren_enc_sink_setcaps));
- gst_pad_set_event_function (enc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_siren_enc_sink_event));
- gst_pad_set_chain_function (enc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_siren_enc_chain));
+ GST_DEBUG_OBJECT (enc, "start");
- gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
- gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
+ senc->encoder = Siren7_NewEncoder (16000);
- GST_DEBUG_OBJECT (enc, "Init done");
+ return TRUE;
}
-static void
-gst_siren_enc_finalize (GObject * object)
+static gboolean
+gst_siren_enc_stop (GstAudioEncoder * enc)
{
- GstSirenEnc *enc = GST_SIREN_ENC (object);
+ GstSirenEnc *senc = GST_SIREN_ENC (enc);
- GST_DEBUG_OBJECT (object, "Disposing");
+ GST_DEBUG_OBJECT (senc, "stop");
- Siren7_CloseEncoder (enc->encoder);
- g_object_unref (enc->adapter);
+ Siren7_CloseEncoder (senc->encoder);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ return TRUE;
}
static gboolean
-gst_siren_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
+gst_siren_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
{
GstSirenEnc *enc;
gboolean res;
GstCaps *outcaps;
- enc = GST_SIREN_ENC (GST_PAD_PARENT (pad));
+ enc = GST_SIREN_ENC (benc);
outcaps = gst_static_pad_template_get_caps (&srctemplate);
- res = gst_pad_set_caps (enc->srcpad, outcaps);
+ res = gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), outcaps);
gst_caps_unref (outcaps);
- return res;
-}
-
-static gboolean
-gst_siren_enc_sink_event (GstPad * pad, GstEvent * event)
-{
- GstSirenEnc *enc;
- gboolean res;
+ /* report needs to base class */
+ gst_audio_encoder_set_frame_samples_min (benc, 320);
+ gst_audio_encoder_set_frame_samples_max (benc, 320);
+ /* no remainder or flushing please */
+ gst_audio_encoder_set_hard_min (benc, TRUE);
+ gst_audio_encoder_set_drainable (benc, FALSE);
- enc = GST_SIREN_ENC (GST_PAD_PARENT (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- gst_adapter_clear (enc->adapter);
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- gst_adapter_clear (enc->adapter);
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- default:
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- }
return res;
}
static GstFlowReturn
-gst_siren_enc_chain (GstPad * pad, GstBuffer * buf)
+gst_siren_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
{
GstSirenEnc *enc;
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *out_buf;
guint8 *in_data, *out_data;
- guint8 *to_free = NULL;
guint i, size, num_frames;
gint out_size, in_size;
gint encode_ret;
- gboolean discont;
- GstClockTime timestamp;
- guint64 distance;
- GstCaps *outcaps;
- enc = GST_SIREN_ENC (GST_PAD_PARENT (pad));
+ g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
- discont = GST_BUFFER_IS_DISCONT (buf);
- if (discont) {
- GST_DEBUG_OBJECT (enc, "received DISCONT, flush adapter");
- gst_adapter_clear (enc->adapter);
- enc->discont = TRUE;
- }
+ enc = GST_SIREN_ENC (benc);
- gst_adapter_push (enc->adapter, buf);
+ size = GST_BUFFER_SIZE (buf);
- size = gst_adapter_available (enc->adapter);
+ GST_LOG_OBJECT (enc, "Received buffer of size %d", GST_BUFFER_SIZE (buf));
- GST_LOG_OBJECT (enc, "Received buffer of size %d with adapter of size : %d",
- GST_BUFFER_SIZE (buf), size);
+ g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
+ g_return_val_if_fail (size % 640 == 0, GST_FLOW_ERROR);
/* we need to process 640 input bytes to produce 40 output bytes */
/* calculate the amount of frames we will handle */
num_frames = size / 640;
- /* no frames, wait some more */
- if (num_frames == 0)
- goto done;
-
/* this is the input/output size */
in_size = num_frames * 640;
out_size = num_frames * 40;
@@ -248,32 +201,14 @@ gst_siren_enc_chain (GstPad * pad, GstBuffer * buf)
GST_LOG_OBJECT (enc, "we have %u frames, %u in, %u out", num_frames, in_size,
out_size);
- /* set output caps when needed */
- if ((outcaps = GST_PAD_CAPS (enc->srcpad)) == NULL) {
- outcaps = gst_static_pad_template_get_caps (&srctemplate);
- gst_pad_set_caps (enc->srcpad, outcaps);
- gst_caps_unref (outcaps);
- }
-
/* get a buffer */
- ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad, -1,
- out_size, outcaps, &out_buf);
+ ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (benc),
+ -1, out_size, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (benc)), &out_buf);
if (ret != GST_FLOW_OK)
goto alloc_failed;
- /* get the timestamp for the output buffer */
- timestamp = gst_adapter_prev_timestamp (enc->adapter, &distance);
-
- /* add the amount of time taken by the distance */
- if (timestamp != -1)
- timestamp += gst_util_uint64_scale_int (distance / 2, GST_SECOND, 16000);
-
- GST_LOG_OBJECT (enc,
- "timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT,
- GST_TIME_ARGS (timestamp), distance);
-
/* get the input data for all the frames */
- to_free = in_data = gst_adapter_take (enc->adapter, in_size);
+ in_data = GST_BUFFER_DATA (buf);
out_data = GST_BUFFER_DATA (out_buf);
for (i = 0; i < num_frames; i++) {
@@ -291,20 +226,10 @@ gst_siren_enc_chain (GstPad * pad, GstBuffer * buf)
GST_LOG_OBJECT (enc, "Finished encoding");
- /* mark discont */
- if (enc->discont) {
- GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT);
- enc->discont = FALSE;
- }
- GST_BUFFER_TIMESTAMP (out_buf) = timestamp;
- GST_BUFFER_DURATION (out_buf) = num_frames * FRAME_DURATION;
-
- ret = gst_pad_push (enc->srcpad, out_buf);
+ /* we encode all we get, pass it along */
+ ret = gst_audio_encoder_finish_frame (benc, out_buf, -1);
done:
- if (to_free)
- g_free (to_free);
-
return ret;
/* ERRORS */
@@ -324,33 +249,6 @@ encode_error:
}
}
-static GstStateChangeReturn
-gst_siren_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstSirenEnc *enc = GST_SIREN_ENC (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- enc->discont = FALSE;
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_adapter_clear (enc->adapter);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
gboolean
gst_siren_enc_plugin_init (GstPlugin * plugin)
{
diff --git a/gst/siren/gstsirenenc.h b/gst/siren/gstsirenenc.h
index 1d63628dc..3477db1a7 100644
--- a/gst/siren/gstsirenenc.h
+++ b/gst/siren/gstsirenenc.h
@@ -24,7 +24,7 @@
#define __GST_SIREN_ENC_H__
#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
+#include <gst/audio/gstaudioencoder.h>
#include "siren7.h"
@@ -48,21 +48,15 @@ typedef struct _GstSirenEncPrivate GstSirenEncPrivate;
struct _GstSirenEnc
{
- GstElement parent;
+ GstAudioEncoder parent;
/* protected by the stream lock */
SirenEncoder encoder;
- GstAdapter *adapter;
-
- gboolean discont;
-
- GstPad *srcpad;
- GstPad *sinkpad;
};
struct _GstSirenEncClass
{
- GstElementClass parent_class;
+ GstAudioEncoderClass parent_class;
};
GType gst_siren_enc_get_type (void);
diff --git a/gst/videoparsers/gsth263parse.c b/gst/videoparsers/gsth263parse.c
index a3c5ea4f4..9ff1af66c 100644
--- a/gst/videoparsers/gsth263parse.c
+++ b/gst/videoparsers/gsth263parse.c
@@ -158,7 +158,8 @@ find_psc (GstBuffer * buffer, guint skip)
if (!gst_byte_reader_set_pos (&br, skip))
goto out;
- gst_byte_reader_peek_uint24_be (&br, &psc);
+ if (gst_byte_reader_peek_uint24_be (&br, &psc) == FALSE)
+ goto out;
/* Scan for the picture start code (22 bits - 0x0020) */
while ((gst_byte_reader_get_remaining (&br) >= 3)) {
@@ -166,8 +167,8 @@ find_psc (GstBuffer * buffer, guint skip)
((psc & 0xffffc0) == 0x000080)) {
psc_pos = gst_byte_reader_get_pos (&br);
break;
- } else
- gst_byte_reader_skip (&br, 1);
+ } else if (gst_byte_reader_skip (&br, 1) == FALSE)
+ break;
}
out:
diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c
index 420394f69..4e1f5b000 100644
--- a/gst/videoparsers/gsth264parse.c
+++ b/gst/videoparsers/gsth264parse.c
@@ -920,6 +920,7 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
gboolean found = FALSE;
GstMapInfo map;
guint8 *data;
+ gint nl;
/* only nal payload in stored nals */
@@ -956,12 +957,13 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
buf = gst_buffer_new_allocate (NULL, 5 + 1 + sps_size + 1 + pps_size, NULL);
gst_buffer_map (buf, &map, GST_MAP_WRITE);
data = map.data;
+ nl = h264parse->nal_length_size;
data[0] = 1; /* AVC Decoder Configuration Record ver. 1 */
data[1] = profile_idc; /* profile_idc */
data[2] = profile_comp; /* profile_compability */
data[3] = level_idc; /* level_idc */
- data[4] = 0xfc | (4 - 1); /* nal_length_size_minus1 */
+ data[4] = 0xfc | (nl - 1); /* nal_length_size_minus1 */
data[5] = 0xe0 | num_sps; /* number of SPSs */
data += 6;
@@ -1578,14 +1580,16 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_byte_writer_init_with_size (&bw, gst_buffer_get_size (buffer),
FALSE);
- gst_byte_writer_put_buffer (&bw, buffer, 0, h264parse->idr_pos);
+ gst_byte_writer_put_buffer_unchecked (&bw, buffer, 0,
+ h264parse->idr_pos);
GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
if ((codec_nal = h264parse->sps_nals[i])) {
gsize nal_size = gst_buffer_get_size (codec_nal);
GST_DEBUG_OBJECT (h264parse, "inserting SPS nal");
- gst_byte_writer_put_uint32_be (&bw, bs ? 1 : nal_size);
- gst_byte_writer_put_buffer (&bw, codec_nal, 0, nal_size);
+ gst_byte_writer_put_uint32_be_unchecked (&bw, bs ? 1 : nal_size);
+ gst_byte_writer_put_buffer_unchecked (&bw, codec_nal, 0,
+ nal_size);
h264parse->last_report = new_ts;
}
}
@@ -1593,12 +1597,14 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
if ((codec_nal = h264parse->pps_nals[i])) {
gsize nal_size = gst_buffer_get_size (codec_nal);
GST_DEBUG_OBJECT (h264parse, "inserting PPS nal");
- gst_byte_writer_put_uint32_be (&bw, bs ? 1 : nal_size);
- gst_byte_writer_put_buffer (&bw, codec_nal, 0, nal_size);
+ gst_byte_writer_put_uint32_be_unchecked (&bw, bs ? 1 : nal_size);
+ gst_byte_writer_put_buffer_unchecked (&bw, codec_nal, 0,
+ nal_size);
h264parse->last_report = new_ts;
}
}
- gst_byte_writer_put_buffer (&bw, buffer, h264parse->idr_pos, -1);
+ gst_byte_writer_put_buffer_unchecked (&bw, buffer, h264parse->idr_pos,
+ -1);
/* collect result and push */
new_buf = gst_byte_writer_reset_and_get_buffer (&bw);
gst_buffer_copy_into (new_buf, buffer, GST_BUFFER_COPY_METADATA, 0,
diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c
index f0726b960..fd72aa678 100644
--- a/gst/videoparsers/gstmpegvideoparse.c
+++ b/gst/videoparsers/gstmpegvideoparse.c
@@ -655,7 +655,7 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
profile = profiles[profile_c - 1];
if ((level_c > 3) && (level_c < 11) && (level_c % 2 == 0))
- level = levels[(level_c >> 1) - 1];
+ level = levels[(level_c >> 1) - 2];
if (profile_c == 8) {
/* Non-hierarchical profile */
@@ -683,6 +683,8 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
/* FIXME does it make sense to expose profile/level in the caps ? */
+ GST_DEBUG_OBJECT (mpvparse, "profile:'%s' level:'%s'", profile, level);
+
if (profile)
gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
else