mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +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>
|
||||
|
||||
* gst/audioconvert/gstaudioconvert.c:
|
||||
|
|
|
@ -28,6 +28,7 @@ an implementation of an audio ringbuffer
|
|||
@empty_seg:
|
||||
@state:
|
||||
@segdone:
|
||||
@segbase:
|
||||
@waiting:
|
||||
|
||||
<!-- ##### STRUCT GstRingBufferClass ##### -->
|
||||
|
|
|
@ -21,7 +21,7 @@ static guint update_id;
|
|||
static guint seek_timeout_id = 0;
|
||||
static gulong changed_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
//#define SOURCE "filesrc"
|
||||
#define SOURCE "gnomevfssrc"
|
||||
#define ASINK "alsasink"
|
||||
//#define ASINK "osssink"
|
||||
|
@ -33,8 +33,8 @@ static gulong changed_id;
|
|||
#define UPDATE_INTERVAL 500
|
||||
|
||||
/* number of milliseconds to play for after a seek */
|
||||
#define SCRUB_TIME 250
|
||||
#define SCRUB
|
||||
//#define SCRUB_TIME 250
|
||||
//#define SCRUB
|
||||
|
||||
#define THREAD
|
||||
#define PAD_SEEK
|
||||
|
@ -376,6 +376,7 @@ make_vorbis_theora_pipeline (const gchar * location)
|
|||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
GstPad *pad;
|
||||
|
||||
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_convert, audiosink);
|
||||
|
||||
gst_element_add_ghost_pad (audio_bin, gst_element_get_pad (a_queue, "sink"),
|
||||
"sink");
|
||||
pad = gst_element_get_pad (a_queue, "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"),
|
||||
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_add_ghost_pad (video_bin, gst_element_get_pad (v_queue, "sink"),
|
||||
"sink");
|
||||
pad = gst_element_get_pad (v_queue, "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"),
|
||||
NULL);
|
||||
|
@ -933,6 +936,8 @@ update_scale (gpointer data)
|
|||
gtk_widget_queue_draw (hscale);
|
||||
}
|
||||
|
||||
gst_object_unref (clock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -992,7 +997,7 @@ do_seek (GtkWidget * widget)
|
|||
}
|
||||
|
||||
if (res)
|
||||
GST_PIPELINE (pipeline)->stream_time = real;
|
||||
gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
|
||||
else
|
||||
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,
|
||||
gboolean active);
|
||||
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);
|
||||
|
||||
|
@ -1173,6 +1174,7 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain)
|
|||
gint i;
|
||||
GList *headers;
|
||||
GstOggPad *pad;
|
||||
GstEvent *event;
|
||||
|
||||
if (chain == ogg->current_chain)
|
||||
return TRUE;
|
||||
|
@ -1188,6 +1190,13 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain)
|
|||
gst_element_no_more_pads (GST_ELEMENT (ogg));
|
||||
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 */
|
||||
for (i = 0; i < chain->streams->len; 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);
|
||||
|
||||
chain->total_time = 0;
|
||||
chain->start_time = 0;
|
||||
chain->start_time = G_MAXINT64;
|
||||
chain->last_time = 0;
|
||||
chain->begin_time = ogg->total_time;
|
||||
|
||||
|
@ -1904,7 +1913,7 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_ogg_demux_send_eos (GstOggDemux * ogg)
|
||||
gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event)
|
||||
{
|
||||
GstOggChain *chain = ogg->current_chain;
|
||||
|
||||
|
@ -1914,9 +1923,11 @@ gst_ogg_demux_send_eos (GstOggDemux * ogg)
|
|||
for (i = 0; i < chain->streams->len; 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
|
||||
|
@ -1946,6 +1957,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
|
|||
GST_CHAIN_UNLOCK (ogg);
|
||||
if (!got_chains)
|
||||
goto chain_read_failed;
|
||||
|
||||
ogg->need_chains = FALSE;
|
||||
ogg->offset = 0;
|
||||
}
|
||||
|
@ -1953,7 +1965,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
|
|||
GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset);
|
||||
if (ogg->offset == ogg->length) {
|
||||
ret = GST_FLOW_OK;
|
||||
gst_ogg_demux_send_eos (ogg);
|
||||
gst_ogg_demux_send_event (ogg, gst_event_new (GST_EVENT_EOS));
|
||||
goto pause;
|
||||
}
|
||||
|
||||
|
@ -1982,7 +1994,7 @@ pause:
|
|||
GST_LOG_OBJECT (ogg, "pausing task, reason %d", ret);
|
||||
gst_pad_pause_task (ogg->sinkpad);
|
||||
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,
|
||||
("stream stopped, reason %d", ret),
|
||||
("stream stopped, reason %d", ret));
|
||||
|
|
|
@ -54,10 +54,11 @@ struct _GstTheoraDec
|
|||
theora_info info;
|
||||
theora_comment comment;
|
||||
|
||||
guint packetno;
|
||||
gboolean have_header;
|
||||
guint64 granulepos;
|
||||
|
||||
gboolean initialized;
|
||||
GstClockTime last_timestamp;
|
||||
guint64 frame_nr;
|
||||
gboolean need_keyframe;
|
||||
gint width, height;
|
||||
gint offset_x, offset_y;
|
||||
|
@ -281,7 +282,7 @@ theora_dec_src_convert (GstPad * pad,
|
|||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
/* we need the info part before we can done something */
|
||||
if (dec->packetno < 1)
|
||||
if (!dec->have_header)
|
||||
return FALSE;
|
||||
|
||||
if (src_format == *dest_format) {
|
||||
|
@ -347,7 +348,7 @@ theora_dec_sink_convert (GstPad * pad,
|
|||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
/* we need the info part before we can done something */
|
||||
if (dec->packetno < 1)
|
||||
if (!dec->have_header)
|
||||
return FALSE;
|
||||
|
||||
if (src_format == *dest_format) {
|
||||
|
@ -581,69 +582,32 @@ theora_dec_src_getcaps (GstPad * pad)
|
|||
static gboolean
|
||||
theora_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
gint64 start_value, end_value, time, bytes;
|
||||
gboolean ret = TRUE;
|
||||
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");
|
||||
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:
|
||||
GST_STREAM_LOCK (pad);
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT,
|
||||
&start_value, &end_value)) {
|
||||
dec->granulepos = start_value;
|
||||
GST_DEBUG_OBJECT (dec,
|
||||
"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;
|
||||
}
|
||||
dec->need_keyframe = TRUE;
|
||||
dec->granulepos = -1;
|
||||
dec->last_timestamp = -1;
|
||||
ret = gst_pad_push_event (dec->srcpad, event);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
default:
|
||||
ret = gst_pad_event_default (dec->sinkpad, event);
|
||||
ret = gst_pad_push_event (dec->srcpad, event);
|
||||
break;
|
||||
}
|
||||
gst_object_unref (dec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -750,7 +714,7 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
|
|||
gst_pad_set_caps (dec->srcpad, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
dec->initialized = TRUE;
|
||||
dec->have_header = TRUE;
|
||||
|
||||
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))
|
||||
goto header_read_error;
|
||||
|
||||
switch (packet->packetno) {
|
||||
case 1:
|
||||
switch (packet->packet[0]) {
|
||||
case 0x81:
|
||||
res = theora_handle_comment_packet (dec, packet);
|
||||
break;
|
||||
case 2:
|
||||
case 0x82:
|
||||
res = theora_handle_type_packet (dec, packet);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
g_warning ("unknown theora header packet found");
|
||||
case 0x80:
|
||||
/* nothing special, this is the identification header */
|
||||
res = GST_FLOW_OK;
|
||||
break;
|
||||
}
|
||||
|
@ -792,8 +759,39 @@ static GstFlowReturn
|
|||
theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -813,7 +811,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
|
|||
gint cwidth, cheight;
|
||||
GstFlowReturn result;
|
||||
|
||||
if (!dec->initialized)
|
||||
if (!dec->have_header)
|
||||
goto not_initialized;
|
||||
|
||||
/* 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_END (out) = dec->packetno - 3;
|
||||
GST_BUFFER_OFFSET (out) = dec->frame_nr;
|
||||
dec->frame_nr++;
|
||||
GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
|
||||
GST_BUFFER_DURATION (out) =
|
||||
GST_SECOND * ((gdouble) dec->info.fps_denominator) /
|
||||
dec->info.fps_numerator;
|
||||
|
@ -909,7 +908,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
|
|||
not_initialized:
|
||||
{
|
||||
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;
|
||||
}
|
||||
dropping:
|
||||
|
@ -946,110 +945,50 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||
{
|
||||
GstTheoraDec *dec;
|
||||
ogg_packet packet;
|
||||
guint64 offset_end;
|
||||
GstClockTime outtime;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
|
||||
dec = GST_THEORA_DEC (GST_PAD_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;
|
||||
}
|
||||
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||
|
||||
/* make ogg_packet out of the buffer */
|
||||
packet.packet = GST_BUFFER_DATA (buf);
|
||||
packet.bytes = GST_BUFFER_SIZE (buf);
|
||||
packet.granulepos = dec->granulepos;
|
||||
packet.packetno = dec->packetno;
|
||||
packet.b_o_s = (packet.packetno == 0) ? 1 : 0;
|
||||
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
|
||||
packet.packetno = 0; /* we don't really care */
|
||||
packet.b_o_s = dec->have_header ? 0 : 1;
|
||||
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,
|
||||
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 */
|
||||
if (packet.packet[0] & 0x80) {
|
||||
if (packet.packetno > 3) {
|
||||
if (dec->have_header) {
|
||||
GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
|
||||
goto done;
|
||||
}
|
||||
result = theora_handle_header_packet (dec, &packet);
|
||||
} else {
|
||||
result = theora_handle_data_packet (dec, &packet, outtime);
|
||||
result = theora_handle_data_packet (dec, &packet, dec->last_timestamp);
|
||||
}
|
||||
|
||||
done:
|
||||
dec->packetno++;
|
||||
_inc_granulepos (dec);
|
||||
|
||||
gst_object_unref (dec);
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return result;
|
||||
|
@ -1070,8 +1009,9 @@ theora_dec_change_state (GstElement * element)
|
|||
case GST_STATE_READY_TO_PAUSED:
|
||||
theora_info_init (&dec->info);
|
||||
theora_comment_init (&dec->comment);
|
||||
dec->have_header = FALSE;
|
||||
dec->need_keyframe = TRUE;
|
||||
dec->initialized = FALSE;
|
||||
dec->last_timestamp = -1;
|
||||
dec->granulepos = -1;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
|
@ -1089,7 +1029,7 @@ theora_dec_change_state (GstElement * element)
|
|||
theora_clear (&dec->state);
|
||||
theora_comment_clear (&dec->comment);
|
||||
theora_info_clear (&dec->info);
|
||||
dec->packetno = 0;
|
||||
dec->have_header = FALSE;
|
||||
dec->granulepos = -1;
|
||||
break;
|
||||
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_function (dec->srcpad, vorbis_dec_src_query);
|
||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
||||
|
||||
dec->queued = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -366,90 +368,33 @@ vorbis_dec_src_event (GstPad * pad, GstEvent * event)
|
|||
static gboolean
|
||||
vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
gint64 start_value, end_value, time, bytes;
|
||||
gboolean ret = TRUE;
|
||||
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");
|
||||
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:
|
||||
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;
|
||||
|
||||
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
|
||||
vorbis_synthesis_restart (&dec->vd);
|
||||
vorbis_synthesis_restart (&dec->vd);
|
||||
#endif
|
||||
}
|
||||
ret = gst_pad_push_event (dec->srcpad, event);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
default:
|
||||
ret = gst_pad_event_default (pad, event);
|
||||
ret = gst_pad_push_event (dec->srcpad, event);
|
||||
break;
|
||||
}
|
||||
gst_object_unref (dec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -640,6 +585,52 @@ copy_samples (float *out, float **in, guint samples, gint channels)
|
|||
#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
|
||||
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);
|
||||
|
||||
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;
|
||||
else
|
||||
} else {
|
||||
GST_BUFFER_TIMESTAMP (out) = -1;
|
||||
}
|
||||
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)
|
||||
vd->granulepos += sample_count;
|
||||
|
@ -692,6 +684,10 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet)
|
|||
result = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
/* granulepos is the last sample in the packet */
|
||||
if (packet->granulepos != -1)
|
||||
vd->granulepos = packet->granulepos;
|
||||
|
||||
return result;
|
||||
|
||||
/* ERRORS */
|
||||
|
@ -727,7 +723,7 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
|
|||
/* make ogg_packet out of the buffer */
|
||||
packet.packet = GST_BUFFER_DATA (buffer);
|
||||
packet.bytes = GST_BUFFER_SIZE (buffer);
|
||||
packet.granulepos = vd->granulepos;
|
||||
packet.granulepos = GST_BUFFER_OFFSET_END (buffer);
|
||||
packet.packetno = vd->packetno++;
|
||||
/*
|
||||
* 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));
|
||||
|
||||
/* granulepos is the last sample in the packet */
|
||||
if (GST_BUFFER_OFFSET_END_IS_VALID (buffer))
|
||||
vd->granulepos = GST_BUFFER_OFFSET_END (buffer);;
|
||||
|
||||
done:
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
|
|
|
@ -26,10 +26,7 @@
|
|||
#include <gst/gst.h>
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VORBIS_DEC \
|
||||
(gst_vorbis_dec_get_type())
|
||||
|
@ -59,6 +56,8 @@ struct _GstVorbisDec {
|
|||
guint64 granulepos;
|
||||
|
||||
gboolean initialized;
|
||||
|
||||
GList *queued;
|
||||
};
|
||||
|
||||
struct _GstVorbisDecClass {
|
||||
|
@ -67,9 +66,6 @@ struct _GstVorbisDecClass {
|
|||
|
||||
GType gst_vorbis_dec_get_type(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#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)
|
||||
return 0;
|
||||
|
||||
/* our processed samples are always increasing */
|
||||
samples = gst_ring_buffer_samples_done (sink->ringbuffer);
|
||||
|
||||
result = samples * GST_SECOND / sink->ringbuffer->spec.rate;
|
||||
result += GST_ELEMENT (sink)->base_time;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -270,9 +270,8 @@ static void
|
|||
gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
|
||||
GstClockTime * start, GstClockTime * end)
|
||||
{
|
||||
/* ne need to sync to a clock here, we schedule the samples based
|
||||
* on our own clock for the moment. FIXME, implement this when
|
||||
* we are not using our own clock */
|
||||
/* our clock sync is a bit too much for the base class to handle so
|
||||
* we implement it ourselves. */
|
||||
*start = 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);
|
||||
}
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -339,17 +319,38 @@ wrong_state:
|
|||
static GstFlowReturn
|
||||
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);
|
||||
|
||||
offset = GST_BUFFER_OFFSET (buf);
|
||||
|
||||
GST_DEBUG ("in offset %llu, time %" GST_TIME_FORMAT, offset,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||
/* can't do anything when we don't have the device */
|
||||
if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
result = samples * GST_SECOND / src->ringbuffer->spec.rate;
|
||||
result += GST_ELEMENT (src)->base_time;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -374,8 +374,6 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
|||
buf->empty_seg[i] = buf->spec.silence_sample[j];
|
||||
j = (j + 1) % buf->spec.bytes_per_sample;
|
||||
}
|
||||
/* set sample position to 0 */
|
||||
gst_ring_buffer_set_sample (buf, 0);
|
||||
} else {
|
||||
g_warning
|
||||
("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)
|
||||
sample = 0;
|
||||
|
||||
if (buf->samples_per_seg == 0)
|
||||
return;
|
||||
|
||||
/* FIXME, we assume the ringbuffer can restart at a random
|
||||
* position, round down to the beginning and keep track of
|
||||
* 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;
|
||||
|
||||
for (i = 0; i < buf->spec.segtotal; 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
|
||||
|
@ -813,7 +814,7 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
|||
gint diff;
|
||||
|
||||
/* 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 */
|
||||
diff = writeseg - segdone;
|
||||
|
@ -931,7 +932,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
|||
gint diff;
|
||||
|
||||
/* 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 */
|
||||
diff = segdone - readseg;
|
||||
|
|
|
@ -161,6 +161,7 @@ struct _GstRingBuffer {
|
|||
/*< public >*/ /* ATOMIC */
|
||||
gint state; /* state of the buffer */
|
||||
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 */
|
||||
|
||||
/*< private >*/
|
||||
|
|
|
@ -1199,6 +1199,7 @@ gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
|||
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||
*start -= bsink->discont_start;
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
||||
*end = *start + GST_BUFFER_DURATION (buf);
|
||||
} else {
|
||||
|
|
|
@ -1496,6 +1496,7 @@ gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
|||
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||
*start -= bsink->discont_start;
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
||||
*end = *start + GST_BUFFER_DURATION (buf);
|
||||
} else {
|
||||
|
|
|
@ -21,7 +21,7 @@ static guint update_id;
|
|||
static guint seek_timeout_id = 0;
|
||||
static gulong changed_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
//#define SOURCE "filesrc"
|
||||
#define SOURCE "gnomevfssrc"
|
||||
#define ASINK "alsasink"
|
||||
//#define ASINK "osssink"
|
||||
|
@ -33,8 +33,8 @@ static gulong changed_id;
|
|||
#define UPDATE_INTERVAL 500
|
||||
|
||||
/* number of milliseconds to play for after a seek */
|
||||
#define SCRUB_TIME 250
|
||||
#define SCRUB
|
||||
//#define SCRUB_TIME 250
|
||||
//#define SCRUB
|
||||
|
||||
#define THREAD
|
||||
#define PAD_SEEK
|
||||
|
@ -376,6 +376,7 @@ make_vorbis_theora_pipeline (const gchar * location)
|
|||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
GstPad *pad;
|
||||
|
||||
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_convert, audiosink);
|
||||
|
||||
gst_element_add_ghost_pad (audio_bin, gst_element_get_pad (a_queue, "sink"),
|
||||
"sink");
|
||||
pad = gst_element_get_pad (a_queue, "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"),
|
||||
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_add_ghost_pad (video_bin, gst_element_get_pad (v_queue, "sink"),
|
||||
"sink");
|
||||
pad = gst_element_get_pad (v_queue, "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"),
|
||||
NULL);
|
||||
|
@ -933,6 +936,8 @@ update_scale (gpointer data)
|
|||
gtk_widget_queue_draw (hscale);
|
||||
}
|
||||
|
||||
gst_object_unref (clock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -992,7 +997,7 @@ do_seek (GtkWidget * widget)
|
|||
}
|
||||
|
||||
if (res)
|
||||
GST_PIPELINE (pipeline)->stream_time = real;
|
||||
gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
|
||||
else
|
||||
g_print ("seek failed\n");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue