[FFmpeg-devel] [PATCH 6/8] ffserver.c: Add config file reading

Michael Niedermayer michael at niedermayer.cc
Sun May 20 23:13:35 EEST 2018


On Sun, May 20, 2018 at 08:54:02PM +0200, Stephan Holljes wrote:
> Signed-off-by: Stephan Holljes <klaxa1337 at googlemail.com>
> ---
>  ffserver.c | 248 ++++++++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 172 insertions(+), 76 deletions(-)
> 
> diff --git a/ffserver.c b/ffserver.c
> index 44fc263..3d842d8 100644
> --- a/ffserver.c
> +++ b/ffserver.c
> @@ -38,6 +38,7 @@
>  #include "segment.h"
>  #include "publisher.h"
>  #include "httpd.h"
> +#include "configreader.h"
>  
>  #define BUFFER_SECS 30
>  #define LISTEN_TIMEOUT_MSEC 1000
> @@ -54,9 +55,11 @@ struct WriteInfo {
>  };
>  
>  struct AcceptInfo {
> -    struct PublisherContext *pub;
> +    struct PublisherContext **pubs;
>      struct HTTPDInterface *httpd;
> -    AVFormatContext *ifmt_ctx;
> +    AVFormatContext **ifmt_ctxs;
> +    struct HTTPDConfig *config;
> +    int nb_pub; /* number of publishers (streams) equal to number of ifmt_ctx */
>  };
>  
>  
> @@ -287,52 +290,77 @@ void *accept_thread(void *arg)
>  {
>      struct AcceptInfo *info = (struct AcceptInfo*) arg;
>      struct FFServerInfo *ffinfo = NULL;
> +    struct PublisherContext *pub;
>      char status[4096];
> +    char *stream_name;
>      struct HTTPClient *client = NULL;
>      void *server = NULL;
>      AVIOContext *client_ctx = NULL;
>      AVFormatContext *ofmt_ctx = NULL;
> +    AVFormatContext *ifmt_ctx;
>      unsigned char *avio_buffer;
>      AVOutputFormat *ofmt;
>      AVDictionary *mkvopts = NULL;
>      AVStream *in_stream, *out_stream;
>      int ret, i, reply_code;
> -    struct HTTPDConfig config = {
> -        .bind_address = "0",
> -        .port = 8080,
> -        .accept_timeout = LISTEN_TIMEOUT_MSEC,
> -    };
> -    
> -    info->httpd->init(&server, config);
> -    
> -    
> +    int shutdown;
> +    struct HTTPDConfig *config = info->config;
> +
> +    info->httpd->init(&server, *config);
> +
>      for (;;) {
> -        if (info->pub->shutdown)
> +        shutdown = 1;
> +        for (i = 0; i < config->nb_streams; i++) {
> +            if (info->pubs[i] && !info->pubs[i]->shutdown)
> +                shutdown = 0;
> +        }
> +        if (shutdown)
>              break;
> -        publisher_gen_status_json(info->pub, status);
> -        av_log(server, AV_LOG_INFO, status);
> +        for (i = 0; i < config->nb_streams; i++) {
> +            publisher_gen_status_json(info->pubs[i], status);
> +            av_log(server, AV_LOG_INFO, status);
> +        }
>          client = NULL;
>          av_log(server, AV_LOG_DEBUG, "Accepting new clients.\n");
>          reply_code = 200;
> -        if (publisher_reserve_client(info->pub)) {
> -            av_log(client, AV_LOG_WARNING, "No more client slots free, Returning 503.\n");
> -            reply_code = 503;
> -        }
> -        
> +
>          if ((ret = info->httpd->accept(server, &client, reply_code)) < 0) {
>              if (ret == HTTPD_LISTEN_TIMEOUT) {
> -                publisher_cancel_reserve(info->pub);
>                  continue;
>              } else if (ret == HTTPD_CLIENT_ERROR) {
>                  info->httpd->close(server, client);
>              }
>              av_log(server, AV_LOG_WARNING, "Error during accept, retrying.\n");
> -            publisher_cancel_reserve(info->pub);
>              continue;
>          }
> -        
> +
> +        pub = NULL;
> +        ifmt_ctx = NULL;
> +        for (i = 0; i < config->nb_streams; i++) {
> +            stream_name = info->pubs[i]->stream_name;
> +            //       skip leading '/'  ---v
> +            if(!strncmp(client->resource + 1, stream_name, strlen(stream_name))) {
> +                pub = info->pubs[i];
> +                ifmt_ctx = info->ifmt_ctxs[i];
> +                break;
> +            }
> +        }
> +
> +        if (!pub || !ifmt_ctx) {
> +            av_log(client_ctx, AV_LOG_WARNING, "No suitable publisher found for resource: %s.\n",
> +                                                        client->resource ? client->resource : "(null)");
> +            reply_code = 404;
> +        }
> +
> +
> +        if (pub && ifmt_ctx && publisher_reserve_client(pub)) {
> +            av_log(client_ctx, AV_LOG_WARNING, "No more client slots free, Returning 503.\n");
> +            reply_code = 503;
> +        }
> +
>          if (reply_code != 200) {
> -            publisher_cancel_reserve(info->pub);
> +            if (pub && ifmt_ctx)
> +                publisher_cancel_reserve(pub);
>              info->httpd->close(server, client);
>              continue;
>          }
> @@ -345,7 +373,7 @@ void *accept_thread(void *arg)
>          client_ctx = avio_alloc_context(avio_buffer, AV_BUFSIZE, 1, ffinfo, NULL, &ffserver_write, NULL);
>          if (!client_ctx) {
>              av_log(client, AV_LOG_ERROR, "Could not allocate output format context.\n");
> -            publisher_cancel_reserve(info->pub);
> +            publisher_cancel_reserve(pub);
>              info->httpd->close(server, client);
>              av_free(client_ctx->buffer);
>              avio_context_free(&client_ctx);
> @@ -355,7 +383,7 @@ void *accept_thread(void *arg)
>          avformat_alloc_output_context2(&ofmt_ctx, NULL, "matroska", NULL);
>          if (!ofmt_ctx) {
>              av_log(client, AV_LOG_ERROR, "Could not allocate output format context.\n");
> -            publisher_cancel_reserve(info->pub);
> +            publisher_cancel_reserve(pub);
>              info->httpd->close(server, client);
>              avformat_free_context(ofmt_ctx);
>              av_free(client_ctx->buffer);
> @@ -365,7 +393,7 @@ void *accept_thread(void *arg)
>          }
>          if ((ret = av_dict_set(&mkvopts, "live", "1", 0)) < 0) {
>              av_log(client, AV_LOG_ERROR, "Failed to set live mode for matroska: %s\n", av_err2str(ret));
> -            publisher_cancel_reserve(info->pub);
> +            publisher_cancel_reserve(pub);
>              info->httpd->close(server, client);
>              avformat_free_context(ofmt_ctx);
>              av_free(client_ctx->buffer);
> @@ -377,13 +405,13 @@ void *accept_thread(void *arg)
>          ofmt = ofmt_ctx->oformat;
>          ofmt->flags |= AVFMT_NOFILE | AVFMT_FLAG_AUTO_BSF;
>          
> -        for (i = 0; i < info->ifmt_ctx->nb_streams; i++) {
> -            in_stream = info->ifmt_ctx->streams[i];
> +        for (i = 0; i < ifmt_ctx->nb_streams; i++) {
> +            in_stream = ifmt_ctx->streams[i];
>              out_stream = avformat_new_stream(ofmt_ctx, NULL);
>              
>              if (!out_stream) {
>                  av_log(client, AV_LOG_ERROR, "Could not allocate output stream.\n");
> -                publisher_cancel_reserve(info->pub);
> +                publisher_cancel_reserve(pub);
>                  info->httpd->close(server, client);
>                  avformat_free_context(ofmt_ctx);
>                  av_free(client_ctx->buffer);
> @@ -395,7 +423,7 @@ void *accept_thread(void *arg)
>              ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
>              if (ret < 0) {
>                  av_log(client, AV_LOG_ERROR, "Failed to copy context from input to output stream codec context: %s.\n", av_err2str(ret));
> -                publisher_cancel_reserve(info->pub);
> +                publisher_cancel_reserve(pub);
>                  info->httpd->close(server, client);
>                  avformat_free_context(ofmt_ctx);
>                  av_free(client_ctx->buffer);
> @@ -412,12 +440,12 @@ void *accept_thread(void *arg)
>              }
>              av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
>          }
> -        av_dict_copy(&info->ifmt_ctx->metadata, ofmt_ctx->metadata, 0);
> +        av_dict_copy(&ifmt_ctx->metadata, ofmt_ctx->metadata, 0);
>          ofmt_ctx->pb = client_ctx;
>          ret = avformat_write_header(ofmt_ctx, &mkvopts);
>          if (ret < 0) {
>              av_log(client, AV_LOG_ERROR, "Could not write header to client: %s.\n", av_err2str(ret));
> -            publisher_cancel_reserve(info->pub);
> +            publisher_cancel_reserve(pub);
>              info->httpd->close(server, client);
>              avformat_free_context(ofmt_ctx);
>              av_free(client_ctx->buffer);
> @@ -425,7 +453,7 @@ void *accept_thread(void *arg)
>              av_free(ffinfo);
>              continue;
>          }
> -        publisher_add_client(info->pub, ofmt_ctx, ffinfo);
> +        publisher_add_client(pub, ofmt_ctx, ffinfo);
>          ofmt_ctx = NULL;
>          
>      }
> @@ -467,59 +495,127 @@ void *write_thread(void *arg)
>      return NULL;
>  }
>  
> -
> -int main(int argc, char *argv[])
> -{
> -    struct ReadInfo rinfo;
> +void *run_server(void *arg) {
>      struct AcceptInfo ainfo;
> -    struct WriteInfo *winfos;
> -    struct PublisherContext *pub;
> -    int ret, i;
> -    pthread_t r_thread, a_thread;
> -    pthread_t *w_threads;
> +    struct ReadInfo *rinfos;
> +    struct WriteInfo **winfos_p;
> +    struct HTTPDConfig *config = (struct HTTPDConfig*) arg;
> +    struct PublisherContext **pubs;
> +    AVFormatContext **ifmt_ctxs;
> +    int ret, i, stream_index;
> +    pthread_t *r_threads;
> +    pthread_t **w_threads_p;
>      
> -    AVFormatContext *ifmt_ctx = NULL;
> -    
> -    rinfo.in_filename = "pipe:0";
> -    if (argc > 1)
> -        rinfo.in_filename = argv[1];
> +    pubs = av_mallocz(config->nb_streams * sizeof(struct PublisherContext*));
> +    ifmt_ctxs = av_mallocz(config->nb_streams * sizeof(AVFormatContext*));

av_mallocz_array

also missing alloc failure checks

[...]
> +        w_threads_p[stream_index] = w_threads;
> +        pthread_create(&r_thread, NULL, read_thread, &rinfos[stream_index]);
> +        r_threads[stream_index] = r_thread;

missing failure check


[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Into a blind darkness they enter who follow after the Ignorance,
they as if into a greater darkness enter who devote themselves
to the Knowledge alone. -- Isha Upanishad
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20180520/84c983e4/attachment.sig>


More information about the ffmpeg-devel mailing list