[FFmpeg-devel] [PATCH 3/5] ffserver: Implement http interface and implementation
Stephan Holljes
klaxa1337 at googlemail.com
Thu May 10 18:41:24 EEST 2018
Signed-off-by: Stephan Holljes <klaxa1337 at 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
More information about the ffmpeg-devel
mailing list