From patchwork Thu Jun 28 00:51:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Holljes X-Patchwork-Id: 9547 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:104:0:0:0:0:0 with SMTP id c4-v6csp1484001jad; Wed, 27 Jun 2018 17:59:59 -0700 (PDT) X-Google-Smtp-Source: AAOMgpd5SALExfiWpxl+TT06sbm9xQdyYcyvsT+N5QSXCgldXN4jK1xKrWxF54jEo5ppRdyxNvj6 X-Received: by 2002:a1c:4596:: with SMTP id l22-v6mr6682914wmi.33.1530147599724; Wed, 27 Jun 2018 17:59:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530147599; cv=none; d=google.com; s=arc-20160816; b=w0wNfh0mBbWaVlF3F7w6DNDQ/hJGUwO6zvGeuLPkRwSfw8QQ0hG2dzr6qZsQeLrTJl Ccb6w8m1osrqTFET2Lf4L5KJGc6bizTysgiRFLgpV1/BoR5Uzj0Pu6QMQUqc/Yt53+xW b+S2dayxAWJ+6jFu6JgbJPPOSAL2zas4GQLrP28Up2kCIepaKjbEezbEF8Av8fnfMTtL aK8Wlk9RxuIzdoeyHGtWyecqhqTRoIH7odJbQIwdkZNo+Fr8V8kDzyzYdJEuq6H0ZRP+ tfwtHFiegywx+NCuperPe61687fQh9yASh9kgAbhQFxe7q2CuDeTo6za9MbDXA1b2hSK DhCw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=TsWHazDs6iE0nm5gKySAEOSeeiotl6HDxi4DQU5lZSY=; b=U5+ZB6EjCjds7+TDRzGuRZSjGd20S/15PLzC6hHLjyNkIoC8UObS3zqEDXTgDFhVLP yJbz7H3eD7KyF1eBbng4nx9irn3ncCdKK+yBmaJxAgcIyxM1+PItbbwAs/3DFPtq2DcJ 4DoFftoe+PZS2E8uORlV5BUJmEGv07GsgzbwOAwUACbQjumoxMfW39b93aHHrBUIrtRP 3/xFoh6ekzmfCDukT3w9M6yy8e+oZwV2yScHMW+w0PjBLIrsgr3AzvxTkjIfFFoL+0Fh dyHaqy9nLhp4893qEmCn5qEMlckEIUdhpwh4sKqQFE1IKHAl2iOTOBft/O/e5A45zOzN lKgQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@googlemail.com header.s=20161025 header.b=r1aP7bBk; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id k9-v6si5917912wrg.272.2018.06.27.17.59.59; Wed, 27 Jun 2018 17:59:59 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@googlemail.com header.s=20161025 header.b=r1aP7bBk; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 17D6E68A579; Thu, 28 Jun 2018 03:59:51 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f68.google.com (mail-wm0-f68.google.com [74.125.82.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E95E068A10D for ; Thu, 28 Jun 2018 03:59:43 +0300 (EEST) Received: by mail-wm0-f68.google.com with SMTP id z13-v6so7224935wma.5 for ; Wed, 27 Jun 2018 17:59:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CRxCfHr8rewMq3XxCDri9VNnEi7Xp9cQfnJzIaN4GS8=; b=r1aP7bBk8Jc50I4KYz/m5GGyaTHMQxUYMKJieGVxOJ9VWu2juDb+ZC+5VFgpy7E4uk vyow/TXGavIJ1Jr1Bx+JPNZPj+xjswn9caGueb82mSysaPlofgt0xhqTIYMw7yVAelrb AKjaSm8n19M9gko1tw0ZWcv4bucY+cHE6M05o7su3H40OtbYLp7MCggmyr7XUleN9+VL A/e5f0s8YGk9D3R337ZJbR9MK8WWEE2cgnXKMA2OTWy5fLQs7KMZkqeS0E3qoYYJ1x4f 5EWb2vsjkC7wHnXtkPuGMK/PTQwbew+WdbuBWF99yAKSweyw5p5PKXEFhAFJbGBjNIME 0tdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CRxCfHr8rewMq3XxCDri9VNnEi7Xp9cQfnJzIaN4GS8=; b=kxS4cEQNlopibpnjHSUL0N75gvOY6cDbmn2jJBY/2546LLwcrGDXb5egxvLhJ2P0q+ m27rpD8dMtTjJFQqa6y1xveH/id6+jsiZmXFk1sSsFM2gMRryngC4DqxbjfGIqEqmshl yG3prEsG2mHYdAcbKwEKvDgdYmGGo8dh5VH+InMrlDHivr3+GUJmoS2ven+3L9w7Saw6 jrN3UFnN4JRPVHWVt/Usb3lwd/JDQTYOxlA6F8+JOvYNVhNZ7vBR4h37eeHdpTFZvaFi /Ho1W8dJHgWa76MWu2JkOHpSOyYqG6jN861u9naHFkunXCNP3yJHQqK0JS17/5W20IFb NTYw== X-Gm-Message-State: APt69E3umxaxu70wNP/jcdK8X/rjOfCyPkFM7fgg/YwBnJW/DoQ+zGUZ dTC/iwB8WxAhmmUSz1qGDbHdHw== X-Received: by 2002:a1c:34c9:: with SMTP id b192-v6mr6696432wma.21.1530147103289; Wed, 27 Jun 2018 17:51:43 -0700 (PDT) Received: from localhost.localdomain ([46.5.2.0]) by smtp.gmail.com with ESMTPSA id a9-v6sm1363017wrq.1.2018.06.27.17.51.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Jun 2018 17:51:42 -0700 (PDT) From: Stephan Holljes To: ffmpeg-devel@ffmpeg.org Date: Thu, 28 Jun 2018 02:51:14 +0200 Message-Id: <20180628005117.18902-15-klaxa1337@googlemail.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180628005117.18902-1-klaxa1337@googlemail.com> References: <20180628005117.18902-1-klaxa1337@googlemail.com> Subject: [FFmpeg-devel] [PATCH 14/17] Add fileserver and add it to Makefile X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Stephan Holljes MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Stephan Holljes --- Makefile | 7 ++- ffserver.c | 150 +++++++++++++++++++++++++++++++++++++++------------ fileserver.c | 97 +++++++++++++++++++++++++++++++++ fileserver.h | 63 ++++++++++++++++++++++ 4 files changed, 282 insertions(+), 35 deletions(-) create mode 100644 fileserver.c create mode 100644 fileserver.h diff --git a/Makefile b/Makefile index 83bc4e0..18f3ac3 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ LUA_FLAGS = $(shell pkg-config --libs --cflags lua5.3) CFLAGS=-fsanitize=address -fsanitize=undefined # LAV_FLAGS = -L/usr/local/lib -lavcodec -lavformat -lavutil -ffserver: segment.o publisher.o lavfhttpd.o configreader.o ffserver.c - cc -g -Wall $(CFLAGS) $(LAV_FLAGS) $(LUA_FLAGS) -lpthread -o ffserver segment.o publisher.o lavfhttpd.o configreader.o ffserver.c +ffserver: segment.o publisher.o fileserver.o lavfhttpd.o configreader.o ffserver.c + cc -g -Wall $(CFLAGS) $(LAV_FLAGS) $(LUA_FLAGS) -lpthread -o ffserver segment.o publisher.o fileserver.o lavfhttpd.o configreader.o ffserver.c segment.o: segment.c segment.h cc -g -Wall $(CFLAGS) $(LAV_FLAGS) -lpthread -c segment.c @@ -13,6 +13,9 @@ segment.o: segment.c segment.h publisher.o: publisher.c publisher.h cc -g -Wall $(CFLAGS) $(LAV_FLAGS) -lpthread -c publisher.c +fileserver.o: fileserver.c fileserver.h + cc -g -Wall $(CFLAGS) $(LAV_FLAGS) -lpthread -c fileserver.c + lavfhttpd.o: lavfhttpd.c httpd.h cc -g -Wall $(CFLAGS) $(LAV_FLAGS) -lpthread -c lavfhttpd.c diff --git a/ffserver.c b/ffserver.c index 4f42f74..91ad29a 100644 --- a/ffserver.c +++ b/ffserver.c @@ -37,9 +37,11 @@ #include #include #include +#include #include "segment.h" #include "publisher.h" +#include "fileserver.h" #include "httpd.h" #include "configreader.h" @@ -64,6 +66,7 @@ struct AcceptInfo { struct HTTPDInterface *httpd; AVFormatContext **ifmt_ctxs; struct HTTPDConfig *config; + struct FileserverContext *fs; int nb_pub; /** number of publishers (streams) equal to number of ifmt_ctx */ }; @@ -448,8 +451,8 @@ void *accept_thread(void *arg) struct AcceptInfo *info = (struct AcceptInfo*) arg; struct FFServerInfo *ffinfo = NULL; struct PublisherContext *pub; - char status[4096]; - char *stream_name; + char status[4096], requested_file[1024], sanitized_file[1024]; + char *stream_name, *resource; struct HTTPClient *client = NULL; void *server = NULL; AVIOContext *client_ctx = NULL; @@ -493,6 +496,8 @@ void *accept_thread(void *arg) pub = NULL; ifmt_ctx = NULL; + resource = client->resource; + snprintf(requested_file, 1024, "%s", resource); for (i = 0; i < config->nb_streams; i++) { stream_name = info->pubs[i]->stream_name; // skip leading '/' ---v @@ -515,7 +520,8 @@ void *accept_thread(void *arg) } } - if (!pub || !ifmt_ctx) { + + if ((!pub || !ifmt_ctx) && !requested_file[0]) { av_log(client_ctx, AV_LOG_WARNING, "No suitable publisher found for resource: %s.\n", client->resource ? client->resource : "(null)"); reply_code = 404; @@ -534,13 +540,6 @@ void *accept_thread(void *arg) continue; } - avio_buffer = av_malloc(AV_BUFSIZE); - if (!avio_buffer) { - av_log(client_ctx, AV_LOG_ERROR, "Could not allocate output format context.\n"); - publisher_cancel_reserve(pub); - info->httpd->close(server, client); - continue; - } ffinfo = av_malloc(sizeof(*ffinfo)); if (!ffinfo) { av_log(client_ctx, AV_LOG_ERROR, "Could not allocate FFServerInfo struct.\n"); @@ -551,6 +550,30 @@ void *accept_thread(void *arg) ffinfo->httpd = info->httpd; ffinfo->client = client; ffinfo->server = server; + + + // try to serve file + if (requested_file[0]) { + snprintf(sanitized_file, 1024, "%s", requested_file); + resource = requested_file; + while(resource && *resource == '/') { + resource++; + } + + snprintf(sanitized_file, 1024, "%s", resource); + fileserver_schedule(info->fs, ffinfo, sanitized_file); + continue; + } + + avio_buffer = av_malloc(AV_BUFSIZE); + if (!avio_buffer) { + av_log(client_ctx, AV_LOG_ERROR, "Could not allocate output format context.\n"); + publisher_cancel_reserve(pub); + info->httpd->close(server, client); + continue; + } + + client_ctx = avio_alloc_context(avio_buffer, AV_BUFSIZE, 1, ffinfo, NULL, &ffserver_write, NULL); if (!client_ctx) { av_log(NULL, AV_LOG_ERROR, "Could not allocate output format context.\n"); @@ -676,16 +699,52 @@ void *write_thread(void *arg) return NULL; } +void *fileserver_thread(void *arg) +{ + struct FileserverContext *fs = (struct FileserverContext*) arg; + int i, clients_served; + struct FileserverClient *c; + for (;;) { + usleep(500000); + av_log(NULL, AV_LOG_WARNING, "Checking clients, fileserver-thread %s: ", fs->server_name); + clients_served = 0; + for (i = 0; i < MAX_CLIENTS; i++) { + c = &fs->clients[i]; + pthread_mutex_lock(&c->client_lock); + if (c->buf) { + c->ffinfo->httpd->write(c->ffinfo->server, c->ffinfo->client, c->buf, c->size); + av_file_unmap(c->buf, c->size); + c->ffinfo->httpd->close(c->ffinfo->server, c->ffinfo->client); + c->buf = NULL; + c->size = 0; + av_freep(&c->ffinfo); + clients_served++; + } + pthread_mutex_unlock(&c->client_lock); + } + av_log(NULL, AV_LOG_WARNING, "%d/%d served\n", clients_served, MAX_CLIENTS); + if (fs->shutdown) { + printf("shutting down\n"); + break; + } + } + + return NULL; +} + void *run_server(void *arg) { struct AcceptInfo ainfo; struct ReadInfo *rinfos; struct WriteInfo **winfos_p; struct HTTPDConfig *config = (struct HTTPDConfig*) arg; struct PublisherContext **pubs; + struct FileserverContext *fs = NULL; AVFormatContext **ifmt_ctxs; int ret, i, stream_index; + int stream_formats[FMT_NB] = { 0 }; pthread_t *r_threads; pthread_t **w_threads_p; + pthread_t fs_thread = 0; pubs = av_mallocz_array(config->nb_streams, sizeof(struct PublisherContext*)); if (!pubs) { @@ -718,6 +777,7 @@ void *run_server(void *arg) { av_log_set_level(AV_LOG_INFO); ainfo.pubs = pubs; + ainfo.fs = fs; ainfo.ifmt_ctxs = ifmt_ctxs; ainfo.nb_pub = config->nb_streams; ainfo.httpd = &lavfhttpd; @@ -751,56 +811,75 @@ void *run_server(void *arg) { struct WriteInfo *winfos = NULL; pthread_t *w_threads = NULL; pthread_t r_thread; + int stream_formats[FMT_NB] = { 0 }; rinfo.input_uri = config->streams[stream_index].input_uri; rinfo.server_name = config->server_name; + for (i = 0; i < config->streams[stream_index].nb_formats; i++) + stream_formats[config->streams[stream_index].formats[i]] = 1; + if ((ret = avformat_open_input(&ifmt_ctx, rinfo.input_uri, NULL, NULL))) { av_log(NULL, AV_LOG_ERROR, "run_server: Could not open input\n"); continue; } + ifmt_ctxs[stream_index] = ifmt_ctx; + if (stream_formats[FMT_MATROSKA]) + publisher_init(&pub, config->streams[stream_index].stream_name); - publisher_init(&pub, config->streams[stream_index].stream_name); pubs[stream_index] = pub; rinfo.ifmt_ctx = ifmt_ctx; rinfo.pub = pub; rinfos[stream_index] = rinfo; - - w_threads = av_mallocz_array(pub->nb_threads, sizeof(pthread_t)); - if (!w_threads) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate write thread handles.\n"); - continue; - } - winfos = av_mallocz_array(pub->nb_threads, sizeof(struct WriteInfo)); - if (!winfos) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate write infos.\n"); - continue; - } - w_threads_p[stream_index] = w_threads; - winfos_p[stream_index] = winfos; - - for (i = 0; i < pub->nb_threads; i++) { - winfos[i].pub = pub; - winfos[i].thread_id = i; - ret = pthread_create(&w_threads[i], NULL, write_thread, &winfos_p[stream_index][i]); + if (stream_formats[FMT_MATROSKA]) { + w_threads = av_mallocz_array(pub->nb_threads, sizeof(pthread_t)); + if (!w_threads) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate write thread handles.\n"); + continue; + } + winfos = av_mallocz_array(pub->nb_threads, sizeof(struct WriteInfo)); + if (!winfos) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate write infos.\n"); + continue; + } + w_threads_p[stream_index] = w_threads; + winfos_p[stream_index] = winfos; + + for (i = 0; i < pub->nb_threads; i++) { + winfos[i].pub = pub; + winfos[i].thread_id = i; + ret = pthread_create(&w_threads[i], NULL, write_thread, &winfos_p[stream_index][i]); + if (ret != 0) { + pub->shutdown = 1; + w_threads[i] = 0; + goto end; + } + } + w_threads_p[stream_index] = w_threads; + ret = pthread_create(&r_thread, NULL, read_thread, &rinfos[stream_index]); if (ret != 0) { pub->shutdown = 1; + r_thread = 0; goto end; } + r_threads[stream_index] = r_thread; } - w_threads_p[stream_index] = w_threads; - ret = pthread_create(&r_thread, NULL, read_thread, &rinfos[stream_index]); + + } + if (stream_formats[FMT_HLS] || stream_formats[FMT_DASH]) { + ret = pthread_create(&fs_thread, NULL, fileserver_thread, fs); if (ret != 0) { - pub->shutdown = 1; + fs->shutdown = 1; + fs_thread = 0; goto end; } - r_threads[stream_index] = r_thread; } + //pthread_create(&a_thread, NULL, accept_thread, &ainfo); accept_thread(&ainfo); @@ -823,6 +902,11 @@ end: publisher_free(pubs[stream_index]); } + if (fs_thread) { + fs->shutdown = 1; + pthread_join(fs_thread, NULL); + fileserver_free(fs); + } error_cleanup: av_free(rinfos); av_free(winfos_p); diff --git a/fileserver.c b/fileserver.c new file mode 100644 index 0000000..a3460e3 --- /dev/null +++ b/fileserver.c @@ -0,0 +1,97 @@ +/* + * 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 + */ + +#include "fileserver.h" +#include "httpd.h" + +#include + +#include +#include + +void fileserver_schedule(struct FileserverContext *fs, struct FFServerInfo *ffinfo, const char *filename) +{ + int i, ret; + char final_filename[1024]; + struct FileserverClient *fsc = NULL; + for (i = 0; i < MAX_CLIENTS; i++) { + pthread_mutex_lock(&fs->clients[i].client_lock); + if (!fs->clients[i].ffinfo) { + fsc = &fs->clients[i]; + break; + } + pthread_mutex_unlock(&fs->clients[i].client_lock); + } + // fsc still locked + if (fsc) { + fsc->ffinfo = ffinfo; + snprintf(final_filename, 1024, "%s/%s", fs->server_name, filename); + ret = av_file_map(final_filename, &fsc->buf, &fsc->size, 0, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not read file: %s: %s.\n", final_filename, av_err2str(ret)); + fsc->ffinfo->httpd->close(fsc->ffinfo->server, fsc->ffinfo->client); + av_freep(&fsc->ffinfo); + fsc->buf = NULL; + fsc->size = 0; + } + fsc->ofmt_ctx = ofmt_ctx; + pthread_mutex_unlock(&fsc->client_lock); + } else { + av_log(NULL, AV_LOG_WARNING, "Could not find free client slot.\n"); + ffinfo->httpd->close(ffinfo->server, ffinfo->client); + av_free(ffinfo); + } + av_log(NULL, AV_LOG_INFO, "Scheduled serving file: %s\n", final_filename); + return; +} + +void fileserver_init(struct FileserverContext **fs_p, const char *server_name) +{ + struct FileserverContext *fs = av_mallocz(sizeof(struct FileserverContext)); + int i; + *fs_p = NULL; + + if (!fs) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate fileserver context.\n"); + return; + } + + for (i = 0; i < MAX_CLIENTS; i++) { + fs->clients[i].ffinfo = NULL; + fs->clients[i].buf = NULL; + fs->clients[i].size = 0; + pthread_mutex_init(&fs->clients[i].client_lock, NULL); + } + + fs->nb_threads = 1; + fs->server_name = server_name; + fs->shutdown = 0; + *fs_p = fs; + return; +} + +void fileserver_free(struct FileserverContext *fs) { + int i; + for (i = 0; i < MAX_CLIENTS; i++) { + pthread_mutex_lock(&fs->clients[i].client_lock); + av_free(fs->clients[i].ffinfo); + av_free(fs->clients[i].buf); + pthread_mutex_unlock(&fs->clients[i].client_lock); + } + av_free(fs); +} diff --git a/fileserver.h b/fileserver.h new file mode 100644 index 0000000..6e449c0 --- /dev/null +++ b/fileserver.h @@ -0,0 +1,63 @@ +/* + * 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 FILESERVER_H +#define FILESERVER_H + +#define MAX_CLIENTS 16 + +#include "httpd.h" +#include + +struct FileserverClient { + struct FFServerInfo *ffinfo; + pthread_mutex_t client_lock; + unsigned char *buf; + size_t size; +}; + + +struct FileserverContext { + struct FileserverClient clients[MAX_CLIENTS]; + int nb_threads; + int shutdown; + const char *server_name; +}; + +/** + * Schedule file for sending to a client. It is added to a list of clients. + * @param fs pointer to the FileserverContext to schedule to + * @param ffinfo pointer to an FFServerInfo struct containing information for serving the file + * @param filename filename of the file to serve + */ +void fileserver_schedule(struct FileserverContext *fs, struct FFServerInfo *ffinfo, AVIOContext *ofmt_ctx, const char *filename); + +/** + * Initialize a Fileservercontext + * @param fs_p pointer to a pointer where the FileserverContext will be allocated + * @param server_name the name of the server + */ +void fileserver_init(struct FileserverContext **fs_p, const char *server_name); + +/** + * Free a Fileservercontext + */ +void fileserver_free(struct FileserverContext *fs); + + +#endif