summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2004-12-29 11:04:28 +0000
committerWim Taymans <wim.taymans@gmail.com>2004-12-29 11:04:28 +0000
commita52078924d1a3e30f2e27390323704cb59ecace8 (patch)
treef4bcfb28139683ea34e1cf0273df57fa88af5df3
parentb55e609daa1d06a35950bbce78de8ebe73ec17d3 (diff)
downloadgstreamer-plugins-base-a52078924d1a3e30f2e27390323704cb59ecace8.tar.gz
Various plugin updates.
Original commit message from CVS: Various plugin updates.
-rw-r--r--ChangeLog70
-rw-r--r--examples/seeking/seek.c124
-rw-r--r--ext/ogg/README105
-rw-r--r--ext/ogg/gstoggdemux.c2164
-rw-r--r--ext/ogg/gstoggmux.c40
-rw-r--r--ext/ogg/gstogmparse.c26
-rw-r--r--ext/theora/theoradec.c65
-rw-r--r--ext/theora/theoraenc.c74
-rw-r--r--ext/vorbis/Makefile.am4
-rw-r--r--ext/vorbis/vorbis.c5
-rw-r--r--ext/vorbis/vorbisdec.c126
-rw-r--r--ext/vorbis/vorbisenc.c106
-rw-r--r--ext/vorbis/vorbisparse.c19
-rw-r--r--gst/audioconvert/bufferframesconvert.c41
-rw-r--r--gst/audioconvert/gstaudioconvert.c250
-rw-r--r--gst/audioconvert/gstchannelmix.h3
-rw-r--r--gst/ffmpegcolorspace/gstffmpegcolorspace.c22
-rw-r--r--tests/examples/seek/seek.c124
18 files changed, 1496 insertions, 1872 deletions
diff --git a/ChangeLog b/ChangeLog
index 325b6e9d7..6affd5e7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,73 @@
+2004-12-29 Wim Taymans <wim@fluendo.com>
+
+ * examples/seeking/seek.c: (dynamic_link), (make_vorbis_pipeline),
+ (make_mp3_pipeline), (make_avi_pipeline), (make_mpeg_pipeline),
+ (make_mpegnt_pipeline), (update_scale), (stop_seek), (play_cb),
+ (pause_cb), (stop_cb), (main):
+ * ext/mad/gstmad.c: (gst_mad_init), (gst_mad_convert_sink),
+ (gst_mad_convert_src), (gst_mad_src_query), (gst_mad_src_event),
+ (gst_mad_update_info), (gst_mad_sink_event),
+ (gst_mad_check_caps_reset), (gst_mad_chain):
+ * ext/ogg/README:
+ * ext/ogg/gstoggdemux.c: (gst_ogg_pad_get_type),
+ (gst_ogg_pad_init), (gst_ogg_pad_formats),
+ (gst_ogg_pad_event_masks), (gst_ogg_pad_query_types),
+ (gst_ogg_pad_src_convert), (gst_ogg_pad_src_query),
+ (gst_ogg_pad_reset), (gst_ogg_pad_submit_packet),
+ (gst_ogg_pad_submit_page), (gst_ogg_chain_new),
+ (gst_ogg_chain_free), (gst_ogg_chain_new_stream),
+ (gst_ogg_chain_get_stream), (gst_ogg_chain_has_stream),
+ (gst_ogg_demux_base_init), (gst_ogg_demux_init),
+ (gst_ogg_demux_finalize), (gst_ogg_demux_handle_event),
+ (gst_ogg_demux_submit_buffer), (gst_ogg_demux_seek),
+ (gst_ogg_demux_get_data), (gst_ogg_demux_get_next_page),
+ (gst_ogg_demux_get_prev_page),
+ (gst_ogg_demux_bisect_forward_serialno),
+ (gst_ogg_demux_read_chain), (gst_ogg_demux_find_pad),
+ (gst_ogg_demux_find_chains), (gst_ogg_demux_chain),
+ (gst_ogg_demux_loop), (gst_ogg_demux_sink_activate),
+ (gst_ogg_demux_change_state), (gst_ogg_print):
+ * ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init),
+ (gst_ogg_mux_init), (gst_ogg_mux_sinkconnect),
+ (gst_ogg_mux_next_buffer), (gst_ogg_mux_buffer_from_page),
+ (gst_ogg_mux_push_page), (gst_ogg_mux_send_headers),
+ (gst_ogg_mux_loop):
+ * ext/ogg/gstogmparse.c: (gst_ogm_parse_chain):
+ * ext/theora/theoradec.c: (gst_theora_dec_init),
+ (theora_dec_sink_event), (theora_dec_chain):
+ * ext/theora/theoraenc.c: (gst_theora_enc_init),
+ (theora_enc_sink_setcaps), (theora_buffer_from_packet),
+ (theora_push_buffer), (theora_enc_sink_event), (theora_enc_chain):
+ * ext/vorbis/Makefile.am:
+ * ext/vorbis/vorbis.c: (plugin_init):
+ * ext/vorbis/vorbisdec.c: (gst_vorbis_dec_init),
+ (vorbis_dec_sink_event), (vorbis_dec_chain):
+ * ext/vorbis/vorbisenc.c: (gst_vorbisenc_class_init),
+ (gst_vorbisenc_sink_setcaps), (gst_vorbisenc_init),
+ (gst_vorbisenc_push_buffer), (gst_vorbisenc_sink_event),
+ (gst_vorbisenc_chain):
+ * ext/vorbis/vorbisparse.c: (vorbis_parse_chain):
+ * gst/audioconvert/bufferframesconvert.c:
+ (buffer_frames_convert_init), (buffer_frames_convert_setcaps),
+ (buffer_frames_convert_chain):
+ * gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_init),
+ (gst_audio_convert_chain),
+ (gst_audio_convert_caps_remove_format_info),
+ (gst_audio_convert_getcaps), (gst_audio_convert_parse_caps),
+ (gst_audio_convert_setcaps), (_fixate_caps_to_int),
+ (gst_audio_convert_fixate), (gst_audio_convert_get_buffer),
+ (gst_audio_convert_buffer_to_default_format),
+ (gst_audio_convert_buffer_from_default_format),
+ (gst_audio_convert_channels):
+ * gst/audioconvert/gstchannelmix.h:
+ * gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+ (gst_ffmpegcsp_caps_remove_format_info), (gst_ffmpegcsp_getcaps),
+ (gst_ffmpegcsp_configure_context), (gst_ffmpegcsp_setcaps),
+ (gst_ffmpegcsp_chain):
+ * sys/oss/gstosssink.c: (gst_osssink_setcaps),
+ (gst_osssink_handle_event), (gst_osssink_chain):
+ Various plugin updates.
+
2004-12-20 Wim Taymans <wim@fluendo.com>
* configure.ac:
diff --git a/examples/seeking/seek.c b/examples/seeking/seek.c
index c85ca8b02..ec1ccc9a2 100644
--- a/examples/seeking/seek.c
+++ b/examples/seeking/seek.c
@@ -51,11 +51,11 @@ dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
{
dyn_link *connect = (dyn_link *) data;
- if (!strcmp (gst_pad_get_name (newpad), connect->padname)) {
- gst_element_set_state (pipeline, GST_STATE_PAUSED);
- gst_bin_add (GST_BIN (pipeline), connect->bin);
+ if (connect->padname == NULL ||
+ !strcmp (gst_pad_get_name (newpad), connect->padname)) {
+ if (connect->bin)
+ gst_bin_add (GST_BIN (pipeline), connect->bin);
gst_pad_link (newpad, connect->target);
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
seekable_pads = g_list_prepend (seekable_pads, newpad);
rate_pads = g_list_prepend (rate_pads, newpad);
@@ -273,25 +273,35 @@ make_parse_pipeline (const gchar * location)
static GstElement *
make_vorbis_pipeline (const gchar * location)
{
- GstElement *pipeline;
- GstElement *src, *decoder, *audiosink;
+ GstElement *pipeline, *audio_bin;
+ GstElement *src, *demux, *decoder, *convert, *audiosink;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
src = gst_element_factory_make_or_warn (SOURCE, "src");
- decoder = gst_element_factory_make_or_warn ("vorbisfile", "decoder");
+ demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
+ decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
+ convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
g_object_set (G_OBJECT (src), "location", location, NULL);
+ audio_bin = gst_bin_new ("a_decoder_bin");
+
gst_bin_add (GST_BIN (pipeline), src);
- gst_bin_add (GST_BIN (pipeline), decoder);
- gst_bin_add (GST_BIN (pipeline), audiosink);
+ gst_bin_add (GST_BIN (pipeline), demux);
+ gst_bin_add (GST_BIN (audio_bin), decoder);
+ gst_bin_add (GST_BIN (audio_bin), convert);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
+ gst_bin_add (GST_BIN (pipeline), audio_bin);
- gst_element_link (src, decoder);
- gst_element_link (decoder, audiosink);
+ gst_element_link (src, demux);
+ gst_element_link (decoder, convert);
+ gst_element_link (convert, audiosink);
+
+ setup_dynamic_link (demux, NULL, gst_element_get_pad (decoder, "sink"), NULL);
seekable = gst_element_get_pad (decoder, "src");
seekable_pads = g_list_prepend (seekable_pads, seekable);
@@ -305,7 +315,7 @@ static GstElement *
make_mp3_pipeline (const gchar * location)
{
GstElement *pipeline;
- GstElement *src, *decoder, *osssink, *queue, *audio_thread;
+ GstElement *src, *decoder, *osssink, *queue;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -315,8 +325,6 @@ make_mp3_pipeline (const gchar * location)
queue = gst_element_factory_make_or_warn ("queue", "queue");
osssink = gst_element_factory_make_or_warn ("osssink", "sink");
- audio_thread = gst_thread_new ("a_decoder_thread");
-
seekable_elements = g_list_prepend (seekable_elements, osssink);
g_object_set (G_OBJECT (src), "location", location, NULL);
@@ -324,9 +332,8 @@ make_mp3_pipeline (const gchar * location)
gst_bin_add (GST_BIN (pipeline), src);
gst_bin_add (GST_BIN (pipeline), decoder);
- gst_bin_add (GST_BIN (audio_thread), queue);
- gst_bin_add (GST_BIN (audio_thread), osssink);
- gst_bin_add (GST_BIN (pipeline), audio_thread);
+ gst_bin_add (GST_BIN (pipeline), queue);
+ gst_bin_add (GST_BIN (pipeline), osssink);
gst_element_link (src, decoder);
gst_element_link (decoder, queue);
@@ -345,8 +352,7 @@ make_avi_pipeline (const gchar * location)
{
GstElement *pipeline, *audio_bin, *video_bin;
GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
- GstElement *a_queue = NULL, *audio_thread = NULL, *v_queue =
- NULL, *video_thread = NULL;
+ GstElement *a_queue = NULL, *v_queue = NULL;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -363,16 +369,14 @@ make_avi_pipeline (const gchar * location)
audio_bin = gst_bin_new ("a_decoder_bin");
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
- audio_thread = gst_thread_new ("a_decoder_thread");
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
gst_element_link (a_decoder, a_queue);
gst_element_link (a_queue, audiosink);
gst_bin_add (GST_BIN (audio_bin), a_decoder);
- gst_bin_add (GST_BIN (audio_bin), audio_thread);
- gst_bin_add (GST_BIN (audio_thread), a_queue);
- gst_bin_add (GST_BIN (audio_thread), audiosink);
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
gst_element_set_state (audio_bin, GST_STATE_PAUSED);
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
@@ -388,7 +392,6 @@ make_avi_pipeline (const gchar * location)
//v_decoder = gst_element_factory_make_or_warn ("identity", "v_dec");
//v_decoder = gst_element_factory_make_or_warn ("windec", "v_dec");
v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
- video_thread = gst_thread_new ("v_decoder_thread");
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
//videosink = gst_element_factory_make_or_warn ("fakesink", "v_sink");
//g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
@@ -397,9 +400,8 @@ make_avi_pipeline (const gchar * location)
gst_element_link (v_decoder, v_queue);
gst_element_link (v_queue, videosink);
gst_bin_add (GST_BIN (video_bin), v_decoder);
- gst_bin_add (GST_BIN (video_bin), video_thread);
- gst_bin_add (GST_BIN (video_thread), v_queue);
- gst_bin_add (GST_BIN (video_thread), videosink);
+ gst_bin_add (GST_BIN (video_bin), v_queue);
+ gst_bin_add (GST_BIN (video_bin), videosink);
gst_element_set_state (video_bin, GST_STATE_PAUSED);
@@ -421,7 +423,7 @@ make_mpeg_pipeline (const gchar * location)
GstElement *pipeline, *audio_bin, *video_bin;
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
GstElement *audiosink, *videosink;
- GstElement *a_queue, *audio_thread, *v_queue, *video_thread;
+ GstElement *a_queue, *v_queue;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -440,16 +442,14 @@ make_mpeg_pipeline (const gchar * location)
audio_bin = gst_bin_new ("a_decoder_bin");
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
- audio_thread = gst_thread_new ("a_decoder_thread");
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
gst_element_link (a_decoder, a_queue);
gst_element_link (a_queue, audiosink);
gst_bin_add (GST_BIN (audio_bin), a_decoder);
- gst_bin_add (GST_BIN (audio_bin), audio_thread);
- gst_bin_add (GST_BIN (audio_thread), a_queue);
- gst_bin_add (GST_BIN (audio_thread), audiosink);
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
"sink"), audio_bin);
@@ -462,7 +462,6 @@ make_mpeg_pipeline (const gchar * location)
video_bin = gst_bin_new ("v_decoder_bin");
v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
- video_thread = gst_thread_new ("v_decoder_thread");
//g_object_set (G_OBJECT (video_thread), "priority", 2, NULL);
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
@@ -470,8 +469,8 @@ make_mpeg_pipeline (const gchar * location)
gst_element_link_many (v_decoder, v_queue, v_filter, NULL);
gst_element_link (v_filter, videosink);
- gst_bin_add_many (GST_BIN (video_bin), v_decoder, video_thread, NULL);
- gst_bin_add_many (GST_BIN (video_thread), v_queue, v_filter, videosink, NULL);
+ gst_bin_add_many (GST_BIN (video_bin), v_decoder, NULL);
+ gst_bin_add_many (GST_BIN (video_bin), v_queue, v_filter, videosink, NULL);
setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
"sink"), video_bin);
@@ -491,7 +490,7 @@ make_mpegnt_pipeline (const gchar * location)
GstElement *pipeline, *audio_bin, *video_bin;
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
GstElement *audiosink, *videosink;
- GstElement *a_queue, *audio_thread;
+ GstElement *a_queue;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -510,7 +509,6 @@ make_mpegnt_pipeline (const gchar * location)
audio_bin = gst_bin_new ("a_decoder_bin");
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
- audio_thread = gst_thread_new ("a_decoder_thread");
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
@@ -518,9 +516,8 @@ make_mpegnt_pipeline (const gchar * location)
gst_element_link (a_decoder, a_queue);
gst_element_link (a_queue, audiosink);
gst_bin_add (GST_BIN (audio_bin), a_decoder);
- gst_bin_add (GST_BIN (audio_bin), audio_thread);
- gst_bin_add (GST_BIN (audio_thread), a_queue);
- gst_bin_add (GST_BIN (audio_thread), audiosink);
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
"sink"), audio_bin);
@@ -758,7 +755,7 @@ update_scale (gpointer data)
gboolean res;
duration = 0;
- clock = gst_bin_get_clock (GST_BIN (pipeline));
+ clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
if (elem_seek) {
if (seekable_elements) {
@@ -811,25 +808,6 @@ update_scale (gpointer data)
}
static gboolean
-iterate (gpointer data)
-{
- gboolean res;
-
- if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
- res = gst_bin_iterate (GST_BIN (data));
- } else {
- g_usleep (500);
- res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
- }
-
- if (!res) {
- gtk_timeout_remove (update_id);
- g_print ("stopping iterations\n");
- }
- return res;
-}
-
-static gboolean
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
{
gst_element_set_state (pipeline, GST_STATE_PAUSED);
@@ -880,7 +858,6 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
}
gst_element_set_state (pipeline, GST_STATE_PLAYING);
- gtk_idle_add ((GtkFunction) iterate, pipeline);
update_id =
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
@@ -890,9 +867,11 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
static void
play_cb (GtkButton * button, gpointer data)
{
- if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
+ GstElementState state;
+
+ gst_element_get_state (pipeline, &state, NULL, NULL);
+ if (state != GST_STATE_PLAYING) {
gst_element_set_state (pipeline, GST_STATE_PLAYING);
- gtk_idle_add ((GtkFunction) iterate, pipeline);
update_id =
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
}
@@ -901,7 +880,10 @@ play_cb (GtkButton * button, gpointer data)
static void
pause_cb (GtkButton * button, gpointer data)
{
- if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
+ GstElementState state;
+
+ gst_element_get_state (pipeline, &state, NULL, NULL);
+ if (state != GST_STATE_PAUSED) {
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gtk_timeout_remove (update_id);
}
@@ -910,7 +892,10 @@ pause_cb (GtkButton * button, gpointer data)
static void
stop_cb (GtkButton * button, gpointer data)
{
- if (gst_element_get_state (pipeline) != GST_STATE_READY) {
+ GstElementState state;
+
+ gst_element_get_state (pipeline, &state, NULL, NULL);
+ if (state != GST_STATE_READY) {
gst_element_set_state (pipeline, GST_STATE_READY);
gtk_adjustment_set_value (adjustment, 0.0);
gtk_timeout_remove (update_id);
@@ -1032,18 +1017,13 @@ main (int argc, char **argv)
if (verbose) {
g_signal_connect (pipeline, "deep_notify",
- G_CALLBACK (gst_element_default_deep_notify), NULL);
+ G_CALLBACK (gst_object_default_deep_notify), NULL);
}
- g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
- NULL);
-
gtk_main ();
gst_element_set_state (pipeline, GST_STATE_NULL);
- //gst_object_unref (GST_OBJECT (pipeline));
-
- //g_mem_chunk_info();
+ gst_object_unref (GST_OBJECT (pipeline));
return 0;
}
diff --git a/ext/ogg/README b/ext/ogg/README
index 2b4bc64b4..b9ec119ee 100644
--- a/ext/ogg/README
+++ b/ext/ogg/README
@@ -1,9 +1,110 @@
+ogg demuxer
+-----------
+
+This ogg demuxer has two modes of operation, which both share a significant
+amount of code. The first mode is the streaming mode which is automatically
+selected when the demuxer is connected to a non-getrange based element. When
+connected to a getrange based element the ogg demuxer can do full seeking
+with great efficiency.
+
+1) the streaming mode.
+
+ In this mode, the ogg demuxer receives buffers in the _chain() function which
+ are then simply submited to the ogg sync layer. Pages are then processed when the
+ sync layer detects them, pads are created for new chains and packets are sent to
+ the peer elements of the pads.
+
+ In this mode, no seeking is possible. This is the typical case when the stream is
+ read from a network source.
+
+ In this mode, no setup is done at startup, the pages are just read and decoded.
+ A new logical chain is detected when one of the pages has the BOS flag set. At this
+ point the existing pads are removed and new pads are created for all the logical
+ streams in this new chain.
+
+
+2) the random access mode.
+
+ In this mode, the ogg file is first scanned to detect the position and length of
+ all chains. This scanning is performed using a recursive binary search algorithm
+ that is explained below.
+
+ find_chains(start, end)
+ {
+ ret1 = read_next_pages (start);
+ ret2 = read_prev_page (end);
+
+ if (WAS_HEADER (ret1)) {
+ }
+ else {
+ }
+
+ }
+
+ a) read first and last pages
+
+ start end
+ V V
+ +-----------------------+-------------+--------------------+
+ | 111 | 222 | 333 |
+ BOS BOS BOS EOS
+
+
+ after reading start, serial 111, BOS, chain[0] = 111
+ after reading end, serial 333, EOS
+
+ start serialno != end serialno, binary search start, (end-start)/2
+
+ start bisect end
+ V V V
+ +-----------------------+-------------+--------------------+
+ | 111 | 222 | 333 |
+
+
+ after reading start, serial 111, BOS, chain[0] = 111
+ after reading end, serial 222, EOS
+
+ while (
+
+
+
+testcases
+---------
+
+ a) stream without BOS
+
+ +----------------------------------------------------------+
+ 111 |
+ EOS
+
+ b) chained stream, first chain without BOS
+
+ +-------------------+--------------------------------------+
+ 111 | 222 |
+ BOS EOS
+
+
+ c) chained stream
+
+ +-------------------+--------------------------------------+
+ | 111 | 222 |
+ BOS BOS EOS
+
+
+ d) chained stream, second without BOS
+
+ +-------------------+--------------------------------------+
+ | 111 | 222 |
+ BOS EOS
+
+
+
ogg and the granulepos
----------------------
an ogg streams contains pages with a serial number and a granule pos. The granulepos
-is a number that is codec specific and denotes the 'position' of the last packet
-in that page.
+is a number that is codec specific and denotes the 'position' of the last sample in
+the last packet in that page.
ogg has therefore no notion about time, it only knows about bytes and granule positions.
diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c
index e68cf6c3d..189999580 100644
--- a/ext/ogg/gstoggdemux.c
+++ b/ext/ogg/gstoggdemux.c
@@ -1,5 +1,5 @@
/* GStreamer
- * Copyright (C) 2003, 2004 Benjamin Otte <otte@gnome.org>
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* gstoggdemux.c: ogg stream demuxer
*
@@ -27,136 +27,445 @@
#include <ogg/ogg.h>
#include <string.h>
-/* tweak this to improve setup times */
-/* PLEASE don't just tweak it because one file is faster with tweaked numbers,
- * but use a good benchmark with both video and audio files */
-/* number of bytes we seek in front of desired point so we can resync properly */
-#define SETUP_EXPECTED_PAGE_SIZE (8500) /* this is out of vorbisfile */
-/* number of bytes where we don't seek to middle anymore but just walk through
- * all packets */
-#define SETUP_PASSTHROUGH_SIZE (SETUP_EXPECTED_PAGE_SIZE * 20)
-/* if we have to repeat a seek backwards because we didn't seek back far enough,
- * we multiply the amount we seek by this amount */
-#define SETUP_SEEK_MULTIPLIER (5)
+#define CHUNKSIZE (8500) /* this is out of vorbisfile */
+enum
+{
+ OV_EREAD = -1,
+ OV_EFAULT = -2,
+ OV_FALSE = -3,
+ OV_EOF = -4,
+};
GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_debug);
GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_setup_debug);
#define GST_CAT_DEFAULT gst_ogg_demux_debug
+#define GST_TYPE_OGG_PAD (gst_ogg_pad_get_type())
+#define GST_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PAD, GstOggPad))
+#define GST_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PAD, GstOggPad))
+#define GST_IS_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PAD))
+#define GST_IS_OGG_PAD_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PAD))
+
+typedef struct _GstOggPad GstOggPad;
+typedef struct _GstOggPadClass GstOggPadClass;
+
#define GST_TYPE_OGG_DEMUX (gst_ogg_demux_get_type())
#define GST_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_DEMUX, GstOggDemux))
#define GST_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_DEMUX, GstOggDemux))
#define GST_IS_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_DEMUX))
#define GST_IS_OGG_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX))
+static GType gst_ogg_demux_get_type (void);
+
typedef struct _GstOggDemux GstOggDemux;
typedef struct _GstOggDemuxClass GstOggDemuxClass;
-typedef enum
+/* all information needed for one ogg stream */
+struct _GstOggPad
+{
+ GstRealPad pad; /* subclass GstRealPad */
+
+ GstOggDemux *ogg;
+
+ gint serialno;
+ gint64 packetno;
+ gint64 offset;
+
+ gint64 current_granule;
+ gint64 first_granule;
+ gint64 last_granule;
+
+ ogg_stream_state stream;
+};
+
+struct _GstOggPadClass
+{
+ GstRealPadClass parent_class;
+};
+
+static void gst_ogg_pad_init (GstOggPad * pad);
+static const GstFormat *gst_ogg_pad_formats (GstPad * pad);
+static const GstEventMask *gst_ogg_pad_event_masks (GstPad * pad);
+static const GstQueryType *gst_ogg_pad_query_types (GstPad * pad);
+static gboolean gst_ogg_pad_src_convert (GstPad * pad,
+ GstFormat src_format, gint64 src_value,
+ GstFormat * dest_format, gint64 * dest_value);
+static gboolean gst_ogg_pad_src_query (GstPad * pad, GstQueryType type,
+ GstFormat * format, gint64 * value);
+static GstCaps *gst_ogg_type_find (ogg_packet * packet);
+
+static GType
+gst_ogg_pad_get_type (void)
{
- /* just because you shouldn't make a valid enum value 0 */
- GST_OGG_STATE_INAVLID,
- /* just started, we need to decide if we should do setup */
- GST_OGG_STATE_START,
- /* setup is analyzing the stream, getting lengths and so on */
- GST_OGG_STATE_SETUP,
- /* after a seek, during resyncing */
- GST_OGG_STATE_SEEK,
- /* normal playback */
- GST_OGG_STATE_PLAY
+ static GType ogg_pad_type = 0;
+
+ if (!ogg_pad_type) {
+ static const GTypeInfo ogg_pad_info = {
+ sizeof (GstOggPadClass),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ sizeof (GstOggPad),
+ 0,
+ (GInstanceInitFunc) gst_ogg_pad_init,
+ };
+
+ ogg_pad_type =
+ g_type_register_static (GST_TYPE_REAL_PAD, "GstOggPad", &ogg_pad_info,
+ 0);
+ }
+ return ogg_pad_type;
}
-GstOggState;
-/* all information needed for one ogg stream */
-typedef struct
+static void
+gst_ogg_pad_init (GstOggPad * pad)
{
- GstPad *pad; /* reference for this pad is held by element we belong to */
+ //gst_pad_set_event_function (GST_PAD (pad), GST_DEBUG_FUNCPTR (gst_ogg_pad_event));
+ gst_pad_set_event_mask_function (GST_PAD (pad),
+ GST_DEBUG_FUNCPTR (gst_ogg_pad_event_masks));
+ //gst_pad_set_getcaps_function (GST_PAD (pad), GST_DEBUG_FUNCPTR (gst_ogg_pad_getcaps));
+ //gst_pad_set_query_function (GST_PAD (pad), GST_DEBUG_FUNCPTR (gst_ogg_pad_query));
+ gst_pad_set_query_type_function (GST_PAD (pad),
+ GST_DEBUG_FUNCPTR (gst_ogg_pad_query_types));
+ gst_pad_set_formats_function (GST_PAD (pad),
+ GST_DEBUG_FUNCPTR (gst_ogg_pad_formats));
+ gst_pad_set_convert_function (GST_PAD (pad),
+ GST_DEBUG_FUNCPTR (gst_ogg_pad_src_convert));
+ gst_pad_set_query_function (GST_PAD (pad),
+ GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query));
+}
- gint serial;
- ogg_stream_state stream;
- guint64 offset; /* end offset of last buffer */
- guint64 known_offset; /* last known offset */
- gint64 packetno; /* number of next expected packet */
+static const GstFormat *
+gst_ogg_pad_formats (GstPad * pad)
+{
+ static GstFormat src_formats[] = {
+ GST_FORMAT_BYTES,
+ GST_FORMAT_DEFAULT, /* granulepos */
+ GST_FORMAT_TIME,
+ 0
+ };
+ static GstFormat sink_formats[] = {
+ GST_FORMAT_BYTES,
+ GST_FORMAT_DEFAULT, /* bytes */
+ 0
+ };
- guint64 start; /* first valid granulepos */
- guint64 length; /* length of stream or 0 */
- glong pages; /* number of pages in stream or 0 */
+ return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
+}
- gint64 start_offset; /* earliest offset in file where this stream has been found */
- gboolean start_found; /* we have found the bos (first) page */
- gint64 end_offset; /* last offset in file where this stream has been found */
- gboolean end_found; /* we have fount the eos (last) page */
+static const GstEventMask *
+gst_ogg_pad_event_masks (GstPad * pad)
+{
+ static const GstEventMask src_event_masks[] = {
+ {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
+ {0,}
+ };
- guint flags;
+ return src_event_masks;
}
-GstOggPad;
-typedef enum
+static const GstQueryType *
+gst_ogg_pad_query_types (GstPad * pad)
+{
+ static const GstQueryType query_types[] = {
+ GST_QUERY_START,
+ GST_QUERY_SEGMENT_END,
+ GST_QUERY_POSITION,
+ 0
+ };
+
+ return query_types;
+}
+
+static gboolean
+gst_ogg_pad_src_convert (GstPad * pad,
+ GstFormat src_format, gint64 src_value,
+ GstFormat * dest_format, gint64 * dest_value)
{
- GST_OGG_PAD_NEEDS_DISCONT = (1 << 0),
- GST_OGG_PAD_NEEDS_FLUSH = (1 << 1)
+ gboolean res = FALSE;
+ GstOggDemux *ogg;
+
+ ogg = GST_OGG_DEMUX (GST_PAD_PARENT (pad));
+
+ /* fill me, not sure with what... */
+
+ return res;
+}
+
+static gboolean
+gst_ogg_pad_src_query (GstPad * pad, GstQueryType type,
+ GstFormat * format, gint64 * value)
+{
+ gboolean res = TRUE;
+
+ GstOggDemux *ogg;
+ GstOggPad *cur;
+
+ ogg = GST_OGG_DEMUX (GST_PAD_PARENT (pad));
+
+ cur = GST_OGG_PAD (pad);
+
+ switch (type) {
+ case GST_QUERY_START:
+ *value = cur->first_granule;
+ break;
+ case GST_QUERY_SEGMENT_END:
+ *value = cur->last_granule;
+ break;
+ case GST_QUERY_POSITION:
+ *value = cur->current_granule;
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+
+ return res;
+}
+
+static void
+gst_ogg_pad_reset (GstOggPad * pad)
+{
+ ogg_stream_reset (&pad->stream);
+ /* FIXME: need a discont here */
+}
+
+
+/* submit a packet to the oggpad, this function will run the
+ * typefind code for the pad if this is the first packet for this
+ * stream
+ */
+static GstFlowReturn
+gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
+{
+ GstBuffer *buf;
+ gint64 granule;
+
+ GstOggDemux *ogg = pad->ogg;
+
+ GST_DEBUG_OBJECT (ogg,
+ "%p submit packet %d, packetno %lld", pad, pad->serialno, pad->packetno);
+
+ granule = packet->granulepos;
+ if (granule != -1) {
+ pad->current_granule = granule;
+ }
+
+ /* first packet */
+ if (pad->packetno == 0) {
+ GstCaps *caps = gst_ogg_type_find (packet);
+
+ if (caps == NULL) {
+ GST_WARNING_OBJECT (ogg,
+ "couldn't find caps for stream with serial %d", pad->serialno);
+ caps = gst_caps_new_simple ("application/octet-stream", NULL);
+ }
+
+ gst_pad_set_caps (GST_PAD (pad), caps);
+ gst_caps_unref (caps);
+ gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD (pad));
+ }
+
+ pad->packetno++;
+
+ buf =
+ gst_pad_alloc_buffer (GST_PAD (pad), GST_BUFFER_OFFSET_NONE,
+ packet->bytes, GST_PAD_CAPS (pad));
+ if (buf) {
+ memcpy (buf->data, packet->packet, packet->bytes);
+ GST_BUFFER_OFFSET (buf) = pad->offset;
+ GST_BUFFER_OFFSET_END (buf) = packet->granulepos;
+ pad->offset = packet->granulepos;
+
+ return gst_pad_push (GST_PAD (pad), buf);
+ }
+ return GST_FLOW_ERROR;
+}
+
+/* submit a page to an oggpad, this function will then submit all
+ * the packets in the page.
+ */
+static GstFlowReturn
+gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page)
+{
+ ogg_packet packet;
+ int ret;
+ gboolean done = FALSE;
+ GstFlowReturn result = GST_FLOW_OK;
+ GstOggDemux *ogg;
+
+ ogg = GST_OGG_DEMUX (GST_PAD_PARENT (pad));
+
+ if (ogg_stream_pagein (&pad->stream, page) != 0) {
+ GST_WARNING_OBJECT (ogg,
+ "ogg stream choked on page (serial %d), resetting stream",
+ pad->serialno);
+ gst_ogg_pad_reset (pad);
+ return GST_FLOW_OK;
+ }
+
+ while (!done) {
+ ret = ogg_stream_packetout (&pad->stream, &packet);
+ GST_LOG_OBJECT (ogg, "packetout gave %d", ret);
+ switch (ret) {
+ case 0:
+ done = TRUE;
+ break;
+ case -1:
+ /* out of sync, could call gst_ogg_pad_reset() here but ogg can decode
+ * the packet just fine. We should probably send a DISCONT though. */
+ break;
+ case 1:
+ result = gst_ogg_pad_submit_packet (pad, &packet);
+ if (result != GST_FLOW_OK) {
+ done = TRUE;
+ }
+ break;
+ default:
+ GST_WARNING_OBJECT (ogg,
+ "invalid return value %d for ogg_stream_packetout, resetting stream",
+ ret);
+ gst_ogg_pad_reset (pad);
+ break;
+ }
+ }
+ return result;
}
-GstOggPadFlags;
/* all information needed for one ogg chain (relevant for chained bitstreams) */
typedef struct
{
- gint64 starts_at; /* starting offset of chain */
- gint64 ends_at; /* end offset of stream (only valid when not last chain or not in setup) */
+ GstOggDemux *ogg;
+
+ gint64 offset; /* starting offset of chain */
+ gint64 end_offset; /* end offset of chain */
+ gint64 bytes; /* number of bytes */
- GSList *pads; /* list of GstOggPad */
+ gboolean have_bos;
+
+ GArray *streams;
}
GstOggChain;
+static GstOggChain *
+gst_ogg_chain_new (GstOggDemux * ogg)
+{
+ GstOggChain *chain = g_new0 (GstOggChain, 1);
+
+ GST_DEBUG_OBJECT (ogg, "creating new chain %p", chain);
+ chain->ogg = ogg;
+ chain->offset = -1;
+ chain->bytes = -1;
+ chain->have_bos = FALSE;
+ chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *));
+
+ return chain;
+}
+
+#if 0
+static void
+gst_ogg_chain_free (GstOggChain * chain)
+{
+ g_array_free (chain->streams, TRUE);
+}
+#endif
+
+static GstOggPad *
+gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno)
+{
+ GstOggPad *ret;
+ GstTagList *list;
+ gchar *name;
+
+ GST_DEBUG_OBJECT (chain->ogg, "creating new stream %ld in chain %p", serialno,
+ chain);
+
+ ret = g_object_new (GST_TYPE_OGG_PAD, NULL);
+ /* we own this one */
+ gst_object_ref (GST_OBJECT (ret));
+ gst_object_sink (GST_OBJECT (ret));
+
+ list = gst_tag_list_new ();
+ name = g_strdup_printf ("serial_%ld", serialno);
+
+ GST_RPAD_DIRECTION (ret) = GST_PAD_SRC;
+ ret->ogg = chain->ogg;
+ gst_object_set_name (GST_OBJECT (ret), name);
+ g_free (name);
+
+ ret->first_granule = -1;
+ ret->last_granule = -1;
+ ret->current_granule = -1;
+
+ ret->serialno = serialno;
+ if (ogg_stream_init (&ret->stream, serialno) != 0) {
+ GST_ERROR ("Could not initialize ogg_stream struct for serial %d.",
+ serialno);
+ g_object_unref (G_OBJECT (ret));
+ return NULL;
+ }
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno,
+ NULL);
+ //gst_element_found_tags (GST_ELEMENT (ogg), list);
+ gst_tag_list_free (list);
+
+ GST_LOG ("created new ogg src %p for stream with serial %d", ret, serialno);
+
+ g_array_append_val (chain->streams, ret);
+
+ return ret;
+}
+
+static GstOggPad *
+gst_ogg_chain_get_stream (GstOggChain * chain, glong serialno)
+{
+ gint i;
+
+ for (i = 0; i < chain->streams->len; i++) {
+ GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
+
+ if (pad->serialno == serialno)
+ return pad;
+ }
+ return NULL;
+}
+
+static gboolean
+gst_ogg_chain_has_stream (GstOggChain * chain, glong serialno)
+{
+ return gst_ogg_chain_get_stream (chain, serialno) != NULL;
+}
+
#define CURRENT_CHAIN(ogg) (&g_array_index ((ogg)->chains, GstOggChain, (ogg)->current_chain))
-#define FOR_PAD_IN_CURRENT_CHAIN(ogg, __pad, ...) \
- FOR_PAD_IN_CHAIN(ogg, __pad, (ogg)->current_chain, __VA_ARGS__)
-#define FOR_PAD_IN_CHAIN(ogg, _pad, i, ...) G_STMT_START{ \
- GSList *_walk; \
- GstOggChain *_chain = &g_array_index ((ogg)->chains, GstOggChain, i); \
- if (i != -1) { \
- for (_walk = _chain->pads; _walk; _walk = g_slist_next (_walk)) { \
- GstOggPad *_pad = (GstOggPad *) _walk->data; \
- __VA_ARGS__ \
- } \
- } \
-}G_STMT_END
typedef enum
{
- GST_OGG_FLAG_BOS = GST_ELEMENT_FLAG_LAST,
- GST_OGG_FLAG_EOS,
- GST_OGG_FLAG_WAIT_FOR_DISCONT
-}
-GstOggFlag;
+ OGG_STATE_NEW_CHAIN,
+ OGG_STATE_STREAMING,
+} OggState;
struct _GstOggDemux
{
GstElement element;
- /* pad */
- GstFilePad *sinkpad;
+ GstPad *sinkpad;
+
+ gint64 length;
+ gint64 offset;
+
+ OggState state;
/* state */
- GstOggState state;
GArray *chains; /* list of chains we know */
- gint current_chain; /* id of chain that currently "plays" */
- gboolean bos; /* no-more-pads signal needs this */
- /* setup */
- GSList *unordered; /* streams we haven't found chains for yet */
- guint setup_state; /* seperate from global state */
+
+ GstOggChain *current_chain;
+ GstOggChain *building_chain;
/* ogg stuff */
ogg_sync_state sync;
-
- /* seeking */
- GstOggPad *seek_pad;
- gint64 seek_to;
- gint64 seek_skipped;
- guint64 seek_offset;
- GstFormat seek_format;
- gint seek_try;
};
struct _GstOggDemuxClass
@@ -190,93 +499,32 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_CAPS ("application/ogg")
);
-/* different setup phases */
-typedef enum
-{
- SETUP_INVALID,
- SETUP_READ_FIRST_BOS,
- SETUP_READ_BOS,
- SETUP_FIND_LAST_CHAIN,
- SETUP_FIND_END_OF_CHAIN,
- SETUP_FIND_END_OF_STREAMS,
- SETUP_FIND_END_OF_LAST_STREAMS
-}
-GstOggSetupState;
-
-typedef struct
-{
- gboolean (*init) (GstOggDemux * ogg);
- gboolean (*process) (GstOggDemux * ogg, ogg_page * page);
-}
-SetupStateFunc;
-
-static gboolean _read_bos_init (GstOggDemux * ogg);
-static gboolean _read_bos_process (GstOggDemux * ogg, ogg_page * page);
-static gboolean _find_chain_init (GstOggDemux * ogg);
-static gboolean _find_chain_process (GstOggDemux * ogg, ogg_page * page);
-static gboolean _find_last_chain_init (GstOggDemux * ogg);
-static gboolean _find_last_chain_process (GstOggDemux * ogg, ogg_page * page);
-static gboolean _find_streams_init (GstOggDemux * ogg);
-static gboolean _find_streams_process (GstOggDemux * ogg, ogg_page * page);
-
-static SetupStateFunc setup_funcs[] = {
- {NULL, NULL},
- {_read_bos_init, _read_bos_process},
- {_read_bos_init, _read_bos_process},
- {_find_last_chain_init, _find_last_chain_process},
- {_find_chain_init, _find_chain_process},
- {_find_streams_init, _find_streams_process},
- {_find_streams_init, _find_streams_process},
- {NULL, NULL} /* just because */
-};
-
-static gboolean gst_ogg_demux_set_setup_state (GstOggDemux * ogg,
- GstOggSetupState state);
-
static void gst_ogg_demux_finalize (GObject * object);
-static gboolean gst_ogg_demux_src_event (GstPad * pad, GstEvent * event);
-static const GstEventMask *gst_ogg_demux_get_event_masks (GstPad * pad);
-static const GstQueryType *gst_ogg_demux_get_query_types (GstPad * pad);
-static const GstFormat *gst_ogg_demux_get_formats (GstPad * pad);
-
-static gboolean gst_ogg_demux_src_query (GstPad * pad,
- GstQueryType type, GstFormat * format, gint64 * value);
+//static const GstEventMask *gst_ogg_demux_get_event_masks (GstPad * pad);
+//static const GstQueryType *gst_ogg_demux_get_query_types (GstPad * pad);
+static GstOggChain *gst_ogg_demux_read_chain (GstOggDemux * ogg);
-static void gst_ogg_demux_iterate (GstFilePad * pad);
static gboolean gst_ogg_demux_handle_event (GstPad * pad, GstEvent * event);
-
+static gboolean gst_ogg_demux_loop (GstOggPad * pad);
+static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad,
+ GstActivateMode mode);
static GstElementStateReturn gst_ogg_demux_change_state (GstElement * element);
-static GstOggPad *gst_ogg_pad_new (GstOggDemux * ogg, int serial_no);
-static void gst_ogg_pad_remove (GstOggDemux * ogg, GstOggPad * ogg_pad);
-static void gst_ogg_pad_reset (GstOggDemux * ogg, GstOggPad * pad);
-static void gst_ogg_demux_push (GstOggDemux * ogg, ogg_page * page);
-static void gst_ogg_pad_push (GstOggDemux * ogg, GstOggPad * ogg_pad);
-static void gst_ogg_chains_clear (GstOggDemux * ogg);
-static void gst_ogg_add_chain (GstOggDemux * ogg);
-
-static GstCaps *gst_ogg_type_find (ogg_packet * packet);
-
static void gst_ogg_print (GstOggDemux * demux);
-#define GST_OGG_SET_STATE(ogg, new_state) G_STMT_START{ \
- GST_DEBUG_OBJECT (ogg, "setting state to %s", G_STRINGIFY (new_state)); \
- ogg->state = new_state; \
- ogg->setup_state = (new_state == GST_OGG_STATE_SETUP) ? \
- SETUP_READ_FIRST_BOS : SETUP_INVALID; \
-}G_STMT_END
-
-GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT)
+GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT);
- static void gst_ogg_demux_base_init (gpointer g_class)
+static void
+gst_ogg_demux_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
static GstElementDetails gst_ogg_demux_details =
GST_ELEMENT_DETAILS ("ogg demuxer",
"Codec/Demuxer",
"demux ogg streams (info about ogg: http://xiph.org)",
- "Benjamin Otte <otte@gnome.org>");
+ "Wim Taymand <wim@fluendo.com>");
gst_element_class_set_details (element_class, &gst_ogg_demux_details);
@@ -299,22 +547,20 @@ gst_ogg_demux_class_init (GstOggDemuxClass * klass)
static void
gst_ogg_demux_init (GstOggDemux * ogg)
{
- GST_FLAG_SET (ogg, GST_ELEMENT_EVENT_AWARE);
-
/* create the sink pad */
ogg->sinkpad =
- GST_FILE_PAD (gst_file_pad_new (gst_static_pad_template_get
- (&ogg_demux_sink_template_factory), "sink"));
- gst_file_pad_set_iterate_function (ogg->sinkpad, gst_ogg_demux_iterate);
- gst_file_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_handle_event);
- gst_pad_set_formats_function (GST_PAD (ogg->sinkpad),
- gst_ogg_demux_get_formats);
- gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD (ogg->sinkpad));
-
- /* initalize variables */
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_START);
- ogg->chains = g_array_new (TRUE, TRUE, sizeof (GstOggChain));
- ogg->current_chain = -1;
+ gst_pad_new_from_template (gst_static_pad_template_get
+ (&ogg_demux_sink_template_factory), "sink");
+ gst_pad_set_formats_function (ogg->sinkpad, gst_ogg_pad_formats);
+ gst_pad_set_loop_function (ogg->sinkpad,
+ (GstPadLoopFunction) gst_ogg_demux_loop);
+ gst_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_handle_event);
+ gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_demux_chain);
+ gst_pad_set_activate_function (ogg->sinkpad, gst_ogg_demux_sink_activate);
+ gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
+
+ ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *));
+ ogg->state = OGG_STATE_NEW_CHAIN;
}
static void
@@ -326,1296 +572,533 @@ gst_ogg_demux_finalize (GObject * object)
ogg_sync_clear (&ogg->sync);
- /* chains are removed when going to READY */
- g_assert (ogg->current_chain == -1);
- g_assert (ogg->chains->len == 0);
- g_array_free (ogg->chains, TRUE);
-
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static const GstFormat *
-gst_ogg_demux_get_formats (GstPad * pad)
+static gboolean
+gst_ogg_demux_handle_event (GstPad * pad, GstEvent * event)
{
- static GstFormat src_formats[] = {
- GST_FORMAT_BYTES,
- GST_FORMAT_DEFAULT, /* granulepos */
- GST_FORMAT_TIME,
- 0
- };
- static GstFormat sink_formats[] = {
- GST_FORMAT_BYTES,
- GST_FORMAT_DEFAULT, /* bytes */
- 0
- };
+ GstOggDemux *ogg = GST_OGG_DEMUX (GST_PAD_PARENT (pad));
- return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_DISCONTINUOUS:
+ GST_DEBUG_OBJECT (ogg, "got a discont event");
+ ogg_sync_reset (&ogg->sync);
+ gst_event_unref (event);
+ break;
+ default:
+ return gst_pad_event_default (pad, event);
+ }
+ return TRUE;
}
-static const GstEventMask *
-gst_ogg_demux_get_event_masks (GstPad * pad)
+/* submit the given buffer to the ogg sync.
+ *
+ * Returns the number of bytes submited.
+ */
+static gint
+gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
{
- static const GstEventMask gst_ogg_demux_src_event_masks[] = {
- {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
- {0,}
- };
+ guint size;
+ guint8 *data;
+ gchar *oggbuffer;
- return gst_ogg_demux_src_event_masks;
-}
-static const GstQueryType *
-gst_ogg_demux_get_query_types (GstPad * pad)
-{
- static const GstQueryType gst_ogg_demux_src_query_types[] = {
- GST_QUERY_TOTAL,
- GST_QUERY_POSITION,
- 0
- };
+ size = GST_BUFFER_SIZE (buffer);
+ data = GST_BUFFER_DATA (buffer);
+
+ oggbuffer = ogg_sync_buffer (&ogg->sync, size);
+ memcpy (oggbuffer, data, size);
+ ogg_sync_wrote (&ogg->sync, size);
- return gst_ogg_demux_src_query_types;
+ return size;
}
-static GstOggPad *
-gst_ogg_get_pad_by_pad (GstOggDemux * ogg, GstPad * pad)
+/* in radom access mode this code updates the current read position
+ * and resets the ogg sync buffer so that the next read will happen
+ * from this new location.
+ */
+static void
+gst_ogg_demux_seek (GstOggDemux * ogg, gint64 offset)
{
- GSList *walk;
- GstOggPad *cur;
+ GST_LOG_OBJECT (ogg, "seeking to %lld", offset);
- if (ogg->current_chain == -1) {
- GST_DEBUG_OBJECT (ogg, "no active chain, returning NULL");
- return NULL;
- }
- for (walk = CURRENT_CHAIN (ogg)->pads; walk; walk = g_slist_next (walk)) {
- cur = (GstOggPad *) walk->data;
- if (cur->pad == pad)
- return cur;
- }
- return NULL;
+ ogg->offset = offset;
+ ogg_sync_reset (&ogg->sync);
}
-/* will subtract the base from a given granulepos in a stream
- * (lineairly) and return the relative granulepos from the first
- * packet in the stream, or some approximation thereof. Input is
- * in granulepos units, output is either granulepos or time.
- * Uses time internally. Returns -1 on error.
+/* read more data from the current offset and submit to
+ * the ogg sync layer.
+ *
+ * Return number of bytes written.
*/
-static gint64
-get_relative (GstOggDemux * ogg, GstOggPad * cur, gint64 granpos, GstFormat out)
+static gint
+gst_ogg_demux_get_data (GstOggDemux * ogg)
{
- gint64 time, start = -1, tmp;
- GstFormat fmt;
-
- /* we're gonna ask our peer */
- if (!GST_PAD_PEER (cur->pad))
- return -1;
+ GstFlowReturn ret;
+ GstBuffer *buffer;
+ gint size;
- /* lineair unit (time) */
- fmt = GST_FORMAT_TIME;
- if (!gst_pad_convert (GST_PAD_PEER (cur->pad),
- GST_FORMAT_DEFAULT, granpos, &fmt, &time))
- return -1;
+ GST_LOG_OBJECT (ogg, "get data %lld", ogg->offset);
+ if (ogg->offset == ogg->length)
+ return 0;
- /* get base for this chain */
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
- if (pad->start != -1 &&
- GST_PAD_PEER (pad->pad) &&
- gst_pad_convert (GST_PAD_PEER (pad->pad),
- GST_FORMAT_DEFAULT, pad->start,
- &fmt, &tmp) && (start == -1 || tmp < start))
- start = tmp;);
- if (start == -1)
+ ret = gst_pad_pull_range (ogg->sinkpad, ogg->offset, CHUNKSIZE, &buffer);
+ if (ret != GST_FLOW_OK)
return -1;
- /* base is *end of first page*, so subtract $random amount to make
- * us think it's the start of the page (= 1 second) */
- if (start > GST_SECOND)
- start -= GST_SECOND;
- else
- start = 0;
-
- /* subtract */
- if (time > start)
- time -= start;
- else
- time = 0;
-
- /* convert back to $outputformat */
- if (!gst_pad_convert (GST_PAD_PEER (cur->pad),
- GST_FORMAT_TIME, time, &out, &tmp))
- return -1;
+ size = gst_ogg_demux_submit_buffer (ogg, buffer);
- return tmp;
+ return size;
}
-/* the query function on the src pad only knows about granulepos
- * values but we can use the peer plugins to convert the granulepos
- * (which is supposed to be the default format) to any other format
+/* Read the next page from the current offset.
*/
-static gboolean
-gst_ogg_demux_src_query (GstPad * pad, GstQueryType type,
- GstFormat * format, gint64 * value)
+static gint64
+gst_ogg_demux_get_next_page (GstOggDemux * ogg, ogg_page * og, gint64 boundary)
{
- gboolean res = FALSE;
- GstOggDemux *ogg;
- GstOggPad *cur;
- guint64 granulepos = 0;
+ gint64 end_offset = 0;
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
-
- cur = gst_ogg_get_pad_by_pad (ogg, pad);
- if (!cur)
- return FALSE;
+ GST_LOG_OBJECT (ogg, "get next page %lld", boundary);
- switch (type) {
- case GST_QUERY_TOTAL:{
- if (cur->length != 0 && cur->length > cur->start) {
- granulepos = cur->length;
- res = TRUE;
- }
- break;
- }
- case GST_QUERY_POSITION:
- if (cur->length != 0 && cur->length > cur->start) {
- granulepos = cur->known_offset;
- res = TRUE;
- }
- break;
- default:
- break;
- }
+ if (boundary > 0)
+ end_offset = ogg->offset + boundary;
- if (res) {
- gint64 time;
+ while (TRUE) {
+ glong more;
- time = get_relative (ogg, cur, granulepos, GST_FORMAT_TIME);
- if (time == -1)
- return FALSE;
-
- /* still ok, got a granulepos then */
- switch (*format) {
- case GST_FORMAT_TIME:
- /* fine, result should be granulepos */
- *value = time;
- break;
- default:
- /* something we have to ask our peer */
- if (GST_PAD_PEER (pad)) {
- res = gst_pad_convert (GST_PAD_PEER (pad),
- GST_FORMAT_TIME, time, format, value);
- } else {
- res = FALSE;
- }
- break;
+ if (boundary > 0 && ogg->offset >= end_offset) {
+ GST_LOG_OBJECT (ogg, "offset %lld >= end_offset %lld", ogg->offset,
+ end_offset);
+ return OV_FALSE;
}
- }
- return res;
-}
-
-/* The current seeking implementation is the most simple I could come up with:
- * - when seeking forwards, just discard data until desired position is reached
- * - when seeking backwards, seek to beginning and seek forward from there
- * Anyone is free to improve this algorithm as it is quite stupid and probably
- * really slow.
- *
- * The seeking position can be specified as the granulepos in case a decoder
- * plugin can give us a correct granulepos, or in timestamps.
- * In the case of a time seek, we repeadedly ask the peer element to
- * convert the granulepos in the page to a timestamp. We go back to playing
- * when the timestamp is the requested one (or close enough to it).
- */
-static gboolean
-gst_ogg_demux_src_event (GstPad * pad, GstEvent * event)
-{
- GstOggDemux *ogg;
- GstOggPad *cur;
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
- cur = gst_ogg_get_pad_by_pad (ogg, pad);
+ more = ogg_sync_pageseek (&ogg->sync, og);
- /* FIXME: optimize this so events from inactive chains work?
- * in theory there shouldn't be an exisiting pad for inactive chains */
- if (cur == NULL)
- goto error;
+ if (more < 0) {
+ GST_LOG_OBJECT (ogg, "skipped %ld bytes", more);
+ /* skipped n bytes */
+ ogg->offset -= more;
+ } else if (more == 0) {
+ gint ret;
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- {
- gint64 offset, position, total, seek_offset;
- GstFormat format, my_format;
- gboolean res;
-
- format = GST_EVENT_SEEK_FORMAT (event);
- offset = GST_EVENT_SEEK_OFFSET (event);
-
- my_format = format;
-
- /* get position, we'll need it later to decide what direction
- * we need to seek in */
- res = gst_ogg_demux_src_query (pad,
- GST_QUERY_POSITION, &my_format, &position);
- if (!res)
- goto error;
-
- switch (GST_EVENT_SEEK_METHOD (event)) {
- case GST_SEEK_METHOD_END:
- {
- gint64 value;
-
- /* invalid offset */
- if (offset > 0)
- goto error;
-
- /* calculate total length first */
- res = gst_ogg_demux_src_query (pad,
- GST_QUERY_TOTAL, &my_format, &value);
- if (!res)
- goto error;
-
- /* requested position is end + offset */
- offset = value + offset;
- break;
- }
- case GST_SEEK_METHOD_CUR:
- {
- /* add current position to offset */
- offset = position + offset;
- break;
- }
- case GST_SEEK_METHOD_SET:
- /* offset and format are fine here */
- break;
- default:
- g_warning ("invalid seek method in seek event");
- goto error;
- }
+ /* send more paramedics */
+ if (boundary == 0)
+ return OV_FALSE;
- my_format = GST_FORMAT_TIME;
- if (format != GST_FORMAT_TIME) {
- if (!GST_PAD_PEER (pad) ||
- !gst_pad_convert (GST_PAD_PEER (pad), format,
- offset, &my_format, &position))
- goto error;
- } else {
- position = offset;
- }
- if (!gst_ogg_demux_src_query (pad, GST_QUERY_TOTAL, &my_format, &total))
- goto error;
- if (position < 0)
- position = 0;
- else if (position > total)
- position = total;
- seek_offset = gst_file_pad_get_length (ogg->sinkpad) *
- ((gdouble) position) / ((gdouble) total);
- if (gst_file_pad_seek (ogg->sinkpad, seek_offset,
- GST_SEEK_METHOD_SET) != 0)
- goto error;
- ogg->seek_try = 1;
- ogg_sync_clear (&ogg->sync);
+ ret = gst_ogg_demux_get_data (ogg);
+ if (ret == 0)
+ return OV_EOF;
+ if (ret < 0)
+ return OV_EREAD;
+ } else {
+ /* got a page. Return the offset at the page beginning,
+ advance the internal offset past the page end */
+ gint64 ret = ogg->offset;
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SEEK);
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
- pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;);
- if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
- pad->flags |= GST_OGG_PAD_NEEDS_FLUSH;);
- }
- GST_DEBUG_OBJECT (ogg,
- "initiating seeking to format %d, offset %" G_GUINT64_FORMAT, format,
- offset);
+ ogg->offset += more;
- /* store format and position we seek to */
- ogg->seek_pad = cur;
- ogg->seek_to = position;
- ogg->seek_format = GST_FORMAT_TIME;
- ogg->seek_offset = seek_offset;
+ GST_LOG_OBJECT (ogg, "got page at %lld, serial %08lx, end at %lld", ret,
+ ogg_page_serialno (og), ogg->offset);
- gst_event_unref (event);
- return TRUE;
+ return ret;
}
- default:
- return gst_pad_event_default (pad, event);
}
-
- g_assert_not_reached ();
-
-error:
- gst_event_unref (event);
- return FALSE;
-}
-
-static gboolean
-gst_ogg_demux_src_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = FALSE;
- GstOggDemux *ogg;
- GstOggPad *cur;
-
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
- cur = gst_ogg_get_pad_by_pad (ogg, pad);
-
- /* fill me, not sure with what... */
-
- return res;
}
-static void
-gst_ogg_start_playing (GstOggDemux * ogg)
+/* from the current offset, find the previous page, seeking backwards
+ * until we find the page. */
+static gint
+gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og)
{
- GST_DEBUG_OBJECT (ogg, "done with setup, changing to playback now");
- if (gst_file_pad_seek (ogg->sinkpad, 0, GST_SEEK_METHOD_SET) != 0) {
- GST_ELEMENT_ERROR (ogg, CORE, SEEK, (NULL),
- ("cannot seek to start after EOS"));
- }
- ogg_sync_clear (&ogg->sync);
- if (ogg->current_chain >= 0) {
- ogg->current_chain = 0;
- } else {
- gst_ogg_add_chain (ogg);
+ gint64 begin = ogg->offset;
+ gint64 end = begin;
+ gint64 ret;
+ gint64 offset = -1;
+
+ while (offset == -1) {
+ begin -= CHUNKSIZE;
+ if (begin < 0)
+ begin = 0;
+
+ gst_ogg_demux_seek (ogg, begin);
+
+ /* now continue reading until we run out of data, if we find a page
+ * start, we save it. It might not be the final page as there could be
+ * another page after this one. */
+ while (ogg->offset < end) {
+ ret = gst_ogg_demux_get_next_page (ogg, og, end - ogg->offset);
+ if (ret == OV_EREAD)
+ return OV_EREAD;
+ if (ret < 0) {
+ break;
+ } else {
+ offset = ret;
+ }
+ }
}
- GST_FLAG_UNSET (ogg, GST_OGG_FLAG_EOS);
- GST_FLAG_SET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT);
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_PLAY);
- gst_ogg_print (ogg);
-}
-static gboolean
-gst_ogg_demux_handle_event (GstPad * pad, GstEvent * event)
-{
- GstOggDemux *ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
+ /* we have the offset. Actually snork and hold the page now */
+ gst_ogg_demux_seek (ogg, offset);
+ ret = gst_ogg_demux_get_next_page (ogg, og, CHUNKSIZE);
+ if (ret < 0)
+ /* this shouldn't be possible */
+ return OV_EFAULT;
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_DISCONTINUOUS:
- GST_DEBUG_OBJECT (ogg, "got a discont event");
- ogg_sync_reset (&ogg->sync);
- gst_event_unref (event);
- GST_FLAG_UNSET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT);
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
- pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;);
- break;
- default:
- gst_pad_event_default (pad, event);
- break;
- }
- return TRUE;
+ return offset;
}
-static void
-gst_ogg_demux_eos (GstOggDemux * ogg)
+/* finds each bitstream link one at a time using a bisection search
+ * (has to begin by knowing the offset of the lb's initial page).
+ * Recurses for each link so it can alloc the link storage after
+ * finding them all, then unroll and fill the cache at the same time
+ */
+static gint
+gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg,
+ gint64 begin, gint64 searched, gint64 end, GstOggChain * chain, glong m)
{
- guint i;
- GSList *walk;
- GstEvent *event;
-
- GST_DEBUG_OBJECT (ogg, "got EOS");
- ogg->current_chain = -1;
- if (ogg->state == GST_OGG_STATE_SETUP) {
- gst_ogg_start_playing (ogg);
- return;
- }
- event = gst_event_new (GST_EVENT_EOS);
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = &g_array_index (ogg->chains, GstOggChain, i);
+ gint64 endsearched = end;
+ gint64 next = end;
+ ogg_page og;
+ gint64 ret;
+ GstOggChain *nextchain;
+
+ GST_LOG_OBJECT (ogg,
+ "bisect begin: %lld, searched: %lld, end %lld, chain: %p", begin,
+ searched, end, chain);
+
+ /* the below guards against garbage seperating the last and
+ * first pages of two links. */
+ while (searched < endsearched) {
+ gint64 bisect;
+
+ if (endsearched - searched < CHUNKSIZE) {
+ bisect = searched;
+ } else {
+ bisect = (searched + endsearched) / 2;
+ }
- for (walk = chain->pads; walk; walk = g_slist_next (walk)) {
- GstOggPad *pad = (GstOggPad *) walk->data;
+ gst_ogg_demux_seek (ogg, bisect);
+ ret = gst_ogg_demux_get_next_page (ogg, &og, -1);
+ if (ret == OV_EREAD) {
+ GST_LOG_OBJECT (ogg, "OV_READ");
+ return OV_EREAD;
+ }
- if (pad->pad && GST_PAD_IS_USABLE (pad->pad)) {
- gst_data_ref (GST_DATA (event));
- gst_pad_push (pad->pad, GST_DATA (event));
- }
+ if (ret < 0 || !gst_ogg_chain_has_stream (chain, ogg_page_serialno (&og))) {
+ endsearched = bisect;
+ if (ret >= 0)
+ next = ret;
+ } else {
+ searched = ret + og.header_len + og.body_len;
}
}
- gst_element_set_eos (GST_ELEMENT (ogg));
- gst_event_unref (event);
-}
-
-static GstOggPad *
-gst_ogg_pad_get_in_chain (GstOggDemux * ogg, guint chain, int serial)
-{
- FOR_PAD_IN_CHAIN (ogg, pad, chain, if (pad->serial == serial)
- return pad;);
- return NULL;
-}
-/* get the pad with the given serial in the current stream or NULL if none */
-static GstOggPad *
-gst_ogg_pad_get_in_current_chain (GstOggDemux * ogg, int serial)
-{
- if (ogg->current_chain == -1)
- return NULL;
- g_return_val_if_fail (ogg->current_chain < ogg->chains->len, NULL);
- return gst_ogg_pad_get_in_chain (ogg, ogg->current_chain, serial);
-}
+ GST_LOG_OBJECT (ogg, "found begin at %lld", next);
-/* FIXME: HACK - i dunno if this is supported ogg API */
-static guint
-gst_ogg_page_get_length (ogg_page * page)
-{
- return page->header_len + page->body_len;
-}
+ chain->end_offset = searched;
+ gst_ogg_demux_seek (ogg, next);
+ nextchain = gst_ogg_demux_read_chain (ogg);
-static gint64
-gst_ogg_demux_position (GstOggDemux * ogg)
-{
- gint64 pos = gst_file_pad_tell (ogg->sinkpad);
+ if (searched < end && nextchain != NULL) {
+ ret = gst_ogg_demux_bisect_forward_serialno (ogg, next, ogg->offset,
+ end, nextchain, m + 1);
- if (pos < 0)
- return pos;
+ if (ret == OV_EREAD) {
+ GST_LOG_OBJECT (ogg, "OV_READ");
+ return OV_EREAD;
+ }
+ }
+ g_array_insert_val (ogg->chains, 0, chain);
- return pos - ogg->sync.fill + ogg->sync.returned;
+ return 0;
}
-/* END HACK */
-
-/* fill in values from this page */
-#include <signal.h>
-static void
-gst_ogg_pad_populate (GstOggDemux * ogg, GstOggPad * pad, ogg_page * page)
+/* read a chain from the ogg file. This code will
+ * read all BOS pages and will create and return a GstOggChain
+ * structure with the results.
+ */
+static GstOggChain *
+gst_ogg_demux_read_chain (GstOggDemux * ogg)
{
- gint64 start, end;
+ GstOggChain *chain = NULL;
+ gint64 offset = ogg->offset;
- if (pad->start > ogg_page_granulepos (page) && ogg_page_granulepos (page) > 0) {
- pad->start = ogg_page_granulepos (page);
- }
- if (pad->length < ogg_page_granulepos (page))
- pad->length = ogg_page_granulepos (page);
- if (pad->pages < ogg_page_pageno (page))
- pad->pages = ogg_page_pageno (page);
- end = gst_ogg_demux_position (ogg);
- if (end >= 0) {
- /* we need to know the offsets into the stream for the current page */
- start = end - gst_ogg_page_get_length (page);
- //g_print ("really setting start from %lld to %lld\n", pad->start_offset, start);
- //g_print ("really setting end from %lld to %lld\n", pad->end_offset, end);
- if (start < pad->start_offset || pad->start_offset < 0)
- pad->start_offset = start;
- if (ogg_page_bos (page))
- pad->start_found = TRUE;
- if (end > pad->end_offset)
- pad->end_offset = end;
- if (ogg_page_eos (page))
- pad->end_found = TRUE;
- }
-}
+ GST_LOG_OBJECT (ogg, "reading chain at %lld", offset);
-/* get the ogg pad with the given serial in the unordered list or create and add it */
-static GstOggPad *
-gst_ogg_pad_get_unordered (GstOggDemux * ogg, ogg_page * page)
-{
- GSList *walk;
- GstOggPad *pad;
- int serial = ogg_page_serialno (page);
+ while (TRUE) {
+ ogg_page og;
+ GstOggPad *pad;
+ glong serial;
+ gint ret;
- for (walk = ogg->unordered; walk; walk = g_slist_next (walk)) {
- pad = (GstOggPad *) walk->data;
+ ret = gst_ogg_demux_get_next_page (ogg, &og, -1);
+ if (ret < 0 || !ogg_page_bos (&og))
+ break;
- if (pad->serial == serial)
- goto out;
- }
- pad = gst_ogg_pad_new (ogg, serial);
- ogg->unordered = g_slist_prepend (ogg->unordered, pad);
+ if (chain == NULL) {
+ chain = gst_ogg_chain_new (ogg);
+ chain->offset = offset;
+ }
-out:
- /* update start and end pointer if applicable */
- gst_ogg_pad_populate (ogg, pad, page);
+ serial = ogg_page_serialno (&og);
+ pad = gst_ogg_chain_new_stream (chain, serial);
+ pad->first_granule = ogg_page_granulepos (&og);
+ pad->current_granule = pad->first_granule;
+ pad->last_granule = 0;
+ chain->have_bos = TRUE;
+ }
- return pad;
+ return chain;
}
+/* find a pad with a given serial number
+ */
static GstOggPad *
-gst_ogg_pad_get (GstOggDemux * ogg, ogg_page * page)
-{
- GstOggPad *pad =
- gst_ogg_pad_get_in_current_chain (ogg, ogg_page_serialno (page));
- if (pad) {
- gst_ogg_pad_populate (ogg, pad, page);
- } else {
- pad = gst_ogg_pad_get_unordered (ogg, page);
- }
- return pad;
-}
-
-static void
-gst_ogg_add_chain (GstOggDemux * ogg)
+gst_ogg_demux_find_pad (GstOggDemux * ogg, int serialno)
{
- GST_LOG_OBJECT (ogg, "adding chain %u", ogg->chains->len);
- ogg->current_chain = ogg->chains->len;
- g_array_set_size (ogg->chains, ogg->chains->len + 1);
-}
+ GstOggPad *pad;
+ gint i;
-/* abort setup phase and just start playing */
-static void
-abort_setup (GstOggDemux * ogg)
-{
- gst_ogg_print (ogg);
- gst_ogg_chains_clear (ogg);
- gst_ogg_start_playing (ogg);
-}
+ for (i = 0; i < ogg->chains->len; i++) {
+ GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
-#undef GST_CAT_DEFAULT
-#define GST_CAT_DEFAULT gst_ogg_demux_setup_debug
-static gboolean
-gst_ogg_demux_set_setup_state (GstOggDemux * ogg, GstOggSetupState state)
-{
- g_assert (ogg->state == GST_OGG_STATE_SETUP);
- g_assert (state > 0);
- g_assert (state < G_N_ELEMENTS (setup_funcs));
- g_assert (state != ogg->setup_state);
-
- GST_DEBUG_OBJECT (ogg, "setting setup state from %d to %d", ogg->setup_state,
- state);
- ogg->setup_state = state;
- if (!setup_funcs[state].init (ogg)) {
- abort_setup (ogg);
- return FALSE;
+ pad = gst_ogg_chain_get_stream (chain, serialno);
+ if (pad)
+ return pad;
}
-
- return TRUE;
+ return NULL;
}
-/* seeks to the given position if TRUE is returned. Seeks a bit before this
- * offset for syncing. You can call this function multiple times, if sync
- * failed, it will then seek further back. It will never seek further back as
- * min_offset though.
+/* find all the chains in the ogg file, this reads the first and
+ * last page of the ogg stream, if they match then the ogg file has
+ * just one chain, else we do a binary search for all chains.
*/
static gboolean
-gst_ogg_demux_seek_before (GstOggDemux * ogg, gint64 offset, gint64 min_offset)
+gst_ogg_demux_find_chains (GstOggDemux * ogg)
{
- gint64 before;
+ ogg_page og;
+ GstPad *peer;
+ GstFormat format;
+ gboolean res;
+ gulong serialno;
GstOggChain *chain;
- gint streams;
- /* figure out how many streams are in this chain */
- chain = CURRENT_CHAIN (ogg);
- if (chain) {
- streams = g_slist_length (chain->pads);
+ /* get peer to figure out length */
+ if ((peer = gst_pad_get_peer (ogg->sinkpad)) == NULL)
+ goto no_peer;
+
+ /* find length to read last page, we store this for later use. */
+ format = GST_FORMAT_BYTES;
+ res = gst_pad_query (peer, GST_QUERY_TOTAL, &format, &ogg->length);
+ gst_object_unref (GST_OBJECT (peer));
+ if (!res)
+ goto no_length;
+
+ /* read chain from offset 0, this is the first chain of the
+ * ogg file. */
+ gst_ogg_demux_seek (ogg, 0);
+ chain = gst_ogg_demux_read_chain (ogg);
+
+ /* read page from end offset, we use this page to check if its serial
+ * number is contained in the first chain. If this is the case then
+ * this ogg is not a chained ogg and we can skip the scanning. */
+ gst_ogg_demux_seek (ogg, ogg->length);
+ gst_ogg_demux_get_prev_page (ogg, &og);
+ serialno = ogg_page_serialno (&og);
+
+ if (!gst_ogg_chain_has_stream (chain, serialno)) {
+ /* the last page is not in the first stream, this means we should
+ * find all the chains in this chained ogg. */
+ gst_ogg_demux_bisect_forward_serialno (ogg, 0, 0, ogg->length, chain, 0);
} else {
- streams = 1;
+ /* we still call this function here but with an empty range so that
+ * we can reuse the setup code in this routine. */
+ gst_ogg_demux_bisect_forward_serialno (ogg, 0, ogg->length, ogg->length,
+ chain, 0);
}
+ /* now dump our chains and streams */
+ gst_ogg_print (ogg);
- /* need to multiply the expected page size with the numer of streams we
- * detected to have a good chance of finding all pages */
- before = ogg->seek_skipped ? ogg->seek_skipped * SETUP_SEEK_MULTIPLIER :
- SETUP_EXPECTED_PAGE_SIZE * streams;
+ return TRUE;
- GST_DEBUG_OBJECT (ogg,
- "seeking to %" G_GINT64_FORMAT " bytes before %" G_GINT64_FORMAT,
- before, offset);
- /* tried to seek to start once, don't try again */
- if (min_offset + ogg->seek_skipped > offset)
+ /*** error cases ***/
+no_peer:
+ {
+ GST_DEBUG ("we don't have a peer");
return FALSE;
- if (gst_file_pad_seek (ogg->sinkpad, MAX (min_offset, offset - before),
- GST_SEEK_METHOD_SET) != 0)
+ }
+no_length:
+ {
+ GST_DEBUG ("can't get file length");
return FALSE;
- ogg_sync_clear (&ogg->sync);
- ogg->seek_skipped = before;
- ogg->seek_to = offset;
-
- return TRUE;
+ }
}
-static gboolean
-_read_bos_init (GstOggDemux * ogg)
+/* streaming mode, receive a buffer, parse it, create pads for
+ * the serialno, submit pages and packets to the oggpads
+ */
+static GstFlowReturn
+gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
{
- gst_ogg_add_chain (ogg);
-
- return TRUE;
-}
+ GstOggDemux *ogg;
+ gint ret = -1;
+ GstFlowReturn result = GST_FLOW_OK;
-static gboolean
-_read_bos_process (GstOggDemux * ogg, ogg_page * page)
-{
- /* here we're reading in the bos pages of the current chain */
- if (ogg_page_bos (page)) {
- GstOggPad *pad;
+ ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
- GST_LOG_OBJECT (ogg,
- "SETUP_READ_BOS: bos found with serial %d, adding to current chain",
- ogg_page_serialno (page));
- pad = gst_ogg_pad_get_unordered (ogg, page);
- ogg->unordered = g_slist_remove (ogg->unordered, pad);
- g_assert (CURRENT_CHAIN (ogg));
- CURRENT_CHAIN (ogg)->pads =
- g_slist_prepend (CURRENT_CHAIN (ogg)->pads, pad);
- } else {
- gboolean have_all_first_pages = TRUE;
+ GST_DEBUG ("chain");
+ gst_ogg_demux_submit_buffer (ogg, buffer);
- if (CURRENT_CHAIN (ogg)->pads == NULL) {
- GST_ERROR_OBJECT (ogg, "broken ogg stream, chain has no BOS pages");
- return FALSE;
- }
+ while (ret != 0 && result == GST_FLOW_OK) {
+ ogg_page page;
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, if (pad->start == (guint64) - 1)
- have_all_first_pages = FALSE;);
-
- if (have_all_first_pages) {
- GST_DEBUG_OBJECT (ogg,
- "SETUP_READ_BOS: no more bos pages, going to find end of stream");
- if (ogg->setup_state == SETUP_READ_FIRST_BOS) {
- return gst_ogg_demux_set_setup_state (ogg, SETUP_FIND_LAST_CHAIN);
- } else if (ogg->unordered) {
- return gst_ogg_demux_set_setup_state (ogg,
- SETUP_FIND_END_OF_LAST_STREAMS);
- } else {
- return gst_ogg_demux_set_setup_state (ogg, SETUP_FIND_END_OF_STREAMS);
- }
+ ret = ogg_sync_pageout (&ogg->sync, &page);
+ if (ret == 0)
+ /* need more data */
+ break;
+ if (ret == -1) {
+ /* discontinuity in the pages */
} else {
- GstOggPad *pad =
- gst_ogg_pad_get_in_current_chain (ogg, ogg_page_serialno (page));
+ GstOggPad *pad;
+ guint serialno;
- gst_ogg_pad_populate (ogg, pad, page);
- }
- }
- return TRUE;
-}
+ serialno = ogg_page_serialno (&page);
-static gboolean
-_find_chain_get_unknown_part (GstOggDemux * ogg, gint64 * start, gint64 * end)
-{
- *start = 0;
- *end = G_MAXINT64;
-
- g_assert (ogg->current_chain >= 0);
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset););
-
- if (ogg->setup_state == SETUP_FIND_LAST_CHAIN) {
- *end = gst_file_pad_get_length (ogg->sinkpad);
- if (*end < 0)
- return FALSE;
- } else {
- GSList *walk;
-
- g_assert (ogg->unordered != NULL);
- for (walk = ogg->unordered; walk; walk = g_slist_next (walk)) {
- GstOggPad *temp = walk->data;
-
- *end = MIN (*end, temp->start_offset);
+ GST_LOG_OBJECT (ogg,
+ "processing ogg page (serial %d, pageno %ld, granule pos %llu, bos %d)",
+ serialno, ogg_page_pageno (&page),
+ ogg_page_granulepos (&page), ogg_page_bos (&page));
+
+ if (ogg_page_bos (&page)) {
+ /* first page */
+ if (ogg->state == OGG_STATE_STREAMING) {
+ /* FIXME, remove previous pads since this is a new BOS when
+ * we were in streaming mode. */
+ ogg->state = OGG_STATE_NEW_CHAIN;
+ }
+ pad = gst_ogg_demux_find_pad (ogg, serialno);
+ if (pad == NULL) {
+ if (ogg->building_chain == NULL) {
+ ogg->building_chain = gst_ogg_chain_new (ogg);
+ ogg->building_chain->offset = 0;
+ }
+ pad = gst_ogg_chain_new_stream (ogg->building_chain, serialno);
+ pad->first_granule = ogg_page_granulepos (&page);
+ }
+ } else {
+ if (ogg->building_chain) {
+ g_array_append_val (ogg->chains, ogg->building_chain);
+ ogg->building_chain = NULL;
+ }
+ ogg->state = OGG_STATE_STREAMING;
+ pad = gst_ogg_demux_find_pad (ogg, serialno);
+ }
+ if (pad) {
+ result = gst_ogg_pad_submit_page (pad, &page);
+ } else {
+ GST_LOG_OBJECT (ogg, "cannot find pad for serial %d", serialno);
+ }
}
}
- GST_DEBUG_OBJECT (ogg, "we're looking for a new chain in the range [%"
- G_GINT64_FORMAT ", %" G_GINT64_FORMAT "]", *start, *end);
+ gst_buffer_unref (buffer);
- /* overlapping chains?! */
- if (*end < *start) {
- GST_ERROR_OBJECT (ogg, "chained streams overlap, bailing out");
- return FALSE;
- }
-
- return TRUE;
+ return result;
}
+/* random access code
+ *
+ * - first find all the chains and streams by scanning the
+ * file.
+ * - then get and chain buffers, just like the streaming
+ * case.
+ * - when seeking, we can use the chain info to perform the
+ * seek.
+ */
static gboolean
-_find_last_chain_init (GstOggDemux * ogg)
+gst_ogg_demux_loop (GstOggPad * pad)
{
- gint64 end = gst_file_pad_get_length (ogg->sinkpad);
+ GstOggDemux *ogg;
- ogg->seek_skipped = 0;
- if (end < 0)
- return FALSE;
- if (!gst_ogg_demux_seek_before (ogg, end, 0))
- return FALSE;
- return TRUE;
-}
+ ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
-static gboolean
-_find_last_chain_process (GstOggDemux * ogg, ogg_page * page)
-{
- GstOggPad *pad = gst_ogg_pad_get (ogg, page);
+ gst_ogg_demux_find_chains (ogg);
- /* optimization: set eos as found - we're investigating last pages here anyway */
- pad->end_found = TRUE;
- /* set to 0 to indicate we found a page */
- ogg->seek_skipped = 0;
- return TRUE;
-}
+ ogg->offset = 0;
+ while (TRUE) {
+ GstFlowReturn ret;
+ GstBuffer *buffer;
-static gboolean
-_find_chain_seek (GstOggDemux * ogg, gint64 start, gint64 end)
-{
- if (end - start < SETUP_PASSTHROUGH_SIZE) {
- GST_LOG_OBJECT (ogg,
- "iterating through remaining window, because it's smaller than %u bytes",
- SETUP_PASSTHROUGH_SIZE);
- if (ogg->seek_to >= start) {
- ogg->seek_skipped = 0;
- if (!gst_ogg_demux_seek_before (ogg, start, start))
- return FALSE;
- }
- } else {
- if (!gst_ogg_demux_seek_before (ogg, (start + end) / 2, start))
+ GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset);
+ if (ogg->offset == ogg->length)
return FALSE;
- }
- return TRUE;
-}
-static gboolean
-_find_chain_init (GstOggDemux * ogg)
-{
- gint64 start, end;
-
- ogg->seek_skipped = 0;
- ogg->seek_to = -1;
- if (!_find_chain_get_unknown_part (ogg, &start, &end))
- return FALSE;
- if (!_find_chain_seek (ogg, start, end))
- return FALSE;
- return TRUE;
-}
-
-static gboolean
-_find_chain_process (GstOggDemux * ogg, ogg_page * page)
-{
- gint64 start, end;
-
- if (!_find_chain_get_unknown_part (ogg, &start, &end))
- return FALSE;
-
- if (ogg->seek_to <= start && gst_ogg_demux_position (ogg) > end) {
- /* we now should have the first bos page, because
- * - we seeked to a point in the known chain
- * - we're now in a part that belongs to the unordered streams
- */
- g_assert (g_slist_find (ogg->unordered, gst_ogg_pad_get (ogg, page)));
- if (!ogg_page_bos (page)) {
- /* broken stream */
+ ret = gst_pad_pull_range (ogg->sinkpad, ogg->offset, CHUNKSIZE, &buffer);
+ if (ret != GST_FLOW_OK) {
+ GST_LOG_OBJECT (ogg, "got error %d", ret);
return FALSE;
}
- if (!gst_ogg_demux_set_setup_state (ogg, SETUP_READ_BOS))
- return FALSE;
- return _read_bos_process (ogg, page);
- } else {
- if (!_find_chain_seek (ogg, start, end))
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-_find_streams_check (GstOggDemux * ogg)
-{
- gint chain_nr = ogg->setup_state == SETUP_FIND_END_OF_LAST_STREAMS ?
- ogg->chains->len - 1 : ogg->chains->len - 2;
- gint64 endpos;
+ ogg->offset += GST_BUFFER_SIZE (buffer);
- /* figure out positions */
- if (ogg->setup_state == SETUP_FIND_END_OF_LAST_STREAMS) {
- if ((endpos = gst_file_pad_get_length (ogg->sinkpad)) < 0)
+ ret = gst_ogg_demux_chain (ogg->sinkpad, buffer);
+ if (ret != GST_FLOW_OK) {
+ GST_LOG_OBJECT (ogg, "got error %d", ret);
return FALSE;
- } else {
- endpos = G_MAXINT64;
- FOR_PAD_IN_CHAIN (ogg, pad, ogg->chains->len - 1,
- endpos = MIN (endpos, pad->start_offset););
- }
- if (!ogg->seek_skipped || gst_ogg_demux_position (ogg) >= endpos) {
- /* have we found the endposition for all streams yet? */
- FOR_PAD_IN_CHAIN (ogg, pad, chain_nr, if (!pad->end_offset)
- goto go_on;);
- /* get out, we're done */
- ogg->seek_skipped = 0;
- ogg->seek_to = -1;
- if (ogg->unordered) {
- ogg->setup_state = SETUP_FIND_END_OF_CHAIN;
- } else {
- gst_ogg_start_playing (ogg);
}
- return TRUE;
- go_on:
- if (!gst_ogg_demux_seek_before (ogg, endpos, 0))
- return FALSE;
}
-
return TRUE;
}
static gboolean
-_find_streams_init (GstOggDemux * ogg)
-{
- ogg->seek_skipped = 0;
- ogg->seek_to = -1;
- return _find_streams_check (ogg);
-}
-
-static gboolean
-_find_streams_process (GstOggDemux * ogg, ogg_page * page)
-{
- gint chain_nr = ogg->setup_state == SETUP_FIND_END_OF_LAST_STREAMS ?
- ogg->chains->len - 1 : ogg->chains->len - 2;
-
- g_assert (ogg->setup_state == SETUP_FIND_END_OF_LAST_STREAMS ||
- ogg->setup_state == SETUP_FIND_END_OF_STREAMS);
- g_assert (chain_nr >= 0);
- /* mark current pad as having an endframe */
- if (ogg->seek_skipped) {
- GstOggPad *pad =
- gst_ogg_pad_get_in_chain (ogg, chain_nr, ogg_page_serialno (page));
- if (pad) {
- pad->end_offset = TRUE;
- g_print ("marking pad %d as having an end\n", pad->serial);
- }
- }
- return _find_streams_check (ogg);
-}
-
-#undef GST_CAT_DEFAULT
-#define GST_CAT_DEFAULT gst_ogg_demux_debug
-
-static void
-gst_ogg_demux_iterate (GstFilePad * pad)
+gst_ogg_demux_sink_activate (GstPad * sinkpad, GstActivateMode mode)
{
+ gboolean result = FALSE;
GstOggDemux *ogg;
- guint8 *data;
- guint available;
- int pageout_ret = 1;
- gint64 offset_end;
-
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (GST_PAD (pad)));
-
- available = gst_file_pad_available (ogg->sinkpad);
- if (available == 0) {
- if (gst_file_pad_eof (ogg->sinkpad)) {
- gst_ogg_demux_eos (ogg);
- } else {
- GST_DEBUG_OBJECT (ogg, "no data available, doing nothing");
- }
- if (ogg->state != GST_OGG_STATE_SETUP)
- return;
- }
- GST_LOG_OBJECT (ogg, "queueing next %u bytes of data", available);
- data = (guint8 *) ogg_sync_buffer (&ogg->sync, available);
- if ((available = gst_file_pad_read (ogg->sinkpad, data, available)) < 0) {
- GST_ERROR_OBJECT (ogg, "error %u reading data from pad",
- gst_file_pad_error (ogg->sinkpad));
- return;
- }
- if (ogg_sync_wrote (&ogg->sync, available) != 0) {
- GST_ELEMENT_ERROR (ogg, LIBRARY, TOO_LAZY, (NULL),
- ("ogg_sync_wrote failed"));
- return;
- }
- offset_end = gst_file_pad_tell (ogg->sinkpad);
- g_assert (offset_end >= 0); /* FIXME: do sth reasonable if no length available */
- while (pageout_ret != 0) {
- ogg_page page;
-
- pageout_ret = ogg_sync_pageout (&ogg->sync, &page);
- switch (pageout_ret) {
- case -1:
- /* FIXME: need some kind of discont here, we don't know any values to send though,
- * we only have the END_OFFSET */
- break;
- case 0:
- if (ogg->state == GST_OGG_STATE_SETUP) {
- if (gst_file_pad_get_length (ogg->sinkpad) <= offset_end) {
- if (ogg->seek_skipped) {
- if (!gst_ogg_demux_seek_before (ogg,
- gst_file_pad_get_length (ogg->sinkpad), 0))
- abort_setup (ogg);
- } else if (ogg->setup_state == SETUP_FIND_LAST_CHAIN) {
- if (ogg->unordered) {
- if (!gst_ogg_demux_seek_before (ogg, offset_end / 2, 0))
- abort_setup (ogg);
- if (!gst_ogg_demux_set_setup_state (ogg,
- SETUP_FIND_END_OF_CHAIN))
- goto out;
- } else {
- if (!gst_ogg_demux_set_setup_state (ogg,
- SETUP_FIND_END_OF_LAST_STREAMS))
- goto out;
- }
- } else {
- abort_setup (ogg);
- }
- goto out;
- }
- }
- break;
- case 1:
- GST_LOG_OBJECT (ogg,
- "processing ogg page (serial %d, packet %ld, granule pos %llu, state: %d, bos %d)",
- ogg_page_serialno (&page), ogg_page_pageno (&page),
- ogg_page_granulepos (&page), ogg->state, ogg_page_bos (&page));
- switch (ogg->state) {
- case GST_OGG_STATE_SETUP:
- if (!setup_funcs[ogg->setup_state].process (ogg, &page)) {
- abort_setup (ogg);
- goto out;
- }
- break;
- case GST_OGG_STATE_START:
- if (gst_file_pad_seek (ogg->sinkpad, 0, GST_SEEK_METHOD_END) == 0) {
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SETUP);
- GST_DEBUG_OBJECT (ogg, "stream can seek, try setup now");
- if (gst_file_pad_seek (ogg->sinkpad, 0, GST_SEEK_METHOD_SET) != 0) {
- GST_ELEMENT_ERROR (ogg, CORE, SEEK, (NULL),
- ("stream can seek to end, but not to start. Can't handle that."));
- }
- ogg_sync_clear (&ogg->sync);
- gst_ogg_add_chain (ogg);
- GST_FLAG_SET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT);
- goto out;
- } else {
- GST_DEBUG_OBJECT (ogg, "stream can not seek");
- gst_ogg_add_chain (ogg);
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_PLAY);
- }
- /* fall through */
- case GST_OGG_STATE_SEEK:
- case GST_OGG_STATE_PLAY:
- gst_ogg_demux_push (ogg, &page);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- break;
- default:
- GST_WARNING_OBJECT (ogg,
- "unknown return value %d from ogg_sync_pageout", pageout_ret);
- pageout_ret = 0;
- break;
- }
- }
-out:
- return;
-}
-static GstOggPad *
-gst_ogg_pad_new (GstOggDemux * ogg, int serial)
-{
- GstOggPad *ret = g_new0 (GstOggPad, 1);
- GstTagList *list = gst_tag_list_new ();
-
- ret->serial = serial;
- if (ogg_stream_init (&ret->stream, serial) != 0) {
- GST_ERROR_OBJECT (ogg,
- "Could not initialize ogg_stream struct for serial %d.", serial);
- g_free (ret);
- return NULL;
- }
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serial, NULL);
- gst_element_found_tags (GST_ELEMENT (ogg), list);
- gst_tag_list_free (list);
-
- GST_LOG_OBJECT (ogg, "created new ogg src %p for stream with serial %d", ret,
- serial);
- ret->start_offset = ret->end_offset = -1;
- ret->start = -1;
- ret->start_found = ret->end_found = FALSE;
-
- return ret;
-}
-static void
-gst_ogg_pad_remove (GstOggDemux * ogg, GstOggPad * pad)
-{
- if (pad->pad) {
- /* FIXME:
- * we do it in the EOS signal already - EOS handling needs to be better thought out.
- * Correct way would be pushing EOS on eos page, but scheduler doesn't like that
- */
- if (GST_PAD_IS_USABLE (pad->pad))
- gst_pad_push (pad->pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
-
- gst_element_remove_pad (GST_ELEMENT (ogg), pad->pad);
- pad->pad = NULL;
- }
- if (ogg_stream_clear (&pad->stream) != 0)
- GST_ERROR_OBJECT (ogg,
- "ogg_stream_clear (serial %d) did not return 0, ignoring this error",
- pad->serial);
- GST_LOG_OBJECT (ogg, "free ogg src %p for stream with serial %d", pad,
- pad->serial);
- g_free (pad);
-}
-static void
-gst_ogg_demux_push (GstOggDemux * ogg, ogg_page * page)
-{
- GstOggPad *cur =
- gst_ogg_pad_get_in_current_chain (ogg, ogg_page_serialno (page));
-
- /* now we either have a stream (cur) or not */
- if (ogg_page_bos (page)) {
- if (cur) {
- GST_DEBUG_OBJECT (ogg,
- "ogg page declared as BOS while stream %d already existed."
- "Possibly a seek happened.", cur->serial);
- } else if (cur) {
- GST_DEBUG_OBJECT (ogg, "reactivating deactivated stream %d.",
- cur->serial);
- } else {
- /* FIXME: monitor if we are still in creation stage? */
- cur = gst_ogg_pad_new (ogg, ogg_page_serialno (page));
- if (!cur) {
- GST_ELEMENT_ERROR (ogg, LIBRARY, TOO_LAZY, (NULL),
- ("Creating ogg_stream struct failed."));
- return;
- }
- if (ogg->current_chain == -1) {
- /* add new one at the end */
- gst_ogg_add_chain (ogg);
- }
- CURRENT_CHAIN (ogg)->pads =
- g_slist_prepend (CURRENT_CHAIN (ogg)->pads, cur);
- }
- ogg->bos = TRUE;
- } else if (ogg->bos) {
- gst_element_no_more_pads (GST_ELEMENT (ogg));
- ogg->bos = FALSE;
- }
- if (cur == NULL) {
- GST_ELEMENT_ERROR (ogg, STREAM, DECODE, (NULL),
- ("invalid ogg stream serial no"));
- return;
- }
- if (ogg_stream_pagein (&cur->stream, page) != 0) {
- GST_WARNING_OBJECT (ogg,
- "ogg stream choked on page (serial %d), resetting stream", cur->serial);
- gst_ogg_pad_reset (ogg, cur);
- return;
- }
- switch (ogg->state) {
- case GST_OGG_STATE_SEEK:
- GST_LOG_OBJECT (ogg,
- "in seek - offset now: %" G_GUINT64_FORMAT
- " (pad %d) - desired offset %" G_GUINT64_FORMAT " (pad %d)",
- cur->known_offset, cur->serial, ogg->seek_to, ogg->seek_pad->serial);
-
- if (cur != ogg->seek_pad) {
- break;
- } else {
- gint64 position, diff;
- gdouble ratio;
-
- /* see if we reached the destination position when seeking */
- position = get_relative (ogg, cur, ogg_page_granulepos (page),
- GST_FORMAT_TIME);
- /* Note: ogg->seek_to is already in GST_FORMAT_TIME... */
- if (position == -1) {
- /* let's just stop then */
- goto play;
- }
- /* fairly random treshold. */
- if (ogg->seek_to > position)
- diff = ogg->seek_to - position;
- else
- diff = position - ogg->seek_to;
- if (diff < GST_SECOND) {
- GST_DEBUG ("Close enough (%" GST_TIME_FORMAT " seconds off)",
- GST_TIME_ARGS (diff));
- ogg->seek_to = position;
- goto play;
- }
-
- /* not too long */
- if (ogg->seek_try > 5) {
- GST_DEBUG ("Seeking took too long, continuing with current page");
- ogg->seek_to = position;
- goto play;
- }
+ ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
- /* seek again! yay */
- ratio = (gdouble) ogg->seek_to / position;
- ogg->seek_offset = ogg->seek_offset * ratio;
- if (gst_file_pad_seek (ogg->sinkpad, ogg->seek_offset,
- GST_SEEK_METHOD_SET) != 0) {
- goto play;
- }
- ogg->seek_try++;
- ogg_sync_clear (&ogg->sync);
- return;
-
- play:
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_PLAY);
- GST_DEBUG_OBJECT (ogg,
- "ended seek at offset %" G_GUINT64_FORMAT " (requested %"
- G_GUINT64_FORMAT, cur->known_offset, ogg->seek_to);
- ogg->seek_pad = NULL;
- ogg->seek_offset = 0;
- ogg->seek_try = 0;
- }
- /* fallthrough */
- case GST_OGG_STATE_PLAY:
- cur->known_offset = ogg_page_granulepos (page);
- gst_ogg_pad_push (ogg, cur);
+ switch (mode) {
+ case GST_ACTIVATE_PUSH:
break;
- default:
- g_assert_not_reached ();
+ case GST_ACTIVATE_PULL:
+ /* if we have a scheduler we can start the task */
+ if (GST_ELEMENT_SCHEDULER (ogg)) {
+ GST_STREAM_LOCK (sinkpad);
+ GST_RPAD_TASK (sinkpad) =
+ gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (ogg),
+ (GstTaskFunction) gst_ogg_demux_loop, sinkpad);
+
+ gst_task_start (GST_RPAD_TASK (sinkpad));
+ GST_STREAM_UNLOCK (sinkpad);
+ result = TRUE;
+ }
break;
- }
- if (ogg_page_eos (page)) {
- GST_DEBUG_OBJECT (ogg, "got EOS for stream with serial %d, sending EOS now",
- cur->serial);
+ case GST_ACTIVATE_NONE:
+ /* step 1, unblock clock sync (if any) */
- /* send an EOS before removing this pad */
- if (GST_PAD_IS_USABLE (cur->pad))
- gst_pad_push (cur->pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
-
- gst_element_remove_pad (GST_ELEMENT (ogg), cur->pad);
- cur->pad = NULL;
- }
-}
-static void
-gst_ogg_pad_push (GstOggDemux * ogg, GstOggPad * pad)
-{
- ogg_packet packet;
- int ret;
- GstBuffer *buf;
-
- /* Hack. If someone connects to the push (or any related) signal and
- * goes to READY, the pad will be destroyed and the next line will
- * segfault. This does not work on PLAY -> READY -> PLAY. */
- while (GST_STATE (ogg) >= GST_STATE_PAUSED) {
- ret = ogg_stream_packetout (&pad->stream, &packet);
- GST_LOG_OBJECT (ogg, "packetout gave %d", ret);
- switch (ret) {
- case 0:
- return;
- case -1:
- /* out of sync, could call gst_ogg_pad_reset() here but ogg can decode
- * the packet just fine. We should probably send a DISCONT though. */
- break;
- case 1:{
- gint64 pos = -1;
-
- /* only push data when playing, not during seek or similar */
- if (ogg->state != GST_OGG_STATE_PLAY)
- continue;
- if (!pad->pad) {
- GstCaps *caps = gst_ogg_type_find (&packet);
- gchar *name = g_strdup_printf ("serial_%d", pad->serial);
-
- if (caps == NULL) {
- GST_WARNING_OBJECT (ogg,
- "couldn't find caps for stream with serial %d", pad->serial);
- caps = gst_caps_new_simple ("application/octet-stream", NULL);
- }
- pad->pad =
- gst_pad_new_from_template (gst_static_pad_template_get
- (&ogg_demux_src_template_factory), name);
- g_free (name);
- gst_pad_set_event_function (pad->pad,
- GST_DEBUG_FUNCPTR (gst_ogg_demux_src_event));
- gst_pad_set_event_mask_function (pad->pad,
- GST_DEBUG_FUNCPTR (gst_ogg_demux_get_event_masks));
- gst_pad_set_query_function (pad->pad,
- GST_DEBUG_FUNCPTR (gst_ogg_demux_src_query));
- gst_pad_set_query_type_function (pad->pad,
- GST_DEBUG_FUNCPTR (gst_ogg_demux_get_query_types));
- gst_pad_set_formats_function (pad->pad,
- GST_DEBUG_FUNCPTR (gst_ogg_demux_get_formats));
- gst_pad_set_convert_function (pad->pad,
- GST_DEBUG_FUNCPTR (gst_ogg_demux_src_convert));
-
- gst_pad_use_explicit_caps (pad->pad);
- gst_pad_set_explicit_caps (pad->pad, caps);
- gst_caps_free (caps);
- gst_pad_set_active (pad->pad, TRUE);
- gst_element_add_pad (GST_ELEMENT (ogg), pad->pad);
- }
- /* check for discont */
- if (packet.packetno != pad->packetno++) {
- pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;
- pad->packetno = packet.packetno + 1;
- }
+ /* step 2, make sure streaming finishes */
+ GST_STREAM_LOCK (sinkpad);
- if (pad->known_offset != -1) {
- pos = get_relative (ogg, pad, pad->known_offset, GST_FORMAT_DEFAULT);
- }
-
- if ((pad->flags & GST_OGG_PAD_NEEDS_FLUSH)
- && GST_PAD_IS_USABLE (pad->pad)) {
- gst_pad_push (pad->pad, GST_DATA (gst_event_new (GST_EVENT_FLUSH)));
- pad->flags &= (~GST_OGG_PAD_NEEDS_FLUSH);
- }
-
- /* send discont if needed */
- if ((pad->flags & GST_OGG_PAD_NEEDS_DISCONT)
- && GST_PAD_IS_USABLE (pad->pad)) {
- /* so in order to synchronized the variety of streams, we will
- * not use the granpos but the last seekpos for the discont. */
- GstFormat fmt;
- GstEvent *event;
- gint64 discont;
-
- if (pos != -1) {
- fmt = GST_FORMAT_DEFAULT;
- if (!GST_PAD_PEER (pad->pad) ||
- !gst_pad_convert (GST_PAD_PEER (pad->pad),
- ogg->seek_format, ogg->seek_to, &fmt, &discont)) {
- event = gst_event_new_discontinuous (FALSE,
- ogg->seek_format, ogg->seek_to, GST_FORMAT_UNDEFINED);
- } else {
- event = gst_event_new_discontinuous (FALSE,
- GST_FORMAT_DEFAULT, discont, GST_FORMAT_UNDEFINED);
- }
- } else {
- event = gst_event_new_discontinuous (FALSE,
- GST_FORMAT_DEFAULT, 0, GST_FORMAT_UNDEFINED);
- }
-
- /* FIXME: this might be wrong because we can only use the last
- * known offset */
-
- gst_pad_push (pad->pad, GST_DATA (event));
- pad->flags &= (~GST_OGG_PAD_NEEDS_DISCONT);
- }
-
- /* optimization: use a bufferpool containing the ogg packet? */
- buf =
- gst_pad_alloc_buffer (pad->pad, GST_BUFFER_OFFSET_NONE,
- packet.bytes);
- memcpy (buf->data, packet.packet, packet.bytes);
- if (pad->offset != -1)
- GST_BUFFER_OFFSET (buf) = pad->offset;
- if (packet.granulepos != -1 && pos != -1)
- GST_BUFFER_OFFSET_END (buf) = pos;
- pad->offset = packet.granulepos;
- if (GST_PAD_IS_USABLE (pad->pad))
- gst_pad_push (pad->pad, GST_DATA (buf));
- break;
+ /* step 3, stop the task */
+ if (GST_RPAD_TASK (sinkpad)) {
+ gst_task_stop (GST_RPAD_TASK (sinkpad));
+ gst_object_unref (GST_OBJECT (GST_RPAD_TASK (sinkpad)));
+ GST_RPAD_TASK (sinkpad) = NULL;
}
- default:
- GST_ERROR_OBJECT (ogg,
- "invalid return value %d for ogg_stream_packetout, resetting stream",
- ret);
- gst_ogg_pad_reset (ogg, pad);
- break;
- }
- }
-}
-static void
-gst_ogg_pad_reset (GstOggDemux * ogg, GstOggPad * pad)
-{
- ogg_stream_reset (&pad->stream);
- pad->offset = GST_BUFFER_OFFSET_NONE;
- /* FIXME: need a discont here */
-}
-
-static void
-gst_ogg_chains_clear (GstOggDemux * ogg)
-{
- gint i;
- GSList *walk;
-
- for (i = ogg->chains->len - 1; i >= 0; i--) {
- GstOggChain *cur = &g_array_index (ogg->chains, GstOggChain, i);
+ GST_STREAM_UNLOCK (sinkpad);
- for (walk = cur->pads; walk; walk = g_slist_next (walk)) {
- gst_ogg_pad_remove (ogg, (GstOggPad *) walk->data);
- }
- g_slist_free (cur->pads);
- cur->pads = NULL;
- g_array_remove_index (ogg->chains, i);
+ result = TRUE;
+ break;
}
- ogg->current_chain = -1;
+ return result;
}
static GstElementStateReturn
gst_ogg_demux_change_state (GstElement * element)
{
GstOggDemux *ogg;
+ GstElementStateReturn result = GST_STATE_FAILURE;
ogg = GST_OGG_DEMUX (element);
@@ -1628,13 +1111,14 @@ gst_ogg_demux_change_state (GstElement * element)
break;
case GST_STATE_PAUSED_TO_PLAYING:
break;
+ }
+
+ result = parent_class->change_state (element);
+
+ switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
- gst_ogg_chains_clear (ogg);
- GST_OGG_SET_STATE (ogg, GST_OGG_STATE_START);
- ogg->seek_pad = NULL;
- ogg->seek_to = 0;
break;
case GST_STATE_READY_TO_NULL:
ogg_sync_clear (&ogg->sync);
@@ -1642,8 +1126,7 @@ gst_ogg_demux_change_state (GstElement * element)
default:
break;
}
-
- return parent_class->change_state (element);
+ return result;
}
/*** typefinding **************************************************************/
@@ -1736,38 +1219,23 @@ gst_ogg_print (GstOggDemux * ogg)
#else /* !GST_DISABLE_GST_DEBUG */
-#define gst_ogg_print_pad(ogg, _pad) \
-G_STMT_START{\
- GstOggPad *pad = (_pad); \
- GST_INFO_OBJECT (ogg, " stream %d:", pad->serial); \
- GST_INFO_OBJECT (ogg, " length %" G_GUINT64_FORMAT, pad->length); \
- GST_INFO_OBJECT (ogg, " pages %ld", pad->pages); \
- GST_INFO_OBJECT (ogg, " offset: %"G_GINT64_FORMAT"%s - %"G_GINT64_FORMAT"%s", \
- pad->start_offset, pad->start_found ? "" : " (?)", \
- pad->end_offset, pad->end_found ? "" : " (?)"); \
-}G_STMT_END
static void
gst_ogg_print (GstOggDemux * ogg)
{
- guint i;
- GSList *walk;
+ guint j, i;
for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = &g_array_index (ogg->chains, GstOggChain, i);
+ GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
- GST_INFO_OBJECT (ogg, "chain %d (%u streams):", i,
- g_slist_length (chain->pads));
- for (walk = chain->pads; walk; walk = g_slist_next (walk)) {
- gst_ogg_print_pad (ogg, walk->data);
- }
- }
- if (ogg->unordered) {
- GST_INFO_OBJECT (ogg, "unordered (%u streams):", i,
- g_slist_length (ogg->unordered));
- for (walk = ogg->unordered; walk; walk = g_slist_next (walk)) {
- gst_ogg_print_pad (ogg, walk->data);
+ GST_INFO_OBJECT (ogg, "chain %d (%u streams):", i, chain->streams->len);
+ GST_INFO_OBJECT (ogg, " offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT,
+ chain->offset, chain->end_offset);
+
+ for (j = 0; j < chain->streams->len; j++) {
+ GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j);
+
+ GST_INFO_OBJECT (ogg, " stream %08lx:", stream->serialno);
}
}
-
}
#endif /* GST_DISABLE_GST_DEBUG */
diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c
index 164970b66..121875291 100644
--- a/ext/ogg/gstoggmux.c
+++ b/ext/ogg/gstoggmux.c
@@ -219,6 +219,9 @@ gst_ogg_mux_class_init (GstOggMuxClass * klass)
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ gobject_class->get_property = gst_ogg_mux_get_property;
+ gobject_class->set_property = gst_ogg_mux_set_property;
+
gstelement_class->request_new_pad = gst_ogg_mux_request_new_pad;
g_object_class_install_property (gobject_class, ARG_MAX_DELAY,
@@ -232,8 +235,6 @@ gst_ogg_mux_class_init (GstOggMuxClass * klass)
gstelement_class->change_state = gst_ogg_mux_change_state;
- gstelement_class->get_property = gst_ogg_mux_get_property;
- gstelement_class->set_property = gst_ogg_mux_set_property;
}
static const GstEventMask *
@@ -259,7 +260,6 @@ gst_ogg_mux_init (GstOggMux * ogg_mux)
gst_pad_set_event_function (ogg_mux->srcpad, gst_ogg_mux_handle_src_event);
gst_element_add_pad (GST_ELEMENT (ogg_mux), ogg_mux->srcpad);
- GST_FLAG_SET (GST_ELEMENT (ogg_mux), GST_ELEMENT_EVENT_AWARE);
GST_FLAG_SET (GST_ELEMENT (ogg_mux), GST_OGG_FLAG_BOS);
/* seed random number generator for creation of serial numbers */
@@ -273,24 +273,20 @@ gst_ogg_mux_init (GstOggMux * ogg_mux)
ogg_mux->delta_pad = NULL;
- gst_element_set_loop_function (GST_ELEMENT (ogg_mux), gst_ogg_mux_loop);
+ //gst_element_set_loop_function (GST_ELEMENT (ogg_mux), gst_ogg_mux_loop);
+ gst_ogg_mux_loop (GST_ELEMENT (ogg_mux));
}
static GstPadLinkReturn
-gst_ogg_mux_sinkconnect (GstPad * pad, const GstCaps * vscaps)
+gst_ogg_mux_sinkconnect (GstPad * pad, GstPad * peer)
{
GstOggMux *ogg_mux;
- GstStructure *structure;
- const gchar *mimetype;
ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
GST_DEBUG_OBJECT (ogg_mux, "sinkconnect triggered on %s",
gst_pad_get_name (pad));
- structure = gst_caps_get_structure (vscaps, 0);
- mimetype = gst_structure_get_name (structure);
-
return GST_PAD_LINK_OK;
}
@@ -412,9 +408,10 @@ static GstBuffer *
gst_ogg_mux_next_buffer (GstOggPad * pad, gboolean * interrupt)
{
GstData *data = NULL;
+ GstBuffer *buffer = NULL;
- while (data == NULL) {
- data = gst_pad_pull (pad->pad);
+ while (buffer == NULL) {
+ //gst_pad_pull (pad->pad, &buffer);
GST_DEBUG ("muxer: pulled %s:%s %p", GST_DEBUG_PAD_NAME (pad->pad), data);
/* if it's an event, handle it */
if (GST_IS_EVENT (data)) {
@@ -430,9 +427,9 @@ gst_ogg_mux_next_buffer (GstOggPad * pad, gboolean * interrupt)
pad->eos = TRUE;
gst_event_unref (event);
return NULL;
- case GST_EVENT_INTERRUPT:
- *interrupt = TRUE;
- return NULL;
+ //case GST_EVENT_INTERRUPT:
+ // *interrupt = TRUE;
+ // return NULL;
case GST_EVENT_DISCONTINUOUS:
{
guint64 value;
@@ -489,7 +486,7 @@ gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
/* allocate space for header and body */
buffer = gst_pad_alloc_buffer (mux->srcpad, GST_BUFFER_OFFSET_NONE,
- page->header_len + page->body_len);
+ page->header_len + page->body_len, NULL);
memcpy (GST_BUFFER_DATA (buffer), page->header, page->header_len);
memcpy (GST_BUFFER_DATA (buffer) + page->header_len,
page->body, page->body_len);
@@ -511,7 +508,7 @@ gst_ogg_mux_push_page (GstOggMux * mux, ogg_page * page, gboolean delta)
if (GST_PAD_IS_USABLE (mux->srcpad)) {
GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta);
- gst_pad_push (mux->srcpad, GST_DATA (buffer));
+ gst_pad_push (mux->srcpad, buffer);
}
}
@@ -817,7 +814,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
caps = gst_pad_get_caps (mux->srcpad);
if (caps) {
gst_ogg_mux_set_header_on_caps (caps, hbufs);
- gst_pad_try_set_caps (mux->srcpad, caps);
+ //gst_pad_try_set_caps (mux->srcpad, caps);
}
/* and send the buffers */
hwalk = hbufs;
@@ -827,7 +824,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
hwalk = hwalk->next;
if (GST_PAD_IS_USABLE (mux->srcpad)) {
- gst_pad_push (mux->srcpad, GST_DATA (buf));
+ gst_pad_push (mux->srcpad, buf);
} else {
gst_buffer_unref (buf);
}
@@ -897,9 +894,8 @@ gst_ogg_mux_loop (GstElement * element)
} else {
/* no pad to pull on, send EOS */
if (GST_PAD_IS_USABLE (ogg_mux->srcpad))
- gst_pad_push (ogg_mux->srcpad,
- GST_DATA (gst_event_new (GST_EVENT_EOS)));
- gst_element_set_eos (element);
+ gst_pad_push_event (ogg_mux->srcpad, gst_event_new (GST_EVENT_EOS));
+ //gst_element_set_eos (element);
return;
}
}
diff --git a/ext/ogg/gstogmparse.c b/ext/ogg/gstogmparse.c
index 19c3cae8e..b8f52a6a3 100644
--- a/ext/ogg/gstogmparse.c
+++ b/ext/ogg/gstogmparse.c
@@ -133,7 +133,7 @@ static const GstFormat *gst_ogm_parse_get_sink_formats (GstPad * pad);
static gboolean gst_ogm_parse_sink_convert (GstPad * pad, GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-static void gst_ogm_parse_chain (GstPad * pad, GstData * data);
+static GstFlowReturn gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer);
static GstElementStateReturn gst_ogm_parse_change_state (GstElement * element);
@@ -366,11 +366,11 @@ gst_ogm_parse_sink_convert (GstPad * pad,
return res;
}
-static void
-gst_ogm_parse_chain (GstPad * pad, GstData * dat)
+static GstFlowReturn
+gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer)
{
GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
- GstBuffer *buf = GST_BUFFER (dat);
+ GstBuffer *buf = GST_BUFFER (buffer);
guint8 *data = GST_BUFFER_DATA (buf);
guint size = GST_BUFFER_SIZE (buf);
@@ -453,13 +453,13 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
}
ogm->srcpad = gst_pad_new_from_template (ogm->srcpadtempl, "src");
- gst_pad_use_explicit_caps (ogm->srcpad);
- if (!gst_pad_set_explicit_caps (ogm->srcpad, caps)) {
- GST_ELEMENT_ERROR (ogm, CORE, NEGOTIATION, (NULL), (NULL));
- //gst_object_unref (GST_OBJECT (ogm->srcpad));
- ogm->srcpad = NULL;
- break;
- }
+ //gst_pad_use_explicit_caps (ogm->srcpad);
+ //if (!gst_pad_set_explicit_caps (ogm->srcpad, caps)) {
+ // GST_ELEMENT_ERROR (ogm, CORE, NEGOTIATION, (NULL), (NULL));
+ //gst_object_unref (GST_OBJECT (ogm->srcpad));
+ // ogm->srcpad = NULL;
+ // break;
+ //}
gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
break;
}
@@ -510,7 +510,7 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
default:
g_assert_not_reached ();
}
- gst_pad_push (ogm->srcpad, GST_DATA (sbuf));
+ gst_pad_push (ogm->srcpad, sbuf);
} else {
GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
("Wrong packet startcode 0x%02x", data[0]), (NULL));
@@ -519,6 +519,8 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
}
gst_buffer_unref (buf);
+
+ return GST_FLOW_OK;
}
static GstElementStateReturn
diff --git a/ext/theora/theoradec.c b/ext/theora/theoradec.c
index 849a81fc6..74f057c76 100644
--- a/ext/theora/theoradec.c
+++ b/ext/theora/theoradec.c
@@ -109,7 +109,8 @@ static void theora_dec_get_property (GObject * object, guint prop_id,
static void theora_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
-static void theora_dec_chain (GstPad * pad, GstData * data);
+static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
static GstElementStateReturn theora_dec_change_state (GstElement * element);
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
static gboolean theora_dec_src_query (GstPad * pad,
@@ -164,13 +165,13 @@ gst_theora_dec_init (GstTheoraDec * dec)
(&theora_dec_sink_factory), "sink");
gst_pad_set_formats_function (dec->sinkpad, theora_get_formats);
gst_pad_set_convert_function (dec->sinkpad, theora_dec_sink_convert);
+ gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
dec->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&theora_dec_src_factory), "src");
- gst_pad_use_explicit_caps (dec->srcpad);
gst_pad_set_event_mask_function (dec->srcpad, theora_get_event_masks);
gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
@@ -180,8 +181,6 @@ gst_theora_dec_init (GstTheoraDec * dec)
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
- GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
-
dec->crop = THEORA_DEF_CROP;
}
@@ -455,10 +454,13 @@ theora_dec_src_event (GstPad * pad, GstEvent * event)
return res;
}
-static void
-theora_dec_event (GstTheoraDec * dec, GstEvent * event)
+static gboolean
+theora_dec_sink_event (GstPad * pad, GstEvent * event)
{
guint64 value, time, bytes;
+ GstTheoraDec *dec;
+
+ dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (dec, "handling event");
switch (GST_EVENT_TYPE (event)) {
@@ -477,9 +479,9 @@ theora_dec_event (GstTheoraDec * dec, GstEvent * event)
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
("can't handle discont before parsing first 3 packets"));
dec->packetno = 0;
- gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE,
- GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
- (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0)));
+ gst_pad_push_event (dec->srcpad, gst_event_new_discontinuous (FALSE,
+ GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
+ (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0));
} else {
GstFormat time_format, default_format, bytes_format;
@@ -494,10 +496,9 @@ theora_dec_event (GstTheoraDec * dec, GstEvent * event)
&default_format, &value)
&& theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
&bytes_format, &bytes)) {
- gst_pad_push (dec->srcpad,
- GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
- time, GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes,
- 0)));
+ gst_pad_push_event (dec->srcpad,
+ gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
+ time, GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes, 0));
/* store new framenumber */
dec->packetno = value + 3;
} else {
@@ -511,29 +512,26 @@ theora_dec_event (GstTheoraDec * dec, GstEvent * event)
default:
break;
}
- gst_pad_event_default (dec->sinkpad, event);
+ return gst_pad_event_default (dec->sinkpad, event);
}
#define ROUND_UP_2(x) (((x) + 1) & ~1)
#define ROUND_UP_4(x) (((x) + 3) & ~3)
#define ROUND_UP_8(x) (((x) + 7) & ~7)
-static void
-theora_dec_chain (GstPad * pad, GstData * data)
+static GstFlowReturn
+theora_dec_chain (GstPad * pad, GstBuffer * buffer)
{
GstBuffer *buf;
GstTheoraDec *dec;
ogg_packet packet;
guint64 offset_end;
GstClockTime outtime;
+ GstFlowReturn result = GST_FLOW_OK;
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
- if (GST_IS_EVENT (data)) {
- theora_dec_event (dec, GST_EVENT (data));
- return;
- }
+ dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
- buf = GST_BUFFER (data);
+ buf = GST_BUFFER (buffer);
if (dec->packetno >= 3) {
offset_end = GST_BUFFER_OFFSET_END (buf);
@@ -569,6 +567,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
(NULL), ("couldn't read header packet"));
+ result = GST_FLOW_ERROR;
goto done;
}
@@ -593,7 +592,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
GST_TAG_ENCODER_VERSION, dec->info.version_major,
GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate,
GST_TAG_VIDEO_CODEC, "Theora", NULL);
- gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
+ //gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
dec->packetno++;
} else if (packet.packetno == 2) {
@@ -655,8 +654,8 @@ theora_dec_chain (GstPad * pad, GstData * data)
"pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
"width", G_TYPE_INT, dec->width, "height", G_TYPE_INT,
dec->height, NULL);
- gst_pad_set_explicit_caps (dec->srcpad, caps);
- gst_caps_free (caps);
+ gst_pad_set_caps (dec->srcpad, caps);
+ gst_caps_unref (caps);
dec->initialized = TRUE;
dec->packetno++;
@@ -675,6 +674,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
dec->packetno++;
if (!dec->initialized) {
+ result = GST_FLOW_ERROR;
goto done;
}
@@ -711,16 +711,18 @@ theora_dec_chain (GstPad * pad, GstData * data)
if (theora_decode_packetin (&dec->state, &packet)) {
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
(NULL), ("theora decoder did not read data packet"));
+ result = GST_FLOW_ERROR;
goto done;
}
if (theora_decode_YUVout (&dec->state, &yuv) < 0) {
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
(NULL), ("couldn't read out YUV image"));
+ result = GST_FLOW_ERROR;
goto done;
}
- g_return_if_fail (yuv.y_width == dec->info.width);
- g_return_if_fail (yuv.y_height == dec->info.height);
+ g_return_val_if_fail (yuv.y_width == dec->info.width, GST_FLOW_ERROR);
+ g_return_val_if_fail (yuv.y_height == dec->info.height, GST_FLOW_ERROR);
width = dec->width;
height = dec->height;
@@ -737,7 +739,8 @@ theora_dec_chain (GstPad * pad, GstData * data)
/* now copy over the area contained in offset_x,offset_y,
* frame_width, frame_height */
- out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size);
+ out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size,
+ GST_PAD_CAPS (dec->srcpad));
/* copy the visible region to the destination. This is actually pretty
* complicated and gstreamer doesn't support all the needed caps to do this
@@ -785,11 +788,13 @@ theora_dec_chain (GstPad * pad, GstData * data)
dec->info.fps_numerator;
GST_BUFFER_TIMESTAMP (out) = outtime;
- gst_pad_push (dec->srcpad, GST_DATA (out));
+ result = gst_pad_push (dec->srcpad, out);
}
done:
- gst_data_unref (data);
+ gst_buffer_unref (buffer);
dec->granulepos++;
+
+ return result;
}
static GstElementStateReturn
diff --git a/ext/theora/theoraenc.c b/ext/theora/theoraenc.c
index 3116ae7f6..58b6d99b0 100644
--- a/ext/theora/theoraenc.c
+++ b/ext/theora/theoraenc.c
@@ -170,10 +170,10 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
-static void theora_enc_chain (GstPad * pad, GstData * data);
+static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
static GstElementStateReturn theora_enc_change_state (GstElement * element);
-static GstPadLinkReturn theora_enc_sink_link (GstPad * pad,
- const GstCaps * caps);
+static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
static void theora_enc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void theora_enc_set_property (GObject * object, guint prop_id,
@@ -255,13 +255,13 @@ gst_theora_enc_init (GstTheoraEnc * enc)
gst_pad_new_from_template (gst_static_pad_template_get
(&theora_enc_sink_factory), "sink");
gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
- gst_pad_set_link_function (enc->sinkpad, theora_enc_sink_link);
+ gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
+ gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
enc->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&theora_enc_src_factory), "src");
- gst_pad_use_explicit_caps (enc->srcpad);
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
enc->center = THEORA_DEF_CENTER;
@@ -276,12 +276,10 @@ gst_theora_enc_init (GstTheoraEnc * enc)
enc->keyframe_threshold = THEORA_DEF_KEYFRAME_THRESHOLD;
enc->keyframe_mindistance = THEORA_DEF_KEYFRAME_MINDISTANCE;
enc->noise_sensitivity = THEORA_DEF_NOISE_SENSITIVITY;
-
- GST_FLAG_SET (enc, GST_ELEMENT_EVENT_AWARE);
}
-static GstPadLinkReturn
-theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
+static gboolean
+theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstStructure *structure = gst_caps_get_structure (caps, 0);
GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
@@ -289,9 +287,6 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
GValue fps = { 0 };
GValue framerate = { 0 };
- if (!gst_caps_is_fixed (caps))
- return GST_PAD_LINK_DELAYED;
-
gst_structure_get_int (structure, "width", &enc->width);
gst_structure_get_int (structure, "height", &enc->height);
gst_structure_get_double (structure, "framerate", &enc->fps);
@@ -352,7 +347,7 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
theora_encode_init (&enc->state, &enc->info);
- return GST_PAD_LINK_OK;
+ return TRUE;
}
/* prepare a buffer for transmission by passing data through libtheora */
@@ -363,7 +358,7 @@ theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
GstBuffer *buf;
buf = gst_pad_alloc_buffer (enc->srcpad,
- GST_BUFFER_OFFSET_NONE, packet->bytes);
+ GST_BUFFER_OFFSET_NONE, packet->bytes, GST_PAD_CAPS (enc->srcpad));
memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
GST_BUFFER_OFFSET (buf) = enc->bytes_out;
GST_BUFFER_OFFSET_END (buf) = packet->granulepos;
@@ -392,7 +387,7 @@ theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
enc->bytes_out += GST_BUFFER_SIZE (buffer);
if (GST_PAD_IS_USABLE (enc->srcpad)) {
- gst_pad_push (enc->srcpad, GST_DATA (buffer));
+ gst_pad_push (enc->srcpad, buffer);
} else {
gst_buffer_unref (buffer);
}
@@ -439,31 +434,38 @@ theora_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
g_value_unset (&list);
}
-static void
-theora_enc_chain (GstPad * pad, GstData * data)
+static gboolean
+theora_enc_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstTheoraEnc *enc;
+ ogg_packet op;
+
+ enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* push last packet with eos flag */
+ while (theora_encode_packetout (&enc->state, 1, &op)) {
+ GstClockTime out_time =
+ theora_granule_time (&enc->state, op.granulepos) * GST_SECOND;
+ theora_push_packet (enc, &op, out_time, GST_SECOND / enc->fps);
+ }
+ default:
+ return gst_pad_event_default (pad, event);
+ }
+}
+
+static GstFlowReturn
+theora_enc_chain (GstPad * pad, GstBuffer * buffer)
{
GstTheoraEnc *enc;
ogg_packet op;
GstBuffer *buf;
GstClockTime in_time;
- enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
- if (GST_IS_EVENT (data)) {
- switch (GST_EVENT_TYPE (data)) {
- case GST_EVENT_EOS:
- /* push last packet with eos flag */
- while (theora_encode_packetout (&enc->state, 1, &op)) {
- GstClockTime out_time =
- theora_granule_time (&enc->state, op.granulepos) * GST_SECOND;
- theora_push_packet (enc, &op, out_time, GST_SECOND / enc->fps);
- }
- default:
- gst_pad_event_default (pad, GST_EVENT (data));
- return;
- }
- }
+ enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
- buf = GST_BUFFER (data);
+ buf = GST_BUFFER (buffer);
in_time = GST_BUFFER_TIMESTAMP (buf);
/* no packets written yet, setup headers */
@@ -495,7 +497,7 @@ theora_enc_chain (GstPad * pad, GstData * data)
/* negotiate with these caps */
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_try_set_caps (enc->srcpad, caps);
+ gst_pad_set_caps (enc->srcpad, caps);
/* push out the header buffers */
theora_push_buffer (enc, buf1);
@@ -554,7 +556,7 @@ theora_enc_chain (GstPad * pad, GstData * data)
dst_uv_stride = enc->info_width / 2;
newbuf = gst_pad_alloc_buffer (enc->srcpad,
- GST_BUFFER_OFFSET_NONE, y_size * 3 / 2);
+ GST_BUFFER_OFFSET_NONE, y_size * 3 / 2, GST_PAD_CAPS (enc->srcpad));
dest_y = yuv.y = GST_BUFFER_DATA (newbuf);
dest_u = yuv.u = yuv.y + y_size;
@@ -655,6 +657,8 @@ theora_enc_chain (GstPad * pad, GstData * data)
gst_buffer_unref (buf);
}
+
+ return GST_FLOW_OK;
}
static GstElementStateReturn
diff --git a/ext/vorbis/Makefile.am b/ext/vorbis/Makefile.am
index 380be3114..ecf15aae7 100644
--- a/ext/vorbis/Makefile.am
+++ b/ext/vorbis/Makefile.am
@@ -1,10 +1,10 @@
plugin_LTLIBRARIES = libgstvorbis.la
libgstvorbis_la_SOURCES = vorbis.c \
- vorbisdec.c vorbisenc.c oggvorbisenc.c vorbisparse.c
+ vorbisdec.c vorbisenc.c vorbisparse.c
libgstvorbis_la_CFLAGS = $(GST_CFLAGS) $(VORBIS_CFLAGS)
## AM_PATH_VORBIS also sets VORBISENC_LIBS
libgstvorbis_la_LIBADD = $(VORBIS_LIBS) $(VORBISENC_LIBS) $(VORBISFILE_LIBS)
libgstvorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-noinst_HEADERS = vorbisenc.h vorbisdec.h oggvorbisenc.h vorbisparse.h
+noinst_HEADERS = vorbisenc.h vorbisdec.h vorbisparse.h
diff --git a/ext/vorbis/vorbis.c b/ext/vorbis/vorbis.c
index dcf1524cc..94f402094 100644
--- a/ext/vorbis/vorbis.c
+++ b/ext/vorbis/vorbis.c
@@ -22,7 +22,6 @@
#endif
#include "vorbisenc.h"
-#include "oggvorbisenc.h"
#include "vorbisdec.h"
#include "vorbisparse.h"
@@ -37,10 +36,6 @@ plugin_init (GstPlugin * plugin)
!gst_library_load ("gstaudio") || !gst_library_load ("gsttags"))
return FALSE;
- if (!gst_element_register (plugin, "vorbisenc", GST_RANK_NONE,
- GST_TYPE_OGGVORBISENC))
- return FALSE;
-
if (!gst_element_register (plugin, "rawvorbisenc", GST_RANK_NONE,
GST_TYPE_VORBISENC))
return FALSE;
diff --git a/ext/vorbis/vorbisdec.c b/ext/vorbis/vorbisdec.c
index 67edc381d..a85added8 100644
--- a/ext/vorbis/vorbisdec.c
+++ b/ext/vorbis/vorbisdec.c
@@ -72,7 +72,8 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_BOILERPLATE (GstVorbisDec, gst_vorbis_dec, GstElement, GST_TYPE_ELEMENT);
-static void vorbis_dec_chain (GstPad * pad, GstData * data);
+static gboolean vorbis_dec_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn vorbis_dec_chain (GstPad * pad, GstBuffer * buffer);
static GstElementStateReturn vorbis_dec_change_state (GstElement * element);
static const GstFormat *vorbis_dec_get_formats (GstPad * pad);
@@ -152,6 +153,7 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
dec->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&vorbis_dec_sink_factory), "sink");
+ gst_pad_set_event_function (dec->sinkpad, vorbis_dec_sink_event);
gst_pad_set_chain_function (dec->sinkpad, vorbis_dec_chain);
gst_pad_set_formats_function (dec->sinkpad, vorbis_dec_get_formats);
gst_pad_set_convert_function (dec->sinkpad, vorbis_dec_convert);
@@ -160,7 +162,6 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
dec->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&vorbis_dec_src_factory), "src");
- gst_pad_use_explicit_caps (dec->srcpad);
gst_pad_set_event_mask_function (dec->srcpad, vorbis_get_event_masks);
gst_pad_set_event_function (dec->srcpad, vorbis_dec_src_event);
gst_pad_set_query_type_function (dec->srcpad, vorbis_get_query_types);
@@ -168,8 +169,6 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
gst_pad_set_formats_function (dec->srcpad, vorbis_dec_get_formats);
gst_pad_set_convert_function (dec->srcpad, vorbis_dec_convert);
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-
- GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
}
static gboolean
@@ -295,10 +294,14 @@ vorbis_dec_src_event (GstPad * pad, GstEvent * event)
return res;
}
-static void
-vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
+static gboolean
+vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
{
guint64 value, time, bytes;
+ gboolean ret = TRUE;
+ GstVorbisDec *dec;
+
+ dec = GST_VORBIS_DEC (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (dec, "handling event");
switch (GST_EVENT_TYPE (event)) {
@@ -318,9 +321,9 @@ vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
("can't handle discont before parsing first 3 packets"));
dec->packetno = 0;
- gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE,
- GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
- (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0)));
+ gst_pad_push_event (dec->srcpad, gst_event_new_discontinuous (FALSE,
+ GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
+ (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0));
} else {
GstFormat time_format, default_format, bytes_format;
@@ -334,10 +337,10 @@ vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
dec->granulepos, &time_format, &time)
&& vorbis_dec_convert (dec->srcpad, GST_FORMAT_DEFAULT,
dec->granulepos, &bytes_format, &bytes)) {
- gst_pad_push (dec->srcpad,
- GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
- time, GST_FORMAT_DEFAULT, dec->granulepos,
- GST_FORMAT_BYTES, bytes, 0)));
+ gst_pad_push_event (dec->srcpad,
+ gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
+ time, GST_FORMAT_DEFAULT, dec->granulepos,
+ GST_FORMAT_BYTES, bytes, 0));
} else {
GST_ERROR_OBJECT (dec,
"failed to parse data for DISCONT event, not sending any");
@@ -349,25 +352,22 @@ vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
gst_data_unref (GST_DATA (event));
break;
default:
- gst_pad_event_default (dec->sinkpad, event);
+ ret = gst_pad_event_default (dec->sinkpad, event);
break;
}
+ return ret;
}
-static void
-vorbis_dec_chain (GstPad * pad, GstData * data)
+static GstFlowReturn
+vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
{
- GstBuffer *buf;
+ GstBuffer *buf = GST_BUFFER (buffer);
GstVorbisDec *vd;
- ogg_packet packet; /* lol */
+ ogg_packet packet;
+ GstFlowReturn result = GST_FLOW_OK;
- vd = GST_VORBIS_DEC (gst_pad_get_parent (pad));
- if (GST_IS_EVENT (data)) {
- vorbis_dec_event (vd, GST_EVENT (data));
- return;
- }
+ vd = GST_VORBIS_DEC (GST_PAD_PARENT (pad));
- buf = GST_BUFFER (data);
/* make ogg_packet out of the buffer */
packet.packet = GST_BUFFER_DATA (buf);
packet.bytes = GST_BUFFER_SIZE (buf);
@@ -391,16 +391,16 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
GST_WARNING_OBJECT (GST_ELEMENT (vd),
"unexpected packet type %d, expected %d",
(gint) packet.packet[0], (gint) packet.packetno);
- gst_data_unref (data);
- return;
+ gst_buffer_unref (buffer);
+ return GST_FLOW_UNEXPECTED;
}
/* Packetno = 0 if the first byte is exactly 0x01 */
packet.b_o_s = (packet.packet[0] == 0x1) ? 1 : 0;
if (vorbis_synthesis_headerin (&vd->vi, &vd->vc, &packet)) {
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
(NULL), ("couldn't read header packet"));
- gst_data_unref (data);
- return;
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
}
if (packet.packetno == 1) {
gchar *encoder = NULL;
@@ -429,7 +429,7 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
if (vd->vi.bitrate_lower > 0)
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL);
- gst_element_found_tags_for_pad (GST_ELEMENT (vd), vd->srcpad, 0, list);
+ //gst_element_found_tags_for_pad (GST_ELEMENT (vd), vd->srcpad, 0, list);
} else if (packet.packetno == 2) {
GstCaps *caps;
const GstAudioChannelPosition *pos = NULL;
@@ -490,20 +490,17 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
break;
}
default:
- gst_data_unref (data);
- gst_caps_free (caps);
+ gst_buffer_unref (buffer);
+ gst_caps_unref (caps);
GST_ELEMENT_ERROR (vd, STREAM, NOT_IMPLEMENTED, (NULL),
("Unsupported channel count %d", vd->vi.channels));
- return;
+ return GST_FLOW_ERROR;
}
if (pos) {
gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
}
- if (!gst_pad_set_explicit_caps (vd->srcpad, caps)) {
- gst_caps_free (caps);
- return;
- }
- gst_caps_free (caps);
+ gst_pad_set_caps (vd->srcpad, caps);
+ gst_caps_unref (caps);
}
} else {
float **pcm;
@@ -512,52 +509,59 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
if (packet.packetno < 3) {
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
(NULL), ("no header sent yet (packet no is %d)", packet.packetno));
- gst_data_unref (data);
- return;
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
}
/* normal data packet */
if (vorbis_synthesis (&vd->vb, &packet)) {
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
(NULL), ("couldn't read data packet"));
- gst_data_unref (data);
- return;
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
}
if (vorbis_synthesis_blockin (&vd->vd, &vd->vb) < 0) {
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
(NULL), ("vorbis decoder did not accept data packet"));
- gst_data_unref (data);
- return;
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
}
sample_count = vorbis_synthesis_pcmout (&vd->vd, &pcm);
if (sample_count > 0) {
int i, j;
GstBuffer *out = gst_pad_alloc_buffer (vd->srcpad, GST_BUFFER_OFFSET_NONE,
- sample_count * vd->vi.channels * sizeof (float));
- float *out_data = (float *) GST_BUFFER_DATA (out);
+ sample_count * vd->vi.channels * sizeof (float),
+ GST_PAD_CAPS (vd->srcpad));
+ float *out_data;
+
+ if (out != NULL) {
+ out_data = (float *) GST_BUFFER_DATA (out);
#ifdef GST_VORBIS_DEC_SEQUENTIAL
- for (i = 0; i < vd->vi.channels; i++) {
- memcpy (out_data, pcm[i], sample_count * sizeof (float));
- out_data += sample_count;
- }
-#else
- for (j = 0; j < sample_count; j++) {
for (i = 0; i < vd->vi.channels; i++) {
- *out_data = pcm[i][j];
- out_data++;
+ memcpy (out_data, pcm[i], sample_count * sizeof (float));
+ out_data += sample_count;
+ }
+#else
+ for (j = 0; j < sample_count; j++) {
+ for (i = 0; i < vd->vi.channels; i++) {
+ *out_data = pcm[i][j];
+ out_data++;
+ }
}
- }
#endif
- GST_BUFFER_OFFSET (out) = vd->granulepos;
- GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count;
- GST_BUFFER_TIMESTAMP (out) = vd->granulepos * GST_SECOND / vd->vi.rate;
- GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate;
- gst_pad_push (vd->srcpad, GST_DATA (out));
+ GST_BUFFER_OFFSET (out) = vd->granulepos;
+ GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count;
+ GST_BUFFER_TIMESTAMP (out) = vd->granulepos * GST_SECOND / vd->vi.rate;
+ GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate;
+ result = gst_pad_push (vd->srcpad, out);
+ vd->granulepos += sample_count;
+ }
vorbis_synthesis_read (&vd->vd, sample_count);
- vd->granulepos += sample_count;
}
}
- gst_data_unref (data);
+ gst_buffer_unref (buffer);
+
+ return result;
}
static GstElementStateReturn
diff --git a/ext/vorbis/vorbisenc.c b/ext/vorbis/vorbisenc.c
index a2e6bf70f..1a74d54a3 100644
--- a/ext/vorbis/vorbisenc.c
+++ b/ext/vorbis/vorbisenc.c
@@ -103,7 +103,8 @@ static void gst_vorbisenc_base_init (gpointer g_class);
static void gst_vorbisenc_class_init (VorbisEncClass * klass);
static void gst_vorbisenc_init (VorbisEnc * vorbisenc);
-static void gst_vorbisenc_chain (GstPad * pad, GstData * _data);
+static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_vorbisenc_setup (VorbisEnc * vorbisenc);
static void gst_vorbisenc_get_property (GObject * object, guint prop_id,
@@ -197,6 +198,9 @@ gst_vorbisenc_class_init (VorbisEncClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
+ gobject_class->set_property = gst_vorbisenc_set_property;
+ gobject_class->get_property = gst_vorbisenc_get_property;
+
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
g_param_spec_int ("max-bitrate", "Maximum Bitrate",
"Specify a maximum bitrate (in bps). Useful for streaming "
@@ -226,14 +230,11 @@ gst_vorbisenc_class_init (VorbisEncClass * klass)
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
- gobject_class->set_property = gst_vorbisenc_set_property;
- gobject_class->get_property = gst_vorbisenc_get_property;
-
gstelement_class->change_state = gst_vorbisenc_change_state;
}
-static GstPadLinkReturn
-gst_vorbisenc_sinkconnect (GstPad * pad, const GstCaps * caps)
+static gboolean
+gst_vorbisenc_sink_setcaps (GstPad * pad, GstCaps * caps)
{
VorbisEnc *vorbisenc;
GstStructure *structure;
@@ -248,9 +249,9 @@ gst_vorbisenc_sinkconnect (GstPad * pad, const GstCaps * caps)
gst_vorbisenc_setup (vorbisenc);
if (vorbisenc->setup)
- return GST_PAD_LINK_OK;
+ return TRUE;
- return GST_PAD_LINK_REFUSED;
+ return FALSE;
}
static gboolean
@@ -447,8 +448,9 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc)
vorbisenc->sinkpad =
gst_pad_new_from_template (gst_vorbisenc_sink_template, "sink");
gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad);
+ gst_pad_set_event_function (vorbisenc->sinkpad, gst_vorbisenc_sink_event);
gst_pad_set_chain_function (vorbisenc->sinkpad, gst_vorbisenc_chain);
- gst_pad_set_link_function (vorbisenc->sinkpad, gst_vorbisenc_sinkconnect);
+ gst_pad_set_setcaps_function (vorbisenc->sinkpad, gst_vorbisenc_sink_setcaps);
gst_pad_set_convert_function (vorbisenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_vorbisenc_convert_sink));
gst_pad_set_formats_function (vorbisenc->sinkpad,
@@ -482,9 +484,6 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc)
vorbisenc->header_sent = FALSE;
vorbisenc->tags = gst_tag_list_new ();
-
- /* we're chained and we can deal with events */
- GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE);
}
@@ -736,7 +735,7 @@ gst_vorbisenc_push_buffer (VorbisEnc * vorbisenc, GstBuffer * buffer)
vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
if (GST_PAD_IS_USABLE (vorbisenc->srcpad)) {
- gst_pad_push (vorbisenc->srcpad, GST_DATA (buffer));
+ gst_pad_push (vorbisenc->srcpad, buffer);
} else {
gst_buffer_unref (buffer);
}
@@ -782,45 +781,49 @@ gst_vorbisenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
g_value_unset (&list);
}
-static void
-gst_vorbisenc_chain (GstPad * pad, GstData * _data)
+static gboolean
+gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event)
{
- GstBuffer *buf = GST_BUFFER (_data);
+ gboolean res = TRUE;
VorbisEnc *vorbisenc;
- g_return_if_fail (pad != NULL);
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
+ vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* end of file. this can be done implicitly in the mainline,
+ but it's easier to see here in non-clever fashion.
+ Tell the library we're at end of stream so that it can handle
+ the last frame and mark end of stream in the output properly */
+ vorbis_analysis_wrote (&vorbisenc->vd, 0);
+ vorbisenc->eos = TRUE;
+ gst_event_unref (event);
+ break;
+ case GST_EVENT_TAG:
+ if (vorbisenc->tags) {
+ gst_tag_list_insert (vorbisenc->tags, gst_event_tag_get_list (event),
+ gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
+ } else {
+ g_assert_not_reached ();
+ }
+ res = gst_pad_event_default (pad, event);
+ break;
+ default:
+ res = gst_pad_event_default (pad, event);
+ break;
+ }
+ return res;
+}
- vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
+static GstFlowReturn
+gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstBuffer *buf = GST_BUFFER (buffer);
+ VorbisEnc *vorbisenc;
- if (GST_IS_EVENT (buf)) {
- GstEvent *event = GST_EVENT (buf);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- /* end of file. this can be done implicitly in the mainline,
- but it's easier to see here in non-clever fashion.
- Tell the library we're at end of stream so that it can handle
- the last frame and mark end of stream in the output properly */
- vorbis_analysis_wrote (&vorbisenc->vd, 0);
- vorbisenc->eos = TRUE;
- gst_event_unref (event);
- break;
- case GST_EVENT_TAG:
- if (vorbisenc->tags) {
- gst_tag_list_insert (vorbisenc->tags, gst_event_tag_get_list (event),
- gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
- } else {
- g_assert_not_reached ();
- }
- gst_pad_event_default (pad, event);
- return;
- default:
- gst_pad_event_default (pad, event);
- return;
- }
- } else {
+ vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
+
+ {
gfloat *data;
gulong size;
gulong i, j;
@@ -830,7 +833,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
gst_buffer_unref (buf);
GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
("encoder not initialized (input is not audio?)"));
- return;
+ return GST_FLOW_UNEXPECTED;
}
if (!vorbisenc->header_sent) {
@@ -863,7 +866,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
/* negotiate with these caps */
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_try_set_caps (vorbisenc->srcpad, caps);
+ gst_pad_set_caps (vorbisenc->srcpad, caps);
/* push out buffers */
gst_vorbisenc_push_buffer (vorbisenc, buf1);
@@ -915,9 +918,10 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
vorbis_block_clear (&vorbisenc->vb);
vorbis_dsp_clear (&vorbisenc->vd);
vorbis_info_clear (&vorbisenc->vi);
- gst_pad_push (vorbisenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
- gst_element_set_eos (GST_ELEMENT (vorbisenc));
+ gst_pad_push_event (vorbisenc->srcpad, gst_event_new (GST_EVENT_EOS));
+ //gst_element_set_eos (GST_ELEMENT (vorbisenc));
}
+ return GST_FLOW_OK;
}
static void
diff --git a/ext/vorbis/vorbisparse.c b/ext/vorbis/vorbisparse.c
index 95e6970f7..bbcea816c 100644
--- a/ext/vorbis/vorbisparse.c
+++ b/ext/vorbis/vorbisparse.c
@@ -62,7 +62,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_BOILERPLATE (GstVorbisParse, gst_vorbis_parse, GstElement,
GST_TYPE_ELEMENT);
-static void vorbis_parse_chain (GstPad * pad, GstData * data);
+static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstBuffer * buffer);
static GstElementStateReturn vorbis_parse_change_state (GstElement * element);
static void
@@ -143,23 +143,22 @@ vorbis_parse_set_header_on_caps (GstVorbisParse * parse, GstCaps * caps)
g_value_unset (&list);
}
-static void
-vorbis_parse_chain (GstPad * pad, GstData * data)
+static GstFlowReturn
+vorbis_parse_chain (GstPad * pad, GstBuffer * buffer)
{
GstBuffer *buf;
GstVorbisParse *parse;
- parse = GST_VORBIS_PARSE (gst_pad_get_parent (pad));
- g_assert (parse);
+ parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad));
- buf = GST_BUFFER (data);
+ buf = GST_BUFFER (buffer);
parse->packetno++;
/* if 1 <= packetno <= 3, it's streamheader,
* so put it on the streamheader list and return */
if (parse->packetno <= 3) {
parse->streamheader = g_list_append (parse->streamheader, buf);
- return;
+ return GST_FLOW_OK;
}
/* else, if we haven't sent streamheader buffers yet,
@@ -172,7 +171,7 @@ vorbis_parse_chain (GstPad * pad, GstData * data)
/* negotiate with these caps */
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_try_set_caps (parse->srcpad, caps);
+ gst_pad_set_caps (parse->srcpad, caps);
/* push out buffers */
gst_pad_push (parse->srcpad, parse->streamheader->data);
@@ -182,7 +181,9 @@ vorbis_parse_chain (GstPad * pad, GstData * data)
parse->streamheader_sent = TRUE;
}
/* just send on buffer by default */
- gst_pad_push (parse->srcpad, data);
+ gst_pad_push (parse->srcpad, buf);
+
+ return GST_FLOW_OK;
}
static GstElementStateReturn
diff --git a/gst/audioconvert/bufferframesconvert.c b/gst/audioconvert/bufferframesconvert.c
index 402f3e7c9..3cb03855d 100644
--- a/gst/audioconvert/bufferframesconvert.c
+++ b/gst/audioconvert/bufferframesconvert.c
@@ -91,10 +91,10 @@ static GstElementStateReturn buffer_frames_convert_change_state (GstElement *
element);
static GstCaps *buffer_frames_convert_getcaps (GstPad * pad);
-static GstPadLinkReturn buffer_frames_convert_link (GstPad * pad,
- const GstCaps * caps);
+static gboolean buffer_frames_convert_setcaps (GstPad * pad, GstCaps * caps);
-static void buffer_frames_convert_chain (GstPad * sinkpad, GstData * _data);
+static GstFlowReturn buffer_frames_convert_chain (GstPad * sinkpad,
+ GstBuffer * buffer);
static GstElementClass *parent_class = NULL;
@@ -151,14 +151,14 @@ buffer_frames_convert_init (BufferFramesConvert * this)
this->sinkpad = gst_pad_new_from_template
(gst_static_pad_template_get (&sink_static_template), "sink");
gst_element_add_pad (GST_ELEMENT (this), this->sinkpad);
- gst_pad_set_link_function (this->sinkpad, buffer_frames_convert_link);
+ gst_pad_set_setcaps_function (this->sinkpad, buffer_frames_convert_setcaps);
gst_pad_set_getcaps_function (this->sinkpad, buffer_frames_convert_getcaps);
gst_pad_set_chain_function (this->sinkpad, buffer_frames_convert_chain);
this->srcpad = gst_pad_new_from_template
(gst_static_pad_template_get (&src_static_template), "src");
gst_element_add_pad (GST_ELEMENT (this), this->srcpad);
- gst_pad_set_link_function (this->srcpad, buffer_frames_convert_link);
+ gst_pad_set_setcaps_function (this->srcpad, buffer_frames_convert_setcaps);
gst_pad_set_getcaps_function (this->srcpad, buffer_frames_convert_getcaps);
this->in_buffer_samples = -1;
@@ -216,9 +216,10 @@ buffer_frames_convert_getcaps (GstPad * pad)
return ret;
}
-static GstPadLinkReturn
-buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
+static gboolean
+buffer_frames_convert_setcaps (GstPad * pad, GstCaps * caps)
{
+#if 0
BufferFramesConvert *this;
GstCaps *othercaps;
GstPad *otherpad;
@@ -231,7 +232,7 @@ buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
otherpad = pad == this->srcpad ? this->sinkpad : this->srcpad;
/* first try to act as a passthrough */
- ret = gst_pad_try_set_caps (otherpad, caps);
+ ret = gst_pad_set_caps (otherpad, caps);
if (GST_PAD_LINK_SUCCESSFUL (ret)) {
this->passthrough = TRUE;
return ret;
@@ -261,12 +262,13 @@ buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
if (this->out_buffer_samples == 0)
this->passthrough = TRUE;
+#endif
- return GST_PAD_LINK_OK;
+ return TRUE;
}
-static void
-buffer_frames_convert_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+buffer_frames_convert_chain (GstPad * pad, GstBuffer * buf)
{
BufferFramesConvert *this;
GstBuffer *buf_in, *buf_out;
@@ -278,11 +280,10 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
this = (BufferFramesConvert *) GST_OBJECT_PARENT (pad);
if (this->passthrough) {
- gst_pad_push (this->srcpad, _data);
- return;
+ return gst_pad_push (this->srcpad, buf);
}
- buf_in = (GstBuffer *) _data;
+ buf_in = buf;
data_in = (gfloat *) GST_BUFFER_DATA (buf_in);
samples_in = samples_in_remaining =
GST_BUFFER_SIZE (buf_in) / sizeof (gfloat);
@@ -304,12 +305,12 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
if (!samples_out_remaining) {
this->buf_out = NULL;
this->samples_out_remaining = 0;
- gst_pad_push (this->srcpad, (GstData *) buf_out);
+ gst_pad_push (this->srcpad, buf_out);
} else {
/* we used up the incoming samples, but didn't fill our buffer */
this->samples_out_remaining = samples_out_remaining;
gst_buffer_unref (buf_in);
- return;
+ return GST_FLOW_OK;
}
}
@@ -320,7 +321,7 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
out_buffer_samples * sizeof (gfloat));
data_in += out_buffer_samples;
samples_in_remaining -= out_buffer_samples;
- gst_pad_push (this->srcpad, (GstData *) buf_out);
+ gst_pad_push (this->srcpad, buf_out);
}
/* if there's an event coming next, just push what we have */
@@ -330,13 +331,13 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
gst_buffer_create_sub (buf_in,
(samples_in - samples_in_remaining) * sizeof (gfloat),
samples_in_remaining * sizeof (gfloat));
- gst_pad_push (this->srcpad, (GstData *) buf_out);
+ gst_pad_push (this->srcpad, buf_out);
} else {
/* otherwise make a leftover buffer if it's necessary */
if (samples_in_remaining) {
buf_out =
gst_pad_alloc_buffer (this->srcpad, 0,
- out_buffer_samples * sizeof (gfloat));
+ out_buffer_samples * sizeof (gfloat), GST_PAD_CAPS (this->srcpad));
data_out = (gfloat *) GST_BUFFER_DATA (buf_out);
this->buf_out = buf_out;
this->samples_out_remaining = out_buffer_samples - samples_in_remaining;
@@ -346,4 +347,6 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
}
gst_buffer_unref (buf_in);
+
+ return GST_FLOW_OK;
}
diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c
index 1ec992577..047307d31 100644
--- a/gst/audioconvert/gstaudioconvert.c
+++ b/gst/audioconvert/gstaudioconvert.c
@@ -60,10 +60,9 @@ static void gst_audio_convert_init (GstAudioConvert * audio_convert);
static void gst_audio_convert_dispose (GObject * obj);
/* gstreamer functions */
-static void gst_audio_convert_chain (GstPad * pad, GstData * _data);
-static GstPadLinkReturn gst_audio_convert_link (GstPad * pad,
- const GstCaps * caps);
-static GstCaps *gst_audio_convert_fixate (GstPad * pad, const GstCaps * caps);
+static GstFlowReturn gst_audio_convert_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_audio_convert_setcaps (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_audio_convert_fixate (GstPad * pad, GstCaps * caps);
static GstCaps *gst_audio_convert_getcaps (GstPad * pad);
static GstElementStateReturn gst_audio_convert_change_state (GstElement *
element);
@@ -180,8 +179,8 @@ gst_audio_convert_init (GstAudioConvert * this)
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_audio_convert_sink_template), "sink");
gst_pad_set_getcaps_function (this->sink, gst_audio_convert_getcaps);
- gst_pad_set_link_function (this->sink, gst_audio_convert_link);
- gst_pad_set_fixate_function (this->sink, gst_audio_convert_fixate);
+ gst_pad_set_setcaps_function (this->sink, gst_audio_convert_setcaps);
+ gst_pad_set_fixatecaps_function (this->sink, gst_audio_convert_fixate);
gst_element_add_pad (GST_ELEMENT (this), this->sink);
/* srcpad */
@@ -189,8 +188,8 @@ gst_audio_convert_init (GstAudioConvert * this)
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_audio_convert_src_template), "src");
gst_pad_set_getcaps_function (this->src, gst_audio_convert_getcaps);
- gst_pad_set_link_function (this->src, gst_audio_convert_link);
- gst_pad_set_fixate_function (this->src, gst_audio_convert_fixate);
+ gst_pad_set_setcaps_function (this->src, gst_audio_convert_setcaps);
+ gst_pad_set_fixatecaps_function (this->src, gst_audio_convert_fixate);
gst_element_add_pad (GST_ELEMENT (this), this->src);
gst_pad_set_chain_function (this->sink, gst_audio_convert_chain);
@@ -221,34 +220,28 @@ gst_audio_convert_dispose (GObject * obj)
/*** GSTREAMER FUNCTIONS ******************************************************/
-static void
-gst_audio_convert_chain (GstPad * pad, GstData * data)
+static GstFlowReturn
+gst_audio_convert_chain (GstPad * pad, GstBuffer * buf)
{
- GstBuffer *buf = GST_BUFFER (data);
GstAudioConvert *this;
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
- g_return_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)));
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
/* FIXME */
- if (GST_IS_EVENT (buf)) {
- gst_pad_event_default (pad, GST_EVENT (buf));
- return;
- }
- g_return_if_fail (GST_IS_BUFFER (buf));
- if (!gst_pad_is_negotiated (this->sink)) {
+#if 0
+ if (!GST_PAD_CAPS (this->sink)) {
GST_ELEMENT_ERROR (this, CORE, NEGOTIATION, (NULL),
("Sink pad (connected to %s:%s) not negotiated before chain function",
GST_DEBUG_PAD_NAME (gst_pad_get_peer (this->sink))));
- return;
+ gst_buffer_unref (buf);
+ return GST_FLOW_NOT_NEGOTIATED;
}
- if (!gst_pad_is_negotiated (this->src)) {
- gst_data_unref (data);
- return;
+ if (!GST_PAD_CAPS (this->src)) {
+ gst_buffer_unref (buf);
+ return GST_FLOW_NOT_NEGOTIATED;
}
+#endif
/**
* Theory of operation:
@@ -264,35 +257,25 @@ gst_audio_convert_chain (GstPad * pad, GstData * data)
buf = gst_audio_convert_buffer_from_default_format (this, buf);
- gst_pad_push (this->src, GST_DATA (buf));
+ gst_pad_push (this->src, buf);
+
+ return GST_FLOW_OK;
}
-/* this function is complicated now, but it will be unnecessary when we convert
- * rate. */
static GstCaps *
-gst_audio_convert_getcaps (GstPad * pad)
+gst_audio_convert_caps_remove_format_info (GstPad * pad, GstCaps * caps)
{
- GstAudioConvert *this;
- GstPad *otherpad;
- GstStructure *structure;
- GstCaps *othercaps, *caps;
- const GstCaps *templcaps;
int i, size;
+ GstAudioConvert *this;
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)), NULL);
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
- otherpad = (pad == this->src) ? this->sink : this->src;
-
- /* all we want to find out is the rate */
- templcaps = gst_pad_get_pad_template_caps (pad);
- othercaps = gst_pad_get_allowed_caps (otherpad);
-
- size = gst_caps_get_size (othercaps);
+ size = gst_caps_get_size (caps);
for (i = size - 1; i >= 0; i--) {
- structure = gst_caps_get_structure (othercaps, i);
+ GstStructure *structure;
+
+ structure = gst_caps_get_structure (caps, i);
gst_structure_remove_field (structure, "channels");
gst_structure_remove_field (structure, "channel-positions");
gst_structure_remove_field (structure, "endianness");
@@ -312,10 +295,34 @@ gst_audio_convert_getcaps (GstPad * pad)
gst_structure_set_name (structure, "audio/x-raw-int");
gst_structure_remove_field (structure, "buffer-frames");
}
- gst_caps_append_structure (othercaps, structure);
+ gst_caps_append_structure (caps, structure);
}
+
+ return caps;
+}
+
+/* this function is complicated now, but it will be unnecessary when we convert
+ * rate. */
+static GstCaps *
+gst_audio_convert_getcaps (GstPad * pad)
+{
+ GstAudioConvert *this;
+ GstPad *otherpad;
+ GstCaps *othercaps, *caps;
+ const GstCaps *templcaps;
+
+ this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
+
+ otherpad = (pad == this->src) ? this->sink : this->src;
+
+ /* we can do all our peer can */
+ othercaps = gst_pad_peer_get_caps (otherpad);
+ /* without the format info even */
+ othercaps = gst_audio_convert_caps_remove_format_info (pad, othercaps);
+ /* but filtered against our template */
+ templcaps = gst_pad_get_pad_template_caps (pad);
caps = gst_caps_intersect (othercaps, templcaps);
- gst_caps_free (othercaps);
+ gst_caps_unref (othercaps);
/* Get the channel positions in as well. */
gst_audio_set_caps_channel_positions_list (caps, supported_positions,
@@ -330,6 +337,8 @@ gst_audio_convert_parse_caps (const GstCaps * gst_caps,
{
GstStructure *structure = gst_caps_get_structure (gst_caps, 0);
+ GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, gst_caps, gst_caps);
+
g_return_val_if_fail (gst_caps_is_fixed (gst_caps), FALSE);
g_return_val_if_fail (caps != NULL, FALSE);
@@ -368,76 +377,72 @@ gst_audio_convert_parse_caps (const GstCaps * gst_caps,
return TRUE;
}
-static GstPadLinkReturn
-gst_audio_convert_link (GstPad * pad, const GstCaps * caps)
+static gboolean
+gst_audio_convert_setcaps (GstPad * pad, GstCaps * caps)
{
GstAudioConvert *this;
GstPad *otherpad;
- GstAudioConvertCaps ac_caps = { 0 }, other_ac_caps = {
- 0};
- GstCaps *othercaps;
- guint i;
- GstPadLinkReturn ret;
+ GstAudioConvertCaps ac_caps = { 0 };
+ GstAudioConvertCaps other_ac_caps = { 0 };
+ GstCaps **other_prefered, **prefered;
- g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_LINK_REFUSED);
- g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)),
- GST_PAD_LINK_REFUSED);
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)), FALSE);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
- otherpad = (pad == this->src ? this->sink : this->src);
/* we'll need a new matrix after every new negotiation */
gst_audio_convert_unset_matrix (this);
ac_caps.pos = NULL;
if (!gst_audio_convert_parse_caps (caps, &ac_caps))
- return GST_PAD_LINK_REFUSED;
-
- /* ok, not those - try setting "any" caps */
- othercaps = gst_pad_get_allowed_caps (otherpad);
- for (i = 0; i < gst_caps_get_size (othercaps); i++) {
- GstStructure *structure = gst_caps_get_structure (othercaps, i);
-
- gst_structure_set (structure, "rate", G_TYPE_INT, ac_caps.rate, NULL);
- if (strcmp (gst_structure_get_name (structure), "audio/x-raw-float") == 0) {
- if (!ac_caps.is_int) {
- gst_structure_set (structure, "buffer-frames", G_TYPE_INT,
- ac_caps.buffer_frames, NULL);
- } else {
- gst_structure_set (structure, "buffer-frames", GST_TYPE_INT_RANGE, 0,
- G_MAXINT, NULL);
- }
- }
- }
- if (this->sink == pad) {
- g_free (this->sinkcaps.pos);
- this->sinkcaps = ac_caps;
- } else {
- g_free (this->srccaps.pos);
- this->srccaps = ac_caps;
- }
- GST_LOG_OBJECT (this, "trying to set caps to %" GST_PTR_FORMAT, othercaps);
+ return FALSE;
- ret = gst_pad_try_set_caps_nonfixed (otherpad, othercaps);
- gst_caps_free (othercaps);
- if (ret < GST_PAD_LINK_OK)
- return ret;
+ otherpad = (pad == this->src ? this->sink : this->src);
+ prefered = (pad == this->src) ? &this->src_prefered : &this->sink_prefered;
+ other_prefered =
+ (pad == this->src) ? &this->sink_prefered : &this->src_prefered;
- /* woohoo, got it */
- othercaps = (GstCaps *) gst_pad_get_negotiated_caps (otherpad);
- if (othercaps) {
- other_ac_caps.pos = NULL;
+ *prefered = caps;
- if (!gst_audio_convert_parse_caps (othercaps, &other_ac_caps)) {
- g_critical ("internal negotiation error");
- return GST_PAD_LINK_REFUSED;
- }
+ /* check passthrough */
+ if (gst_pad_peer_accept_caps (otherpad, caps)) {
+ /* great, so that will be our suggestion then */
+ *other_prefered = gst_caps_ref (caps);
} else {
- other_ac_caps = ac_caps;
- other_ac_caps.pos = g_memdup (ac_caps.pos,
- ac_caps.channels * sizeof (GstAudioChannelPosition));
- }
+ /* nope, find something we can convert to and the peer can
+ * accept. */
+ GstCaps *othercaps = gst_pad_peer_get_caps (otherpad);
+
+ if (othercaps) {
+ /* peel off first one */
+ GstCaps *targetcaps = gst_caps_copy_1 (othercaps);
+ GstStructure *structure = gst_caps_get_structure (targetcaps, 0);
+
+ gst_caps_unref (othercaps);
+
+ /* set the rate on the caps */
+ gst_structure_set (structure, "rate", G_TYPE_INT, ac_caps.rate, NULL);
+ gst_structure_set (structure, "channels", G_TYPE_INT, ac_caps.channels,
+ NULL);
+ if (strcmp (gst_structure_get_name (structure), "audio/x-raw-float") == 0) {
+ if (!ac_caps.is_int) {
+ gst_structure_set (structure, "buffer-frames", G_TYPE_INT,
+ ac_caps.buffer_frames, NULL);
+ } else {
+ gst_structure_set (structure, "buffer-frames", GST_TYPE_INT_RANGE, 0,
+ G_MAXINT, NULL);
+ }
+ }
+ /* this will be our suggestion */
+ *other_prefered = targetcaps;
+ if (!gst_audio_convert_parse_caps (targetcaps, &other_ac_caps))
+ return FALSE;
+ GST_RPAD_CAPS (otherpad) = targetcaps;
+ }
+ }
if (this->sink == pad) {
g_free (this->srccaps.pos);
this->srccaps = other_ac_caps;
@@ -449,7 +454,7 @@ gst_audio_convert_link (GstPad * pad, const GstCaps * caps)
}
GST_DEBUG_OBJECT (this, "negotiated pad to %" GST_PTR_FORMAT, caps);
- return GST_PAD_LINK_OK;
+ return TRUE;
}
/* tries to fixate the given field of the given caps to the given int value */
@@ -467,7 +472,7 @@ _fixate_caps_to_int (GstCaps ** caps, const gchar * field, gint value)
gst_caps_append (try, gst_caps_new_simple ("audio/x-raw-float", field,
GST_TYPE_INT_RANGE, G_MININT, value - 1, NULL));
isect_lower = gst_caps_intersect (*caps, try);
- gst_caps_free (try);
+ gst_caps_unref (try);
if (!gst_caps_is_empty (isect_lower)) {
try = gst_caps_new_simple ("audio/x-raw-int", field, GST_TYPE_INT_RANGE,
@@ -475,18 +480,18 @@ _fixate_caps_to_int (GstCaps ** caps, const gchar * field, gint value)
gst_caps_append (try, gst_caps_new_simple ("audio/x-raw-float", field,
GST_TYPE_INT_RANGE, value, G_MAXINT, NULL));
isect_higher = gst_caps_intersect (*caps, try);
- gst_caps_free (try);
+ gst_caps_unref (try);
/* FIXME: why choose to end up with the higher range, and not the fixed
* value ? */
if (!gst_caps_is_empty (isect_higher)) {
- gst_caps_free (*caps);
+ gst_caps_unref (*caps);
*caps = isect_higher;
ret = TRUE;
} else {
- gst_caps_free (isect_higher);
+ gst_caps_unref (isect_higher);
}
}
- gst_caps_free (isect_lower);
+ gst_caps_unref (isect_lower);
/* FIXME: why don't we already return here when ret == TRUE ? */
for (i = 0; i < gst_caps_get_size (*caps); i++) {
@@ -500,27 +505,29 @@ _fixate_caps_to_int (GstCaps ** caps, const gchar * field, gint value)
}
static GstCaps *
-gst_audio_convert_fixate (GstPad * pad, const GstCaps * caps)
+gst_audio_convert_fixate (GstPad * pad, GstCaps * caps)
{
const GValue *pos_val;
GstAudioConvert *this =
GST_AUDIO_CONVERT (gst_object_get_parent (GST_OBJECT (pad)));
- GstPad *otherpad = (pad == this->sink ? this->src : this->sink);
+ //GstPad *otherpad = (pad == this->sink ? this->src : this->sink);
GstAudioConvertCaps try, ac_caps =
(pad == this->sink ? this->srccaps : this->sinkcaps);
GstCaps *copy = gst_caps_copy (caps);
- if (!GST_PAD_IS_NEGOTIATING (otherpad)) {
- try.channels = 2;
- try.width = 16;
- try.depth = 16;
- try.endianness = G_BYTE_ORDER;
- } else {
- try.channels = ac_caps.channels;
- try.width = ac_caps.is_int ? ac_caps.width : 16;
- try.depth = ac_caps.is_int ? ac_caps.depth : 16;
- try.endianness = ac_caps.is_int ? ac_caps.endianness : G_BYTE_ORDER;
- }
+ //if (!GST_PAD_IS_NEGOTIATING (otherpad)) {
+ try.channels = 2;
+ try.width = 16;
+ try.depth = 16;
+ try.endianness = G_BYTE_ORDER;
+ /*
+ } else {
+ try.channels = ac_caps.channels;
+ try.width = ac_caps.is_int ? ac_caps.width : 16;
+ try.depth = ac_caps.is_int ? ac_caps.depth : 16;
+ try.endianness = ac_caps.is_int ? ac_caps.endianness : G_BYTE_ORDER;
+ }
+ */
if (_fixate_caps_to_int (&copy, "channels", try.channels)) {
int n;
@@ -582,7 +589,7 @@ gst_audio_convert_fixate (GstPad * pad, const GstCaps * caps)
}
}
- gst_caps_free (copy);
+ gst_caps_unref (copy);
return NULL;
}
@@ -630,7 +637,7 @@ gst_audio_convert_get_buffer (GstBuffer * buf, guint size)
} else {
ret = gst_buffer_new_and_alloc (size);
g_assert (ret);
- gst_buffer_stamp (ret, buf);
+ //gst_buffer_stamp (ret, buf);
GST_LOG ("returning new buffer. data: %p - size: %u - maxsize: %u",
ret->data, ret->size, ret->maxsize);
return ret;
@@ -681,6 +688,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
ret =
gst_audio_convert_get_buffer (buf,
buf->size * 32 / this->sinkcaps.width);
+ gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
count = ret->size / 4;
src = buf->data + (count - 1) * (this->sinkcaps.width / 8);
@@ -731,6 +739,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
/* should just give the same buffer, unless it's not writable -- float is
* already 32 bits */
ret = gst_audio_convert_get_buffer (buf, buf->size);
+ gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
in = (gfloat *) GST_BUFFER_DATA (buf);
out = (gint32 *) GST_BUFFER_DATA (ret);
@@ -790,6 +799,7 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
ret =
gst_audio_convert_get_buffer (buf,
buf->size * this->srccaps.width / 32);
+ gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
dest = ret->data;
src = (gint32 *) buf->data;
@@ -833,6 +843,7 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
ret =
gst_audio_convert_get_buffer (buf,
buf->size * this->srccaps.width / 32);
+ gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
dest = (gfloat *) ret->data;
src = (gint32 *) buf->data;
@@ -864,6 +875,7 @@ gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
/* convert */
count = GST_BUFFER_SIZE (buf) / 4 / this->sinkcaps.channels;
ret = gst_audio_convert_get_buffer (buf, count * 4 * this->srccaps.channels);
+ gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
gst_audio_convert_mix (this, (gint32 *) GST_BUFFER_DATA (buf),
(gint32 *) GST_BUFFER_DATA (ret), count);
gst_buffer_unref (buf);
diff --git a/gst/audioconvert/gstchannelmix.h b/gst/audioconvert/gstchannelmix.h
index 28d5082da..3fc107085 100644
--- a/gst/audioconvert/gstchannelmix.h
+++ b/gst/audioconvert/gstchannelmix.h
@@ -67,6 +67,9 @@ struct _GstAudioConvert
GstAudioConvertCaps srccaps;
GstAudioConvertCaps sinkcaps;
+ GstCaps *src_prefered;
+ GstCaps *sink_prefered;
+
/* channel conversion matrix, m[in_channels][out_channels].
* If identity matrix, passthrough applies. */
gfloat **matrix;
diff --git a/gst/ffmpegcolorspace/gstffmpegcolorspace.c b/gst/ffmpegcolorspace/gstffmpegcolorspace.c
index 3f2766851..294af8caf 100644
--- a/gst/ffmpegcolorspace/gstffmpegcolorspace.c
+++ b/gst/ffmpegcolorspace/gstffmpegcolorspace.c
@@ -114,6 +114,8 @@ gst_ffmpegcsp_caps_remove_format_info (GstCaps * caps)
GstStructure *structure;
GstCaps *rgbcaps;
+ caps = gst_caps_copy_on_write (caps);
+
for (i = 0; i < gst_caps_get_size (caps); i++) {
structure = gst_caps_get_structure (caps, i);
@@ -154,19 +156,13 @@ gst_ffmpegcsp_getcaps (GstPad * pad)
space = GST_FFMPEGCSP (GST_PAD_PARENT (pad));
otherpad = (pad == space->srcpad) ? space->sinkpad : space->srcpad;
- otherpeer = gst_pad_get_peer (otherpad);
- if (otherpeer) {
- /* if peer, we can do whatever the peer can */
- othercaps = gst_pad_get_caps (otherpeer);
- /* without the format info */
- othercaps = gst_ffmpegcsp_caps_remove_format_info (othercaps);
- /* and filtered against our padtemplate */
- caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
- gst_caps_unref (othercaps);
- } else {
- /* no peer, our padtemplate is enough */
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
- }
+ /* we can do whatever the peer can */
+ othercaps = gst_pad_peer_get_caps (otherpad);
+ /* without the format info */
+ othercaps = gst_ffmpegcsp_caps_remove_format_info (othercaps);
+ /* and filtered against our padtemplate */
+ caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
+ gst_caps_unref (othercaps);
return caps;
}
diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c
index c85ca8b02..ec1ccc9a2 100644
--- a/tests/examples/seek/seek.c
+++ b/tests/examples/seek/seek.c
@@ -51,11 +51,11 @@ dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
{
dyn_link *connect = (dyn_link *) data;
- if (!strcmp (gst_pad_get_name (newpad), connect->padname)) {
- gst_element_set_state (pipeline, GST_STATE_PAUSED);
- gst_bin_add (GST_BIN (pipeline), connect->bin);
+ if (connect->padname == NULL ||
+ !strcmp (gst_pad_get_name (newpad), connect->padname)) {
+ if (connect->bin)
+ gst_bin_add (GST_BIN (pipeline), connect->bin);
gst_pad_link (newpad, connect->target);
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
seekable_pads = g_list_prepend (seekable_pads, newpad);
rate_pads = g_list_prepend (rate_pads, newpad);
@@ -273,25 +273,35 @@ make_parse_pipeline (const gchar * location)
static GstElement *
make_vorbis_pipeline (const gchar * location)
{
- GstElement *pipeline;
- GstElement *src, *decoder, *audiosink;
+ GstElement *pipeline, *audio_bin;
+ GstElement *src, *demux, *decoder, *convert, *audiosink;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
src = gst_element_factory_make_or_warn (SOURCE, "src");
- decoder = gst_element_factory_make_or_warn ("vorbisfile", "decoder");
+ demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
+ decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
+ convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
g_object_set (G_OBJECT (src), "location", location, NULL);
+ audio_bin = gst_bin_new ("a_decoder_bin");
+
gst_bin_add (GST_BIN (pipeline), src);
- gst_bin_add (GST_BIN (pipeline), decoder);
- gst_bin_add (GST_BIN (pipeline), audiosink);
+ gst_bin_add (GST_BIN (pipeline), demux);
+ gst_bin_add (GST_BIN (audio_bin), decoder);
+ gst_bin_add (GST_BIN (audio_bin), convert);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
+ gst_bin_add (GST_BIN (pipeline), audio_bin);
- gst_element_link (src, decoder);
- gst_element_link (decoder, audiosink);
+ gst_element_link (src, demux);
+ gst_element_link (decoder, convert);
+ gst_element_link (convert, audiosink);
+
+ setup_dynamic_link (demux, NULL, gst_element_get_pad (decoder, "sink"), NULL);
seekable = gst_element_get_pad (decoder, "src");
seekable_pads = g_list_prepend (seekable_pads, seekable);
@@ -305,7 +315,7 @@ static GstElement *
make_mp3_pipeline (const gchar * location)
{
GstElement *pipeline;
- GstElement *src, *decoder, *osssink, *queue, *audio_thread;
+ GstElement *src, *decoder, *osssink, *queue;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -315,8 +325,6 @@ make_mp3_pipeline (const gchar * location)
queue = gst_element_factory_make_or_warn ("queue", "queue");
osssink = gst_element_factory_make_or_warn ("osssink", "sink");
- audio_thread = gst_thread_new ("a_decoder_thread");
-
seekable_elements = g_list_prepend (seekable_elements, osssink);
g_object_set (G_OBJECT (src), "location", location, NULL);
@@ -324,9 +332,8 @@ make_mp3_pipeline (const gchar * location)
gst_bin_add (GST_BIN (pipeline), src);
gst_bin_add (GST_BIN (pipeline), decoder);
- gst_bin_add (GST_BIN (audio_thread), queue);
- gst_bin_add (GST_BIN (audio_thread), osssink);
- gst_bin_add (GST_BIN (pipeline), audio_thread);
+ gst_bin_add (GST_BIN (pipeline), queue);
+ gst_bin_add (GST_BIN (pipeline), osssink);
gst_element_link (src, decoder);
gst_element_link (decoder, queue);
@@ -345,8 +352,7 @@ make_avi_pipeline (const gchar * location)
{
GstElement *pipeline, *audio_bin, *video_bin;
GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
- GstElement *a_queue = NULL, *audio_thread = NULL, *v_queue =
- NULL, *video_thread = NULL;
+ GstElement *a_queue = NULL, *v_queue = NULL;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -363,16 +369,14 @@ make_avi_pipeline (const gchar * location)
audio_bin = gst_bin_new ("a_decoder_bin");
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
- audio_thread = gst_thread_new ("a_decoder_thread");
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
gst_element_link (a_decoder, a_queue);
gst_element_link (a_queue, audiosink);
gst_bin_add (GST_BIN (audio_bin), a_decoder);
- gst_bin_add (GST_BIN (audio_bin), audio_thread);
- gst_bin_add (GST_BIN (audio_thread), a_queue);
- gst_bin_add (GST_BIN (audio_thread), audiosink);
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
gst_element_set_state (audio_bin, GST_STATE_PAUSED);
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
@@ -388,7 +392,6 @@ make_avi_pipeline (const gchar * location)
//v_decoder = gst_element_factory_make_or_warn ("identity", "v_dec");
//v_decoder = gst_element_factory_make_or_warn ("windec", "v_dec");
v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
- video_thread = gst_thread_new ("v_decoder_thread");
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
//videosink = gst_element_factory_make_or_warn ("fakesink", "v_sink");
//g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
@@ -397,9 +400,8 @@ make_avi_pipeline (const gchar * location)
gst_element_link (v_decoder, v_queue);
gst_element_link (v_queue, videosink);
gst_bin_add (GST_BIN (video_bin), v_decoder);
- gst_bin_add (GST_BIN (video_bin), video_thread);
- gst_bin_add (GST_BIN (video_thread), v_queue);
- gst_bin_add (GST_BIN (video_thread), videosink);
+ gst_bin_add (GST_BIN (video_bin), v_queue);
+ gst_bin_add (GST_BIN (video_bin), videosink);
gst_element_set_state (video_bin, GST_STATE_PAUSED);
@@ -421,7 +423,7 @@ make_mpeg_pipeline (const gchar * location)
GstElement *pipeline, *audio_bin, *video_bin;
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
GstElement *audiosink, *videosink;
- GstElement *a_queue, *audio_thread, *v_queue, *video_thread;
+ GstElement *a_queue, *v_queue;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -440,16 +442,14 @@ make_mpeg_pipeline (const gchar * location)
audio_bin = gst_bin_new ("a_decoder_bin");
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
- audio_thread = gst_thread_new ("a_decoder_thread");
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
gst_element_link (a_decoder, a_queue);
gst_element_link (a_queue, audiosink);
gst_bin_add (GST_BIN (audio_bin), a_decoder);
- gst_bin_add (GST_BIN (audio_bin), audio_thread);
- gst_bin_add (GST_BIN (audio_thread), a_queue);
- gst_bin_add (GST_BIN (audio_thread), audiosink);
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
"sink"), audio_bin);
@@ -462,7 +462,6 @@ make_mpeg_pipeline (const gchar * location)
video_bin = gst_bin_new ("v_decoder_bin");
v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
- video_thread = gst_thread_new ("v_decoder_thread");
//g_object_set (G_OBJECT (video_thread), "priority", 2, NULL);
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
@@ -470,8 +469,8 @@ make_mpeg_pipeline (const gchar * location)
gst_element_link_many (v_decoder, v_queue, v_filter, NULL);
gst_element_link (v_filter, videosink);
- gst_bin_add_many (GST_BIN (video_bin), v_decoder, video_thread, NULL);
- gst_bin_add_many (GST_BIN (video_thread), v_queue, v_filter, videosink, NULL);
+ gst_bin_add_many (GST_BIN (video_bin), v_decoder, NULL);
+ gst_bin_add_many (GST_BIN (video_bin), v_queue, v_filter, videosink, NULL);
setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
"sink"), video_bin);
@@ -491,7 +490,7 @@ make_mpegnt_pipeline (const gchar * location)
GstElement *pipeline, *audio_bin, *video_bin;
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
GstElement *audiosink, *videosink;
- GstElement *a_queue, *audio_thread;
+ GstElement *a_queue;
GstPad *seekable;
pipeline = gst_pipeline_new ("app");
@@ -510,7 +509,6 @@ make_mpegnt_pipeline (const gchar * location)
audio_bin = gst_bin_new ("a_decoder_bin");
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
- audio_thread = gst_thread_new ("a_decoder_thread");
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
@@ -518,9 +516,8 @@ make_mpegnt_pipeline (const gchar * location)
gst_element_link (a_decoder, a_queue);
gst_element_link (a_queue, audiosink);
gst_bin_add (GST_BIN (audio_bin), a_decoder);
- gst_bin_add (GST_BIN (audio_bin), audio_thread);
- gst_bin_add (GST_BIN (audio_thread), a_queue);
- gst_bin_add (GST_BIN (audio_thread), audiosink);
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
"sink"), audio_bin);
@@ -758,7 +755,7 @@ update_scale (gpointer data)
gboolean res;
duration = 0;
- clock = gst_bin_get_clock (GST_BIN (pipeline));
+ clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
if (elem_seek) {
if (seekable_elements) {
@@ -811,25 +808,6 @@ update_scale (gpointer data)
}
static gboolean
-iterate (gpointer data)
-{
- gboolean res;
-
- if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
- res = gst_bin_iterate (GST_BIN (data));
- } else {
- g_usleep (500);
- res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
- }
-
- if (!res) {
- gtk_timeout_remove (update_id);
- g_print ("stopping iterations\n");
- }
- return res;
-}
-
-static gboolean
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
{
gst_element_set_state (pipeline, GST_STATE_PAUSED);
@@ -880,7 +858,6 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
}
gst_element_set_state (pipeline, GST_STATE_PLAYING);
- gtk_idle_add ((GtkFunction) iterate, pipeline);
update_id =
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
@@ -890,9 +867,11 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
static void
play_cb (GtkButton * button, gpointer data)
{
- if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
+ GstElementState state;
+
+ gst_element_get_state (pipeline, &state, NULL, NULL);
+ if (state != GST_STATE_PLAYING) {
gst_element_set_state (pipeline, GST_STATE_PLAYING);
- gtk_idle_add ((GtkFunction) iterate, pipeline);
update_id =
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
}
@@ -901,7 +880,10 @@ play_cb (GtkButton * button, gpointer data)
static void
pause_cb (GtkButton * button, gpointer data)
{
- if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
+ GstElementState state;
+
+ gst_element_get_state (pipeline, &state, NULL, NULL);
+ if (state != GST_STATE_PAUSED) {
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gtk_timeout_remove (update_id);
}
@@ -910,7 +892,10 @@ pause_cb (GtkButton * button, gpointer data)
static void
stop_cb (GtkButton * button, gpointer data)
{
- if (gst_element_get_state (pipeline) != GST_STATE_READY) {
+ GstElementState state;
+
+ gst_element_get_state (pipeline, &state, NULL, NULL);
+ if (state != GST_STATE_READY) {
gst_element_set_state (pipeline, GST_STATE_READY);
gtk_adjustment_set_value (adjustment, 0.0);
gtk_timeout_remove (update_id);
@@ -1032,18 +1017,13 @@ main (int argc, char **argv)
if (verbose) {
g_signal_connect (pipeline, "deep_notify",
- G_CALLBACK (gst_element_default_deep_notify), NULL);
+ G_CALLBACK (gst_object_default_deep_notify), NULL);
}
- g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
- NULL);
-
gtk_main ();
gst_element_set_state (pipeline, GST_STATE_NULL);
- //gst_object_unref (GST_OBJECT (pipeline));
-
- //g_mem_chunk_info();
+ gst_object_unref (GST_OBJECT (pipeline));
return 0;
}