-
-
Save klaxa/60ce4fc108c865169428 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[klaxa@remotehost ffmpeg]$ ./ffmpeg -i test.mp3 -c copy -http_listen -f mp3 http://0.0.0.0ffmpeg version N-70997-g84ae729 Copyright (c) 2000-2015 the FFmpeg developers | |
built with gcc 4.9.2 (GCC) 20150304 (prerelease) | |
configuration: --disable-optimizations --enable-openssl | |
libavutil 54. 20.100 / 54. 20.100 | |
libavcodec 56. 29.100 / 56. 29.100 | |
libavformat 56. 26.101 / 56. 26.101 | |
libavdevice 56. 4.100 / 56. 4.100 | |
libavfilter 5. 13.101 / 5. 13.101 | |
libswscale 3. 1.101 / 3. 1.101 | |
libswresample 1. 1.100 / 1. 1.100 | |
Unrecognized option 'http_listen'. | |
Error splitting the argument list: Option not found |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/libavformat/http.c b/libavformat/http.c | |
index da3c9be..5d991c3 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 = 1 }, 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"); | |
} | |
- | |
- ret = http_open_cnx(h, options); | |
- if (ret < 0) | |
- av_dict_free(&s->chained_options); | |
- return ret; | |
+ 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; | |
+ } | |
+ | |
+ 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment