Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- httpd.h | 58 +++++++++++++++++++++++ lavfhttpd.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 httpd.h create mode 100644 lavfhttpd.c
diff --git a/httpd.h b/httpd.h new file mode 100644 index 0000000..6fb91bd --- /dev/null +++ b/httpd.h @@ -0,0 +1,58 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef HTTPDINTERFACE_H +#define HTTPDINTERFACE_H + +#define HTTPD_OK 0 +#define HTTPD_LISTEN_TIMEOUT -1 +#define HTTPD_CLIENT_ERROR -2 +#define HTTPD_OTHER_ERROR -3 + +#include "publisher.h" + +/* HTTPD Config struct */ +struct HTTPDConfig { + char *bind_address; + int port; + int accept_timeout; +}; + +/* HTTPClient struct, this information is shared between ffserver and the httpd implementation */ +struct HTTPClient { + /* the method requested by the client, this field has to be set and freed by the httpd implementation */ + char *method; + /* the resource requested by the client, this field has to be set and freed by the httpd implementation */ + char *resource; + void *httpd_data; // httpd implementation specific data +}; + +/* HTTPDInterface that an httpd implementation must provide */ +struct HTTPDInterface { + int (*init) (void **server, struct HTTPDConfig config); + int (*free) (void *server); + int (*accept)(void *server, struct HTTPClient **client, int reply_code); + int (*write) (void *server, struct HTTPClient *client, const unsigned char *buf, int size); + int (*read) (void *server, struct HTTPClient *client, unsigned char *buf, int size); + void (*close)(void *server, struct HTTPClient *client); + void (*shutdown)(void *server); +}; + +/* Current HTTPDInterface implementation using lavformat */ +extern struct HTTPDInterface lavfhttpd; +#endif diff --git a/lavfhttpd.c b/lavfhttpd.c new file mode 100644 index 0000000..41f6d3e --- /dev/null +++ b/lavfhttpd.c @@ -0,0 +1,150 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LAVFHTTPD_H +#define LAVFHTTPD_H + +#include "httpd.h" +#include <libavutil/opt.h> + + +int lavfhttpd_init(void **server, struct HTTPDConfig config) +{ + char out_uri[1024]; + int ret; + AVDictionary *opts = NULL; + AVIOContext *server_ctx = NULL; + + snprintf(out_uri, 1024, "http://%s:%d", config.bind_address, config.port); + + avformat_network_init(); + + if ((ret = av_dict_set(&opts, "listen", "2", 0)) < 0) { + av_log(opts, AV_LOG_ERROR, "Failed to set listen mode for server: %s\n", av_err2str(ret)); + av_free(opts); + return -1; + } + + if ((ret = av_dict_set_int(&opts, "listen_timeout", config.accept_timeout, 0)) < 0) { + av_log(opts, AV_LOG_ERROR, "Failed to set listen_timeout for server: %s\n", av_err2str(ret)); + av_free(opts); + return -1; + } + + if ((ret = avio_open2(&server_ctx, out_uri, AVIO_FLAG_WRITE, NULL, &opts)) < 0) { + av_log(server, AV_LOG_ERROR, "Failed to open server: %s\n", av_err2str(ret)); + av_free(opts); + return -1; + } + av_free(opts); + + *server = server_ctx; + return 0; +} + +int lavfhttpd_accept(void *server, struct HTTPClient **client, int reply_code) +{ + AVIOContext *server_ctx = (AVIOContext*) server; + AVIOContext *client_ctx = NULL; + struct HTTPClient *client_http = NULL; + int ret, ret2, handshake; + int reply_code2 = reply_code; + char *method, *resource; + if ((ret = avio_accept(server_ctx, &client_ctx)) < 0) { + if (ret == AVERROR(ETIMEDOUT)) + return HTTPD_LISTEN_TIMEOUT; + else + return HTTPD_OTHER_ERROR; + } + client_ctx->seekable = 0; + ret2 = HTTPD_OK; + client_http = av_malloc(sizeof(struct HTTPClient)); + client_http->method = NULL; + client_http->resource = NULL; + client_http->httpd_data = client_ctx; + while ((handshake = avio_handshake(client_ctx)) > 0) { + av_opt_get(client_ctx, "method", AV_OPT_SEARCH_CHILDREN, &method); + av_opt_get(client_ctx, "resource", AV_OPT_SEARCH_CHILDREN, &resource); + av_log(client_ctx, AV_LOG_DEBUG, "method: %s resource: %s\n", method, resource); + if (method && strlen(method) && strncmp("GET", method, 3)) { + ret2 = HTTPD_CLIENT_ERROR; + reply_code2 = 400; + if ((ret = av_opt_set_int(client_ctx, "reply_code", reply_code2, AV_OPT_SEARCH_CHILDREN)) < 0) { + av_log(client_ctx, AV_LOG_WARNING, "Failed to set reply_code: %s.\n", av_err2str(ret)); + } + } + if (client_http->method) + av_free(client_http->method); + if (client_http->resource) + av_free(client_http->resource); + client_http->method = av_strdup(method); + client_http->resource = av_strdup(resource); + av_free(method); + av_free(resource); + } + if (handshake < 0) { + ret2 = HTTPD_CLIENT_ERROR; + reply_code2 = 400; + } + + if ((ret = av_opt_set_int(client_ctx, "reply_code", reply_code2, AV_OPT_SEARCH_CHILDREN)) < 0) { + av_log(client_ctx, AV_LOG_WARNING, "Failed to set reply_code: %s.\n", av_err2str(ret)); + } + + *client = client_http; + return ret2; +} + +int lavfhttpd_write(void *server, struct HTTPClient *client, const unsigned char *buf, int size) +{ + AVIOContext *client_ctx = (AVIOContext*) client->httpd_data; + avio_write(client_ctx, buf, size); + avio_flush(client_ctx); + return size; +} + +int lavfhttpd_read(void *server, struct HTTPClient *client, unsigned char *buf, int size) +{ + AVIOContext *client_ctx = (AVIOContext*) client->httpd_data; + return avio_read(client_ctx, buf, size); +} + +void lavfhttpd_close(void *server, struct HTTPClient *client) +{ + AVIOContext *client_ctx = (AVIOContext*) client->httpd_data; + av_free(client->method); + av_free(client->resource); + avio_close(client_ctx); +} + +void lavfhttpd_shutdown(void *server) +{ + AVIOContext *server_ctx = (AVIOContext*) server; + avio_close(server_ctx); + avformat_network_deinit(); +} + +struct HTTPDInterface lavfhttpd = { + .init = lavfhttpd_init, + .accept = lavfhttpd_accept, + .write = lavfhttpd_write, + .close = lavfhttpd_close, + .shutdown = lavfhttpd_shutdown, +}; + +#endif -- 2.16.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel