Skip to content
This repository
Browse code

Merge pull request #2557 from elupus/abort

dvdplayer: fix abort of ffmpeg streams
  • Loading branch information...
commit 71862137c5337fc678681a23bfbc65f4db7a7b2f 2 parents 425fd3e + 21af8ba
Joakim Plate authored
24  lib/ffmpeg/libavformat/udp.c
@@ -334,11 +334,6 @@ static void *circular_buffer_task( void *_URLContext)
334 334
         int ret;
335 335
         int len;
336 336
 
337  
-        if (ff_check_interrupt(&h->interrupt_callback)) {
338  
-            s->circular_buffer_error = EINTR;
339  
-            goto end;
340  
-        }
341  
-
342 337
         FD_ZERO(&rfds);
343 338
         FD_SET(s->udp_fd, &rfds);
344 339
         tv.tv_sec = 1;
@@ -347,7 +342,7 @@ static void *circular_buffer_task( void *_URLContext)
347 342
         if (ret < 0) {
348 343
             if (ff_neterrno() == AVERROR(EINTR))
349 344
                 continue;
350  
-            s->circular_buffer_error = EIO;
  345
+            s->circular_buffer_error = AVERROR(EIO);
351 346
             goto end;
352 347
         }
353 348
 
@@ -361,14 +356,14 @@ static void *circular_buffer_task( void *_URLContext)
361 356
         /* No Space left, error, what do we do now */
362 357
         if(left < UDP_MAX_PKT_SIZE + 4) {
363 358
             av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n");
364  
-            s->circular_buffer_error = EIO;
  359
+            s->circular_buffer_error = AVERROR(EIO);
365 360
             goto end;
366 361
         }
367 362
         left = FFMIN(left, s->fifo->end - s->fifo->wptr);
368 363
         len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0);
369 364
         if (len < 0) {
370 365
             if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) {
371  
-                s->circular_buffer_error = EIO;
  366
+                s->circular_buffer_error = AVERROR(EIO);
372 367
                 goto end;
373 368
             }
374 369
             continue;
@@ -568,7 +563,7 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
568 563
 {
569 564
     UDPContext *s = h->priv_data;
570 565
     int ret;
571  
-    int avail;
  566
+    int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK;
572 567
 
573 568
 #if HAVE_PTHREADS
574 569
     if (s->fifo) {
@@ -592,12 +587,19 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
592 587
             } else if(s->circular_buffer_error){
593 588
                 pthread_mutex_unlock(&s->mutex);
594 589
                 return s->circular_buffer_error;
595  
-            } else if(h->flags & AVIO_FLAG_NONBLOCK) {
  590
+            } else if(nonblock) {
596 591
                 pthread_mutex_unlock(&s->mutex);
597 592
                 return AVERROR(EAGAIN);
598 593
             }
599 594
             else {
600  
-                pthread_cond_wait(&s->cond, &s->mutex);
  595
+                /* FIXME: using the monotonic clock would be better,
  596
+                   but it does not exist on all supported platforms. */
  597
+                int64_t t = av_gettime() + 100000;
  598
+                struct timespec tv = { .tv_sec  =  t / 1000000,
  599
+                                       .tv_nsec = (t % 1000000) * 1000 };
  600
+                if (pthread_cond_timedwait(&s->cond, &s->mutex, &tv) < 0)
  601
+                    return AVERROR(errno == ETIMEDOUT ? EAGAIN : errno);
  602
+                nonblock = 1;
601 603
             }
602 604
         } while( 1);
603 605
     }
47  xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -35,6 +35,7 @@
35 35
 #include "DVDInputStreams/DVDInputStreamBluray.h"
36 36
 #endif
37 37
 #include "DVDInputStreams/DVDInputStreamPVRManager.h"
  38
+#include "DVDInputStreams/DVDInputStreamFFmpeg.h"
38 39
 #include "DVDDemuxUtils.h"
39 40
 #include "DVDClock.h" // for DVD_TIME_BASE
40 41
 #include "commons/Exception.h"
@@ -155,11 +156,9 @@ static void ff_flush_avutil_log_buffers(void)
155 156
       ++it;
156 157
 }
157 158
 
158  
-static XbmcThreads::ThreadLocal<CDVDDemuxFFmpeg> g_demuxer;
159  
-
160  
-static int interrupt_cb(void* unused)
  159
+static int interrupt_cb(void* ctx)
161 160
 {
162  
-  CDVDDemuxFFmpeg* demuxer = g_demuxer.get();
  161
+  CDVDDemuxFFmpeg* demuxer = static_cast<CDVDDemuxFFmpeg*>(ctx);
163 162
   if(demuxer && demuxer->Aborted())
164 163
     return 1;
165 164
   return 0;
@@ -176,10 +175,10 @@ static int dvd_file_open(URLContext *h, const char *filename, int flags)
176 175
 
177 176
 static int dvd_file_read(void *h, uint8_t* buf, int size)
178 177
 {
179  
-  if(interrupt_cb(NULL))
180  
-    return -1;
  178
+  if(interrupt_cb(h))
  179
+    return AVERROR_EXIT;
181 180
 
182  
-  CDVDInputStream* pInputStream = (CDVDInputStream*)h;
  181
+  CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
183 182
   return pInputStream->Read(buf, size);
184 183
 }
185 184
 /*
@@ -190,10 +189,10 @@ static int dvd_file_write(URLContext *h, BYTE* buf, int size)
190 189
 */
191 190
 static offset_t dvd_file_seek(void *h, offset_t pos, int whence)
192 191
 {
193  
-  if(interrupt_cb(NULL))
194  
-    return -1;
  192
+  if(interrupt_cb(h))
  193
+    return AVERROR_EXIT;
195 194
 
196  
-  CDVDInputStream* pInputStream = (CDVDInputStream*)h;
  195
+  CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
197 196
   if(whence == AVSEEK_SIZE)
198 197
     return pInputStream->GetLength();
199 198
   else
@@ -227,6 +226,10 @@ bool CDVDDemuxFFmpeg::Aborted()
227 226
   if(m_timeout.IsTimePast())
228 227
     return true;
229 228
 
  229
+  CDVDInputStreamFFmpeg * input = dynamic_cast<CDVDInputStreamFFmpeg*>(m_pInput);
  230
+  if(input && input->Aborted())
  231
+    return true;
  232
+
230 233
   return false;
231 234
 }
232 235
 
@@ -236,9 +239,8 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
236 239
   std::string strFile;
237 240
   m_iCurrentPts = DVD_NOPTS_VALUE;
238 241
   m_speed = DVD_PLAYSPEED_NORMAL;
239  
-  g_demuxer.set(this);
240 242
   m_program = UINT_MAX;
241  
-  const AVIOInterruptCB int_cb = { interrupt_cb, NULL };
  243
+  const AVIOInterruptCB int_cb = { interrupt_cb, this };
242 244
 
243 245
   if (!pInput) return false;
244 246
 
@@ -270,6 +272,10 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
270 272
       iformat = m_dllAvFormat.av_find_input_format("mjpeg");
271 273
   }
272 274
 
  275
+  // open the demuxer
  276
+  m_pFormatContext  = m_dllAvFormat.avformat_alloc_context();
  277
+  m_pFormatContext->interrupt_callback = int_cb;
  278
+
273 279
   // try to abort after 30 seconds
274 280
   m_timeout.Set(30000);
275 281
 
@@ -411,8 +417,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
411 417
     }
412 418
 
413 419
 
414  
-    // open the demuxer
415  
-    m_pFormatContext     = m_dllAvFormat.avformat_alloc_context();
416 420
     m_pFormatContext->pb = m_ioContext;
417 421
 
418 422
     if (m_dllAvFormat.avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, NULL) < 0)
@@ -423,9 +427,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
423 427
     }
424 428
   }
425 429
 
426  
-  // set the interrupt callback, appeared in libavformat 53.15.0
427  
-  m_pFormatContext->interrupt_callback = int_cb;
428  
-
429 430
   // Avoid detecting framerate if advancedsettings.xml says so
430 431
   if (g_advancedSettings.m_videoFpsDetect == 0) 
431 432
       m_pFormatContext->fps_probe_size = 0;
@@ -506,8 +507,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
506 507
 
507 508
 void CDVDDemuxFFmpeg::Dispose()
