Commit c6f044e604 for ffmpeg
commit c6f044e6041c76e156f6845ab1f7082f8058e063
Author: Zhao Zhili <quinkblack@foxmail.com>
Date: Sat Oct 10 00:05:19 2026 +0800
avformat/udp: wake the rx thread when the input is closed
Closing an input that receives no data took up to POLLING_TIME, as
udp_close() could only wait for the rx thread to come back from its
poll() slice before joining it. Have the thread wait on a wakeup
channel next to the socket and signal that channel from udp_close()
after setting close_req.
Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
diff --git a/libavformat/udp.c b/libavformat/udp.c
index a21b04e89c..74f3f3674c 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -73,6 +73,10 @@
#define UDP_RX_BUF_SIZE 393216
#define UDP_MAX_PKT_SIZE 65536
#define UDP_HEADER_SIZE 8
+/* Bounds how long udp_close() waits when signaling the wakeup channel
+ * failed and no datagram arrives to release the rx thread.
+ */
+#define UDP_RX_WAIT_TIMEOUT_MS 1000
typedef struct UDPQueuedPacketHeader {
int pkt_size;
@@ -108,6 +112,7 @@ typedef struct UDPContext {
pthread_t circular_buffer_thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
+ FFNetWakeup wakeup; /* ends the rx thread's socket wait on close */
int thread_started;
#endif
uint8_t tmp[UDP_MAX_PKT_SIZE + sizeof(UDPQueuedPacketHeader)];
@@ -543,10 +548,16 @@ static void *circular_buffer_task_rx( void *_URLContext)
if (pkt_header.pkt_size < 0) {
err = ff_neterrno();
if (err == AVERROR(EAGAIN))
- err = ff_network_wait_fd(s->udp_fd, 0);
+ err = ff_network_wait_fd_wakeup(s->udp_fd, 0,
+ UDP_RX_WAIT_TIMEOUT_MS,
+ &s->wakeup);
}
pthread_mutex_lock(&s->mutex);
if (pkt_header.pkt_size < 0) {
+ // ff_network_wakeup_signal to exit
+ if (err == AVERROR_EXIT)
+ goto end;
+
if (err < 0 && err != AVERROR(EAGAIN) && err != AVERROR(EINTR)) {
s->circular_buffer_error = err;
goto end;
@@ -934,11 +945,18 @@ static int udp_open(URLContext *h, const char *uri, int flags)
ret = AVERROR(ret);
goto cond_fail;
}
+ if (!is_output) {
+ ret = ff_network_wakeup_open(&s->wakeup);
+ if (ret < 0) {
+ av_log(h, AV_LOG_ERROR, "Failed to create the wakeup channel\n");
+ goto thread_fail;
+ }
+ }
ret = pthread_create(&s->circular_buffer_thread, NULL, is_output?circular_buffer_task_tx:circular_buffer_task_rx, h);
if (ret != 0) {
av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", strerror(ret));
ret = AVERROR(ret);
- goto thread_fail;
+ goto create_fail;
}
s->thread_started = 1;
}
@@ -946,6 +964,9 @@ static int udp_open(URLContext *h, const char *uri, int flags)
return 0;
#if HAVE_THREADS
+ create_fail:
+ if (!is_output)
+ ff_network_wakeup_close(&s->wakeup);
thread_fail:
pthread_cond_destroy(&s->cond);
cond_fail:
@@ -1097,6 +1118,8 @@ static int udp_close(URLContext *h)
s->close_req = 1;
pthread_cond_signal(&s->cond);
pthread_mutex_unlock(&s->mutex);
+ if (s->rx_fifo)
+ ff_network_wakeup_signal(&s->wakeup);
}
#endif
@@ -1109,6 +1132,8 @@ static int udp_close(URLContext *h)
ret = pthread_join(s->circular_buffer_thread, NULL);
if (ret != 0)
av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", strerror(ret));
+ if (s->rx_fifo)
+ ff_network_wakeup_close(&s->wakeup);
pthread_mutex_destroy(&s->mutex);
pthread_cond_destroy(&s->cond);
}