Skip to content

Commit

Permalink
Merge pull request #2557 from elupus/abort
Browse files Browse the repository at this point in the history
dvdplayer: fix abort of ffmpeg streams
  • Loading branch information
elupus committed Apr 7, 2013
2 parents 425fd3e + 21af8ba commit 7186213
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 42 deletions.
24 changes: 13 additions & 11 deletions lib/ffmpeg/libavformat/udp.c
Expand Up @@ -334,11 +334,6 @@ static void *circular_buffer_task( void *_URLContext)
int ret;
int len;

if (ff_check_interrupt(&h->interrupt_callback)) {
s->circular_buffer_error = EINTR;
goto end;
}

FD_ZERO(&rfds);
FD_SET(s->udp_fd, &rfds);
tv.tv_sec = 1;
Expand All @@ -347,7 +342,7 @@ static void *circular_buffer_task( void *_URLContext)
if (ret < 0) {
if (ff_neterrno() == AVERROR(EINTR))
continue;
s->circular_buffer_error = EIO;
s->circular_buffer_error = AVERROR(EIO);
goto end;
}

Expand All @@ -361,14 +356,14 @@ static void *circular_buffer_task( void *_URLContext)
/* No Space left, error, what do we do now */
if(left < UDP_MAX_PKT_SIZE + 4) {
av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n");
s->circular_buffer_error = EIO;
s->circular_buffer_error = AVERROR(EIO);
goto end;
}
left = FFMIN(left, s->fifo->end - s->fifo->wptr);
len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0);
if (len < 0) {
if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) {
s->circular_buffer_error = EIO;
s->circular_buffer_error = AVERROR(EIO);
goto end;
}
continue;
Expand Down Expand Up @@ -568,7 +563,7 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
{
UDPContext *s = h->priv_data;
int ret;
int avail;
int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK;

#if HAVE_PTHREADS
if (s->fifo) {
Expand All @@ -592,12 +587,19 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
} else if(s->circular_buffer_error){
pthread_mutex_unlock(&s->mutex);
return s->circular_buffer_error;
} else if(h->flags & AVIO_FLAG_NONBLOCK) {
} else if(nonblock) {
pthread_mutex_unlock(&s->mutex);
return AVERROR(EAGAIN);
}
else {
pthread_cond_wait(&s->cond, &s->mutex);
/* FIXME: using the monotonic clock would be better,
but it does not exist on all supported platforms. */
int64_t t = av_gettime() + 100000;
struct timespec tv = { .tv_sec = t / 1000000,
.tv_nsec = (t % 1000000) * 1000 };
if (pthread_cond_timedwait(&s->cond, &s->mutex, &tv) < 0)
return AVERROR(errno == ETIMEDOUT ? EAGAIN : errno);
nonblock = 1;
}
} while( 1);
}
Expand Down
47 changes: 18 additions & 29 deletions xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
Expand Up @@ -35,6 +35,7 @@
#include "DVDInputStreams/DVDInputStreamBluray.h"
#endif
#include "DVDInputStreams/DVDInputStreamPVRManager.h"
#include "DVDInputStreams/DVDInputStreamFFmpeg.h"
#include "DVDDemuxUtils.h"
#include "DVDClock.h" // for DVD_TIME_BASE
#include "commons/Exception.h"
Expand Down Expand Up @@ -155,11 +156,9 @@ static void ff_flush_avutil_log_buffers(void)
++it;
}

static XbmcThreads::ThreadLocal<CDVDDemuxFFmpeg> g_demuxer;

static int interrupt_cb(void* unused)
static int interrupt_cb(void* ctx)
{
CDVDDemuxFFmpeg* demuxer = g_demuxer.get();
CDVDDemuxFFmpeg* demuxer = static_cast<CDVDDemuxFFmpeg*>(ctx);
if(demuxer && demuxer->Aborted())
return 1;
return 0;
Expand All @@ -176,10 +175,10 @@ static int dvd_file_open(URLContext *h, const char *filename, int flags)

static int dvd_file_read(void *h, uint8_t* buf, int size)
{
if(interrupt_cb(NULL))
return -1;
if(interrupt_cb(h))
return AVERROR_EXIT;

CDVDInputStream* pInputStream = (CDVDInputStream*)h;
CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
return pInputStream->Read(buf, size);
}
/*
Expand All @@ -190,10 +189,10 @@ static int dvd_file_write(URLContext *h, BYTE* buf, int size)
*/
static offset_t dvd_file_seek(void *h, offset_t pos, int whence)
{
if(interrupt_cb(NULL))
return -1;
if(interrupt_cb(h))
return AVERROR_EXIT;

CDVDInputStream* pInputStream = (CDVDInputStream*)h;
CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
if(whence == AVSEEK_SIZE)
return pInputStream->GetLength();
else
Expand Down Expand Up @@ -227,6 +226,10 @@ bool CDVDDemuxFFmpeg::Aborted()
if(m_timeout.IsTimePast())
return true;

CDVDInputStreamFFmpeg * input = dynamic_cast<CDVDInputStreamFFmpeg*>(m_pInput);
if(input && input->Aborted())
return true;

return false;
}

Expand All @@ -236,9 +239,8 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
std::string strFile;
m_iCurrentPts = DVD_NOPTS_VALUE;
m_speed = DVD_PLAYSPEED_NORMAL;
g_demuxer.set(this);
m_program = UINT_MAX;
const AVIOInterruptCB int_cb = { interrupt_cb, NULL };
const AVIOInterruptCB int_cb = { interrupt_cb, this };

if (!pInput) return false;

Expand Down Expand Up @@ -270,6 +272,10 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
iformat = m_dllAvFormat.av_find_input_format("mjpeg");
}

// open the demuxer
m_pFormatContext = m_dllAvFormat.avformat_alloc_context();
m_pFormatContext->interrupt_callback = int_cb;

// try to abort after 30 seconds
m_timeout.Set(30000);

Expand Down Expand Up @@ -411,8 +417,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
}


// open the demuxer
m_pFormatContext = m_dllAvFormat.avformat_alloc_context();
m_pFormatContext->pb = m_ioContext;

if (m_dllAvFormat.avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, NULL) < 0)
Expand All @@ -423,9 +427,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
}
}

// set the interrupt callback, appeared in libavformat 53.15.0
m_pFormatContext->interrupt_callback = int_cb;

// Avoid detecting framerate if advancedsettings.xml says so
if (g_advancedSettings.m_videoFpsDetect == 0)
m_pFormatContext->fps_probe_size = 0;
Expand Down Expand Up @@ -506,8 +507,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)

void CDVDDemuxFFmpeg::Dispose()
{
g_demuxer.set(this);

if (m_pFormatContext)
{
if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext)
Expand Down Expand Up @@ -554,8 +553,6 @@ void CDVDDemuxFFmpeg::Reset()

void CDVDDemuxFFmpeg::Flush()
{
g_demuxer.set(this);

// naughty usage of an internal ffmpeg function
if (m_pFormatContext)
m_dllAvFormat.av_read_frame_flush(m_pFormatContext);
Expand All @@ -570,8 +567,6 @@ void CDVDDemuxFFmpeg::Abort()

void CDVDDemuxFFmpeg::SetSpeed(int iSpeed)
{
g_demuxer.set(this);

if(!m_pFormatContext)
return;

Expand Down Expand Up @@ -632,8 +627,6 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num)

DemuxPacket* CDVDDemuxFFmpeg::Read()
{
g_demuxer.set(this);

AVPacket pkt;
DemuxPacket* pPacket = NULL;
// 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)
Expand Down Expand Up @@ -815,8 +808,6 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()

bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
{
g_demuxer.set(this);

if(time < 0)
time = 0;

Expand Down Expand Up @@ -875,8 +866,6 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)

bool CDVDDemuxFFmpeg::SeekByte(int64_t pos)
{
g_demuxer.set(this);

CSingleLock lock(m_critSection);
int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE);

Expand Down
2 changes: 1 addition & 1 deletion xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
Expand Up @@ -111,6 +111,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
bool Aborted();

AVFormatContext* m_pFormatContext;
CDVDInputStream* m_pInput;

protected:
friend class CDemuxStreamAudioFFmpeg;
Expand Down Expand Up @@ -140,6 +141,5 @@ class CDVDDemuxFFmpeg : public CDVDDemux
unsigned m_program;
XbmcThreads::EndTime m_timeout;

CDVDInputStream* m_pInput;
};

Expand Up @@ -24,6 +24,9 @@ using namespace XFILE;

CDVDInputStreamFFmpeg::CDVDInputStreamFFmpeg()
: CDVDInputStream(DVDSTREAM_TYPE_FFMPEG)
, m_can_pause(false)
, m_can_seek(false)
, m_aborted(false)
{

}
Expand All @@ -35,7 +38,10 @@ CDVDInputStreamFFmpeg::~CDVDInputStreamFFmpeg()

bool CDVDInputStreamFFmpeg::IsEOF()
{
return false;
if(m_aborted)
return true;
else
return false;
}

bool CDVDInputStreamFFmpeg::Open(const char* strFile, const std::string& content)
Expand All @@ -45,6 +51,7 @@ bool CDVDInputStreamFFmpeg::Open(const char* strFile, const std::string& content

m_can_pause = true;
m_can_seek = true;
m_aborted = false;

if(strnicmp(strFile, "udp://", 6) == 0
|| strnicmp(strFile, "rtp://", 6) == 0)
Expand Down
4 changes: 4 additions & 0 deletions xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.h
Expand Up @@ -37,10 +37,14 @@ class CDVDInputStreamFFmpeg
virtual bool IsEOF();
virtual int64_t GetLength();

virtual void Abort() { m_aborted = true; }
bool Aborted() { return m_aborted; }

bool CanSeek() { return m_can_seek; }
bool CanPause() { return m_can_pause; }

protected:
bool m_can_pause;
bool m_can_seek;
bool m_aborted;
};
3 changes: 3 additions & 0 deletions xbmc/cores/dvdplayer/DVDPlayer.cpp
Expand Up @@ -520,6 +520,9 @@ bool CDVDPlayer::CloseFile()
if(m_pSubtitleDemuxer)
m_pSubtitleDemuxer->Abort();

if(m_pInputStream)
m_pInputStream->Abort();

CLog::Log(LOGNOTICE, "DVDPlayer: waiting for threads to exit");

// wait for the main thread to finish up
Expand Down

0 comments on commit 7186213

Please sign in to comment.