mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
Updated seek example.
Original commit message from CVS: * docs/libs/tmpl/gstringbuffer.sgml: * examples/seeking/seek.c: (make_vorbis_theora_pipeline), (query_rates), (query_positions_elems), (query_positions_pads), (update_scale), (do_seek): Updated seek example. * ext/ogg/gstoggdemux.c: (gst_ogg_pad_submit_packet), (gst_ogg_pad_submit_page), (gst_ogg_demux_activate_chain), (gst_ogg_demux_find_chains), (gst_ogg_demux_send_event), (gst_ogg_demux_loop): Push out correct discont values. * ext/theora/theoradec.c: (theora_dec_src_convert), (theora_dec_sink_convert), (theora_dec_src_getcaps), (theora_dec_sink_event), (theora_handle_type_packet), (theora_handle_header_packet), (theora_dec_push), (theora_handle_data_packet), (theora_dec_chain), (theora_dec_change_state): Better timestamping. * ext/vorbis/vorbisdec.c: (gst_vorbis_dec_init), (vorbis_dec_sink_event), (vorbis_dec_push), (vorbis_handle_data_packet), (vorbis_dec_chain): * ext/vorbis/vorbisdec.h: Better timestamping. * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_get_time), (gst_base_audio_sink_get_times), (gst_base_audio_sink_event), (gst_base_audio_sink_render): Handle syncing on timestamps instead of sample offsets. Make use of DISCONT values as described in design docs. * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_get_time): * gst-libs/gst/audio/gstringbuffer.c: (gst_ring_buffer_acquire), (gst_ring_buffer_set_sample), (gst_ring_buffer_commit), (gst_ring_buffer_read): * gst-libs/gst/audio/gstringbuffer.h: * sys/ximage/ximagesink.c: (gst_ximagesink_get_times), (gst_ximagesink_show_frame): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_times): Correcly convert buffer timestamp to stream time.
This commit is contained in:
parent
567802ca2c
commit
82dc411e33
14 changed files with 289 additions and 289 deletions
45
ChangeLog
45
ChangeLog
|
@ -1,3 +1,48 @@
|
||||||
|
2005-07-16 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* docs/libs/tmpl/gstringbuffer.sgml:
|
||||||
|
* examples/seeking/seek.c: (make_vorbis_theora_pipeline),
|
||||||
|
(query_rates), (query_positions_elems), (query_positions_pads),
|
||||||
|
(update_scale), (do_seek):
|
||||||
|
Updated seek example.
|
||||||
|
|
||||||
|
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_submit_packet),
|
||||||
|
(gst_ogg_pad_submit_page), (gst_ogg_demux_activate_chain),
|
||||||
|
(gst_ogg_demux_find_chains), (gst_ogg_demux_send_event),
|
||||||
|
(gst_ogg_demux_loop):
|
||||||
|
Push out correct discont values.
|
||||||
|
|
||||||
|
* ext/theora/theoradec.c: (theora_dec_src_convert),
|
||||||
|
(theora_dec_sink_convert), (theora_dec_src_getcaps),
|
||||||
|
(theora_dec_sink_event), (theora_handle_type_packet),
|
||||||
|
(theora_handle_header_packet), (theora_dec_push),
|
||||||
|
(theora_handle_data_packet), (theora_dec_chain),
|
||||||
|
(theora_dec_change_state):
|
||||||
|
Better timestamping.
|
||||||
|
|
||||||
|
* ext/vorbis/vorbisdec.c: (gst_vorbis_dec_init),
|
||||||
|
(vorbis_dec_sink_event), (vorbis_dec_push),
|
||||||
|
(vorbis_handle_data_packet), (vorbis_dec_chain):
|
||||||
|
* ext/vorbis/vorbisdec.h:
|
||||||
|
Better timestamping.
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosink.c:
|
||||||
|
(gst_base_audio_sink_get_time), (gst_base_audio_sink_get_times),
|
||||||
|
(gst_base_audio_sink_event), (gst_base_audio_sink_render):
|
||||||
|
Handle syncing on timestamps instead of sample offsets. Make
|
||||||
|
use of DISCONT values as described in design docs.
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosrc.c:
|
||||||
|
(gst_base_audio_src_get_time):
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.c: (gst_ring_buffer_acquire),
|
||||||
|
(gst_ring_buffer_set_sample), (gst_ring_buffer_commit),
|
||||||
|
(gst_ring_buffer_read):
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.h:
|
||||||
|
* sys/ximage/ximagesink.c: (gst_ximagesink_get_times),
|
||||||
|
(gst_ximagesink_show_frame):
|
||||||
|
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_times):
|
||||||
|
Correcly convert buffer timestamp to stream time.
|
||||||
|
|
||||||
2005-07-16 Wim Taymans <wim@fluendo.com>
|
2005-07-16 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* gst/audioconvert/gstaudioconvert.c:
|
* gst/audioconvert/gstaudioconvert.c:
|
||||||
|
|
|
@ -28,6 +28,7 @@ an implementation of an audio ringbuffer
|
||||||
@empty_seg:
|
@empty_seg:
|
||||||
@state:
|
@state:
|
||||||
@segdone:
|
@segdone:
|
||||||
|
@segbase:
|
||||||
@waiting:
|
@waiting:
|
||||||
|
|
||||||
<!-- ##### STRUCT GstRingBufferClass ##### -->
|
<!-- ##### STRUCT GstRingBufferClass ##### -->
|
||||||
|
|
|
@ -21,7 +21,7 @@ static guint update_id;
|
||||||
static guint seek_timeout_id = 0;
|
static guint seek_timeout_id = 0;
|
||||||
static gulong changed_id;
|
static gulong changed_id;
|
||||||
|
|
||||||
//#define SOURCE "gnomevfssrc"
|
//#define SOURCE "filesrc"
|
||||||
#define SOURCE "gnomevfssrc"
|
#define SOURCE "gnomevfssrc"
|
||||||
#define ASINK "alsasink"
|
#define ASINK "alsasink"
|
||||||
//#define ASINK "osssink"
|
//#define ASINK "osssink"
|
||||||
|
@ -33,8 +33,8 @@ static gulong changed_id;
|
||||||
#define UPDATE_INTERVAL 500
|
#define UPDATE_INTERVAL 500
|
||||||
|
|
||||||
/* number of milliseconds to play for after a seek */
|
/* number of milliseconds to play for after a seek */
|
||||||
#define SCRUB_TIME 250
|
//#define SCRUB_TIME 250
|
||||||
#define SCRUB
|
//#define SCRUB
|
||||||
|
|
||||||
#define THREAD
|
#define THREAD
|
||||||
#define PAD_SEEK
|
#define PAD_SEEK
|
||||||
|
@ -376,6 +376,7 @@ make_vorbis_theora_pipeline (const gchar * location)
|
||||||
GstElement *audiosink, *videosink;
|
GstElement *audiosink, *videosink;
|
||||||
GstElement *a_queue, *v_queue;
|
GstElement *a_queue, *v_queue;
|
||||||
GstPad *seekable;
|
GstPad *seekable;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
pipeline = gst_pipeline_new ("app");
|
pipeline = gst_pipeline_new ("app");
|
||||||
|
|
||||||
|
@ -405,8 +406,9 @@ make_vorbis_theora_pipeline (const gchar * location)
|
||||||
gst_element_link (a_decoder, a_convert);
|
gst_element_link (a_decoder, a_convert);
|
||||||
gst_element_link (a_convert, audiosink);
|
gst_element_link (a_convert, audiosink);
|
||||||
|
|
||||||
gst_element_add_ghost_pad (audio_bin, gst_element_get_pad (a_queue, "sink"),
|
pad = gst_element_get_pad (a_queue, "sink");
|
||||||
"sink");
|
gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
|
||||||
|
gst_object_unref (GST_OBJECT_CAST (pad));
|
||||||
|
|
||||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
|
setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -427,8 +429,9 @@ make_vorbis_theora_pipeline (const gchar * location)
|
||||||
|
|
||||||
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
||||||
|
|
||||||
gst_element_add_ghost_pad (video_bin, gst_element_get_pad (v_queue, "sink"),
|
pad = gst_element_get_pad (v_queue, "sink");
|
||||||
"sink");
|
gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
|
||||||
|
gst_object_unref (GST_OBJECT_CAST (pad));
|
||||||
|
|
||||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
|
setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -933,6 +936,8 @@ update_scale (gpointer data)
|
||||||
gtk_widget_queue_draw (hscale);
|
gtk_widget_queue_draw (hscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_object_unref (clock);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,7 +997,7 @@ do_seek (GtkWidget * widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
GST_PIPELINE (pipeline)->stream_time = real;
|
gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
|
||||||
else
|
else
|
||||||
g_print ("seek failed\n");
|
g_print ("seek failed\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -898,6 +898,7 @@ static gboolean gst_ogg_demux_sink_activate_pull (GstPad * sinkpad,
|
||||||
static gboolean gst_ogg_demux_sink_activate_push (GstPad * sinkpad,
|
static gboolean gst_ogg_demux_sink_activate_push (GstPad * sinkpad,
|
||||||
gboolean active);
|
gboolean active);
|
||||||
static GstElementStateReturn gst_ogg_demux_change_state (GstElement * element);
|
static GstElementStateReturn gst_ogg_demux_change_state (GstElement * element);
|
||||||
|
static void gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event);
|
||||||
|
|
||||||
static void gst_ogg_print (GstOggDemux * demux);
|
static void gst_ogg_print (GstOggDemux * demux);
|
||||||
|
|
||||||
|
@ -1173,6 +1174,7 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain)
|
||||||
gint i;
|
gint i;
|
||||||
GList *headers;
|
GList *headers;
|
||||||
GstOggPad *pad;
|
GstOggPad *pad;
|
||||||
|
GstEvent *event;
|
||||||
|
|
||||||
if (chain == ogg->current_chain)
|
if (chain == ogg->current_chain)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1188,6 +1190,13 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain)
|
||||||
gst_element_no_more_pads (GST_ELEMENT (ogg));
|
gst_element_no_more_pads (GST_ELEMENT (ogg));
|
||||||
ogg->current_chain = chain;
|
ogg->current_chain = chain;
|
||||||
|
|
||||||
|
/* send the base time */
|
||||||
|
event = gst_event_new_discontinuous (1.0,
|
||||||
|
GST_FORMAT_TIME, (gint64) chain->start_time, (gint64) chain->total_time,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gst_ogg_demux_send_event (ogg, event);
|
||||||
|
|
||||||
/* then send out the buffers */
|
/* then send out the buffers */
|
||||||
for (i = 0; i < chain->streams->len; i++) {
|
for (i = 0; i < chain->streams->len; i++) {
|
||||||
pad = g_array_index (chain->streams, GstOggPad *, i);
|
pad = g_array_index (chain->streams, GstOggPad *, i);
|
||||||
|
@ -1775,7 +1784,7 @@ gst_ogg_demux_find_chains (GstOggDemux * ogg)
|
||||||
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
|
GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
|
||||||
|
|
||||||
chain->total_time = 0;
|
chain->total_time = 0;
|
||||||
chain->start_time = 0;
|
chain->start_time = G_MAXINT64;
|
||||||
chain->last_time = 0;
|
chain->last_time = 0;
|
||||||
chain->begin_time = ogg->total_time;
|
chain->begin_time = ogg->total_time;
|
||||||
|
|
||||||
|
@ -1904,7 +1913,7 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_ogg_demux_send_eos (GstOggDemux * ogg)
|
gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstOggChain *chain = ogg->current_chain;
|
GstOggChain *chain = ogg->current_chain;
|
||||||
|
|
||||||
|
@ -1914,9 +1923,11 @@ gst_ogg_demux_send_eos (GstOggDemux * ogg)
|
||||||
for (i = 0; i < chain->streams->len; i++) {
|
for (i = 0; i < chain->streams->len; i++) {
|
||||||
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
||||||
|
|
||||||
gst_pad_push_event (GST_PAD (pad), gst_event_new (GST_EVENT_EOS));
|
gst_event_ref (event);
|
||||||
|
gst_pad_push_event (GST_PAD (pad), event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gst_event_unref (event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* random access code
|
/* random access code
|
||||||
|
@ -1946,6 +1957,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
|
||||||
GST_CHAIN_UNLOCK (ogg);
|
GST_CHAIN_UNLOCK (ogg);
|
||||||
if (!got_chains)
|
if (!got_chains)
|
||||||
goto chain_read_failed;
|
goto chain_read_failed;
|
||||||
|
|
||||||
ogg->need_chains = FALSE;
|
ogg->need_chains = FALSE;
|
||||||
ogg->offset = 0;
|
ogg->offset = 0;
|
||||||
}
|
}
|
||||||
|
@ -1953,7 +1965,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
|
||||||
GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset);
|
GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset);
|
||||||
if (ogg->offset == ogg->length) {
|
if (ogg->offset == ogg->length) {
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
gst_ogg_demux_send_eos (ogg);
|
gst_ogg_demux_send_event (ogg, gst_event_new (GST_EVENT_EOS));
|
||||||
goto pause;
|
goto pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1982,7 +1994,7 @@ pause:
|
||||||
GST_LOG_OBJECT (ogg, "pausing task, reason %d", ret);
|
GST_LOG_OBJECT (ogg, "pausing task, reason %d", ret);
|
||||||
gst_pad_pause_task (ogg->sinkpad);
|
gst_pad_pause_task (ogg->sinkpad);
|
||||||
if (GST_FLOW_IS_FATAL (ret)) {
|
if (GST_FLOW_IS_FATAL (ret)) {
|
||||||
gst_ogg_demux_send_eos (ogg);
|
gst_ogg_demux_send_event (ogg, gst_event_new (GST_EVENT_EOS));
|
||||||
GST_ELEMENT_ERROR (ogg, STREAM, STOPPED,
|
GST_ELEMENT_ERROR (ogg, STREAM, STOPPED,
|
||||||
("stream stopped, reason %d", ret),
|
("stream stopped, reason %d", ret),
|
||||||
("stream stopped, reason %d", ret));
|
("stream stopped, reason %d", ret));
|
||||||
|
|
|
@ -54,10 +54,11 @@ struct _GstTheoraDec
|
||||||
theora_info info;
|
theora_info info;
|
||||||
theora_comment comment;
|
theora_comment comment;
|
||||||
|
|
||||||
guint packetno;
|
gboolean have_header;
|
||||||
guint64 granulepos;
|
guint64 granulepos;
|
||||||
|
|
||||||
gboolean initialized;
|
GstClockTime last_timestamp;
|
||||||
|
guint64 frame_nr;
|
||||||
gboolean need_keyframe;
|
gboolean need_keyframe;
|
||||||
gint width, height;
|
gint width, height;
|
||||||
gint offset_x, offset_y;
|
gint offset_x, offset_y;
|
||||||
|
@ -281,7 +282,7 @@ theora_dec_src_convert (GstPad * pad,
|
||||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
/* we need the info part before we can done something */
|
/* we need the info part before we can done something */
|
||||||
if (dec->packetno < 1)
|
if (!dec->have_header)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (src_format == *dest_format) {
|
if (src_format == *dest_format) {
|
||||||
|
@ -347,7 +348,7 @@ theora_dec_sink_convert (GstPad * pad,
|
||||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
/* we need the info part before we can done something */
|
/* we need the info part before we can done something */
|
||||||
if (dec->packetno < 1)
|
if (!dec->have_header)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (src_format == *dest_format) {
|
if (src_format == *dest_format) {
|
||||||
|
@ -581,69 +582,32 @@ theora_dec_src_getcaps (GstPad * pad)
|
||||||
static gboolean
|
static gboolean
|
||||||
theora_dec_sink_event (GstPad * pad, GstEvent * event)
|
theora_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
gint64 start_value, end_value, time, bytes;
|
|
||||||
gboolean ret = TRUE;
|
gboolean ret = TRUE;
|
||||||
GstTheoraDec *dec;
|
GstTheoraDec *dec;
|
||||||
|
|
||||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "handling event");
|
GST_LOG_OBJECT (dec, "handling event");
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
ret = gst_pad_push_event (dec->srcpad, event);
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
break;
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
GST_STREAM_LOCK (pad);
|
GST_STREAM_LOCK (pad);
|
||||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT,
|
dec->need_keyframe = TRUE;
|
||||||
&start_value, &end_value)) {
|
dec->granulepos = -1;
|
||||||
dec->granulepos = start_value;
|
dec->last_timestamp = -1;
|
||||||
GST_DEBUG_OBJECT (dec,
|
ret = gst_pad_push_event (dec->srcpad, event);
|
||||||
"setting granuleposition to %" G_GUINT64_FORMAT " after discont",
|
|
||||||
start_value);
|
|
||||||
} else {
|
|
||||||
GST_WARNING_OBJECT (dec,
|
|
||||||
"discont event didn't include offset, we might set it wrong now");
|
|
||||||
dec->granulepos = -1;
|
|
||||||
}
|
|
||||||
if (dec->packetno < 3) {
|
|
||||||
if (dec->granulepos != 0)
|
|
||||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
|
||||||
("can't handle discont before parsing first 3 packets"));
|
|
||||||
dec->packetno = 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;
|
|
||||||
|
|
||||||
time_format = GST_FORMAT_TIME;
|
|
||||||
default_format = GST_FORMAT_DEFAULT;
|
|
||||||
bytes_format = GST_FORMAT_BYTES;
|
|
||||||
|
|
||||||
/* if one of them works, all of them work */
|
|
||||||
if (theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT,
|
|
||||||
dec->granulepos, &time_format, &time)
|
|
||||||
&& theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
|
|
||||||
&default_format, &start_value)
|
|
||||||
&& theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
|
|
||||||
&bytes_format, &bytes)) {
|
|
||||||
gst_pad_push_event (dec->srcpad,
|
|
||||||
gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
|
||||||
time, GST_FORMAT_DEFAULT, start_value, GST_FORMAT_BYTES,
|
|
||||||
bytes, 0));
|
|
||||||
/* store new framenumber */
|
|
||||||
dec->packetno = start_value + 3;
|
|
||||||
} else {
|
|
||||||
GST_ERROR_OBJECT (dec,
|
|
||||||
"failed to parse data for DISCONT event, not sending any");
|
|
||||||
}
|
|
||||||
/* sync to keyframe */
|
|
||||||
dec->need_keyframe = TRUE;
|
|
||||||
}
|
|
||||||
GST_STREAM_UNLOCK (pad);
|
GST_STREAM_UNLOCK (pad);
|
||||||
gst_event_unref (event);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = gst_pad_event_default (dec->sinkpad, event);
|
ret = gst_pad_push_event (dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
gst_object_unref (dec);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,7 +714,7 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
|
||||||
gst_pad_set_caps (dec->srcpad, caps);
|
gst_pad_set_caps (dec->srcpad, caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
dec->initialized = TRUE;
|
dec->have_header = TRUE;
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
@ -765,15 +729,18 @@ theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
|
||||||
if (theora_decode_header (&dec->info, &dec->comment, packet))
|
if (theora_decode_header (&dec->info, &dec->comment, packet))
|
||||||
goto header_read_error;
|
goto header_read_error;
|
||||||
|
|
||||||
switch (packet->packetno) {
|
switch (packet->packet[0]) {
|
||||||
case 1:
|
case 0x81:
|
||||||
res = theora_handle_comment_packet (dec, packet);
|
res = theora_handle_comment_packet (dec, packet);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 0x82:
|
||||||
res = theora_handle_type_packet (dec, packet);
|
res = theora_handle_type_packet (dec, packet);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* ignore */
|
/* ignore */
|
||||||
|
g_warning ("unknown theora header packet found");
|
||||||
|
case 0x80:
|
||||||
|
/* nothing special, this is the identification header */
|
||||||
res = GST_FLOW_OK;
|
res = GST_FLOW_OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -792,8 +759,39 @@ static GstFlowReturn
|
||||||
theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
|
theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstFlowReturn result;
|
GstFlowReturn result;
|
||||||
|
GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
|
||||||
result = gst_pad_push (dec->srcpad, buf);
|
if (outtime == GST_CLOCK_TIME_NONE) {
|
||||||
|
dec->queued = g_list_append (dec->queued, buf);
|
||||||
|
GST_DEBUG_OBJECT (dec, "queued buffer");
|
||||||
|
result = GST_FLOW_OK;
|
||||||
|
} else {
|
||||||
|
if (dec->queued) {
|
||||||
|
gint64 size;
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "first buffer with time %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (outtime));
|
||||||
|
|
||||||
|
size = g_list_length (dec->queued);
|
||||||
|
for (walk = dec->queued; walk; walk = g_list_next (walk)) {
|
||||||
|
GstBuffer *buffer = GST_BUFFER (walk->data);
|
||||||
|
GstClockTime time;
|
||||||
|
|
||||||
|
time = outtime - ((size * GST_SECOND * dec->info.fps_denominator)
|
||||||
|
/ dec->info.fps_numerator);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", size, time);
|
||||||
|
GST_BUFFER_TIMESTAMP (buffer) = time;
|
||||||
|
/* ignore the result */
|
||||||
|
gst_pad_push (dec->srcpad, buffer);
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
g_list_free (dec->queued);
|
||||||
|
dec->queued = NULL;
|
||||||
|
}
|
||||||
|
result = gst_pad_push (dec->srcpad, buf);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -813,7 +811,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
|
||||||
gint cwidth, cheight;
|
gint cwidth, cheight;
|
||||||
GstFlowReturn result;
|
GstFlowReturn result;
|
||||||
|
|
||||||
if (!dec->initialized)
|
if (!dec->have_header)
|
||||||
goto not_initialized;
|
goto not_initialized;
|
||||||
|
|
||||||
/* the second most significant bit of the first data byte is cleared
|
/* the second most significant bit of the first data byte is cleared
|
||||||
|
@ -894,8 +892,9 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_BUFFER_OFFSET (out) = dec->packetno - 4;
|
GST_BUFFER_OFFSET (out) = dec->frame_nr;
|
||||||
GST_BUFFER_OFFSET_END (out) = dec->packetno - 3;
|
dec->frame_nr++;
|
||||||
|
GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
|
||||||
GST_BUFFER_DURATION (out) =
|
GST_BUFFER_DURATION (out) =
|
||||||
GST_SECOND * ((gdouble) dec->info.fps_denominator) /
|
GST_SECOND * ((gdouble) dec->info.fps_denominator) /
|
||||||
dec->info.fps_numerator;
|
dec->info.fps_numerator;
|
||||||
|
@ -909,7 +908,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
|
||||||
not_initialized:
|
not_initialized:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
|
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
|
||||||
(NULL), ("no header sent yet (packet no is %d)", packet->packetno));
|
(NULL), ("no header sent yet"));
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
dropping:
|
dropping:
|
||||||
|
@ -946,110 +945,50 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstTheoraDec *dec;
|
GstTheoraDec *dec;
|
||||||
ogg_packet packet;
|
ogg_packet packet;
|
||||||
guint64 offset_end;
|
|
||||||
GstClockTime outtime;
|
|
||||||
GstFlowReturn result = GST_FLOW_OK;
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
if (dec->packetno >= 3) {
|
|
||||||
/* try timestamp first */
|
|
||||||
outtime = GST_BUFFER_TIMESTAMP (buf);
|
|
||||||
|
|
||||||
if (outtime == -1) {
|
|
||||||
gboolean need_flush = FALSE;
|
|
||||||
|
|
||||||
/* the offset end field in theora is actually the time of
|
|
||||||
* this frame, not the end time */
|
|
||||||
offset_end = GST_BUFFER_OFFSET_END (buf);
|
|
||||||
GST_DEBUG_OBJECT (dec, "got buffer with granule %lld", offset_end);
|
|
||||||
|
|
||||||
if (offset_end != -1) {
|
|
||||||
if (dec->granulepos == -1) {
|
|
||||||
GST_DEBUG_OBJECT (dec, "first buffer with granule");
|
|
||||||
need_flush = TRUE;
|
|
||||||
}
|
|
||||||
dec->granulepos = offset_end;
|
|
||||||
}
|
|
||||||
if (dec->granulepos == -1) {
|
|
||||||
/* we need to wait for a buffer with at least a timestamp or an
|
|
||||||
* offset before we can generate valid timestamps */
|
|
||||||
dec->queued = g_list_append (dec->queued, buf);
|
|
||||||
GST_DEBUG_OBJECT (dec, "queued buffer");
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
} else {
|
|
||||||
/* granulepos to time */
|
|
||||||
outtime =
|
|
||||||
GST_SECOND * theora_granule_time (&dec->state, dec->granulepos);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "granulepos=%lld outtime=%" GST_TIME_FORMAT,
|
|
||||||
dec->granulepos, GST_TIME_ARGS (outtime));
|
|
||||||
|
|
||||||
if (need_flush) {
|
|
||||||
GList *walk;
|
|
||||||
GstClockTime patch;
|
|
||||||
gint64 len;
|
|
||||||
gint64 old_granule = dec->granulepos;
|
|
||||||
|
|
||||||
dec->granulepos = -1;
|
|
||||||
|
|
||||||
len = g_list_length (dec->queued);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "first buffer with granule, flushing");
|
|
||||||
|
|
||||||
/* now resubmit all queued buffers with corrected timestamps */
|
|
||||||
for (walk = dec->queued; walk; walk = g_list_next (walk)) {
|
|
||||||
GstBuffer *qbuffer = GST_BUFFER (walk->data);
|
|
||||||
|
|
||||||
patch = outtime - (GST_SECOND * len * dec->info.fps_denominator) /
|
|
||||||
dec->info.fps_numerator,
|
|
||||||
GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", len, patch);
|
|
||||||
GST_BUFFER_TIMESTAMP (qbuffer) = patch;
|
|
||||||
|
|
||||||
/* buffers are unreffed in chain function */
|
|
||||||
theora_dec_chain (pad, qbuffer);
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
g_list_free (dec->queued);
|
|
||||||
dec->queued = NULL;
|
|
||||||
|
|
||||||
dec->granulepos = old_granule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (dec, "got buffer with timestamp %lld", outtime);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* we don't know yet */
|
|
||||||
outtime = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make ogg_packet out of the buffer */
|
/* make ogg_packet out of the buffer */
|
||||||
packet.packet = GST_BUFFER_DATA (buf);
|
packet.packet = GST_BUFFER_DATA (buf);
|
||||||
packet.bytes = GST_BUFFER_SIZE (buf);
|
packet.bytes = GST_BUFFER_SIZE (buf);
|
||||||
packet.granulepos = dec->granulepos;
|
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
|
||||||
packet.packetno = dec->packetno;
|
packet.packetno = 0; /* we don't really care */
|
||||||
packet.b_o_s = (packet.packetno == 0) ? 1 : 0;
|
packet.b_o_s = dec->have_header ? 0 : 1;
|
||||||
packet.e_o_s = 0;
|
packet.e_o_s = 0;
|
||||||
|
|
||||||
|
if (dec->have_header) {
|
||||||
|
if (packet.granulepos != -1) {
|
||||||
|
dec->granulepos = packet.granulepos;
|
||||||
|
dec->last_timestamp =
|
||||||
|
GST_SECOND * theora_granule_time (&dec->state, packet.granulepos);
|
||||||
|
} else if (dec->last_timestamp != -1) {
|
||||||
|
dec->last_timestamp +=
|
||||||
|
(GST_SECOND * dec->info.fps_denominator) / dec->info.fps_numerator;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dec->last_timestamp = -1;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "header=%d packetno=%lld, outtime=%" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (dec, "header=%d packetno=%lld, outtime=%" GST_TIME_FORMAT,
|
||||||
packet.packet[0], packet.packetno, GST_TIME_ARGS (outtime));
|
packet.packet[0], packet.packetno, GST_TIME_ARGS (dec->last_timestamp));
|
||||||
|
|
||||||
/* switch depending on packet type */
|
/* switch depending on packet type */
|
||||||
if (packet.packet[0] & 0x80) {
|
if (packet.packet[0] & 0x80) {
|
||||||
if (packet.packetno > 3) {
|
if (dec->have_header) {
|
||||||
GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
|
GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
result = theora_handle_header_packet (dec, &packet);
|
result = theora_handle_header_packet (dec, &packet);
|
||||||
} else {
|
} else {
|
||||||
result = theora_handle_data_packet (dec, &packet, outtime);
|
result = theora_handle_data_packet (dec, &packet, dec->last_timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
dec->packetno++;
|
|
||||||
_inc_granulepos (dec);
|
_inc_granulepos (dec);
|
||||||
|
|
||||||
|
gst_object_unref (dec);
|
||||||
|
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1070,8 +1009,9 @@ theora_dec_change_state (GstElement * element)
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
theora_info_init (&dec->info);
|
theora_info_init (&dec->info);
|
||||||
theora_comment_init (&dec->comment);
|
theora_comment_init (&dec->comment);
|
||||||
|
dec->have_header = FALSE;
|
||||||
dec->need_keyframe = TRUE;
|
dec->need_keyframe = TRUE;
|
||||||
dec->initialized = FALSE;
|
dec->last_timestamp = -1;
|
||||||
dec->granulepos = -1;
|
dec->granulepos = -1;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
@ -1089,7 +1029,7 @@ theora_dec_change_state (GstElement * element)
|
||||||
theora_clear (&dec->state);
|
theora_clear (&dec->state);
|
||||||
theora_comment_clear (&dec->comment);
|
theora_comment_clear (&dec->comment);
|
||||||
theora_info_clear (&dec->info);
|
theora_info_clear (&dec->info);
|
||||||
dec->packetno = 0;
|
dec->have_header = FALSE;
|
||||||
dec->granulepos = -1;
|
dec->granulepos = -1;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
|
|
|
@ -171,6 +171,8 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
|
||||||
gst_pad_set_query_type_function (dec->srcpad, vorbis_get_query_types);
|
gst_pad_set_query_type_function (dec->srcpad, vorbis_get_query_types);
|
||||||
gst_pad_set_query_function (dec->srcpad, vorbis_dec_src_query);
|
gst_pad_set_query_function (dec->srcpad, vorbis_dec_src_query);
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
||||||
|
|
||||||
|
dec->queued = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -366,90 +368,33 @@ vorbis_dec_src_event (GstPad * pad, GstEvent * event)
|
||||||
static gboolean
|
static gboolean
|
||||||
vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
|
vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
gint64 start_value, end_value, time, bytes;
|
|
||||||
gboolean ret = TRUE;
|
gboolean ret = TRUE;
|
||||||
GstVorbisDec *dec;
|
GstVorbisDec *dec;
|
||||||
|
|
||||||
dec = GST_VORBIS_DEC (GST_PAD_PARENT (pad));
|
dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "handling event");
|
GST_LOG_OBJECT (dec, "handling event");
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
ret = gst_pad_push_event (dec->srcpad, event);
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
break;
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
GST_STREAM_LOCK (pad);
|
GST_STREAM_LOCK (pad);
|
||||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT,
|
|
||||||
(gint64 *) & start_value, &end_value)) {
|
|
||||||
dec->granulepos = start_value;
|
|
||||||
GST_DEBUG_OBJECT (dec,
|
|
||||||
"setting granuleposition to %" G_GUINT64_FORMAT " after discont",
|
|
||||||
start_value);
|
|
||||||
} else {
|
|
||||||
if (gst_event_discont_get_value (event, GST_FORMAT_TIME,
|
|
||||||
(gint64 *) & start_value, &end_value)) {
|
|
||||||
dec->granulepos = start_value * dec->vi.rate / GST_SECOND;
|
|
||||||
GST_DEBUG_OBJECT (dec,
|
|
||||||
"setting granuleposition to %" G_GUINT64_FORMAT " after discont",
|
|
||||||
dec->granulepos);
|
|
||||||
} else {
|
|
||||||
GST_WARNING_OBJECT (dec,
|
|
||||||
"discont event didn't include offset, we might set it wrong now");
|
|
||||||
dec->granulepos = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GST_DEBUG ("vd: discont %" G_GUINT64_FORMAT, dec->granulepos);
|
|
||||||
|
|
||||||
dec->granulepos = -1;
|
dec->granulepos = -1;
|
||||||
|
|
||||||
if (dec->packetno < 3) {
|
|
||||||
if (dec->granulepos != 0)
|
|
||||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
|
||||||
("can't handle discont before parsing first 3 packets"));
|
|
||||||
dec->packetno = 0;
|
|
||||||
#if 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));
|
|
||||||
#endif
|
|
||||||
gst_event_ref (event);
|
|
||||||
gst_pad_push_event (dec->srcpad, event);
|
|
||||||
} else {
|
|
||||||
GstFormat time_format, default_format, bytes_format;
|
|
||||||
|
|
||||||
time_format = GST_FORMAT_TIME;
|
|
||||||
default_format = GST_FORMAT_DEFAULT;
|
|
||||||
bytes_format = GST_FORMAT_BYTES;
|
|
||||||
|
|
||||||
dec->packetno = 3;
|
|
||||||
/* if one of them works, all of them work */
|
|
||||||
if (vorbis_dec_convert (dec->srcpad, GST_FORMAT_DEFAULT,
|
|
||||||
dec->granulepos, &time_format, &time)
|
|
||||||
&& vorbis_dec_convert (dec->srcpad, GST_FORMAT_DEFAULT,
|
|
||||||
dec->granulepos, &bytes_format, &bytes)) {
|
|
||||||
|
|
||||||
gst_event_ref (event);
|
|
||||||
gst_pad_push_event (dec->srcpad, event);
|
|
||||||
/*
|
|
||||||
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");
|
|
||||||
gst_event_ref (event);
|
|
||||||
gst_pad_push_event (dec->srcpad, event);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_VORBIS_SYNTHESIS_RESTART
|
#ifdef HAVE_VORBIS_SYNTHESIS_RESTART
|
||||||
vorbis_synthesis_restart (&dec->vd);
|
vorbis_synthesis_restart (&dec->vd);
|
||||||
#endif
|
#endif
|
||||||
}
|
ret = gst_pad_push_event (dec->srcpad, event);
|
||||||
GST_STREAM_UNLOCK (pad);
|
GST_STREAM_UNLOCK (pad);
|
||||||
gst_event_unref (event);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_push_event (dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
gst_object_unref (dec);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,6 +585,52 @@ copy_samples (float *out, float **in, guint samples, gint channels)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
vorbis_dec_push (GstVorbisDec * dec, GstBuffer * buf)
|
||||||
|
{
|
||||||
|
GstFlowReturn result;
|
||||||
|
gint64 outoffset = GST_BUFFER_OFFSET (buf);
|
||||||
|
|
||||||
|
if (outoffset == -1) {
|
||||||
|
dec->queued = g_list_append (dec->queued, buf);
|
||||||
|
GST_DEBUG_OBJECT (dec, "queued buffer");
|
||||||
|
result = GST_FLOW_OK;
|
||||||
|
} else {
|
||||||
|
if (dec->queued) {
|
||||||
|
gint64 size;
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "first buffer with offset %lld", outoffset);
|
||||||
|
|
||||||
|
size = g_list_length (dec->queued);
|
||||||
|
for (walk = g_list_last (dec->queued); walk;
|
||||||
|
walk = g_list_previous (walk)) {
|
||||||
|
GstBuffer *buffer = GST_BUFFER (walk->data);
|
||||||
|
|
||||||
|
outoffset -=
|
||||||
|
GST_BUFFER_SIZE (buffer) / (sizeof (float) * dec->vi.channels);
|
||||||
|
|
||||||
|
GST_BUFFER_OFFSET (buffer) = outoffset;
|
||||||
|
GST_BUFFER_TIMESTAMP (buffer) = outoffset * GST_SECOND / dec->vi.rate;;
|
||||||
|
GST_DEBUG_OBJECT (dec, "patch buffer %lld offset %lld", size,
|
||||||
|
outoffset);
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
for (walk = dec->queued; walk; walk = g_list_next (walk)) {
|
||||||
|
GstBuffer *buffer = GST_BUFFER (walk->data);
|
||||||
|
|
||||||
|
/* ignore the result */
|
||||||
|
gst_pad_push (dec->srcpad, buffer);
|
||||||
|
}
|
||||||
|
g_list_free (dec->queued);
|
||||||
|
dec->queued = NULL;
|
||||||
|
}
|
||||||
|
result = gst_pad_push (dec->srcpad, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet)
|
vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
|
@ -671,14 +662,15 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet)
|
||||||
copy_samples (out_data, pcm, sample_count, vd->vi.channels);
|
copy_samples (out_data, pcm, sample_count, vd->vi.channels);
|
||||||
|
|
||||||
GST_BUFFER_OFFSET (out) = vd->granulepos;
|
GST_BUFFER_OFFSET (out) = vd->granulepos;
|
||||||
GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count;
|
if (vd->granulepos != -1) {
|
||||||
if (vd->granulepos != -1)
|
GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count;
|
||||||
GST_BUFFER_TIMESTAMP (out) = vd->granulepos * GST_SECOND / vd->vi.rate;
|
GST_BUFFER_TIMESTAMP (out) = vd->granulepos * GST_SECOND / vd->vi.rate;
|
||||||
else
|
} else {
|
||||||
GST_BUFFER_TIMESTAMP (out) = -1;
|
GST_BUFFER_TIMESTAMP (out) = -1;
|
||||||
|
}
|
||||||
GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate;
|
GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate;
|
||||||
|
|
||||||
result = gst_pad_push (vd->srcpad, out);
|
result = vorbis_dec_push (vd, out);
|
||||||
|
|
||||||
if (vd->granulepos != -1)
|
if (vd->granulepos != -1)
|
||||||
vd->granulepos += sample_count;
|
vd->granulepos += sample_count;
|
||||||
|
@ -692,6 +684,10 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet)
|
||||||
result = GST_FLOW_OK;
|
result = GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* granulepos is the last sample in the packet */
|
||||||
|
if (packet->granulepos != -1)
|
||||||
|
vd->granulepos = packet->granulepos;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -727,7 +723,7 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
/* make ogg_packet out of the buffer */
|
/* make ogg_packet out of the buffer */
|
||||||
packet.packet = GST_BUFFER_DATA (buffer);
|
packet.packet = GST_BUFFER_DATA (buffer);
|
||||||
packet.bytes = GST_BUFFER_SIZE (buffer);
|
packet.bytes = GST_BUFFER_SIZE (buffer);
|
||||||
packet.granulepos = vd->granulepos;
|
packet.granulepos = GST_BUFFER_OFFSET_END (buffer);
|
||||||
packet.packetno = vd->packetno++;
|
packet.packetno = vd->packetno++;
|
||||||
/*
|
/*
|
||||||
* FIXME. Is there anyway to know that this is the last packet and
|
* FIXME. Is there anyway to know that this is the last packet and
|
||||||
|
@ -750,10 +746,6 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
GST_DEBUG ("offset end: %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET_END (buffer));
|
GST_DEBUG ("offset end: %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET_END (buffer));
|
||||||
|
|
||||||
/* granulepos is the last sample in the packet */
|
|
||||||
if (GST_BUFFER_OFFSET_END_IS_VALID (buffer))
|
|
||||||
vd->granulepos = GST_BUFFER_OFFSET_END (buffer);;
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,7 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <vorbis/codec.h>
|
#include <vorbis/codec.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_VORBIS_DEC \
|
#define GST_TYPE_VORBIS_DEC \
|
||||||
(gst_vorbis_dec_get_type())
|
(gst_vorbis_dec_get_type())
|
||||||
|
@ -59,6 +56,8 @@ struct _GstVorbisDec {
|
||||||
guint64 granulepos;
|
guint64 granulepos;
|
||||||
|
|
||||||
gboolean initialized;
|
gboolean initialized;
|
||||||
|
|
||||||
|
GList *queued;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstVorbisDecClass {
|
struct _GstVorbisDecClass {
|
||||||
|
@ -67,9 +66,6 @@ struct _GstVorbisDecClass {
|
||||||
|
|
||||||
GType gst_vorbis_dec_get_type(void);
|
GType gst_vorbis_dec_get_type(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_END_DECLS
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_VORBIS_DEC_H__ */
|
#endif /* __GST_VORBIS_DEC_H__ */
|
||||||
|
|
|
@ -163,10 +163,10 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
||||||
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
|
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* our processed samples are always increasing */
|
||||||
samples = gst_ring_buffer_samples_done (sink->ringbuffer);
|
samples = gst_ring_buffer_samples_done (sink->ringbuffer);
|
||||||
|
|
||||||
result = samples * GST_SECOND / sink->ringbuffer->spec.rate;
|
result = samples * GST_SECOND / sink->ringbuffer->spec.rate;
|
||||||
result += GST_ELEMENT (sink)->base_time;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -270,9 +270,8 @@ static void
|
||||||
gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
|
gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
|
||||||
GstClockTime * start, GstClockTime * end)
|
GstClockTime * start, GstClockTime * end)
|
||||||
{
|
{
|
||||||
/* ne need to sync to a clock here, we schedule the samples based
|
/* our clock sync is a bit too much for the base class to handle so
|
||||||
* on our own clock for the moment. FIXME, implement this when
|
* we implement it ourselves. */
|
||||||
* we are not using our own clock */
|
|
||||||
*start = GST_CLOCK_TIME_NONE;
|
*start = GST_CLOCK_TIME_NONE;
|
||||||
*end = GST_CLOCK_TIME_NONE;
|
*end = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
@ -289,25 +288,6 @@ gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
|
||||||
gst_ring_buffer_pause (sink->ringbuffer);
|
gst_ring_buffer_pause (sink->ringbuffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
|
||||||
{
|
|
||||||
gint64 time, sample;
|
|
||||||
|
|
||||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &sample,
|
|
||||||
NULL))
|
|
||||||
goto have_value;
|
|
||||||
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &time, NULL)) {
|
|
||||||
sample = time * sink->ringbuffer->spec.rate / GST_SECOND;
|
|
||||||
goto have_value;
|
|
||||||
}
|
|
||||||
g_warning ("discont without valid timestamp");
|
|
||||||
sample = 0;
|
|
||||||
|
|
||||||
have_value:
|
|
||||||
GST_DEBUG ("discont now at %lld", sample);
|
|
||||||
gst_ring_buffer_set_sample (sink->ringbuffer, sample);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -339,17 +319,38 @@ wrong_state:
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
guint64 offset;
|
guint64 render_offset, in_offset;
|
||||||
|
GstClockTime time, render_time;
|
||||||
GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
|
GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
|
||||||
|
|
||||||
offset = GST_BUFFER_OFFSET (buf);
|
/* can't do anything when we don't have the device */
|
||||||
|
|
||||||
GST_DEBUG ("in offset %llu, time %" GST_TIME_FORMAT, offset,
|
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
|
||||||
if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
|
if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
|
||||||
goto wrong_state;
|
goto wrong_state;
|
||||||
|
|
||||||
gst_ring_buffer_commit (sink->ringbuffer, offset,
|
in_offset = GST_BUFFER_OFFSET (buf);
|
||||||
|
time = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
|
||||||
|
GST_DEBUG ("time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->discont_start));
|
||||||
|
|
||||||
|
/* samples should be rendered based on their timestamp. All samples
|
||||||
|
* arriving before the discont_start are to be trown away */
|
||||||
|
/* FIXME, for now we drop the sample completely, we should
|
||||||
|
* in fact clip the sample */
|
||||||
|
if (time < bsink->discont_start)
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
/* bring buffer timestamp to stream time */
|
||||||
|
render_time = time - bsink->discont_start;
|
||||||
|
/* add base time to get absolute clock time */
|
||||||
|
render_time += gst_element_get_base_time (GST_ELEMENT (bsink));
|
||||||
|
/* and bring the time to the offset in the buffer */
|
||||||
|
render_offset = render_time * sink->ringbuffer->spec.rate / GST_SECOND;
|
||||||
|
|
||||||
|
GST_DEBUG ("render time %" GST_TIME_FORMAT ", render offset %llu",
|
||||||
|
GST_TIME_ARGS (render_time), render_offset);
|
||||||
|
|
||||||
|
gst_ring_buffer_commit (sink->ringbuffer, render_offset,
|
||||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
|
@ -153,7 +153,6 @@ gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
|
||||||
samples = gst_ring_buffer_samples_done (src->ringbuffer);
|
samples = gst_ring_buffer_samples_done (src->ringbuffer);
|
||||||
|
|
||||||
result = samples * GST_SECOND / src->ringbuffer->spec.rate;
|
result = samples * GST_SECOND / src->ringbuffer->spec.rate;
|
||||||
result += GST_ELEMENT (src)->base_time;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,8 +374,6 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
||||||
buf->empty_seg[i] = buf->spec.silence_sample[j];
|
buf->empty_seg[i] = buf->spec.silence_sample[j];
|
||||||
j = (j + 1) % buf->spec.bytes_per_sample;
|
j = (j + 1) % buf->spec.bytes_per_sample;
|
||||||
}
|
}
|
||||||
/* set sample position to 0 */
|
|
||||||
gst_ring_buffer_set_sample (buf, 0);
|
|
||||||
} else {
|
} else {
|
||||||
g_warning
|
g_warning
|
||||||
("invalid bytes_per_sample from acquire ringbuffer, fix the element");
|
("invalid bytes_per_sample from acquire ringbuffer, fix the element");
|
||||||
|
@ -701,17 +699,20 @@ gst_ring_buffer_set_sample (GstRingBuffer * buf, guint64 sample)
|
||||||
if (sample == -1)
|
if (sample == -1)
|
||||||
sample = 0;
|
sample = 0;
|
||||||
|
|
||||||
|
if (buf->samples_per_seg == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
/* FIXME, we assume the ringbuffer can restart at a random
|
/* FIXME, we assume the ringbuffer can restart at a random
|
||||||
* position, round down to the beginning and keep track of
|
* position, round down to the beginning and keep track of
|
||||||
* offset when calculating the processed samples. */
|
* offset when calculating the processed samples. */
|
||||||
buf->segdone = sample / buf->samples_per_seg;
|
buf->segbase = buf->segdone - sample / buf->samples_per_seg;
|
||||||
buf->next_sample = sample;
|
buf->next_sample = sample;
|
||||||
|
|
||||||
for (i = 0; i < buf->spec.segtotal; i++) {
|
for (i = 0; i < buf->spec.segtotal; i++) {
|
||||||
gst_ring_buffer_clear (buf, i);
|
gst_ring_buffer_clear (buf, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG ("setting sample to %llu, segdone %d", sample, buf->segdone);
|
GST_DEBUG ("set sample to %llu, segbase %d", sample, buf->segbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -813,7 +814,7 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
gint diff;
|
gint diff;
|
||||||
|
|
||||||
/* get the currently processed segment */
|
/* get the currently processed segment */
|
||||||
segdone = g_atomic_int_get (&buf->segdone);
|
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
||||||
|
|
||||||
/* see how far away it is from the write segment */
|
/* see how far away it is from the write segment */
|
||||||
diff = writeseg - segdone;
|
diff = writeseg - segdone;
|
||||||
|
@ -931,7 +932,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
gint diff;
|
gint diff;
|
||||||
|
|
||||||
/* get the currently processed segment */
|
/* get the currently processed segment */
|
||||||
segdone = g_atomic_int_get (&buf->segdone);
|
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
||||||
|
|
||||||
/* see how far away it is from the read segment */
|
/* see how far away it is from the read segment */
|
||||||
diff = segdone - readseg;
|
diff = segdone - readseg;
|
||||||
|
|
|
@ -161,6 +161,7 @@ struct _GstRingBuffer {
|
||||||
/*< public >*/ /* ATOMIC */
|
/*< public >*/ /* ATOMIC */
|
||||||
gint state; /* state of the buffer */
|
gint state; /* state of the buffer */
|
||||||
gint segdone; /* number of segments processed since last start */
|
gint segdone; /* number of segments processed since last start */
|
||||||
|
gint segbase; /* segment corresponding to segment 0 */
|
||||||
gint waiting; /* when waiting for a segment to be freed */
|
gint waiting; /* when waiting for a segment to be freed */
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
|
|
@ -1199,6 +1199,7 @@ gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||||
|
|
||||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
*start -= bsink->discont_start;
|
||||||
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
||||||
*end = *start + GST_BUFFER_DURATION (buf);
|
*end = *start + GST_BUFFER_DURATION (buf);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1496,6 +1496,7 @@ gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||||
|
|
||||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
*start -= bsink->discont_start;
|
||||||
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
||||||
*end = *start + GST_BUFFER_DURATION (buf);
|
*end = *start + GST_BUFFER_DURATION (buf);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,7 +21,7 @@ static guint update_id;
|
||||||
static guint seek_timeout_id = 0;
|
static guint seek_timeout_id = 0;
|
||||||
static gulong changed_id;
|
static gulong changed_id;
|
||||||
|
|
||||||
//#define SOURCE "gnomevfssrc"
|
//#define SOURCE "filesrc"
|
||||||
#define SOURCE "gnomevfssrc"
|
#define SOURCE "gnomevfssrc"
|
||||||
#define ASINK "alsasink"
|
#define ASINK "alsasink"
|
||||||
//#define ASINK "osssink"
|
//#define ASINK "osssink"
|
||||||
|
@ -33,8 +33,8 @@ static gulong changed_id;
|
||||||
#define UPDATE_INTERVAL 500
|
#define UPDATE_INTERVAL 500
|
||||||
|
|
||||||
/* number of milliseconds to play for after a seek */
|
/* number of milliseconds to play for after a seek */
|
||||||
#define SCRUB_TIME 250
|
//#define SCRUB_TIME 250
|
||||||
#define SCRUB
|
//#define SCRUB
|
||||||
|
|
||||||
#define THREAD
|
#define THREAD
|
||||||
#define PAD_SEEK
|
#define PAD_SEEK
|
||||||
|
@ -376,6 +376,7 @@ make_vorbis_theora_pipeline (const gchar * location)
|
||||||
GstElement *audiosink, *videosink;
|
GstElement *audiosink, *videosink;
|
||||||
GstElement *a_queue, *v_queue;
|
GstElement *a_queue, *v_queue;
|
||||||
GstPad *seekable;
|
GstPad *seekable;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
pipeline = gst_pipeline_new ("app");
|
pipeline = gst_pipeline_new ("app");
|
||||||
|
|
||||||
|
@ -405,8 +406,9 @@ make_vorbis_theora_pipeline (const gchar * location)
|
||||||
gst_element_link (a_decoder, a_convert);
|
gst_element_link (a_decoder, a_convert);
|
||||||
gst_element_link (a_convert, audiosink);
|
gst_element_link (a_convert, audiosink);
|
||||||
|
|
||||||
gst_element_add_ghost_pad (audio_bin, gst_element_get_pad (a_queue, "sink"),
|
pad = gst_element_get_pad (a_queue, "sink");
|
||||||
"sink");
|
gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
|
||||||
|
gst_object_unref (GST_OBJECT_CAST (pad));
|
||||||
|
|
||||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
|
setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -427,8 +429,9 @@ make_vorbis_theora_pipeline (const gchar * location)
|
||||||
|
|
||||||
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
||||||
|
|
||||||
gst_element_add_ghost_pad (video_bin, gst_element_get_pad (v_queue, "sink"),
|
pad = gst_element_get_pad (v_queue, "sink");
|
||||||
"sink");
|
gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
|
||||||
|
gst_object_unref (GST_OBJECT_CAST (pad));
|
||||||
|
|
||||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
|
setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -933,6 +936,8 @@ update_scale (gpointer data)
|
||||||
gtk_widget_queue_draw (hscale);
|
gtk_widget_queue_draw (hscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_object_unref (clock);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,7 +997,7 @@ do_seek (GtkWidget * widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
GST_PIPELINE (pipeline)->stream_time = real;
|
gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
|
||||||
else
|
else
|
||||||
g_print ("seek failed\n");
|
g_print ("seek failed\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue