After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 738285 - playbin: Sequential playback of the file list does not work
playbin: Sequential playback of the file list does not work
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gst-plugins-base
git master
Other Linux
: Normal normal
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2014-10-10 10:38 UTC by Andrei Sarakeev
Modified: 2018-05-05 15:37 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
for inspect (1.85 KB, patch)
2014-10-10 10:38 UTC, Andrei Sarakeev
rejected Details | Review
log (508.26 KB, text/plain)
2014-10-10 10:39 UTC, Andrei Sarakeev
  Details
patch (2.68 KB, patch)
2014-10-14 08:39 UTC, Andrei Sarakeev
none Details | Review
patch (846 bytes, patch)
2014-10-14 08:44 UTC, Andrei Sarakeev
none Details | Review
patch (2.42 KB, patch)
2014-10-15 12:12 UTC, Andrei Sarakeev
none Details | Review
patch 2 (1.97 KB, patch)
2014-10-20 07:22 UTC, Andrei Sarakeev
needs-work Details | Review
fix (2.55 KB, patch)
2014-10-20 11:45 UTC, Andrei Sarakeev
needs-work Details | Review
fix (5.18 KB, patch)
2014-10-21 06:03 UTC, Andrei Sarakeev
needs-work Details | Review
fix (1.65 KB, patch)
2014-10-21 10:17 UTC, Andrei Sarakeev
none Details | Review
fix (1.68 KB, patch)
2014-10-21 10:27 UTC, Andrei Sarakeev
needs-work Details | Review
graph pulsesink (142.20 KB, image/png)
2014-10-22 09:42 UTC, Andrei Sarakeev
  Details
graph alsasink (146.19 KB, image/png)
2014-10-22 09:43 UTC, Andrei Sarakeev
  Details
pulsesink log (23.78 KB, text/x-log)
2014-10-22 09:56 UTC, Andrei Sarakeev
  Details
fix input-selector (1.74 KB, patch)
2014-10-23 10:17 UTC, Andrei Sarakeev
none Details | Review
fix input-selectoe (956 bytes, patch)
2014-10-23 10:20 UTC, Andrei Sarakeev
none Details | Review
fix pending eos (3.44 KB, patch)
2014-10-24 05:08 UTC, Andrei Sarakeev
none Details | Review
fix pending eos (3.47 KB, patch)
2014-10-24 05:19 UTC, Andrei Sarakeev
none Details | Review
fix pending eos (3.75 KB, patch)
2014-10-24 05:41 UTC, Andrei Sarakeev
needs-work Details | Review
fix (3.67 KB, patch)
2014-10-24 08:22 UTC, Andrei Sarakeev
none Details | Review
fix (8.33 KB, patch)
2014-10-24 12:02 UTC, Andrei Sarakeev
none Details | Review
fix and new tests (17.50 KB, patch)
2014-10-30 10:05 UTC, Andrei Sarakeev
needs-work Details | Review
fix and new tests (20.42 KB, patch)
2014-11-06 07:30 UTC, Andrei Sarakeev
none Details | Review

Description Andrei Sarakeev 2014-10-10 10:38:11 UTC
Created attachment 288200 [details] [review]
for inspect

simple example (Sequential playback of the file list):
== start ========================================
static GMainLoop *loop;
static gint index = 0;
static gchar* list[] = {
  "media_uri_1",
  "media_uri_2",
  NULL
  };

static void
play_next(GObject *playbin, gpointer user_data)
{
  const gchar *next = list[++index];
  if (next == NULL) {
      g_main_loop_quit (loop);
  }
  g_object_set(playbin, "uri", next, NULL);
}


int main()
{
  ...
 
  GstElement *playbin = gst_element_factory_make("playbin", "playbin");
  g_signal_connect(G_OBJECT(playbin), "about-to-finish", (GCallback)play_next, NULL);
  g_object_set(G_OBJECT(playbin), "uri", list[index], NULL);
  gst_element_set_state(playbin, GST_STATE_PLAYING);
 
  ...
}
== end =========================================

To make it easier to explain, apply example.patch from attachment

View log from attachemt:

line 1540 (EOS from audio):
0:00:09.175147876 gstdecodebin2.c:4475:source_pad_event_probe:<decodebin0:src_1> we received EOS

line 1551 (inspect result EOS event):
0:00:09.175320269 gstdecodebin2.c:4632:gst_decode_pad_event:<decodebin0:src_1> EOS result: unknown, 1

