Sorry, This a wrong patch from a private branch. I will post the correct one later.
On Tue, May 31, 2016 at 7:05 PM, Xinzheng Zhang <zhangxzh...@gmail.com> wrote: > From: xinzhengzhang <zhangxzh...@gmail.com> > > --- > libavformat/tcp.c | 194 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 194 insertions(+) > > diff --git a/libavformat/tcp.c b/libavformat/tcp.c > index 4ac061a..dc3e0bd 100644 > --- a/libavformat/tcp.c > +++ b/libavformat/tcp.c > @@ -32,11 +32,15 @@ > #if HAVE_POLL_H > #include <poll.h> > #endif > +#if HAVE_PTHREADS > +#include <pthread.h> > +#endif > > typedef struct TCPContext { > const AVClass *class; > int fd; > int listen; > + int addrinfo_timeout; > int open_timeout; > int rw_timeout; > int listen_timeout; > @@ -52,6 +56,7 @@ static const AVOption options[] = { > { "listen", "Listen for incoming connections", > OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, > .flags = D|E }, > { "timeout", "set timeout (in microseconds) of socket I/O > operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, > -1, INT_MAX, .flags = D|E }, > { "listen_timeout", "Connection awaiting timeout (in > milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 > }, -1, INT_MAX, .flags = D|E }, > + { "addrinfo_timeout", "set timeout (in microseconds) for > getaddrinfo()", OFFSET(addrinfo_timeout), AV_OPT_TYPE_INT, { .i64 = -1 > }, -1, INT_MAX, .flags = D|E }, > { "send_buffer_size", "Socket send buffer size (in bytes)", > OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, > INT_MAX, .flags = D|E }, > { "recv_buffer_size", "Socket receive buffer size (in bytes)", > OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, > INT_MAX, .flags = D|E }, > { "ijkapplication", "AVApplicationContext", > OFFSET(app_ctx), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, > INT64_MAX, .flags = D }, > @@ -65,6 +70,189 @@ static const AVClass tcp_class = { > .version = LIBAVUTIL_VERSION_INT, > }; > > +#ifdef HAVE_PTHREADS > + > +typedef struct TCPAddrinfoRequest > +{ > + AVBufferRef *buffer; > + > + pthread_mutex_t mutex; > + pthread_cond_t cond; > + > + int64_t timeout; // in microseconds; > + AVIOInterruptCB interrupt_callback; > + > + char *hostname; > + char *servname; > + struct addrinfo hints; > + struct addrinfo *res; > + > + volatile int finished; > + int ret; > +} TCPAddrinfoRequest; > + > +static void tcp_getaddrinfo_request_free(TCPAddrinfoRequest *req) > +{ > + freeaddrinfo(req->res); > + > + av_freep(&req->servname); > + av_freep(&req->hostname); > + pthread_cond_destroy(&req->cond); > + pthread_mutex_destroy(&req->mutex); > + av_freep(&req); > +} > + > +static void tcp_getaddrinfo_request_free_buffer(void *opaque, uint8_t > *data) > +{ > + TCPAddrinfoRequest *req = (TCPAddrinfoRequest *)opaque; > + tcp_getaddrinfo_request_free(req); > +} > + > +static int tcp_getaddrinfo_request_create(TCPAddrinfoRequest **request, > + const char *hostname, > + const char *servname, > + const struct addrinfo *hints, > + int64_t timeout, > + const AVIOInterruptCB *int_cb) > +{ > + TCPAddrinfoRequest *req = (TCPAddrinfoRequest *) > av_mallocz(sizeof(TCPAddrinfoRequest)); > + if (!req) > + return AVERROR(ENOMEM); > + > + if (pthread_mutex_init(&req->mutex, NULL)) { > + av_freep(&req); > + return AVERROR(ENOMEM); > + } > + > + if (pthread_cond_init(&req->cond, NULL)) { > + pthread_mutex_destroy(&req->mutex); > + av_freep(&req); > + return AVERROR(ENOMEM); > + } > + > + req->timeout = timeout; > + req->interrupt_callback = *int_cb; > + > + if (hostname && *hostname) { > + req->hostname = av_strdup(hostname); > + if (!req->hostname) > + goto fail; > + } > + > + if (servname) { > + req->servname = av_strdup(servname); > + if (!req->hostname) > + goto fail; > + } > + > + if (hints) { > + req->hints.ai_family = hints->ai_family; > + req->hints.ai_socktype = hints->ai_socktype; > + req->hints.ai_protocol = hints->ai_protocol; > + req->hints.ai_flags = hints->ai_flags; > + } > + > + req->buffer = av_buffer_create(NULL, 0, > tcp_getaddrinfo_request_free_buffer, req, 0); > + if (!req->buffer) > + goto fail; > + > + *request = req; > + return 0; > +fail: > + tcp_getaddrinfo_request_free(req); > + return AVERROR(ENOMEM); > +} > + > +static void *tcp_getaddrinfo_worker(void *arg) > +{ > + TCPAddrinfoRequest *req = arg; > + > + req->ret = getaddrinfo(req->hostname, req->servname, &req->hints, > &req->res); > + > + pthread_mutex_lock(&req->mutex); > + req->finished = 1; > + pthread_cond_signal(&req->cond); > + pthread_mutex_unlock(&req->mutex); > + > + av_buffer_unref(&req->buffer); > + return NULL; > +} > + > +static int tcp_getaddrinfo_nonblock(const char *hostname, const char > *servname, > + const struct addrinfo *hints, struct > addrinfo **res, > + int64_t timeout, > + const AVIOInterruptCB *int_cb) > +{ > + int ret; > + int64_t start; > + int64_t now; > + AVBufferRef *req_ref = NULL; > + TCPAddrinfoRequest *req = NULL; > + pthread_t work_thread; > + > + if (hostname && !hostname[0]) > + hostname = NULL; > + > + if (timeout <= 0) > + return getaddrinfo(hostname, servname, hints, res); > + > + ret = tcp_getaddrinfo_request_create(&req, hostname, servname, hints, > timeout, int_cb); > + if (ret) > + goto fail; > + > + req_ref = av_buffer_ref(req->buffer); > + if (ret) > + goto fail; > + > + /* FIXME: using a thread pool would be better. */ > + ret = pthread_create(&work_thread, NULL, tcp_getaddrinfo_worker, req); > + if (ret) { > + ret = AVERROR(ret); > + goto fail; > + } > + > + pthread_detach(work_thread); > + > + start = av_gettime(); > + now = start; > + > + pthread_mutex_lock(&req->mutex); > + while (!req->finished && start + timeout > now) { > + int64_t wait_time = now + 100000; > + struct timespec tv = { .tv_sec = wait_time / 1000000, > + .tv_nsec = (wait_time % 1000000) * 1000 }; > +#if HAVE_PTHREAD_COND_TIMEWAIT_MONOTONIC_NP > + ret = pthread_cond_timedwait_monotonic_np(&req->cond, > &req->mutex, &tv); > +else > + ret = pthread_cond_timedwait(&req->cond, &req->mutex, &tv); > +#endif > + if (ret == 0 || ret != ETIMEDOUT) > + break; > + > + if (ff_check_interrupt(&req->interrupt_callback)) > + return AVERROR_EXIT; > + > + now = av_gettime(); > + } > + pthread_mutex_unlock(&req->mutex); > + > + if (!req->finished && ret != 0) { > + ret = AVERROR(ret); > + goto fail; > + } > + > + ret = req->ret; > + *res = req->res; > + req->res = NULL; > + av_buffer_unref(&req_ref); > + return ret; > +fail: > + av_buffer_unref(&req_ref); > + return ret; > +} > + > +#endif > + > /* return non zero if error */ > static int tcp_open(URLContext *h, const char *uri, int flags) > { > @@ -111,10 +299,16 @@ static int tcp_open(URLContext *h, const char *uri, > int flags) > snprintf(portstr, sizeof(portstr), "%d", port); > if (s->listen) > hints.ai_flags |= AI_PASSIVE; > +#ifdef HAVE_PTHREADS > + ret = tcp_getaddrinfo_nonblock(hostname, portstr, &hints, &ai, > s->addrinfo_timeout, &h->interrupt_callback); > +#else > + if (s->addrinfo_timeout > 0) > + av_log(h, AV_LOG_WARNING, "Ignore addrinfo_timeout without > pthreads support.\n") > if (!hostname[0]) > ret = getaddrinfo(NULL, portstr, &hints, &ai); > else > ret = getaddrinfo(hostname, portstr, &hints, &ai); > +#endif > if (ret) { > av_log(h, AV_LOG_ERROR, > "Failed to resolve hostname %s: %s\n", > -- > 2.6.4 (Apple Git-63) > > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel