|
|
@@ -69,6 +69,8 @@ typedef struct { |
|
|
|
int circular_buffer_error; |
|
|
|
#if HAVE_PTHREADS |
|
|
|
pthread_t circular_buffer_thread; |
|
|
|
pthread_mutex_t mutex; |
|
|
|
pthread_cond_t cond; |
|
|
|
#endif |
|
|
|
uint8_t tmp[UDP_MAX_PKT_SIZE+4]; |
|
|
|
int remaining_in_dg; |
|
|
@@ -317,6 +319,7 @@ static int udp_get_file_handle(URLContext *h) |
|
|
|
return s->udp_fd; |
|
|
|
} |
|
|
|
|
|
|
|
#if HAVE_PTHREADS |
|
|
|
static void *circular_buffer_task( void *_URLContext) |
|
|
|
{ |
|
|
|
URLContext *h = _URLContext; |
|
|
@@ -331,7 +334,7 @@ static void *circular_buffer_task( void *_URLContext) |
|
|
|
|
|
|
|
if (ff_check_interrupt(&h->interrupt_callback)) { |
|
|
|
s->circular_buffer_error = EINTR; |
|
|
|
return NULL; |
|
|
|
goto end; |
|
|
|
} |
|
|
|
|
|
|
|
FD_ZERO(&rfds); |
|
|
@@ -343,7 +346,7 @@ static void *circular_buffer_task( void *_URLContext) |
|
|
|
if (ff_neterrno() == AVERROR(EINTR)) |
|
|
|
continue; |
|
|
|
s->circular_buffer_error = EIO; |
|
|
|
return NULL; |
|
|
|
goto end; |
|
|
|
} |
|
|
|
|
|
|
|
if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) |
|
|
@@ -357,23 +360,31 @@ static void *circular_buffer_task( void *_URLContext) |
|
|
|
if(left < UDP_MAX_PKT_SIZE + 4) { |
|
|
|
av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n"); |
|
|
|
s->circular_buffer_error = EIO; |
|
|
|
return NULL; |
|
|
|
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; |
|
|
|
return NULL; |
|
|
|
goto end; |
|
|
|
} |
|
|
|
continue; |
|
|
|
} |
|
|
|
AV_WL32(s->tmp, len); |
|
|
|
pthread_mutex_lock(&s->mutex); |
|
|
|
av_fifo_generic_write(s->fifo, s->tmp, len+4, NULL); |
|
|
|
pthread_cond_signal(&s->cond); |
|
|
|
pthread_mutex_unlock(&s->mutex); |
|
|
|
} |
|
|
|
|
|
|
|
end: |
|
|
|
pthread_mutex_lock(&s->mutex); |
|
|
|
pthread_cond_signal(&s->cond); |
|
|
|
pthread_mutex_unlock(&s->mutex); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
/* put it in UDP context */ |
|
|
|
/* return non zero if error */ |
|
|
@@ -516,6 +527,8 @@ static int udp_open(URLContext *h, const char *uri, int flags) |
|
|
|
if (!is_output && s->circular_buffer_size) { |
|
|
|
/* start the task going */ |
|
|
|
s->fifo = av_fifo_alloc(s->circular_buffer_size); |
|
|
|
pthread_mutex_init(&s->mutex, NULL); |
|
|
|
pthread_cond_init(&s->cond, NULL); |
|
|
|
if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h)) { |
|
|
|
av_log(h, AV_LOG_ERROR, "pthread_create failed\n"); |
|
|
|
goto fail; |
|
|
@@ -536,15 +549,15 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) |
|
|
|
UDPContext *s = h->priv_data; |
|
|
|
int ret; |
|
|
|
int avail; |
|
|
|
fd_set rfds; |
|
|
|
struct timeval tv; |
|
|
|
|
|
|
|
#if HAVE_PTHREADS |
|
|
|
if (s->fifo) { |
|
|
|
|
|
|
|
pthread_mutex_lock(&s->mutex); |
|
|
|
do { |
|
|
|
avail = av_fifo_size(s->fifo); |
|
|
|
if (avail) { // >=size) { |
|
|
|
uint8_t tmp[4]; |
|
|
|
pthread_mutex_unlock(&s->mutex); |
|
|
|
|
|
|
|
av_fifo_generic_read(s->fifo, tmp, 4, NULL); |
|
|
|
avail= AV_RL32(tmp); |
|
|
@@ -557,19 +570,15 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) |
|
|
|
av_fifo_drain(s->fifo, AV_RL32(tmp) - avail); |
|
|
|
return avail; |
|
|
|
} else if(s->circular_buffer_error){ |
|
|
|
pthread_mutex_unlock(&s->mutex); |
|
|
|
return s->circular_buffer_error; |
|
|
|
} |
|
|
|
else { |
|
|
|
FD_ZERO(&rfds); |
|
|
|
FD_SET(s->udp_fd, &rfds); |
|
|
|
tv.tv_sec = 1; |
|
|
|
tv.tv_usec = 0; |
|
|
|
ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv); |
|
|
|
if (ret<0) |
|
|
|
return ret; |
|
|
|
pthread_cond_wait(&s->cond, &s->mutex); |
|
|
|
} |
|
|
|
} while( 1); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
if (!(h->flags & AVIO_FLAG_NONBLOCK)) { |
|
|
|
ret = ff_network_wait_fd(s->udp_fd, 0); |
|
|
@@ -610,6 +619,10 @@ static int udp_close(URLContext *h) |
|
|
|
udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); |
|
|
|
closesocket(s->udp_fd); |
|
|
|
av_fifo_free(s->fifo); |
|
|
|
#if HAVE_PTHREADS |
|
|
|
pthread_mutex_destroy(&s->mutex); |
|
|
|
pthread_cond_destroy(&s->cond); |
|
|
|
#endif |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|