Hi, this is a patch for a proof-of-concept for an http server.
Usage on the server side: ffmpeg -i test.mp3 -c copy -listen 1 -f mp3 http://0.0.0.0 Usage on the client side: ffplay http://localhost:8080 I looked at tls.c and tcp.c and copied parts of the code. Please comment. Regards, Stephan Holljes --- libavformat/http.c | 113 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 30 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index da3c9be..d61e4e2 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -96,8 +96,12 @@ typedef struct HTTPContext { int send_expect_100; char *method; int reconnect; + int listen; + int fd; + int header_sent; } HTTPContext; + #define OFFSET(x) offsetof(HTTPContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM @@ -127,6 +131,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", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, 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 }, { NULL } }; @@ -299,8 +304,10 @@ int ff_http_averror(int status_code, int default_averror) static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { + struct addrinfo hints = { 0 }, *ai; HTTPContext *s = h->priv_data; - int ret; + int ret = -1, fd; + char portstr[] = "8080"; // allow non-root users for now if( s->seekable == 1 ) h->is_streamed = 0; @@ -320,11 +327,39 @@ static int http_open(URLContext *h, const char *uri, int flags, av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n"); } + if (s->listen) { + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags |= AI_PASSIVE; + ret = getaddrinfo(NULL, portstr, &hints, &ai); + if (ret) { + av_log(h, AV_LOG_ERROR, "borked"); + return AVERROR(EIO); + } + fd = ff_socket(ai->ai_family, + ai->ai_socktype, + ai->ai_protocol); + if (fd < 0) { + ret = ff_neterrno(); + freeaddrinfo(ai); + return -1; + } - ret = http_open_cnx(h, options); - if (ret < 0) - av_dict_free(&s->chained_options); - return ret; + fd = ff_listen_bind(fd, ai->ai_addr, ai->ai_addrlen, -1, h); + if (fd < 0) { + freeaddrinfo(ai); + return fd; + } + h->is_streamed = 1; + s->fd = fd; + freeaddrinfo(ai); + return 0; + } else { + ret = http_open_cnx(h, options); + if (ret < 0) + av_dict_free(&s->chained_options); + return ret; + } } static int http_getc(HTTPContext *s) @@ -1102,25 +1137,40 @@ static int http_write(URLContext *h, const uint8_t *buf, int size) char temp[11] = ""; /* 32-bit hex + CRLF + nul */ int ret; char crlf[] = "\r\n"; + char header[] = "HTTP 200 OK\r\n\r\n"; HTTPContext *s = h->priv_data; + if (!s->listen) { + if (!s->chunked_post) { + /* non-chunked data is sent without any special encoding */ + return ffurl_write(s->hd, buf, size); + } - if (!s->chunked_post) { - /* non-chunked data is sent without any special encoding */ - return ffurl_write(s->hd, buf, size); - } - - /* silently ignore zero-size data since chunk encoding that would - * signal EOF */ - if (size > 0) { - /* upload data using chunked encoding */ - snprintf(temp, sizeof(temp), "%x\r\n", size); + /* silently ignore zero-size data since chunk encoding that would + * signal EOF */ + if (size > 0) { + /* upload data using chunked encoding */ + snprintf(temp, sizeof(temp), "%x\r\n", size); - if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 || - (ret = ffurl_write(s->hd, buf, size)) < 0 || - (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0) - return ret; + if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 || + (ret = ffurl_write(s->hd, buf, size)) < 0 || + (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0) + return ret; + } + return size; + } else { + if (!s->header_sent) { + ret = send(s->fd, header, sizeof(header), MSG_NOSIGNAL); + s->header_sent = 1; + return ret < 0 ? ff_neterrno() : ret; + } + if (size > 0) { + ret = send(s->fd, buf, size, MSG_NOSIGNAL); + return ret < 0 ? ff_neterrno() : ret; + } else { + ret = -1; + } + return ret; } - return size; } static int http_shutdown(URLContext *h, int flags) @@ -1143,20 +1193,23 @@ static int http_close(URLContext *h) { int ret = 0; HTTPContext *s = h->priv_data; - + if (!s->listen) { #if CONFIG_ZLIB - inflateEnd(&s->inflate_stream); - av_freep(&s->inflate_buffer); + inflateEnd(&s->inflate_stream); + av_freep(&s->inflate_buffer); #endif /* CONFIG_ZLIB */ - if (!s->end_chunked_post) - /* Close the write direction by sending the end of chunked encoding. */ - ret = http_shutdown(h, h->flags); + if (!s->end_chunked_post) + /* Close the write direction by sending the end of chunked encoding. */ + ret = http_shutdown(h, h->flags); - if (s->hd) - ffurl_closep(&s->hd); - av_dict_free(&s->chained_options); - return ret; + if (s->hd) + ffurl_closep(&s->hd); + av_dict_free(&s->chained_options); + return ret; + } else { + return shutdown(s->fd, SHUT_RDWR); + } } static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel