[PATCH] Fix deadlocks caused by input_vdr's discontinuity handling

View: New views
1 Messages — Rating Filter:   Alert me  

[PATCH] Fix deadlocks caused by input_vdr's discontinuity handling

by Reinhard Nissl :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

In trickspeed mode, input_vdr's metronom generates a discontinuity for
each video frame. These generated discontinuities could interfere with
discontinuities generated by the demuxer. As a result the metronom
deadlocked while waiting for a matching discontinuity indication.
So care must be taken to not mix internal and external discontinuities.


1 file changed, 125 insertions(+), 17 deletions(-)
src/vdr/input_vdr.c |  142 ++++++++++++++++++++++++++++++++++++++++++++-------




# HG changeset patch
# User Reinhard Nißl <rnissl@...>
# Date 1248468606 -7200
# Node ID dd19b839f8e7c9c0e1e0e15224651485d473f29d
# Parent  f54baed366ef51f555e5febb1e2e2b6568c5207f
Fix deadlocks caused by input_vdr's discontinuity handling.
In trickspeed mode, input_vdr's metronom generates a discontinuity for
each video frame. These generated discontinuities could interfere with
discontinuities generated by the demuxer. As a result the metronom
deadlocked while waiting for a matching discontinuity indication.
So care must be taken to not mix internal and external discontinuities.

diff --git a/src/vdr/input_vdr.c b/src/vdr/input_vdr.c
--- a/src/vdr/input_vdr.c
+++ b/src/vdr/input_vdr.c
@@ -124,11 +124,15 @@ struct vdr_input_plugin_s
   uint8_t             osd_supports_argb_layer;
 
   uint8_t             audio_channels;
-  uint8_t             trick_speed_mode;
   uint8_t             mute_mode;
   uint8_t             volume_mode;
   int                 last_volume;
   vdr_frame_size_changed_data_t frame_size;
+  
+  uint8_t             trick_speed_mode;
+  uint8_t             trick_speed_mode_blocked;
+  pthread_mutex_t     trick_speed_mode_lock;
+  pthread_cond_t      trick_speed_mode_cond;
   
   pthread_t           rpc_thread;
   int                 rpc_thread_shutdown;
@@ -812,7 +816,14 @@ static off_t vdr_execute_rpc_command(vdr
 
       if (this->trick_speed_mode != data->on)
       {
+        pthread_mutex_lock(&this->trick_speed_mode_lock);
+
+        while (this->trick_speed_mode_blocked)
+          pthread_cond_wait(&this->trick_speed_mode_cond, &this->trick_speed_mode_lock);
+
         this->trick_speed_mode = data->on;
+
+        pthread_mutex_unlock(&this->trick_speed_mode_lock);
       
         _x_demux_seek(this->stream, 0, 0, 0);
 
@@ -1801,6 +1812,9 @@ static void vdr_plugin_dispose(input_plu
   pthread_cond_destroy(&this->metronom_thread_request_cond);
   pthread_cond_destroy(&this->metronom_thread_reply_cond);
 
+  pthread_mutex_destroy(&this->trick_speed_mode_lock);
+  pthread_cond_destroy(&this->trick_speed_mode_cond);
+
   pthread_mutex_destroy(&this->find_sync_point_lock);
   pthread_mutex_destroy(&this->adjust_zoom_lock);
   
@@ -2089,6 +2103,8 @@ static int vdr_plugin_open_socket_mrl(in
   return 1;
 }
 
+static void vdr_metronom_handle_audio_discontinuity_impl(metronom_t *self, int type, int64_t disc_off);
+
 static void *vdr_metronom_thread_loop(void *arg)
 {
   vdr_input_plugin_t *this = (vdr_input_plugin_t *)arg;
@@ -2104,7 +2120,7 @@ static void *vdr_metronom_thread_loop(vo
     if (this->metronom_thread_request == -1)
       run = 0;
     else
-      this->metronom.metronom.handle_audio_discontinuity(&this->metronom.metronom, DISC_ABSOLUTE, this->metronom_thread_request);
+      vdr_metronom_handle_audio_discontinuity_impl(&this->metronom.metronom, DISC_ABSOLUTE, this->metronom_thread_request);
 
     this->metronom_thread_request = 0;
     this->metronom_thread_reply = 1;
@@ -2391,7 +2407,7 @@ fprintf(stderr, "B =====================
   }
 }
 
-static void vdr_metronom_handle_audio_discontinuity(metronom_t *self, int type, int64_t disc_off)
+static void vdr_metronom_handle_audio_discontinuity_impl(metronom_t *self, int type, int64_t disc_off)
 {
   vdr_metronom_t *this = (vdr_metronom_t *)self;
   int64_t vpts_offset = vdr_vpts_offset_queue_change_begin(this->input, type);
@@ -2401,7 +2417,48 @@ static void vdr_metronom_handle_audio_di
  vdr_vpts_offset_queue_change_end(this->input, type, disc_off, vpts_offset);
 }
 
-static void vdr_metronom_handle_video_discontinuity(metronom_t *self, int type, int64_t disc_off)
+static void vdr_metronom_handle_audio_discontinuity(metronom_t *self, int type, int64_t disc_off)
+{
+  vdr_metronom_t *this = (vdr_metronom_t *)self;
+
+  pthread_mutex_lock(&this->input->trick_speed_mode_lock);
+
+  if (this->input->trick_speed_mode_blocked & 0x04) /* must not enter while video is leaving */
+    pthread_cond_wait(&this->input->trick_speed_mode_cond, &this->input->trick_speed_mode_lock);
+
+  this->input->trick_speed_mode_blocked |= 0x02; /* audio is in */
+
+  if (!this->input->trick_speed_mode)
+  {
+    pthread_mutex_unlock(&this->input->trick_speed_mode_lock);
+
+    vdr_metronom_handle_audio_discontinuity_impl(self, type, disc_off);
+
+    pthread_mutex_lock(&this->input->trick_speed_mode_lock);
+  }
+  else
+  {
+    if (this->input->trick_speed_mode_blocked != 0x03) /* wait for audio and video in */
+    {
+      pthread_cond_wait(&this->input->trick_speed_mode_cond, &this->input->trick_speed_mode_lock);
+      this->input->trick_speed_mode_blocked &= ~0x04; /* video left already */
+    }
+    else
+    {
+      this->input->trick_speed_mode_blocked |= 0x04; /* audio is leaving */
+      pthread_cond_broadcast(&this->input->trick_speed_mode_cond);
+    }
+  }
+
+  this->input->trick_speed_mode_blocked &= ~0x02; /* audio is out */
+
+  if (!this->input->trick_speed_mode_blocked)
+    pthread_cond_broadcast(&this->input->trick_speed_mode_cond);
+
+  pthread_mutex_unlock(&this->input->trick_speed_mode_lock);
+}
+
+static void vdr_metronom_handle_video_discontinuity_impl(metronom_t *self, int type, int64_t disc_off)
 {
   vdr_metronom_t *this = (vdr_metronom_t *)self;
   int64_t vpts_offset = vdr_vpts_offset_queue_change_begin(this->input, type);
@@ -2411,28 +2468,76 @@ static void vdr_metronom_handle_video_di
   vdr_vpts_offset_queue_change_end(this->input, type, disc_off, vpts_offset);
 }
 
+static void vdr_metronom_handle_video_discontinuity(metronom_t *self, int type, int64_t disc_off)
+{
+  vdr_metronom_t *this = (vdr_metronom_t *)self;
+
+  pthread_mutex_lock(&this->input->trick_speed_mode_lock);
+
+  if (this->input->trick_speed_mode_blocked & 0x04) /* must not enter while audio is leaving */
+    pthread_cond_wait(&this->input->trick_speed_mode_cond, &this->input->trick_speed_mode_lock);
+
+  this->input->trick_speed_mode_blocked |= 0x01; /* video is in */
+
+  if (!this->input->trick_speed_mode)
+  {
+    pthread_mutex_unlock(&this->input->trick_speed_mode_lock);
+
+    vdr_metronom_handle_video_discontinuity_impl(self, type, disc_off);
+
+    pthread_mutex_lock(&this->input->trick_speed_mode_lock);
+  }
+  else
+  {
+    if (this->input->trick_speed_mode_blocked != 0x03) /* wait for audio and video in */
+    {
+      pthread_cond_wait(&this->input->trick_speed_mode_cond, &this->input->trick_speed_mode_lock);
+      this->input->trick_speed_mode_blocked &= ~0x04; /* audio left already */
+    }
+    else
+    {
+      this->input->trick_speed_mode_blocked |= 0x04; /* video is leaving */
+      pthread_cond_broadcast(&this->input->trick_speed_mode_cond);
+    }
+  }
+
+  this->input->trick_speed_mode_blocked &= ~0x01; /* video is out */
+
+  if (!this->input->trick_speed_mode_blocked)
+    pthread_cond_broadcast(&this->input->trick_speed_mode_cond);
+
+  pthread_mutex_unlock(&this->input->trick_speed_mode_lock);
+}
+
 static void vdr_metronom_got_video_frame(metronom_t *self, vo_frame_t *frame)
 {
   vdr_metronom_t *this = (vdr_metronom_t *)self;
 
-  if (this->input->trick_speed_mode && frame->pts)
+  if (frame->pts)
   {
-    pthread_mutex_lock(&this->input->metronom_thread_call_lock);
+    pthread_mutex_lock(&this->input->trick_speed_mode_lock);
 
-    pthread_mutex_lock(&this->input->metronom_thread_lock);
-    this->input->metronom_thread_request = frame->pts;
-    this->input->metronom_thread_reply = 0;
-    pthread_cond_broadcast(&this->input->metronom_thread_request_cond);
-    pthread_mutex_unlock(&this->input->metronom_thread_lock);
+    if (this->input->trick_speed_mode)
+    {
+      pthread_mutex_lock(&this->input->metronom_thread_call_lock);
 
-    vdr_metronom_handle_video_discontinuity(self, DISC_ABSOLUTE, frame->pts);    
+      pthread_mutex_lock(&this->input->metronom_thread_lock);
+      this->input->metronom_thread_request = frame->pts;
+      this->input->metronom_thread_reply = 0;
+      pthread_cond_broadcast(&this->input->metronom_thread_request_cond);
+      pthread_mutex_unlock(&this->input->metronom_thread_lock);
 
-    pthread_mutex_lock(&this->input->metronom_thread_lock);
-    if (!this->input->metronom_thread_reply)
-      pthread_cond_wait(&this->input->metronom_thread_reply_cond, &this->input->metronom_thread_lock);
-    pthread_mutex_unlock(&this->input->metronom_thread_lock);
+      vdr_metronom_handle_video_discontinuity_impl(self, DISC_ABSOLUTE, frame->pts);    
 
-    pthread_mutex_unlock(&this->input->metronom_thread_call_lock);
+      pthread_mutex_lock(&this->input->metronom_thread_lock);
+      if (!this->input->metronom_thread_reply)
+        pthread_cond_wait(&this->input->metronom_thread_reply_cond, &this->input->metronom_thread_lock);
+      pthread_mutex_unlock(&this->input->metronom_thread_lock);
+
+      pthread_mutex_unlock(&this->input->metronom_thread_call_lock);
+    }
+
+    pthread_mutex_unlock(&this->input->trick_speed_mode_lock);
   }
 
   this->stream_metronom->got_video_frame(this->stream_metronom, frame);
@@ -2565,6 +2670,9 @@ static input_plugin_t *vdr_class_get_ins
   pthread_mutex_init(&this->rpc_thread_shutdown_lock, 0);
   pthread_cond_init(&this->rpc_thread_shutdown_cond, 0);
 
+  pthread_mutex_init(&this->trick_speed_mode_lock, 0);
+  pthread_cond_init(&this->trick_speed_mode_cond, 0);
+
   pthread_mutex_init(&this->metronom_thread_lock, 0);
   pthread_cond_init(&this->metronom_thread_request_cond, 0);
   pthread_cond_init(&this->metronom_thread_reply_cond, 0);


------------------------------------------------------------------------------

_______________________________________________
xine-devel mailing list
xine-devel@...
https://lists.sourceforge.net/lists/listinfo/xine-devel