branch | RCL_3 |
changeset 30 | 7e817e7e631c |
parent 29 | 567bb019e3e3 |
29:567bb019e3e3 | 30:7e817e7e631c |
---|---|
161 #endif |
161 #endif |
162 |
162 |
163 #define GST_BASE_SINK_GET_PRIVATE(obj) \ |
163 #define GST_BASE_SINK_GET_PRIVATE(obj) \ |
164 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate)) |
164 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate)) |
165 |
165 |
166 #define GST_FLOW_STEP GST_FLOW_CUSTOM_ERROR |
|
167 |
|
168 typedef struct |
|
169 { |
|
170 gboolean valid; /* if this info is valid */ |
|
171 guint32 seqnum; /* the seqnum of the STEP event */ |
|
172 GstFormat format; /* the format of the amount */ |
|
173 guint64 amount; /* the total amount of data to skip */ |
|
174 guint64 position; /* the position in the stepped data */ |
|
175 guint64 duration; /* the duration in time of the skipped data */ |
|
176 guint64 start; /* running_time of the start */ |
|
177 gdouble rate; /* rate of skipping */ |
|
178 gdouble start_rate; /* rate before skipping */ |
|
179 guint64 start_start; /* start position skipping */ |
|
180 guint64 start_stop; /* stop position skipping */ |
|
181 gboolean flush; /* if this was a flushing step */ |
|
182 gboolean intermediate; /* if this is an intermediate step */ |
|
183 gboolean need_preroll; /* if we need preroll after this step */ |
|
184 } GstStepInfo; |
|
185 |
|
186 /* FIXME, some stuff in ABI.data and other in Private... |
166 /* FIXME, some stuff in ABI.data and other in Private... |
187 * Make up your mind please. |
167 * Make up your mind please. |
188 */ |
168 */ |
189 struct _GstBaseSinkPrivate |
169 struct _GstBaseSinkPrivate |
190 { |
170 { |
191 gint qos_enabled; /* ATOMIC */ |
171 gint qos_enabled; /* ATOMIC */ |
192 gboolean async_enabled; |
172 gboolean async_enabled; |
193 GstClockTimeDiff ts_offset; |
173 GstClockTimeDiff ts_offset; |
194 GstClockTime render_delay; |
|
195 |
174 |
196 /* start, stop of current buffer, stream time, used to report position */ |
175 /* start, stop of current buffer, stream time, used to report position */ |
197 GstClockTime current_sstart; |
176 GstClockTime current_sstart; |
198 GstClockTime current_sstop; |
177 GstClockTime current_sstop; |
199 |
178 |
240 /* when we are prerolled and able to report latency */ |
219 /* when we are prerolled and able to report latency */ |
241 gboolean have_latency; |
220 gboolean have_latency; |
242 |
221 |
243 /* the last buffer we prerolled or rendered. Useful for making snapshots */ |
222 /* the last buffer we prerolled or rendered. Useful for making snapshots */ |
244 GstBuffer *last_buffer; |
223 GstBuffer *last_buffer; |
245 |
|
246 /* caps for pull based scheduling */ |
|
247 GstCaps *pull_caps; |
|
248 |
|
249 /* blocksize for pulling */ |
|
250 guint blocksize; |
|
251 |
|
252 gboolean discont; |
|
253 |
|
254 /* seqnum of the stream */ |
|
255 guint32 seqnum; |
|
256 |
|
257 gboolean call_preroll; |
|
258 gboolean step_unlock; |
|
259 |
|
260 /* we have a pending and a current step operation */ |
|
261 GstStepInfo current_step; |
|
262 GstStepInfo pending_step; |
|
263 }; |
224 }; |
264 |
225 |
265 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size)) |
226 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size)) |
266 |
227 |
267 /* generic running average, this has a neutral window size */ |
228 /* generic running average, this has a neutral window size */ |
273 #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16) |
234 #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16) |
274 #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4) |
235 #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4) |
275 |
236 |
276 /* BaseSink properties */ |
237 /* BaseSink properties */ |
277 |
238 |
239 #define DEFAULT_SIZE 1024 |
|
278 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */ |
240 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */ |
279 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE |
241 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE |
280 |
242 |
281 #define DEFAULT_PREROLL_QUEUE_LEN 0 |
243 #define DEFAULT_PREROLL_QUEUE_LEN 0 |
282 #define DEFAULT_SYNC TRUE |
244 #define DEFAULT_SYNC TRUE |
283 #define DEFAULT_MAX_LATENESS -1 |
245 #define DEFAULT_MAX_LATENESS -1 |
284 #define DEFAULT_QOS FALSE |
246 #define DEFAULT_QOS FALSE |
285 #define DEFAULT_ASYNC TRUE |
247 #define DEFAULT_ASYNC TRUE |
286 #define DEFAULT_TS_OFFSET 0 |
248 #define DEFAULT_TS_OFFSET 0 |
287 #define DEFAULT_BLOCKSIZE 4096 |
|
288 #define DEFAULT_RENDER_DELAY 0 |
|
289 |
249 |
290 enum |
250 enum |
291 { |
251 { |
292 PROP_0, |
252 PROP_0, |
293 PROP_PREROLL_QUEUE_LEN, |
253 PROP_PREROLL_QUEUE_LEN, |
295 PROP_MAX_LATENESS, |
255 PROP_MAX_LATENESS, |
296 PROP_QOS, |
256 PROP_QOS, |
297 PROP_ASYNC, |
257 PROP_ASYNC, |
298 PROP_TS_OFFSET, |
258 PROP_TS_OFFSET, |
299 PROP_LAST_BUFFER, |
259 PROP_LAST_BUFFER, |
300 PROP_BLOCKSIZE, |
|
301 PROP_RENDER_DELAY, |
|
302 PROP_LAST |
260 PROP_LAST |
303 }; |
261 }; |
304 |
262 |
305 static GstElementClass *parent_class = NULL; |
263 static GstElementClass *parent_class = NULL; |
306 |
264 |
313 |
271 |
314 |
272 |
315 GType |
273 GType |
316 gst_base_sink_get_type (void) |
274 gst_base_sink_get_type (void) |
317 { |
275 { |
318 static volatile gsize base_sink_type = 0; |
276 static GType base_sink_type = 0; |
319 |
277 |
320 if (g_once_init_enter (&base_sink_type)) { |
278 if (G_UNLIKELY (base_sink_type == 0)) { |
321 GType _type; |
|
322 static const GTypeInfo base_sink_info = { |
279 static const GTypeInfo base_sink_info = { |
323 sizeof (GstBaseSinkClass), |
280 sizeof (GstBaseSinkClass), |
324 NULL, |
281 NULL, |
325 NULL, |
282 NULL, |
326 (GClassInitFunc) gst_base_sink_class_init, |
283 (GClassInitFunc) gst_base_sink_class_init, |
329 sizeof (GstBaseSink), |
286 sizeof (GstBaseSink), |
330 0, |
287 0, |
331 (GInstanceInitFunc) gst_base_sink_init, |
288 (GInstanceInitFunc) gst_base_sink_init, |
332 }; |
289 }; |
333 |
290 |
334 _type = g_type_register_static (GST_TYPE_ELEMENT, |
291 base_sink_type = g_type_register_static (GST_TYPE_ELEMENT, |
335 "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT); |
292 "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT); |
336 g_once_init_leave (&base_sink_type, _type); |
|
337 } |
293 } |
338 return base_sink_type; |
294 return base_sink_type; |
339 } |
295 } |
340 |
296 |
341 static void gst_base_sink_set_property (GObject * object, guint prop_id, |
297 static void gst_base_sink_set_property (GObject * object, guint prop_id, |
355 GstClockTime * start, GstClockTime * end); |
311 GstClockTime * start, GstClockTime * end); |
356 static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink, |
312 static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink, |
357 GstPad * pad, gboolean flushing); |
313 GstPad * pad, gboolean flushing); |
358 static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink, |
314 static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink, |
359 gboolean active); |
315 gboolean active); |
360 static gboolean gst_base_sink_default_do_seek (GstBaseSink * sink, |
|
361 GstSegment * segment); |
|
362 static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink, |
|
363 GstEvent * event, GstSegment * segment); |
|
364 |
316 |
365 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element, |
317 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element, |
366 GstStateChange transition); |
318 GstStateChange transition); |
367 |
319 |
368 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer); |
320 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer); |
369 static GstFlowReturn gst_base_sink_chain_list (GstPad * pad, |
|
370 GstBufferList * list); |
|
371 |
|
372 static void gst_base_sink_loop (GstPad * pad); |
321 static void gst_base_sink_loop (GstPad * pad); |
373 static gboolean gst_base_sink_pad_activate (GstPad * pad); |
322 static gboolean gst_base_sink_pad_activate (GstPad * pad); |
374 static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active); |
323 static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active); |
375 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active); |
324 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active); |
376 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event); |
325 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event); |
377 static gboolean gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query); |
326 static gboolean gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query); |
378 |
327 |
379 static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink); |
|
380 |
|
381 /* check if an object was too late */ |
328 /* check if an object was too late */ |
382 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink, |
329 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink, |
383 GstMiniObject * obj, GstClockTime start, GstClockTime stop, |
330 GstMiniObject * obj, GstClockTime start, GstClockTime stop, |
384 GstClockReturn status, GstClockTimeDiff jitter); |
331 GstClockReturn status, GstClockTimeDiff jitter); |
385 static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink, |
|
386 gboolean is_list, GstMiniObject * obj); |
|
387 |
332 |
388 static void |
333 static void |
389 gst_base_sink_class_init (GstBaseSinkClass * klass) |
334 gst_base_sink_class_init (GstBaseSinkClass * klass) |
390 { |
335 { |
391 GObjectClass *gobject_class; |
336 GObjectClass *gobject_class; |
408 /* FIXME, this next value should be configured using an event from the |
353 /* FIXME, this next value should be configured using an event from the |
409 * upstream element, ie, the BUFFER_SIZE event. */ |
354 * upstream element, ie, the BUFFER_SIZE event. */ |
410 g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN, |
355 g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN, |
411 g_param_spec_uint ("preroll-queue-len", "Preroll queue length", |
356 g_param_spec_uint ("preroll-queue-len", "Preroll queue length", |
412 "Number of buffers to queue during preroll", 0, G_MAXUINT, |
357 "Number of buffers to queue during preroll", 0, G_MAXUINT, |
413 DEFAULT_PREROLL_QUEUE_LEN, |
358 DEFAULT_PREROLL_QUEUE_LEN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
414 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); |
|
415 |
359 |
416 g_object_class_install_property (gobject_class, PROP_SYNC, |
360 g_object_class_install_property (gobject_class, PROP_SYNC, |
417 g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC, |
361 g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC, |
418 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
362 G_PARAM_READWRITE)); |
419 |
363 |
420 g_object_class_install_property (gobject_class, PROP_MAX_LATENESS, |
364 g_object_class_install_property (gobject_class, PROP_MAX_LATENESS, |
421 g_param_spec_int64 ("max-lateness", "Max Lateness", |
365 g_param_spec_int64 ("max-lateness", "Max Lateness", |
422 "Maximum number of nanoseconds that a buffer can be late before it " |
366 "Maximum number of nanoseconds that a buffer can be late before it " |
423 "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS, |
367 "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS, |
424 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
368 G_PARAM_READWRITE)); |
425 |
369 |
426 g_object_class_install_property (gobject_class, PROP_QOS, |
370 g_object_class_install_property (gobject_class, PROP_QOS, |
427 g_param_spec_boolean ("qos", "Qos", |
371 g_param_spec_boolean ("qos", "Qos", |
428 "Generate Quality-of-Service events upstream", DEFAULT_QOS, |
372 "Generate Quality-of-Service events upstream", DEFAULT_QOS, |
429 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
373 G_PARAM_READWRITE)); |
430 /** |
374 /** |
431 * GstBaseSink:async |
375 * GstBaseSink:async |
432 * |
376 * |
433 * If set to #TRUE, the basesink will perform asynchronous state changes. |
377 * If set to #TRUE, the basesink will perform asynchronous state changes. |
434 * When set to #FALSE, the sink will not signal the parent when it prerolls. |
378 * When set to #FALSE, the sink will not signal the parent when it prerolls. |
437 * |
381 * |
438 * Since: 0.10.15 |
382 * Since: 0.10.15 |
439 */ |
383 */ |
440 g_object_class_install_property (gobject_class, PROP_ASYNC, |
384 g_object_class_install_property (gobject_class, PROP_ASYNC, |
441 g_param_spec_boolean ("async", "Async", |
385 g_param_spec_boolean ("async", "Async", |
442 "Go asynchronously to PAUSED", DEFAULT_ASYNC, |
386 "Go asynchronously to PAUSED", DEFAULT_ASYNC, G_PARAM_READWRITE)); |
443 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
444 /** |
387 /** |
445 * GstBaseSink:ts-offset |
388 * GstBaseSink:ts-offset |
446 * |
389 * |
447 * Controls the final synchronisation, a negative value will render the buffer |
390 * Controls the final synchronisation, a negative value will render the buffer |
448 * earlier while a positive value delays playback. This property can be |
391 * earlier while a positive value delays playback. This property can be |
451 * Since: 0.10.15 |
394 * Since: 0.10.15 |
452 */ |
395 */ |
453 g_object_class_install_property (gobject_class, PROP_TS_OFFSET, |
396 g_object_class_install_property (gobject_class, PROP_TS_OFFSET, |
454 g_param_spec_int64 ("ts-offset", "TS Offset", |
397 g_param_spec_int64 ("ts-offset", "TS Offset", |
455 "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64, |
398 "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64, |
456 DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
399 DEFAULT_TS_OFFSET, G_PARAM_READWRITE)); |
400 |
|
457 /** |
401 /** |
458 * GstBaseSink:last-buffer |
402 * GstBaseSink:last-buffer |
459 * |
403 * |
460 * The last buffer that arrived in the sink and was used for preroll or for |
404 * The last buffer that arrived in the sink and was used for preroll or for |
461 * rendering. This property can be used to generate thumbnails. This property |
405 * rendering. This property can be used to generate thumbnails. This property |
464 * Since: 0.10.15 |
408 * Since: 0.10.15 |
465 */ |
409 */ |
466 g_object_class_install_property (gobject_class, PROP_LAST_BUFFER, |
410 g_object_class_install_property (gobject_class, PROP_LAST_BUFFER, |
467 gst_param_spec_mini_object ("last-buffer", "Last Buffer", |
411 gst_param_spec_mini_object ("last-buffer", "Last Buffer", |
468 "The last buffer received in the sink", GST_TYPE_BUFFER, |
412 "The last buffer received in the sink", GST_TYPE_BUFFER, |
469 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
413 G_PARAM_READABLE)); |
470 /** |
|
471 * GstBaseSink:blocksize |
|
472 * |
|
473 * The amount of bytes to pull when operating in pull mode. |
|
474 * |
|
475 * Since: 0.10.22 |
|
476 */ |
|
477 g_object_class_install_property (gobject_class, PROP_BLOCKSIZE, |
|
478 g_param_spec_uint ("blocksize", "Block size", |
|
479 "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT, |
|
480 DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
481 /** |
|
482 * GstBaseSink:render-delay |
|
483 * |
|
484 * The additional delay between synchronisation and actual rendering of the |
|
485 * media. This property will add additional latency to the device in order to |
|
486 * make other sinks compensate for the delay. |
|
487 * |
|
488 * Since: 0.10.22 |
|
489 */ |
|
490 g_object_class_install_property (gobject_class, PROP_RENDER_DELAY, |
|
491 g_param_spec_uint64 ("render-delay", "Render Delay", |
|
492 "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64, |
|
493 DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
494 |
414 |
495 gstelement_class->change_state = |
415 gstelement_class->change_state = |
496 GST_DEBUG_FUNCPTR (gst_base_sink_change_state); |
416 GST_DEBUG_FUNCPTR (gst_base_sink_change_state); |
497 gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event); |
417 gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event); |
498 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query); |
418 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query); |
512 GstBaseSink *bsink; |
432 GstBaseSink *bsink; |
513 GstCaps *caps = NULL; |
433 GstCaps *caps = NULL; |
514 |
434 |
515 bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); |
435 bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); |
516 bclass = GST_BASE_SINK_GET_CLASS (bsink); |
436 bclass = GST_BASE_SINK_GET_CLASS (bsink); |
517 |
437 if (bclass->get_caps) |
518 if (bsink->pad_mode == GST_ACTIVATE_PULL) { |
438 caps = bclass->get_caps (bsink); |
519 /* if we are operating in pull mode we only accept the negotiated caps */ |
439 |
520 GST_OBJECT_LOCK (pad); |
|
521 if ((caps = GST_PAD_CAPS (pad))) |
|
522 gst_caps_ref (caps); |
|
523 GST_OBJECT_UNLOCK (pad); |
|
524 } |
|
525 if (caps == NULL) { |
440 if (caps == NULL) { |
526 if (bclass->get_caps) |
441 GstPadTemplate *pad_template; |
527 caps = bclass->get_caps (bsink); |
442 |
528 |
443 pad_template = |
529 if (caps == NULL) { |
444 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink"); |
530 GstPadTemplate *pad_template; |
445 if (pad_template != NULL) { |
531 |
446 caps = gst_caps_ref (gst_pad_template_get_caps (pad_template)); |
532 pad_template = |
|
533 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), |
|
534 "sink"); |
|
535 if (pad_template != NULL) { |
|
536 caps = gst_caps_ref (gst_pad_template_get_caps (pad_template)); |
|
537 } |
|
538 } |
447 } |
539 } |
448 } |
540 gst_object_unref (bsink); |
449 gst_object_unref (bsink); |
541 |
450 |
542 return caps; |
451 return caps; |
549 GstBaseSink *bsink; |
458 GstBaseSink *bsink; |
550 gboolean res = TRUE; |
459 gboolean res = TRUE; |
551 |
460 |
552 bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); |
461 bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); |
553 bclass = GST_BASE_SINK_GET_CLASS (bsink); |
462 bclass = GST_BASE_SINK_GET_CLASS (bsink); |
463 |
|
464 if (bsink->pad_mode == GST_ACTIVATE_PULL) { |
|
465 GstPad *peer = gst_pad_get_peer (pad); |
|
466 |
|
467 if (peer) |
|
468 res = gst_pad_set_caps (peer, caps); |
|
469 else |
|
470 res = FALSE; |
|
471 |
|
472 if (!res) |
|
473 GST_DEBUG_OBJECT (bsink, "peer setcaps() failed"); |
|
474 } |
|
554 |
475 |
555 if (res && bclass->set_caps) |
476 if (res && bclass->set_caps) |
556 res = bclass->set_caps (bsink, caps); |
477 res = bclass->set_caps (bsink, caps); |
557 |
478 |
558 gst_object_unref (bsink); |
479 gst_object_unref (bsink); |
626 GST_DEBUG_FUNCPTR (gst_base_sink_pad_activate_pull)); |
547 GST_DEBUG_FUNCPTR (gst_base_sink_pad_activate_pull)); |
627 gst_pad_set_event_function (basesink->sinkpad, |
548 gst_pad_set_event_function (basesink->sinkpad, |
628 GST_DEBUG_FUNCPTR (gst_base_sink_event)); |
549 GST_DEBUG_FUNCPTR (gst_base_sink_event)); |
629 gst_pad_set_chain_function (basesink->sinkpad, |
550 gst_pad_set_chain_function (basesink->sinkpad, |
630 GST_DEBUG_FUNCPTR (gst_base_sink_chain)); |
551 GST_DEBUG_FUNCPTR (gst_base_sink_chain)); |
631 gst_pad_set_chain_list_function (basesink->sinkpad, |
|
632 GST_DEBUG_FUNCPTR (gst_base_sink_chain_list)); |
|
633 gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad); |
552 gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad); |
634 |
553 |
635 basesink->pad_mode = GST_ACTIVATE_NONE; |
554 basesink->pad_mode = GST_ACTIVATE_NONE; |
636 basesink->preroll_queue = g_queue_new (); |
555 basesink->preroll_queue = g_queue_new (); |
637 basesink->abidata.ABI.clip_segment = gst_segment_new (); |
556 basesink->abidata.ABI.clip_segment = gst_segment_new (); |
640 basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH; |
559 basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH; |
641 basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL; |
560 basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL; |
642 |
561 |
643 basesink->sync = DEFAULT_SYNC; |
562 basesink->sync = DEFAULT_SYNC; |
644 basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS; |
563 basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS; |
645 g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS); |
564 gst_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS); |
646 priv->async_enabled = DEFAULT_ASYNC; |
565 priv->async_enabled = DEFAULT_ASYNC; |
647 priv->ts_offset = DEFAULT_TS_OFFSET; |
566 priv->ts_offset = DEFAULT_TS_OFFSET; |
648 priv->render_delay = DEFAULT_RENDER_DELAY; |
|
649 priv->blocksize = DEFAULT_BLOCKSIZE; |
|
650 |
567 |
651 GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK); |
568 GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK); |
652 } |
569 } |
653 |
570 |
654 static void |
571 static void |
793 void |
710 void |
794 gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled) |
711 gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled) |
795 { |
712 { |
796 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
713 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
797 |
714 |
798 g_atomic_int_set (&sink->priv->qos_enabled, enabled); |
715 gst_atomic_int_set (&sink->priv->qos_enabled, enabled); |
799 } |
716 } |
800 |
717 |
801 /** |
718 /** |
802 * gst_base_sink_is_qos_enabled: |
719 * gst_base_sink_is_qos_enabled: |
803 * @sink: the sink |
720 * @sink: the sink |
846 { |
763 { |
847 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
764 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
848 |
765 |
849 GST_PAD_PREROLL_LOCK (sink->sinkpad); |
766 GST_PAD_PREROLL_LOCK (sink->sinkpad); |
850 sink->priv->async_enabled = enabled; |
767 sink->priv->async_enabled = enabled; |
851 GST_LOG_OBJECT (sink, "set async enabled to %d", enabled); |
|
852 GST_PAD_PREROLL_UNLOCK (sink->sinkpad); |
768 GST_PAD_PREROLL_UNLOCK (sink->sinkpad); |
853 } |
769 } |
854 |
770 |
855 /** |
771 /** |
856 * gst_base_sink_is_async_enabled: |
772 * gst_base_sink_is_async_enabled: |
903 { |
819 { |
904 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
820 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
905 |
821 |
906 GST_OBJECT_LOCK (sink); |
822 GST_OBJECT_LOCK (sink); |
907 sink->priv->ts_offset = offset; |
823 sink->priv->ts_offset = offset; |
908 GST_LOG_OBJECT (sink, "set time offset to %" G_GINT64_FORMAT, offset); |
|
909 GST_OBJECT_UNLOCK (sink); |
824 GST_OBJECT_UNLOCK (sink); |
910 } |
825 } |
911 |
826 |
912 /** |
827 /** |
913 * gst_base_sink_get_ts_offset: |
828 * gst_base_sink_get_ts_offset: |
974 static void |
889 static void |
975 gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer) |
890 gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer) |
976 { |
891 { |
977 GstBuffer *old; |
892 GstBuffer *old; |
978 |
893 |
894 if (buffer) |
|
895 gst_buffer_ref (buffer); |
|
896 |
|
979 GST_OBJECT_LOCK (sink); |
897 GST_OBJECT_LOCK (sink); |
980 old = sink->priv->last_buffer; |
898 old = sink->priv->last_buffer; |
981 if (G_LIKELY (old != buffer)) { |
899 sink->priv->last_buffer = buffer; |
982 GST_DEBUG_OBJECT (sink, "setting last buffer to %p", buffer); |
|
983 if (G_LIKELY (buffer)) |
|
984 gst_buffer_ref (buffer); |
|
985 sink->priv->last_buffer = buffer; |
|
986 } else { |
|
987 old = NULL; |
|
988 } |
|
989 GST_OBJECT_UNLOCK (sink); |
900 GST_OBJECT_UNLOCK (sink); |
990 |
901 |
991 /* avoid unreffing with the lock because cleanup code might want to take the |
902 if (old) |
992 * lock too */ |
|
993 if (G_LIKELY (old)) |
|
994 gst_buffer_unref (old); |
903 gst_buffer_unref (old); |
995 } |
904 } |
996 |
905 |
997 /** |
906 /** |
998 * gst_base_sink_get_latency: |
907 * gst_base_sink_get_latency: |
1051 gst_base_sink_query_latency (GstBaseSink * sink, gboolean * live, |
960 gst_base_sink_query_latency (GstBaseSink * sink, gboolean * live, |
1052 gboolean * upstream_live, GstClockTime * min_latency, |
961 gboolean * upstream_live, GstClockTime * min_latency, |
1053 GstClockTime * max_latency) |
962 GstClockTime * max_latency) |
1054 { |
963 { |
1055 gboolean l, us_live, res, have_latency; |
964 gboolean l, us_live, res, have_latency; |
1056 GstClockTime min, max, render_delay; |
965 GstClockTime min, max; |
1057 GstQuery *query; |
966 GstQuery *query; |
1058 GstClockTime us_min, us_max; |
967 GstClockTime us_min, us_max; |
1059 |
968 |
1060 /* we are live when we sync to the clock */ |
969 /* we are live when we sync to the clock */ |
1061 GST_OBJECT_LOCK (sink); |
970 GST_OBJECT_LOCK (sink); |
1062 l = sink->sync; |
971 l = sink->sync; |
1063 have_latency = sink->priv->have_latency; |
972 have_latency = sink->priv->have_latency; |
1064 render_delay = sink->priv->render_delay; |
|
1065 GST_OBJECT_UNLOCK (sink); |
973 GST_OBJECT_UNLOCK (sink); |
1066 |
974 |
1067 /* assume no latency */ |
975 /* assume no latency */ |
1068 min = 0; |
976 min = 0; |
1069 max = -1; |
977 max = -1; |
1070 us_live = FALSE; |
978 us_live = FALSE; |
1071 |
979 |
1072 if (have_latency) { |
980 /* we are live */ |
1073 GST_DEBUG_OBJECT (sink, "we are ready for LATENCY query"); |
981 if (l) { |
1074 /* we are ready for a latency query this is when we preroll or when we are |
982 if (have_latency) { |
1075 * not async. */ |
983 /* we are live and ready for a latency query */ |
1076 query = gst_query_new_latency (); |
984 query = gst_query_new_latency (); |
1077 |
985 |
1078 /* ask the peer for the latency */ |
986 /* ask the peer for the latency */ |
1079 if ((res = gst_base_sink_peer_query (sink, query))) { |
987 if (!(res = gst_base_sink_peer_query (sink, query))) |
988 goto query_failed; |
|
989 |
|
1080 /* get upstream min and max latency */ |
990 /* get upstream min and max latency */ |
1081 gst_query_parse_latency (query, &us_live, &us_min, &us_max); |
991 gst_query_parse_latency (query, &us_live, &us_min, &us_max); |
992 gst_query_unref (query); |
|
1082 |
993 |
1083 if (us_live) { |
994 if (us_live) { |
1084 /* upstream live, use its latency, subclasses should use these |
995 /* upstream live, use its latency, subclasses should use these |
1085 * values to create the complete latency. */ |
996 * values to create the complete latency. */ |
1086 min = us_min; |
997 min = us_min; |
1087 max = us_max; |
998 max = us_max; |
1088 } |
999 } |
1089 if (l) { |
1000 } else { |
1090 /* we need to add the render delay if we are live */ |
1001 /* we are live but are not yet ready for a latency query */ |
1091 if (min != -1) |
1002 res = FALSE; |
1092 min += render_delay; |
|
1093 if (max != -1) |
|
1094 max += render_delay; |
|
1095 } |
|
1096 } |
1003 } |
1004 } else { |
|
1005 /* not live, result is always TRUE */ |
|
1006 res = TRUE; |
|
1007 } |
|
1008 |
|
1009 GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d," |
|
1010 " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l, |
|
1011 have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); |
|
1012 |
|
1013 if (live) |
|
1014 *live = l; |
|
1015 if (upstream_live) |
|
1016 *upstream_live = us_live; |
|
1017 if (min_latency) |
|
1018 *min_latency = min; |
|
1019 if (max_latency) |
|
1020 *max_latency = max; |
|
1021 |
|
1022 return res; |
|
1023 |
|
1024 /* ERRORS */ |
|
1025 query_failed: |
|
1026 { |
|
1027 GST_DEBUG_OBJECT (sink, "latency query failed"); |
|
1097 gst_query_unref (query); |
1028 gst_query_unref (query); |
1098 } else { |
1029 return FALSE; |
1099 GST_DEBUG_OBJECT (sink, "we are not yet ready for LATENCY query"); |
1030 } |
1100 res = FALSE; |
|
1101 } |
|
1102 |
|
1103 /* not live, we tried to do the query, if it failed we return TRUE anyway */ |
|
1104 if (!res) { |
|
1105 if (!l) { |
|
1106 res = TRUE; |
|
1107 GST_DEBUG_OBJECT (sink, "latency query failed but we are not live"); |
|
1108 } else { |
|
1109 GST_DEBUG_OBJECT (sink, "latency query failed and we are live"); |
|
1110 } |
|
1111 } |
|
1112 |
|
1113 if (res) { |
|
1114 GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d," |
|
1115 " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l, |
|
1116 have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); |
|
1117 |
|
1118 if (live) |
|
1119 *live = l; |
|
1120 if (upstream_live) |
|
1121 *upstream_live = us_live; |
|
1122 if (min_latency) |
|
1123 *min_latency = min; |
|
1124 if (max_latency) |
|
1125 *max_latency = max; |
|
1126 } |
|
1127 return res; |
|
1128 } |
|
1129 |
|
1130 /** |
|
1131 * gst_base_sink_set_render_delay: |
|
1132 * @sink: a #GstBaseSink |
|
1133 * @delay: the new delay |
|
1134 * |
|
1135 * Set the render delay in @sink to @delay. The render delay is the time |
|
1136 * between actual rendering of a buffer and its synchronisation time. Some |
|
1137 * devices might delay media rendering which can be compensated for with this |
|
1138 * function. |
|
1139 * |
|
1140 * After calling this function, this sink will report additional latency and |
|
1141 * other sinks will adjust their latency to delay the rendering of their media. |
|
1142 * |
|
1143 * This function is usually called by subclasses. |
|
1144 * |
|
1145 * Since: 0.10.21 |
|
1146 */ |
|
1147 #ifdef __SYMBIAN32__ |
|
1148 EXPORT_C |
|
1149 #endif |
|
1150 |
|
1151 void |
|
1152 gst_base_sink_set_render_delay (GstBaseSink * sink, GstClockTime delay) |
|
1153 { |
|
1154 GstClockTime old_render_delay; |
|
1155 |
|
1156 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
|
1157 |
|
1158 GST_OBJECT_LOCK (sink); |
|
1159 old_render_delay = sink->priv->render_delay; |
|
1160 sink->priv->render_delay = delay; |
|
1161 GST_LOG_OBJECT (sink, "set render delay to %" GST_TIME_FORMAT, |
|
1162 GST_TIME_ARGS (delay)); |
|
1163 GST_OBJECT_UNLOCK (sink); |
|
1164 |
|
1165 if (delay != old_render_delay) { |
|
1166 GST_DEBUG_OBJECT (sink, "posting latency changed"); |
|
1167 gst_element_post_message (GST_ELEMENT_CAST (sink), |
|
1168 gst_message_new_latency (GST_OBJECT_CAST (sink))); |
|
1169 } |
|
1170 } |
|
1171 |
|
1172 /** |
|
1173 * gst_base_sink_get_render_delay: |
|
1174 * @sink: a #GstBaseSink |
|
1175 * |
|
1176 * Get the render delay of @sink. see gst_base_sink_set_render_delay() for more |
|
1177 * information about the render delay. |
|
1178 * |
|
1179 * Returns: the render delay of @sink. |
|
1180 * |
|
1181 * Since: 0.10.21 |
|
1182 */ |
|
1183 #ifdef __SYMBIAN32__ |
|
1184 EXPORT_C |
|
1185 #endif |
|
1186 |
|
1187 GstClockTime |
|
1188 gst_base_sink_get_render_delay (GstBaseSink * sink) |
|
1189 { |
|
1190 GstClockTimeDiff res; |
|
1191 |
|
1192 g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0); |
|
1193 |
|
1194 GST_OBJECT_LOCK (sink); |
|
1195 res = sink->priv->render_delay; |
|
1196 GST_OBJECT_UNLOCK (sink); |
|
1197 |
|
1198 return res; |
|
1199 } |
|
1200 |
|
1201 /** |
|
1202 * gst_base_sink_set_blocksize: |
|
1203 * @sink: a #GstBaseSink |
|
1204 * @blocksize: the blocksize in bytes |
|
1205 * |
|
1206 * Set the number of bytes that the sink will pull when it is operating in pull |
|
1207 * mode. |
|
1208 * |
|
1209 * Since: 0.10.22 |
|
1210 */ |
|
1211 #ifdef __SYMBIAN32__ |
|
1212 EXPORT_C |
|
1213 #endif |
|
1214 |
|
1215 void |
|
1216 gst_base_sink_set_blocksize (GstBaseSink * sink, guint blocksize) |
|
1217 { |
|
1218 g_return_if_fail (GST_IS_BASE_SINK (sink)); |
|
1219 |
|
1220 GST_OBJECT_LOCK (sink); |
|
1221 sink->priv->blocksize = blocksize; |
|
1222 GST_LOG_OBJECT (sink, "set blocksize to %u", blocksize); |
|
1223 GST_OBJECT_UNLOCK (sink); |
|
1224 } |
|
1225 |
|
1226 /** |
|
1227 * gst_base_sink_get_blocksize: |
|
1228 * @sink: a #GstBaseSink |
|
1229 * |
|
1230 * Get the number of bytes that the sink will pull when it is operating in pull |
|
1231 * mode. |
|
1232 * |
|
1233 * Returns: the number of bytes @sink will pull in pull mode. |
|
1234 * |
|
1235 * Since: 0.10.22 |
|
1236 */ |
|
1237 #ifdef __SYMBIAN32__ |
|
1238 EXPORT_C |
|
1239 #endif |
|
1240 |
|
1241 guint |
|
1242 gst_base_sink_get_blocksize (GstBaseSink * sink) |
|
1243 { |
|
1244 guint res; |
|
1245 |
|
1246 g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0); |
|
1247 |
|
1248 GST_OBJECT_LOCK (sink); |
|
1249 res = sink->priv->blocksize; |
|
1250 GST_OBJECT_UNLOCK (sink); |
|
1251 |
|
1252 return res; |
|
1253 } |
1031 } |
1254 |
1032 |
1255 static void |
1033 static void |
1256 gst_base_sink_set_property (GObject * object, guint prop_id, |
1034 gst_base_sink_set_property (GObject * object, guint prop_id, |
1257 const GValue * value, GParamSpec * pspec) |
1035 const GValue * value, GParamSpec * pspec) |
1278 gst_base_sink_set_async_enabled (sink, g_value_get_boolean (value)); |
1056 gst_base_sink_set_async_enabled (sink, g_value_get_boolean (value)); |
1279 break; |
1057 break; |
1280 case PROP_TS_OFFSET: |
1058 case PROP_TS_OFFSET: |
1281 gst_base_sink_set_ts_offset (sink, g_value_get_int64 (value)); |
1059 gst_base_sink_set_ts_offset (sink, g_value_get_int64 (value)); |
1282 break; |
1060 break; |
1283 case PROP_BLOCKSIZE: |
|
1284 gst_base_sink_set_blocksize (sink, g_value_get_uint (value)); |
|
1285 break; |
|
1286 case PROP_RENDER_DELAY: |
|
1287 gst_base_sink_set_render_delay (sink, g_value_get_uint64 (value)); |
|
1288 break; |
|
1289 default: |
1061 default: |
1290 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
1062 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
1291 break; |
1063 break; |
1292 } |
1064 } |
1293 } |
1065 } |
1320 g_value_set_int64 (value, gst_base_sink_get_ts_offset (sink)); |
1092 g_value_set_int64 (value, gst_base_sink_get_ts_offset (sink)); |
1321 break; |
1093 break; |
1322 case PROP_LAST_BUFFER: |
1094 case PROP_LAST_BUFFER: |
1323 gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink)); |
1095 gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink)); |
1324 break; |
1096 break; |
1325 case PROP_BLOCKSIZE: |
|
1326 g_value_set_uint (value, gst_base_sink_get_blocksize (sink)); |
|
1327 break; |
|
1328 case PROP_RENDER_DELAY: |
|
1329 g_value_set_uint64 (value, gst_base_sink_get_render_delay (sink)); |
|
1330 break; |
|
1331 default: |
1097 default: |
1332 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
1098 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
1333 break; |
1099 break; |
1334 } |
1100 } |
1335 } |
1101 } |
1368 } |
1134 } |
1369 /* we can't have EOS anymore now */ |
1135 /* we can't have EOS anymore now */ |
1370 basesink->eos = FALSE; |
1136 basesink->eos = FALSE; |
1371 basesink->priv->received_eos = FALSE; |
1137 basesink->priv->received_eos = FALSE; |
1372 basesink->have_preroll = FALSE; |
1138 basesink->have_preroll = FALSE; |
1373 basesink->priv->step_unlock = FALSE; |
|
1374 basesink->eos_queued = FALSE; |
1139 basesink->eos_queued = FALSE; |
1375 basesink->preroll_queued = 0; |
1140 basesink->preroll_queued = 0; |
1376 basesink->buffers_queued = 0; |
1141 basesink->buffers_queued = 0; |
1377 basesink->events_queued = 0; |
1142 basesink->events_queued = 0; |
1378 /* can't report latency anymore until we preroll again */ |
1143 /* can't report latency anymore until we preroll again */ |
1437 /* commit state and proceed to next pending state */ |
1202 /* commit state and proceed to next pending state */ |
1438 GstState current, next, pending, post_pending; |
1203 GstState current, next, pending, post_pending; |
1439 gboolean post_paused = FALSE; |
1204 gboolean post_paused = FALSE; |
1440 gboolean post_async_done = FALSE; |
1205 gboolean post_async_done = FALSE; |
1441 gboolean post_playing = FALSE; |
1206 gboolean post_playing = FALSE; |
1207 gboolean sync; |
|
1442 |
1208 |
1443 /* we are certainly not playing async anymore now */ |
1209 /* we are certainly not playing async anymore now */ |
1444 basesink->playing_async = FALSE; |
1210 basesink->playing_async = FALSE; |
1445 |
1211 |
1446 GST_OBJECT_LOCK (basesink); |
1212 GST_OBJECT_LOCK (basesink); |
1447 current = GST_STATE (basesink); |
1213 current = GST_STATE (basesink); |
1448 next = GST_STATE_NEXT (basesink); |
1214 next = GST_STATE_NEXT (basesink); |
1449 pending = GST_STATE_PENDING (basesink); |
1215 pending = GST_STATE_PENDING (basesink); |
1450 post_pending = pending; |
1216 post_pending = pending; |
1217 sync = basesink->sync; |
|
1451 |
1218 |
1452 switch (pending) { |
1219 switch (pending) { |
1453 case GST_STATE_PLAYING: |
1220 case GST_STATE_PLAYING: |
1454 { |
1221 { |
1455 GstBaseSinkClass *bclass; |
1222 GstBaseSinkClass *bclass; |
1468 post_paused = TRUE; |
1235 post_paused = TRUE; |
1469 } |
1236 } |
1470 |
1237 |
1471 /* make sure we notify the subclass of async playing */ |
1238 /* make sure we notify the subclass of async playing */ |
1472 if (bclass->async_play) { |
1239 if (bclass->async_play) { |
1473 GST_WARNING_OBJECT (basesink, "deprecated async_play"); |
|
1474 ret = bclass->async_play (basesink); |
1240 ret = bclass->async_play (basesink); |
1475 if (ret == GST_STATE_CHANGE_FAILURE) |
1241 if (ret == GST_STATE_CHANGE_FAILURE) |
1476 goto async_failed; |
1242 goto async_failed; |
1477 } |
1243 } |
1478 break; |
1244 break; |
1566 GST_OBJECT_UNLOCK (basesink); |
1332 GST_OBJECT_UNLOCK (basesink); |
1567 return FALSE; |
1333 return FALSE; |
1568 } |
1334 } |
1569 } |
1335 } |
1570 |
1336 |
1571 static void |
|
1572 start_stepping (GstBaseSink * sink, GstSegment * segment, |
|
1573 GstStepInfo * pending, GstStepInfo * current) |
|
1574 { |
|
1575 gint64 end; |
|
1576 GstMessage *message; |
|
1577 |
|
1578 GST_DEBUG_OBJECT (sink, "update pending step"); |
|
1579 |
|
1580 GST_OBJECT_LOCK (sink); |
|
1581 memcpy (current, pending, sizeof (GstStepInfo)); |
|
1582 pending->valid = FALSE; |
|
1583 GST_OBJECT_UNLOCK (sink); |
|
1584 |
|
1585 /* post message first */ |
|
1586 message = |
|
1587 gst_message_new_step_start (GST_OBJECT (sink), TRUE, current->format, |
|
1588 current->amount, current->rate, current->flush, current->intermediate); |
|
1589 gst_message_set_seqnum (message, current->seqnum); |
|
1590 gst_element_post_message (GST_ELEMENT (sink), message); |
|
1591 |
|
1592 /* get the running time of where we paused and remember it */ |
|
1593 current->start = gst_element_get_start_time (GST_ELEMENT_CAST (sink)); |
|
1594 gst_segment_set_running_time (segment, GST_FORMAT_TIME, current->start); |
|
1595 |
|
1596 /* set the new rate for the remainder of the segment */ |
|
1597 current->start_rate = segment->rate; |
|
1598 segment->rate *= current->rate; |
|
1599 segment->abs_rate = ABS (segment->rate); |
|
1600 |
|
1601 /* save values */ |
|
1602 if (segment->rate > 0.0) |
|
1603 current->start_stop = segment->stop; |
|
1604 else |
|
1605 current->start_start = segment->start; |
|
1606 |
|
1607 if (current->format == GST_FORMAT_TIME) { |
|
1608 end = current->start + current->amount; |
|
1609 if (!current->flush) { |
|
1610 /* update the segment clipping regions for non-flushing seeks */ |
|
1611 if (segment->rate > 0.0) { |
|
1612 segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end); |
|
1613 segment->last_stop = segment->stop; |
|
1614 } else { |
|
1615 gint64 position; |
|
1616 |
|
1617 position = gst_segment_to_position (segment, GST_FORMAT_TIME, end); |
|
1618 segment->time = position; |
|
1619 segment->start = position; |
|
1620 segment->last_stop = position; |
|
1621 } |
|
1622 } |
|
1623 } |
|
1624 |
|
1625 GST_DEBUG_OBJECT (sink, |
|
1626 "segment now rate %lf, applied rate %lf, " |
|
1627 "format GST_FORMAT_TIME, " |
|
1628 "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT |
|
1629 ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, |
|
1630 segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start), |
|
1631 GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time), |
|
1632 GST_TIME_ARGS (segment->accum)); |
|
1633 |
|
1634 GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT, |
|
1635 GST_TIME_ARGS (current->start)); |
|
1636 |
|
1637 if (current->amount == -1) { |
|
1638 GST_DEBUG_OBJECT (sink, "step amount == -1, stop stepping"); |
|
1639 current->valid = FALSE; |
|
1640 } else { |
|
1641 GST_DEBUG_OBJECT (sink, "step amount: %" G_GUINT64_FORMAT ", format: %s, " |
|
1642 "rate: %f", current->amount, gst_format_get_name (current->format), |
|
1643 current->rate); |
|
1644 } |
|
1645 } |
|
1646 |
|
1647 static void |
|
1648 stop_stepping (GstBaseSink * sink, GstSegment * segment, |
|
1649 GstStepInfo * current, gint64 rstart, gint64 rstop, gboolean eos) |
|
1650 { |
|
1651 gint64 stop, position; |
|
1652 GstMessage *message; |
|
1653 |
|
1654 GST_DEBUG_OBJECT (sink, "step complete"); |
|
1655 |
|
1656 if (segment->rate > 0.0) |
|
1657 stop = rstart; |
|
1658 else |
|
1659 stop = rstop; |
|
1660 |
|
1661 GST_DEBUG_OBJECT (sink, |
|
1662 "step stop at running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (stop)); |
|
1663 |
|
1664 if (stop == -1) |
|
1665 current->duration = current->position; |
|
1666 else |
|
1667 current->duration = stop - current->start; |
|
1668 |
|
1669 GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT, |
|
1670 GST_TIME_ARGS (current->duration)); |
|
1671 |
|
1672 position = current->start + current->duration; |
|
1673 |
|
1674 /* now move the segment to the new running time */ |
|
1675 gst_segment_set_running_time (segment, GST_FORMAT_TIME, position); |
|
1676 |
|
1677 if (current->flush) { |
|
1678 /* and remove the accumulated time we flushed, start time did not change */ |
|
1679 segment->accum = current->start; |
|
1680 } else { |
|
1681 /* start time is now the stepped position */ |
|
1682 gst_element_set_start_time (GST_ELEMENT_CAST (sink), position); |
|
1683 } |
|
1684 |
|
1685 /* restore the previous rate */ |
|
1686 segment->rate = current->start_rate; |
|
1687 segment->abs_rate = ABS (segment->rate); |
|
1688 |
|
1689 if (segment->rate > 0.0) |
|
1690 segment->stop = current->start_stop; |
|
1691 else |
|
1692 segment->start = current->start_start; |
|
1693 |
|
1694 /* the clip segment is used for position report in paused... */ |
|
1695 memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment)); |
|
1696 |
|
1697 /* post the step done when we know the stepped duration in TIME */ |
|
1698 message = |
|
1699 gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format, |
|
1700 current->amount, current->rate, current->flush, current->intermediate, |
|
1701 current->duration, eos); |
|
1702 gst_message_set_seqnum (message, current->seqnum); |
|
1703 gst_element_post_message (GST_ELEMENT_CAST (sink), message); |
|
1704 |
|
1705 if (!current->intermediate) |
|
1706 sink->need_preroll = current->need_preroll; |
|
1707 |
|
1708 /* and the current step info finished and becomes invalid */ |
|
1709 current->valid = FALSE; |
|
1710 } |
|
1711 |
|
1712 static gboolean |
|
1713 handle_stepping (GstBaseSink * sink, GstSegment * segment, |
|
1714 GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart, |
|
1715 gint64 * rstop) |
|
1716 { |
|
1717 GstBaseSinkPrivate *priv; |
|
1718 gboolean step_end = FALSE; |
|
1719 |
|
1720 priv = sink->priv; |
|
1721 |
|
1722 /* see if we need to skip this buffer because of stepping */ |
|
1723 switch (current->format) { |
|
1724 case GST_FORMAT_TIME: |
|
1725 { |
|
1726 guint64 end; |
|
1727 gint64 first, last; |
|
1728 |
|
1729 if (segment->rate > 0.0) { |
|
1730 first = *rstart; |
|
1731 last = *rstop; |
|
1732 } else { |
|
1733 first = *rstop; |
|
1734 last = *rstart; |
|
1735 } |
|
1736 |
|
1737 end = current->start + current->amount; |
|
1738 current->position = first - current->start; |
|
1739 |
|
1740 if (G_UNLIKELY (segment->abs_rate != 1.0)) |
|
1741 current->position /= segment->abs_rate; |
|
1742 |
|
1743 GST_DEBUG_OBJECT (sink, |
|
1744 "buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, |
|
1745 GST_TIME_ARGS (first), GST_TIME_ARGS (last)); |
|
1746 GST_DEBUG_OBJECT (sink, |
|
1747 "got time step %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "/%" |
|
1748 GST_TIME_FORMAT, GST_TIME_ARGS (current->position), |
|
1749 GST_TIME_ARGS (last - current->start), |
|
1750 GST_TIME_ARGS (current->amount)); |
|
1751 |
|
1752 if ((current->flush && current->position >= current->amount) |
|
1753 || last >= end) { |
|
1754 GST_DEBUG_OBJECT (sink, "step ended, we need clipping"); |
|
1755 step_end = TRUE; |
|
1756 if (segment->rate > 0.0) { |
|
1757 *rstart = end; |
|
1758 *cstart = gst_segment_to_position (segment, GST_FORMAT_TIME, end); |
|
1759 } else { |
|
1760 *rstop = end; |
|
1761 *cstop = gst_segment_to_position (segment, GST_FORMAT_TIME, end); |
|
1762 } |
|
1763 } |
|
1764 GST_DEBUG_OBJECT (sink, |
|
1765 "cstart %" GST_TIME_FORMAT ", rstart %" GST_TIME_FORMAT, |
|
1766 GST_TIME_ARGS (*cstart), GST_TIME_ARGS (*rstart)); |
|
1767 GST_DEBUG_OBJECT (sink, |
|
1768 "cstop %" GST_TIME_FORMAT ", rstop %" GST_TIME_FORMAT, |
|
1769 GST_TIME_ARGS (*cstop), GST_TIME_ARGS (*rstop)); |
|
1770 break; |
|
1771 } |
|
1772 case GST_FORMAT_BUFFERS: |
|
1773 GST_DEBUG_OBJECT (sink, |
|
1774 "got default step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, |
|
1775 current->position, current->amount); |
|
1776 |
|
1777 if (current->position < current->amount) { |
|
1778 current->position++; |
|
1779 } else { |
|
1780 step_end = TRUE; |
|
1781 } |
|
1782 break; |
|
1783 case GST_FORMAT_DEFAULT: |
|
1784 default: |
|
1785 GST_DEBUG_OBJECT (sink, |
|
1786 "got unknown step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, |
|
1787 current->position, current->amount); |
|
1788 break; |
|
1789 } |
|
1790 return step_end; |
|
1791 } |
|
1792 |
1337 |
1793 /* with STREAM_LOCK, PREROLL_LOCK |
1338 /* with STREAM_LOCK, PREROLL_LOCK |
1794 * |
1339 * |
1795 * Returns TRUE if the object needs synchronisation and takes therefore |
1340 * Returns TRUE if the object needs synchronisation and takes therefore |
1796 * part in prerolling. |
1341 * part in prerolling. |
1800 */ |
1345 */ |
1801 static gboolean |
1346 static gboolean |
1802 gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj, |
1347 gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj, |
1803 GstClockTime * rsstart, GstClockTime * rsstop, |
1348 GstClockTime * rsstart, GstClockTime * rsstop, |
1804 GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync, |
1349 GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync, |
1805 gboolean * stepped, GstSegment * segment, GstStepInfo * step, |
1350 GstSegment * segment) |
1806 gboolean * step_end) |
|
1807 { |
1351 { |
1808 GstBaseSinkClass *bclass; |
1352 GstBaseSinkClass *bclass; |
1809 GstBuffer *buffer; |
1353 GstBuffer *buffer; |
1810 GstClockTime start, stop; /* raw start/stop timestamps */ |
1354 GstClockTime start, stop; /* raw start/stop timestamps */ |
1811 gint64 cstart, cstop; /* clipped raw timestamps */ |
1355 gint64 cstart, cstop; /* clipped raw timestamps */ |
1812 gint64 rstart, rstop; /* clipped timestamps converted to running time */ |
1356 gint64 rstart, rstop; /* clipped timestamps converted to running time */ |
1813 GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */ |
1357 GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */ |
1814 GstFormat format; |
1358 GstFormat format; |
1815 GstBaseSinkPrivate *priv; |
1359 GstBaseSinkPrivate *priv; |
1816 gboolean eos; |
|
1817 |
1360 |
1818 priv = basesink->priv; |
1361 priv = basesink->priv; |
1819 |
1362 |
1820 /* start with nothing */ |
1363 /* start with nothing */ |
1821 start = stop = -1; |
1364 start = stop = sstart = sstop = rstart = rstop = -1; |
1822 |
1365 |
1823 if (G_UNLIKELY (GST_IS_EVENT (obj))) { |
1366 if (G_UNLIKELY (GST_IS_EVENT (obj))) { |
1824 GstEvent *event = GST_EVENT_CAST (obj); |
1367 GstEvent *event = GST_EVENT_CAST (obj); |
1825 |
1368 |
1826 switch (GST_EVENT_TYPE (event)) { |
1369 switch (GST_EVENT_TYPE (event)) { |
1827 /* EOS event needs syncing */ |
1370 /* EOS event needs syncing */ |
1828 case GST_EVENT_EOS: |
1371 case GST_EVENT_EOS: |
1829 { |
1372 sstart = sstop = priv->current_sstop; |
1830 if (basesink->segment.rate >= 0.0) { |
|
1831 sstart = sstop = priv->current_sstop; |
|
1832 if (sstart == -1) { |
|
1833 /* we have not seen a buffer yet, use the segment values */ |
|
1834 sstart = sstop = gst_segment_to_stream_time (&basesink->segment, |
|
1835 basesink->segment.format, basesink->segment.stop); |
|
1836 } |
|
1837 } else { |
|
1838 sstart = sstop = priv->current_sstart; |
|
1839 if (sstart == -1) { |
|
1840 /* we have not seen a buffer yet, use the segment values */ |
|
1841 sstart = sstop = gst_segment_to_stream_time (&basesink->segment, |
|
1842 basesink->segment.format, basesink->segment.start); |
|
1843 } |
|
1844 } |
|
1845 |
|
1846 rstart = rstop = priv->eos_rtime; |
1373 rstart = rstop = priv->eos_rtime; |
1847 *do_sync = rstart != -1; |
1374 *do_sync = rstart != -1; |
1848 GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT, |
1375 GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT, |
1849 GST_TIME_ARGS (rstart)); |
1376 GST_TIME_ARGS (rstart)); |
1850 /* if we are stepping, we end now */ |
1377 goto done; |
1851 *step_end = step->valid; |
|
1852 eos = TRUE; |
|
1853 goto eos_done; |
|
1854 } |
|
1855 default: |
|
1856 /* other events do not need syncing */ |
1378 /* other events do not need syncing */ |
1857 /* FIXME, maybe NEWSEGMENT might need synchronisation |
1379 /* FIXME, maybe NEWSEGMENT might need synchronisation |
1858 * since the POSITION query depends on accumulated times and |
1380 * since the POSITION query depends on accumulated times and |
1859 * we cannot accumulate the current segment before the previous |
1381 * we cannot accumulate the current segment before the previous |
1860 * one completed. |
1382 * one completed. |
1861 */ |
1383 */ |
1384 default: |
|
1862 return FALSE; |
1385 return FALSE; |
1863 } |
1386 } |
1864 } |
1387 } |
1865 |
1388 |
1866 eos = FALSE; |
|
1867 |
|
1868 /* else do buffer sync code */ |
1389 /* else do buffer sync code */ |
1869 buffer = GST_BUFFER_CAST (obj); |
1390 buffer = GST_BUFFER_CAST (obj); |
1870 |
1391 |
1871 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
1392 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
1872 |
1393 |
1873 /* just get the times to see if we need syncing, if the start returns -1 we |
1394 /* just get the times to see if we need syncing */ |
1874 * don't sync. */ |
|
1875 if (bclass->get_times) |
1395 if (bclass->get_times) |
1876 bclass->get_times (basesink, buffer, &start, &stop); |
1396 bclass->get_times (basesink, buffer, &start, &stop); |
1877 |
1397 |
1878 if (start == -1) { |
1398 if (start == -1) { |
1879 /* we don't need to sync but we still want to get the timestamps for |
|
1880 * tracking the position */ |
|
1881 gst_base_sink_get_times (basesink, buffer, &start, &stop); |
1399 gst_base_sink_get_times (basesink, buffer, &start, &stop); |
1882 *do_sync = FALSE; |
1400 *do_sync = FALSE; |
1883 } else { |
1401 } else { |
1884 *do_sync = TRUE; |
1402 *do_sync = TRUE; |
1885 } |
1403 } |
1889 GST_TIME_ARGS (stop), *do_sync); |
1407 GST_TIME_ARGS (stop), *do_sync); |
1890 |
1408 |
1891 /* collect segment and format for code clarity */ |
1409 /* collect segment and format for code clarity */ |
1892 format = segment->format; |
1410 format = segment->format; |
1893 |
1411 |
1894 /* no timestamp clipping if we did not get a TIME segment format */ |
1412 /* no timestamp clipping if we did not * get a TIME segment format */ |
1895 if (G_UNLIKELY (format != GST_FORMAT_TIME)) { |
1413 if (G_UNLIKELY (format != GST_FORMAT_TIME)) { |
1896 cstart = start; |
1414 cstart = start; |
1897 cstop = stop; |
1415 cstop = stop; |
1898 /* do running and stream time in TIME format */ |
1416 /* do running and stream time in TIME format */ |
1899 format = GST_FORMAT_TIME; |
1417 format = GST_FORMAT_TIME; |
1900 GST_LOG_OBJECT (basesink, "not time format, don't clip"); |
|
1901 goto do_times; |
1418 goto do_times; |
1902 } |
1419 } |
1903 |
1420 |
1904 /* clip, only when we know about time */ |
1421 /* clip */ |
1905 if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME, |
1422 if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME, |
1906 (gint64) start, (gint64) stop, &cstart, &cstop))) { |
1423 (gint64) start, (gint64) stop, &cstart, &cstop))) |
1907 if (step->valid) { |
|
1908 GST_DEBUG_OBJECT (basesink, "step out of segment"); |
|
1909 /* when we are stepping, pretend we're at the end of the segment */ |
|
1910 if (segment->rate > 0.0) { |
|
1911 cstart = segment->stop; |
|
1912 cstop = segment->stop; |
|
1913 } else { |
|
1914 cstart = segment->start; |
|
1915 cstop = segment->start; |
|
1916 } |
|
1917 goto do_times; |
|
1918 } |
|
1919 goto out_of_segment; |
1424 goto out_of_segment; |
1920 } |
|
1921 |
1425 |
1922 if (G_UNLIKELY (start != cstart || stop != cstop)) { |
1426 if (G_UNLIKELY (start != cstart || stop != cstop)) { |
1923 GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT |
1427 GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT |
1924 ", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart), |
1428 ", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart), |
1925 GST_TIME_ARGS (cstop)); |
1429 GST_TIME_ARGS (cstop)); |
1926 } |
1430 } |
1927 |
1431 |
1928 /* set last stop position */ |
1432 /* set last stop position */ |
1929 if (G_LIKELY (cstop != GST_CLOCK_TIME_NONE)) |
1433 gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop); |
1930 gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop); |
|
1931 else |
|
1932 gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart); |
|
1933 |
1434 |
1934 do_times: |
1435 do_times: |
1935 rstart = gst_segment_to_running_time (segment, format, cstart); |
|
1936 rstop = gst_segment_to_running_time (segment, format, cstop); |
|
1937 |
|
1938 if (G_UNLIKELY (step->valid)) { |
|
1939 if (!(*step_end = handle_stepping (basesink, segment, step, &cstart, &cstop, |
|
1940 &rstart, &rstop))) { |
|
1941 /* step is still busy, we discard data when we are flushing */ |
|
1942 *stepped = step->flush; |
|
1943 } |
|
1944 } |
|
1945 /* this can produce wrong values if we accumulated non-TIME segments. If this happens, |
1436 /* this can produce wrong values if we accumulated non-TIME segments. If this happens, |
1946 * upstream is behaving very badly */ |
1437 * upstream is behaving very badly */ |
1947 sstart = gst_segment_to_stream_time (segment, format, cstart); |
1438 sstart = gst_segment_to_stream_time (segment, format, cstart); |
1948 sstop = gst_segment_to_stream_time (segment, format, cstop); |
1439 sstop = gst_segment_to_stream_time (segment, format, cstop); |
1949 |
1440 rstart = gst_segment_to_running_time (segment, format, cstart); |
1950 eos_done: |
1441 rstop = gst_segment_to_running_time (segment, format, cstop); |
1951 /* eos_done label only called when doing EOS, we also stop stepping then */ |
1442 |
1952 if (*step_end && step->flush) { |
1443 done: |
1953 GST_DEBUG_OBJECT (basesink, "flushing step ended"); |
|
1954 stop_stepping (basesink, segment, step, rstart, rstop, eos); |
|
1955 *step_end = FALSE; |
|
1956 } |
|
1957 |
|
1958 /* save times */ |
1444 /* save times */ |
1959 *rsstart = sstart; |
1445 *rsstart = sstart; |
1960 *rsstop = sstop; |
1446 *rsstop = sstop; |
1961 *rrstart = rstart; |
1447 *rrstart = rstart; |
1962 *rrstop = rstop; |
1448 *rrstop = rstop; |
1965 return TRUE; |
1451 return TRUE; |
1966 |
1452 |
1967 /* special cases */ |
1453 /* special cases */ |
1968 out_of_segment: |
1454 out_of_segment: |
1969 { |
1455 { |
1970 /* we usually clip in the chain function already but stepping could cause |
1456 /* should not happen since we clip them in the chain function already, |
1971 * the segment to be updated later. we return FALSE so that we don't try |
1457 * we return FALSE so that we don't try to sync on it. */ |
1972 * to sync on it. */ |
1458 GST_ELEMENT_WARNING (basesink, STREAM, FAILED, |
1459 (NULL), ("unexpected buffer out of segment found.")); |
|
1973 GST_LOG_OBJECT (basesink, "buffer skipped, not in segment"); |
1460 GST_LOG_OBJECT (basesink, "buffer skipped, not in segment"); |
1974 return FALSE; |
1461 return FALSE; |
1975 } |
1462 } |
1976 } |
1463 } |
1977 |
1464 |
1978 /* with STREAM_LOCK, PREROLL_LOCK, LOCK |
1465 /* with STREAM_LOCK, PREROLL_LOCK |
1979 * adjust a timestamp with the latency and timestamp offset */ |
1466 * |
1980 static GstClockTime |
1467 * Waits for the clock to reach @time. If @time is not valid, no |
1981 gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time) |
1468 * synchronisation is done and BADTIME is returned. |
1982 { |
1469 * If synchronisation is disabled in the element or there is no |
1470 * clock, no synchronisation is done and BADTIME is returned. |
|
1471 * |
|
1472 * Else a blocking wait is performed on the clock. We save the ClockID |
|
1473 * so we can unlock the entry at any time. While we are blocking, we |
|
1474 * release the PREROLL_LOCK so that other threads can interrupt the entry. |
|
1475 * |
|
1476 * @time is expressed in running time. |
|
1477 */ |
|
1478 static GstClockReturn |
|
1479 gst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time, |
|
1480 GstClockTimeDiff * jitter) |
|
1481 { |
|
1482 GstClockID id; |
|
1483 GstClockReturn ret; |
|
1484 GstClock *clock; |
|
1983 GstClockTimeDiff ts_offset; |
1485 GstClockTimeDiff ts_offset; |
1984 |
1486 |
1985 /* don't do anything funny with invalid timestamps */ |
|
1986 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) |
1487 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) |
1987 return time; |
1488 goto invalid_time; |
1988 |
1489 |
1490 GST_OBJECT_LOCK (basesink); |
|
1491 if (G_UNLIKELY (!basesink->sync)) |
|
1492 goto no_sync; |
|
1493 |
|
1494 if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL)) |
|
1495 goto no_clock; |
|
1496 |
|
1497 /* add base time and latency */ |
|
1498 time += GST_ELEMENT_CAST (basesink)->base_time; |
|
1989 time += basesink->priv->latency; |
1499 time += basesink->priv->latency; |
1990 |
1500 |
1991 /* apply offset, be carefull for underflows */ |
1501 /* apply offset, be carefull for underflows */ |
1992 ts_offset = basesink->priv->ts_offset; |
1502 ts_offset = basesink->priv->ts_offset; |
1993 if (ts_offset < 0) { |
1503 if (ts_offset < 0) { |
1997 else |
1507 else |
1998 time = 0; |
1508 time = 0; |
1999 } else |
1509 } else |
2000 time += ts_offset; |
1510 time += ts_offset; |
2001 |
1511 |
2002 return time; |
|
2003 } |
|
2004 |
|
2005 /** |
|
2006 * gst_base_sink_wait_clock: |
|
2007 * @sink: the sink |
|
2008 * @time: the running_time to be reached |
|
2009 * @jitter: the jitter to be filled with time diff (can be NULL) |
|
2010 * |
|
2011 * This function will block until @time is reached. It is usually called by |
|
2012 * subclasses that use their own internal synchronisation. |
|
2013 * |
|
2014 * If @time is not valid, no sycnhronisation is done and #GST_CLOCK_BADTIME is |
|
2015 * returned. Likewise, if synchronisation is disabled in the element or there |
|
2016 * is no clock, no synchronisation is done and #GST_CLOCK_BADTIME is returned. |
|
2017 * |
|
2018 * This function should only be called with the PREROLL_LOCK held, like when |
|
2019 * receiving an EOS event in the ::event vmethod or when receiving a buffer in |
|
2020 * the ::render vmethod. |
|
2021 * |
|
2022 * The @time argument should be the running_time of when this method should |
|
2023 * return and is not adjusted with any latency or offset configured in the |
|
2024 * sink. |
|
2025 * |
|
2026 * Since 0.10.20 |
|
2027 * |
|
2028 * Returns: #GstClockReturn |
|
2029 */ |
|
2030 #ifdef __SYMBIAN32__ |
|
2031 EXPORT_C |
|
2032 #endif |
|
2033 |
|
2034 GstClockReturn |
|
2035 gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, |
|
2036 GstClockTimeDiff * jitter) |
|
2037 { |
|
2038 GstClockID id; |
|
2039 GstClockReturn ret; |
|
2040 GstClock *clock; |
|
2041 |
|
2042 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) |
|
2043 goto invalid_time; |
|
2044 |
|
2045 GST_OBJECT_LOCK (sink); |
|
2046 if (G_UNLIKELY (!sink->sync)) |
|
2047 goto no_sync; |
|
2048 |
|
2049 if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (sink)) == NULL)) |
|
2050 goto no_clock; |
|
2051 |
|
2052 /* add base_time to running_time to get the time against the clock */ |
|
2053 time += GST_ELEMENT_CAST (sink)->base_time; |
|
2054 |
|
2055 id = gst_clock_new_single_shot_id (clock, time); |
1512 id = gst_clock_new_single_shot_id (clock, time); |
2056 GST_OBJECT_UNLOCK (sink); |
1513 GST_OBJECT_UNLOCK (basesink); |
2057 |
1514 |
2058 /* A blocking wait is performed on the clock. We save the ClockID |
1515 basesink->clock_id = id; |
2059 * so we can unlock the entry at any time. While we are blocking, we |
|
2060 * release the PREROLL_LOCK so that other threads can interrupt the |
|
2061 * entry. */ |
|
2062 sink->clock_id = id; |
|
2063 /* release the preroll lock while waiting */ |
1516 /* release the preroll lock while waiting */ |
2064 GST_PAD_PREROLL_UNLOCK (sink->sinkpad); |
1517 GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); |
2065 |
1518 |
2066 ret = gst_clock_id_wait (id, jitter); |
1519 ret = gst_clock_id_wait (id, jitter); |
2067 |
1520 |
2068 GST_PAD_PREROLL_LOCK (sink->sinkpad); |
1521 GST_PAD_PREROLL_LOCK (basesink->sinkpad); |
2069 gst_clock_id_unref (id); |
1522 gst_clock_id_unref (id); |
2070 sink->clock_id = NULL; |
1523 basesink->clock_id = NULL; |
2071 |
1524 |
2072 return ret; |
1525 return ret; |
2073 |
1526 |
2074 /* no syncing needed */ |
1527 /* no syncing needed */ |
2075 invalid_time: |
1528 invalid_time: |
2076 { |
1529 { |
2077 GST_DEBUG_OBJECT (sink, "time not valid, no sync needed"); |
1530 GST_DEBUG_OBJECT (basesink, "time not valid, no sync needed"); |
2078 return GST_CLOCK_BADTIME; |
1531 return GST_CLOCK_BADTIME; |
2079 } |
1532 } |
2080 no_sync: |
1533 no_sync: |
2081 { |
1534 { |
2082 GST_DEBUG_OBJECT (sink, "sync disabled"); |
1535 GST_DEBUG_OBJECT (basesink, "sync disabled"); |
2083 GST_OBJECT_UNLOCK (sink); |
1536 GST_OBJECT_UNLOCK (basesink); |
2084 return GST_CLOCK_BADTIME; |
1537 return GST_CLOCK_BADTIME; |
2085 } |
1538 } |
2086 no_clock: |
1539 no_clock: |
2087 { |
1540 { |
2088 GST_DEBUG_OBJECT (sink, "no clock, can't sync"); |
1541 GST_DEBUG_OBJECT (basesink, "no clock, can't sync"); |
2089 GST_OBJECT_UNLOCK (sink); |
1542 GST_OBJECT_UNLOCK (basesink); |
2090 return GST_CLOCK_BADTIME; |
1543 return GST_CLOCK_BADTIME; |
2091 } |
1544 } |
2092 } |
1545 } |
2093 |
1546 |
2094 /** |
1547 /** |
2101 * |
1554 * |
2102 * This function will block until a state change to PLAYING happens (in which |
1555 * This function will block until a state change to PLAYING happens (in which |
2103 * case this function returns #GST_FLOW_OK) or the processing must be stopped due |
1556 * case this function returns #GST_FLOW_OK) or the processing must be stopped due |
2104 * to a state change to READY or a FLUSH event (in which case this function |
1557 * to a state change to READY or a FLUSH event (in which case this function |
2105 * returns #GST_FLOW_WRONG_STATE). |
1558 * returns #GST_FLOW_WRONG_STATE). |
2106 * |
|
2107 * This function should only be called with the PREROLL_LOCK held, like in the |
|
2108 * render function. |
|
2109 * |
1559 * |
2110 * Since: 0.10.11 |
1560 * Since: 0.10.11 |
2111 * |
1561 * |
2112 * Returns: #GST_FLOW_OK if the preroll completed and processing can |
1562 * Returns: #GST_FLOW_OK if the preroll completed and processing can |
2113 * continue. Any other return value should be returned from the render vmethod. |
1563 * continue. Any other return value should be returned from the render vmethod. |
2124 /* block until the state changes, or we get a flush, or something */ |
1574 /* block until the state changes, or we get a flush, or something */ |
2125 GST_PAD_PREROLL_WAIT (sink->sinkpad); |
1575 GST_PAD_PREROLL_WAIT (sink->sinkpad); |
2126 sink->have_preroll = FALSE; |
1576 sink->have_preroll = FALSE; |
2127 if (G_UNLIKELY (sink->flushing)) |
1577 if (G_UNLIKELY (sink->flushing)) |
2128 goto stopping; |
1578 goto stopping; |
2129 if (G_UNLIKELY (sink->priv->step_unlock)) |
|
2130 goto step_unlocked; |
|
2131 GST_DEBUG_OBJECT (sink, "continue after preroll"); |
1579 GST_DEBUG_OBJECT (sink, "continue after preroll"); |
2132 |
1580 |
2133 return GST_FLOW_OK; |
1581 return GST_FLOW_OK; |
2134 |
1582 |
2135 /* ERRORS */ |
1583 /* ERRORS */ |
2136 stopping: |
1584 stopping: |
2137 { |
1585 { |
2138 GST_DEBUG_OBJECT (sink, "preroll interrupted because of flush"); |
1586 GST_DEBUG_OBJECT (sink, "preroll interrupted"); |
2139 return GST_FLOW_WRONG_STATE; |
1587 return GST_FLOW_WRONG_STATE; |
2140 } |
|
2141 step_unlocked: |
|
2142 { |
|
2143 sink->priv->step_unlock = FALSE; |
|
2144 GST_DEBUG_OBJECT (sink, "preroll interrupted because of step"); |
|
2145 return GST_FLOW_STEP; |
|
2146 } |
|
2147 } |
|
2148 |
|
2149 /** |
|
2150 * gst_base_sink_do_preroll: |
|
2151 * @sink: the sink |
|
2152 * @obj: the object that caused the preroll |
|
2153 * |
|
2154 * If the @sink spawns its own thread for pulling buffers from upstream it |
|
2155 * should call this method after it has pulled a buffer. If the element needed |
|
2156 * to preroll, this function will perform the preroll and will then block |
|
2157 * until the element state is changed. |
|
2158 * |
|
2159 * This function should be called with the PREROLL_LOCK held. |
|
2160 * |
|
2161 * Since 0.10.22 |
|
2162 * |
|
2163 * Returns: #GST_FLOW_OK if the preroll completed and processing can |
|
2164 * continue. Any other return value should be returned from the render vmethod. |
|
2165 */ |
|
2166 #ifdef __SYMBIAN32__ |
|
2167 EXPORT_C |
|
2168 #endif |
|
2169 |
|
2170 GstFlowReturn |
|
2171 gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj) |
|
2172 { |
|
2173 GstFlowReturn ret; |
|
2174 |
|
2175 while (G_UNLIKELY (sink->need_preroll)) { |
|
2176 GST_DEBUG_OBJECT (sink, "prerolling object %p", obj); |
|
2177 |
|
2178 ret = gst_base_sink_preroll_object (sink, FALSE, obj); |
|
2179 if (ret != GST_FLOW_OK) |
|
2180 goto preroll_failed; |
|
2181 |
|
2182 /* need to recheck here because the commit state could have |
|
2183 * made us not need the preroll anymore */ |
|
2184 if (G_LIKELY (sink->need_preroll)) { |
|
2185 /* block until the state changes, or we get a flush, or something */ |
|
2186 ret = gst_base_sink_wait_preroll (sink); |
|
2187 if (ret != GST_FLOW_OK) { |
|
2188 if (ret == GST_FLOW_STEP) |
|
2189 ret = GST_FLOW_OK; |
|
2190 else |
|
2191 goto preroll_failed; |
|
2192 } |
|
2193 } |
|
2194 } |
|
2195 return GST_FLOW_OK; |
|
2196 |
|
2197 /* ERRORS */ |
|
2198 preroll_failed: |
|
2199 { |
|
2200 GST_DEBUG_OBJECT (sink, "preroll failed %d", ret); |
|
2201 return ret; |
|
2202 } |
1588 } |
2203 } |
1589 } |
2204 |
1590 |
2205 /** |
1591 /** |
2206 * gst_base_sink_wait_eos: |
1592 * gst_base_sink_wait_eos: |
2213 * EOS be handled by the base class. |
1599 * EOS be handled by the base class. |
2214 * |
1600 * |
2215 * This function should only be called with the PREROLL_LOCK held, like when |
1601 * This function should only be called with the PREROLL_LOCK held, like when |
2216 * receiving an EOS event in the ::event vmethod. |
1602 * receiving an EOS event in the ::event vmethod. |
2217 * |
1603 * |
2218 * The @time argument should be the running_time of when the EOS should happen |
|
2219 * and will be adjusted with any latency and offset configured in the sink. |
|
2220 * |
|
2221 * Since 0.10.15 |
1604 * Since 0.10.15 |
2222 * |
1605 * |
2223 * Returns: #GstFlowReturn |
1606 * Returns: #GstFlowReturn |
2224 */ |
1607 */ |
2225 #ifdef __SYMBIAN32__ |
1608 #ifdef __SYMBIAN32__ |
2232 { |
1615 { |
2233 GstClockReturn status; |
1616 GstClockReturn status; |
2234 GstFlowReturn ret; |
1617 GstFlowReturn ret; |
2235 |
1618 |
2236 do { |
1619 do { |
2237 GstClockTime stime; |
|
2238 |
|
2239 GST_DEBUG_OBJECT (sink, "checking preroll"); |
1620 GST_DEBUG_OBJECT (sink, "checking preroll"); |
2240 |
1621 |
2241 /* first wait for the playing state before we can continue */ |
1622 /* first wait for the playing state before we can continue */ |
2242 if (G_UNLIKELY (sink->need_preroll)) { |
1623 if (G_UNLIKELY (sink->need_preroll)) { |
2243 ret = gst_base_sink_wait_preroll (sink); |
1624 ret = gst_base_sink_wait_preroll (sink); |
2244 if (ret != GST_FLOW_OK) { |
1625 if (ret != GST_FLOW_OK) |
2245 if (ret == GST_FLOW_STEP) |
1626 goto flushing; |
2246 ret = GST_FLOW_OK; |
|
2247 else |
|
2248 goto flushing; |
|
2249 } |
|
2250 } |
1627 } |
2251 |
1628 |
2252 /* preroll done, we can sync since we are in PLAYING now. */ |
1629 /* preroll done, we can sync since we are in PLAYING now. */ |
2253 GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %" |
1630 GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %" |
2254 GST_TIME_FORMAT, GST_TIME_ARGS (time)); |
1631 GST_TIME_FORMAT, GST_TIME_ARGS (time)); |
2255 |
1632 |
2256 /* compensate for latency and ts_offset. We don't adjust for render delay |
|
2257 * because we don't interact with the device on EOS normally. */ |
|
2258 stime = gst_base_sink_adjust_time (sink, time); |
|
2259 |
|
2260 /* wait for the clock, this can be interrupted because we got shut down or |
1633 /* wait for the clock, this can be interrupted because we got shut down or |
2261 * we PAUSED. */ |
1634 * we PAUSED. */ |
2262 status = gst_base_sink_wait_clock (sink, stime, jitter); |
1635 status = gst_base_sink_wait_clock (sink, time, jitter); |
2263 |
1636 |
2264 GST_DEBUG_OBJECT (sink, "clock returned %d", status); |
1637 GST_DEBUG_OBJECT (sink, "clock returned %d", status); |
2265 |
1638 |
2266 /* invalid time, no clock or sync disabled, just continue then */ |
1639 /* invalid time, no clock or sync disabled, just continue then */ |
2267 if (status == GST_CLOCK_BADTIME) |
1640 if (status == GST_CLOCK_BADTIME) |
2309 * |
1682 * |
2310 * does not take ownership of obj. |
1683 * does not take ownership of obj. |
2311 */ |
1684 */ |
2312 static GstFlowReturn |
1685 static GstFlowReturn |
2313 gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad, |
1686 gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad, |
2314 GstMiniObject * obj, gboolean * late, gboolean * step_end) |
1687 GstMiniObject * obj, gboolean * late) |
2315 { |
1688 { |
2316 GstClockTimeDiff jitter; |
1689 GstClockTimeDiff jitter; |
2317 gboolean syncable; |
1690 gboolean syncable; |
2318 GstClockReturn status = GST_CLOCK_OK; |
1691 GstClockReturn status = GST_CLOCK_OK; |
2319 GstClockTime rstart, rstop, sstart, sstop, stime; |
1692 GstClockTime rstart, rstop, sstart, sstop; |
2320 gboolean do_sync; |
1693 gboolean do_sync; |
2321 GstBaseSinkPrivate *priv; |
1694 GstBaseSinkPrivate *priv; |
2322 GstFlowReturn ret; |
|
2323 GstStepInfo *current, *pending; |
|
2324 gboolean stepped; |
|
2325 |
1695 |
2326 priv = basesink->priv; |
1696 priv = basesink->priv; |
2327 |
1697 |
2328 do_step: |
|
2329 sstart = sstop = rstart = rstop = -1; |
1698 sstart = sstop = rstart = rstop = -1; |
2330 do_sync = TRUE; |
1699 do_sync = TRUE; |
2331 stepped = FALSE; |
|
2332 |
1700 |
2333 priv->current_rstart = -1; |
1701 priv->current_rstart = -1; |
2334 |
|
2335 /* get stepping info */ |
|
2336 current = &priv->current_step; |
|
2337 pending = &priv->pending_step; |
|
2338 |
1702 |
2339 /* get timing information for this object against the render segment */ |
1703 /* get timing information for this object against the render segment */ |
2340 syncable = gst_base_sink_get_sync_times (basesink, obj, |
1704 syncable = gst_base_sink_get_sync_times (basesink, obj, |
2341 &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment, |
1705 &sstart, &sstop, &rstart, &rstop, &do_sync, &basesink->segment); |
2342 current, step_end); |
|
2343 |
|
2344 if (G_UNLIKELY (stepped)) |
|
2345 goto step_skipped; |
|
2346 |
1706 |
2347 /* a syncable object needs to participate in preroll and |
1707 /* a syncable object needs to participate in preroll and |
2348 * clocking. All buffers and EOS are syncable. */ |
1708 * clocking. All buffers and EOS are syncable. */ |
2349 if (G_UNLIKELY (!syncable)) |
1709 if (G_UNLIKELY (!syncable)) |
2350 goto not_syncable; |
1710 goto not_syncable; |
2351 |
1711 |
2352 /* store timing info for current object */ |
1712 /* store timing info for current object */ |
2353 priv->current_rstart = rstart; |
1713 priv->current_rstart = rstart; |
2354 priv->current_rstop = (rstop != -1 ? rstop : rstart); |
1714 priv->current_rstop = (rstop != -1 ? rstop : rstart); |
2355 |
|
2356 /* save sync time for eos when the previous object needed sync */ |
1715 /* save sync time for eos when the previous object needed sync */ |
2357 priv->eos_rtime = (do_sync ? priv->current_rstop : -1); |
1716 priv->eos_rtime = (do_sync ? priv->current_rstop : -1); |
2358 |
1717 |
2359 again: |
1718 again: |
2360 /* first do preroll, this makes sure we commit our state |
1719 /* first do preroll, this makes sure we commit our state |
2361 * to PAUSED and can continue to PLAYING. We cannot perform |
1720 * to PAUSED and can continue to PLAYING. We cannot perform |
2362 * any clock sync in PAUSED because there is no clock. */ |
1721 * any clock sync in PAUSED because there is no clock. |
2363 ret = gst_base_sink_do_preroll (basesink, obj); |
1722 */ |
2364 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
1723 while (G_UNLIKELY (basesink->need_preroll)) { |
2365 goto preroll_failed; |
1724 GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj); |
1725 |
|
1726 if (G_LIKELY (basesink->playing_async)) { |
|
1727 /* commit state */ |
|
1728 if (G_UNLIKELY (!gst_base_sink_commit_state (basesink))) |
|
1729 goto stopping; |
|
1730 } |
|
1731 |
|
1732 /* need to recheck here because the commit state could have |
|
1733 * made us not need the preroll anymore */ |
|
1734 if (G_LIKELY (basesink->need_preroll)) { |
|
1735 /* block until the state changes, or we get a flush, or something */ |
|
1736 if (gst_base_sink_wait_preroll (basesink) != GST_FLOW_OK) |
|
1737 goto flushing; |
|
1738 } |
|
1739 } |
|
2366 |
1740 |
2367 /* After rendering we store the position of the last buffer so that we can use |
1741 /* After rendering we store the position of the last buffer so that we can use |
2368 * it to report the position. We need to take the lock here. */ |
1742 * it to report the position. We need to take the lock here. */ |
2369 GST_OBJECT_LOCK (basesink); |
1743 GST_OBJECT_LOCK (basesink); |
2370 priv->current_sstart = sstart; |
1744 priv->current_sstart = sstart; |
2371 priv->current_sstop = (sstop != -1 ? sstop : sstart); |
1745 priv->current_sstop = (sstop != -1 ? sstop : sstart); |
2372 GST_OBJECT_UNLOCK (basesink); |
1746 GST_OBJECT_UNLOCK (basesink); |
2373 |
1747 |
2374 /* update the segment with a pending step if the current one is invalid and we |
|
2375 * have a new pending one. We only accept new step updates after a preroll */ |
|
2376 if (G_UNLIKELY (pending->valid && !current->valid)) { |
|
2377 start_stepping (basesink, &basesink->segment, pending, current); |
|
2378 goto do_step; |
|
2379 } |
|
2380 |
|
2381 if (!do_sync) |
1748 if (!do_sync) |
2382 goto done; |
1749 goto done; |
2383 |
1750 |
2384 /* adjust for latency */ |
|
2385 stime = gst_base_sink_adjust_time (basesink, rstart); |
|
2386 |
|
2387 /* adjust for render-delay, avoid underflows */ |
|
2388 if (stime != -1) { |
|
2389 if (stime > priv->render_delay) |
|
2390 stime -= priv->render_delay; |
|
2391 else |
|
2392 stime = 0; |
|
2393 } |
|
2394 |
|
2395 /* preroll done, we can sync since we are in PLAYING now. */ |
1751 /* preroll done, we can sync since we are in PLAYING now. */ |
2396 GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %" |
1752 GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %" |
2397 GST_TIME_FORMAT ", adjusted %" GST_TIME_FORMAT, |
1753 GST_TIME_FORMAT, GST_TIME_ARGS (rstart)); |
2398 GST_TIME_ARGS (rstart), GST_TIME_ARGS (stime)); |
1754 |
2399 |
1755 /* this function will return immediatly if start == -1, no clock |
2400 /* This function will return immediatly if start == -1, no clock |
|
2401 * or sync is disabled with GST_CLOCK_BADTIME. */ |
1756 * or sync is disabled with GST_CLOCK_BADTIME. */ |
2402 status = gst_base_sink_wait_clock (basesink, stime, &jitter); |
1757 status = gst_base_sink_wait_clock (basesink, rstart, &jitter); |
2403 |
1758 |
2404 GST_DEBUG_OBJECT (basesink, "clock returned %d", status); |
1759 GST_DEBUG_OBJECT (basesink, "clock returned %d", status); |
2405 |
1760 |
2406 /* invalid time, no clock or sync disabled, just render */ |
1761 /* invalid time, no clock or sync disabled, just render */ |
2407 if (status == GST_CLOCK_BADTIME) |
1762 if (status == GST_CLOCK_BADTIME) |
2413 |
1768 |
2414 /* check for unlocked by a state change, we are not flushing so |
1769 /* check for unlocked by a state change, we are not flushing so |
2415 * we can try to preroll on the current buffer. */ |
1770 * we can try to preroll on the current buffer. */ |
2416 if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) { |
1771 if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) { |
2417 GST_DEBUG_OBJECT (basesink, "unscheduled, waiting some more"); |
1772 GST_DEBUG_OBJECT (basesink, "unscheduled, waiting some more"); |
2418 priv->call_preroll = TRUE; |
|
2419 goto again; |
1773 goto again; |
2420 } |
1774 } |
2421 |
1775 |
2422 /* successful syncing done, record observation */ |
1776 /* successful syncing done, record observation */ |
2423 priv->current_jitter = jitter; |
1777 priv->current_jitter = jitter; |
2428 |
1782 |
2429 done: |
1783 done: |
2430 return GST_FLOW_OK; |
1784 return GST_FLOW_OK; |
2431 |
1785 |
2432 /* ERRORS */ |
1786 /* ERRORS */ |
2433 step_skipped: |
|
2434 { |
|
2435 GST_DEBUG_OBJECT (basesink, "skipped stepped object %p", obj); |
|
2436 *late = TRUE; |
|
2437 return GST_FLOW_OK; |
|
2438 } |
|
2439 not_syncable: |
1787 not_syncable: |
2440 { |
1788 { |
2441 GST_DEBUG_OBJECT (basesink, "non syncable object %p", obj); |
1789 GST_DEBUG_OBJECT (basesink, "non syncable object %p", obj); |
2442 return GST_FLOW_OK; |
1790 return GST_FLOW_OK; |
2443 } |
1791 } |
2444 flushing: |
1792 flushing: |
2445 { |
1793 { |
2446 GST_DEBUG_OBJECT (basesink, "we are flushing"); |
1794 GST_DEBUG_OBJECT (basesink, "we are flushing"); |
2447 return GST_FLOW_WRONG_STATE; |
1795 return GST_FLOW_WRONG_STATE; |
2448 } |
1796 } |
2449 preroll_failed: |
1797 stopping: |
2450 { |
1798 { |
2451 GST_DEBUG_OBJECT (basesink, "preroll failed"); |
1799 GST_DEBUG_OBJECT (basesink, "stopping while commiting state"); |
2452 *step_end = FALSE; |
1800 return GST_FLOW_WRONG_STATE; |
2453 return ret; |
|
2454 } |
1801 } |
2455 } |
1802 } |
2456 |
1803 |
2457 static gboolean |
1804 static gboolean |
2458 gst_base_sink_send_qos (GstBaseSink * basesink, |
1805 gst_base_sink_send_qos (GstBaseSink * basesink, |
2486 |
1833 |
2487 priv = sink->priv; |
1834 priv = sink->priv; |
2488 |
1835 |
2489 start = priv->current_rstart; |
1836 start = priv->current_rstart; |
2490 |
1837 |
2491 if (priv->current_step.valid) |
|
2492 return; |
|
2493 |
|
2494 /* if Quality-of-Service disabled, do nothing */ |
1838 /* if Quality-of-Service disabled, do nothing */ |
2495 if (!g_atomic_int_get (&priv->qos_enabled) || start == -1) |
1839 if (!g_atomic_int_get (&priv->qos_enabled) || start == -1) |
2496 return; |
1840 return; |
2497 |
1841 |
2498 stop = priv->current_rstop; |
1842 stop = priv->current_rstop; |
2499 jitter = priv->current_jitter; |
1843 jitter = priv->current_jitter; |
2500 |
1844 |
2501 if (jitter < 0) { |
1845 /* this is the time the buffer entered the sink */ |
2502 /* this is the time the buffer entered the sink */ |
1846 entered = start + jitter; |
2503 if (start < -jitter) |
1847 /* this is the time the buffer left the sink */ |
2504 entered = 0; |
1848 left = start + (jitter < 0 ? 0 : jitter); |
2505 else |
|
2506 entered = start + jitter; |
|
2507 left = start; |
|
2508 } else { |
|
2509 /* this is the time the buffer entered the sink */ |
|
2510 entered = start + jitter; |
|
2511 /* this is the time the buffer left the sink */ |
|
2512 left = start + jitter; |
|
2513 } |
|
2514 |
1849 |
2515 /* calculate duration of the buffer */ |
1850 /* calculate duration of the buffer */ |
2516 if (stop != -1) |
1851 if (stop != -1) |
2517 duration = stop - start; |
1852 duration = stop - start; |
2518 else |
1853 else |
2576 "updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT |
1911 "updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT |
2577 ", avg_rate: %g", GST_TIME_ARGS (priv->avg_duration), |
1912 ", avg_rate: %g", GST_TIME_ARGS (priv->avg_duration), |
2578 GST_TIME_ARGS (priv->avg_pt), priv->avg_rate); |
1913 GST_TIME_ARGS (priv->avg_pt), priv->avg_rate); |
2579 |
1914 |
2580 |
1915 |
1916 /* if we have a valid rate, start sending QoS messages */ |
|
2581 if (priv->avg_rate >= 0.0) { |
1917 if (priv->avg_rate >= 0.0) { |
2582 /* if we have a valid rate, start sending QoS messages */ |
|
2583 if (priv->current_jitter < 0) { |
|
2584 /* make sure we never go below 0 when adding the jitter to the |
|
2585 * timestamp. */ |
|
2586 if (priv->current_rstart < -priv->current_jitter) |
|
2587 priv->current_jitter = -priv->current_rstart; |
|
2588 } |
|
2589 gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart, |
1918 gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart, |
2590 priv->current_jitter); |
1919 priv->current_jitter); |
2591 } |
1920 } |
2592 |
1921 |
2593 /* record when this buffer will leave us */ |
1922 /* record when this buffer will leave us */ |
2659 else |
1988 else |
2660 max_lateness += start; |
1989 max_lateness += start; |
2661 |
1990 |
2662 /* if the jitter bigger than duration and lateness we are too late */ |
1991 /* if the jitter bigger than duration and lateness we are too late */ |
2663 if ((late = start + jitter > max_lateness)) { |
1992 if ((late = start + jitter > max_lateness)) { |
2664 GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink, |
1993 GST_DEBUG_OBJECT (basesink, "buffer is too late %" GST_TIME_FORMAT |
2665 "buffer is too late %" GST_TIME_FORMAT |
|
2666 " > %" GST_TIME_FORMAT, GST_TIME_ARGS (start + jitter), |
1994 " > %" GST_TIME_FORMAT, GST_TIME_ARGS (start + jitter), |
2667 GST_TIME_ARGS (max_lateness)); |
1995 GST_TIME_ARGS (max_lateness)); |
2668 /* !!emergency!!, if we did not receive anything valid for more than a |
1996 /* !!emergency!!, if we did not receive anything valid for more than a |
2669 * second, render it anyway so the user sees something */ |
1997 * second, render it anyway so the user sees something */ |
2670 if (priv->last_in_time != -1 && start - priv->last_in_time > GST_SECOND) { |
1998 if (priv->last_in_time && start - priv->last_in_time > GST_SECOND) { |
2671 late = FALSE; |
1999 late = FALSE; |
2672 GST_ELEMENT_WARNING (basesink, CORE, CLOCK, |
2000 GST_DEBUG_OBJECT (basesink, |
2673 (_("A lot of buffers are being dropped.")), |
|
2674 ("There may be a timestamping problem, or this computer is too slow.")); |
|
2675 GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink, |
|
2676 "**emergency** last buffer at %" GST_TIME_FORMAT " > GST_SECOND", |
2001 "**emergency** last buffer at %" GST_TIME_FORMAT " > GST_SECOND", |
2677 GST_TIME_ARGS (priv->last_in_time)); |
2002 GST_TIME_ARGS (priv->last_in_time)); |
2678 } |
2003 } |
2679 } |
2004 } |
2680 |
2005 |
2705 GST_DEBUG_OBJECT (basesink, "buffer has no timestamp"); |
2030 GST_DEBUG_OBJECT (basesink, "buffer has no timestamp"); |
2706 return FALSE; |
2031 return FALSE; |
2707 } |
2032 } |
2708 } |
2033 } |
2709 |
2034 |
2710 /* called before and after calling the render vmethod. It keeps track of how |
|
2711 * much time was spent in the render method and is used to check if we are |
|
2712 * flooded */ |
|
2713 static void |
2035 static void |
2714 gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start) |
2036 gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start) |
2715 { |
2037 { |
2716 GstBaseSinkPrivate *priv; |
2038 GstBaseSinkPrivate *priv; |
2717 |
2039 |
2742 * |
2064 * |
2743 * takes ownership of obj. |
2065 * takes ownership of obj. |
2744 */ |
2066 */ |
2745 static GstFlowReturn |
2067 static GstFlowReturn |
2746 gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad, |
2068 gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad, |
2747 gboolean is_list, gpointer obj) |
2069 GstMiniObject * obj) |
2748 { |
2070 { |
2749 GstFlowReturn ret; |
2071 GstFlowReturn ret = GST_FLOW_OK; |
2750 GstBaseSinkClass *bclass; |
2072 GstBaseSinkClass *bclass; |
2751 gboolean late, step_end; |
2073 gboolean late = FALSE; |
2752 gpointer sync_obj; |
|
2753 |
|
2754 GstBaseSinkPrivate *priv; |
2074 GstBaseSinkPrivate *priv; |
2755 |
2075 |
2756 priv = basesink->priv; |
2076 priv = basesink->priv; |
2757 |
|
2758 if (is_list) { |
|
2759 /* |
|
2760 * If buffer list, use the first group buffer within the list |
|
2761 * for syncing |
|
2762 */ |
|
2763 sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); |
|
2764 g_assert (NULL != sync_obj); |
|
2765 } else { |
|
2766 sync_obj = obj; |
|
2767 } |
|
2768 |
|
2769 again: |
|
2770 late = FALSE; |
|
2771 step_end = FALSE; |
|
2772 ret = GST_FLOW_OK; |
|
2773 |
2077 |
2774 /* synchronize this object, non syncable objects return OK |
2078 /* synchronize this object, non syncable objects return OK |
2775 * immediatly. */ |
2079 * immediatly. */ |
2776 ret = gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end); |
2080 ret = gst_base_sink_do_sync (basesink, pad, obj, &late); |
2777 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
2081 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
2778 goto sync_failed; |
2082 goto sync_failed; |
2779 |
2083 |
2780 /* and now render, event or buffer/buffer list. */ |
2084 /* and now render, event or buffer. */ |
2781 if (G_LIKELY (is_list || GST_IS_BUFFER (obj))) { |
2085 if (G_LIKELY (GST_IS_BUFFER (obj))) { |
2086 GstBuffer *buf; |
|
2087 |
|
2782 /* drop late buffers unconditionally, let's hope it's unlikely */ |
2088 /* drop late buffers unconditionally, let's hope it's unlikely */ |
2783 if (G_UNLIKELY (late)) |
2089 if (G_UNLIKELY (late)) |
2784 goto dropped; |
2090 goto dropped; |
2785 |
2091 |
2092 buf = GST_BUFFER_CAST (obj); |
|
2093 |
|
2094 gst_base_sink_set_last_buffer (basesink, buf); |
|
2095 |
|
2786 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
2096 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
2787 |
2097 |
2788 if (G_LIKELY ((is_list && bclass->render_list) || |
2098 if (G_LIKELY (bclass->render)) { |
2789 (!is_list && bclass->render))) { |
|
2790 gint do_qos; |
2099 gint do_qos; |
2791 |
2100 |
2792 /* read once, to get same value before and after */ |
2101 /* read once, to get same value before and after */ |
2793 do_qos = g_atomic_int_get (&priv->qos_enabled); |
2102 do_qos = g_atomic_int_get (&priv->qos_enabled); |
2794 |
2103 |
2795 GST_DEBUG_OBJECT (basesink, "rendering object %p", obj); |
2104 GST_DEBUG_OBJECT (basesink, "rendering buffer %p", obj); |
2796 |
2105 |
2797 /* record rendering time for QoS and stats */ |
2106 /* record rendering time for QoS and stats */ |
2798 if (do_qos) |
2107 if (do_qos) |
2799 gst_base_sink_do_render_stats (basesink, TRUE); |
2108 gst_base_sink_do_render_stats (basesink, TRUE); |
2800 |
2109 |
2801 if (!is_list) { |
2110 ret = bclass->render (basesink, buf); |
2802 GstBuffer *buf; |
2111 |
2803 |
2112 priv->rendered++; |
2804 /* For buffer lists do not set last buffer. Creating buffer |
|
2805 * with meaningful data can be done only with memcpy which will |
|
2806 * significantly affect performance */ |
|
2807 buf = GST_BUFFER_CAST (obj); |
|
2808 gst_base_sink_set_last_buffer (basesink, buf); |
|
2809 |
|
2810 ret = bclass->render (basesink, buf); |
|
2811 } else { |
|
2812 GstBufferList *buflist; |
|
2813 |
|
2814 buflist = GST_BUFFER_LIST_CAST (obj); |
|
2815 |
|
2816 ret = bclass->render_list (basesink, buflist); |
|
2817 } |
|
2818 |
2113 |
2819 if (do_qos) |
2114 if (do_qos) |
2820 gst_base_sink_do_render_stats (basesink, FALSE); |
2115 gst_base_sink_do_render_stats (basesink, FALSE); |
2821 |
|
2822 if (ret == GST_FLOW_STEP) |
|
2823 goto again; |
|
2824 |
|
2825 if (G_UNLIKELY (basesink->flushing)) |
|
2826 goto flushing; |
|
2827 |
|
2828 priv->rendered++; |
|
2829 } |
2116 } |
2830 } else { |
2117 } else { |
2831 GstEvent *event = GST_EVENT_CAST (obj); |
2118 GstEvent *event = GST_EVENT_CAST (obj); |
2832 gboolean event_res = TRUE; |
2119 gboolean event_res = TRUE; |
2833 GstEventType type; |
2120 GstEventType type; |
2840 gst_event_type_get_name (type)); |
2127 gst_event_type_get_name (type)); |
2841 |
2128 |
2842 if (bclass->event) |
2129 if (bclass->event) |
2843 event_res = bclass->event (basesink, event); |
2130 event_res = bclass->event (basesink, event); |
2844 |
2131 |
2845 /* when we get here we could be flushing again when the event handler calls |
|
2846 * _wait_eos(). We have to ignore this object in that case. */ |
|
2847 if (G_UNLIKELY (basesink->flushing)) |
|
2848 goto flushing; |
|
2849 |
|
2850 if (G_LIKELY (event_res)) { |
2132 if (G_LIKELY (event_res)) { |
2851 guint32 seqnum; |
|
2852 |
|
2853 seqnum = basesink->priv->seqnum = gst_event_get_seqnum (event); |
|
2854 GST_DEBUG_OBJECT (basesink, "Got seqnum #%" G_GUINT32_FORMAT, seqnum); |
|
2855 |
|
2856 switch (type) { |
2133 switch (type) { |
2857 case GST_EVENT_EOS: |
2134 case GST_EVENT_EOS: |
2858 { |
|
2859 GstMessage *message; |
|
2860 |
|
2861 /* the EOS event is completely handled so we mark |
2135 /* the EOS event is completely handled so we mark |
2862 * ourselves as being in the EOS state. eos is also |
2136 * ourselves as being in the EOS state. eos is also |
2863 * protected by the object lock so we can read it when |
2137 * protected by the object lock so we can read it when |
2864 * answering the POSITION query. */ |
2138 * answering the POSITION query. */ |
2865 GST_OBJECT_LOCK (basesink); |
2139 GST_OBJECT_LOCK (basesink); |
2866 basesink->eos = TRUE; |
2140 basesink->eos = TRUE; |
2867 GST_OBJECT_UNLOCK (basesink); |
2141 GST_OBJECT_UNLOCK (basesink); |
2868 |
|
2869 /* ok, now we can post the message */ |
2142 /* ok, now we can post the message */ |
2870 GST_DEBUG_OBJECT (basesink, "Now posting EOS"); |
2143 GST_DEBUG_OBJECT (basesink, "Now posting EOS"); |
2871 |
2144 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
2872 message = gst_message_new_eos (GST_OBJECT_CAST (basesink)); |
2145 gst_message_new_eos (GST_OBJECT_CAST (basesink))); |
2873 gst_message_set_seqnum (message, seqnum); |
|
2874 gst_element_post_message (GST_ELEMENT_CAST (basesink), message); |
|
2875 break; |
2146 break; |
2876 } |
|
2877 case GST_EVENT_NEWSEGMENT: |
2147 case GST_EVENT_NEWSEGMENT: |
2878 /* configure the segment */ |
2148 /* configure the segment */ |
2879 gst_base_sink_configure_segment (basesink, pad, event, |
2149 gst_base_sink_configure_segment (basesink, pad, event, |
2880 &basesink->segment); |
2150 &basesink->segment); |
2881 break; |
2151 break; |
2884 } |
2154 } |
2885 } |
2155 } |
2886 } |
2156 } |
2887 |
2157 |
2888 done: |
2158 done: |
2889 if (step_end) { |
|
2890 /* the step ended, check if we need to activate a new step */ |
|
2891 GST_DEBUG_OBJECT (basesink, "step ended"); |
|
2892 stop_stepping (basesink, &basesink->segment, &priv->current_step, |
|
2893 priv->current_rstart, priv->current_rstop, basesink->eos); |
|
2894 goto again; |
|
2895 } |
|
2896 |
|
2897 gst_base_sink_perform_qos (basesink, late); |
2159 gst_base_sink_perform_qos (basesink, late); |
2898 |
2160 |
2899 GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj); |
2161 GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj); |
2900 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2162 gst_mini_object_unref (obj); |
2163 |
|
2901 return ret; |
2164 return ret; |
2902 |
2165 |
2903 /* ERRORS */ |
2166 /* ERRORS */ |
2904 sync_failed: |
2167 sync_failed: |
2905 { |
2168 { |
2910 { |
2173 { |
2911 priv->dropped++; |
2174 priv->dropped++; |
2912 GST_DEBUG_OBJECT (basesink, "buffer late, dropping"); |
2175 GST_DEBUG_OBJECT (basesink, "buffer late, dropping"); |
2913 goto done; |
2176 goto done; |
2914 } |
2177 } |
2915 flushing: |
|
2916 { |
|
2917 GST_DEBUG_OBJECT (basesink, "we are flushing, ignore object"); |
|
2918 gst_mini_object_unref (obj); |
|
2919 return GST_FLOW_WRONG_STATE; |
|
2920 } |
|
2921 } |
2178 } |
2922 |
2179 |
2923 /* with STREAM_LOCK, PREROLL_LOCK |
2180 /* with STREAM_LOCK, PREROLL_LOCK |
2924 * |
2181 * |
2925 * Perform preroll on the given object. For buffers this means |
2182 * Perform preroll on the given object. For buffers this means |
2927 * If that succeeds, the state will be commited. |
2184 * If that succeeds, the state will be commited. |
2928 * |
2185 * |
2929 * function does not take ownership of obj. |
2186 * function does not take ownership of obj. |
2930 */ |
2187 */ |
2931 static GstFlowReturn |
2188 static GstFlowReturn |
2932 gst_base_sink_preroll_object (GstBaseSink * basesink, gboolean is_list, |
2189 gst_base_sink_preroll_object (GstBaseSink * basesink, GstPad * pad, |
2933 GstMiniObject * obj) |
2190 GstMiniObject * obj) |
2934 { |
2191 { |
2935 GstFlowReturn ret; |
2192 GstFlowReturn ret; |
2936 |
2193 |
2937 GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj); |
2194 GST_DEBUG_OBJECT (basesink, "do preroll %p", obj); |
2938 |
2195 |
2939 /* if it's a buffer, we need to call the preroll method */ |
2196 /* if it's a buffer, we need to call the preroll method */ |
2940 if (G_LIKELY (is_list || GST_IS_BUFFER (obj)) && basesink->priv->call_preroll) { |
2197 if (G_LIKELY (GST_IS_BUFFER (obj))) { |
2941 GstBaseSinkClass *bclass; |
2198 GstBaseSinkClass *bclass; |
2942 GstBuffer *buf; |
2199 GstBuffer *buf; |
2943 GstClockTime timestamp; |
2200 GstClockTime timestamp; |
2944 |
2201 |
2945 if (is_list) { |
2202 buf = GST_BUFFER_CAST (obj); |
2946 buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); |
|
2947 g_assert (NULL != buf); |
|
2948 } else { |
|
2949 buf = GST_BUFFER_CAST (obj); |
|
2950 } |
|
2951 |
|
2952 timestamp = GST_BUFFER_TIMESTAMP (buf); |
2203 timestamp = GST_BUFFER_TIMESTAMP (buf); |
2953 |
2204 |
2954 GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT, |
2205 GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT, |
2955 GST_TIME_ARGS (timestamp)); |
2206 GST_TIME_ARGS (timestamp)); |
2956 |
2207 |
2957 /* |
2208 gst_base_sink_set_last_buffer (basesink, buf); |
2958 * For buffer lists do not set last buffer. Creating buffer |
|
2959 * with meaningful data can be done only with memcpy which will |
|
2960 * significantly affect performance |
|
2961 */ |
|
2962 if (!is_list) { |
|
2963 gst_base_sink_set_last_buffer (basesink, buf); |
|
2964 } |
|
2965 |
2209 |
2966 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
2210 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
2967 if (bclass->preroll) |
2211 if (bclass->preroll) |
2968 if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK) |
2212 if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK) |
2969 goto preroll_failed; |
2213 goto preroll_failed; |
2970 |
|
2971 basesink->priv->call_preroll = FALSE; |
|
2972 } |
2214 } |
2973 |
2215 |
2974 /* commit state */ |
2216 /* commit state */ |
2975 if (G_LIKELY (basesink->playing_async)) { |
2217 if (G_LIKELY (basesink->playing_async)) { |
2976 if (G_UNLIKELY (!gst_base_sink_commit_state (basesink))) |
2218 if (G_UNLIKELY (!gst_base_sink_commit_state (basesink))) |
3001 * |
2243 * |
3002 * This function takes ownership of the object. |
2244 * This function takes ownership of the object. |
3003 */ |
2245 */ |
3004 static GstFlowReturn |
2246 static GstFlowReturn |
3005 gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad, |
2247 gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad, |
3006 gboolean is_list, gpointer obj, gboolean prerollable) |
2248 GstMiniObject * obj, gboolean prerollable) |
3007 { |
2249 { |
3008 GstFlowReturn ret = GST_FLOW_OK; |
2250 GstFlowReturn ret = GST_FLOW_OK; |
3009 gint length; |
2251 gint length; |
3010 GQueue *q; |
2252 GQueue *q; |
3011 |
2253 |
3017 |
2259 |
3018 GST_DEBUG_OBJECT (basesink, "now %d prerolled items", length); |
2260 GST_DEBUG_OBJECT (basesink, "now %d prerolled items", length); |
3019 |
2261 |
3020 /* first prerollable item needs to finish the preroll */ |
2262 /* first prerollable item needs to finish the preroll */ |
3021 if (length == 1) { |
2263 if (length == 1) { |
3022 ret = gst_base_sink_preroll_object (basesink, is_list, obj); |
2264 ret = gst_base_sink_preroll_object (basesink, pad, obj); |
3023 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
2265 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
3024 goto preroll_failed; |
2266 goto preroll_failed; |
3025 } |
2267 } |
3026 /* need to recheck if we need preroll, commmit state during preroll |
2268 /* need to recheck if we need preroll, commmit state during preroll |
3027 * could have made us not need more preroll. */ |
2269 * could have made us not need more preroll. */ |
3030 * queue. */ |
2272 * queue. */ |
3031 if (G_UNLIKELY (length <= basesink->preroll_queue_max_len)) |
2273 if (G_UNLIKELY (length <= basesink->preroll_queue_max_len)) |
3032 goto more_preroll; |
2274 goto more_preroll; |
3033 } |
2275 } |
3034 } |
2276 } |
2277 |
|
3035 /* we can start rendering (or blocking) the queued object |
2278 /* we can start rendering (or blocking) the queued object |
3036 * if any. */ |
2279 * if any. */ |
3037 q = basesink->preroll_queue; |
2280 q = basesink->preroll_queue; |
3038 while (G_UNLIKELY (!g_queue_is_empty (q))) { |
2281 while (G_UNLIKELY (!g_queue_is_empty (q))) { |
3039 GstMiniObject *o; |
2282 GstMiniObject *o; |
3040 |
2283 |
3041 o = g_queue_pop_head (q); |
2284 o = g_queue_pop_head (q); |
3042 GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o); |
2285 GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o); |
3043 |
2286 |
3044 /* do something with the return value */ |
2287 /* do something with the return value */ |
3045 ret = gst_base_sink_render_object (basesink, pad, FALSE, o); |
2288 ret = gst_base_sink_render_object (basesink, pad, o); |
3046 if (ret != GST_FLOW_OK) |
2289 if (ret != GST_FLOW_OK) |
3047 goto dequeue_failed; |
2290 goto dequeue_failed; |
3048 } |
2291 } |
3049 |
2292 |
3050 /* now render the object */ |
2293 /* now render the object */ |
3051 ret = gst_base_sink_render_object (basesink, pad, is_list, obj); |
2294 ret = gst_base_sink_render_object (basesink, pad, obj); |
3052 basesink->preroll_queued = 0; |
2295 basesink->preroll_queued = 0; |
3053 |
2296 |
3054 return ret; |
2297 return ret; |
3055 |
2298 |
3056 /* special cases */ |
2299 /* special cases */ |
3057 preroll_failed: |
2300 preroll_failed: |
3058 { |
2301 { |
3059 GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s", |
2302 GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s", |
3060 gst_flow_get_name (ret)); |
2303 gst_flow_get_name (ret)); |
3061 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2304 gst_mini_object_unref (obj); |
3062 return ret; |
2305 return ret; |
3063 } |
2306 } |
3064 more_preroll: |
2307 more_preroll: |
3065 { |
2308 { |
3066 /* add object to the queue and return */ |
2309 /* add object to the queue and return */ |
3071 } |
2314 } |
3072 dequeue_failed: |
2315 dequeue_failed: |
3073 { |
2316 { |
3074 GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s", |
2317 GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s", |
3075 gst_flow_get_name (ret)); |
2318 gst_flow_get_name (ret)); |
3076 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2319 gst_mini_object_unref (obj); |
3077 return ret; |
2320 return ret; |
3078 } |
2321 } |
3079 } |
2322 } |
3080 |
2323 |
3081 /* with STREAM_LOCK |
2324 /* with STREAM_LOCK |
3096 goto flushing; |
2339 goto flushing; |
3097 |
2340 |
3098 if (G_UNLIKELY (basesink->priv->received_eos)) |
2341 if (G_UNLIKELY (basesink->priv->received_eos)) |
3099 goto was_eos; |
2342 goto was_eos; |
3100 |
2343 |
3101 ret = |
2344 ret = gst_base_sink_queue_object_unlocked (basesink, pad, obj, prerollable); |
3102 gst_base_sink_queue_object_unlocked (basesink, pad, FALSE, obj, |
|
3103 prerollable); |
|
3104 GST_PAD_PREROLL_UNLOCK (pad); |
2345 GST_PAD_PREROLL_UNLOCK (pad); |
3105 |
2346 |
3106 return ret; |
2347 return ret; |
3107 |
2348 |
3108 /* ERRORS */ |
2349 /* ERRORS */ |
3119 "we are EOS, dropping object, return UNEXPECTED"); |
2360 "we are EOS, dropping object, return UNEXPECTED"); |
3120 GST_PAD_PREROLL_UNLOCK (pad); |
2361 GST_PAD_PREROLL_UNLOCK (pad); |
3121 gst_mini_object_unref (obj); |
2362 gst_mini_object_unref (obj); |
3122 return GST_FLOW_UNEXPECTED; |
2363 return GST_FLOW_UNEXPECTED; |
3123 } |
2364 } |
3124 } |
|
3125 |
|
3126 static void |
|
3127 gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad) |
|
3128 { |
|
3129 /* make sure we are not blocked on the clock also clear any pending |
|
3130 * eos state. */ |
|
3131 gst_base_sink_set_flushing (basesink, pad, TRUE); |
|
3132 |
|
3133 /* we grab the stream lock but that is not needed since setting the |
|
3134 * sink to flushing would make sure no state commit is being done |
|
3135 * anymore */ |
|
3136 GST_PAD_STREAM_LOCK (pad); |
|
3137 gst_base_sink_reset_qos (basesink); |
|
3138 if (basesink->priv->async_enabled) { |
|
3139 /* and we need to commit our state again on the next |
|
3140 * prerolled buffer */ |
|
3141 basesink->playing_async = TRUE; |
|
3142 gst_element_lost_state (GST_ELEMENT_CAST (basesink)); |
|
3143 } else { |
|
3144 basesink->priv->have_latency = TRUE; |
|
3145 basesink->need_preroll = FALSE; |
|
3146 } |
|
3147 gst_base_sink_set_last_buffer (basesink, NULL); |
|
3148 GST_PAD_STREAM_UNLOCK (pad); |
|
3149 } |
|
3150 |
|
3151 static void |
|
3152 gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad) |
|
3153 { |
|
3154 /* unset flushing so we can accept new data, this also flushes out any EOS |
|
3155 * event. */ |
|
3156 gst_base_sink_set_flushing (basesink, pad, FALSE); |
|
3157 |
|
3158 /* for position reporting */ |
|
3159 GST_OBJECT_LOCK (basesink); |
|
3160 basesink->priv->current_sstart = -1; |
|
3161 basesink->priv->current_sstop = -1; |
|
3162 basesink->priv->eos_rtime = -1; |
|
3163 basesink->priv->call_preroll = TRUE; |
|
3164 basesink->priv->current_step.valid = FALSE; |
|
3165 basesink->priv->pending_step.valid = FALSE; |
|
3166 if (basesink->pad_mode == GST_ACTIVATE_PUSH) { |
|
3167 /* we need new segment info after the flush. */ |
|
3168 basesink->have_newsegment = FALSE; |
|
3169 gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); |
|
3170 gst_segment_init (basesink->abidata.ABI.clip_segment, GST_FORMAT_UNDEFINED); |
|
3171 } |
|
3172 GST_OBJECT_UNLOCK (basesink); |
|
3173 } |
2365 } |
3174 |
2366 |
3175 static gboolean |
2367 static gboolean |
3176 gst_base_sink_event (GstPad * pad, GstEvent * event) |
2368 gst_base_sink_event (GstPad * pad, GstEvent * event) |
3177 { |
2369 { |
3199 /* we can't accept anything when we are EOS */ |
2391 /* we can't accept anything when we are EOS */ |
3200 result = FALSE; |
2392 result = FALSE; |
3201 gst_event_unref (event); |
2393 gst_event_unref (event); |
3202 } else { |
2394 } else { |
3203 /* we set the received EOS flag here so that we can use it when testing if |
2395 /* we set the received EOS flag here so that we can use it when testing if |
3204 * we are prerolled and to refuse more buffers. */ |
2396 * we are prerolled and to refure more buffers. */ |
3205 basesink->priv->received_eos = TRUE; |
2397 basesink->priv->received_eos = TRUE; |
3206 |
2398 |
3207 /* EOS is a prerollable object, we call the unlocked version because it |
2399 /* EOS is a prerollable object, we call the unlocked version because it |
3208 * does not check the received_eos flag. */ |
2400 * does not check the received_eos flag. */ |
3209 ret = gst_base_sink_queue_object_unlocked (basesink, pad, |
2401 ret = gst_base_sink_queue_object_unlocked (basesink, pad, |
3210 FALSE, GST_MINI_OBJECT_CAST (event), TRUE); |
2402 GST_MINI_OBJECT_CAST (event), TRUE); |
3211 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
2403 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
3212 result = FALSE; |
2404 result = FALSE; |
3213 } |
2405 } |
3214 GST_PAD_PREROLL_UNLOCK (pad); |
2406 GST_PAD_PREROLL_UNLOCK (pad); |
3215 break; |
2407 break; |
3235 gst_base_sink_configure_segment (basesink, pad, event, |
2427 gst_base_sink_configure_segment (basesink, pad, event, |
3236 basesink->abidata.ABI.clip_segment); |
2428 basesink->abidata.ABI.clip_segment); |
3237 |
2429 |
3238 ret = |
2430 ret = |
3239 gst_base_sink_queue_object_unlocked (basesink, pad, |
2431 gst_base_sink_queue_object_unlocked (basesink, pad, |
3240 FALSE, GST_MINI_OBJECT_CAST (event), FALSE); |
2432 GST_MINI_OBJECT_CAST (event), FALSE); |
3241 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
2433 if (G_UNLIKELY (ret != GST_FLOW_OK)) |
3242 result = FALSE; |
2434 result = FALSE; |
3243 else { |
2435 else |
3244 GST_OBJECT_LOCK (basesink); |
|
3245 basesink->have_newsegment = TRUE; |
2436 basesink->have_newsegment = TRUE; |
3246 GST_OBJECT_UNLOCK (basesink); |
|
3247 } |
|
3248 } |
2437 } |
3249 GST_PAD_PREROLL_UNLOCK (pad); |
2438 GST_PAD_PREROLL_UNLOCK (pad); |
3250 break; |
2439 break; |
3251 } |
2440 } |
3252 case GST_EVENT_FLUSH_START: |
2441 case GST_EVENT_FLUSH_START: |
3253 if (bclass->event) |
2442 if (bclass->event) |
3254 bclass->event (basesink, event); |
2443 bclass->event (basesink, event); |
3255 |
2444 |
3256 GST_DEBUG_OBJECT (basesink, "flush-start %p", event); |
2445 GST_DEBUG_OBJECT (basesink, "flush-start %p", event); |
3257 |
2446 |
3258 gst_base_sink_flush_start (basesink, pad); |
2447 /* make sure we are not blocked on the clock also clear any pending |
2448 * eos state. */ |
|
2449 gst_base_sink_set_flushing (basesink, pad, TRUE); |
|
2450 |
|
2451 /* we grab the stream lock but that is not needed since setting the |
|
2452 * sink to flushing would make sure no state commit is being done |
|
2453 * anymore */ |
|
2454 GST_PAD_STREAM_LOCK (pad); |
|
2455 gst_base_sink_reset_qos (basesink); |
|
2456 if (basesink->priv->async_enabled) { |
|
2457 /* and we need to commit our state again on the next |
|
2458 * prerolled buffer */ |
|
2459 basesink->playing_async = TRUE; |
|
2460 gst_element_lost_state (GST_ELEMENT_CAST (basesink)); |
|
2461 } else { |
|
2462 basesink->priv->have_latency = TRUE; |
|
2463 basesink->need_preroll = FALSE; |
|
2464 } |
|
2465 gst_base_sink_set_last_buffer (basesink, NULL); |
|
2466 GST_PAD_STREAM_UNLOCK (pad); |
|
3259 |
2467 |
3260 gst_event_unref (event); |
2468 gst_event_unref (event); |
3261 break; |
2469 break; |
3262 case GST_EVENT_FLUSH_STOP: |
2470 case GST_EVENT_FLUSH_STOP: |
3263 if (bclass->event) |
2471 if (bclass->event) |
3264 bclass->event (basesink, event); |
2472 bclass->event (basesink, event); |
3265 |
2473 |
3266 GST_DEBUG_OBJECT (basesink, "flush-stop %p", event); |
2474 GST_DEBUG_OBJECT (basesink, "flush-stop %p", event); |
3267 |
2475 |
3268 gst_base_sink_flush_stop (basesink, pad); |
2476 /* unset flushing so we can accept new data, this also flushes out any EOS |
2477 * event. */ |
|
2478 gst_base_sink_set_flushing (basesink, pad, FALSE); |
|
2479 |
|
2480 /* we need new segment info after the flush. */ |
|
2481 gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); |
|
2482 gst_segment_init (basesink->abidata.ABI.clip_segment, |
|
2483 GST_FORMAT_UNDEFINED); |
|
2484 basesink->have_newsegment = FALSE; |
|
2485 |
|
2486 /* for position reporting */ |
|
2487 GST_OBJECT_LOCK (basesink); |
|
2488 basesink->priv->current_sstart = -1; |
|
2489 basesink->priv->current_sstop = -1; |
|
2490 GST_OBJECT_UNLOCK (basesink); |
|
3269 |
2491 |
3270 gst_event_unref (event); |
2492 gst_event_unref (event); |
3271 break; |
2493 break; |
3272 default: |
2494 default: |
3273 /* other events are sent to queue or subclass depending on if they |
2495 /* other events are sent to queue or subclass depending on if they |
3328 /* we have 2 cases where the PREROLL_LOCK is released: |
2550 /* we have 2 cases where the PREROLL_LOCK is released: |
3329 * 1) we are blocking in the PREROLL_LOCK and thus are prerolled. |
2551 * 1) we are blocking in the PREROLL_LOCK and thus are prerolled. |
3330 * 2) we are syncing on the clock |
2552 * 2) we are syncing on the clock |
3331 */ |
2553 */ |
3332 is_prerolled = basesink->have_preroll || basesink->priv->received_eos; |
2554 is_prerolled = basesink->have_preroll || basesink->priv->received_eos; |
3333 res = !is_prerolled; |
2555 res = !is_prerolled && basesink->pad_mode != GST_ACTIVATE_PULL; |
3334 |
|
3335 GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d", |
2556 GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d", |
3336 basesink->have_preroll, basesink->priv->received_eos, res); |
2557 basesink->have_preroll, basesink->priv->received_eos, res); |
3337 |
2558 |
3338 return res; |
2559 return res; |
3339 } |
2560 } |
3346 * |
2567 * |
3347 * This function takes ownership of the buffer. |
2568 * This function takes ownership of the buffer. |
3348 */ |
2569 */ |
3349 static GstFlowReturn |
2570 static GstFlowReturn |
3350 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, |
2571 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, |
3351 gboolean is_list, gpointer obj) |
2572 GstBuffer * buf) |
3352 { |
2573 { |
3353 GstBaseSinkClass *bclass; |
|
3354 GstFlowReturn result; |
2574 GstFlowReturn result; |
3355 GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE; |
2575 GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE; |
3356 GstSegment *clip_segment; |
2576 GstSegment *clip_segment; |
3357 GstBuffer *time_buf; |
|
3358 |
2577 |
3359 if (G_UNLIKELY (basesink->flushing)) |
2578 if (G_UNLIKELY (basesink->flushing)) |
3360 goto flushing; |
2579 goto flushing; |
3361 |
2580 |
3362 if (G_UNLIKELY (basesink->priv->received_eos)) |
2581 if (G_UNLIKELY (basesink->priv->received_eos)) |
3363 goto was_eos; |
2582 goto was_eos; |
3364 |
|
3365 if (is_list) { |
|
3366 time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); |
|
3367 g_assert (NULL != time_buf); |
|
3368 } else { |
|
3369 time_buf = GST_BUFFER_CAST (obj); |
|
3370 } |
|
3371 |
2583 |
3372 /* for code clarity */ |
2584 /* for code clarity */ |
3373 clip_segment = basesink->abidata.ABI.clip_segment; |
2585 clip_segment = basesink->abidata.ABI.clip_segment; |
3374 |
2586 |
3375 if (G_UNLIKELY (!basesink->have_newsegment)) { |
2587 if (G_UNLIKELY (!basesink->have_newsegment)) { |
3380 GST_ELEMENT_WARNING (basesink, STREAM, FAILED, |
2592 GST_ELEMENT_WARNING (basesink, STREAM, FAILED, |
3381 (_("Internal data flow problem.")), |
2593 (_("Internal data flow problem.")), |
3382 ("Received buffer without a new-segment. Assuming timestamps start from 0.")); |
2594 ("Received buffer without a new-segment. Assuming timestamps start from 0.")); |
3383 } |
2595 } |
3384 |
2596 |
2597 basesink->have_newsegment = TRUE; |
|
3385 /* this means this sink will assume timestamps start from 0 */ |
2598 /* this means this sink will assume timestamps start from 0 */ |
3386 GST_OBJECT_LOCK (basesink); |
|
3387 clip_segment->start = 0; |
2599 clip_segment->start = 0; |
3388 clip_segment->stop = -1; |
2600 clip_segment->stop = -1; |
3389 basesink->segment.start = 0; |
2601 basesink->segment.start = 0; |
3390 basesink->segment.stop = -1; |
2602 basesink->segment.stop = -1; |
3391 basesink->have_newsegment = TRUE; |
2603 } |
3392 GST_OBJECT_UNLOCK (basesink); |
2604 |
3393 } |
2605 /* check if the buffer needs to be dropped */ |
3394 |
2606 /* we don't use the subclassed method as it may not return |
3395 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
2607 * valid values for our purpose here */ |
3396 |
2608 gst_base_sink_get_times (basesink, buf, &start, &end); |
3397 /* check if the buffer needs to be dropped, we first ask the subclass for the |
|
3398 * start and end */ |
|
3399 if (bclass->get_times) |
|
3400 bclass->get_times (basesink, time_buf, &start, &end); |
|
3401 |
|
3402 if (start == -1) { |
|
3403 /* if the subclass does not want sync, we use our own values so that we at |
|
3404 * least clip the buffer to the segment */ |
|
3405 gst_base_sink_get_times (basesink, time_buf, &start, &end); |
|
3406 } |
|
3407 |
2609 |
3408 GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT |
2610 GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT |
3409 ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); |
2611 ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); |
3410 |
2612 |
3411 /* a dropped buffer does not participate in anything */ |
2613 /* a dropped buffer does not participate in anything */ |
3417 } |
2619 } |
3418 |
2620 |
3419 /* now we can process the buffer in the queue, this function takes ownership |
2621 /* now we can process the buffer in the queue, this function takes ownership |
3420 * of the buffer */ |
2622 * of the buffer */ |
3421 result = gst_base_sink_queue_object_unlocked (basesink, pad, |
2623 result = gst_base_sink_queue_object_unlocked (basesink, pad, |
3422 is_list, obj, TRUE); |
2624 GST_MINI_OBJECT_CAST (buf), TRUE); |
2625 |
|
3423 return result; |
2626 return result; |
3424 |
2627 |
3425 /* ERRORS */ |
2628 /* ERRORS */ |
3426 flushing: |
2629 flushing: |
3427 { |
2630 { |
3428 GST_DEBUG_OBJECT (basesink, "sink is flushing"); |
2631 GST_DEBUG_OBJECT (basesink, "sink is flushing"); |
3429 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2632 gst_buffer_unref (buf); |
3430 return GST_FLOW_WRONG_STATE; |
2633 return GST_FLOW_WRONG_STATE; |
3431 } |
2634 } |
3432 was_eos: |
2635 was_eos: |
3433 { |
2636 { |
3434 GST_DEBUG_OBJECT (basesink, |
2637 GST_DEBUG_OBJECT (basesink, |
3435 "we are EOS, dropping object, return UNEXPECTED"); |
2638 "we are EOS, dropping object, return UNEXPECTED"); |
3436 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2639 gst_buffer_unref (buf); |
3437 return GST_FLOW_UNEXPECTED; |
2640 return GST_FLOW_UNEXPECTED; |
3438 } |
2641 } |
3439 out_of_segment: |
2642 out_of_segment: |
3440 { |
2643 { |
3441 GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment"); |
2644 GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment"); |
3442 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2645 gst_buffer_unref (buf); |
3443 return GST_FLOW_OK; |
2646 return GST_FLOW_OK; |
3444 } |
2647 } |
3445 } |
2648 } |
3446 |
2649 |
3447 /* with STREAM_LOCK |
2650 /* with STREAM_LOCK |
3448 */ |
2651 */ |
3449 static GstFlowReturn |
2652 static GstFlowReturn |
3450 gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, |
2653 gst_base_sink_chain (GstPad * pad, GstBuffer * buf) |
3451 gboolean is_list, gpointer obj) |
2654 { |
3452 { |
2655 GstBaseSink *basesink; |
3453 GstFlowReturn result; |
2656 GstFlowReturn result; |
2657 |
|
2658 basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); |
|
3454 |
2659 |
3455 if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) |
2660 if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) |
3456 goto wrong_mode; |
2661 goto wrong_mode; |
3457 |
2662 |
3458 GST_PAD_PREROLL_LOCK (pad); |
2663 GST_PAD_PREROLL_LOCK (pad); |
3459 result = gst_base_sink_chain_unlocked (basesink, pad, is_list, obj); |
2664 result = gst_base_sink_chain_unlocked (basesink, pad, buf); |
3460 GST_PAD_PREROLL_UNLOCK (pad); |
2665 GST_PAD_PREROLL_UNLOCK (pad); |
3461 |
2666 |
3462 done: |
2667 done: |
3463 return result; |
2668 return result; |
3464 |
2669 |
3468 GST_OBJECT_LOCK (pad); |
2673 GST_OBJECT_LOCK (pad); |
3469 GST_WARNING_OBJECT (basesink, |
2674 GST_WARNING_OBJECT (basesink, |
3470 "Push on pad %s:%s, but it was not activated in push mode", |
2675 "Push on pad %s:%s, but it was not activated in push mode", |
3471 GST_DEBUG_PAD_NAME (pad)); |
2676 GST_DEBUG_PAD_NAME (pad)); |
3472 GST_OBJECT_UNLOCK (pad); |
2677 GST_OBJECT_UNLOCK (pad); |
3473 gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); |
2678 gst_buffer_unref (buf); |
3474 /* we don't post an error message this will signal to the peer |
2679 /* we don't post an error message this will signal to the peer |
3475 * pushing that EOS is reached. */ |
2680 * pushing that EOS is reached. */ |
3476 result = GST_FLOW_UNEXPECTED; |
2681 result = GST_FLOW_UNEXPECTED; |
3477 goto done; |
2682 goto done; |
3478 } |
2683 } |
3479 } |
2684 } |
3480 |
2685 |
3481 static GstFlowReturn |
|
3482 gst_base_sink_chain (GstPad * pad, GstBuffer * buf) |
|
3483 { |
|
3484 GstBaseSink *basesink; |
|
3485 |
|
3486 basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); |
|
3487 |
|
3488 return gst_base_sink_chain_main (basesink, pad, FALSE, buf); |
|
3489 } |
|
3490 |
|
3491 static GstFlowReturn |
|
3492 gst_base_sink_chain_list (GstPad * pad, GstBufferList * list) |
|
3493 { |
|
3494 GstBaseSink *basesink; |
|
3495 GstBaseSinkClass *bclass; |
|
3496 GstFlowReturn result; |
|
3497 |
|
3498 basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); |
|
3499 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
|
3500 |
|
3501 if (G_LIKELY (bclass->render_list)) { |
|
3502 result = gst_base_sink_chain_main (basesink, pad, TRUE, list); |
|
3503 } else { |
|
3504 GstBufferListIterator *it; |
|
3505 GstBuffer *group; |
|
3506 |
|
3507 GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer"); |
|
3508 |
|
3509 it = gst_buffer_list_iterate (list); |
|
3510 |
|
3511 result = GST_FLOW_OK; |
|
3512 if (gst_buffer_list_iterator_next_group (it)) { |
|
3513 do { |
|
3514 group = gst_buffer_list_iterator_merge_group (it); |
|
3515 if (group == NULL) { |
|
3516 group = gst_buffer_new (); |
|
3517 GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); |
|
3518 } else { |
|
3519 GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group"); |
|
3520 } |
|
3521 result = gst_base_sink_chain_main (basesink, pad, FALSE, group); |
|
3522 } while (result == GST_FLOW_OK |
|
3523 && gst_buffer_list_iterator_next_group (it)); |
|
3524 } else { |
|
3525 GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); |
|
3526 result = |
|
3527 gst_base_sink_chain_main (basesink, pad, FALSE, gst_buffer_new ()); |
|
3528 } |
|
3529 gst_buffer_list_iterator_free (it); |
|
3530 gst_buffer_list_unref (list); |
|
3531 } |
|
3532 return result; |
|
3533 } |
|
3534 |
|
3535 |
|
3536 static gboolean |
|
3537 gst_base_sink_default_do_seek (GstBaseSink * sink, GstSegment * segment) |
|
3538 { |
|
3539 gboolean res = TRUE; |
|
3540 |
|
3541 /* update our offset if the start/stop position was updated */ |
|
3542 if (segment->format == GST_FORMAT_BYTES) { |
|
3543 segment->time = segment->start; |
|
3544 } else if (segment->start == 0) { |
|
3545 /* seek to start, we can implement a default for this. */ |
|
3546 segment->time = 0; |
|
3547 } else { |
|
3548 res = FALSE; |
|
3549 GST_INFO_OBJECT (sink, "Can't do a default seek"); |
|
3550 } |
|
3551 |
|
3552 return res; |
|
3553 } |
|
3554 |
|
3555 #define SEEK_TYPE_IS_RELATIVE(t) (((t) != GST_SEEK_TYPE_NONE) && ((t) != GST_SEEK_TYPE_SET)) |
|
3556 |
|
3557 static gboolean |
|
3558 gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink, |
|
3559 GstEvent * event, GstSegment * segment) |
|
3560 { |
|
3561 /* By default, we try one of 2 things: |
|
3562 * - For absolute seek positions, convert the requested position to our |
|
3563 * configured processing format and place it in the output segment \ |
|
3564 * - For relative seek positions, convert our current (input) values to the |
|
3565 * seek format, adjust by the relative seek offset and then convert back to |
|
3566 * the processing format |
|
3567 */ |
|
3568 GstSeekType cur_type, stop_type; |
|
3569 gint64 cur, stop; |
|
3570 GstSeekFlags flags; |
|
3571 GstFormat seek_format, dest_format; |
|
3572 gdouble rate; |
|
3573 gboolean update; |
|
3574 gboolean res = TRUE; |
|
3575 |
|
3576 gst_event_parse_seek (event, &rate, &seek_format, &flags, |
|
3577 &cur_type, &cur, &stop_type, &stop); |
|
3578 dest_format = segment->format; |
|
3579 |
|
3580 if (seek_format == dest_format) { |
|
3581 gst_segment_set_seek (segment, rate, seek_format, flags, |
|
3582 cur_type, cur, stop_type, stop, &update); |
|
3583 return TRUE; |
|
3584 } |
|
3585 |
|
3586 if (cur_type != GST_SEEK_TYPE_NONE) { |
|
3587 /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */ |
|
3588 res = |
|
3589 gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format, |
|
3590 &cur); |
|
3591 cur_type = GST_SEEK_TYPE_SET; |
|
3592 } |
|
3593 |
|
3594 if (res && stop_type != GST_SEEK_TYPE_NONE) { |
|
3595 /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */ |
|
3596 res = |
|
3597 gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format, |
|
3598 &stop); |
|
3599 stop_type = GST_SEEK_TYPE_SET; |
|
3600 } |
|
3601 |
|
3602 /* And finally, configure our output segment in the desired format */ |
|
3603 gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur, |
|
3604 stop_type, stop, &update); |
|
3605 |
|
3606 if (!res) |
|
3607 goto no_format; |
|
3608 |
|
3609 return res; |
|
3610 |
|
3611 no_format: |
|
3612 { |
|
3613 GST_DEBUG_OBJECT (sink, "undefined format given, seek aborted."); |
|
3614 return FALSE; |
|
3615 } |
|
3616 } |
|
3617 |
|
3618 /* perform a seek, only executed in pull mode */ |
|
3619 static gboolean |
|
3620 gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event) |
|
3621 { |
|
3622 gboolean flush; |
|
3623 gdouble rate; |
|
3624 GstFormat seek_format, dest_format; |
|
3625 GstSeekFlags flags; |
|
3626 GstSeekType cur_type, stop_type; |
|
3627 gboolean seekseg_configured = FALSE; |
|
3628 gint64 cur, stop; |
|
3629 gboolean update, res = TRUE; |
|
3630 GstSegment seeksegment; |
|
3631 |
|
3632 dest_format = sink->segment.format; |
|
3633 |
|
3634 if (event) { |
|
3635 GST_DEBUG_OBJECT (sink, "performing seek with event %p", event); |
|
3636 gst_event_parse_seek (event, &rate, &seek_format, &flags, |
|
3637 &cur_type, &cur, &stop_type, &stop); |
|
3638 |
|
3639 flush = flags & GST_SEEK_FLAG_FLUSH; |
|
3640 } else { |
|
3641 GST_DEBUG_OBJECT (sink, "performing seek without event"); |
|
3642 flush = FALSE; |
|
3643 } |
|
3644 |
|
3645 if (flush) { |
|
3646 GST_DEBUG_OBJECT (sink, "flushing upstream"); |
|
3647 gst_pad_push_event (pad, gst_event_new_flush_start ()); |
|
3648 gst_base_sink_flush_start (sink, pad); |
|
3649 } else { |
|
3650 GST_DEBUG_OBJECT (sink, "pausing pulling thread"); |
|
3651 } |
|
3652 |
|
3653 GST_PAD_STREAM_LOCK (pad); |
|
3654 |
|
3655 /* If we configured the seeksegment above, don't overwrite it now. Otherwise |
|
3656 * copy the current segment info into the temp segment that we can actually |
|
3657 * attempt the seek with. We only update the real segment if the seek suceeds. */ |
|
3658 if (!seekseg_configured) { |
|
3659 memcpy (&seeksegment, &sink->segment, sizeof (GstSegment)); |
|
3660 |
|
3661 /* now configure the final seek segment */ |
|
3662 if (event) { |
|
3663 if (sink->segment.format != seek_format) { |
|
3664 /* OK, here's where we give the subclass a chance to convert the relative |
|
3665 * seek into an absolute one in the processing format. We set up any |
|
3666 * absolute seek above, before taking the stream lock. */ |
|
3667 if (!gst_base_sink_default_prepare_seek_segment (sink, event, |
|
3668 &seeksegment)) { |
|
3669 GST_DEBUG_OBJECT (sink, |
|
3670 "Preparing the seek failed after flushing. " "Aborting seek"); |
|
3671 res = FALSE; |
|
3672 } |
|
3673 } else { |
|
3674 /* The seek format matches our processing format, no need to ask the |
|
3675 * the subclass to configure the segment. */ |
|
3676 gst_segment_set_seek (&seeksegment, rate, seek_format, flags, |
|
3677 cur_type, cur, stop_type, stop, &update); |
|
3678 } |
|
3679 } |
|
3680 /* Else, no seek event passed, so we're just (re)starting the |
|
3681 current segment. */ |
|
3682 } |
|
3683 |
|
3684 if (res) { |
|
3685 GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT |
|
3686 " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT, |
|
3687 seeksegment.start, seeksegment.stop, seeksegment.last_stop); |
|
3688 |
|
3689 /* do the seek, segment.last_stop contains the new position. */ |
|
3690 res = gst_base_sink_default_do_seek (sink, &seeksegment); |
|
3691 } |
|
3692 |
|
3693 |
|
3694 if (flush) { |
|
3695 GST_DEBUG_OBJECT (sink, "stop flushing upstream"); |
|
3696 gst_pad_push_event (pad, gst_event_new_flush_stop ()); |
|
3697 gst_base_sink_flush_stop (sink, pad); |
|
3698 } else if (res && sink->abidata.ABI.running) { |
|
3699 /* we are running the current segment and doing a non-flushing seek, |
|
3700 * close the segment first based on the last_stop. */ |
|
3701 GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT |
|
3702 " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop); |
|
3703 } |
|
3704 |
|
3705 /* The subclass must have converted the segment to the processing format |
|
3706 * by now */ |
|
3707 if (res && seeksegment.format != dest_format) { |
|
3708 GST_DEBUG_OBJECT (sink, "Subclass failed to prepare a seek segment " |
|
3709 "in the correct format. Aborting seek."); |
|
3710 res = FALSE; |
|
3711 } |
|
3712 |
|
3713 /* if successfull seek, we update our real segment and push |
|
3714 * out the new segment. */ |
|
3715 if (res) { |
|
3716 memcpy (&sink->segment, &seeksegment, sizeof (GstSegment)); |
|
3717 |
|
3718 if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) { |
|
3719 gst_element_post_message (GST_ELEMENT (sink), |
|
3720 gst_message_new_segment_start (GST_OBJECT (sink), |
|
3721 sink->segment.format, sink->segment.last_stop)); |
|
3722 } |
|
3723 } |
|
3724 |
|
3725 sink->priv->discont = TRUE; |
|
3726 sink->abidata.ABI.running = TRUE; |
|
3727 |
|
3728 GST_PAD_STREAM_UNLOCK (pad); |
|
3729 |
|
3730 return res; |
|
3731 } |
|
3732 |
|
3733 static void |
|
3734 set_step_info (GstBaseSink * sink, GstStepInfo * current, GstStepInfo * pending, |
|
3735 guint seqnum, GstFormat format, guint64 amount, gdouble rate, |
|
3736 gboolean flush, gboolean intermediate) |
|
3737 { |
|
3738 GST_OBJECT_LOCK (sink); |
|
3739 pending->seqnum = seqnum; |
|
3740 pending->format = format; |
|
3741 pending->amount = amount; |
|
3742 pending->position = 0; |
|
3743 pending->rate = rate; |
|
3744 pending->flush = flush; |
|
3745 pending->intermediate = intermediate; |
|
3746 pending->valid = TRUE; |
|
3747 /* flush invalidates the current stepping segment */ |
|
3748 if (flush) |
|
3749 current->valid = FALSE; |
|
3750 GST_OBJECT_UNLOCK (sink); |
|
3751 } |
|
3752 |
|
3753 static gboolean |
|
3754 gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event) |
|
3755 { |
|
3756 GstBaseSinkPrivate *priv; |
|
3757 GstBaseSinkClass *bclass; |
|
3758 gboolean flush, intermediate; |
|
3759 gdouble rate; |
|
3760 GstFormat format; |
|
3761 guint64 amount; |
|
3762 guint seqnum; |
|
3763 GstStepInfo *pending, *current; |
|
3764 GstMessage *message; |
|
3765 |
|
3766 bclass = GST_BASE_SINK_GET_CLASS (sink); |
|
3767 priv = sink->priv; |
|
3768 |
|
3769 GST_DEBUG_OBJECT (sink, "performing step with event %p", event); |
|
3770 |
|
3771 gst_event_parse_step (event, &format, &amount, &rate, &flush, &intermediate); |
|
3772 seqnum = gst_event_get_seqnum (event); |
|
3773 |
|
3774 pending = &priv->pending_step; |
|
3775 current = &priv->current_step; |
|
3776 |
|
3777 /* post message first */ |
|
3778 message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format, |
|
3779 amount, rate, flush, intermediate); |
|
3780 gst_message_set_seqnum (message, seqnum); |
|
3781 gst_element_post_message (GST_ELEMENT (sink), message); |
|
3782 |
|
3783 if (flush) { |
|
3784 /* we need to call ::unlock before locking PREROLL_LOCK |
|
3785 * since we lock it before going into ::render */ |
|
3786 if (bclass->unlock) |
|
3787 bclass->unlock (sink); |
|
3788 |
|
3789 GST_PAD_PREROLL_LOCK (sink->sinkpad); |
|
3790 /* now that we have the PREROLL lock, clear our unlock request */ |
|
3791 if (bclass->unlock_stop) |
|
3792 bclass->unlock_stop (sink); |
|
3793 |
|
3794 /* update the stepinfo and make it valid */ |
|
3795 set_step_info (sink, current, pending, seqnum, format, amount, rate, flush, |
|
3796 intermediate); |
|
3797 |
|
3798 if (sink->priv->async_enabled) { |
|
3799 /* and we need to commit our state again on the next |
|
3800 * prerolled buffer */ |
|
3801 sink->playing_async = TRUE; |
|
3802 priv->pending_step.need_preroll = TRUE; |
|
3803 sink->need_preroll = FALSE; |
|
3804 gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE); |
|
3805 } else { |
|
3806 sink->priv->have_latency = TRUE; |
|
3807 sink->need_preroll = FALSE; |
|
3808 } |
|
3809 priv->current_sstart = -1; |
|
3810 priv->current_sstop = -1; |
|
3811 priv->eos_rtime = -1; |
|
3812 priv->call_preroll = TRUE; |
|
3813 gst_base_sink_set_last_buffer (sink, NULL); |
|
3814 gst_base_sink_reset_qos (sink); |
|
3815 |
|
3816 if (sink->clock_id) { |
|
3817 gst_clock_id_unschedule (sink->clock_id); |
|
3818 } |
|
3819 |
|
3820 if (sink->have_preroll) { |
|
3821 GST_DEBUG_OBJECT (sink, "signal waiter"); |
|
3822 priv->step_unlock = TRUE; |
|
3823 GST_PAD_PREROLL_SIGNAL (sink->sinkpad); |
|
3824 } |
|
3825 GST_PAD_PREROLL_UNLOCK (sink->sinkpad); |
|
3826 } else { |
|
3827 /* update the stepinfo and make it valid */ |
|
3828 set_step_info (sink, current, pending, seqnum, format, amount, rate, flush, |
|
3829 intermediate); |
|
3830 } |
|
3831 |
|
3832 return TRUE; |
|
3833 } |
|
3834 |
|
3835 /* with STREAM_LOCK |
2686 /* with STREAM_LOCK |
3836 */ |
2687 */ |
3837 static void |
2688 static void |
3838 gst_base_sink_loop (GstPad * pad) |
2689 gst_base_sink_loop (GstPad * pad) |
3839 { |
2690 { |
3840 GstBaseSink *basesink; |
2691 GstBaseSink *basesink; |
3841 GstBuffer *buf = NULL; |
2692 GstBuffer *buf = NULL; |
3842 GstFlowReturn result; |
2693 GstFlowReturn result; |
3843 guint blocksize; |
|
3844 guint64 offset; |
|
3845 |
2694 |
3846 basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); |
2695 basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad)); |
3847 |
2696 |
3848 g_assert (basesink->pad_mode == GST_ACTIVATE_PULL); |
2697 g_assert (basesink->pad_mode == GST_ACTIVATE_PULL); |
3849 |
2698 |
3850 if ((blocksize = basesink->priv->blocksize) == 0) |
|
3851 blocksize = -1; |
|
3852 |
|
3853 offset = basesink->segment.last_stop; |
|
3854 |
|
3855 GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u", |
2699 GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u", |
3856 offset, blocksize); |
2700 basesink->offset, (guint) DEFAULT_SIZE); |
3857 |
2701 |
3858 result = gst_pad_pull_range (pad, offset, blocksize, &buf); |
2702 result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf); |
3859 if (G_UNLIKELY (result != GST_FLOW_OK)) |
2703 if (G_UNLIKELY (result != GST_FLOW_OK)) |
3860 goto paused; |
2704 goto paused; |
3861 |
2705 |
3862 if (G_UNLIKELY (buf == NULL)) |
2706 if (G_UNLIKELY (buf == NULL)) |
3863 goto no_buffer; |
2707 goto no_buffer; |
3864 |
2708 |
3865 offset += GST_BUFFER_SIZE (buf); |
2709 basesink->offset += GST_BUFFER_SIZE (buf); |
3866 |
|
3867 gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset); |
|
3868 |
2710 |
3869 GST_PAD_PREROLL_LOCK (pad); |
2711 GST_PAD_PREROLL_LOCK (pad); |
3870 result = gst_base_sink_chain_unlocked (basesink, pad, FALSE, buf); |
2712 result = gst_base_sink_chain_unlocked (basesink, pad, buf); |
3871 GST_PAD_PREROLL_UNLOCK (pad); |
2713 GST_PAD_PREROLL_UNLOCK (pad); |
3872 if (G_UNLIKELY (result != GST_FLOW_OK)) |
2714 if (G_UNLIKELY (result != GST_FLOW_OK)) |
3873 goto paused; |
2715 goto paused; |
3874 |
2716 |
3875 return; |
2717 return; |
3880 GST_LOG_OBJECT (basesink, "pausing task, reason %s", |
2722 GST_LOG_OBJECT (basesink, "pausing task, reason %s", |
3881 gst_flow_get_name (result)); |
2723 gst_flow_get_name (result)); |
3882 gst_pad_pause_task (pad); |
2724 gst_pad_pause_task (pad); |
3883 /* fatal errors and NOT_LINKED cause EOS */ |
2725 /* fatal errors and NOT_LINKED cause EOS */ |
3884 if (GST_FLOW_IS_FATAL (result) || result == GST_FLOW_NOT_LINKED) { |
2726 if (GST_FLOW_IS_FATAL (result) || result == GST_FLOW_NOT_LINKED) { |
3885 if (result == GST_FLOW_UNEXPECTED) { |
2727 /* FIXME, we shouldn't post EOS when we are operating in segment mode */ |
3886 /* perform EOS logic */ |
2728 gst_base_sink_event (pad, gst_event_new_eos ()); |
3887 if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) { |
2729 /* EOS does not cause an ERROR message */ |
3888 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
2730 if (result != GST_FLOW_UNEXPECTED) { |
3889 gst_message_new_segment_done (GST_OBJECT_CAST (basesink), |
|
3890 basesink->segment.format, basesink->segment.last_stop)); |
|
3891 } else { |
|
3892 gst_base_sink_event (pad, gst_event_new_eos ()); |
|
3893 } |
|
3894 } else { |
|
3895 /* for fatal errors we post an error message, post the error |
|
3896 * first so the app knows about the error first. */ |
|
3897 GST_ELEMENT_ERROR (basesink, STREAM, FAILED, |
2731 GST_ELEMENT_ERROR (basesink, STREAM, FAILED, |
3898 (_("Internal data stream error.")), |
2732 (_("Internal data stream error.")), |
3899 ("stream stopped, reason %s", gst_flow_get_name (result))); |
2733 ("stream stopped, reason %s", gst_flow_get_name (result))); |
3900 gst_base_sink_event (pad, gst_event_new_eos ()); |
|
3901 } |
2734 } |
3902 } |
2735 } |
3903 return; |
2736 return; |
3904 } |
2737 } |
3905 no_buffer: |
2738 no_buffer: |
3906 { |
2739 { |
3907 GST_LOG_OBJECT (basesink, "no buffer, pausing"); |
2740 GST_LOG_OBJECT (basesink, "no buffer, pausing"); |
3908 GST_ELEMENT_ERROR (basesink, STREAM, FAILED, |
|
3909 (_("Internal data flow error.")), ("element returned NULL buffer")); |
|
3910 result = GST_FLOW_ERROR; |
2741 result = GST_FLOW_ERROR; |
3911 goto paused; |
2742 goto paused; |
3912 } |
2743 } |
3913 } |
2744 } |
3914 |
2745 |
3941 /* step 2, unblock clock sync (if any) or any other blocking thing */ |
2772 /* step 2, unblock clock sync (if any) or any other blocking thing */ |
3942 if (basesink->clock_id) { |
2773 if (basesink->clock_id) { |
3943 gst_clock_id_unschedule (basesink->clock_id); |
2774 gst_clock_id_unschedule (basesink->clock_id); |
3944 } |
2775 } |
3945 |
2776 |
3946 /* flush out the data thread if it's locked in finish_preroll, this will |
2777 /* flush out the data thread if it's locked in finish_preroll */ |
3947 * also flush out the EOS state */ |
|
3948 GST_DEBUG_OBJECT (basesink, |
2778 GST_DEBUG_OBJECT (basesink, |
3949 "flushing out data thread, need preroll to TRUE"); |
2779 "flushing out data thread, need preroll to TRUE"); |
3950 gst_base_sink_preroll_queue_flush (basesink, pad); |
2780 gst_base_sink_preroll_queue_flush (basesink, pad); |
3951 } |
2781 } |
3952 GST_PAD_PREROLL_UNLOCK (pad); |
2782 GST_PAD_PREROLL_UNLOCK (pad); |
3981 |
2811 |
3982 GST_DEBUG_OBJECT (basesink, "Trying pull mode first"); |
2812 GST_DEBUG_OBJECT (basesink, "Trying pull mode first"); |
3983 |
2813 |
3984 gst_base_sink_set_flushing (basesink, pad, FALSE); |
2814 gst_base_sink_set_flushing (basesink, pad, FALSE); |
3985 |
2815 |
3986 /* we need to have the pull mode enabled */ |
2816 if (basesink->can_activate_pull && gst_pad_check_pull_range (pad) |
3987 if (!basesink->can_activate_pull) { |
2817 && gst_pad_activate_pull (pad, TRUE)) { |
3988 GST_DEBUG_OBJECT (basesink, "pull mode disabled"); |
2818 GST_DEBUG_OBJECT (basesink, "Success activating pull mode"); |
3989 goto fallback; |
2819 result = TRUE; |
3990 } |
2820 } else { |
3991 |
2821 GST_DEBUG_OBJECT (basesink, "Falling back to push mode"); |
3992 /* check if downstreams supports pull mode at all */ |
2822 if (gst_pad_activate_push (pad, TRUE)) { |
3993 if (!gst_pad_check_pull_range (pad)) { |
2823 GST_DEBUG_OBJECT (basesink, "Success activating push mode"); |
3994 GST_DEBUG_OBJECT (basesink, "pull mode not supported"); |
2824 result = TRUE; |
3995 goto fallback; |
2825 } |
3996 } |
2826 } |
3997 |
2827 |
3998 /* set the pad mode before starting the task so that it's in the |
|
3999 * correct state for the new thread. also the sink set_caps and get_caps |
|
4000 * function checks this */ |
|
4001 basesink->pad_mode = GST_ACTIVATE_PULL; |
|
4002 |
|
4003 /* we first try to negotiate a format so that when we try to activate |
|
4004 * downstream, it knows about our format */ |
|
4005 if (!gst_base_sink_negotiate_pull (basesink)) { |
|
4006 GST_DEBUG_OBJECT (basesink, "failed to negotiate in pull mode"); |
|
4007 goto fallback; |
|
4008 } |
|
4009 |
|
4010 /* ok activate now */ |
|
4011 if (!gst_pad_activate_pull (pad, TRUE)) { |
|
4012 /* clear any pending caps */ |
|
4013 GST_OBJECT_LOCK (basesink); |
|
4014 gst_caps_replace (&basesink->priv->pull_caps, NULL); |
|
4015 GST_OBJECT_UNLOCK (basesink); |
|
4016 GST_DEBUG_OBJECT (basesink, "failed to activate in pull mode"); |
|
4017 goto fallback; |
|
4018 } |
|
4019 |
|
4020 GST_DEBUG_OBJECT (basesink, "Success activating pull mode"); |
|
4021 result = TRUE; |
|
4022 goto done; |
|
4023 |
|
4024 /* push mode fallback */ |
|
4025 fallback: |
|
4026 GST_DEBUG_OBJECT (basesink, "Falling back to push mode"); |
|
4027 if ((result = gst_pad_activate_push (pad, TRUE))) { |
|
4028 GST_DEBUG_OBJECT (basesink, "Success activating push mode"); |
|
4029 } |
|
4030 |
|
4031 done: |
|
4032 if (!result) { |
2828 if (!result) { |
4033 GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode"); |
2829 GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode"); |
4034 gst_base_sink_set_flushing (basesink, pad, TRUE); |
2830 gst_base_sink_set_flushing (basesink, pad, TRUE); |
4035 } |
2831 } |
4036 |
2832 |
4073 |
2869 |
4074 static gboolean |
2870 static gboolean |
4075 gst_base_sink_negotiate_pull (GstBaseSink * basesink) |
2871 gst_base_sink_negotiate_pull (GstBaseSink * basesink) |
4076 { |
2872 { |
4077 GstCaps *caps; |
2873 GstCaps *caps; |
4078 gboolean result; |
2874 GstPad *pad; |
4079 |
2875 |
4080 result = FALSE; |
2876 GST_OBJECT_LOCK (basesink); |
4081 |
2877 pad = basesink->sinkpad; |
4082 /* this returns the intersection between our caps and the peer caps. If there |
2878 gst_object_ref (pad); |
4083 * is no peer, it returns NULL and we can't operate in pull mode so we can |
2879 GST_OBJECT_UNLOCK (basesink); |
4084 * fail the negotiation. */ |
2880 |
4085 caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (basesink)); |
2881 caps = gst_pad_get_allowed_caps (pad); |
4086 if (caps == NULL || gst_caps_is_empty (caps)) |
2882 if (gst_caps_is_empty (caps)) |
4087 goto no_caps_possible; |
2883 goto no_caps_possible; |
4088 |
2884 |
4089 GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps); |
|
4090 |
|
4091 caps = gst_caps_make_writable (caps); |
2885 caps = gst_caps_make_writable (caps); |
4092 /* get the first (prefered) format */ |
|
4093 gst_caps_truncate (caps); |
2886 gst_caps_truncate (caps); |
4094 /* try to fixate */ |
2887 gst_pad_fixate_caps (pad, caps); |
4095 gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps); |
|
4096 |
|
4097 GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps); |
|
4098 |
2888 |
4099 if (gst_caps_is_any (caps)) { |
2889 if (gst_caps_is_any (caps)) { |
4100 GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, " |
2890 GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, " |
4101 "allowing pull()"); |
2891 "allowing pull()"); |
4102 /* neither side has template caps in this case, so they are prepared for |
2892 /* neither side has template caps in this case, so they are prepared for |
4103 pull() without setcaps() */ |
2893 pull() without setcaps() */ |
4104 result = TRUE; |
2894 } else { |
4105 } else if (gst_caps_is_fixed (caps)) { |
2895 if (!gst_pad_set_caps (pad, caps)) |
4106 if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps)) |
|
4107 goto could_not_set_caps; |
2896 goto could_not_set_caps; |
4108 |
|
4109 GST_OBJECT_LOCK (basesink); |
|
4110 gst_caps_replace (&basesink->priv->pull_caps, caps); |
|
4111 GST_OBJECT_UNLOCK (basesink); |
|
4112 |
|
4113 result = TRUE; |
|
4114 } |
2897 } |
4115 |
2898 |
4116 gst_caps_unref (caps); |
2899 gst_caps_unref (caps); |
4117 |
2900 gst_object_unref (pad); |
4118 return result; |
2901 |
2902 return TRUE; |
|
4119 |
2903 |
4120 no_caps_possible: |
2904 no_caps_possible: |
4121 { |
2905 { |
4122 GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps"); |
2906 GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps"); |
4123 GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY"); |
2907 GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY"); |
4124 if (caps) |
2908 gst_object_unref (pad); |
4125 gst_caps_unref (caps); |
|
4126 return FALSE; |
2909 return FALSE; |
4127 } |
2910 } |
4128 could_not_set_caps: |
2911 could_not_set_caps: |
4129 { |
2912 { |
4130 GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps); |
2913 GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps); |
4131 gst_caps_unref (caps); |
2914 gst_caps_unref (caps); |
2915 gst_object_unref (pad); |
|
4132 return FALSE; |
2916 return FALSE; |
4133 } |
2917 } |
4134 } |
2918 } |
4135 |
2919 |
4136 /* this won't get called until we implement an activate function */ |
2920 /* this won't get called until we implement an activate function */ |
4143 |
2927 |
4144 basesink = GST_BASE_SINK (gst_pad_get_parent (pad)); |
2928 basesink = GST_BASE_SINK (gst_pad_get_parent (pad)); |
4145 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
2929 bclass = GST_BASE_SINK_GET_CLASS (basesink); |
4146 |
2930 |
4147 if (active) { |
2931 if (active) { |
4148 GstFormat format; |
2932 if (!basesink->can_activate_pull) { |
4149 gint64 duration; |
2933 result = FALSE; |
4150 |
2934 basesink->pad_mode = GST_ACTIVATE_NONE; |
4151 /* we mark we have a newsegment here because pull based |
|
4152 * mode works just fine without having a newsegment before the |
|
4153 * first buffer */ |
|
4154 format = GST_FORMAT_BYTES; |
|
4155 |
|
4156 gst_segment_init (&basesink->segment, format); |
|
4157 gst_segment_init (basesink->abidata.ABI.clip_segment, format); |
|
4158 GST_OBJECT_LOCK (basesink); |
|
4159 basesink->have_newsegment = TRUE; |
|
4160 GST_OBJECT_UNLOCK (basesink); |
|
4161 |
|
4162 /* get the peer duration in bytes */ |
|
4163 result = gst_pad_query_peer_duration (pad, &format, &duration); |
|
4164 if (result) { |
|
4165 GST_DEBUG_OBJECT (basesink, |
|
4166 "setting duration in bytes to %" G_GINT64_FORMAT, duration); |
|
4167 gst_segment_set_duration (basesink->abidata.ABI.clip_segment, format, |
|
4168 duration); |
|
4169 gst_segment_set_duration (&basesink->segment, format, duration); |
|
4170 } else { |
2935 } else { |
4171 GST_DEBUG_OBJECT (basesink, "unknown duration"); |
2936 GstPad *peer = gst_pad_get_peer (pad); |
2937 |
|
2938 if (G_UNLIKELY (peer == NULL)) { |
|
2939 g_warning ("Trying to activate pad in pull mode, but no peer"); |
|
2940 result = FALSE; |
|
2941 basesink->pad_mode = GST_ACTIVATE_NONE; |
|
2942 } else { |
|
2943 if (gst_pad_activate_pull (peer, TRUE)) { |
|
2944 /* we mark we have a newsegment here because pull based |
|
2945 * mode works just fine without having a newsegment before the |
|
2946 * first buffer */ |
|
2947 gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); |
|
2948 gst_segment_init (basesink->abidata.ABI.clip_segment, |
|
2949 GST_FORMAT_UNDEFINED); |
|
2950 basesink->have_newsegment = TRUE; |
|
2951 |
|
2952 /* set the pad mode before starting the task so that it's in the |
|
2953 correct state for the new thread. also the sink set_caps function |
|
2954 checks this */ |
|
2955 basesink->pad_mode = GST_ACTIVATE_PULL; |
|
2956 if ((result = gst_base_sink_negotiate_pull (basesink))) { |
|
2957 if (bclass->activate_pull) |
|
2958 result = bclass->activate_pull (basesink, TRUE); |
|
2959 else |
|
2960 result = FALSE; |
|
2961 } |
|
2962 /* but if starting the thread fails, set it back */ |
|
2963 if (!result) |
|
2964 basesink->pad_mode = GST_ACTIVATE_NONE; |
|
2965 } else { |
|
2966 GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode"); |
|
2967 result = FALSE; |
|
2968 basesink->pad_mode = GST_ACTIVATE_NONE; |
|
2969 } |
|
2970 gst_object_unref (peer); |
|
2971 } |
|
4172 } |
2972 } |
4173 |
|
4174 if (bclass->activate_pull) |
|
4175 result = bclass->activate_pull (basesink, TRUE); |
|
4176 else |
|
4177 result = FALSE; |
|
4178 |
|
4179 if (!result) |
|
4180 goto activate_failed; |
|
4181 |
|
4182 } else { |
2973 } else { |
4183 if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) { |
2974 if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) { |
4184 g_warning ("Internal GStreamer activation error!!!"); |
2975 g_warning ("Internal GStreamer activation error!!!"); |
4185 result = FALSE; |
2976 result = FALSE; |
4186 } else { |
2977 } else { |
4187 result = gst_base_sink_set_flushing (basesink, pad, TRUE); |
2978 result = gst_base_sink_set_flushing (basesink, pad, TRUE); |
4188 if (bclass->activate_pull) |
2979 if (bclass->activate_pull) |
4189 result &= bclass->activate_pull (basesink, FALSE); |
2980 result &= bclass->activate_pull (basesink, FALSE); |
4190 basesink->pad_mode = GST_ACTIVATE_NONE; |
2981 basesink->pad_mode = GST_ACTIVATE_NONE; |
4191 /* clear any pending caps */ |
|
4192 GST_OBJECT_LOCK (basesink); |
|
4193 gst_caps_replace (&basesink->priv->pull_caps, NULL); |
|
4194 GST_OBJECT_UNLOCK (basesink); |
|
4195 } |
2982 } |
4196 } |
2983 } |
2984 |
|
4197 gst_object_unref (basesink); |
2985 gst_object_unref (basesink); |
4198 |
2986 |
4199 return result; |
2987 return result; |
4200 |
|
4201 /* ERRORS */ |
|
4202 activate_failed: |
|
4203 { |
|
4204 /* reset, as starting the thread failed */ |
|
4205 basesink->pad_mode = GST_ACTIVATE_NONE; |
|
4206 |
|
4207 GST_ERROR_OBJECT (basesink, "subclass failed to activate in pull mode"); |
|
4208 return FALSE; |
|
4209 } |
|
4210 } |
2988 } |
4211 |
2989 |
4212 /* send an event to our sinkpad peer. */ |
2990 /* send an event to our sinkpad peer. */ |
4213 static gboolean |
2991 static gboolean |
4214 gst_base_sink_send_event (GstElement * element, GstEvent * event) |
2992 gst_base_sink_send_event (GstElement * element, GstEvent * event) |
4215 { |
2993 { |
4216 GstPad *pad; |
2994 GstPad *pad; |
4217 GstBaseSink *basesink = GST_BASE_SINK (element); |
2995 GstBaseSink *basesink = GST_BASE_SINK (element); |
4218 gboolean forward, result = TRUE; |
2996 gboolean forward, result = TRUE; |
4219 GstActivateMode mode; |
|
4220 |
|
4221 GST_OBJECT_LOCK (element); |
|
4222 /* get the pad and the scheduling mode */ |
|
4223 pad = gst_object_ref (basesink->sinkpad); |
|
4224 mode = basesink->pad_mode; |
|
4225 GST_OBJECT_UNLOCK (element); |
|
4226 |
2997 |
4227 /* only push UPSTREAM events upstream */ |
2998 /* only push UPSTREAM events upstream */ |
4228 forward = GST_EVENT_IS_UPSTREAM (event); |
2999 forward = GST_EVENT_IS_UPSTREAM (event); |
4229 |
3000 |
4230 switch (GST_EVENT_TYPE (event)) { |
3001 switch (GST_EVENT_TYPE (event)) { |
4232 { |
3003 { |
4233 GstClockTime latency; |
3004 GstClockTime latency; |
4234 |
3005 |
4235 gst_event_parse_latency (event, &latency); |
3006 gst_event_parse_latency (event, &latency); |
4236 |
3007 |
4237 /* store the latency. We use this to adjust the running_time before syncing |
|
4238 * it to the clock. */ |
|
4239 GST_OBJECT_LOCK (element); |
3008 GST_OBJECT_LOCK (element); |
4240 basesink->priv->latency = latency; |
3009 basesink->priv->latency = latency; |
4241 if (!basesink->priv->have_latency) |
|
4242 forward = FALSE; |
|
4243 GST_OBJECT_UNLOCK (element); |
3010 GST_OBJECT_UNLOCK (element); |
4244 GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT, |
3011 GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT, |
4245 GST_TIME_ARGS (latency)); |
3012 GST_TIME_ARGS (latency)); |
4246 |
3013 |
4247 /* We forward this event so that all elements know about the global pipeline |
3014 /* don't forward, yet */ |
4248 * latency. This is interesting for an element when it wants to figure out |
3015 forward = FALSE; |
4249 * when a particular piece of data will be rendered. */ |
|
4250 break; |
3016 break; |
4251 } |
3017 } |
4252 case GST_EVENT_SEEK: |
|
4253 /* in pull mode we will execute the seek */ |
|
4254 if (mode == GST_ACTIVATE_PULL) |
|
4255 result = gst_base_sink_perform_seek (basesink, pad, event); |
|
4256 break; |
|
4257 case GST_EVENT_STEP: |
|
4258 result = gst_base_sink_perform_step (basesink, pad, event); |
|
4259 forward = FALSE; |
|
4260 break; |
|
4261 default: |
3018 default: |
4262 break; |
3019 break; |
4263 } |
3020 } |
4264 |
3021 |
4265 if (forward) { |
3022 if (forward) { |
3023 GST_OBJECT_LOCK (element); |
|
3024 pad = gst_object_ref (basesink->sinkpad); |
|
3025 GST_OBJECT_UNLOCK (element); |
|
3026 |
|
4266 result = gst_pad_push_event (pad, event); |
3027 result = gst_pad_push_event (pad, event); |
3028 |
|
3029 gst_object_unref (pad); |
|
4267 } else { |
3030 } else { |
4268 /* not forwarded, unref the event */ |
3031 /* not forwarded, unref the event */ |
4269 gst_event_unref (event); |
3032 gst_event_unref (event); |
4270 } |
3033 } |
4271 |
|
4272 gst_object_unref (pad); |
|
4273 return result; |
3034 return result; |
4274 } |
3035 } |
4275 |
3036 |
4276 static gboolean |
3037 static gboolean |
4277 gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query) |
3038 gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query) |
4286 return res; |
3047 return res; |
4287 } |
3048 } |
4288 |
3049 |
4289 /* get the end position of the last seen object, this is used |
3050 /* get the end position of the last seen object, this is used |
4290 * for EOS and for making sure that we don't report a position we |
3051 * for EOS and for making sure that we don't report a position we |
4291 * have not reached yet. With LOCK. */ |
3052 * have not reached yet. */ |
4292 static gboolean |
3053 static gboolean |
4293 gst_base_sink_get_position_last (GstBaseSink * basesink, GstFormat format, |
3054 gst_base_sink_get_position_last (GstBaseSink * basesink, gint64 * cur) |
4294 gint64 * cur) |
3055 { |
4295 { |
3056 /* return last observed stream time */ |
4296 GstFormat oformat; |
3057 *cur = basesink->priv->current_sstop; |
4297 GstSegment *segment; |
|
4298 gboolean ret = TRUE; |
|
4299 |
|
4300 segment = &basesink->segment; |
|
4301 oformat = segment->format; |
|
4302 |
|
4303 if (oformat == GST_FORMAT_TIME) { |
|
4304 /* return last observed stream time, we keep the stream time around in the |
|
4305 * time format. */ |
|
4306 *cur = basesink->priv->current_sstop; |
|
4307 } else { |
|
4308 /* convert last stop to stream time */ |
|
4309 *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop); |
|
4310 } |
|
4311 |
|
4312 if (*cur != -1 && oformat != format) { |
|
4313 GST_OBJECT_UNLOCK (basesink); |
|
4314 /* convert to the target format if we need to, release lock first */ |
|
4315 ret = |
|
4316 gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur); |
|
4317 if (!ret) |
|
4318 *cur = -1; |
|
4319 GST_OBJECT_LOCK (basesink); |
|
4320 } |
|
4321 |
|
4322 GST_DEBUG_OBJECT (basesink, "POSITION: %" GST_TIME_FORMAT, |
3058 GST_DEBUG_OBJECT (basesink, "POSITION: %" GST_TIME_FORMAT, |
4323 GST_TIME_ARGS (*cur)); |
3059 GST_TIME_ARGS (*cur)); |
4324 |
3060 return TRUE; |
4325 return ret; |
|
4326 } |
3061 } |
4327 |
3062 |
4328 /* get the position when we are PAUSED, this is the stream time of the buffer |
3063 /* get the position when we are PAUSED, this is the stream time of the buffer |
4329 * that prerolled. If no buffer is prerolled (we are still flushing), this |
3064 * that prerolled. If no buffer is prerolled (we are still flushing), this |
4330 * value will be -1. With LOCK. */ |
3065 * value will be -1. */ |
4331 static gboolean |
3066 static gboolean |
4332 gst_base_sink_get_position_paused (GstBaseSink * basesink, GstFormat format, |
3067 gst_base_sink_get_position_paused (GstBaseSink * basesink, gint64 * cur) |
4333 gint64 * cur) |
|
4334 { |
3068 { |
4335 gboolean res; |
3069 gboolean res; |
4336 gint64 time; |
3070 gint64 time; |
4337 GstSegment *segment; |
3071 GstSegment *segment; |
4338 GstFormat oformat; |
3072 |
4339 |
3073 *cur = basesink->priv->current_sstart; |
4340 /* we don't use the clip segment in pull mode, when seeking we update the |
3074 segment = basesink->abidata.ABI.clip_segment; |
4341 * main segment directly with the new segment values without it having to be |
|
4342 * activated by the rendering after preroll */ |
|
4343 if (basesink->pad_mode == GST_ACTIVATE_PUSH) |
|
4344 segment = basesink->abidata.ABI.clip_segment; |
|
4345 else |
|
4346 segment = &basesink->segment; |
|
4347 oformat = segment->format; |
|
4348 |
|
4349 if (oformat == GST_FORMAT_TIME) { |
|
4350 *cur = basesink->priv->current_sstart; |
|
4351 if (segment->rate < 0.0 && basesink->priv->current_sstop != -1) { |
|
4352 /* for reverse playback we prefer the stream time stop position if we have |
|
4353 * one */ |
|
4354 *cur = basesink->priv->current_sstop; |
|
4355 } |
|
4356 } else { |
|
4357 *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop); |
|
4358 } |
|
4359 |
3075 |
4360 time = segment->time; |
3076 time = segment->time; |
4361 |
3077 |
4362 if (*cur != -1) { |
3078 if (*cur != -1) { |
4363 *cur = MAX (*cur, time); |
3079 *cur = MAX (*cur, time); |
4371 GST_DEBUG_OBJECT (basesink, "POSITION as time: %" GST_TIME_FORMAT, |
3087 GST_DEBUG_OBJECT (basesink, "POSITION as time: %" GST_TIME_FORMAT, |
4372 GST_TIME_ARGS (*cur)); |
3088 GST_TIME_ARGS (*cur)); |
4373 } else { |
3089 } else { |
4374 /* reverse, next expected timestamp is segment->stop. We use the function |
3090 /* reverse, next expected timestamp is segment->stop. We use the function |
4375 * to get things right for negative applied_rates. */ |
3091 * to get things right for negative applied_rates. */ |
4376 *cur = gst_segment_to_stream_time (segment, oformat, segment->stop); |
3092 *cur = |
3093 gst_segment_to_stream_time (segment, GST_FORMAT_TIME, segment->stop); |
|
4377 GST_DEBUG_OBJECT (basesink, "reverse POSITION: %" GST_TIME_FORMAT, |
3094 GST_DEBUG_OBJECT (basesink, "reverse POSITION: %" GST_TIME_FORMAT, |
4378 GST_TIME_ARGS (*cur)); |
3095 GST_TIME_ARGS (*cur)); |
4379 } |
3096 } |
4380 } |
3097 } |
4381 |
|
4382 res = (*cur != -1); |
3098 res = (*cur != -1); |
4383 if (res && oformat != format) { |
|
4384 GST_OBJECT_UNLOCK (basesink); |
|
4385 res = |
|
4386 gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur); |
|
4387 if (!res) |
|
4388 *cur = -1; |
|
4389 GST_OBJECT_LOCK (basesink); |
|
4390 } |
|
4391 |
3099 |
4392 return res; |
3100 return res; |
4393 } |
3101 } |
4394 |
3102 |
4395 static gboolean |
3103 static gboolean |
4396 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, |
3104 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, |
4397 gint64 * cur, gboolean * upstream) |
3105 gint64 * cur) |
4398 { |
3106 { |
4399 GstClock *clock; |
3107 GstClock *clock; |
4400 gboolean res = FALSE; |
3108 gboolean res = FALSE; |
4401 GstFormat oformat, tformat; |
3109 |
4402 GstClockTime now, base, latency; |
3110 switch (format) { |
4403 gint64 time, accum, duration; |
3111 /* we can answer time format */ |
4404 gdouble rate; |
3112 case GST_FORMAT_TIME: |
4405 gint64 last; |
3113 { |
4406 |
3114 GstClockTime now, base, latency; |
4407 GST_OBJECT_LOCK (basesink); |
3115 gint64 time, accum, duration; |
4408 /* our intermediate time format */ |
3116 gdouble rate; |
4409 tformat = GST_FORMAT_TIME; |
3117 gint64 last; |
4410 /* get the format in the segment */ |
3118 |
4411 oformat = basesink->segment.format; |
3119 GST_OBJECT_LOCK (basesink); |
4412 |
3120 |
4413 /* can only give answer based on the clock if not EOS */ |
3121 /* can only give answer based on the clock if not EOS */ |
4414 if (G_UNLIKELY (basesink->eos)) |
3122 if (G_UNLIKELY (basesink->eos)) |
4415 goto in_eos; |
3123 goto in_eos; |
4416 |
3124 |
4417 /* we can only get the segment when we are not NULL or READY */ |
3125 /* in PAUSE we cannot read from the clock so we |
4418 if (!basesink->have_newsegment) |
3126 * report time based on the last seen timestamp. */ |
4419 goto wrong_state; |
3127 if (GST_STATE (basesink) == GST_STATE_PAUSED) |
4420 |
3128 goto in_pause; |
4421 /* when not in PLAYING or when we're busy with a state change, we |
3129 |
4422 * cannot read from the clock so we report time based on the |
3130 /* We get position from clock only in PLAYING, we checked |
4423 * last seen timestamp. */ |
3131 * the PAUSED case above, so this is check is to test |
4424 if (GST_STATE (basesink) != GST_STATE_PLAYING || |
3132 * READY and NULL, where the position is always 0 */ |
4425 GST_STATE_PENDING (basesink) != GST_STATE_VOID_PENDING) |
3133 if (GST_STATE (basesink) != GST_STATE_PLAYING) |
4426 goto in_pause; |
3134 goto wrong_state; |
4427 |
3135 |
4428 /* we need to sync on the clock. */ |
3136 /* we need to sync on the clock. */ |
4429 if (basesink->sync == FALSE) |
3137 if (basesink->sync == FALSE) |
4430 goto no_sync; |
3138 goto no_sync; |
4431 |
3139 |
4432 /* and we need a clock */ |
3140 /* and we need a clock */ |
4433 if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL)) |
3141 if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL)) |
4434 goto no_sync; |
3142 goto no_sync; |
4435 |
3143 |
4436 /* collect all data we need holding the lock */ |
3144 /* collect all data we need holding the lock */ |
4437 if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time)) |
3145 if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time)) |
4438 time = basesink->segment.time; |
3146 time = basesink->segment.time; |
4439 else |
3147 else |
4440 time = 0; |
3148 time = 0; |
4441 |
3149 |
4442 if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop)) |
3150 if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop)) |
4443 duration = basesink->segment.stop - basesink->segment.start; |
3151 duration = basesink->segment.stop - basesink->segment.start; |
4444 else |
3152 else |
4445 duration = 0; |
3153 duration = 0; |
4446 |
3154 |
4447 base = GST_ELEMENT_CAST (basesink)->base_time; |
3155 base = GST_ELEMENT_CAST (basesink)->base_time; |
4448 accum = basesink->segment.accum; |
3156 accum = basesink->segment.accum; |
4449 rate = basesink->segment.rate * basesink->segment.applied_rate; |
3157 rate = basesink->segment.rate * basesink->segment.applied_rate; |
4450 latency = basesink->priv->latency; |
3158 gst_base_sink_get_position_last (basesink, &last); |
4451 |
3159 latency = basesink->priv->latency; |
4452 gst_object_ref (clock); |
3160 |
4453 |
3161 gst_object_ref (clock); |
4454 /* this function might release the LOCK */ |
3162 /* need to release the object lock before we can get the time, |
4455 gst_base_sink_get_position_last (basesink, format, &last); |
3163 * a clock might take the LOCK of the provider, which could be |
4456 |
3164 * a basesink subclass. */ |
4457 /* need to release the object lock before we can get the time, |
3165 GST_OBJECT_UNLOCK (basesink); |
4458 * a clock might take the LOCK of the provider, which could be |
3166 |
4459 * a basesink subclass. */ |
3167 now = gst_clock_get_time (clock); |
4460 GST_OBJECT_UNLOCK (basesink); |
3168 |
4461 |
3169 /* subtract base time and accumulated time from the clock time. |
4462 now = gst_clock_get_time (clock); |
3170 * Make sure we don't go negative. This is the current time in |
4463 |
3171 * the segment which we need to scale with the combined |
4464 if (oformat != tformat) { |
3172 * rate and applied rate. */ |
4465 /* convert accum, time and duration to time */ |
3173 base += accum; |
4466 if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat, |
3174 base += latency; |
4467 &accum)) |
3175 base = MIN (now, base); |
4468 goto convert_failed; |
3176 |
4469 if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration, &tformat, |
3177 /* for negative rates we need to count back from from the segment |
4470 &duration)) |
3178 * duration. */ |
4471 goto convert_failed; |
3179 if (rate < 0.0) |
4472 if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat, |
3180 time += duration; |
4473 &time)) |
3181 *cur = time + gst_guint64_to_gdouble (now - base) * rate; |
4474 goto convert_failed; |
3182 |
4475 } |
3183 /* never report more than last seen position */ |
4476 |
3184 if (last != -1) |
4477 /* subtract base time and accumulated time from the clock time. |
3185 *cur = MIN (last, *cur); |
4478 * Make sure we don't go negative. This is the current time in |
3186 |
4479 * the segment which we need to scale with the combined |
3187 gst_object_unref (clock); |
4480 * rate and applied rate. */ |
3188 |
4481 base += accum; |
3189 res = TRUE; |
4482 base += latency; |
3190 |
4483 base = MIN (now, base); |
3191 GST_DEBUG_OBJECT (basesink, |
4484 |
3192 "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %" |
4485 /* for negative rates we need to count back from from the segment |
3193 GST_TIME_FORMAT " + time %" GST_TIME_FORMAT, |
4486 * duration. */ |
3194 GST_TIME_ARGS (now), GST_TIME_ARGS (base), |
4487 if (rate < 0.0) |
3195 GST_TIME_ARGS (accum), GST_TIME_ARGS (time)); |
4488 time += duration; |
3196 break; |
4489 |
3197 } |
4490 *cur = time + gst_guint64_to_gdouble (now - base) * rate; |
3198 default: |
4491 |
3199 /* cannot answer other than TIME, we return FALSE, which will |
4492 /* never report more than last seen position */ |
3200 * send the query upstream. */ |
4493 if (last != -1) |
3201 break; |
4494 *cur = MIN (last, *cur); |
3202 } |
4495 |
|
4496 gst_object_unref (clock); |
|
4497 |
|
4498 GST_DEBUG_OBJECT (basesink, |
|
4499 "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %" |
|
4500 GST_TIME_FORMAT " + time %" GST_TIME_FORMAT, |
|
4501 GST_TIME_ARGS (now), GST_TIME_ARGS (base), |
|
4502 GST_TIME_ARGS (accum), GST_TIME_ARGS (time)); |
|
4503 |
|
4504 if (oformat != format) { |
|
4505 /* convert time to final format */ |
|
4506 if (!gst_pad_query_convert (basesink->sinkpad, tformat, *cur, &format, cur)) |
|
4507 goto convert_failed; |
|
4508 } |
|
4509 |
|
4510 res = TRUE; |
|
4511 |
3203 |
4512 done: |
3204 done: |
4513 GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT, |
3205 GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT, |
4514 res, GST_TIME_ARGS (*cur)); |
3206 res, GST_TIME_ARGS (*cur)); |
4515 return res; |
3207 return res; |
4516 |
3208 |
4517 /* special cases */ |
3209 /* special cases */ |
4518 in_eos: |
3210 in_eos: |
4519 { |
3211 { |
4520 GST_DEBUG_OBJECT (basesink, "position in EOS"); |
3212 GST_DEBUG_OBJECT (basesink, "position in EOS"); |
4521 res = gst_base_sink_get_position_last (basesink, format, cur); |
3213 res = gst_base_sink_get_position_last (basesink, cur); |
4522 GST_OBJECT_UNLOCK (basesink); |
3214 GST_OBJECT_UNLOCK (basesink); |
4523 goto done; |
3215 goto done; |
4524 } |
3216 } |
4525 in_pause: |
3217 in_pause: |
4526 { |
3218 { |
4527 GST_DEBUG_OBJECT (basesink, "position in PAUSED"); |
3219 GST_DEBUG_OBJECT (basesink, "position in PAUSED"); |
4528 res = gst_base_sink_get_position_paused (basesink, format, cur); |
3220 res = gst_base_sink_get_position_paused (basesink, cur); |
4529 GST_OBJECT_UNLOCK (basesink); |
3221 GST_OBJECT_UNLOCK (basesink); |
4530 goto done; |
3222 goto done; |
4531 } |
3223 } |
4532 wrong_state: |
3224 wrong_state: |
4533 { |
3225 { |
4534 /* in NULL or READY we always return FALSE and -1 */ |
3226 /* in NULL or READY we always return 0 */ |
4535 GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1"); |
3227 GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1"); |
4536 res = FALSE; |
3228 res = FALSE; |
4537 *cur = -1; |
3229 *cur = -1; |
4538 GST_OBJECT_UNLOCK (basesink); |
3230 GST_OBJECT_UNLOCK (basesink); |
4539 goto done; |
3231 goto done; |
4540 } |
3232 } |
4541 no_sync: |
3233 no_sync: |
4542 { |
3234 { |
4543 /* report last seen timestamp if any, else ask upstream to answer */ |
3235 /* report last seen timestamp if any, else return FALSE so |
3236 * that upstream can answer */ |
|
4544 if ((*cur = basesink->priv->current_sstart) != -1) |
3237 if ((*cur = basesink->priv->current_sstart) != -1) |
4545 res = TRUE; |
3238 res = TRUE; |
4546 else |
|
4547 *upstream = TRUE; |
|
4548 |
|
4549 GST_DEBUG_OBJECT (basesink, "no sync, res %d, POSITION %" GST_TIME_FORMAT, |
3239 GST_DEBUG_OBJECT (basesink, "no sync, res %d, POSITION %" GST_TIME_FORMAT, |
4550 res, GST_TIME_ARGS (*cur)); |
3240 res, GST_TIME_ARGS (*cur)); |
4551 GST_OBJECT_UNLOCK (basesink); |
3241 GST_OBJECT_UNLOCK (basesink); |
4552 return res; |
3242 return res; |
4553 } |
|
4554 convert_failed: |
|
4555 { |
|
4556 GST_DEBUG_OBJECT (basesink, "convert failed, try upstream"); |
|
4557 *upstream = TRUE; |
|
4558 return FALSE; |
|
4559 } |
3243 } |
4560 } |
3244 } |
4561 |
3245 |
4562 static gboolean |
3246 static gboolean |
4563 gst_base_sink_query (GstElement * element, GstQuery * query) |
3247 gst_base_sink_query (GstElement * element, GstQuery * query) |
4569 switch (GST_QUERY_TYPE (query)) { |
3253 switch (GST_QUERY_TYPE (query)) { |
4570 case GST_QUERY_POSITION: |
3254 case GST_QUERY_POSITION: |
4571 { |
3255 { |
4572 gint64 cur = 0; |
3256 gint64 cur = 0; |
4573 GstFormat format; |
3257 GstFormat format; |
4574 gboolean upstream = FALSE; |
|
4575 |
3258 |
4576 gst_query_parse_position (query, &format, NULL); |
3259 gst_query_parse_position (query, &format, NULL); |
4577 |
3260 |
4578 GST_DEBUG_OBJECT (basesink, "position format %d", format); |
3261 GST_DEBUG_OBJECT (basesink, "position format %d", format); |
4579 |
3262 |
4580 /* first try to get the position based on the clock */ |
3263 /* first try to get the position based on the clock */ |
4581 if ((res = |
3264 if ((res = gst_base_sink_get_position (basesink, format, &cur))) { |
4582 gst_base_sink_get_position (basesink, format, &cur, &upstream))) { |
|
4583 gst_query_set_position (query, format, cur); |
3265 gst_query_set_position (query, format, cur); |
4584 } else if (upstream) { |
3266 } else { |
4585 /* fallback to peer query */ |
3267 /* fallback to peer query */ |
4586 res = gst_base_sink_peer_query (basesink, query); |
3268 res = gst_base_sink_peer_query (basesink, query); |
4587 } |
3269 } |
4588 break; |
3270 break; |
4589 } |
3271 } |
4590 case GST_QUERY_DURATION: |
3272 case GST_QUERY_DURATION: |
4591 { |
3273 GST_DEBUG_OBJECT (basesink, "duration query"); |
4592 GstFormat format, uformat; |
3274 res = gst_base_sink_peer_query (basesink, query); |
4593 gint64 duration, uduration; |
3275 break; |
4594 |
|
4595 gst_query_parse_duration (query, &format, NULL); |
|
4596 |
|
4597 GST_DEBUG_OBJECT (basesink, "duration query in format %s", |
|
4598 gst_format_get_name (format)); |
|
4599 |
|
4600 if (basesink->pad_mode == GST_ACTIVATE_PULL) { |
|
4601 uformat = GST_FORMAT_BYTES; |
|
4602 |
|
4603 /* get the duration in bytes, in pull mode that's all we are sure to |
|
4604 * know. We have to explicitly get this value from upstream instead of |
|
4605 * using our cached value because it might change. Duration caching |
|
4606 * should be done at a higher level. */ |
|
4607 res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, |
|
4608 &uduration); |
|
4609 if (res) { |
|
4610 gst_segment_set_duration (&basesink->segment, uformat, uduration); |
|
4611 if (format != uformat) { |
|
4612 /* convert to the requested format */ |
|
4613 res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration, |
|
4614 &format, &duration); |
|
4615 } else { |
|
4616 duration = uduration; |
|
4617 } |
|
4618 if (res) { |
|
4619 /* set the result */ |
|
4620 gst_query_set_duration (query, format, duration); |
|
4621 } |
|
4622 } |
|
4623 } else { |
|
4624 /* in push mode we simply forward upstream */ |
|
4625 res = gst_base_sink_peer_query (basesink, query); |
|
4626 } |
|
4627 break; |
|
4628 } |
|
4629 case GST_QUERY_LATENCY: |
3276 case GST_QUERY_LATENCY: |
4630 { |
3277 { |
4631 gboolean live, us_live; |
3278 gboolean live, us_live; |
4632 GstClockTime min, max; |
3279 GstClockTime min, max; |
4633 |
3280 |
4681 case GST_STATE_CHANGE_READY_TO_PAUSED: |
3328 case GST_STATE_CHANGE_READY_TO_PAUSED: |
4682 /* need to complete preroll before this state change completes, there |
3329 /* need to complete preroll before this state change completes, there |
4683 * is no data flow in READY so we can safely assume we need to preroll. */ |
3330 * is no data flow in READY so we can safely assume we need to preroll. */ |
4684 GST_PAD_PREROLL_LOCK (basesink->sinkpad); |
3331 GST_PAD_PREROLL_LOCK (basesink->sinkpad); |
4685 GST_DEBUG_OBJECT (basesink, "READY to PAUSED"); |
3332 GST_DEBUG_OBJECT (basesink, "READY to PAUSED"); |
4686 basesink->have_newsegment = FALSE; |
|
4687 gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); |
3333 gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); |
4688 gst_segment_init (basesink->abidata.ABI.clip_segment, |
3334 gst_segment_init (basesink->abidata.ABI.clip_segment, |
4689 GST_FORMAT_UNDEFINED); |
3335 GST_FORMAT_UNDEFINED); |
3336 basesink->have_newsegment = FALSE; |
|
4690 basesink->offset = 0; |
3337 basesink->offset = 0; |
4691 basesink->have_preroll = FALSE; |
3338 basesink->have_preroll = FALSE; |
4692 priv->step_unlock = FALSE; |
|
4693 basesink->need_preroll = TRUE; |
3339 basesink->need_preroll = TRUE; |
4694 basesink->playing_async = TRUE; |
3340 basesink->playing_async = TRUE; |
4695 priv->current_sstart = -1; |
3341 priv->current_sstart = -1; |
4696 priv->current_sstop = -1; |
3342 priv->current_sstop = -1; |
4697 priv->eos_rtime = -1; |
3343 priv->eos_rtime = -1; |
4698 priv->latency = 0; |
3344 priv->latency = 0; |
4699 basesink->eos = FALSE; |
3345 basesink->eos = FALSE; |
4700 priv->received_eos = FALSE; |
3346 priv->received_eos = FALSE; |
4701 gst_base_sink_reset_qos (basesink); |
3347 gst_base_sink_reset_qos (basesink); |
4702 priv->commited = FALSE; |
3348 priv->commited = FALSE; |
4703 priv->call_preroll = TRUE; |
|
4704 priv->current_step.valid = FALSE; |
|
4705 priv->pending_step.valid = FALSE; |
|
4706 if (priv->async_enabled) { |
3349 if (priv->async_enabled) { |
4707 GST_DEBUG_OBJECT (basesink, "doing async state change"); |
3350 GST_DEBUG_OBJECT (basesink, "doing async state change"); |
4708 /* when async enabled, post async-start message and return ASYNC from |
3351 /* when async enabled, post async-start message and return ASYNC from |
4709 * the state change function */ |
3352 * the state change function */ |
4710 ret = GST_STATE_CHANGE_ASYNC; |
3353 ret = GST_STATE_CHANGE_ASYNC; |
4721 GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll"); |
3364 GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll"); |
4722 /* no preroll needed anymore now. */ |
3365 /* no preroll needed anymore now. */ |
4723 basesink->playing_async = FALSE; |
3366 basesink->playing_async = FALSE; |
4724 basesink->need_preroll = FALSE; |
3367 basesink->need_preroll = FALSE; |
4725 if (basesink->eos) { |
3368 if (basesink->eos) { |
4726 GstMessage *message; |
|
4727 |
|
4728 /* need to post EOS message here */ |
3369 /* need to post EOS message here */ |
4729 GST_DEBUG_OBJECT (basesink, "Now posting EOS"); |
3370 GST_DEBUG_OBJECT (basesink, "Now posting EOS"); |
4730 message = gst_message_new_eos (GST_OBJECT_CAST (basesink)); |
3371 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
4731 gst_message_set_seqnum (message, basesink->priv->seqnum); |
3372 gst_message_new_eos (GST_OBJECT_CAST (basesink))); |
4732 gst_element_post_message (GST_ELEMENT_CAST (basesink), message); |
|
4733 } else { |
3373 } else { |
4734 GST_DEBUG_OBJECT (basesink, "signal preroll"); |
3374 GST_DEBUG_OBJECT (basesink, "signal preroll"); |
4735 GST_PAD_PREROLL_SIGNAL (basesink->sinkpad); |
3375 GST_PAD_PREROLL_SIGNAL (basesink->sinkpad); |
4736 } |
3376 } |
4737 } else { |
3377 } else { |
4738 GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled"); |
3378 GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled"); |
4739 basesink->need_preroll = TRUE; |
3379 basesink->need_preroll = TRUE; |
4740 basesink->playing_async = TRUE; |
3380 basesink->playing_async = TRUE; |
4741 priv->call_preroll = TRUE; |
|
4742 priv->commited = FALSE; |
3381 priv->commited = FALSE; |
4743 if (priv->async_enabled) { |
3382 if (priv->async_enabled) { |
4744 GST_DEBUG_OBJECT (basesink, "doing async state change"); |
3383 GST_DEBUG_OBJECT (basesink, "doing async state change"); |
4745 ret = GST_STATE_CHANGE_ASYNC; |
3384 ret = GST_STATE_CHANGE_ASYNC; |
4746 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
3385 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
4760 if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE)) |
3399 if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE)) |
4761 goto activate_failed; |
3400 goto activate_failed; |
4762 } |
3401 } |
4763 |
3402 |
4764 switch (transition) { |
3403 switch (transition) { |
3404 case GST_STATE_CHANGE_READY_TO_PAUSED: |
|
3405 /* note that this is the upward case, which doesn't follow most |
|
3406 patterns */ |
|
3407 if (basesink->pad_mode == GST_ACTIVATE_PULL) { |
|
3408 GST_DEBUG_OBJECT (basesink, "basesink activated in pull mode, " |
|
3409 "returning SUCCESS directly"); |
|
3410 GST_PAD_PREROLL_LOCK (basesink->sinkpad); |
|
3411 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
|
3412 gst_message_new_async_done (GST_OBJECT_CAST (basesink))); |
|
3413 GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); |
|
3414 ret = GST_STATE_CHANGE_SUCCESS; |
|
3415 } |
|
3416 break; |
|
4765 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
3417 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
4766 GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED"); |
3418 GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED"); |
4767 /* FIXME, make sure we cannot enter _render first */ |
3419 /* FIXME, make sure we cannot enter _render first */ |
4768 |
3420 |
4769 /* we need to call ::unlock before locking PREROLL_LOCK |
3421 /* we need to call ::unlock before locking PREROLL_LOCK |
4796 } else { |
3448 } else { |
4797 GST_DEBUG_OBJECT (basesink, |
3449 GST_DEBUG_OBJECT (basesink, |
4798 "PLAYING to PAUSED, we are not prerolled"); |
3450 "PLAYING to PAUSED, we are not prerolled"); |
4799 basesink->playing_async = TRUE; |
3451 basesink->playing_async = TRUE; |
4800 priv->commited = FALSE; |
3452 priv->commited = FALSE; |
4801 priv->call_preroll = TRUE; |
|
4802 if (priv->async_enabled) { |
3453 if (priv->async_enabled) { |
4803 GST_DEBUG_OBJECT (basesink, "doing async state change"); |
3454 GST_DEBUG_OBJECT (basesink, "doing async state change"); |
4804 ret = GST_STATE_CHANGE_ASYNC; |
3455 ret = GST_STATE_CHANGE_ASYNC; |
4805 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
3456 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
4806 gst_message_new_async_start (GST_OBJECT_CAST (basesink), |
3457 gst_message_new_async_start (GST_OBJECT_CAST (basesink), |
4814 gst_base_sink_reset_qos (basesink); |
3465 gst_base_sink_reset_qos (basesink); |
4815 GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); |
3466 GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); |
4816 break; |
3467 break; |
4817 case GST_STATE_CHANGE_PAUSED_TO_READY: |
3468 case GST_STATE_CHANGE_PAUSED_TO_READY: |
4818 GST_PAD_PREROLL_LOCK (basesink->sinkpad); |
3469 GST_PAD_PREROLL_LOCK (basesink->sinkpad); |
4819 /* start by reseting our position state with the object lock so that the |
|
4820 * position query gets the right idea. We do this before we post the |
|
4821 * messages so that the message handlers pick this up. */ |
|
4822 GST_OBJECT_LOCK (basesink); |
|
4823 basesink->have_newsegment = FALSE; |
|
4824 priv->current_sstart = -1; |
|
4825 priv->current_sstop = -1; |
|
4826 priv->have_latency = FALSE; |
|
4827 GST_OBJECT_UNLOCK (basesink); |
|
4828 |
|
4829 gst_base_sink_set_last_buffer (basesink, NULL); |
|
4830 priv->call_preroll = FALSE; |
|
4831 |
|
4832 if (!priv->commited) { |
3470 if (!priv->commited) { |
4833 if (priv->async_enabled) { |
3471 if (priv->async_enabled) { |
4834 GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done"); |
3472 GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done"); |
4835 |
3473 |
4836 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
3474 gst_element_post_message (GST_ELEMENT_CAST (basesink), |
4842 } |
3480 } |
4843 priv->commited = TRUE; |
3481 priv->commited = TRUE; |
4844 } else { |
3482 } else { |
4845 GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll"); |
3483 GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll"); |
4846 } |
3484 } |
3485 priv->current_sstart = -1; |
|
3486 priv->current_sstop = -1; |
|
3487 priv->have_latency = FALSE; |
|
3488 gst_base_sink_set_last_buffer (basesink, NULL); |
|
4847 GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); |
3489 GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); |
4848 break; |
3490 break; |
4849 case GST_STATE_CHANGE_READY_TO_NULL: |
3491 case GST_STATE_CHANGE_READY_TO_NULL: |
4850 if (bclass->stop) { |
3492 if (bclass->stop) { |
4851 if (!bclass->stop (basesink)) { |
3493 if (!bclass->stop (basesink)) { |
4852 GST_WARNING_OBJECT (basesink, "failed to stop"); |
3494 GST_WARNING_OBJECT (basesink, "failed to stop"); |
4853 } |
3495 } |
4854 } |
3496 } |
4855 gst_base_sink_set_last_buffer (basesink, NULL); |
3497 gst_base_sink_set_last_buffer (basesink, NULL); |
4856 priv->call_preroll = FALSE; |
|
4857 break; |
3498 break; |
4858 default: |
3499 default: |
4859 break; |
3500 break; |
4860 } |
3501 } |
4861 |
3502 |