FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ffserver_config.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <float.h>
22 #include "libavutil/opt.h"
23 #include "libavutil/parseutils.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/pixdesc.h"
26 #include "libavutil/avassert.h"
27 
28 // FIXME those are internal headers, ffserver _really_ shouldn't use them
29 #include "libavformat/ffm.h"
30 
31 #include "cmdutils.h"
32 #include "ffserver_config.h"
33 
34 #define MAX_CHILD_ARGS 64
35 
36 static int ffserver_save_avoption(const char *opt, const char *arg, int type,
38 static void vreport_config_error(const char *filename, int line_num,
39  int log_level, int *errors, const char *fmt,
40  va_list vl);
41 static void report_config_error(const char *filename, int line_num,
42  int log_level, int *errors, const char *fmt,
43  ...);
44 
45 #define ERROR(...) report_config_error(config->filename, config->line_num,\
46  AV_LOG_ERROR, &config->errors, __VA_ARGS__)
47 #define WARNING(...) report_config_error(config->filename, config->line_num,\
48  AV_LOG_WARNING, &config->warnings, __VA_ARGS__)
49 
50 /* FIXME: make ffserver work with IPv6 */
51 /* resolve host with also IP address parsing */
52 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
53 {
54 
55  if (!ff_inet_aton(hostname, sin_addr)) {
56 #if HAVE_GETADDRINFO
57  struct addrinfo *ai, *cur;
58  struct addrinfo hints = { 0 };
59  hints.ai_family = AF_INET;
60  if (getaddrinfo(hostname, NULL, &hints, &ai))
61  return -1;
62  /* getaddrinfo returns a linked list of addrinfo structs.
63  * Even if we set ai_family = AF_INET above, make sure
64  * that the returned one actually is of the correct type. */
65  for (cur = ai; cur; cur = cur->ai_next) {
66  if (cur->ai_family == AF_INET) {
67  *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
68  freeaddrinfo(ai);
69  return 0;
70  }
71  }
72  freeaddrinfo(ai);
73  return -1;
74 #else
75  struct hostent *hp;
76  hp = gethostbyname(hostname);
77  if (!hp)
78  return -1;
79  memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
80 #endif
81  }
82  return 0;
83 }
84 
85 void ffserver_get_arg(char *buf, int buf_size, const char **pp)
86 {
87  const char *p;
88  char *q;
89  int quote = 0;
90 
91  p = *pp;
92  q = buf;
93 
94  while (av_isspace(*p)) p++;
95 
96  if (*p == '\"' || *p == '\'')
97  quote = *p++;
98 
99  while (*p != '\0') {
100  if (quote && *p == quote || !quote && av_isspace(*p))
101  break;
102  if ((q - buf) < buf_size - 1)
103  *q++ = *p;
104  p++;
105  }
106 
107  *q = '\0';
108  if (quote && *p == quote)
109  p++;
110  *pp = p;
111 }
112 
114  FFServerIPAddressACL *ext_acl,
115  const char *p, const char *filename, int line_num)
116 {
117  char arg[1024];
119  FFServerIPAddressACL *nacl;
120  FFServerIPAddressACL **naclp;
121 
122  ffserver_get_arg(arg, sizeof(arg), &p);
123  if (av_strcasecmp(arg, "allow") == 0)
124  acl.action = IP_ALLOW;
125  else if (av_strcasecmp(arg, "deny") == 0)
126  acl.action = IP_DENY;
127  else {
128  fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n",
129  filename, line_num, arg);
130  goto bail;
131  }
132 
133  ffserver_get_arg(arg, sizeof(arg), &p);
134 
135  if (resolve_host(&acl.first, arg)) {
136  fprintf(stderr,
137  "%s:%d: ACL refers to invalid host or IP address '%s'\n",
138  filename, line_num, arg);
139  goto bail;
140  }
141 
142  acl.last = acl.first;
143 
144  ffserver_get_arg(arg, sizeof(arg), &p);
145 
146  if (arg[0]) {
147  if (resolve_host(&acl.last, arg)) {
148  fprintf(stderr,
149  "%s:%d: ACL refers to invalid host or IP address '%s'\n",
150  filename, line_num, arg);
151  goto bail;
152  }
153  }
154 
155  nacl = av_mallocz(sizeof(*nacl));
156  naclp = 0;
157 
158  acl.next = 0;
159  *nacl = acl;
160 
161  if (stream)
162  naclp = &stream->acl;
163  else if (feed)
164  naclp = &feed->acl;
165  else if (ext_acl)
166  naclp = &ext_acl;
167  else
168  fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n",
169  filename, line_num);
170 
171  if (naclp) {
172  while (*naclp)
173  naclp = &(*naclp)->next;
174 
175  *naclp = nacl;
176  } else
177  av_free(nacl);
178 
179 bail:
180  return;
181 
182 }
183 
184 /* add a codec and set the default parameters */
185 static void add_codec(FFServerStream *stream, AVCodecContext *av,
187 {
188  AVStream *st;
189  AVDictionary **opts, *recommended = NULL;
190  char *enc_config;
191 
192  if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
193  return;
194 
195  opts = av->codec_type == AVMEDIA_TYPE_AUDIO ?
196  &config->audio_opts : &config->video_opts;
197  av_dict_copy(&recommended, *opts, 0);
200 
201  if (av_dict_count(*opts))
203  "Something is wrong, %d options are not set!\n",
204  av_dict_count(*opts));
205 
206  if (!config->stream_use_defaults) {
207  switch(av->codec_type) {
208  case AVMEDIA_TYPE_AUDIO:
209  if (av->bit_rate == 0)
210  report_config_error(config->filename, config->line_num,
211  AV_LOG_ERROR, &config->errors,
212  "audio bit rate is not set\n");
213  if (av->sample_rate == 0)
214  report_config_error(config->filename, config->line_num,
215  AV_LOG_ERROR, &config->errors,
216  "audio sample rate is not set\n");
217  break;
218  case AVMEDIA_TYPE_VIDEO:
219  if (av->width == 0 || av->height == 0)
220  report_config_error(config->filename, config->line_num,
221  AV_LOG_ERROR, &config->errors,
222  "video size is not set\n");
223  break;
224  default:
225  av_assert0(0);
226  }
227  goto done;
228  }
229 
230  /* stream_use_defaults = true */
231 
232  /* compute default parameters */
233  switch(av->codec_type) {
234  case AVMEDIA_TYPE_AUDIO:
235  if (!av_dict_get(recommended, "b", NULL, 0)) {
236  av->bit_rate = 64000;
237  av_dict_set_int(&recommended, "b", av->bit_rate, 0);
238  WARNING("Setting default value for audio bit rate = %d. "
239  "Use NoDefaults to disable it.\n",
240  av->bit_rate);
241  }
242  if (!av_dict_get(recommended, "ar", NULL, 0)) {
243  av->sample_rate = 22050;
244  av_dict_set_int(&recommended, "ar", av->sample_rate, 0);
245  WARNING("Setting default value for audio sample rate = %d. "
246  "Use NoDefaults to disable it.\n",
247  av->sample_rate);
248  }
249  if (!av_dict_get(recommended, "ac", NULL, 0)) {
250  av->channels = 1;
251  av_dict_set_int(&recommended, "ac", av->channels, 0);
252  WARNING("Setting default value for audio channel count = %d. "
253  "Use NoDefaults to disable it.\n",
254  av->channels);
255  }
256  break;
257  case AVMEDIA_TYPE_VIDEO:
258  if (!av_dict_get(recommended, "b", NULL, 0)) {
259  av->bit_rate = 64000;
260  av_dict_set_int(&recommended, "b", av->bit_rate, 0);
261  WARNING("Setting default value for video bit rate = %d. "
262  "Use NoDefaults to disable it.\n",
263  av->bit_rate);
264  }
265  if (!av_dict_get(recommended, "time_base", NULL, 0)){
266  av->time_base.den = 5;
267  av->time_base.num = 1;
268  av_dict_set(&recommended, "time_base", "1/5", 0);
269  WARNING("Setting default value for video frame rate = %d. "
270  "Use NoDefaults to disable it.\n",
271  av->time_base.den);
272  }
273  if (!av_dict_get(recommended, "video_size", NULL, 0)) {
274  av->width = 160;
275  av->height = 128;
276  av_dict_set(&recommended, "video_size", "160x128", 0);
277  WARNING("Setting default value for video size = %dx%d. "
278  "Use NoDefaults to disable it.\n",
279  av->width, av->height);
280  }
281  /* Bitrate tolerance is less for streaming */
282  if (!av_dict_get(recommended, "bt", NULL, 0)) {
283  av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
284  (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
285  av_dict_set_int(&recommended, "bt", av->bit_rate_tolerance, 0);
286  WARNING("Setting default value for video bit rate tolerance = %d. "
287  "Use NoDefaults to disable it.\n",
288  av->bit_rate_tolerance);
289  }
290 
291  if (!av_dict_get(recommended, "rc_eq", NULL, 0)) {
292  av->rc_eq = av_strdup("tex^qComp");
293  av_dict_set(&recommended, "rc_eq", "tex^qComp", 0);
294  WARNING("Setting default value for video rate control equation = "
295  "%s. Use NoDefaults to disable it.\n",
296  av->rc_eq);
297  }
298  if (!av_dict_get(recommended, "maxrate", NULL, 0)) {
299  av->rc_max_rate = av->bit_rate * 2;
300  av_dict_set_int(&recommended, "maxrate", av->rc_max_rate, 0);
301  WARNING("Setting default value for video max rate = %d. "
302  "Use NoDefaults to disable it.\n",
303  av->rc_max_rate);
304  }
305 
306  if (av->rc_max_rate && !av_dict_get(recommended, "bufsize", NULL, 0)) {
307  av->rc_buffer_size = av->rc_max_rate;
308  av_dict_set_int(&recommended, "bufsize", av->rc_buffer_size, 0);
309  WARNING("Setting default value for video buffer size = %d. "
310  "Use NoDefaults to disable it.\n",
311  av->rc_buffer_size);
312  }
313  break;
314  default:
315  abort();
316  }
317 
318 done:
319  st = av_mallocz(sizeof(AVStream));
320  if (!st)
321  return;
322  av_dict_get_string(recommended, &enc_config, '=', ',');
323  av_dict_free(&recommended);
325  st->codec = av;
326  stream->streams[stream->nb_streams++] = st;
327 }
328 
329 static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name,
331 {
332  int ret;
333  AVCodec *codec = avcodec_find_encoder_by_name(codec_name);
334  if (!codec || codec->type != ctx->codec_type) {
336  &config->errors,
337  "Invalid codec name: '%s'\n", codec_name);
338  return 0;
339  }
340  if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) {
341  if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0)
342  return ret;
343  ctx->codec = codec;
344  }
345  if (ctx->codec_id != codec->id)
347  &config->errors,
348  "Inconsistent configuration: trying to set '%s' "
349  "codec option, but '%s' codec is used previously\n",
350  codec_name, avcodec_get_name(ctx->codec_id));
351  return 0;
352 }
353 
354 static int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config)
355 {
356  FILE *f=NULL;
357  char filename[1000], tmp[1000], tmp2[1000], line[1000];
358  int ret = 0;
359  AVCodecContext *avctx;
360  const AVCodec *codec;
361 
362  switch(type) {
364  avctx = config->dummy_actx;
365  break;
367  avctx = config->dummy_vctx;
368  break;
369  default:
370  av_assert0(0);
371  }
372  codec = avcodec_find_encoder(avctx->codec_id);
373 
374  if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
375  codec ? codec->name : NULL))) {
376  av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg);
377  return AVERROR(EINVAL);
378  }
379 
380  while(!feof(f)){
381  int e= fscanf(f, "%999[^\n]\n", line) - 1;
382  if(line[0] == '#' && !e)
383  continue;
384  e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
385  if(e){
386  av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename,
387  line);
388  ret = AVERROR(EINVAL);
389  break;
390  }
391  if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO ||
392  !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO)
393  {
394  if (ffserver_set_codec(avctx, tmp2, config) < 0)
395  break;
396  } else if (!strcmp(tmp, "scodec")) {
397  av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n");
398  ret = AVERROR(EINVAL);
399  break;
400  } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0)
401  break;
402  }
403 
404  fclose(f);
405 
406  return ret;
407 }
408 
409 static AVOutputFormat *ffserver_guess_format(const char *short_name,
410  const char *filename,
411  const char *mime_type)
412 {
413  AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
414 
415  if (fmt) {
416  AVOutputFormat *stream_fmt;
417  char stream_format_name[64];
418 
419  snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream",
420  fmt->name);
421  stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
422 
423  if (stream_fmt)
424  fmt = stream_fmt;
425  }
426 
427  return fmt;
428 }
429 
430 static void vreport_config_error(const char *filename, int line_num,
431  int log_level, int *errors, const char *fmt,
432  va_list vl)
433 {
434  av_log(NULL, log_level, "%s:%d: ", filename, line_num);
435  av_vlog(NULL, log_level, fmt, vl);
436  if (errors)
437  (*errors)++;
438 }
439 
440 static void report_config_error(const char *filename, int line_num,
441  int log_level, int *errors,
442  const char *fmt, ...)
443 {
444  va_list vl;
445  va_start(vl, fmt);
446  vreport_config_error(filename, line_num, log_level, errors, fmt, vl);
447  va_end(vl);
448 }
449 
450 static int ffserver_set_int_param(int *dest, const char *value, int factor,
451  int min, int max, FFServerConfig *config,
452  const char *error_msg, ...)
453 {
454  int tmp;
455  char *tailp;
456  if (!value || !value[0])
457  goto error;
458  errno = 0;
459  tmp = strtol(value, &tailp, 0);
460  if (tmp < min || tmp > max)
461  goto error;
462  if (factor) {
463  if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor))
464  goto error;
465  tmp *= factor;
466  }
467  if (tailp[0] || errno)
468  goto error;
469  if (dest)
470  *dest = tmp;
471  return 0;
472  error:
473  if (config) {
474  va_list vl;
475  va_start(vl, error_msg);
477  &config->errors, error_msg, vl);
478  va_end(vl);
479  }
480  return AVERROR(EINVAL);
481 }
482 
483 static int ffserver_set_float_param(float *dest, const char *value,
484  float factor, float min, float max,
486  const char *error_msg, ...)
487 {
488  double tmp;
489  char *tailp;
490  if (!value || !value[0])
491  goto error;
492  errno = 0;
493  tmp = strtod(value, &tailp);
494  if (tmp < min || tmp > max)
495  goto error;
496  if (factor)
497  tmp *= factor;
498  if (tailp[0] || errno)
499  goto error;
500  if (dest)
501  *dest = tmp;
502  return 0;
503  error:
504  if (config) {
505  va_list vl;
506  va_start(vl, error_msg);
508  &config->errors, error_msg, vl);
509  va_end(vl);
510  }
511  return AVERROR(EINVAL);
512 }
513 
514 static int ffserver_save_avoption(const char *opt, const char *arg, int type,
516 {
517  static int hinted = 0;
518  int ret = 0;
520  const AVOption *o = NULL;
521  const char *option = NULL;
522  const char *codec_name = NULL;
523  char buff[1024];
525  AVDictionary **dict;
526  enum AVCodecID guessed_codec_id;
527 
528  switch (type) {
530  ctx = config->dummy_vctx;
531  dict = &config->video_opts;
532  guessed_codec_id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ?
534  break;
536  ctx = config->dummy_actx;
537  dict = &config->audio_opts;
538  guessed_codec_id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ?
540  break;
541  default:
542  av_assert0(0);
543  }
544 
545  if (strchr(opt, ':')) {
546  //explicit private option
547  snprintf(buff, sizeof(buff), "%s", opt);
548  codec_name = buff;
549  if(!(option = strchr(buff, ':'))){
550  report_config_error(config->filename, config->line_num,
551  AV_LOG_ERROR, &config->errors,
552  "Syntax error. Unmatched ':'\n");
553  return -1;
554 
555  }
556  buff[option - buff] = '\0';
557  option++;
558  if ((ret = ffserver_set_codec(ctx, codec_name, config)) < 0)
559  return ret;
560  if (!ctx->codec || !ctx->priv_data)
561  return -1;
562  } else {
563  option = opt;
564  }
565 
566  o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM,
568  if (!o &&
569  (!strcmp(option, "time_base") || !strcmp(option, "pixel_format") ||
570  !strcmp(option, "video_size") || !strcmp(option, "codec_tag")))
571  o = av_opt_find(ctx, option, NULL, 0, 0);
572  if (!o) {
574  &config->errors, "Option not found: '%s'\n", opt);
575  if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) {
576  hinted = 1;
577  report_config_error(config->filename, config->line_num,
578  AV_LOG_ERROR, NULL, "If '%s' is a codec private"
579  "option, then prefix it with codec name, for "
580  "example '%s:%s %s' or define codec earlier.\n",
581  opt, avcodec_get_name(guessed_codec_id) ,opt,
582  arg);
583  }
584  } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) {
586  &config->errors, "Invalid value for option %s (%s): %s\n", opt,
587  arg, av_err2str(ret));
588  } else if ((e = av_dict_get(*dict, option, NULL, 0))) {
589  if ((o->type == AV_OPT_TYPE_FLAGS) && arg &&
590  (arg[0] == '+' || arg[0] == '-'))
591  return av_dict_set(dict, option, arg, AV_DICT_APPEND);
593  &config->errors, "Redeclaring value of option '%s'."
594  "Previous value was: '%s'.\n", opt, e->value);
595  } else if (av_dict_set(dict, option, arg, 0) < 0) {
596  return AVERROR(ENOMEM);
597  }
598  return 0;
599 }
600 
601 static int ffserver_save_avoption_int(const char *opt, int64_t arg,
602  int type, FFServerConfig *config)
603 {
604  char buf[22];
605  snprintf(buf, sizeof(buf), "%"PRId64, arg);
606  return ffserver_save_avoption(opt, buf, type, config);
607 }
608 
610  const char **p)
611 {
612  int val;
613  char arg[1024];
614  if (!av_strcasecmp(cmd, "Port") || !av_strcasecmp(cmd, "HTTPPort")) {
615  if (!av_strcasecmp(cmd, "Port"))
616  WARNING("Port option is deprecated. Use HTTPPort instead.\n");
617  ffserver_get_arg(arg, sizeof(arg), p);
618  ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
619  "Invalid port: %s\n", arg);
620  if (val < 1024)
621  WARNING("Trying to use IETF assigned system port: '%d'\n", val);
622  config->http_addr.sin_port = htons(val);
623  } else if (!av_strcasecmp(cmd, "HTTPBindAddress") ||
624  !av_strcasecmp(cmd, "BindAddress")) {
625  if (!av_strcasecmp(cmd, "BindAddress"))
626  WARNING("BindAddress option is deprecated. Use HTTPBindAddress "
627  "instead.\n");
628  ffserver_get_arg(arg, sizeof(arg), p);
629  if (resolve_host(&config->http_addr.sin_addr, arg))
630  ERROR("Invalid host/IP address: '%s'\n", arg);
631  } else if (!av_strcasecmp(cmd, "NoDaemon")) {
632  WARNING("NoDaemon option has no effect. You should remove it.\n");
633  } else if (!av_strcasecmp(cmd, "RTSPPort")) {
634  ffserver_get_arg(arg, sizeof(arg), p);
635  ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
636  "Invalid port: %s\n", arg);
637  config->rtsp_addr.sin_port = htons(val);
638  } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
639  ffserver_get_arg(arg, sizeof(arg), p);
640  if (resolve_host(&config->rtsp_addr.sin_addr, arg))
641  ERROR("Invalid host/IP address: %s\n", arg);
642  } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
643  ffserver_get_arg(arg, sizeof(arg), p);
644  ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
645  "Invalid MaxHTTPConnections: %s\n", arg);
646  config->nb_max_http_connections = val;
647  if (config->nb_max_connections > config->nb_max_http_connections) {
648  ERROR("Inconsistent configuration: MaxClients(%d) > "
649  "MaxHTTPConnections(%d)\n", config->nb_max_connections,
650  config->nb_max_http_connections);
651  }
652  } else if (!av_strcasecmp(cmd, "MaxClients")) {
653  ffserver_get_arg(arg, sizeof(arg), p);
654  ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
655  "Invalid MaxClients: '%s'\n", arg);
656  config->nb_max_connections = val;
657  if (config->nb_max_connections > config->nb_max_http_connections) {
658  ERROR("Inconsistent configuration: MaxClients(%d) > "
659  "MaxHTTPConnections(%d)\n", config->nb_max_connections,
660  config->nb_max_http_connections);
661  }
662  } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
663  int64_t llval;
664  char *tailp;
665  ffserver_get_arg(arg, sizeof(arg), p);
666  errno = 0;
667  llval = strtoll(arg, &tailp, 10);
668  if (llval < 10 || llval > 10000000 || tailp[0] || errno)
669  ERROR("Invalid MaxBandwidth: '%s'\n", arg);
670  else
671  config->max_bandwidth = llval;
672  } else if (!av_strcasecmp(cmd, "CustomLog")) {
673  if (!config->debug) {
674  ffserver_get_arg(config->logfilename, sizeof(config->logfilename),
675  p);
676  }
677  } else if (!av_strcasecmp(cmd, "LoadModule")) {
678  ERROR("Loadable modules are no longer supported\n");
679  } else if (!av_strcasecmp(cmd, "NoDefaults")) {
680  config->use_defaults = 0;
681  } else if (!av_strcasecmp(cmd, "UseDefaults")) {
682  config->use_defaults = 1;
683  } else
684  ERROR("Incorrect keyword: '%s'\n", cmd);
685  return 0;
686 }
687 
688 static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd,
689  const char **p, FFServerStream **pfeed)
690 {
691  FFServerStream *feed;
692  char arg[1024];
693  av_assert0(pfeed);
694  feed = *pfeed;
695  if (!av_strcasecmp(cmd, "<Feed")) {
696  char *q;
697  FFServerStream *s;
698  feed = av_mallocz(sizeof(FFServerStream));
699  if (!feed)
700  return AVERROR(ENOMEM);
701  ffserver_get_arg(feed->filename, sizeof(feed->filename), p);
702  q = strrchr(feed->filename, '>');
703  if (*q)
704  *q = '\0';
705 
706  for (s = config->first_feed; s; s = s->next) {
707  if (!strcmp(feed->filename, s->filename))
708  ERROR("Feed '%s' already registered\n", s->filename);
709  }
710 
711  feed->fmt = av_guess_format("ffm", NULL, NULL);
712  /* default feed file */
713  snprintf(feed->feed_filename, sizeof(feed->feed_filename),
714  "/tmp/%s.ffm", feed->filename);
715  feed->feed_max_size = 5 * 1024 * 1024;
716  feed->is_feed = 1;
717  feed->feed = feed; /* self feeding :-) */
718  *pfeed = feed;
719  return 0;
720  }
721  av_assert0(feed);
722  if (!av_strcasecmp(cmd, "Launch")) {
723  int i;
724 
725  feed->child_argv = av_mallocz_array(MAX_CHILD_ARGS, sizeof(char *));
726  if (!feed->child_argv)
727  return AVERROR(ENOMEM);
728  for (i = 0; i < MAX_CHILD_ARGS - 2; i++) {
729  ffserver_get_arg(arg, sizeof(arg), p);
730  if (!arg[0])
731  break;
732 
733  feed->child_argv[i] = av_strdup(arg);
734  if (!feed->child_argv[i])
735  return AVERROR(ENOMEM);
736  }
737 
738  feed->child_argv[i] =
739  av_asprintf("http://%s:%d/%s",
740  (config->http_addr.sin_addr.s_addr == INADDR_ANY) ?
741  "127.0.0.1" : inet_ntoa(config->http_addr.sin_addr),
742  ntohs(config->http_addr.sin_port), feed->filename);
743  if (!feed->child_argv[i])
744  return AVERROR(ENOMEM);
745  } else if (!av_strcasecmp(cmd, "ACL")) {
746  ffserver_parse_acl_row(NULL, feed, NULL, *p, config->filename,
747  config->line_num);
748  } else if (!av_strcasecmp(cmd, "File") ||
749  !av_strcasecmp(cmd, "ReadOnlyFile")) {
750  ffserver_get_arg(feed->feed_filename, sizeof(feed->feed_filename), p);
751  feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
752  } else if (!av_strcasecmp(cmd, "Truncate")) {
753  ffserver_get_arg(arg, sizeof(arg), p);
754  /* assume Truncate is true in case no argument is specified */
755  if (!arg[0]) {
756  feed->truncate = 1;
757  } else {
758  WARNING("Truncate N syntax in configuration file is deprecated. "
759  "Use Truncate alone with no arguments.\n");
760  feed->truncate = strtod(arg, NULL);
761  }
762  } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
763  char *p1;
764  double fsize;
765 
766  ffserver_get_arg(arg, sizeof(arg), p);
767  p1 = arg;
768  fsize = strtod(p1, &p1);
769  switch(av_toupper(*p1)) {
770  case 'K':
771  fsize *= 1024;
772  break;
773  case 'M':
774  fsize *= 1024 * 1024;
775  break;
776  case 'G':
777  fsize *= 1024 * 1024 * 1024;
778  break;
779  default:
780  ERROR("Invalid file size: '%s'\n", arg);
781  break;
782  }
783  feed->feed_max_size = (int64_t)fsize;
784  if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
785  ERROR("Feed max file size is too small. Must be at least %d.\n",
786  FFM_PACKET_SIZE*4);
787  }
788  } else if (!av_strcasecmp(cmd, "</Feed>")) {
789  *pfeed = NULL;
790  } else {
791  ERROR("Invalid entry '%s' inside <Feed></Feed>\n", cmd);
792  }
793  return 0;
794 }
795 
797  const char **p,
798  FFServerStream **pstream)
799 {
800  char arg[1024], arg2[1024];
801  FFServerStream *stream;
802  int val;
803 
804  av_assert0(pstream);
805  stream = *pstream;
806 
807  if (!av_strcasecmp(cmd, "<Stream")) {
808  char *q;
809  FFServerStream *s;
810  stream = av_mallocz(sizeof(FFServerStream));
811  if (!stream)
812  return AVERROR(ENOMEM);
815  if (!config->dummy_vctx || !config->dummy_actx) {
816  av_free(stream);
819  return AVERROR(ENOMEM);
820  }
823  ffserver_get_arg(stream->filename, sizeof(stream->filename), p);
824  q = strrchr(stream->filename, '>');
825  if (q)
826  *q = '\0';
827 
828  for (s = config->first_stream; s; s = s->next) {
829  if (!strcmp(stream->filename, s->filename))
830  ERROR("Stream '%s' already registered\n", s->filename);
831  }
832 
833  stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
834  if (stream->fmt) {
835  config->guessed_audio_codec_id = stream->fmt->audio_codec;
836  config->guessed_video_codec_id = stream->fmt->video_codec;
837  } else {
840  }
841  config->stream_use_defaults = config->use_defaults;
842  *pstream = stream;
843  return 0;
844  }
845  av_assert0(stream);
846  if (!av_strcasecmp(cmd, "Feed")) {
847  FFServerStream *sfeed;
848  ffserver_get_arg(arg, sizeof(arg), p);
849  sfeed = config->first_feed;
850  while (sfeed) {
851  if (!strcmp(sfeed->filename, arg))
852  break;
853  sfeed = sfeed->next_feed;
854  }
855  if (!sfeed)
856  ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg,
857  stream->filename);
858  else
859  stream->feed = sfeed;
860  } else if (!av_strcasecmp(cmd, "Format")) {
861  ffserver_get_arg(arg, sizeof(arg), p);
862  if (!strcmp(arg, "status")) {
864  stream->fmt = NULL;
865  } else {
866  stream->stream_type = STREAM_TYPE_LIVE;
867  /* JPEG cannot be used here, so use single frame MJPEG */
868  if (!strcmp(arg, "jpeg")) {
869  strcpy(arg, "singlejpeg");
870  stream->single_frame=1;
871  }
872  stream->fmt = ffserver_guess_format(arg, NULL, NULL);
873  if (!stream->fmt)
874  ERROR("Unknown Format: '%s'\n", arg);
875  }
876  if (stream->fmt) {
877  config->guessed_audio_codec_id = stream->fmt->audio_codec;
878  config->guessed_video_codec_id = stream->fmt->video_codec;
879  }
880  } else if (!av_strcasecmp(cmd, "InputFormat")) {
881  ffserver_get_arg(arg, sizeof(arg), p);
882  stream->ifmt = av_find_input_format(arg);
883  if (!stream->ifmt)
884  ERROR("Unknown input format: '%s'\n", arg);
885  } else if (!av_strcasecmp(cmd, "FaviconURL")) {
886  if (stream->stream_type == STREAM_TYPE_STATUS)
888  sizeof(stream->feed_filename), p);
889  else
890  ERROR("FaviconURL only permitted for status streams\n");
891  } else if (!av_strcasecmp(cmd, "Author") ||
892  !av_strcasecmp(cmd, "Comment") ||
893  !av_strcasecmp(cmd, "Copyright") ||
894  !av_strcasecmp(cmd, "Title")) {
895  char key[32];
896  int i;
897  ffserver_get_arg(arg, sizeof(arg), p);
898  for (i = 0; i < strlen(cmd); i++)
899  key[i] = av_tolower(cmd[i]);
900  key[i] = 0;
901  WARNING("Deprecated '%s' option in configuration file. Use "
902  "'Metadata %s VALUE' instead.\n", cmd, key);
903  if (av_dict_set(&stream->metadata, key, arg, 0) < 0)
904  goto nomem;
905  } else if (!av_strcasecmp(cmd, "Metadata")) {
906  ffserver_get_arg(arg, sizeof(arg), p);
907  ffserver_get_arg(arg2, sizeof(arg2), p);
908  if (av_dict_set(&stream->metadata, arg, arg2, 0) < 0)
909  goto nomem;
910  } else if (!av_strcasecmp(cmd, "Preroll")) {
911  ffserver_get_arg(arg, sizeof(arg), p);
912  stream->prebuffer = atof(arg) * 1000;
913  } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
914  stream->send_on_key = 1;
915  } else if (!av_strcasecmp(cmd, "AudioCodec")) {
916  ffserver_get_arg(arg, sizeof(arg), p);
917  ffserver_set_codec(config->dummy_actx, arg, config);
918  } else if (!av_strcasecmp(cmd, "VideoCodec")) {
919  ffserver_get_arg(arg, sizeof(arg), p);
920  ffserver_set_codec(config->dummy_vctx, arg, config);
921  } else if (!av_strcasecmp(cmd, "MaxTime")) {
922  ffserver_get_arg(arg, sizeof(arg), p);
923  stream->max_time = atof(arg) * 1000;
924  } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
925  float f;
926  ffserver_get_arg(arg, sizeof(arg), p);
927  ffserver_set_float_param(&f, arg, 1000, -FLT_MAX, FLT_MAX, config,
928  "Invalid %s: '%s'\n", cmd, arg);
929  if (ffserver_save_avoption_int("b", (int64_t)lrintf(f),
930  AV_OPT_FLAG_AUDIO_PARAM, config) < 0)
931  goto nomem;
932  } else if (!av_strcasecmp(cmd, "AudioChannels")) {
933  ffserver_get_arg(arg, sizeof(arg), p);
934  if (ffserver_save_avoption("ac", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0)
935  goto nomem;
936  } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
937  ffserver_get_arg(arg, sizeof(arg), p);
938  if (ffserver_save_avoption("ar", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0)
939  goto nomem;
940  } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
941  int minrate, maxrate;
942  char *dash;
943  ffserver_get_arg(arg, sizeof(arg), p);
944  dash = strchr(arg, '-');
945  if (dash) {
946  *dash = '\0';
947  dash++;
948  if (ffserver_set_int_param(&minrate, arg, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0 &&
949  ffserver_set_int_param(&maxrate, dash, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0) {
950  if (ffserver_save_avoption_int("minrate", minrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0 ||
951  ffserver_save_avoption_int("maxrate", maxrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
952  goto nomem;
953  }
954  } else
955  ERROR("Incorrect format for VideoBitRateRange. It should be "
956  "<min>-<max>: '%s'.\n", arg);
957  } else if (!av_strcasecmp(cmd, "Debug")) {
958  ffserver_get_arg(arg, sizeof(arg), p);
959  if (ffserver_save_avoption("debug", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 ||
960  ffserver_save_avoption("debug", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
961  goto nomem;
962  } else if (!av_strcasecmp(cmd, "Strict")) {
963  ffserver_get_arg(arg, sizeof(arg), p);
964  if (ffserver_save_avoption("strict", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 ||
965  ffserver_save_avoption("strict", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
966  goto nomem;
967  } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
968  ffserver_get_arg(arg, sizeof(arg), p);
969  ffserver_set_int_param(&val, arg, 8*1024, 0, INT_MAX, config,
970  "Invalid %s: '%s'", cmd, arg);
971  if (ffserver_save_avoption_int("bufsize", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
972  goto nomem;
973  } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
974  ffserver_get_arg(arg, sizeof(arg), p);
975  ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config,
976  "Invalid %s: '%s'", cmd, arg);
977  if (ffserver_save_avoption_int("bt", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
978  goto nomem;
979  } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
980  ffserver_get_arg(arg, sizeof(arg), p);
981  ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config,
982  "Invalid %s: '%s'", cmd, arg);
983  if (ffserver_save_avoption_int("b", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
984  goto nomem;
985  } else if (!av_strcasecmp(cmd, "VideoSize")) {
986  int ret, w, h;
987  ffserver_get_arg(arg, sizeof(arg), p);
988  ret = av_parse_video_size(&w, &h, arg);
989  if (ret < 0)
990  ERROR("Invalid video size '%s'\n", arg);
991  else {
992  if (w % 2 || h % 2)
993  WARNING("Image size is not a multiple of 2\n");
994  if (ffserver_save_avoption("video_size", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
995  goto nomem;
996  }
997  } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
998  ffserver_get_arg(&arg[2], sizeof(arg) - 2, p);
999  arg[0] = '1'; arg[1] = '/';
1000  if (ffserver_save_avoption("time_base", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1001  goto nomem;
1002  } else if (!av_strcasecmp(cmd, "PixelFormat")) {
1003  enum AVPixelFormat pix_fmt;
1004  ffserver_get_arg(arg, sizeof(arg), p);
1005  pix_fmt = av_get_pix_fmt(arg);
1006  if (pix_fmt == AV_PIX_FMT_NONE)
1007  ERROR("Unknown pixel format: '%s'\n", arg);
1008  else if (ffserver_save_avoption("pixel_format", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1009  goto nomem;
1010  } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
1011  ffserver_get_arg(arg, sizeof(arg), p);
1012  if (ffserver_save_avoption("g", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1013  goto nomem;
1014  } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
1015  if (ffserver_save_avoption("g", "1", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1016  goto nomem;
1017  } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
1018  if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1019  goto nomem;
1020  } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
1021  if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || //FIXME remove
1022  ffserver_save_avoption("flags", "+mv4", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1023  goto nomem;
1024  } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
1025  !av_strcasecmp(cmd, "AVOptionAudio")) {
1026  int ret;
1027  ffserver_get_arg(arg, sizeof(arg), p);
1028  ffserver_get_arg(arg2, sizeof(arg2), p);
1029  if (!av_strcasecmp(cmd, "AVOptionVideo"))
1031  config);
1032  else
1034  config);
1035  if (ret < 0)
1036  goto nomem;
1037  } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
1038  !av_strcasecmp(cmd, "AVPresetAudio")) {
1039  ffserver_get_arg(arg, sizeof(arg), p);
1040  if (!av_strcasecmp(cmd, "AVPresetVideo"))
1042  else
1044  } else if (!av_strcasecmp(cmd, "VideoTag")) {
1045  ffserver_get_arg(arg, sizeof(arg), p);
1046  if (strlen(arg) == 4 &&
1047  ffserver_save_avoption_int("codec_tag",
1048  MKTAG(arg[0], arg[1], arg[2], arg[3]),
1049  AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1050  goto nomem;
1051  } else if (!av_strcasecmp(cmd, "BitExact")) {
1052  if (ffserver_save_avoption("flags", "+bitexact", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1053  goto nomem;
1054  } else if (!av_strcasecmp(cmd, "DctFastint")) {
1055  if (ffserver_save_avoption("dct", "fastint", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1056  goto nomem;
1057  } else if (!av_strcasecmp(cmd, "IdctSimple")) {
1058  if (ffserver_save_avoption("idct", "simple", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1059  goto nomem;
1060  } else if (!av_strcasecmp(cmd, "Qscale")) {
1061  ffserver_get_arg(arg, sizeof(arg), p);
1062  ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config,
1063  "Invalid Qscale: '%s'\n", arg);
1064  if (ffserver_save_avoption("flags", "+qscale", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 ||
1065  ffserver_save_avoption_int("global_quality", FF_QP2LAMBDA * val,
1066  AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1067  goto nomem;
1068  } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
1069  ffserver_get_arg(arg, sizeof(arg), p);
1070  if (ffserver_save_avoption("qdiff", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1071  goto nomem;
1072  } else if (!av_strcasecmp(cmd, "VideoQMax")) {
1073  ffserver_get_arg(arg, sizeof(arg), p);
1074  if (ffserver_save_avoption("qmax", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1075  goto nomem;
1076  } else if (!av_strcasecmp(cmd, "VideoQMin")) {
1077  ffserver_get_arg(arg, sizeof(arg), p);
1078  if (ffserver_save_avoption("qmin", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1079  goto nomem;
1080  } else if (!av_strcasecmp(cmd, "LumiMask")) {
1081  ffserver_get_arg(arg, sizeof(arg), p);
1082  if (ffserver_save_avoption("lumi_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1083  goto nomem;
1084  } else if (!av_strcasecmp(cmd, "DarkMask")) {
1085  ffserver_get_arg(arg, sizeof(arg), p);
1086  if (ffserver_save_avoption("dark_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
1087  goto nomem;
1088  } else if (!av_strcasecmp(cmd, "NoVideo")) {
1089  config->no_video = 1;
1090  } else if (!av_strcasecmp(cmd, "NoAudio")) {
1091  config->no_audio = 1;
1092  } else if (!av_strcasecmp(cmd, "ACL")) {
1093  ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
1094  config->line_num);
1095  } else if (!av_strcasecmp(cmd, "DynamicACL")) {
1096  ffserver_get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), p);
1097  } else if (!av_strcasecmp(cmd, "RTSPOption")) {
1098  ffserver_get_arg(arg, sizeof(arg), p);
1099  av_freep(&stream->rtsp_option);
1100  stream->rtsp_option = av_strdup(arg);
1101  } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
1102  ffserver_get_arg(arg, sizeof(arg), p);
1103  if (resolve_host(&stream->multicast_ip, arg))
1104  ERROR("Invalid host/IP address: '%s'\n", arg);
1105  stream->is_multicast = 1;
1106  stream->loop = 1; /* default is looping */
1107  } else if (!av_strcasecmp(cmd, "MulticastPort")) {
1108  ffserver_get_arg(arg, sizeof(arg), p);
1109  ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
1110  "Invalid MulticastPort: '%s'\n", arg);
1111  stream->multicast_port = val;
1112  } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
1113  ffserver_get_arg(arg, sizeof(arg), p);
1114  ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config,
1115  "Invalid MulticastTTL: '%s'\n", arg);
1116  stream->multicast_ttl = val;
1117  } else if (!av_strcasecmp(cmd, "NoLoop")) {
1118  stream->loop = 0;
1119  } else if (!av_strcasecmp(cmd, "</Stream>")) {
1120  config->stream_use_defaults &= 1;
1121  if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) {
1122  if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE)
1123  config->dummy_actx->codec_id = config->guessed_audio_codec_id;
1124  if (!config->no_audio &&
1125  config->dummy_actx->codec_id != AV_CODEC_ID_NONE) {
1127  add_codec(stream, audio_enc, config);
1128  }
1129  if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE)
1130  config->dummy_vctx->codec_id = config->guessed_video_codec_id;
1131  if (!config->no_video &&
1132  config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) {
1134  add_codec(stream, video_enc, config);
1135  }
1136  }
1137  av_dict_free(&config->video_opts);
1138  av_dict_free(&config->audio_opts);
1139  avcodec_free_context(&config->dummy_vctx);
1140  avcodec_free_context(&config->dummy_actx);
1141  *pstream = NULL;
1142  } else if (!av_strcasecmp(cmd, "File") ||
1143  !av_strcasecmp(cmd, "ReadOnlyFile")) {
1144  ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename),
1145  p);
1146  } else if (!av_strcasecmp(cmd, "UseDefaults")) {
1147  if (config->stream_use_defaults > 1)
1148  WARNING("Multiple UseDefaults/NoDefaults entries.\n");
1149  config->stream_use_defaults = 3;
1150  } else if (!av_strcasecmp(cmd, "NoDefaults")) {
1151  if (config->stream_use_defaults > 1)
1152  WARNING("Multiple UseDefaults/NoDefaults entries.\n");
1153  config->stream_use_defaults = 2;
1154  } else {
1155  ERROR("Invalid entry '%s' inside <Stream></Stream>\n", cmd);
1156  }
1157  return 0;
1158  nomem:
1159  av_log(NULL, AV_LOG_ERROR, "Out of memory. Aborting.\n");
1160  av_dict_free(&config->video_opts);
1161  av_dict_free(&config->audio_opts);
1162  avcodec_free_context(&config->dummy_vctx);
1163  avcodec_free_context(&config->dummy_actx);
1164  return AVERROR(ENOMEM);
1165 }
1166 
1168  const char *cmd, const char **p,
1169  FFServerStream **predirect)
1170 {
1171  FFServerStream *redirect;
1172  av_assert0(predirect);
1173  redirect = *predirect;
1174 
1175  if (!av_strcasecmp(cmd, "<Redirect")) {
1176  char *q;
1177  redirect = av_mallocz(sizeof(FFServerStream));
1178  if (!redirect)
1179  return AVERROR(ENOMEM);
1180 
1181  ffserver_get_arg(redirect->filename, sizeof(redirect->filename), p);
1182  q = strrchr(redirect->filename, '>');
1183  if (*q)
1184  *q = '\0';
1185  redirect->stream_type = STREAM_TYPE_REDIRECT;
1186  *predirect = redirect;
1187  return 0;
1188  }
1189  av_assert0(redirect);
1190  if (!av_strcasecmp(cmd, "URL")) {
1191  ffserver_get_arg(redirect->feed_filename,
1192  sizeof(redirect->feed_filename), p);
1193  } else if (!av_strcasecmp(cmd, "</Redirect>")) {
1194  if (!redirect->feed_filename[0])
1195  ERROR("No URL found for <Redirect>\n");
1196  *predirect = NULL;
1197  } else {
1198  ERROR("Invalid entry '%s' inside <Redirect></Redirect>\n", cmd);
1199  }
1200  return 0;
1201 }
1202 
1203 int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config)
1204 {
1205  FILE *f;
1206  char line[1024];
1207  char cmd[64];
1208  const char *p;
1209  FFServerStream **last_stream, *stream = NULL, *redirect = NULL;
1210  FFServerStream **last_feed, *feed = NULL;
1211  int ret = 0;
1212 
1213  av_assert0(config);
1214 
1215  f = fopen(filename, "r");
1216  if (!f) {
1217  ret = AVERROR(errno);
1219  "Could not open the configuration file '%s'\n", filename);
1220  return ret;
1221  }
1222 
1223  config->first_stream = NULL;
1224  config->first_feed = NULL;
1225  config->errors = config->warnings = 0;
1226 
1227  last_stream = &config->first_stream;
1228  last_feed = &config->first_feed;
1229 
1230  config->line_num = 0;
1231  while (fgets(line, sizeof(line), f) != NULL) {
1232  config->line_num++;
1233  p = line;
1234  while (av_isspace(*p))
1235  p++;
1236  if (*p == '\0' || *p == '#')
1237  continue;
1238 
1239  ffserver_get_arg(cmd, sizeof(cmd), &p);
1240 
1241  if (feed || !av_strcasecmp(cmd, "<Feed")) {
1242  int opening = !av_strcasecmp(cmd, "<Feed");
1243  if (opening && (stream || feed || redirect)) {
1244  ERROR("Already in a tag\n");
1245  } else {
1246  ret = ffserver_parse_config_feed(config, cmd, &p, &feed);
1247  if (ret < 0)
1248  break;
1249  if (opening) {
1250  /* add in stream & feed list */
1251  *last_stream = feed;
1252  *last_feed = feed;
1253  last_stream = &feed->next;
1254  last_feed = &feed->next_feed;
1255  }
1256  }
1257  } else if (stream || !av_strcasecmp(cmd, "<Stream")) {
1258  int opening = !av_strcasecmp(cmd, "<Stream");
1259  if (opening && (stream || feed || redirect)) {
1260  ERROR("Already in a tag\n");
1261  } else {
1262  ret = ffserver_parse_config_stream(config, cmd, &p, &stream);
1263  if (ret < 0)
1264  break;
1265  if (opening) {
1266  /* add in stream list */
1267  *last_stream = stream;
1268  last_stream = &stream->next;
1269  }
1270  }
1271  } else if (redirect || !av_strcasecmp(cmd, "<Redirect")) {
1272  int opening = !av_strcasecmp(cmd, "<Redirect");
1273  if (opening && (stream || feed || redirect))
1274  ERROR("Already in a tag\n");
1275  else {
1276  ret = ffserver_parse_config_redirect(config, cmd, &p,
1277  &redirect);
1278  if (ret < 0)
1279  break;
1280  if (opening) {
1281  /* add in stream list */
1282  *last_stream = redirect;
1283  last_stream = &redirect->next;
1284  }
1285  }
1286  } else {
1287  ffserver_parse_config_global(config, cmd, &p);
1288  }
1289  }
1290  if (stream || feed || redirect)
1291  ERROR("Missing closing </%s> tag\n",
1292  stream ? "Stream" : (feed ? "Feed" : "Redirect"));
1293 
1294  fclose(f);
1295  if (ret < 0)
1296  return ret;
1297  if (config->errors)
1298  return AVERROR(EINVAL);
1299  else
1300  return 0;
1301 }
1302 
1303 #undef ERROR
1304 #undef WARNING
1305 
1306 void ffserver_free_child_args(void *argsp)
1307 {
1308  int i;
1309  char **args;
1310  if (!argsp)
1311  return;
1312  args = *(char ***)argsp;
1313  if (!args)
1314  return;
1315  for (i = 0; i < MAX_CHILD_ARGS; i++)
1316  av_free(args[i]);
1317  av_freep(argsp);
1318 }
struct in_addr last
#define NULL
Definition: coverity.c:32
const struct AVCodec * codec
Definition: avcodec.h:1541
int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config)
const char const char void * val
Definition: avisynth_c.h:634
const char * s
Definition: avisynth_c.h:631
static enum AVPixelFormat pix_fmt
struct sockaddr_in http_addr
static void add_codec(FFServerStream *stream, AVCodecContext *av, FFServerConfig *config)
static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt,...)
AVCodec * avcodec_find_encoder(enum AVCodecID id)
Find a registered encoder with a matching codec ID.
Definition: utils.c:2610
AVOption.
Definition: opt.h:245
FFServerIPAddressACL * acl
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
Parse str and put in width_ptr and height_ptr the detected values.
Definition: parseutils.c:143
static int ffserver_set_float_param(float *dest, const char *value, float factor, float min, float max, FFServerConfig *config, const char *error_msg,...)
AVFormatContext * ctx
Definition: movenc-test.c:48
const char * fmt
Definition: avisynth_c.h:632
unsigned int nb_max_connections
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
int64_t bit_rate
the average bitrate
Definition: avcodec.h:1597
static FFServerConfig config
Definition: ffserver.c:202
enum AVCodecID video_codec
default video codec
Definition: avformat.h:534
int num
numerator
Definition: rational.h:44
#define AV_OPT_FLAG_AUDIO_PARAM
Definition: opt.h:280
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition: dict.c:34
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:222
int av_dict_get_string(const AVDictionary *m, char **buffer, const char key_val_sep, const char pairs_sep)
Get dictionary entries as a string.
Definition: dict.c:226
AVInputFormat * ifmt
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:213
enum AVMediaType type
Definition: avcodec.h:3405
#define freeaddrinfo
Definition: network.h:208
AVCodec.
Definition: avcodec.h:3392
AVCodecContext * dummy_vctx
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avcodec.h:1661
AVCodecContext * dummy_actx
struct FFServerStream * next
void ffserver_free_child_args(void *argsp)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int bit_rate_tolerance
number of bits the bitstream is allowed to diverge from the reference.
Definition: avcodec.h:1605
AVOutputFormat * fmt
enum AVCodecID guessed_video_codec_id
attribute_deprecated const char * rc_eq
Definition: avcodec.h:2515
uint64_t max_bandwidth
enum AVCodecID guessed_audio_codec_id
AVOptions.
char logfilename[1024]
#define ERROR(...)
double strtod(const char *, char **)
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:39
AVDictionary * metadata
#define lrintf(x)
Definition: libm_mips.h:70
#define av_log(a,...)
AVStream * streams[FFSERVER_MAX_STREAMS]
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:275
AVCodec * avcodec_find_encoder_by_name(const char *name)
Find a registered encoder with the specified name.
Definition: utils.c:2615
int64_t feed_max_size
static av_const int av_tolower(int c)
Locale-independent conversion of ASCII characters to lowercase.
Definition: avstring.h:241
enum AVCodecID id
Definition: avcodec.h:3406
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:101
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
#define MAX_CHILD_ARGS
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:199
const char * arg
Definition: jacosubdec.c:66
enum FFServerStreamType stream_type
Definition: graph2dot.c:48
char dynamic_acl[1024]
static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, FFServerConfig *config)
simple assert() macros that are a bit more flexible than ISO C assert().
static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, const char **p, FFServerStream **pfeed)
const char * name
Name of the codec implementation.
Definition: avcodec.h:3399
#define FFMAX(a, b)
Definition: common.h:94
#define WARNING(...)
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:896
int rc_buffer_size
decoder bitstream buffer size
Definition: avcodec.h:2500
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
const AVOption * av_opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags)
Look for an option in an object.
Definition: opt.c:1497
void av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration)
AVInputFormat * av_find_input_format(const char *short_name)
Find AVInputFormat based on the short name of the input format.
Definition: format.c:160
static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd, const char **p)
char feed_filename[1024]
struct FFServerStream * next_feed
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:213
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition: options.c:149
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:556
int ff_inet_aton(const char *str, struct in_addr *add)
int width
picture width / height.
Definition: avcodec.h:1711
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:109
AVS_Value args
Definition: avisynth_c.h:562
const char * name
Definition: avformat.h:523
void ffserver_get_arg(char *buf, int buf_size, const char **pp)
struct FFServerIPAddressACL * next
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
AVDictionary * video_opts
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
#define AV_DICT_APPEND
If the entry already exists, append to it.
Definition: dict.h:82
static int ffserver_save_avoption_int(const char *opt, int64_t arg, int type, FFServerConfig *config)
AVOutputFormat * av_guess_format(const char *short_name, const char *filename, const char *mime_type)
Return the output format in the list of registered output formats which best matches the provided par...
Definition: format.c:94
int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags)
Set all the options from a given dictionary on an object.
Definition: opt.c:1467
#define FF_ARRAY_ELEMS(a)
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Definition: utils.c:2648
Stream structure.
Definition: avformat.h:877
enum AVMediaType codec_type
Definition: avcodec.h:1540
static void vreport_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, va_list vl)
void avcodec_free_context(AVCodecContext **avctx)
Free the codec context and everything associated with it and write NULL to the provided pointer...
Definition: options.c:164
enum AVCodecID codec_id
Definition: avcodec.h:1549
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:267
int sample_rate
samples per second
Definition: avcodec.h:2287
char filename[1024]
#define AV_OPT_FLAG_VIDEO_PARAM
Definition: opt.h:281
main external API structure.
Definition: avcodec.h:1532
AVDictionary * audio_opts
struct sockaddr_in rtsp_addr
void * buf
Definition: avisynth_c.h:553
GLint GLenum type
Definition: opengl_enc.c:105
static int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config)
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:69
FILE * get_preset_file(char *filename, size_t filename_size, const char *preset_name, int is_path, const char *codec_name)
Get a file corresponding to a preset file.
Definition: cmdutils.c:1912
static av_const int av_toupper(int c)
Locale-independent conversion of ASCII characters to uppercase.
Definition: avstring.h:231
option
Definition: libkvazaar.c:278
void av_vlog(void *avcl, int level, const char *fmt, va_list vl)
Send the specified message to the log if the level is less than or equal to the current av_log_level...
Definition: log.c:370
static const int factor[16]
Definition: vf_pp7.c:75
#define snprintf
Definition: snprintf.h:34
misc parsing utilities
FFServerStream * first_feed
static int ffserver_parse_config_redirect(FFServerConfig *config, const char *cmd, const char **p, FFServerStream **predirect)
static int ffserver_set_int_param(int *dest, const char *value, int factor, int min, int max, FFServerConfig *config, const char *error_msg,...)
struct FFServerStream * feed
#define getaddrinfo
Definition: network.h:207
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set that converts the value to a string and stores it...
Definition: dict.c:143
struct addrinfo * ai_next
Definition: network.h:135
void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream *feed, FFServerIPAddressACL *ext_acl, const char *p, const char *filename, int line_num)
static AVOutputFormat * ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
int den
denominator
Definition: rational.h:45
int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec)
Set the fields of the given AVCodecContext to default values corresponding to the given codec (defaul...
Definition: options.c:92
void * priv_data
Definition: avcodec.h:1574
#define av_free(p)
char * value
Definition: dict.h:88
enum AVOptionType type
Definition: opt.h:259
int channels
number of audio channels
Definition: avcodec.h:2288
enum AVCodecID audio_codec
default audio codec
Definition: avformat.h:533
AVDictionary * opts
Definition: movenc-test.c:50
#define FF_QP2LAMBDA
factor to convert from H.263 QP to lambda
Definition: avutil.h:219
static int ffserver_save_avoption(const char *opt, const char *arg, int type, FFServerConfig *config)
static void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.h:229
#define av_freep(p)
struct in_addr multicast_ip
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition: pixdesc.c:2090
FFServerStream * first_stream
#define MKTAG(a, b, c, d)
Definition: common.h:342
struct sockaddr * ai_addr
Definition: network.h:133
float min
AVPixelFormat
Pixel format.
Definition: pixfmt.h:61
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:393
unsigned int nb_max_http_connections
struct in_addr first
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:252
enum FFServerIPAddressAction action
#define FFM_PACKET_SIZE
Definition: ffm.h:31
int64_t rc_max_rate
maximum bitrate
Definition: avcodec.h:2523
static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p, FFServerStream **pstream)
int ai_family
Definition: network.h:129