[FFmpeg-devel] GSoC update

Stephan Holljes klaxa1337 at googlemail.com
Fri Jul 3 04:33:53 CEST 2015


On Wed, Jul 1, 2015 at 4:10 PM, Nicolas George <george at nsup.org> wrote:
> Le duodi 12 messidor, an CCXXIII, Stephan Holljes a écrit :
>> This might be a stupid question, but how would I go about that? Just
>> use open() and read() from stdio.h or are there structs that allow me
>> to do that even more easily?
>
> You must use the avio family of function, not the OS functions directly. You
> can have a look at tools/aviocat.c, it is rather simple and does a good
> chunk of what your server needs to do per client.
>
>> From b0f0caa700b8cbd0352304de703d8191bf0ac922 Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 07:42:14 +0200
>> Subject: [PATCH 1/8] 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 | 21 +++++++++++++++++++++
>>  2 files changed, 42 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;
>
> I believe you are slightly changing the behaviour here: in the old code, if
> accept() fails, the server is not closed.
>
>> +
>> +}
>> +
>>  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..e684787 100644
>> --- a/libavformat/network.h
>> +++ b/libavformat/network.h
>> @@ -255,6 +255,27 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
>>                     URLContext *h);
>>
>>  /**
>
>> + * Bind to a file descriptor and return a listening socket without accepting connections.
>> + * @param fd      First argument of bind().
>> + * @param addr    Second argument of bind().
>> + * @param addrlen Third argument of bind().
>> + * @return        A blocking file descriptor on success
>> + *                or an AVERROR on failure.
>
> I believe the summary and @return statements are wrong: the new code always
> returns 0 for success, which is fine.
>
>> + */
>> +int ff_listen(int fd, const struct sockaddr *addr, socklen_t addrlen);
>> +
>> +/**
>> + * Poll for a single connection on the passed file descriptor.
>> + * @param fd      The listening socket file descriptor.
>> + * @param timeout Polling timeout in milliseconds.
>> + * @param h       URLContext providing interrupt check
>> + *                callback and logging context.
>> + * @return        A non-blocking file descriptor on success
>> + *                or an AVERROR on failure.
>> + */
>> +int ff_accept(int fd, int timeout, URLContext *h);
>> +
>> +/**
>>   * Connect to a file descriptor and poll for result.
>>   *
>>   * @param fd       First argument of connect(),
>> --
>> 2.1.0
>>
>
>> From 330c0eedaede961e52a4a4d93b2211156bc15a69 Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 08:16:37 +0200
>> Subject: [PATCH 2/8] lavf/avio: add ffurl_accept and ffurl_handshake
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  libavformat/avio.c | 17 +++++++++++++++++
>>  libavformat/url.h  | 18 ++++++++++++++++++
>>  2 files changed, 35 insertions(+)
>>
>> diff --git a/libavformat/avio.c b/libavformat/avio.c
>> index c188adc..63c8b75 100644
>> --- a/libavformat/avio.c
>> +++ b/libavformat/avio.c
>> @@ -211,6 +211,23 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
>>      return 0;
>>  }
>>
>> +int ffurl_accept(URLContext *s, URLContext **c)
>> +{
>> +    int ret;
>
>> +    if ((ret = s->prot->url_accept(s, c)) < 0)
>> +        return ret;
>
> This will crash if called on a non-server socket. A test on
> s->prot->url_accept with a clear error message and a return code would be a
> good idea. av_assert0() would probably be acceptable too, as it only happens
> in case of clear application error.

I hope I fixed this apropriately.

>
> Another solution would be to have a "listen" field in the URLContext
> structure and test it, changing it to reflect the listen status (normal
> client, server, client during handshake, single-shot server), but that can
> be done later.
>
>> +    (*c)->is_connected = 1;
>
> Maybe this should go in url_handshake().
>
>> +    return ret;
>> +
>> +}
>
> Stray empty line.
>
>> +
>> +int ffurl_handshake(URLContext *c)
>> +{
>> +    if (c->prot->url_handshake)
>> +        return c->prot->url_handshake(c);
>> +    return 0;
>> +}
>> +
>>  #define URL_SCHEME_CHARS                        \
>>      "abcdefghijklmnopqrstuvwxyz"                \
>>      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                \
>> diff --git a/libavformat/url.h b/libavformat/url.h
>> index 99a3201..4cf6892 100644
>> --- a/libavformat/url.h
>> +++ b/libavformat/url.h
>> @@ -58,6 +58,8 @@ 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);
>> +    int     (*url_handshake)(URLContext *c);
>>
>>      /**
>>       * Read data from the protocol.
>> @@ -140,6 +142,22 @@ 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 the accepted filedescriptor on success, ff_neterrno() on failure.
>
> The return value is not a file descriptor. Probably just ">= 0 on success".
>
>> + */
>> +int ffurl_accept(URLContext *s, URLContext **c);
>> +
>> +/**
>
>> + * Performs a protocl handshake on the passed client context.
>
> Inconsistent spelling: most of the doxy are in an impersonal form:
> "perform".
>
>> + * @param  c the client context
>> + * @return >= 0 on success or a negative value corresponding
>> + *         to an AVERROR code on failure
>> + */
>> +int ffurl_handshake(URLContext *c);
>> +
>> +/**
>>   * Read up to size bytes from the resource accessed by h, and store
>>   * the read bytes in buf.
>>   *
>> --
>> 2.1.0
>>
>
>> From 8d8cb5e32a12aedb489a36cf9a26d961244d36a0 Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 08:24:09 +0200
>> Subject: [PATCH 3/8] lavf/avio: add avio_accept and avio_handshake
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  libavformat/avio.h    | 16 ++++++++++++++++
>>  libavformat/aviobuf.c | 17 +++++++++++++++++
>>  2 files changed, 33 insertions(+)
>>
>> diff --git a/libavformat/avio.h b/libavformat/avio.h
>> index d3d9bbd..667e3c5 100644
>> --- a/libavformat/avio.h
>> +++ b/libavformat/avio.h
>> @@ -648,4 +648,20 @@ struct AVBPrint;
>>   */
>>  int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size);
>>
>> +/**
>
>> + * Accepts and allocates a client context on a server context.
>
> Ditto.
>
>> + * @param  s the server context
>> + * @param  c the client context
>> + * @return   >= 0 on success or a negative value corresponding
>> + *           to an AVERROR on failure
>> + */
>> +int avio_accept(AVIOContext *s, AVIOContext **c);
>> +
>> +/**
>
>> + * Performs a protocol dependent handshake
>
> Ditto.
>
>> + * @param  c the client context to perform the handshake on
>> + * @return   >= 0 on success or a negative value corresponding
>> + *           to an AVERROR on failure
>> + */
>
>> +int avio_handshake(AVIOContext *c);
>>  #endif /* AVFORMAT_AVIO_H */
>> diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
>> index ff85081..0591ba5 100644
>> --- a/libavformat/aviobuf.c
>> +++ b/libavformat/aviobuf.c
>> @@ -1021,6 +1021,23 @@ int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size)
>>      return 0;
>>  }
>>
>> +int avio_accept(AVIOContext *s, AVIOContext **c)
>> +{
>> +    int ret;
>> +    URLContext *sc = s->opaque;
>> +    URLContext *cc;
>> +    ret = ffurl_accept(sc, &cc);
>> +    if (ret > 0)
>> +        ret = ffio_fdopen(c, cc);
>> +    return ret;
>> +}
>> +
>> +int avio_handshake(AVIOContext *c)
>> +{
>> +    URLContext *cc = c->opaque;
>> +    return ffurl_handshake(cc);
>> +}
>> +
>>  /* output in a dynamic buffer */
>>
>>  typedef struct DynBuffer {
>> --
>> 2.1.0
>>
>
>> From b8071e7b6416c37fb05cfae29dd4a29ea71bc41e Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 09:28:48 +0200
>> Subject: [PATCH 4/8] lavf/tcp: add tcp_accept
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  libavformat/tcp.c | 17 +++++++++++++++++
>>  1 file changed, 17 insertions(+)
>>
>> diff --git a/libavformat/tcp.c b/libavformat/tcp.c
>> index f24cad2..ddaecc9 100644
>> --- a/libavformat/tcp.c
>> +++ b/libavformat/tcp.c
>> @@ -163,6 +163,22 @@ 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;
>> +    int ret;
>> +    if ((ret = ffurl_alloc(c, s->filename, AVIO_FLAG_READ_WRITE, &s->interrupt_callback)) < 0)
>> +        return ret;
>> +    cc = (*c)->priv_data;
>> +    ret = accept(sc->fd, NULL, NULL);
>> +    if (ret < 0) {
>> +        return ff_neterrno();
>> +    }
>> +    cc->fd = ret;
>
>> +    return ret;
>
> File descriptors are meaningless outside the actual implementation, so
> "return 0" would probably be better.
>
>> +}
>> +
>>  static int tcp_read(URLContext *h, uint8_t *buf, int size)
>>  {
>>      TCPContext *s = h->priv_data;
>> @@ -223,6 +239,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 e493cad7d123025a27f04721ba236593ea44738b Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 09:29:16 +0200
>> Subject: [PATCH 5/8] lavf/tcp: increase range for listen and call the
>>  underlying socket operations accordingly
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  libavformat/tcp.c | 13 +++++++++----
>>  1 file changed, 9 insertions(+), 4 deletions(-)
>>
>> diff --git a/libavformat/tcp.c b/libavformat/tcp.c
>> index ddaecc9..a7a5d74 100644
>> --- a/libavformat/tcp.c
>> +++ b/libavformat/tcp.c
>> @@ -44,7 +44,7 @@ typedef struct TCPContext {
>>  #define D AV_OPT_FLAG_DECODING_PARAM
>>  #define E AV_OPT_FLAG_ENCODING_PARAM
>>  static const AVOption options[] = {
>> -    { "listen",          "Listen for incoming connections",  OFFSET(listen),         AV_OPT_TYPE_INT, { .i64 = 0 },     0,       1,       .flags = D|E },
>> +    { "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 },
>>      { NULL }
>> @@ -125,12 +125,17 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
>>          goto fail;
>>      }
>>
>> -    if (s->listen) {
>> -        if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
>> +    if (s->listen == 2) {
>> +        // multi-client
>> +        if ((ret = ff_listen(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) < 0) {
>> +            goto fail1;
>> +        }
>> +    } else if (s->listen == 1) {
>> +        // single client
>
>> +        if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
>>                                    s->listen_timeout, h)) < 0) {
>>              goto fail1;
>
> This code goes to fail1 without setting ret.
>
>>          }
>> -        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 c8622b35795ea52dc0b25ce1d5d196d1d561e250 Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 09:58:09 +0200
>> Subject: [PATCH 6/8] lavf/http: add http_accept and http_handshake
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  libavformat/http.c | 38 ++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 38 insertions(+)
>>
>> diff --git a/libavformat/http.c b/libavformat/http.c
>> index 676bfd5..9b67b0b 100644
>> --- a/libavformat/http.c
>> +++ b/libavformat/http.c
>> @@ -316,6 +316,21 @@ static void handle_http_errors(URLContext *h, int error)
>>      }
>>  }
>>
>> +static int http_handshake(URLContext *c) {
>> +    int ret, err, new_location;
>> +    HTTPContext *ch = c->priv_data;
>> +    URLContext *cl = ch->hd;
>> +    static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n";
>
>> +    ffurl_handshake(cl);
>
> Needs error check.
>
>> +    if ((err = http_read_header(c, &new_location)) < 0)
>> +        goto fail;
>> +    if ((ret = ffurl_write(cl, header, strlen(header))) < 0)
>> +        goto fail;
>> +fail:
>> +    handle_http_errors(c, err);
>> +    return ret;
>> +}
>> +
>>  static int http_listen(URLContext *h, const char *uri, int flags,
>>                         AVDictionary **options) {
>>      HTTPContext *s = h->priv_data;
>> @@ -382,6 +397,23 @@ static int http_open(URLContext *h, const char *uri, int flags,
>>      return ret;
>>  }
>>
>> +static int http_accept(URLContext *s, URLContext **c)
>> +{
>> +    int ret;
>> +    HTTPContext *sc = s->priv_data;
>> +    HTTPContext *cc;
>> +    URLContext *sl = sc->hd;
>> +    URLContext *cl;
>
>> +    if ((ret = ffurl_alloc(c, s->filename, AVIO_FLAG_READ_WRITE, &sl->interrupt_callback)) < 0)
>
> AVIO_FLAG_READ_WRITE seems wrong.

Changed to AVIO_FLAG_WRITE, but don't we read the request data from
the client? Why does it work as intended with AVIO_FLAG_WRITE?

>
>> +        goto fail;
>> +    cc = (*c)->priv_data;
>> +    if ((ret = ffurl_accept(sl, &cl)) < 0)
>> +        goto fail;
>> +    cc->hd = cl;
>> +fail:
>> +    return ret;
>> +}
>> +
>>  static int http_getc(HTTPContext *s)
>>  {
>>      int len;
>> @@ -1346,6 +1378,8 @@ HTTP_CLASS(http);
>>  URLProtocol ff_http_protocol = {
>>      .name                = "http",
>>      .url_open2           = http_open,
>> +    .url_accept          = http_accept,
>> +    .url_handshake       = http_handshake,
>>      .url_read            = http_read,
>>      .url_write           = http_write,
>>      .url_seek            = http_seek,
>> @@ -1364,6 +1398,8 @@ HTTP_CLASS(https);
>>  URLProtocol ff_https_protocol = {
>
>>      .name                = "https",
>>      .url_open2           = http_open,
>> +    .url_accept          = http_accept,
>> +    .url_handshake       = http_handshake,
>
> Did you test this one? My guess is it will not work because the
> accept/handshake callbacks are not implemented for the TLS code.

Removed in the new patch. I just blindly added the fields without
testing, my bad.

>
>>      .url_read            = http_read,
>>      .url_write           = http_write,
>>      .url_seek            = http_seek,
>> @@ -1477,6 +1513,8 @@ 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_handshake       = http_handshake,
>
> I am not sure the proxy client code needs a server side.

Also removed, this, too, was added blindly.

>
>>      .url_read            = http_buf_read,
>>      .url_write           = http_proxy_write,
>>      .url_close           = http_proxy_close,
>> --
>> 2.1.0
>>
>
>> From b183b01c2bd1978d922f9516f59b200415285823 Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 11:12:15 +0200
>> Subject: [PATCH 7/8] lavf/http: increase range for listen, add http_handshake
>>  and move handshake logic there
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  libavformat/http.c | 24 +++++++++++-------------
>>  1 file changed, 11 insertions(+), 13 deletions(-)
>>
>> diff --git a/libavformat/http.c b/libavformat/http.c
>> index 9b67b0b..f6a6620 100644
>> --- a/libavformat/http.c
>> +++ b/libavformat/http.c
>> @@ -128,7 +128,7 @@ static const AVOption options[] = {
>>      { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
>>      { "method", "Override the HTTP method or set the expected HTTP method from a client", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
>>      { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D },
>> -    { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E },
>> +    { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E },
>>      { NULL }
>>  };
>>
>> @@ -306,6 +306,8 @@ static void handle_http_errors(URLContext *h, int error)
>>      HTTPContext *s = h->priv_data;
>>      if (h->is_connected) {
>>          switch(error) {
>
>> +            case 0:
>> +                break;
>
> I suspect this belongs in patch #6.
>
>>              case AVERROR_HTTP_BAD_REQUEST:
>>                  ffurl_write(s->hd, bad_request, strlen(bad_request));
>>                  break;
>> @@ -335,11 +337,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);
>> @@ -347,20 +348,17 @@ static int http_listen(URLContext *h, const char *uri, int flags,
>>          lower_proto = "tls";
>>      ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port,
>>                  NULL);
>> -    av_dict_set(options, "listen", "1", 0);
>
>> +    av_dict_set_int(options, "listen", s->listen, 0);
>
> Needs error check since not all underlying protocols support listen=2 yet.
>
>>      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;
>> -
>> +    if (s->listen == 1) {
>> +        // single client
>> +        ret = http_handshake(h);
>> +    }
>>  fail:
>> -    handle_http_errors(h, ret);
>>      av_dict_free(&s->chained_options);
>> -    return ret;
>> +    return 0;
>>  }
>>
>>  static int http_open(URLContext *h, const char *uri, int flags,
>> @@ -1295,7 +1293,7 @@ static int http_close(URLContext *h)
>>      av_freep(&s->inflate_buffer);
>>  #endif /* CONFIG_ZLIB */
>>
>> -    if (!s->end_chunked_post)
>> +    if ((s->listen != 2 && !s->end_chunked_post))
>>          /* Close the write direction by sending the end of chunked encoding. */
>>          ret = http_shutdown(h, h->flags);
>>
>> --
>> 2.1.0
>>
>
>> From 803a41609cf37ee44763ada91ae31142873a845a Mon Sep 17 00:00:00 2001
>> From: Stephan Holljes <klaxa1337 at googlemail.com>
>> Date: Tue, 30 Jun 2015 11:12:58 +0200
>> Subject: [PATCH 8/8] doc/protocols: document experimental mutli-client api
>>
>> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
>> ---
>>  doc/protocols.texi | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/doc/protocols.texi b/doc/protocols.texi
>> index 453dbcf..39a132a 100644
>> --- a/doc/protocols.texi
>> +++ b/doc/protocols.texi
>> @@ -292,6 +292,8 @@ autodetection in the future.
>>  If set to 1 enables experimental HTTP server. This can be used to send data when
>>  used as an output option, or read data from a client with HTTP POST when used as
>>  an input option.
>> +If set to 2 enables experimental mutli-client HTTP server. This is not yet implemented
>> +in ffmpeg.c or ffserver.c and thus must not be used as a command line option.
>>  @example
>>  # Server side (sending):
>>  ffmpeg -i somefile.ogg -c copy -listen 1 -f ogg http://@var{server}:@var{port}
>
> This is all for now. I would say it is looking rather promising.
>
> Regards,
>
> --
>   Nicolas George
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Since I was told on IRC that sending git send-email patches is
preferred over attached patch-files, I will send the patches in a
series of follow-up emails.
Thanks again for your feedback!

Regards,
Stephan


More information about the ffmpeg-devel mailing list