Why 'unknown'?

This EOS event will be sticked (result != GST_FLOW_OK)! 

line 1601 (EOS from video):
0:00:10.165434115 gstdecodebin2.c:4475:source_pad_event_probe:<decodebin0:src_0> we received EOS

line 1623 (inspect result EOS event, all right)
0:00:10.168051241 gstdecodebin2.c:4632:gst_decode_pad_event:<decodebin0:src_0> EOS result: ok, 0

PLAY next file
call 'setup_next_source' form gstplaybin2.c

line 1796 (reconfiguring & unblocking):
0:00:10.194371416 gstplaysink.c:3181:gst_play_sink_do_reconfigure:<playsink> reconfiguring

line 1809 ... (audio pad):
0:00:10.199289077 gstdecodebin2.c:4616:gst_decode_pad_chain:<decodebin1:src_1> Buffer 0:00:00.000000000
0:00:10.199311819 gstdecodebin2.c:4618:gst_decode_pad_chain:<decodebin1:src_1> push result eos
0:00:10.199517290 gstdecodebin2.c:4616:gst_decode_pad_chain:<decodebin1:src_1> Buffer 0:00:00.024000000
0:00:10.199599560 gstdecodebin2.c:4618:gst_decode_pad_chain:<decodebin1:src_1> push result eos
0:00:10.199842973 gstdecodebin2.c:4616:gst_decode_pad_chain:<decodebin1:src_1> Buffer 0:00:00.048000000
0:00:10.199894467 gstdecodebin2.c:4618:gst_decode_pad_chain:<decodebin1:src_1> push result eos
...

EOS sticky

line 2655:
0:00:10.335347188 gststreamsynchronizer.c:348:gst_stream_synchronizer_sink_event:<streamsynchronizer0:sink_0> Stream 0 is waiting

finish
Comment 1 Andrei Sarakeev 2014-10-10 10:39:30 UTC
Created attachment 288201 [details]
log

log
Comment 2 Tim-Philipp Müller 2014-10-10 10:52:51 UTC
Does it work with gst-play-1.0 ?
Comment 3 Andrei Sarakeev 2014-10-10 11:14:56 UTC
use gstreamer from git.
https://bugzilla.gnome.org/show_bug.cgi?id=738064
The drained signal must be fixed.
Comment 4 Andrei Sarakeev 2014-10-10 12:46:34 UTC
gst-play-1.0 media1 media2 --gapless
Comment 5 Andrei Sarakeev 2014-10-14 08:39:39 UTC
Created attachment 288495 [details] [review]
patch

My reasoning above were wrong.
playsink->audio_tee_sink and all downstream pads have GST_PAD_FLAG_EOS.
I do not know the correct solution, but sending flush_stop event solves the problem.
Comment 6 Andrei Sarakeev 2014-10-14 08:44:26 UTC
Created attachment 288496 [details] [review]
patch

My reasoning above were wrong.
playsink->audio_tee_sink and all downstream pads have GST_PAD_FLAG_EOS.
I do not know the correct solution, but sending flush_stop event solves the
problem.
Comment 7 Sebastian Dröge (slomo) 2014-10-14 08:55:49 UTC
Sending flush-events here is wrong. There should not be an EOS event forwarded at all in this case. You'll have to check why decodebin does not wait for all streams to produce an EOS event before forwarding it. That's somewhere around the drained signal code you already know :)
Comment 8 Andrei Sarakeev 2014-10-15 12:12:05 UTC
Created attachment 288574 [details] [review]
patch

Yet another attempt
Comment 9 Andrei Sarakeev 2014-10-20 07:22:22 UTC
Created attachment 288885 [details] [review]
patch 2

wait until all chains are drained
Comment 10 Sebastian Dröge (slomo) 2014-10-20 11:15:18 UTC
Review of attachment 288885 [details] [review]:

