[FFmpeg-devel] GSoC update

Nicolas George george at nsup.org
Fri Jun 26 23:09:53 CEST 2015


L'octidi 8 messidor, an CCXXIII, Stephan Holljes a écrit :
> I think I implemented everything necessary, but I don't know how to
> test it. The old behaviour of accepting a single client is now also
> broken.

Since that behaviour was already established, breaking it without notice is
not an option :(

> How do I detect which behaviour the user wants? Should I introduce a new
> option for http and tcp connections or make the listen field take more
> values than just 0 and 1?

Increasing the range for listen is a good idea.

I am afraid it will make the accept functions a but awkward, having to work
with either two contexts (server and client) or only one (server that will
become client).

> Attached are patches with the changes I made so far. It compiles, but
> breaks http server capabilities for now.

To actually test multi-client code, it will be necessary to write a
multi-client sample application. Fortunately, that should not be very hard.


> From 22f958ad8d0058865c94847ca8cd2488e2a61c9e Mon Sep 17 00:00:00 2001
> From: Stephan Holljes <klaxa1337 at googlemail.com>
> Date: Fri, 26 Jun 2015 20:48:49 +0200
> Subject: [PATCH 1/6] lavf/network: split ff_listen_bind into ff_listen and
>  ff_accept
> 
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  libavformat/network.c | 27 +++++++++++++++++++++------
>  libavformat/network.h |  4 ++++
>  2 files changed, 25 insertions(+), 6 deletions(-)
> 
> diff --git a/libavformat/network.c b/libavformat/network.c
> index 47ade8c..8d61746 100644
> --- a/libavformat/network.c
> +++ b/libavformat/network.c
> @@ -187,12 +187,11 @@ int ff_socket(int af, int type, int proto)
>      return fd;
>  }
>  
> -int ff_listen_bind(int fd, const struct sockaddr *addr,
> -                   socklen_t addrlen, int timeout, URLContext *h)
> +int ff_listen(int fd, const struct sockaddr *addr,
> +              socklen_t addrlen)
>  {
>      int ret;
>      int reuse = 1;
> -    struct pollfd lp = { fd, POLLIN, 0 };
>      if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
>          av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
>      }
> @@ -203,6 +202,13 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
>      ret = listen(fd, 1);
>      if (ret)
>          return ff_neterrno();
> +    return ret;
> +}
> +
> +int ff_accept(int fd, int timeout, URLContext *h)
> +{
> +    int ret;
> +    struct pollfd lp = { fd, POLLIN, 0 };
>  
>      ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
>      if (ret < 0)
> @@ -211,15 +217,24 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
>      ret = accept(fd, NULL, NULL);
>      if (ret < 0)
>          return ff_neterrno();
> -
> -    closesocket(fd);
> -
>      if (ff_socket_nonblock(ret, 1) < 0)
>          av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
>  
>      return ret;
>  }
>  
> +int ff_listen_bind(int fd, const struct sockaddr *addr,
> +                   socklen_t addrlen, int timeout, URLContext *h)
> +{
> +    int ret;
> +    if ((ret = ff_listen(fd, addr, addrlen)) < 0)
> +        return ret;
> +    ret = ff_accept(fd, timeout, h);
> +    closesocket(fd);
> +    return ret;
> +
> +}
> +
>  int ff_listen_connect(int fd, const struct sockaddr *addr,
>                        socklen_t addrlen, int timeout, URLContext *h,
>                        int will_try_next)
> diff --git a/libavformat/network.h b/libavformat/network.h
> index 86fb656..44e109c 100644
> --- a/libavformat/network.h
> +++ b/libavformat/network.h
> @@ -254,6 +254,10 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
>                     socklen_t addrlen, int timeout,
>                     URLContext *h);
>  
> +int ff_listen(int fd, const struct sockaddr *addr, socklen_t addrlen);
> +
> +int ff_accept(int fd, int timeout, URLContext *h);
> +
>  /**
>   * Connect to a file descriptor and poll for result.
>   *
> -- 
> 2.1.0
> 

> From 4d0b5e42882f180d76a3a64da96dc87bf0ba0635 Mon Sep 17 00:00:00 2001
> From: Stephan Holljes <klaxa1337 at googlemail.com>
> Date: Fri, 26 Jun 2015 20:50:35 +0200
> Subject: [PATCH 2/6] lavf/avio: add ffurl_accept
> 
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  libavformat/avio.c | 5 +++++
>  libavformat/url.h  | 9 +++++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/libavformat/avio.c b/libavformat/avio.c
> index aff8d10..153230f 100644
> --- a/libavformat/avio.c
> +++ b/libavformat/avio.c
> @@ -211,6 +211,11 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
>      return 0;
>  }
>  
> +int ffurl_accept(URLContext *sc, URLContext *cc)
> +{
> +    return sc->prot->url_accept(sc, cc);
> +}
> +
>  #define URL_SCHEME_CHARS                        \
>      "abcdefghijklmnopqrstuvwxyz"                \
>      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                \
> diff --git a/libavformat/url.h b/libavformat/url.h
> index 99a3201..34fdea2 100644
> --- a/libavformat/url.h
> +++ b/libavformat/url.h
> @@ -58,6 +58,7 @@ typedef struct URLProtocol {
>       * for those nested protocols.
>       */
>      int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);
> +    int     (*url_accept)(URLContext *s, URLContext *c);
>  
>      /**
>       * Read data from the protocol.
> @@ -140,6 +141,14 @@ int ffurl_open(URLContext **puc, const char *filename, int flags,
>                 const AVIOInterruptCB *int_cb, AVDictionary **options);
>  
>  /**
> + * Accept an URLContext c on an URLContext s
> + * @param  s server context
> + * @param  c client context
> + * @return 0 on success, ff_neterrno() on failure.
> + */
> +int ffurl_accept(URLContext *s, URLContext *c);
> +
> +/**
>   * Read up to size bytes from the resource accessed by h, and store
>   * the read bytes in buf.
>   *
> -- 
> 2.1.0
> 

> From 4a2f643af7cc5a7692a6267f484ba3f8d0363066 Mon Sep 17 00:00:00 2001
> From: Stephan Holljes <klaxa1337 at googlemail.com>
> Date: Fri, 26 Jun 2015 20:51:26 +0200
> Subject: [PATCH 3/6] lavf/avio: add avio_accept
> 
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  libavformat/avio.h    |  1 +
>  libavformat/aviobuf.c | 12 ++++++++++++
>  2 files changed, 13 insertions(+)
> 
> diff --git a/libavformat/avio.h b/libavformat/avio.h
> index 5ac5d38..f688851 100644
> --- a/libavformat/avio.h
> +++ b/libavformat/avio.h
> @@ -648,4 +648,5 @@ struct AVBPrint;
>   */
>  int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size);
>  
> +int avio_accept(AVIOContext *s, AVIOContext **c);
>  #endif /* AVFORMAT_AVIO_H */
> diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
> index ff85081..dcdc1a4 100644
> --- a/libavformat/aviobuf.c
> +++ b/libavformat/aviobuf.c
> @@ -1021,6 +1021,18 @@ int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size)
>      return 0;
>  }
>  
> +int avio_accept(AVIOContext *s, AVIOContext **c) {
> +    URLContext *sc = s->opaque;
> +    URLContext *cc;
> +    int ret;
> +    if ((ret = ffurl_open(&cc, sc->filename, AVIO_FLAG_READ_WRITE, &sc->interrupt_callback, NULL)) < 0)
> +        return ret;
> +    if ((ret = ffio_fdopen(c, cc)) < 0)
> +        return ret;
> +    ret = ffurl_accept(sc, cc);
> +    return ret;
> +}
> +
>  /* output in a dynamic buffer */
>  
>  typedef struct DynBuffer {
> -- 
> 2.1.0
> 

> From 8e83b82efb5ae26296bed8244fba1fd93b978f48 Mon Sep 17 00:00:00 2001
> From: Stephan Holljes <klaxa1337 at googlemail.com>
> Date: Fri, 26 Jun 2015 20:55:58 +0200
> Subject: [PATCH 4/6] lavf/tcp: make tcp_open return with a listening socket
>  without calling accept()
> 
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  libavformat/tcp.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/libavformat/tcp.c b/libavformat/tcp.c
> index f24cad2..04210b3 100644
> --- a/libavformat/tcp.c
> +++ b/libavformat/tcp.c
> @@ -126,11 +126,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
>      }
>  
>      if (s->listen) {
> -        if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
> -                                  s->listen_timeout, h)) < 0) {
> +        if ((ret = ff_listen(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) < 0) {
>              goto fail1;
>          }
> -        fd = ret;
>      } else {
>          if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
>                                       s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) {
> -- 
> 2.1.0
> 

> From 418fcd63d8e5ff721ba38763f3677d1b5be6396b Mon Sep 17 00:00:00 2001
> From: Stephan Holljes <klaxa1337 at googlemail.com>
> Date: Fri, 26 Jun 2015 20:56:27 +0200
> Subject: [PATCH 5/6] lavf/tcp: add tcp_accept
> 
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  libavformat/tcp.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/libavformat/tcp.c b/libavformat/tcp.c
> index 04210b3..588e602 100644
> --- a/libavformat/tcp.c
> +++ b/libavformat/tcp.c
> @@ -161,6 +161,20 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
>      return ret;
>  }
>  
> +static int tcp_accept(URLContext *s, URLContext *c)
> +{
> +    TCPContext *sc = s->priv_data;
> +    TCPContext *cc = c->priv_data;
> +    int ret;
> +    ret = accept(sc->fd, NULL, NULL);
> +    if (ret < 0) {
> +        return ff_neterrno();
> +    }
> +    cc->fd = ret;
> +    return 0;
> +
> +}
> +
>  static int tcp_read(URLContext *h, uint8_t *buf, int size)
>  {
>      TCPContext *s = h->priv_data;
> @@ -221,6 +235,7 @@ static int tcp_get_file_handle(URLContext *h)
>  URLProtocol ff_tcp_protocol = {
>      .name                = "tcp",
>      .url_open            = tcp_open,
> +    .url_accept          = tcp_accept,
>      .url_read            = tcp_read,
>      .url_write           = tcp_write,
>      .url_close           = tcp_close,
> -- 
> 2.1.0
> 

> From 88632fa0d54a68c8876e8024c76ead5245be73d1 Mon Sep 17 00:00:00 2001
> From: Stephan Holljes <klaxa1337 at googlemail.com>
> Date: Fri, 26 Jun 2015 20:58:56 +0200
> Subject: [PATCH 6/6] lavf/http: add http_accept and move connection logic to
>  it, since ffurl_open in http_listen returns without a connected client
> 
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  libavformat/http.c | 29 +++++++++++++++++++++--------
>  1 file changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/libavformat/http.c b/libavformat/http.c
> index 676bfd5..65ac507 100644
> --- a/libavformat/http.c
> +++ b/libavformat/http.c
> @@ -320,11 +320,10 @@ static int http_listen(URLContext *h, const char *uri, int flags,
>                         AVDictionary **options) {
>      HTTPContext *s = h->priv_data;
>      int ret;
> -    static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n";
>      char hostname[1024], proto[10];
>      char lower_url[100];
>      const char *lower_proto = "tcp";
> -    int port, new_location;
> +    int port;
>      s->chunked_post = 1;
>      av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
>                   NULL, 0, uri);
> @@ -336,12 +335,6 @@ static int http_listen(URLContext *h, const char *uri, int flags,
>      if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
>                            &h->interrupt_callback, options)) < 0)
>          goto fail;
> -    if ((ret = http_read_header(h, &new_location)) < 0)
> -         goto fail;
> -    if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0)
> -         goto fail;
> -    return 0;
> -
>  fail:
>      handle_http_errors(h, ret);
>      av_dict_free(&s->chained_options);
> @@ -382,6 +375,25 @@ static int http_open(URLContext *h, const char *uri, int flags,
>      return ret;
>  }
>  
> +static int http_accept(URLContext *s, URLContext *c)
> +{
> +    int ret, new_location;
> +    static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n";
> +    HTTPContext *sh = s->priv_data;
> +    HTTPContext *ch = c->priv_data;
> +    URLContext *sl = sh->hd;
> +    URLContext *cl = ch->hd;

> +    if ((ret = ffurl_accept(sl, cl)) < 0)
> +        goto fail;
> +    if ((ret = http_read_header(s, &new_location)) < 0)
> +        goto fail;

This is what I explained earlier: These need to be in two separate API
functions, because the application will probably want to fork a new thread
between ffurl_accept() and http_read_header().

> +    if ((ret = ffurl_write(sl, header, strlen(header))) < 0)
> +        goto fail;
> +fail:
> +    handle_http_errors(s, ret);
> +    return ret;
> +}
> +
>  static int http_getc(HTTPContext *s)
>  {
>      int len;
> @@ -1477,6 +1489,7 @@ static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
>  URLProtocol ff_httpproxy_protocol = {
>      .name                = "httpproxy",
>      .url_open            = http_proxy_open,
> +    .url_accept          = http_accept,
>      .url_read            = http_buf_read,
>      .url_write           = http_proxy_write,
>      .url_close           = http_proxy_close,

Thanks for the timely update. I will look at the code more carefully but it
seems to be going in the right direction.

Regards,

-- 
  Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150626/665b6e97/attachment.asc>


More information about the ffmpeg-devel mailing list