508 509
 {
509  
-  g_demuxer.set(this);
510  
-
511 510
   if (m_pFormatContext)
512 511
   {
513 512
     if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext)
@@ -554,8 +553,6 @@ void CDVDDemuxFFmpeg::Reset()
554 553
 
555 554
 void CDVDDemuxFFmpeg::Flush()
556 555
 {
557  
-  g_demuxer.set(this);
558  
-
559 556
   // naughty usage of an internal ffmpeg function
560 557
   if (m_pFormatContext)
561 558
     m_dllAvFormat.av_read_frame_flush(m_pFormatContext);
@@ -570,8 +567,6 @@ void CDVDDemuxFFmpeg::Abort()
570 567
 
571 568
 void CDVDDemuxFFmpeg::SetSpeed(int iSpeed)
572 569
 {
573  
-  g_demuxer.set(this);
574  
-
575 570
   if(!m_pFormatContext)
576 571
     return;
577 572
 
@@ -632,8 +627,6 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num)
632 627
 
633 628
 DemuxPacket* CDVDDemuxFFmpeg::Read()
634 629
 {
635  
-  g_demuxer.set(this);
636  
-
637 630
   AVPacket pkt;
638 631
   DemuxPacket* pPacket = NULL;
639 632
   // on some cases where the received packet is invalid we will need to return an empty packet (0 length) otherwise the main loop (in CDVDPlayer)
@@ -815,8 +808,6 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
815 808
 
816 809
 bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
817 810
 {
818  
-  g_demuxer.set(this);
819  
-
820 811
   if(time < 0)
821 812
     time = 0;
822 813
 
@@ -875,8 +866,6 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
875 866
 
876 867
 bool CDVDDemuxFFmpeg::SeekByte(int64_t pos)
877 868
 {
878  
-  g_demuxer.set(this);
879  
-
880 869
   CSingleLock lock(m_critSection);
881 870
   int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE);
882 871
 
2  xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
@@ -111,6 +111,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
111 111
   bool Aborted();
112 112
 
113 113
   AVFormatContext* m_pFormatContext;
  114
+  CDVDInputStream* m_pInput;
114 115
 
115 116
 protected:
116 117
   friend class CDemuxStreamAudioFFmpeg;
@@ -140,6 +141,5 @@ class CDVDDemuxFFmpeg : public CDVDDemux
140 141
   unsigned m_program;
141 142
   XbmcThreads::EndTime  m_timeout;
142 143
 
143  
-  CDVDInputStream* m_pInput;
144 144
 };
145 145
 
9  xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp
@@ -24,6 +24,9 @@ using namespace XFILE;
24 24
 
25 25
 CDVDInputStreamFFmpeg::CDVDInputStreamFFmpeg()
26 26
   : CDVDInputStream(DVDSTREAM_TYPE_FFMPEG)
  27
+  , m_can_pause(false)
  28
+  , m_can_seek(false)
  29
+  , m_aborted(false)
27 30
 {
28 31
 
29 32
 }
@@ -35,7 +38,10 @@ CDVDInputStreamFFmpeg::~CDVDInputStreamFFmpeg()
35 38
 
36 39
 bool CDVDInputStreamFFmpeg::IsEOF()
37 40
 {
38  
-  return false;
  41
+  if(m_aborted)
  42
+    return true;
  43
+  else
  44
+    return false;
39 45
 }
40 46
 
41 47
 bool CDVDInputStreamFFmpeg::Open(const char* strFile, const std::string& content)
@@ -45,6 +51,7 @@ bool CDVDInputStreamFFmpeg::Open(const char* strFile, const std::string& content
45 51
 
46 52
   m_can_pause = true;
47 53
   m_can_seek  = true;
  54
+  m_aborted   = false;
48 55
 
49 56
   if(strnicmp(strFile, "udp://", 6) == 0
50 57
   || strnicmp(strFile, "rtp://", 6) == 0)
4  xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.h
@@ -37,10 +37,14 @@ class CDVDInputStreamFFmpeg
37 37
   virtual bool IsEOF();
38 38
   virtual int64_t GetLength();
39 39
 
  40
+  virtual void    Abort()    { m_aborted = true;  }
  41
+  bool            Aborted()  { return m_aborted;  }
  42
+
40 43
   bool            CanSeek()  { return m_can_seek; }
41 44
   bool            CanPause() { return m_can_pause; }
42 45
 
43 46
 protected:
44 47
   bool m_can_pause;
45 48
   bool m_can_seek;
  49
+  bool m_aborted;
46 50
 };
3  xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -520,6 +520,9 @@ bool CDVDPlayer::CloseFile()
520 520
   if(m_pSubtitleDemuxer)
521 521
     m_pSubtitleDemuxer->Abort();
522 522
 
  523
+  if(m_pInputStream)
  524
+    m_pInputStream->Abort();
  525
+
523 526
   CLog::Log(LOGNOTICE, "DVDPlayer: waiting for threads to exit");
524 527
 
525 528
   // wait for the main thread to finish up

0 notes on commit 7186213

Please sign in to comment.
Something went wrong with that request. Please try again.