::: gst/playback/gstdecodebin2.c
@@ +3752,2 @@
     g_signal_emit (dbin, gst_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
+    g_cond_broadcast (&dbin->all_eos_cond);

You should use a mutex here (the object lock), and also store the information that we're all-eos now...

@@ +3782,3 @@
+  if (last_group && !drained) {
+    GST_OBJECT_LOCK (dbin);
+    g_cond_wait (&dbin->all_eos_cond, GST_OBJECT_GET_LOCK (dbin));

... and here check after locking before g_cond_wait() if all are EOS already. Otherwise you have a race condition here.

Also note that g_cond_wait() can be triggered spuriously under certain conditions, so you need a loop like

while (not_all_eos) g_cond_wait();
Comment 11 Andrei Sarakeev 2014-10-20 11:45:55 UTC
Created attachment 288921 [details] [review]
fix

Thanks for the review. I was a windows programmer
Comment 12 Sebastian Dröge (slomo) 2014-10-20 12:13:12 UTC
Review of attachment 288921 [details] [review]:

Thanks for updating the patch :)

::: gst/playback/gstdecodebin2.c
@@ +3787,3 @@
+    GST_OBJECT_LOCK (dbin);
+    while (!dbin->all_eos)
+      g_cond_wait (&dbin->all_eos_cond, GST_OBJECT_GET_LOCK (dbin));

This here needs to unlock on FLUSH_START events, and when going from PAUSED to READY state (before chaining up to the parent class' change_state implementation)

@@ +4781,3 @@
       DYN_UNLOCK (dbin);
       dbin->have_type = FALSE;
+      dbin->all_eos = FALSE;

The condition variable should probably also be reset on FLUSH_STOP
Comment 13 Andrei Sarakeev 2014-10-21 06:03:12 UTC
Created attachment 289005 [details] [review]
fix
Comment 14 Andrei Sarakeev 2014-10-21 09:01:04 UTC
New problem.
if audio disabled (flags=1) => deadlock.

multiqueue wait eos from video

1544      if (mq->numwaiting > 0 && sq->srcresult == GST_FLOW_EOS) {
1545	    compute_high_time (mq);
1546	    compute_high_id (mq);
1547	    wake_up_next_non_linked (mq);
1548	  }

video wait eos form not-linked audio (all_eos)
Comment 15 Sebastian Dröge (slomo) 2014-10-21 09:01:22 UTC
Review of attachment 289005 [details] [review]:

::: gst/playback/gstdecodebin2.c
@@ +3754,2 @@
     g_signal_emit (dbin, gst_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
+    DYN_LOCK (dbin);

Why do you switch to the DYN_LOCK from the OBJECT_LOCK?

@@ +4515,3 @@
+    case GST_EVENT_FLUSH_STOP:
+      DYN_LOCK (dbin);
+      dbin->flushing = FALSE;

Flushing is per pad, not globally
Comment 16 Andrei Sarakeev 2014-10-21 09:06:21 UTC
DYN_LOCK used for dbin->shutdown
Comment 17 Andrei Sarakeev 2014-10-21 09:10:58 UTC
Why not propably use a list eos_pending_pads from my first patch to send pending eos?
Comment 18 Sebastian Dröge (slomo) 2014-10-21 09:20:09 UTC
It seems not necessary for EOS, but for flushing you need to store the flushing state per pad (just store it inside the pad!)
Comment 19 Andrei Sarakeev 2014-10-21 09:22:56 UTC
https://bugzilla.gnome.org/show_bug.cgi?id=738285#c14
Did you read comment 14?
Comment 20 Sebastian Dröge (slomo) 2014-10-21 09:32:51 UTC
Ah, I missed that indeed. Yes, why not just remember which pads are EOS instead of blocking... and once all are EOS send an EOS event on all of them. That should solve all these problems and actually simplify the code.

You don't have to store the EOS state in a list though, it's already stored elsewhere in decodebin in the decode chain or decode pad IIRC.
Comment 21 Andrei Sarakeev 2014-10-21 10:17:48 UTC
Created attachment 289012 [details] [review]
fix
Comment 22 Andrei Sarakeev 2014-10-21 10:27:28 UTC
Created attachment 289013 [details] [review]
fix
Comment 23 Andrei Sarakeev 2014-10-21 10:44:00 UTC
The problem remains:

gst-play-1.0 --gapless only_video.avi audio_and_video.avi

Almost always after the first media without audio, the following media with audio does not play.Your suggestions.
Comment 24 Sebastian Dröge (slomo) 2014-10-21 11:18:19 UTC
Not sure and I don't have time to debug that myself right now. What exactly happens after the first has finished?

And is your fix fixing anything at all then?
Comment 25 Andrei Sarakeev 2014-10-21 11:30:58 UTC
fix should be commited.
I will try to find a solution
Comment 26 Sebastian Dröge (slomo) 2014-10-21 11:35:59 UTC
Well, what exactly does it fix? :)

As I see it, it would prevent sending EOS downstream while there are still unfinished chains... because otherwise e.g. the audio sink might go to EOS already, then we send the drained signal, then we switch to a next track. And then nothing works anymore because the audio sink is already done.
Comment 27 Andrei Sarakeev 2014-10-21 11:41:34 UTC
all right. EOS after drained signal.
fix works.
maybe error in streamsynchronizer.
Comment 28 Andrei Sarakeev 2014-10-21 11:45:14 UTC
There are several problems. fix solves one
Comment 29 Andrei Sarakeev 2014-10-22 09:42:25 UTC
Created attachment 289112 [details]
graph pulsesink

Comment 23. maybe bug in pulsesink. If use alsasink instead pulsesink then all well.
Comment 30 Andrei Sarakeev 2014-10-22 09:43:09 UTC
Created attachment 289113 [details]
graph alsasink
Comment 31 Andrei Sarakeev 2014-10-22 09:56:33 UTC
Created attachment 289114 [details]
pulsesink log

GST_DEBUG=pulse:6 gst-play-1.0 --gapless noaudio.avi media.avi 2>pulse.log
Comment 32 Andrei Sarakeev 2014-10-22 11:22:30 UTC
pulsesink.c

/* called from pulse thread with the mainloop lock */
static void
mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
{
  GstPulseSink *pulsesink = GST_PULSESINK (userdata);
  GstMessage *message;
  GValue val = { 0 };

  GST_DEBUG_OBJECT (pulsesink, "posting ENTER stream status");
  message = gst_message_new_stream_status (GST_OBJECT (pulsesink),
      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT (pulsesink));
  g_value_init (&val, GST_TYPE_G_THREAD);
  g_value_set_boxed (&val, g_thread_self ());
  gst_message_set_stream_status_object (message, &val);
  g_value_unset (&val);

  gst_element_post_message (GST_ELEMENT (pulsesink), message);
================================

  g_return_if_fail (pulsesink->defer_pending);
  pulsesink->defer_pending--;
  pa_threaded_mainloop_signal (mainloop, 0);
}

"gst_element_post_message" function is called and the execution stops, therefore the "pa_threaded_mainloop_signal" function call was not occur.
Sorry for my bad English
Comment 33 Andrei Sarakeev 2014-10-22 12:20:38 UTC
This is deadlock, "gst_element_post_message" try lock mutex GST_OBJECT_GET_LOCK is already locked by another thread.
I need help! I need to play files sequentially.
Comment 34 Sebastian Dröge (slomo) 2014-10-22 12:30:03 UTC
The pulsesink deadlock is unrelated and is bug #736071
Comment 35 Andrei Sarakeev 2014-10-22 12:43:20 UTC
If cancel the #736071 fix, everything works
Comment 36 Sebastian Dröge (slomo) 2014-10-22 12:45:45 UTC
You mean with the patch remaining in this bug, and the pulsesink related fix everything works for you and there's nothing left to be fixed?
Comment 37 Andrei Sarakeev 2014-10-22 12:47:06 UTC
Yes, if commit my patch and cancel #736071 fix, everything works
Comment 38 Sebastian Dröge (slomo) 2014-10-22 13:16:33 UTC
Comment on attachment 289013 [details] [review]
fix

While this looks good, it causes a deadlock in the playbin-complex test.

You can run it with
make elements/playbin-complex.check
in tests/check



Thread 26 (Thread 0x7fffed598700 (LWP 23773))

  • #0 syscall
    at ../sysdeps/unix/sysv/linux/x86_64/syscall.S line 38
  • #1 g_cond_wait
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread-posix.c line 1396
  • #2 gst_queue_loop
    at gstqueue.c line 1299
  • #3 gst_task_func
    at gsttask.c line 317
  • #4 g_thread_pool_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthreadpool.c line 307
  • #5 g_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread.c line 764
  • #6 start_thread
    at pthread_create.c line 309
  • #7 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 111

Thread 25 (Thread 0x7fffee59a700 (LWP 23772))

  • #0 syscall
    at ../sysdeps/unix/sysv/linux/x86_64/syscall.S line 38
  • #1 g_cond_wait
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread-posix.c line 1396
  • #2 gst_input_selector_wait_running_time
    at gstinputselector.c line 755
  • #3 gst_selector_pad_chain
    at gstinputselector.c line 1018
  • #4 gst_pad_chain_data_unchecked
    at gstpad.c line 3836
  • #5 gst_pad_push_data
    at gstpad.c line 4069
  • #6 gst_proxy_pad_chain_default
    at gstghostpad.c line 126
  • #7 gst_pad_chain_data_unchecked
    at gstpad.c line 3836
  • #8 gst_pad_push_data
    at gstpad.c line 4069
  • #9 gst_proxy_pad_chain_default
    at gstghostpad.c line 126
  • #10 gst_pad_chain_data_unchecked
    at gstpad.c line 3836
  • #11 gst_pad_push_data
    at gstpad.c line 4069
  • #12 gst_single_queue_push_one
    at gstmultiqueue.c line 1233
  • #13 gst_multi_queue_loop
    at gstmultiqueue.c line 1488
  • #14 gst_task_func
    at gsttask.c line 317
  • #15 g_thread_pool_thread_proxy
  • #16 g_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread.c line 764
  • #17 start_thread
    at pthread_create.c line 309
  • #18 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 111

Thread 24 (Thread 0x7fffedd99700 (LWP 23771))

  • #0 syscall
    at ../sysdeps/unix/sysv/linux/x86_64/syscall.S line 38
  • #1 g_cond_wait
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread-posix.c line 1396
  • #2 _gst_data_queue_wait_non_empty
    at gstdataqueue.c line 552
  • #3 gst_data_queue_pop
    at gstdataqueue.c line 594
  • #4 gst_multi_queue_loop
    at gstmultiqueue.c line 1368
  • #5 gst_task_func
    at gsttask.c line 317
  • #6 g_thread_pool_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthreadpool.c line 307
  • #7 g_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread.c line 764
  • #8 start_thread
    at pthread_create.c line 309
  • #9 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 111

Thread 23 (Thread 0x7ffff4b42700 (LWP 23770))

  • #0 syscall
    at ../sysdeps/unix/sysv/linux/x86_64/syscall.S line 38
  • #1 g_cond_wait
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread-posix.c line 1396
  • #2 gst_task_func
    at gsttask.c line 302
  • #3 g_thread_pool_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthreadpool.c line 307
  • #4 g_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread.c line 764
  • #5 start_thread
    at pthread_create.c line 309
  • #6 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 111

Thread 4 (Thread 0x7fffef5d9700 (LWP 23751))

  • #0 syscall
    at ../sysdeps/unix/sysv/linux/x86_64/syscall.S line 38
  • #1 g_cond_wait_until
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread-posix.c line 1443
  • #2 g_async_queue_pop_intern_unlocked
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gasyncqueue.c line 422
  • #3 g_async_queue_timeout_pop
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gasyncqueue.c line 543
  • #4 g_thread_pool_wait_for_new_pool
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthreadpool.c line 167
  • #5 g_thread_pool_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthreadpool.c line 364
  • #6 g_thread_proxy
    at /build/glib2.0-dt6trg/glib2.0-2.42.0/./glib/gthread.c line 764
  • #7 start_thread
    at pthread_create.c line 309
  • #8 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 111

Comment 39 Andrei Sarakeev 2014-10-23 09:28:28 UTC
Pause caused by the input-selector. The two audio streams connected to it. When the active stream ends (but the EOS was not sent), non-linked stream not dispatch buffer.
Comment 40 Andrei Sarakeev 2014-10-23 09:35:17 UTC
GST_DEBUG=input-selector:6 make elements/playbin-complex.check
Comment 41 Andrei Sarakeev 2014-10-23 10:17:32 UTC
Created attachment 289194 [details] [review]
fix input-selector
Comment 42 Andrei Sarakeev 2014-10-23 10:20:02 UTC
Created attachment 289195 [details] [review]
fix input-selectoe
Comment 43 Sebastian Dröge (slomo) 2014-10-23 10:48:02 UTC
Can you explain what the exact problem here is and how the commit fixes it?
Comment 44 Andrei Sarakeev 2014-10-23 11:25:13 UTC
I will try to speak correctly in English.
The report can be seen that freezes the last buffer of non-linked audio stream (1). Its timestamp = timestamp last buffer of active audio stream(0). This timestamp = active_segment.position
Correctly would increase the active_segment.position for the duration of the buffer when it successfully sent (and then would not have to make changes), but do not specify the duration of buffers in this test suite. Therefore, we replace the condition on GREAT not Great or equal
Comment 45 Andrei Sarakeev 2014-10-23 11:44:04 UTC
... Otherwise, we will wait for events/data from ended stream.
Comment 46 Sebastian Dröge (slomo) 2014-10-23 12:23:49 UTC
I think this is not correct then. We would run into the same problem if the non-linked streams are longer than the linked ones, e.g. if there are a few milliseconds more audio than video and audio is disabled.
Comment 47 Andrei Sarakeev 2014-10-23 12:29:39 UTC
You're right, but I think it is defect input-selector. I will try to find a solution
Comment 48 Andrei Sarakeev 2014-10-23 12:35:13 UTC
Also note that the worst of the correction will not be
Comment 49 Sebastian Dröge (slomo) 2014-10-23 12:43:13 UTC
The problem is that without the EOS event the input-selector does not know that a stream is finished, and that it can wake up the other streams.

So maybe we should only delay EOS until all *linked* streams are EOS and then forward it, instead of also waiting for the not linked ones.
Comment 50 Andrei Sarakeev 2014-10-24 05:08:29 UTC
Created attachment 289245 [details] [review]
fix pending eos

waiting EOS only for the linked streams
Comment 51 Andrei Sarakeev 2014-10-24 05:19:20 UTC
Created attachment 289246 [details] [review]
fix pending eos

waiting EOS only for the linked streams
Comment 52 Andrei Sarakeev 2014-10-24 05:41:52 UTC
Created attachment 289248 [details] [review]
fix pending eos

waiting EOS only for the linked streams
Comment 53 Sebastian Dröge (slomo) 2014-10-24 07:44:53 UTC
Review of attachment 289248 [details] [review]:

::: gst/playback/gstdecodebin2.c
@@ +3678,3 @@
+    CHAIN_MUTEX_LOCK (chain);
+    chain->drained = TRUE;
+    chain->endpad->drained = TRUE;

Shouldn't it these all be set to TRUE already at this point?

@@ +3682,3 @@
+    peer = gst_pad_get_peer (GST_PAD_CAST (chain->endpad));
+    if (peer) {
+      gst_pad_send_event (peer, gst_event_new_eos ());

gst_pad_push_event (chain->endpad, gst_event_new_eos()) ?

@@ +3722,2 @@
     chain->drained = chain->endpad->drained;
+    *drained = chain->endpad->notlinked;

This does not seem right. A not-linked pad is not automatically drained, it might be selected again later by input-selector. Only if all linked pads are at EOS and only the not-linked ones are not you can consider the not-linked pads as drained.

@@ +3801,3 @@
   }
+  // return last_group;
+  return FALSE;

Don't use C99 comments, but also just delete that line :)

@@ +4645,3 @@
+  if (drained) {
+    gst_buffer_unref (buffer);
+    ret = GST_FLOW_EOS;

This part is not needed, it will return EOS automatically from gst_proxy_pad_chain_default() already.
Comment 54 Andrei Sarakeev 2014-10-24 08:11:50 UTC
Review of attachment 289248 [details] [review]:

::: gst/playback/gstdecodebin2.c
@@ +3678,3 @@
+    CHAIN_MUTEX_LOCK (chain);
+    chain->drained = TRUE;
+    chain->endpad->drained = TRUE;

If not linked stream longer then active, it will not be drained. In the future, if it will come the data we discard them.

@@ +3682,3 @@
+    peer = gst_pad_get_peer (GST_PAD_CAST (chain->endpad));
+    if (peer) {
+    CHAIN_MUTEX_LOCK (chain);

endpad is source pad, not sink pad. EOS is downstream event.

@@ +3722,2 @@
     chain->drained = chain->endpad->drained;
+    *drained = chain->endpad->notlinked;

drained state not saved in the pad (chain->endpad->drained != TRUE), only now

@@ +3801,3 @@
   }
+  // return last_group;
+  return FALSE;

Ok

@@ +4645,3 @@
+  if (drained) {
+    gst_buffer_unref (buffer);
+  gboolean drained;

if not-linked stream longer then active and we already drained signal emit
Comment 55 Andrei Sarakeev 2014-10-24 08:22:56 UTC
Created attachment 289258 [details] [review]
fix
Comment 56 Andrei Sarakeev 2014-10-24 08:59:53 UTC
offtopic: I want to improve the plugin inter (plugin for inter-pipeline
communication), but it's not a bug. I believe that the idea is good, but the
implementation is weak. What do you need me to do?
Comment 57 Tim-Philipp Müller 2014-10-24 09:12:55 UTC
Please open a new bug for that or discuss it on the mailing list.
Comment 58 Sebastian Dröge (slomo) 2014-10-24 09:17:15 UTC
(In reply to comment #54)
> Review of attachment 289248 [details] [review]:
> 
> ::: gst/playback/gstdecodebin2.c
> @@ +3678,3 @@
> +    CHAIN_MUTEX_LOCK (chain);
> +    chain->drained = TRUE;
> +    chain->endpad->drained = TRUE;
> 
> If not linked stream longer then active, it will not be drained. In the future,
> if it will come the data we discard them.

What would be the problem with that?

> @@ +3682,3 @@
> +    peer = gst_pad_get_peer (GST_PAD_CAST (chain->endpad));
> +    if (peer) {
> +    CHAIN_MUTEX_LOCK (chain);
> 
> endpad is source pad, not sink pad. EOS is downstream event.

That's why I said gst_pad_push_event() on the endpad :) That should do the same as gst_pad_send_event() on the peer, but is a few lines shorter.

> @@ +3722,2 @@
>      chain->drained = chain->endpad->drained;
> +    *drained = chain->endpad->notlinked;
> 
> drained state not saved in the pad (chain->endpad->drained != TRUE), only now

Good point, missed that. That would need a comment there :) Or maybe use a separate variable with a speaking name for this.

> @@ +4645,3 @@
> +  if (drained) {
> +    gst_buffer_unref (buffer);
> +  gboolean drained;
> 
> if not-linked stream longer then active and we already drained signal emit

This would break if you try to seek to some position after EOS I think, you would also need to reset the drained flag then. Also what's the problem with letting GstPad worry about this?
Comment 59 Andrei Sarakeev 2014-10-24 09:36:25 UTC
(In reply to comment #58)
> 
> > @@ +3682,3 @@
> > +    peer = gst_pad_get_peer (GST_PAD_CAST (chain->endpad));
> > +    if (peer) {
> > +    CHAIN_MUTEX_LOCK (chain);
> > 
> > endpad is source pad, not sink pad. EOS is downstream event.
> 
> That's why I said gst_pad_push_event() on the endpad :) That should do the same
> as gst_pad_send_event() on the peer, but is a few lines shorter.

endpad already has EOS state/flag (We're EOS), event will not be sent
Comment 60 Andrei Sarakeev 2014-10-24 12:02:35 UTC
Created attachment 289267 [details] [review]
fix

drain_and_switch_* broke my brain.
gst_pad_push_event(endpad) can not be used because endpad already has EOS flag and any event will not be sent.
Comment 61 Andrei Sarakeev 2014-10-24 12:11:08 UTC
I change drain_and_switch_* because notlinked may become persistent.
Comment 62 Andrei Sarakeev 2014-10-29 08:01:13 UTC
Please excuse me for the disrespectful remarks. I did not want to offend.
Comment 63 Sebastian Dröge (slomo) 2014-10-29 08:54:12 UTC
I did not notice any disrespectful remarks :) I was just busy with other stuff, that's why I didn't get to take a look at this again. It's still on my list.
Comment 64 Andrei Sarakeev 2014-10-29 09:21:16 UTC
Maybe I found a bug, it takes time
Comment 65 Sebastian Dröge (slomo) 2014-10-29 09:24:53 UTC
You definitely found a bug :)
Comment 66 Andrei Sarakeev 2014-10-30 10:05:16 UTC
Created attachment 289637 [details] [review]
fix and new tests

If the EOS event is received from the *linked* pad, then pending EOS events are sent when all pads are drained or not linked.

I also added tests:
1. video, video
2. video+audio, video+audio
3. video+audio, video+audio (audio disabled)
4. video, video+audio

/* not used */
#if 0
static gboolean gst_decode_chain_is_drained (GstDecodeChain * chain);
static gboolean gst_decode_group_is_drained (GstDecodeGroup * group);
#endif
Comment 67 Sebastian Dröge (slomo) 2014-11-04 10:10:06 UTC
Review of attachment 289637 [details] [review]:

Please explain what exactly you're doing here and why, in the commit message

::: gst/playback/gstdecodebin2.c
@@ +471,3 @@
 static gboolean gst_decode_chain_is_drained (GstDecodeChain * chain);
+static gboolean gst_decode_group_is_drained (GstDecodeGroup * group);
+#endif

Where do you stop using them?

@@ +4641,3 @@
+  GstDecodePad *dpad = GST_DECODE_PAD (parent);
+  GstFlowReturn ret = gst_proxy_pad_chain_default (pad, parent, buffer);
+  gboolean notlinked = (ret == GST_FLOW_NOT_LINKED);

Handling not-linked specially here seems wrong. If anything this should be (!= OK && != FLUSHING) or something like that

::: tests/check/elements/playbin-complex.c
@@ +1036,3 @@
+  gst_object_unref (bus);
+
+  g_usleep (10000);

Why do you sleep here?

@@ +1037,3 @@
+
+  g_usleep (10000);
+  fail_unless (remaining == 0);

You only check if the about-to-finish signal is emitted often enough... but that doesn't mean that the second URI is actually played. Maybe it just went EOS directly after the first?

@@ +1101,3 @@
+
+  g_usleep (10000);
+  fail_unless (remaining == 0);

Same two comments here

@@ +1138,3 @@
+      g_signal_connect (G_OBJECT (playbin), "about-to-finish",
+      (GCallback) play_next, &remaining);
+  g_object_set (G_OBJECT (playbin), "flags", 1, NULL);

flags are usually set by first getting the current flags, and then unsetting or setting any flags you care about

@@ +1165,3 @@
+
+  g_usleep (10000);
+  fail_unless (remaining == 0);

And here
Comment 68 Andrei Sarakeev 2014-11-05 08:15:23 UTC
Review of attachment 289637 [details] [review]:

::: gst/playback/gstdecodebin2.c
@@ +471,3 @@
 static gboolean gst_decode_chain_is_drained (GstDecodeChain * chain);
+static gboolean gst_decode_group_is_drained (GstDecodeGroup * group);
+#endif

These static functions call each other, and nowhere more (circular reference).

@@ +4641,3 @@
+  GstDecodePad *dpad = GST_DECODE_PAD (parent);
+  GstFlowReturn ret = gst_proxy_pad_chain_default (pad, parent, buffer);
+  gboolean notlinked = (ret == GST_FLOW_NOT_LINKED);

You know better, but that's exactly what I need. No matter: success or failed, only not-linked (comment 39)

::: tests/check/elements/playbin-complex.c
@@ +1036,3 @@
+  gst_object_unref (bus);
+
+      ("caps:video/x-raw, "

if the about-to-finish signal is emitted several times (from different threads), then the next check "fail_unless (remaining == 0)"  could be completed successfully, but could fail (fifty-fifty). Adding a delay we will be sure that all calls completed.

@@ +1037,3 @@
+
+  g_usleep (10000);
+      "format=(string)I420, "

What should I do? We can try to count the number of STREAM_START messages.

@@ +1138,3 @@
+      g_signal_connect (G_OBJECT (playbin), "about-to-finish",
+      (GCallback) play_next, &remaining);
+  gboolean done = FALSE;

Ok
Comment 69 Andrei Sarakeev 2014-11-06 07:30:29 UTC
Created attachment 290073 [details] [review]
fix and new tests

according to the recommendations of part-seqnums.txt I copy the seqnum from the original EOS to the newly created.
I think it is time to end our discussion :), if I'm somewhere is not right, you better do it yourself
Comment 70 Andrei Sarakeev 2014-11-25 09:28:25 UTC
It seems no one uses continuous playback. I need to broadcast on the network. It is not necessary all the time to interrupt the flow
Comment 71 Andrei Sarakeev 2014-11-25 09:42:44 UTC
approaching release of my project. I do not want to fork gstreamer %(
Somebody do something that worked continuous playback or accept my commit
Comment 72 Andrei Sarakeev 2014-11-27 07:13:31 UTC
Essence of the problem:

It is very important for continuous playback send all EOS events after the emission 'drained' signal to the playbin switched on the next media.
If the container contains multiple audio streams, only one stream will be linked to audio sink.
input-selector to pump buffer all streams synchronously with the active stream.
When the active stream ends, the selector will not know and will wait for the next buffer even if there was only a last buffer in not linked stream.
Not linked stream never send the EOS event.
Playback stops.

To prevent this need to wait for EOS events only from the connected streams.

PLEASE, I spent a lot of time to understand the problem and find an acceptable solution. Help me finish the job. Thank you.
Comment 73 Edward Hervey 2018-05-05 15:37:47 UTC
Hi, This issue is fixed with gapless playback in playbin3.