Skip to content

Instantly share code, notes, and snippets.

@klaxa

klaxa/command Secret

Created March 21, 2015 20:31
Show Gist options
  • Save klaxa/60ce4fc108c865169428 to your computer and use it in GitHub Desktop.
Save klaxa/60ce4fc108c865169428 to your computer and use it in GitHub Desktop.
[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
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