diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2004-12-29 11:04:28 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2004-12-29 11:04:28 +0000 |
commit | a52078924d1a3e30f2e27390323704cb59ecace8 (patch) | |
tree | f4bcfb28139683ea34e1cf0273df57fa88af5df3 | |
parent | b55e609daa1d06a35950bbce78de8ebe73ec17d3 (diff) | |
download | gstreamer-plugins-base-a52078924d1a3e30f2e27390323704cb59ecace8.tar.gz |
Various plugin updates.
Original commit message from CVS:
Various plugin updates.
-rw-r--r-- | ChangeLog | 70 | ||||
-rw-r--r-- | examples/seeking/seek.c | 124 | ||||
-rw-r--r-- | ext/ogg/README | 105 | ||||
-rw-r--r-- | ext/ogg/gstoggdemux.c | 2164 | ||||
-rw-r--r-- | ext/ogg/gstoggmux.c | 40 | ||||
-rw-r--r-- | ext/ogg/gstogmparse.c | 26 | ||||
-rw-r--r-- | ext/theora/theoradec.c | 65 | ||||
-rw-r--r-- | ext/theora/theoraenc.c | 74 | ||||
-rw-r--r-- | ext/vorbis/Makefile.am | 4 | ||||
-rw-r--r-- | ext/vorbis/vorbis.c | 5 | ||||
-rw-r--r-- | ext/vorbis/vorbisdec.c | 126 | ||||
-rw-r--r-- | ext/vorbis/vorbisenc.c | 106 | ||||
-rw-r--r-- | ext/vorbis/vorbisparse.c | 19 | ||||
-rw-r--r-- | gst/audioconvert/bufferframesconvert.c | 41 | ||||
-rw-r--r-- | gst/audioconvert/gstaudioconvert.c | 250 | ||||
-rw-r--r-- | gst/audioconvert/gstchannelmix.h | 3 | ||||
-rw-r--r-- | gst/ffmpegcolorspace/gstffmpegcolorspace.c | 22 | ||||
-rw-r--r-- | tests/examples/seek/seek.c | 124 |
18 files changed, 1496 insertions, 1872 deletions
@@ -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 (©, "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; } |