avserver.c
Go to the documentation of this file.
1 /*
2  * Multiple format streaming server
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "config.h"
23 #if !HAVE_CLOSESOCKET
24 #define closesocket close
25 #endif
26 #include <string.h>
27 #include <stdlib.h>
28 #include "libavformat/avformat.h"
29 #include "libavformat/ffm.h"
30 #include "libavformat/network.h"
31 #include "libavformat/os_support.h"
32 #include "libavformat/rtpdec.h"
33 #include "libavformat/rtsp.h"
34 // XXX for ffio_open_dyn_packet_buffer, to be removed
36 #include "libavutil/avstring.h"
37 #include "libavutil/lfg.h"
38 #include "libavutil/dict.h"
39 #include "libavutil/mathematics.h"
40 #include "libavutil/random_seed.h"
41 #include "libavutil/parseutils.h"
42 #include "libavutil/opt.h"
43 #include <stdarg.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <sys/ioctl.h>
47 #if HAVE_POLL_H
48 #include <poll.h>
49 #endif
50 #include <errno.h>
51 #include <sys/time.h>
52 #include <time.h>
53 #include <sys/wait.h>
54 #include <signal.h>
55 #if HAVE_DLFCN_H
56 #include <dlfcn.h>
57 #endif
58 
59 #include "cmdutils.h"
60 
61 const char program_name[] = "avserver";
62 const int program_birth_year = 2000;
63 
64 static const OptionDef options[];
65 
66 enum HTTPState {
70  HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
73  HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
75 
79 };
80 
81 static const char *http_state[] = {
82  "HTTP_WAIT_REQUEST",
83  "HTTP_SEND_HEADER",
84 
85  "SEND_DATA_HEADER",
86  "SEND_DATA",
87  "SEND_DATA_TRAILER",
88  "RECEIVE_DATA",
89  "WAIT_FEED",
90  "READY",
91 
92  "RTSP_WAIT_REQUEST",
93  "RTSP_SEND_REPLY",
94  "RTSP_SEND_PACKET",
95 };
96 
97 #define MAX_STREAMS 20
98 
99 #define IOBUFFER_INIT_SIZE 8192
100 
101 /* timeouts are in ms */
102 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
103 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
104 
105 #define SYNC_TIMEOUT (10 * 1000)
106 
107 typedef struct RTSPActionServerSetup {
108  uint32_t ipaddr;
109  char transport_option[512];
111 
112 typedef struct {
113  int64_t count1, count2;
114  int64_t time1, time2;
115 } DataRateData;
116 
117 /* context associated with one connection */
118 typedef struct HTTPContext {
120  int fd; /* socket file descriptor */
121  struct sockaddr_in from_addr; /* origin */
122  struct pollfd *poll_entry; /* used when polling */
123  int64_t timeout;
124  uint8_t *buffer_ptr, *buffer_end;
126  int post;
128  int chunk_size; /* 0 if it needs to be read */
129  struct HTTPContext *next;
130  int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
131  int64_t data_count;
132  /* feed input */
133  int feed_fd;
134  /* input format handling */
136  int64_t start_time; /* In milliseconds - this wraps fairly often */
137  int64_t first_pts; /* initial pts value */
138  int64_t cur_pts; /* current pts value from the stream in us */
139  int64_t cur_frame_duration; /* duration of the current frame in us */
140  int cur_frame_bytes; /* output frame size, needed to compute
141  the time at which we send each
142  packet */
143  int pts_stream_index; /* stream we choose as clock reference */
144  int64_t cur_clock; /* current clock reference value in us */
145  /* output format handling */
146  struct FFStream *stream;
147  /* -1 is invalid stream */
148  int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
149  int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
151  AVFormatContext fmt_ctx; /* instance of FFStream for one user */
152  int last_packet_sent; /* true if last data packet was sent */
156  char protocol[16];
157  char method[16];
158  char url[128];
160  uint8_t *buffer;
161  int is_packetized; /* if true, the stream is packetized */
162  int packet_stream_index; /* current stream for output in state machine */
163 
164  /* RTSP state specific */
165  uint8_t *pb_buffer; /* XXX: use that in all the code */
167  int seq; /* RTSP sequence number */
168 
169  /* RTP state specific */
171  char session_id[32]; /* session id */
173 
174  /* RTP/UDP specific */
176 
177  /* RTP/TCP specific */
180 } HTTPContext;
181 
182 /* each generated stream is described here */
187 };
188 
190  IP_ALLOW = 1,
192 };
193 
194 typedef struct IPAddressACL {
197  /* These are in host order */
198  struct in_addr first;
199  struct in_addr last;
200 } IPAddressACL;
201 
202 /* description of each stream of the avserver.conf file */
203 typedef struct FFStream {
205  char filename[1024]; /* stream filename */
206  struct FFStream *feed; /* feed we are using (can be null if
207  coming from file) */
208  AVDictionary *in_opts; /* input parameters */
209  AVInputFormat *ifmt; /* if non NULL, force input format */
212  char dynamic_acl[1024];
214  int prebuffer; /* Number of millseconds early to start */
215  int64_t max_time; /* Number of milliseconds to run */
218  int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
219  char feed_filename[1024]; /* file name of the feed storage, or
220  input file name for a stream */
221  char author[512];
222  char title[512];
223  char copyright[512];
224  char comment[512];
225  pid_t pid; /* of avconv process */
226  time_t pid_start; /* of avconv process */
227  char **child_argv;
228  struct FFStream *next;
229  unsigned bandwidth; /* bandwidth, in kbits/s */
230  /* RTSP options */
231  char *rtsp_option;
232  /* multicast specific */
234  struct in_addr multicast_ip;
235  int multicast_port; /* first port used for multicast */
237  int loop; /* if true, send the stream in loops (only meaningful if file) */
238 
239  /* feed specific */
240  int feed_opened; /* true if someone is writing to the feed */
241  int is_feed; /* true if it is a feed */
242  int readonly; /* True if writing is prohibited to the file */
243  int truncate; /* True if feeder connection truncate the feed file */
245  int64_t bytes_served;
246  int64_t feed_max_size; /* maximum storage size, zero means unlimited */
247  int64_t feed_write_index; /* current write position in feed (it wraps around) */
248  int64_t feed_size; /* current size of feed */
250 } FFStream;
251 
252 typedef struct FeedData {
253  long long data_count;
254  float avg_frame_size; /* frame size averaged over last frames with exponential mean */
255 } FeedData;
256 
257 static struct sockaddr_in my_http_addr;
258 static struct sockaddr_in my_rtsp_addr;
259 
260 static char logfilename[1024];
262 static FFStream *first_feed; /* contains only feeds */
263 static FFStream *first_stream; /* contains all streams, including feeds */
264 
265 static void new_connection(int server_fd, int is_rtsp);
266 static void close_connection(HTTPContext *c);
267 
268 /* HTTP handling */
269 static int handle_connection(HTTPContext *c);
270 static int http_parse_request(HTTPContext *c);
271 static int http_send_data(HTTPContext *c);
272 static void compute_status(HTTPContext *c);
273 static int open_input_stream(HTTPContext *c, const char *info);
274 static int http_start_receive_data(HTTPContext *c);
275 static int http_receive_data(HTTPContext *c);
276 
277 /* RTSP handling */
278 static int rtsp_parse_request(HTTPContext *c);
279 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
280 static void rtsp_cmd_options(HTTPContext *c, const char *url);
281 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
282 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285 
286 /* SDP handling */
287 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
288  struct in_addr my_ip);
289 
290 /* RTP handling */
291 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
292  FFStream *stream, const char *session_id,
293  enum RTSPLowerTransport rtp_protocol);
294 static int rtp_new_av_stream(HTTPContext *c,
295  int stream_index, struct sockaddr_in *dest_addr,
296  HTTPContext *rtsp_c);
297 
298 static const char *my_program_name;
299 static const char *my_program_dir;
300 
301 static const char *config_filename = "/etc/avserver.conf";
302 
303 static int avserver_debug;
304 static int avserver_daemon;
305 static int no_launch;
307 
308 /* maximum number of simultaneous HTTP connections */
309 static unsigned int nb_max_http_connections = 2000;
310 static unsigned int nb_max_connections = 5;
311 static unsigned int nb_connections;
312 
313 static uint64_t max_bandwidth = 1000;
314 static uint64_t current_bandwidth;
315 
316 static int64_t cur_time; // Making this global saves on passing it around everywhere
317 
319 
320 static FILE *logfile = NULL;
321 
322 void exit_program(int ret)
323 {
324  exit(ret);
325 }
326 
327 /* FIXME: make avserver work with IPv6 */
328 /* resolve host with also IP address parsing */
329 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
330 {
331 
332  if (!ff_inet_aton(hostname, sin_addr)) {
333 #if HAVE_GETADDRINFO
334  struct addrinfo *ai, *cur;
335  struct addrinfo hints;
336  memset(&hints, 0, sizeof(hints));
337  hints.ai_family = AF_INET;
338  if (getaddrinfo(hostname, NULL, &hints, &ai))
339  return -1;
340  /* getaddrinfo returns a linked list of addrinfo structs.
341  * Even if we set ai_family = AF_INET above, make sure
342  * that the returned one actually is of the correct type. */
343  for (cur = ai; cur; cur = cur->ai_next) {
344  if (cur->ai_family == AF_INET) {
345  *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
346  freeaddrinfo(ai);
347  return 0;
348  }
349  }
350  freeaddrinfo(ai);
351  return -1;
352 #else
353  struct hostent *hp;
354  hp = gethostbyname(hostname);
355  if (!hp)
356  return -1;
357  memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
358 #endif
359  }
360  return 0;
361 }
362 
363 static char *ctime1(char *buf2)
364 {
365  time_t ti;
366  char *p;
367 
368  ti = time(NULL);
369  p = ctime(&ti);
370  strcpy(buf2, p);
371  p = buf2 + strlen(p) - 1;
372  if (*p == '\n')
373  *p = '\0';
374  return buf2;
375 }
376 
377 static void http_vlog(const char *fmt, va_list vargs)
378 {
379  static int print_prefix = 1;
380  if (logfile) {
381  if (print_prefix) {
382  char buf[32];
383  ctime1(buf);
384  fprintf(logfile, "%s ", buf);
385  }
386  print_prefix = strstr(fmt, "\n") != NULL;
387  vfprintf(logfile, fmt, vargs);
388  fflush(logfile);
389  }
390 }
391 
392 #ifdef __GNUC__
393 __attribute__ ((format (printf, 1, 2)))
394 #endif
395 static void http_log(const char *fmt, ...)
396 {
397  va_list vargs;
398  va_start(vargs, fmt);
399  http_vlog(fmt, vargs);
400  va_end(vargs);
401 }
402 
403 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
404 {
405  static int print_prefix = 1;
406  AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
407  if (level > av_log_get_level())
408  return;
409  if (print_prefix && avc)
410  http_log("[%s @ %p]", avc->item_name(ptr), ptr);
411  print_prefix = strstr(fmt, "\n") != NULL;
412  http_vlog(fmt, vargs);
413 }
414 
416 {
417  if (c->suppress_log)
418  return;
419 
420  http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
421  inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
422  c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
423 }
424 
425 static void update_datarate(DataRateData *drd, int64_t count)
426 {
427  if (!drd->time1 && !drd->count1) {
428  drd->time1 = drd->time2 = cur_time;
429  drd->count1 = drd->count2 = count;
430  } else if (cur_time - drd->time2 > 5000) {
431  drd->time1 = drd->time2;
432  drd->count1 = drd->count2;
433  drd->time2 = cur_time;
434  drd->count2 = count;
435  }
436 }
437 
438 /* In bytes per second */
439 static int compute_datarate(DataRateData *drd, int64_t count)
440 {
441  if (cur_time == drd->time1)
442  return 0;
443 
444  return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
445 }
446 
447 
448 static void start_children(FFStream *feed)
449 {
450  if (no_launch)
451  return;
452 
453  for (; feed; feed = feed->next) {
454  if (feed->child_argv && !feed->pid) {
455  feed->pid_start = time(0);
456 
457  feed->pid = fork();
458 
459  if (feed->pid < 0) {
460  http_log("Unable to create children\n");
461  exit(1);
462  }
463  if (!feed->pid) {
464  /* In child */
465  char pathname[1024];
466  char *slash;
467  int i;
468 
469  av_strlcpy(pathname, my_program_name, sizeof(pathname));
470 
471  slash = strrchr(pathname, '/');
472  if (!slash)
473  slash = pathname;
474  else
475  slash++;
476  strcpy(slash, "avconv");
477 
478  http_log("Launch command line: ");
479  http_log("%s ", pathname);
480  for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
481  http_log("%s ", feed->child_argv[i]);
482  http_log("\n");
483 
484  for (i = 3; i < 256; i++)
485  close(i);
486 
487  if (!avserver_debug) {
488  i = open("/dev/null", O_RDWR);
489  if (i != -1) {
490  dup2(i, 0);
491  dup2(i, 1);
492  dup2(i, 2);
493  close(i);
494  }
495  }
496 
497  /* This is needed to make relative pathnames work */
498  chdir(my_program_dir);
499 
500  signal(SIGPIPE, SIG_DFL);
501 
502  execvp(pathname, feed->child_argv);
503 
504  _exit(1);
505  }
506  }
507  }
508 }
509 
510 /* open a listening socket */
511 static int socket_open_listen(struct sockaddr_in *my_addr)
512 {
513  int server_fd, tmp;
514 
515  server_fd = socket(AF_INET,SOCK_STREAM,0);
516  if (server_fd < 0) {
517  perror ("socket");
518  return -1;
519  }
520 
521  tmp = 1;
522  setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
523 
524  my_addr->sin_family = AF_INET;
525  if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
526  char bindmsg[32];
527  snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
528  perror (bindmsg);
529  closesocket(server_fd);
530  return -1;
531  }
532 
533  if (listen (server_fd, 5) < 0) {
534  perror ("listen");
535  closesocket(server_fd);
536  return -1;
537  }
538  ff_socket_nonblock(server_fd, 1);
539 
540  return server_fd;
541 }
542 
543 /* start all multicast streams */
544 static void start_multicast(void)
545 {
546  FFStream *stream;
547  char session_id[32];
548  HTTPContext *rtp_c;
549  struct sockaddr_in dest_addr;
550  int default_port, stream_index;
551 
552  default_port = 6000;
553  for(stream = first_stream; stream != NULL; stream = stream->next) {
554  if (stream->is_multicast) {
555  /* open the RTP connection */
556  snprintf(session_id, sizeof(session_id), "%08x%08x",
557  av_lfg_get(&random_state), av_lfg_get(&random_state));
558 
559  /* choose a port if none given */
560  if (stream->multicast_port == 0) {
561  stream->multicast_port = default_port;
562  default_port += 100;
563  }
564 
565  dest_addr.sin_family = AF_INET;
566  dest_addr.sin_addr = stream->multicast_ip;
567  dest_addr.sin_port = htons(stream->multicast_port);
568 
569  rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
571  if (!rtp_c)
572  continue;
573 
574  if (open_input_stream(rtp_c, "") < 0) {
575  http_log("Could not open input stream for stream '%s'\n",
576  stream->filename);
577  continue;
578  }
579 
580  /* open each RTP stream */
581  for(stream_index = 0; stream_index < stream->nb_streams;
582  stream_index++) {
583  dest_addr.sin_port = htons(stream->multicast_port +
584  2 * stream_index);
585  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
586  http_log("Could not open output stream '%s/streamid=%d'\n",
587  stream->filename, stream_index);
588  exit(1);
589  }
590  }
591 
592  /* change state to send data */
593  rtp_c->state = HTTPSTATE_SEND_DATA;
594  }
595  }
596 }
597 
598 /* main loop of the http server */
599 static int http_server(void)
600 {
601  int server_fd = 0, rtsp_server_fd = 0;
602  int ret, delay, delay1;
603  struct pollfd *poll_table, *poll_entry;
604  HTTPContext *c, *c_next;
605 
606  if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
607  http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
608  return -1;
609  }
610 
611  if (my_http_addr.sin_port) {
612  server_fd = socket_open_listen(&my_http_addr);
613  if (server_fd < 0)
614  return -1;
615  }
616 
617  if (my_rtsp_addr.sin_port) {
618  rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
619  if (rtsp_server_fd < 0)
620  return -1;
621  }
622 
623  if (!rtsp_server_fd && !server_fd) {
624  http_log("HTTP and RTSP disabled.\n");
625  return -1;
626  }
627 
628  http_log("AVserver started.\n");
629 
630  start_children(first_feed);
631 
632  start_multicast();
633 
634  for(;;) {
635  poll_entry = poll_table;
636  if (server_fd) {
637  poll_entry->fd = server_fd;
638  poll_entry->events = POLLIN;
639  poll_entry++;
640  }
641  if (rtsp_server_fd) {
642  poll_entry->fd = rtsp_server_fd;
643  poll_entry->events = POLLIN;
644  poll_entry++;
645  }
646 
647  /* wait for events on each HTTP handle */
648  c = first_http_ctx;
649  delay = 1000;
650  while (c != NULL) {
651  int fd;
652  fd = c->fd;
653  switch(c->state) {
657  c->poll_entry = poll_entry;
658  poll_entry->fd = fd;
659  poll_entry->events = POLLOUT;
660  poll_entry++;
661  break;
663  case HTTPSTATE_SEND_DATA:
665  if (!c->is_packetized) {
666  /* for TCP, we output as much as we can (may need to put a limit) */
667  c->poll_entry = poll_entry;
668  poll_entry->fd = fd;
669  poll_entry->events = POLLOUT;
670  poll_entry++;
671  } else {
672  /* when avserver is doing the timing, we work by
673  looking at which packet need to be sent every
674  10 ms */
675  delay1 = 10; /* one tick wait XXX: 10 ms assumed */
676  if (delay1 < delay)
677  delay = delay1;
678  }
679  break;
682  case HTTPSTATE_WAIT_FEED:
684  /* need to catch errors */
685  c->poll_entry = poll_entry;
686  poll_entry->fd = fd;
687  poll_entry->events = POLLIN;/* Maybe this will work */
688  poll_entry++;
689  break;
690  default:
691  c->poll_entry = NULL;
692  break;
693  }
694  c = c->next;
695  }
696 
697  /* wait for an event on one connection. We poll at least every
698  second to handle timeouts */
699  do {
700  ret = poll(poll_table, poll_entry - poll_table, delay);
701  if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
702  ff_neterrno() != AVERROR(EINTR))
703  return -1;
704  } while (ret < 0);
705 
706  cur_time = av_gettime() / 1000;
707 
710  start_children(first_feed);
711  }
712 
713  /* now handle the events */
714  for(c = first_http_ctx; c != NULL; c = c_next) {
715  c_next = c->next;
716  if (handle_connection(c) < 0) {
717  /* close and free the connection */
718  log_connection(c);
719  close_connection(c);
720  }
721  }
722 
723  poll_entry = poll_table;
724  if (server_fd) {
725  /* new HTTP connection request ? */
726  if (poll_entry->revents & POLLIN)
727  new_connection(server_fd, 0);
728  poll_entry++;
729  }
730  if (rtsp_server_fd) {
731  /* new RTSP connection request ? */
732  if (poll_entry->revents & POLLIN)
733  new_connection(rtsp_server_fd, 1);
734  }
735  }
736 }
737 
738 /* start waiting for a new HTTP/RTSP request */
739 static void start_wait_request(HTTPContext *c, int is_rtsp)
740 {
741  c->buffer_ptr = c->buffer;
742  c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
743 
744  if (is_rtsp) {
747  } else {
750  }
751 }
752 
753 static void http_send_too_busy_reply(int fd)
754 {
755  char buffer[300];
756  int len = snprintf(buffer, sizeof(buffer),
757  "HTTP/1.0 503 Server too busy\r\n"
758  "Content-type: text/html\r\n"
759  "\r\n"
760  "<html><head><title>Too busy</title></head><body>\r\n"
761  "<p>The server is too busy to serve your request at this time.</p>\r\n"
762  "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
763  "</body></html>\r\n",
765  send(fd, buffer, len, 0);
766 }
767 
768 
769 static void new_connection(int server_fd, int is_rtsp)
770 {
771  struct sockaddr_in from_addr;
772  int fd, len;
773  HTTPContext *c = NULL;
774 
775  len = sizeof(from_addr);
776  fd = accept(server_fd, (struct sockaddr *)&from_addr,
777  &len);
778  if (fd < 0) {
779  http_log("error during accept %s\n", strerror(errno));
780  return;
781  }
782  ff_socket_nonblock(fd, 1);
783 
786  goto fail;
787  }
788 
789  /* add a new connection */
790  c = av_mallocz(sizeof(HTTPContext));
791  if (!c)
792  goto fail;
793 
794  c->fd = fd;
795  c->poll_entry = NULL;
796  c->from_addr = from_addr;
798  c->buffer = av_malloc(c->buffer_size);
799  if (!c->buffer)
800  goto fail;
801 
802  c->next = first_http_ctx;
803  first_http_ctx = c;
804  nb_connections++;
805 
806  start_wait_request(c, is_rtsp);
807 
808  return;
809 
810  fail:
811  if (c) {
812  av_free(c->buffer);
813  av_free(c);
814  }
815  closesocket(fd);
816 }
817 
819 {
820  HTTPContext **cp, *c1;
821  int i, nb_streams;
822  AVFormatContext *ctx;
823  URLContext *h;
824  AVStream *st;
825 
826  /* remove connection from list */
827  cp = &first_http_ctx;
828  while ((*cp) != NULL) {
829  c1 = *cp;
830  if (c1 == c)
831  *cp = c->next;
832  else
833  cp = &c1->next;
834  }
835 
836  /* remove references, if any (XXX: do it faster) */
837  for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
838  if (c1->rtsp_c == c)
839  c1->rtsp_c = NULL;
840  }
841 
842  /* remove connection associated resources */
843  if (c->fd >= 0)
844  closesocket(c->fd);
845  if (c->fmt_in) {
846  /* close each frame parser */
847  for(i=0;i<c->fmt_in->nb_streams;i++) {
848  st = c->fmt_in->streams[i];
849  if (st->codec->codec)
850  avcodec_close(st->codec);
851  }
853  }
854 
855  /* free RTP output streams if any */
856  nb_streams = 0;
857  if (c->stream)
858  nb_streams = c->stream->nb_streams;
859 
860  for(i=0;i<nb_streams;i++) {
861  ctx = c->rtp_ctx[i];
862  if (ctx) {
863  av_write_trailer(ctx);
864  av_dict_free(&ctx->metadata);
865  av_free(ctx->streams[0]);
866  av_free(ctx);
867  }
868  h = c->rtp_handles[i];
869  if (h)
870  url_close(h);
871  }
872 
873  ctx = &c->fmt_ctx;
874 
876  if (ctx->oformat) {
877  /* prepare header */
878  if (avio_open_dyn_buf(&ctx->pb) >= 0) {
879  av_write_trailer(ctx);
880  av_freep(&c->pb_buffer);
881  avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
882  }
883  }
884  }
885 
886  for(i=0; i<ctx->nb_streams; i++)
887  av_free(ctx->streams[i]);
888 
889  if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
891 
892  /* signal that there is no feed if we are the feeder socket */
893  if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
894  c->stream->feed_opened = 0;
895  close(c->feed_fd);
896  }
897 
898  av_freep(&c->pb_buffer);
899  av_freep(&c->packet_buffer);
900  av_free(c->buffer);
901  av_free(c);
902  nb_connections--;
903 }
904 
906 {
907  int len, ret;
908 
909  switch(c->state) {
912  /* timeout ? */
913  if ((c->timeout - cur_time) < 0)
914  return -1;
915  if (c->poll_entry->revents & (POLLERR | POLLHUP))
916  return -1;
917 
918  /* no need to read if no events */
919  if (!(c->poll_entry->revents & POLLIN))
920  return 0;
921  /* read the data */
922  read_loop:
923  len = recv(c->fd, c->buffer_ptr, 1, 0);
924  if (len < 0) {
925  if (ff_neterrno() != AVERROR(EAGAIN) &&
926  ff_neterrno() != AVERROR(EINTR))
927  return -1;
928  } else if (len == 0) {
929  return -1;
930  } else {
931  /* search for end of request. */
932  uint8_t *ptr;
933  c->buffer_ptr += len;
934  ptr = c->buffer_ptr;
935  if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
936  (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
937  /* request found : parse it and reply */
938  if (c->state == HTTPSTATE_WAIT_REQUEST) {
939  ret = http_parse_request(c);
940  } else {
941  ret = rtsp_parse_request(c);
942  }
943  if (ret < 0)
944  return -1;
945  } else if (ptr >= c->buffer_end) {
946  /* request too long: cannot do anything */
947  return -1;
948  } else goto read_loop;
949  }
950  break;
951 
953  if (c->poll_entry->revents & (POLLERR | POLLHUP))
954  return -1;
955 
956  /* no need to write if no events */
957  if (!(c->poll_entry->revents & POLLOUT))
958  return 0;
959  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
960  if (len < 0) {
961  if (ff_neterrno() != AVERROR(EAGAIN) &&
962  ff_neterrno() != AVERROR(EINTR)) {
963  /* error : close connection */
964  av_freep(&c->pb_buffer);
965  return -1;
966  }
967  } else {
968  c->buffer_ptr += len;
969  if (c->stream)
970  c->stream->bytes_served += len;
971  c->data_count += len;
972  if (c->buffer_ptr >= c->buffer_end) {
973  av_freep(&c->pb_buffer);
974  /* if error, exit */
975  if (c->http_error)
976  return -1;
977  /* all the buffer was sent : synchronize to the incoming stream */
979  c->buffer_ptr = c->buffer_end = c->buffer;
980  }
981  }
982  break;
983 
984  case HTTPSTATE_SEND_DATA:
987  /* for packetized output, we consider we can always write (the
988  input streams sets the speed). It may be better to verify
989  that we do not rely too much on the kernel queues */
990  if (!c->is_packetized) {
991  if (c->poll_entry->revents & (POLLERR | POLLHUP))
992  return -1;
993 
994  /* no need to read if no events */
995  if (!(c->poll_entry->revents & POLLOUT))
996  return 0;
997  }
998  if (http_send_data(c) < 0)
999  return -1;
1000  /* close connection if trailer sent */
1002  return -1;
1003  break;
1005  /* no need to read if no events */
1006  if (c->poll_entry->revents & (POLLERR | POLLHUP))
1007  return -1;
1008  if (!(c->poll_entry->revents & POLLIN))
1009  return 0;
1010  if (http_receive_data(c) < 0)
1011  return -1;
1012  break;
1013  case HTTPSTATE_WAIT_FEED:
1014  /* no need to read if no events */
1015  if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1016  return -1;
1017 
1018  /* nothing to do, we'll be waken up by incoming feed packets */
1019  break;
1020 
1021  case RTSPSTATE_SEND_REPLY:
1022  if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1023  av_freep(&c->pb_buffer);
1024  return -1;
1025  }
1026  /* no need to write if no events */
1027  if (!(c->poll_entry->revents & POLLOUT))
1028  return 0;
1029  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1030  if (len < 0) {
1031  if (ff_neterrno() != AVERROR(EAGAIN) &&
1032  ff_neterrno() != AVERROR(EINTR)) {
1033  /* error : close connection */
1034  av_freep(&c->pb_buffer);
1035  return -1;
1036  }
1037  } else {
1038  c->buffer_ptr += len;
1039  c->data_count += len;
1040  if (c->buffer_ptr >= c->buffer_end) {
1041  /* all the buffer was sent : wait for a new request */
1042  av_freep(&c->pb_buffer);
1043  start_wait_request(c, 1);
1044  }
1045  }
1046  break;
1047  case RTSPSTATE_SEND_PACKET:
1048  if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1049  av_freep(&c->packet_buffer);
1050  return -1;
1051  }
1052  /* no need to write if no events */
1053  if (!(c->poll_entry->revents & POLLOUT))
1054  return 0;
1055  len = send(c->fd, c->packet_buffer_ptr,
1057  if (len < 0) {
1058  if (ff_neterrno() != AVERROR(EAGAIN) &&
1059  ff_neterrno() != AVERROR(EINTR)) {
1060  /* error : close connection */
1061  av_freep(&c->packet_buffer);
1062  return -1;
1063  }
1064  } else {
1065  c->packet_buffer_ptr += len;
1066  if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1067  /* all the buffer was sent : wait for a new request */
1068  av_freep(&c->packet_buffer);
1070  }
1071  }
1072  break;
1073  case HTTPSTATE_READY:
1074  /* nothing to do */
1075  break;
1076  default:
1077  return -1;
1078  }
1079  return 0;
1080 }
1081 
1082 static int extract_rates(char *rates, int ratelen, const char *request)
1083 {
1084  const char *p;
1085 
1086  for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1087  if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1088  const char *q = p + 7;
1089 
1090  while (*q && *q != '\n' && isspace(*q))
1091  q++;
1092 
1093  if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1094  int stream_no;
1095  int rate_no;
1096 
1097  q += 20;
1098 
1099  memset(rates, 0xff, ratelen);
1100 
1101  while (1) {
1102  while (*q && *q != '\n' && *q != ':')
1103  q++;
1104 
1105  if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1106  break;
1107 
1108  stream_no--;
1109  if (stream_no < ratelen && stream_no >= 0)
1110  rates[stream_no] = rate_no;
1111 
1112  while (*q && *q != '\n' && !isspace(*q))
1113  q++;
1114  }
1115 
1116  return 1;
1117  }
1118  }
1119  p = strchr(p, '\n');
1120  if (!p)
1121  break;
1122 
1123  p++;
1124  }
1125 
1126  return 0;
1127 }
1128 
1129 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1130 {
1131  int i;
1132  int best_bitrate = 100000000;
1133  int best = -1;
1134 
1135  for (i = 0; i < feed->nb_streams; i++) {
1136  AVCodecContext *feed_codec = feed->streams[i]->codec;
1137 
1138  if (feed_codec->codec_id != codec->codec_id ||
1139  feed_codec->sample_rate != codec->sample_rate ||
1140  feed_codec->width != codec->width ||
1141  feed_codec->height != codec->height)
1142  continue;
1143 
1144  /* Potential stream */
1145 
1146  /* We want the fastest stream less than bit_rate, or the slowest
1147  * faster than bit_rate
1148  */
1149 
1150  if (feed_codec->bit_rate <= bit_rate) {
1151  if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1152  best_bitrate = feed_codec->bit_rate;
1153  best = i;
1154  }
1155  } else {
1156  if (feed_codec->bit_rate < best_bitrate) {
1157  best_bitrate = feed_codec->bit_rate;
1158  best = i;
1159  }
1160  }
1161  }
1162 
1163  return best;
1164 }
1165 
1166 static int modify_current_stream(HTTPContext *c, char *rates)
1167 {
1168  int i;
1169  FFStream *req = c->stream;
1170  int action_required = 0;
1171 
1172  /* Not much we can do for a feed */
1173  if (!req->feed)
1174  return 0;
1175 
1176  for (i = 0; i < req->nb_streams; i++) {
1177  AVCodecContext *codec = req->streams[i]->codec;
1178 
1179  switch(rates[i]) {
1180  case 0:
1181  c->switch_feed_streams[i] = req->feed_streams[i];
1182  break;
1183  case 1:
1184  c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1185  break;
1186  case 2:
1187  /* Wants off or slow */
1188  c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1189 #ifdef WANTS_OFF
1190  /* This doesn't work well when it turns off the only stream! */
1191  c->switch_feed_streams[i] = -2;
1192  c->feed_streams[i] = -2;
1193 #endif
1194  break;
1195  }
1196 
1197  if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1198  action_required = 1;
1199  }
1200 
1201  return action_required;
1202 }
1203 
1204 /* XXX: factorize in utils.c ? */
1205 /* XXX: take care with different space meaning */
1206 static void skip_spaces(const char **pp)
1207 {
1208  const char *p;
1209  p = *pp;
1210  while (*p == ' ' || *p == '\t')
1211  p++;
1212  *pp = p;
1213 }
1214 
1215 static void get_word(char *buf, int buf_size, const char **pp)
1216 {
1217  const char *p;
1218  char *q;
1219 
1220  p = *pp;
1221  skip_spaces(&p);
1222  q = buf;
1223  while (!isspace(*p) && *p != '\0') {
1224  if ((q - buf) < buf_size - 1)
1225  *q++ = *p;
1226  p++;
1227  }
1228  if (buf_size > 0)
1229  *q = '\0';
1230  *pp = p;
1231 }
1232 
1233 static void get_arg(char *buf, int buf_size, const char **pp)
1234 {
1235  const char *p;
1236  char *q;
1237  int quote;
1238 
1239  p = *pp;
1240  while (isspace(*p)) p++;
1241  q = buf;
1242  quote = 0;
1243  if (*p == '\"' || *p == '\'')
1244  quote = *p++;
1245  for(;;) {
1246  if (quote) {
1247  if (*p == quote)
1248  break;
1249  } else {
1250  if (isspace(*p))
1251  break;
1252  }
1253  if (*p == '\0')
1254  break;
1255  if ((q - buf) < buf_size - 1)
1256  *q++ = *p;
1257  p++;
1258  }
1259  *q = '\0';
1260  if (quote && *p == quote)
1261  p++;
1262  *pp = p;
1263 }
1264 
1265 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1266  const char *p, const char *filename, int line_num)
1267 {
1268  char arg[1024];
1269  IPAddressACL acl;
1270  int errors = 0;
1271 
1272  get_arg(arg, sizeof(arg), &p);
1273  if (av_strcasecmp(arg, "allow") == 0)
1274  acl.action = IP_ALLOW;
1275  else if (av_strcasecmp(arg, "deny") == 0)
1276  acl.action = IP_DENY;
1277  else {
1278  fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1279  filename, line_num, arg);
1280  errors++;
1281  }
1282 
1283  get_arg(arg, sizeof(arg), &p);
1284 
1285  if (resolve_host(&acl.first, arg) != 0) {
1286  fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1287  filename, line_num, arg);
1288  errors++;
1289  } else
1290  acl.last = acl.first;
1291 
1292  get_arg(arg, sizeof(arg), &p);
1293 
1294  if (arg[0]) {
1295  if (resolve_host(&acl.last, arg) != 0) {
1296  fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1297  filename, line_num, arg);
1298  errors++;
1299  }
1300  }
1301 
1302  if (!errors) {
1303  IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1304  IPAddressACL **naclp = 0;
1305 
1306  acl.next = 0;
1307  *nacl = acl;
1308 
1309  if (stream)
1310  naclp = &stream->acl;
1311  else if (feed)
1312  naclp = &feed->acl;
1313  else if (ext_acl)
1314  naclp = &ext_acl;
1315  else {
1316  fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1317  filename, line_num);
1318  errors++;
1319  }
1320 
1321  if (naclp) {
1322  while (*naclp)
1323  naclp = &(*naclp)->next;
1324 
1325  *naclp = nacl;
1326  }
1327  }
1328 }
1329 
1330 
1332 {
1333  FILE* f;
1334  char line[1024];
1335  char cmd[1024];
1336  IPAddressACL *acl = NULL;
1337  int line_num = 0;
1338  const char *p;
1339 
1340  f = fopen(stream->dynamic_acl, "r");
1341  if (!f) {
1342  perror(stream->dynamic_acl);
1343  return NULL;
1344  }
1345 
1346  acl = av_mallocz(sizeof(IPAddressACL));
1347 
1348  /* Build ACL */
1349  for(;;) {
1350  if (fgets(line, sizeof(line), f) == NULL)
1351  break;
1352  line_num++;
1353  p = line;
1354  while (isspace(*p))
1355  p++;
1356  if (*p == '\0' || *p == '#')
1357  continue;
1358  get_arg(cmd, sizeof(cmd), &p);
1359 
1360  if (!av_strcasecmp(cmd, "ACL"))
1361  parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1362  }
1363  fclose(f);
1364  return acl;
1365 }
1366 
1367 
1368 static void free_acl_list(IPAddressACL *in_acl)
1369 {
1370  IPAddressACL *pacl,*pacl2;
1371 
1372  pacl = in_acl;
1373  while(pacl) {
1374  pacl2 = pacl;
1375  pacl = pacl->next;
1376  av_freep(pacl2);
1377  }
1378 }
1379 
1381 {
1382  enum IPAddressAction last_action = IP_DENY;
1383  IPAddressACL *acl;
1384  struct in_addr *src = &c->from_addr.sin_addr;
1385  unsigned long src_addr = src->s_addr;
1386 
1387  for (acl = in_acl; acl; acl = acl->next) {
1388  if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1389  return (acl->action == IP_ALLOW) ? 1 : 0;
1390  last_action = acl->action;
1391  }
1392 
1393  /* Nothing matched, so return not the last action */
1394  return (last_action == IP_DENY) ? 1 : 0;
1395 }
1396 
1397 static int validate_acl(FFStream *stream, HTTPContext *c)
1398 {
1399  int ret = 0;
1400  IPAddressACL *acl;
1401 
1402 
1403  /* if stream->acl is null validate_acl_list will return 1 */
1404  ret = validate_acl_list(stream->acl, c);
1405 
1406  if (stream->dynamic_acl[0]) {
1407  acl = parse_dynamic_acl(stream, c);
1408 
1409  ret = validate_acl_list(acl, c);
1410 
1411  free_acl_list(acl);
1412  }
1413 
1414  return ret;
1415 }
1416 
1417 /* compute the real filename of a file by matching it without its
1418  extensions to all the stream filenames */
1419 static void compute_real_filename(char *filename, int max_size)
1420 {
1421  char file1[1024];
1422  char file2[1024];
1423  char *p;
1424  FFStream *stream;
1425 
1426  /* compute filename by matching without the file extensions */
1427  av_strlcpy(file1, filename, sizeof(file1));
1428  p = strrchr(file1, '.');
1429  if (p)
1430  *p = '\0';
1431  for(stream = first_stream; stream != NULL; stream = stream->next) {
1432  av_strlcpy(file2, stream->filename, sizeof(file2));
1433  p = strrchr(file2, '.');
1434  if (p)
1435  *p = '\0';
1436  if (!strcmp(file1, file2)) {
1437  av_strlcpy(filename, stream->filename, max_size);
1438  break;
1439  }
1440  }
1441 }
1442 
1450 };
1451 
1452 /* parse http request and prepare header */
1454 {
1455  char *p;
1456  enum RedirType redir_type;
1457  char cmd[32];
1458  char info[1024], filename[1024];
1459  char url[1024], *q;
1460  char protocol[32];
1461  char msg[1024];
1462  const char *mime_type;
1463  FFStream *stream;
1464  int i;
1465  char ratebuf[32];
1466  char *useragent = 0;
1467 
1468  p = c->buffer;
1469  get_word(cmd, sizeof(cmd), (const char **)&p);
1470  av_strlcpy(c->method, cmd, sizeof(c->method));
1471 
1472  if (!strcmp(cmd, "GET"))
1473  c->post = 0;
1474  else if (!strcmp(cmd, "POST"))
1475  c->post = 1;
1476  else
1477  return -1;
1478 
1479  get_word(url, sizeof(url), (const char **)&p);
1480  av_strlcpy(c->url, url, sizeof(c->url));
1481 
1482  get_word(protocol, sizeof(protocol), (const char **)&p);
1483  if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1484  return -1;
1485 
1486  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1487 
1488  if (avserver_debug)
1489  http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1490 
1491  /* find the filename and the optional info string in the request */
1492  p = strchr(url, '?');
1493  if (p) {
1494  av_strlcpy(info, p, sizeof(info));
1495  *p = '\0';
1496  } else
1497  info[0] = '\0';
1498 
1499  av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1500 
1501  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1502  if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1503  useragent = p + 11;
1504  if (*useragent && *useragent != '\n' && isspace(*useragent))
1505  useragent++;
1506  break;
1507  }
1508  p = strchr(p, '\n');
1509  if (!p)
1510  break;
1511 
1512  p++;
1513  }
1514 
1515  redir_type = REDIR_NONE;
1516  if (av_match_ext(filename, "asx")) {
1517  redir_type = REDIR_ASX;
1518  filename[strlen(filename)-1] = 'f';
1519  } else if (av_match_ext(filename, "asf") &&
1520  (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1521  /* if this isn't WMP or lookalike, return the redirector file */
1522  redir_type = REDIR_ASF;
1523  } else if (av_match_ext(filename, "rpm,ram")) {
1524  redir_type = REDIR_RAM;
1525  strcpy(filename + strlen(filename)-2, "m");
1526  } else if (av_match_ext(filename, "rtsp")) {
1527  redir_type = REDIR_RTSP;
1528  compute_real_filename(filename, sizeof(filename) - 1);
1529  } else if (av_match_ext(filename, "sdp")) {
1530  redir_type = REDIR_SDP;
1531  compute_real_filename(filename, sizeof(filename) - 1);
1532  }
1533 
1534  // "redirect" / request to index.html
1535  if (!strlen(filename))
1536  av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1537 
1538  stream = first_stream;
1539  while (stream != NULL) {
1540  if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1541  break;
1542  stream = stream->next;
1543  }
1544  if (stream == NULL) {
1545  snprintf(msg, sizeof(msg), "File '%s' not found", url);
1546  http_log("File '%s' not found\n", url);
1547  goto send_error;
1548  }
1549 
1550  c->stream = stream;
1551  memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1552  memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1553 
1554  if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1555  c->http_error = 301;
1556  q = c->buffer;
1557  q += snprintf(q, c->buffer_size,
1558  "HTTP/1.0 301 Moved\r\n"
1559  "Location: %s\r\n"
1560  "Content-type: text/html\r\n"
1561  "\r\n"
1562  "<html><head><title>Moved</title></head><body>\r\n"
1563  "You should be <a href=\"%s\">redirected</a>.\r\n"
1564  "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1565  /* prepare output buffer */
1566  c->buffer_ptr = c->buffer;
1567  c->buffer_end = q;
1569  return 0;
1570  }
1571 
1572  /* If this is WMP, get the rate information */
1573  if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1574  if (modify_current_stream(c, ratebuf)) {
1575  for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1576  if (c->switch_feed_streams[i] >= 0)
1577  c->switch_feed_streams[i] = -1;
1578  }
1579  }
1580  }
1581 
1582  if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1583  current_bandwidth += stream->bandwidth;
1584 
1585  /* If already streaming this feed, do not let start another feeder. */
1586  if (stream->feed_opened) {
1587  snprintf(msg, sizeof(msg), "This feed is already being received.");
1588  http_log("Feed '%s' already being received\n", stream->feed_filename);
1589  goto send_error;
1590  }
1591 
1592  if (c->post == 0 && max_bandwidth < current_bandwidth) {
1593  c->http_error = 503;
1594  q = c->buffer;
1595  q += snprintf(q, c->buffer_size,
1596  "HTTP/1.0 503 Server too busy\r\n"
1597  "Content-type: text/html\r\n"
1598  "\r\n"
1599  "<html><head><title>Too busy</title></head><body>\r\n"
1600  "<p>The server is too busy to serve your request at this time.</p>\r\n"
1601  "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1602  "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1603  "</body></html>\r\n", current_bandwidth, max_bandwidth);
1604  /* prepare output buffer */
1605  c->buffer_ptr = c->buffer;
1606  c->buffer_end = q;
1608  return 0;
1609  }
1610 
1611  if (redir_type != REDIR_NONE) {
1612  char *hostinfo = 0;
1613 
1614  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1615  if (av_strncasecmp(p, "Host:", 5) == 0) {
1616  hostinfo = p + 5;
1617  break;
1618  }
1619  p = strchr(p, '\n');
1620  if (!p)
1621  break;
1622 
1623  p++;
1624  }
1625 
1626  if (hostinfo) {
1627  char *eoh;
1628  char hostbuf[260];
1629 
1630  while (isspace(*hostinfo))
1631  hostinfo++;
1632 
1633  eoh = strchr(hostinfo, '\n');
1634  if (eoh) {
1635  if (eoh[-1] == '\r')
1636  eoh--;
1637 
1638  if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1639  memcpy(hostbuf, hostinfo, eoh - hostinfo);
1640  hostbuf[eoh - hostinfo] = 0;
1641 
1642  c->http_error = 200;
1643  q = c->buffer;
1644  switch(redir_type) {
1645  case REDIR_ASX:
1646  q += snprintf(q, c->buffer_size,
1647  "HTTP/1.0 200 ASX Follows\r\n"
1648  "Content-type: video/x-ms-asf\r\n"
1649  "\r\n"
1650  "<ASX Version=\"3\">\r\n"
1651  //"<!-- Autogenerated by avserver -->\r\n"
1652  "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1653  "</ASX>\r\n", hostbuf, filename, info);
1654  break;
1655  case REDIR_RAM:
1656  q += snprintf(q, c->buffer_size,
1657  "HTTP/1.0 200 RAM Follows\r\n"
1658  "Content-type: audio/x-pn-realaudio\r\n"
1659  "\r\n"
1660  "# Autogenerated by avserver\r\n"
1661  "http://%s/%s%s\r\n", hostbuf, filename, info);
1662  break;
1663  case REDIR_ASF:
1664  q += snprintf(q, c->buffer_size,
1665  "HTTP/1.0 200 ASF Redirect follows\r\n"
1666  "Content-type: video/x-ms-asf\r\n"
1667  "\r\n"
1668  "[Reference]\r\n"
1669  "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1670  break;
1671  case REDIR_RTSP:
1672  {
1673  char hostname[256], *p;
1674  /* extract only hostname */
1675  av_strlcpy(hostname, hostbuf, sizeof(hostname));
1676  p = strrchr(hostname, ':');
1677  if (p)
1678  *p = '\0';
1679  q += snprintf(q, c->buffer_size,
1680  "HTTP/1.0 200 RTSP Redirect follows\r\n"
1681  /* XXX: incorrect mime type ? */
1682  "Content-type: application/x-rtsp\r\n"
1683  "\r\n"
1684  "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1685  }
1686  break;
1687  case REDIR_SDP:
1688  {
1689  uint8_t *sdp_data;
1690  int sdp_data_size, len;
1691  struct sockaddr_in my_addr;
1692 
1693  q += snprintf(q, c->buffer_size,
1694  "HTTP/1.0 200 OK\r\n"
1695  "Content-type: application/sdp\r\n"
1696  "\r\n");
1697 
1698  len = sizeof(my_addr);
1699  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1700 
1701  /* XXX: should use a dynamic buffer */
1702  sdp_data_size = prepare_sdp_description(stream,
1703  &sdp_data,
1704  my_addr.sin_addr);
1705  if (sdp_data_size > 0) {
1706  memcpy(q, sdp_data, sdp_data_size);
1707  q += sdp_data_size;
1708  *q = '\0';
1709  av_free(sdp_data);
1710  }
1711  }
1712  break;
1713  default:
1714  abort();
1715  break;
1716  }
1717 
1718  /* prepare output buffer */
1719  c->buffer_ptr = c->buffer;
1720  c->buffer_end = q;
1722  return 0;
1723  }
1724  }
1725  }
1726 
1727  snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1728  goto send_error;
1729  }
1730 
1731  stream->conns_served++;
1732 
1733  /* XXX: add there authenticate and IP match */
1734 
1735  if (c->post) {
1736  /* if post, it means a feed is being sent */
1737  if (!stream->is_feed) {
1738  /* However it might be a status report from WMP! Let us log the
1739  * data as it might come in handy one day. */
1740  char *logline = 0;
1741  int client_id = 0;
1742 
1743  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1744  if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1745  logline = p;
1746  break;
1747  }
1748  if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1749  client_id = strtol(p + 18, 0, 10);
1750  p = strchr(p, '\n');
1751  if (!p)
1752  break;
1753 
1754  p++;
1755  }
1756 
1757  if (logline) {
1758  char *eol = strchr(logline, '\n');
1759 
1760  logline += 17;
1761 
1762  if (eol) {
1763  if (eol[-1] == '\r')
1764  eol--;
1765  http_log("%.*s\n", (int) (eol - logline), logline);
1766  c->suppress_log = 1;
1767  }
1768  }
1769 
1770 #ifdef DEBUG
1771  http_log("\nGot request:\n%s\n", c->buffer);
1772 #endif
1773 
1774  if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1775  HTTPContext *wmpc;
1776 
1777  /* Now we have to find the client_id */
1778  for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1779  if (wmpc->wmp_client_id == client_id)
1780  break;
1781  }
1782 
1783  if (wmpc && modify_current_stream(wmpc, ratebuf))
1784  wmpc->switch_pending = 1;
1785  }
1786 
1787  snprintf(msg, sizeof(msg), "POST command not handled");
1788  c->stream = 0;
1789  goto send_error;
1790  }
1791  if (http_start_receive_data(c) < 0) {
1792  snprintf(msg, sizeof(msg), "could not open feed");
1793  goto send_error;
1794  }
1795  c->http_error = 0;
1797  return 0;
1798  }
1799 
1800 #ifdef DEBUG
1801  if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1802  http_log("\nGot request:\n%s\n", c->buffer);
1803 #endif
1804 
1806  goto send_status;
1807 
1808  /* open input stream */
1809  if (open_input_stream(c, info) < 0) {
1810  snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1811  goto send_error;
1812  }
1813 
1814  /* prepare http header */
1815  q = c->buffer;
1816  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1817  mime_type = c->stream->fmt->mime_type;
1818  if (!mime_type)
1819  mime_type = "application/x-octet-stream";
1820  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1821 
1822  /* for asf, we need extra headers */
1823  if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1824  /* Need to allocate a client id */
1825 
1826  c->wmp_client_id = av_lfg_get(&random_state);
1827 
1828  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1829  }
1830  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1831  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1832 
1833  /* prepare output buffer */
1834  c->http_error = 0;
1835  c->buffer_ptr = c->buffer;
1836  c->buffer_end = q;
1838  return 0;
1839  send_error:
1840  c->http_error = 404;
1841  q = c->buffer;
1842  q += snprintf(q, c->buffer_size,
1843  "HTTP/1.0 404 Not Found\r\n"
1844  "Content-type: text/html\r\n"
1845  "\r\n"
1846  "<html>\n"
1847  "<head><title>404 Not Found</title></head>\n"
1848  "<body>%s</body>\n"
1849  "</html>\n", msg);
1850  /* prepare output buffer */
1851  c->buffer_ptr = c->buffer;
1852  c->buffer_end = q;
1854  return 0;
1855  send_status:
1856  compute_status(c);
1857  c->http_error = 200; /* horrible : we use this value to avoid
1858  going to the send data state */
1860  return 0;
1861 }
1862 
1863 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1864 {
1865  static const char *suffix = " kMGTP";
1866  const char *s;
1867 
1868  for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1869 
1870  avio_printf(pb, "%"PRId64"%c", count, *s);
1871 }
1872 
1874 {
1875  HTTPContext *c1;
1876  FFStream *stream;
1877  char *p;
1878  time_t ti;
1879  int i, len;
1880  AVIOContext *pb;
1881 
1882  if (avio_open_dyn_buf(&pb) < 0) {
1883  /* XXX: return an error ? */
1884  c->buffer_ptr = c->buffer;
1885  c->buffer_end = c->buffer;
1886  return;
1887  }
1888 
1889  avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1890  avio_printf(pb, "Content-type: %s\r\n", "text/html");
1891  avio_printf(pb, "Pragma: no-cache\r\n");
1892  avio_printf(pb, "\r\n");
1893 
1894  avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1895  if (c->stream->feed_filename[0])
1896  avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1897  avio_printf(pb, "</head>\n<body>");
1898  avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1899  /* format status */
1900  avio_printf(pb, "<h2>Available Streams</h2>\n");
1901  avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1902  avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
1903  stream = first_stream;
1904  while (stream != NULL) {
1905  char sfilename[1024];
1906  char *eosf;
1907 
1908  if (stream->feed != stream) {
1909  av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1910  eosf = sfilename + strlen(sfilename);
1911  if (eosf - sfilename >= 4) {
1912  if (strcmp(eosf - 4, ".asf") == 0)
1913  strcpy(eosf - 4, ".asx");
1914  else if (strcmp(eosf - 3, ".rm") == 0)
1915  strcpy(eosf - 3, ".ram");
1916  else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1917  /* generate a sample RTSP director if
1918  unicast. Generate an SDP redirector if
1919  multicast */
1920  eosf = strrchr(sfilename, '.');
1921  if (!eosf)
1922  eosf = sfilename + strlen(sfilename);
1923  if (stream->is_multicast)
1924  strcpy(eosf, ".sdp");
1925  else
1926  strcpy(eosf, ".rtsp");
1927  }
1928  }
1929 
1930  avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1931  sfilename, stream->filename);
1932  avio_printf(pb, "<td align=right> %d <td align=right> ",
1933  stream->conns_served);
1934  fmt_bytecount(pb, stream->bytes_served);
1935  switch(stream->stream_type) {
1936  case STREAM_TYPE_LIVE: {
1937  int audio_bit_rate = 0;
1938  int video_bit_rate = 0;
1939  const char *audio_codec_name = "";
1940  const char *video_codec_name = "";
1941  const char *audio_codec_name_extra = "";
1942  const char *video_codec_name_extra = "";
1943 
1944  for(i=0;i<stream->nb_streams;i++) {
1945  AVStream *st = stream->streams[i];
1946  AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1947  switch(st->codec->codec_type) {
1948  case AVMEDIA_TYPE_AUDIO:
1949  audio_bit_rate += st->codec->bit_rate;
1950  if (codec) {
1951  if (*audio_codec_name)
1952  audio_codec_name_extra = "...";
1953  audio_codec_name = codec->name;
1954  }
1955  break;
1956  case AVMEDIA_TYPE_VIDEO:
1957  video_bit_rate += st->codec->bit_rate;
1958  if (codec) {
1959  if (*video_codec_name)
1960  video_codec_name_extra = "...";
1961  video_codec_name = codec->name;
1962  }
1963  break;
1964  case AVMEDIA_TYPE_DATA:
1965  video_bit_rate += st->codec->bit_rate;
1966  break;
1967  default:
1968  abort();
1969  }
1970  }
1971  avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
1972  stream->fmt->name,
1973  stream->bandwidth,
1974  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1975  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1976  if (stream->feed)
1977  avio_printf(pb, "<td>%s", stream->feed->filename);
1978  else
1979  avio_printf(pb, "<td>%s", stream->feed_filename);
1980  avio_printf(pb, "\n");
1981  }
1982  break;
1983  default:
1984  avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1985  break;
1986  }
1987  }
1988  stream = stream->next;
1989  }
1990  avio_printf(pb, "</table>\n");
1991 
1992  stream = first_stream;
1993  while (stream != NULL) {
1994  if (stream->feed == stream) {
1995  avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1996  if (stream->pid) {
1997  avio_printf(pb, "Running as pid %d.\n", stream->pid);
1998 
1999 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2000  {
2001  FILE *pid_stat;
2002  char ps_cmd[64];
2003 
2004  /* This is somewhat linux specific I guess */
2005  snprintf(ps_cmd, sizeof(ps_cmd),
2006  "ps -o \"%%cpu,cputime\" --no-headers %d",
2007  stream->pid);
2008 
2009  pid_stat = popen(ps_cmd, "r");
2010  if (pid_stat) {
2011  char cpuperc[10];
2012  char cpuused[64];
2013 
2014  if (fscanf(pid_stat, "%10s %64s", cpuperc,
2015  cpuused) == 2) {
2016  avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2017  cpuperc, cpuused);
2018  }
2019  fclose(pid_stat);
2020  }
2021  }
2022 #endif
2023 
2024  avio_printf(pb, "<p>");
2025  }
2026  avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
2027 
2028  for (i = 0; i < stream->nb_streams; i++) {
2029  AVStream *st = stream->streams[i];
2030  AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2031  const char *type = "unknown";
2032  char parameters[64];
2033 
2034  parameters[0] = 0;
2035 
2036  switch(st->codec->codec_type) {
2037  case AVMEDIA_TYPE_AUDIO:
2038  type = "audio";
2039  snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2040  break;
2041  case AVMEDIA_TYPE_VIDEO:
2042  type = "video";
2043  snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2044  st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2045  break;
2046  default:
2047  abort();
2048  }
2049  avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2050  i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2051  }
2052  avio_printf(pb, "</table>\n");
2053 
2054  }
2055  stream = stream->next;
2056  }
2057 
2058  /* connection status */
2059  avio_printf(pb, "<h2>Connection Status</h2>\n");
2060 
2061  avio_printf(pb, "Number of connections: %d / %d<br>\n",
2063 
2064  avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2066 
2067  avio_printf(pb, "<table>\n");
2068  avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
2069  c1 = first_http_ctx;
2070  i = 0;
2071  while (c1 != NULL) {
2072  int bitrate;
2073  int j;
2074 
2075  bitrate = 0;
2076  if (c1->stream) {
2077  for (j = 0; j < c1->stream->nb_streams; j++) {
2078  if (!c1->stream->feed)
2079  bitrate += c1->stream->streams[j]->codec->bit_rate;
2080  else if (c1->feed_streams[j] >= 0)
2081  bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2082  }
2083  }
2084 
2085  i++;
2086  p = inet_ntoa(c1->from_addr.sin_addr);
2087  avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2088  i,
2089  c1->stream ? c1->stream->filename : "",
2090  c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2091  p,
2092  c1->protocol,
2093  http_state[c1->state]);
2094  fmt_bytecount(pb, bitrate);
2095  avio_printf(pb, "<td align=right>");
2096  fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2097  avio_printf(pb, "<td align=right>");
2098  fmt_bytecount(pb, c1->data_count);
2099  avio_printf(pb, "\n");
2100  c1 = c1->next;
2101  }
2102  avio_printf(pb, "</table>\n");
2103 
2104  /* date */
2105  ti = time(NULL);
2106  p = ctime(&ti);
2107  avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2108  avio_printf(pb, "</body>\n</html>\n");
2109 
2110  len = avio_close_dyn_buf(pb, &c->pb_buffer);
2111  c->buffer_ptr = c->pb_buffer;
2112  c->buffer_end = c->pb_buffer + len;
2113 }
2114 
2115 static int open_input_stream(HTTPContext *c, const char *info)
2116 {
2117  char buf[128];
2118  char input_filename[1024];
2119  AVFormatContext *s = NULL;
2120  int i, ret;
2121  int64_t stream_pos;
2122 
2123  /* find file name */
2124  if (c->stream->feed) {
2125  strcpy(input_filename, c->stream->feed->feed_filename);
2126  /* compute position (absolute time) */
2127  if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2128  if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2129  return ret;
2130  } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2131  int prebuffer = strtol(buf, 0, 10);
2132  stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2133  } else
2134  stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2135  } else {
2136  strcpy(input_filename, c->stream->feed_filename);
2137  /* compute position (relative time) */
2138  if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2139  if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2140  return ret;
2141  } else
2142  stream_pos = 0;
2143  }
2144  if (input_filename[0] == '\0')
2145  return -1;
2146 
2147  /* open stream */
2148  if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2149  http_log("could not open %s: %d\n", input_filename, ret);
2150  return -1;
2151  }
2152  s->flags |= AVFMT_FLAG_GENPTS;
2153  c->fmt_in = s;
2154  if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2155  http_log("Could not find stream info '%s'\n", input_filename);
2157  return -1;
2158  }
2159 
2160  /* choose stream as clock source (we favorize video stream if
2161  present) for packet sending */
2162  c->pts_stream_index = 0;
2163  for(i=0;i<c->stream->nb_streams;i++) {
2164  if (c->pts_stream_index == 0 &&
2166  c->pts_stream_index = i;
2167  }
2168  }
2169 
2170  if (c->fmt_in->iformat->read_seek)
2171  av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2172  /* set the start time (needed for maxtime and RTP packet timing) */
2173  c->start_time = cur_time;
2175  return 0;
2176 }
2177 
2178 /* return the server clock (in us) */
2179 static int64_t get_server_clock(HTTPContext *c)
2180 {
2181  /* compute current pts value from system time */
2182  return (cur_time - c->start_time) * 1000;
2183 }
2184 
2185 /* return the estimated time at which the current packet must be sent
2186  (in us) */
2188 {
2189  int bytes_left, bytes_sent, frame_bytes;
2190 
2191  frame_bytes = c->cur_frame_bytes;
2192  if (frame_bytes <= 0)
2193  return c->cur_pts;
2194  else {
2195  bytes_left = c->buffer_end - c->buffer_ptr;
2196  bytes_sent = frame_bytes - bytes_left;
2197  return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2198  }
2199 }
2200 
2201 
2203 {
2204  int i, len, ret;
2205  AVFormatContext *ctx;
2206 
2207  av_freep(&c->pb_buffer);
2208  switch(c->state) {
2210  memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2211  av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2212  av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2213  av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2214  av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2215 
2216  c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2217 
2218  for(i=0;i<c->stream->nb_streams;i++) {
2219  AVStream *src;
2220  c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2221  /* if file or feed, then just take streams from FFStream struct */
2222  if (!c->stream->feed ||
2223  c->stream->feed == c->stream)
2224  src = c->stream->streams[i];
2225  else
2226  src = c->stream->feed->streams[c->stream->feed_streams[i]];
2227 
2228  *(c->fmt_ctx.streams[i]) = *src;
2229  c->fmt_ctx.streams[i]->priv_data = 0;
2230  c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2231  AVStream, not in codec */
2232  }
2233  /* set output format parameters */
2234  c->fmt_ctx.oformat = c->stream->fmt;
2236 
2237  c->got_key_frame = 0;
2238 
2239  /* prepare header and save header data in a stream */
2240  if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2241  /* XXX: potential leak */
2242  return -1;
2243  }
2244  c->fmt_ctx.pb->seekable = 0;
2245 
2246  /*
2247  * HACK to avoid mpeg ps muxer to spit many underflow errors
2248  * Default value from Libav
2249  * Try to set it use configuration option
2250  */
2251  c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2252  c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2253 
2254  if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2255  http_log("Error writing output header\n");
2256  return -1;
2257  }
2259 
2260  len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2261  c->buffer_ptr = c->pb_buffer;
2262  c->buffer_end = c->pb_buffer + len;
2263 
2265  c->last_packet_sent = 0;
2266  break;
2267  case HTTPSTATE_SEND_DATA:
2268  /* find a new packet */
2269  /* read a packet from the input stream */
2270  if (c->stream->feed)
2273  c->stream->feed->feed_size);
2274 
2275  if (c->stream->max_time &&
2276  c->stream->max_time + c->start_time - cur_time < 0)
2277  /* We have timed out */
2279  else {
2280  AVPacket pkt;
2281  redo:
2282  ret = av_read_frame(c->fmt_in, &pkt);
2283  if (ret < 0) {
2284  if (c->stream->feed) {
2285  /* if coming from feed, it means we reached the end of the
2286  ffm file, so must wait for more data */
2288  return 1; /* state changed */
2289  } else if (ret == AVERROR(EAGAIN)) {
2290  /* input not ready, come back later */
2291  return 0;
2292  } else {
2293  if (c->stream->loop) {
2295  if (open_input_stream(c, "") < 0)
2296  goto no_loop;
2297  goto redo;
2298  } else {
2299  no_loop:
2300  /* must send trailer now because eof or error */
2302  }
2303  }
2304  } else {
2305  int source_index = pkt.stream_index;
2306  /* update first pts if needed */
2307  if (c->first_pts == AV_NOPTS_VALUE) {
2309  c->start_time = cur_time;
2310  }
2311  /* send it to the appropriate stream */
2312  if (c->stream->feed) {
2313  /* if coming from a feed, select the right stream */
2314  if (c->switch_pending) {
2315  c->switch_pending = 0;
2316  for(i=0;i<c->stream->nb_streams;i++) {
2317  if (c->switch_feed_streams[i] == pkt.stream_index)
2318  if (pkt.flags & AV_PKT_FLAG_KEY)
2319  c->switch_feed_streams[i] = -1;
2320  if (c->switch_feed_streams[i] >= 0)
2321  c->switch_pending = 1;
2322  }
2323  }
2324  for(i=0;i<c->stream->nb_streams;i++) {
2325  if (c->stream->feed_streams[i] == pkt.stream_index) {
2326  AVStream *st = c->fmt_in->streams[source_index];
2327  pkt.stream_index = i;
2328  if (pkt.flags & AV_PKT_FLAG_KEY &&
2329  (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2330  c->stream->nb_streams == 1))
2331  c->got_key_frame = 1;
2332  if (!c->stream->send_on_key || c->got_key_frame)
2333  goto send_it;
2334  }
2335  }
2336  } else {
2337  AVCodecContext *codec;
2338  AVStream *ist, *ost;
2339  send_it:
2340  ist = c->fmt_in->streams[source_index];
2341  /* specific handling for RTP: we use several
2342  output stream (one for each RTP
2343  connection). XXX: need more abstract handling */
2344  if (c->is_packetized) {
2345  /* compute send time and duration */
2346  c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2347  c->cur_pts -= c->first_pts;
2349  /* find RTP context */
2351  ctx = c->rtp_ctx[c->packet_stream_index];
2352  if(!ctx) {
2353  av_free_packet(&pkt);
2354  break;
2355  }
2356  codec = ctx->streams[0]->codec;
2357  /* only one stream per RTP connection */
2358  pkt.stream_index = 0;
2359  } else {
2360  ctx = &c->fmt_ctx;
2361  /* Fudge here */
2362  codec = ctx->streams[pkt.stream_index]->codec;
2363  }
2364 
2365  if (c->is_packetized) {
2366  int max_packet_size;
2368  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2369  else
2370  max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2371  ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2372  } else {
2373  ret = avio_open_dyn_buf(&ctx->pb);
2374  }
2375  if (ret < 0) {
2376  /* XXX: potential leak */
2377  return -1;
2378  }
2379  ost = ctx->streams[pkt.stream_index];
2380 
2381  ctx->pb->seekable = 0;
2382  if (pkt.dts != AV_NOPTS_VALUE)
2383  pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2384  if (pkt.pts != AV_NOPTS_VALUE)
2385  pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2386  pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2387  if (av_write_frame(ctx, &pkt) < 0) {
2388  http_log("Error writing frame to output\n");
2390  }
2391 
2392  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2393  c->cur_frame_bytes = len;
2394  c->buffer_ptr = c->pb_buffer;
2395  c->buffer_end = c->pb_buffer + len;
2396 
2397  codec->frame_number++;
2398  if (len == 0) {
2399  av_free_packet(&pkt);
2400  goto redo;
2401  }
2402  }
2403  av_free_packet(&pkt);
2404  }
2405  }
2406  break;
2407  default:
2409  /* last packet test ? */
2410  if (c->last_packet_sent || c->is_packetized)
2411  return -1;
2412  ctx = &c->fmt_ctx;
2413  /* prepare header */
2414  if (avio_open_dyn_buf(&ctx->pb) < 0) {
2415  /* XXX: potential leak */
2416  return -1;
2417  }
2418  c->fmt_ctx.pb->seekable = 0;
2419  av_write_trailer(ctx);
2420  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2421  c->buffer_ptr = c->pb_buffer;
2422  c->buffer_end = c->pb_buffer + len;
2423 
2424  c->last_packet_sent = 1;
2425  break;
2426  }
2427  return 0;
2428 }
2429 
2430 /* should convert the format at the same time */
2431 /* send data starting at c->buffer_ptr to the output connection
2432  (either UDP or TCP connection) */
2434 {
2435  int len, ret;
2436 
2437  for(;;) {
2438  if (c->buffer_ptr >= c->buffer_end) {
2439  ret = http_prepare_data(c);
2440  if (ret < 0)
2441  return -1;
2442  else if (ret != 0)
2443  /* state change requested */
2444  break;
2445  } else {
2446  if (c->is_packetized) {
2447  /* RTP data output */
2448  len = c->buffer_end - c->buffer_ptr;
2449  if (len < 4) {
2450  /* fail safe - should never happen */
2451  fail1:
2452  c->buffer_ptr = c->buffer_end;
2453  return 0;
2454  }
2455  len = (c->buffer_ptr[0] << 24) |
2456  (c->buffer_ptr[1] << 16) |
2457  (c->buffer_ptr[2] << 8) |
2458  (c->buffer_ptr[3]);
2459  if (len > (c->buffer_end - c->buffer_ptr))
2460  goto fail1;
2461  if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2462  /* nothing to send yet: we can wait */
2463  return 0;
2464  }
2465 
2466  c->data_count += len;
2468  if (c->stream)
2469  c->stream->bytes_served += len;
2470 
2472  /* RTP packets are sent inside the RTSP TCP connection */
2473  AVIOContext *pb;
2474  int interleaved_index, size;
2475  uint8_t header[4];
2476  HTTPContext *rtsp_c;
2477 
2478  rtsp_c = c->rtsp_c;
2479  /* if no RTSP connection left, error */
2480  if (!rtsp_c)
2481  return -1;
2482  /* if already sending something, then wait. */
2483  if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2484  break;
2485  if (avio_open_dyn_buf(&pb) < 0)
2486  goto fail1;
2487  interleaved_index = c->packet_stream_index * 2;
2488  /* RTCP packets are sent at odd indexes */
2489  if (c->buffer_ptr[1] == 200)
2490  interleaved_index++;
2491  /* write RTSP TCP header */
2492  header[0] = '$';
2493  header[1] = interleaved_index;
2494  header[2] = len >> 8;
2495  header[3] = len;
2496  avio_write(pb, header, 4);
2497  /* write RTP packet data */
2498  c->buffer_ptr += 4;
2499  avio_write(pb, c->buffer_ptr, len);
2500  size = avio_close_dyn_buf(pb, &c->packet_buffer);
2501  /* prepare asynchronous TCP sending */
2502  rtsp_c->packet_buffer_ptr = c->packet_buffer;
2503  rtsp_c->packet_buffer_end = c->packet_buffer + size;
2504  c->buffer_ptr += len;
2505 
2506  /* send everything we can NOW */
2507  len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2508  rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2509  if (len > 0)
2510  rtsp_c->packet_buffer_ptr += len;
2511  if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2512  /* if we could not send all the data, we will
2513  send it later, so a new state is needed to
2514  "lock" the RTSP TCP connection */
2515  rtsp_c->state = RTSPSTATE_SEND_PACKET;
2516  break;
2517  } else
2518  /* all data has been sent */
2519  av_freep(&c->packet_buffer);
2520  } else {
2521  /* send RTP packet directly in UDP */
2522  c->buffer_ptr += 4;
2523  url_write(c->rtp_handles[c->packet_stream_index],
2524  c->buffer_ptr, len);
2525  c->buffer_ptr += len;
2526  /* here we continue as we can send several packets per 10 ms slot */
2527  }
2528  } else {
2529  /* TCP data output */
2530  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2531  if (len < 0) {
2532  if (ff_neterrno() != AVERROR(EAGAIN) &&
2533  ff_neterrno() != AVERROR(EINTR))
2534  /* error : close connection */
2535  return -1;
2536  else
2537  return 0;
2538  } else
2539  c->buffer_ptr += len;
2540 
2541  c->data_count += len;
2543  if (c->stream)
2544  c->stream->bytes_served += len;
2545  break;
2546  }
2547  }
2548  } /* for(;;) */
2549  return 0;
2550 }
2551 
2553 {
2554  int fd;
2555 
2556  if (c->stream->feed_opened)
2557  return -1;
2558 
2559  /* Don't permit writing to this one */
2560  if (c->stream->readonly)
2561  return -1;
2562 
2563  /* open feed */
2564  fd = open(c->stream->feed_filename, O_RDWR);
2565  if (fd < 0) {
2566  http_log("Error opening feeder file: %s\n", strerror(errno));
2567  return -1;
2568  }
2569  c->feed_fd = fd;
2570 
2571  if (c->stream->truncate) {
2572  /* truncate feed file */
2574  ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2575  http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2576  } else {
2577  if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2578  http_log("Error reading write index from feed file: %s\n", strerror(errno));
2579  return -1;
2580  }
2581  }
2582 
2584  c->stream->feed_size = lseek(fd, 0, SEEK_END);
2585  lseek(fd, 0, SEEK_SET);
2586 
2587  /* init buffer input */
2588  c->buffer_ptr = c->buffer;
2589  c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2590  c->stream->feed_opened = 1;
2591  c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2592  return 0;
2593 }
2594 
2596 {
2597  HTTPContext *c1;
2598  int len, loop_run = 0;
2599 
2600  while (c->chunked_encoding && !c->chunk_size &&
2601  c->buffer_end > c->buffer_ptr) {
2602  /* read chunk header, if present */
2603  len = recv(c->fd, c->buffer_ptr, 1, 0);
2604 
2605  if (len < 0) {
2606  if (ff_neterrno() != AVERROR(EAGAIN) &&
2607  ff_neterrno() != AVERROR(EINTR))
2608  /* error : close connection */
2609  goto fail;
2610  return 0;
2611  } else if (len == 0) {
2612  /* end of connection : close it */
2613  goto fail;
2614  } else if (c->buffer_ptr - c->buffer >= 2 &&
2615  !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2616  c->chunk_size = strtol(c->buffer, 0, 16);
2617  if (c->chunk_size == 0) // end of stream
2618  goto fail;
2619  c->buffer_ptr = c->buffer;
2620  break;
2621  } else if (++loop_run > 10) {
2622  /* no chunk header, abort */
2623  goto fail;
2624  } else {
2625  c->buffer_ptr++;
2626  }
2627  }
2628 
2629  if (c->buffer_end > c->buffer_ptr) {
2630  len = recv(c->fd, c->buffer_ptr,
2631  FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2632  if (len < 0) {
2633  if (ff_neterrno() != AVERROR(EAGAIN) &&
2634  ff_neterrno() != AVERROR(EINTR))
2635  /* error : close connection */
2636  goto fail;
2637  } else if (len == 0)
2638  /* end of connection : close it */
2639  goto fail;
2640  else {
2641  c->chunk_size -= len;
2642  c->buffer_ptr += len;
2643  c->data_count += len;
2645  }
2646  }
2647 
2648  if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2649  if (c->buffer[0] != 'f' ||
2650  c->buffer[1] != 'm') {
2651  http_log("Feed stream has become desynchronized -- disconnecting\n");
2652  goto fail;
2653  }
2654  }
2655 
2656  if (c->buffer_ptr >= c->buffer_end) {
2657  FFStream *feed = c->stream;
2658  /* a packet has been received : write it in the store, except
2659  if header */
2660  if (c->data_count > FFM_PACKET_SIZE) {
2661 
2662  // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2663  /* XXX: use llseek or url_seek */
2664  lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2665  if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2666  http_log("Error writing to feed file: %s\n", strerror(errno));
2667  goto fail;
2668  }
2669 
2671  /* update file size */
2672  if (feed->feed_write_index > c->stream->feed_size)
2673  feed->feed_size = feed->feed_write_index;
2674 
2675  /* handle wrap around if max file size reached */
2676  if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2678 
2679  /* write index */
2680  if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2681  http_log("Error writing index to feed file: %s\n", strerror(errno));
2682  goto fail;
2683  }
2684 
2685  /* wake up any waiting connections */
2686  for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2687  if (c1->state == HTTPSTATE_WAIT_FEED &&
2688  c1->stream->feed == c->stream->feed)
2689  c1->state = HTTPSTATE_SEND_DATA;
2690  }
2691  } else {
2692  /* We have a header in our hands that contains useful data */
2694  AVIOContext *pb;
2695  AVInputFormat *fmt_in;
2696  int i;
2697 
2698  if (!s)
2699  goto fail;
2700 
2701  /* use feed output format name to find corresponding input format */
2702  fmt_in = av_find_input_format(feed->fmt->name);
2703  if (!fmt_in)
2704  goto fail;
2705 
2706  pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2707  0, NULL, NULL, NULL, NULL);
2708  pb->seekable = 0;
2709 
2710  s->pb = pb;
2711  if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2712  av_free(pb);
2713  goto fail;
2714  }
2715 
2716  /* Now we have the actual streams */
2717  if (s->nb_streams != feed->nb_streams) {
2719  av_free(pb);
2720  http_log("Feed '%s' stream number does not match registered feed\n",
2721  c->stream->feed_filename);
2722  goto fail;
2723  }
2724 
2725  for (i = 0; i < s->nb_streams; i++) {
2726  AVStream *fst = feed->streams[i];
2727  AVStream *st = s->streams[i];
2728  avcodec_copy_context(fst->codec, st->codec);
2729  }
2730 
2732  av_free(pb);
2733  }
2734  c->buffer_ptr = c->buffer;
2735  }
2736 
2737  return 0;
2738  fail:
2739  c->stream->feed_opened = 0;
2740  close(c->feed_fd);
2741  /* wake up any waiting connections to stop waiting for feed */
2742  for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2743  if (c1->state == HTTPSTATE_WAIT_FEED &&
2744  c1->stream->feed == c->stream->feed)
2746  }
2747  return -1;
2748 }
2749 
2750 /********************************************************************/
2751 /* RTSP handling */
2752 
2753 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2754 {
2755  const char *str;
2756  time_t ti;
2757  struct tm *tm;
2758  char buf2[32];
2759 
2760  switch(error_number) {
2761  case RTSP_STATUS_OK:
2762  str = "OK";
2763  break;
2764  case RTSP_STATUS_METHOD:
2765  str = "Method Not Allowed";
2766  break;
2767  case RTSP_STATUS_BANDWIDTH:
2768  str = "Not Enough Bandwidth";
2769  break;
2770  case RTSP_STATUS_SESSION:
2771  str = "Session Not Found";
2772  break;
2773  case RTSP_STATUS_STATE:
2774  str = "Method Not Valid in This State";
2775  break;
2776  case RTSP_STATUS_AGGREGATE:
2777  str = "Aggregate operation not allowed";
2778  break;
2780  str = "Only aggregate operation allowed";
2781  break;
2782  case RTSP_STATUS_TRANSPORT:
2783  str = "Unsupported transport";
2784  break;
2785  case RTSP_STATUS_INTERNAL:
2786  str = "Internal Server Error";
2787  break;
2788  case RTSP_STATUS_SERVICE:
2789  str = "Service Unavailable";
2790  break;
2791  case RTSP_STATUS_VERSION:
2792  str = "RTSP Version not supported";
2793  break;
2794  default:
2795  str = "Unknown Error";
2796  break;
2797  }
2798 
2799  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2800  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2801 
2802  /* output GMT time */
2803  ti = time(NULL);
2804  tm = gmtime(&ti);
2805  strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2806  avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2807 }
2808 
2809 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2810 {
2811  rtsp_reply_header(c, error_number);
2812  avio_printf(c->pb, "\r\n");
2813 }
2814 
2816 {
2817  const char *p, *p1, *p2;
2818  char cmd[32];
2819  char url[1024];
2820  char protocol[32];
2821  char line[1024];
2822  int len;
2823  RTSPMessageHeader header1, *header = &header1;
2824 
2825  c->buffer_ptr[0] = '\0';
2826  p = c->buffer;
2827 
2828  get_word(cmd, sizeof(cmd), &p);
2829  get_word(url, sizeof(url), &p);
2830  get_word(protocol, sizeof(protocol), &p);
2831 
2832  av_strlcpy(c->method, cmd, sizeof(c->method));
2833  av_strlcpy(c->url, url, sizeof(c->url));
2834  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2835 
2836  if (avio_open_dyn_buf(&c->pb) < 0) {
2837  /* XXX: cannot do more */
2838  c->pb = NULL; /* safety */
2839  return -1;
2840  }
2841 
2842  /* check version name */
2843  if (strcmp(protocol, "RTSP/1.0") != 0) {
2845  goto the_end;
2846  }
2847 
2848  /* parse each header line */
2849  memset(header, 0, sizeof(*header));
2850  /* skip to next line */
2851  while (*p != '\n' && *p != '\0')
2852  p++;
2853  if (*p == '\n')
2854  p++;
2855  while (*p != '\0') {
2856  p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2857  if (!p1)
2858  break;
2859  p2 = p1;
2860  if (p2 > p && p2[-1] == '\r')
2861  p2--;
2862  /* skip empty line */
2863  if (p2 == p)
2864  break;
2865  len = p2 - p;
2866  if (len > sizeof(line) - 1)
2867  len = sizeof(line) - 1;
2868  memcpy(line, p, len);
2869  line[len] = '\0';
2870  ff_rtsp_parse_line(header, line, NULL, NULL);
2871  p = p1 + 1;
2872  }
2873 
2874  /* handle sequence number */
2875  c->seq = header->seq;
2876 
2877  if (!strcmp(cmd, "DESCRIBE"))
2878  rtsp_cmd_describe(c, url);
2879  else if (!strcmp(cmd, "OPTIONS"))
2880  rtsp_cmd_options(c, url);
2881  else if (!strcmp(cmd, "SETUP"))
2882  rtsp_cmd_setup(c, url, header);
2883  else if (!strcmp(cmd, "PLAY"))
2884  rtsp_cmd_play(c, url, header);
2885  else if (!strcmp(cmd, "PAUSE"))
2886  rtsp_cmd_pause(c, url, header);
2887  else if (!strcmp(cmd, "TEARDOWN"))
2888  rtsp_cmd_teardown(c, url, header);
2889  else
2891 
2892  the_end:
2893  len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2894  c->pb = NULL; /* safety */
2895  if (len < 0) {
2896  /* XXX: cannot do more */
2897  return -1;
2898  }
2899  c->buffer_ptr = c->pb_buffer;
2900  c->buffer_end = c->pb_buffer + len;
2902  return 0;
2903 }
2904 
2905 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2906  struct in_addr my_ip)
2907 {
2908  AVFormatContext *avc;
2909  AVStream *avs = NULL;
2910  int i;
2911 
2912  avc = avformat_alloc_context();
2913  if (avc == NULL) {
2914  return -1;
2915  }
2916  av_dict_set(&avc->metadata, "title",
2917  stream->title[0] ? stream->title : "No Title", 0);
2918  avc->nb_streams = stream->nb_streams;
2919  if (stream->is_multicast) {
2920  snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2921  inet_ntoa(stream->multicast_ip),
2922  stream->multicast_port, stream->multicast_ttl);
2923  } else {
2924  snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2925  }
2926 
2927  if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2928  !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2929  goto sdp_done;
2930  if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2931  !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2932  goto sdp_done;
2933 
2934  for(i = 0; i < stream->nb_streams; i++) {
2935  avc->streams[i] = &avs[i];
2936  avc->streams[i]->codec = stream->streams[i]->codec;
2937  }
2938  *pbuffer = av_mallocz(2048);
2939  av_sdp_create(&avc, 1, *pbuffer, 2048);
2940 
2941  sdp_done:
2942  av_free(avc->streams);
2943  av_dict_free(&avc->metadata);
2944  av_free(avc);
2945  av_free(avs);
2946 
2947  return strlen(*pbuffer);
2948 }
2949 
2950 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2951 {
2952 // rtsp_reply_header(c, RTSP_STATUS_OK);
2953  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2954  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2955  avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2956  avio_printf(c->pb, "\r\n");
2957 }
2958 
2959 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2960 {
2961  FFStream *stream;
2962  char path1[1024];
2963  const char *path;
2964  uint8_t *content;
2965  int content_length, len;
2966  struct sockaddr_in my_addr;
2967 
2968  /* find which url is asked */
2969  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2970  path = path1;
2971  if (*path == '/')
2972  path++;
2973 
2974  for(stream = first_stream; stream != NULL; stream = stream->next) {
2975  if (!stream->is_feed &&
2976  stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2977  !strcmp(path, stream->filename)) {
2978  goto found;
2979  }
2980  }
2981  /* no stream found */
2982  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2983  return;
2984 
2985  found:
2986  /* prepare the media description in sdp format */
2987 
2988  /* get the host IP */
2989  len = sizeof(my_addr);
2990  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2991  content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2992  if (content_length < 0) {
2994  return;
2995  }
2997  avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2998  avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2999  avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3000  avio_printf(c->pb, "\r\n");
3001  avio_write(c->pb, content, content_length);
3002  av_free(content);
3003 }
3004 
3005 static HTTPContext *find_rtp_session(const char *session_id)
3006 {
3007  HTTPContext *c;
3008 
3009  if (session_id[0] == '\0')
3010  return NULL;
3011 
3012  for(c = first_http_ctx; c != NULL; c = c->next) {
3013  if (!strcmp(c->session_id, session_id))
3014  return c;
3015  }
3016  return NULL;
3017 }
3018 
3020 {
3021  RTSPTransportField *th;
3022  int i;
3023 
3024  for(i=0;i<h->nb_transports;i++) {
3025  th = &h->transports[i];
3026  if (th->lower_transport == lower_transport)
3027  return th;
3028  }
3029  return NULL;
3030 }
3031 
3032 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3033  RTSPMessageHeader *h)
3034 {
3035  FFStream *stream;
3036  int stream_index, rtp_port, rtcp_port;
3037  char buf[1024];
3038  char path1[1024];
3039  const char *path;
3040  HTTPContext *rtp_c;
3041  RTSPTransportField *th;
3042  struct sockaddr_in dest_addr;
3043  RTSPActionServerSetup setup;
3044 
3045  /* find which url is asked */
3046  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3047  path = path1;
3048  if (*path == '/')
3049  path++;
3050 
3051  /* now check each stream */
3052  for(stream = first_stream; stream != NULL; stream = stream->next) {
3053  if (!stream->is_feed &&
3054  stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3055  /* accept aggregate filenames only if single stream */
3056  if (!strcmp(path, stream->filename)) {
3057  if (stream->nb_streams != 1) {
3059  return;
3060  }
3061  stream_index = 0;
3062  goto found;
3063  }
3064 
3065  for(stream_index = 0; stream_index < stream->nb_streams;
3066  stream_index++) {
3067  snprintf(buf, sizeof(buf), "%s/streamid=%d",
3068  stream->filename, stream_index);
3069  if (!strcmp(path, buf))
3070  goto found;
3071  }
3072  }
3073  }
3074  /* no stream found */
3075  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3076  return;
3077  found:
3078 
3079  /* generate session id if needed */
3080  if (h->session_id[0] == '\0')
3081  snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3082  av_lfg_get(&random_state), av_lfg_get(&random_state));
3083 
3084  /* find rtp session, and create it if none found */
3085  rtp_c = find_rtp_session(h->session_id);
3086  if (!rtp_c) {
3087  /* always prefer UDP */
3089  if (!th) {
3091  if (!th) {
3093  return;
3094  }
3095  }
3096 
3097  rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3098  th->lower_transport);
3099  if (!rtp_c) {
3101  return;
3102  }
3103 
3104  /* open input stream */
3105  if (open_input_stream(rtp_c, "") < 0) {
3107  return;
3108  }
3109  }
3110 
3111  /* test if stream is OK (test needed because several SETUP needs
3112  to be done for a given file) */
3113  if (rtp_c->stream != stream) {
3115  return;
3116  }
3117 
3118  /* test if stream is already set up */
3119  if (rtp_c->rtp_ctx[stream_index]) {
3121  return;
3122  }
3123 
3124  /* check transport */
3125  th = find_transport(h, rtp_c->rtp_protocol);
3126  if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3127  th->client_port_min <= 0)) {
3129  return;
3130  }
3131 
3132  /* setup default options */
3133  setup.transport_option[0] = '\0';
3134  dest_addr = rtp_c->from_addr;
3135  dest_addr.sin_port = htons(th->client_port_min);
3136 
3137  /* setup stream */
3138  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3140  return;
3141  }
3142 
3143  /* now everything is OK, so we can send the connection parameters */
3145  /* session ID */
3146  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3147 
3148  switch(rtp_c->rtp_protocol) {
3150  rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3151  rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3152  avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3153  "client_port=%d-%d;server_port=%d-%d",
3155  rtp_port, rtcp_port);
3156  break;
3158  avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3159  stream_index * 2, stream_index * 2 + 1);
3160  break;
3161  default:
3162  break;
3163  }
3164  if (setup.transport_option[0] != '\0')
3165  avio_printf(c->pb, ";%s", setup.transport_option);
3166  avio_printf(c->pb, "\r\n");
3167 
3168 
3169  avio_printf(c->pb, "\r\n");
3170 }
3171 
3172 
3173 /* find an rtp connection by using the session ID. Check consistency
3174  with filename */
3175 static HTTPContext *find_rtp_session_with_url(const char *url,
3176  const char *session_id)
3177 {
3178  HTTPContext *rtp_c;
3179  char path1[1024];
3180  const char *path;
3181  char buf[1024];
3182  int s, len;
3183 
3184  rtp_c = find_rtp_session(session_id);
3185  if (!rtp_c)
3186  return NULL;
3187 
3188  /* find which url is asked */
3189  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3190  path = path1;
3191  if (*path == '/')
3192  path++;
3193  if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3194  for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3195  snprintf(buf, sizeof(buf), "%s/streamid=%d",
3196  rtp_c->stream->filename, s);
3197  if(!strncmp(path, buf, sizeof(buf))) {
3198  // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3199  return rtp_c;
3200  }
3201  }
3202  len = strlen(path);
3203  if (len > 0 && path[len - 1] == '/' &&
3204  !strncmp(path, rtp_c->stream->filename, len - 1))
3205  return rtp_c;
3206  return NULL;
3207 }
3208 
3209 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3210 {
3211  HTTPContext *rtp_c;
3212 
3213  rtp_c = find_rtp_session_with_url(url, h->session_id);
3214  if (!rtp_c) {
3216  return;
3217  }
3218 
3219  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3220  rtp_c->state != HTTPSTATE_WAIT_FEED &&
3221  rtp_c->state != HTTPSTATE_READY) {
3223  return;
3224  }
3225 
3226  rtp_c->state = HTTPSTATE_SEND_DATA;
3227 
3228  /* now everything is OK, so we can send the connection parameters */
3230  /* session ID */
3231  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3232  avio_printf(c->pb, "\r\n");
3233 }
3234 
3235 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3236 {
3237  HTTPContext *rtp_c;
3238 
3239  rtp_c = find_rtp_session_with_url(url, h->session_id);
3240  if (!rtp_c) {
3242  return;
3243  }
3244 
3245  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3246  rtp_c->state != HTTPSTATE_WAIT_FEED) {
3248  return;
3249  }
3250 
3251  rtp_c->state = HTTPSTATE_READY;
3252  rtp_c->first_pts = AV_NOPTS_VALUE;
3253  /* now everything is OK, so we can send the connection parameters */
3255  /* session ID */
3256  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3257  avio_printf(c->pb, "\r\n");
3258 }
3259 
3260 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3261 {
3262  HTTPContext *rtp_c;
3263 
3264  rtp_c = find_rtp_session_with_url(url, h->session_id);
3265  if (!rtp_c) {
3267  return;
3268  }
3269 
3270  /* now everything is OK, so we can send the connection parameters */
3272  /* session ID */
3273  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3274  avio_printf(c->pb, "\r\n");
3275 
3276  /* abort the session */
3277  close_connection(rtp_c);
3278 }
3279 
3280 
3281 /********************************************************************/
3282 /* RTP handling */
3283 
3284 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3285  FFStream *stream, const char *session_id,
3286  enum RTSPLowerTransport rtp_protocol)
3287 {
3288  HTTPContext *c = NULL;
3289  const char *proto_str;
3290 
3291  /* XXX: should output a warning page when coming
3292  close to the connection limit */
3294  goto fail;
3295 
3296  /* add a new connection */
3297  c = av_mallocz(sizeof(HTTPContext));
3298  if (!c)
3299  goto fail;
3300 
3301  c->fd = -1;
3302  c->poll_entry = NULL;
3303  c->from_addr = *from_addr;
3305  c->buffer = av_malloc(c->buffer_size);
3306  if (!c->buffer)
3307  goto fail;
3308  nb_connections++;
3309  c->stream = stream;
3310  av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3311  c->state = HTTPSTATE_READY;
3312  c->is_packetized = 1;
3313  c->rtp_protocol = rtp_protocol;
3314 
3315  /* protocol is shown in statistics */
3316  switch(c->rtp_protocol) {
3318  proto_str = "MCAST";
3319  break;
3321  proto_str = "UDP";
3322  break;
3324  proto_str = "TCP";
3325  break;
3326  default:
3327  proto_str = "???";
3328  break;
3329  }
3330  av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3331  av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3332 
3333  current_bandwidth += stream->bandwidth;
3334 
3335  c->next = first_http_ctx;
3336  first_http_ctx = c;
3337  return c;
3338 
3339  fail:
3340  if (c) {
3341  av_free(c->buffer);
3342  av_free(c);
3343  }
3344  return NULL;
3345 }
3346 
3347 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3348  command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3349  used. */
3351  int stream_index, struct sockaddr_in *dest_addr,
3352  HTTPContext *rtsp_c)
3353 {
3354  AVFormatContext *ctx;
3355  AVStream *st;
3356  char *ipaddr;
3357  URLContext *h = NULL;
3358  uint8_t *dummy_buf;
3359  int max_packet_size;
3360 
3361  /* now we can open the relevant output stream */
3362  ctx = avformat_alloc_context();
3363  if (!ctx)
3364  return -1;
3365  ctx->oformat = av_guess_format("rtp", NULL, NULL);
3366 
3367  st = av_mallocz(sizeof(AVStream));
3368  if (!st)
3369  goto fail;
3370  ctx->nb_streams = 1;
3371  ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3372  if (!ctx->streams)
3373  goto fail;
3374  ctx->streams[0] = st;
3375 
3376  if (!c->stream->feed ||
3377  c->stream->feed == c->stream)
3378  memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3379  else
3380  memcpy(st,
3381  c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3382  sizeof(AVStream));
3383  st->priv_data = NULL;
3384 
3385  /* build destination RTP address */
3386  ipaddr = inet_ntoa(dest_addr->sin_addr);
3387 
3388  switch(c->rtp_protocol) {
3391  /* RTP/UDP case */
3392 
3393  /* XXX: also pass as parameter to function ? */
3394  if (c->stream->is_multicast) {
3395  int ttl;
3396  ttl = c->stream->multicast_ttl;
3397  if (!ttl)
3398  ttl = 16;
3399  snprintf(ctx->filename, sizeof(ctx->filename),
3400  "rtp://%s:%d?multicast=1&ttl=%d",
3401  ipaddr, ntohs(dest_addr->sin_port), ttl);
3402  } else {
3403  snprintf(ctx->filename, sizeof(ctx->filename),
3404  "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3405  }
3406 
3407  if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3408  goto fail;
3409  c->rtp_handles[stream_index] = h;
3410  max_packet_size = url_get_max_packet_size(h);
3411  break;
3413  /* RTP/TCP case */
3414  c->rtsp_c = rtsp_c;
3415  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3416  break;
3417  default:
3418  goto fail;
3419  }
3420 
3421  http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3422  ipaddr, ntohs(dest_addr->sin_port),
3423  c->stream->filename, stream_index, c->protocol);
3424 
3425  /* normally, no packets should be output here, but the packet size may be checked */
3426  if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3427  /* XXX: close stream */
3428  goto fail;
3429  }
3430  if (avformat_write_header(ctx, NULL) < 0) {
3431  fail:
3432  if (h)
3433  url_close(h);
3434  av_free(ctx);
3435  return -1;
3436  }
3437  avio_close_dyn_buf(ctx->pb, &dummy_buf);
3438  av_free(dummy_buf);
3439 
3440  c->rtp_ctx[stream_index] = ctx;
3441  return 0;
3442 }
3443 
3444 /********************************************************************/
3445 /* avserver initialization */
3446 
3447 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3448 {
3449  AVStream *fst;
3450 
3451  fst = av_mallocz(sizeof(AVStream));
3452  if (!fst)
3453  return NULL;
3454  if (copy) {
3456  memcpy(fst->codec, codec, sizeof(AVCodecContext));
3457  if (codec->extradata_size) {
3458  fst->codec->extradata = av_malloc(codec->extradata_size);
3459  memcpy(fst->codec->extradata, codec->extradata,
3460  codec->extradata_size);
3461  }
3462  } else {
3463  /* live streams must use the actual feed's codec since it may be
3464  * updated later to carry extradata needed by the streams.
3465  */
3466  fst->codec = codec;
3467  }
3468  fst->priv_data = av_mallocz(sizeof(FeedData));
3469  fst->index = stream->nb_streams;
3470  av_set_pts_info(fst, 33, 1, 90000);
3472  stream->streams[stream->nb_streams++] = fst;
3473  return fst;
3474 }
3475 
3476 /* return the stream number in the feed */
3477 static int add_av_stream(FFStream *feed, AVStream *st)
3478 {
3479  AVStream *fst;
3480  AVCodecContext *av, *av1;
3481  int i;
3482 
3483  av = st->codec;
3484  for(i=0;i<feed->nb_streams;i++) {
3485  st = feed->streams[i];
3486  av1 = st->codec;
3487  if (av1->codec_id == av->codec_id &&
3488  av1->codec_type == av->codec_type &&
3489  av1->bit_rate == av->bit_rate) {
3490 
3491  switch(av->codec_type) {
3492  case AVMEDIA_TYPE_AUDIO:
3493  if (av1->channels == av->channels &&
3494  av1->sample_rate == av->sample_rate)
3495  return i;
3496  break;
3497  case AVMEDIA_TYPE_VIDEO:
3498  if (av1->width == av->width &&
3499  av1->height == av->height &&
3500  av1->time_base.den == av->time_base.den &&
3501  av1->time_base.num == av->time_base.num &&
3502  av1->gop_size == av->gop_size)
3503  return i;
3504  break;
3505  default:
3506  abort();
3507  }
3508  }
3509  }
3510 
3511  fst = add_av_stream1(feed, av, 0);
3512  if (!fst)
3513  return -1;
3514  return feed->nb_streams - 1;
3515 }
3516 
3517 static void remove_stream(FFStream *stream)
3518 {
3519  FFStream **ps;
3520  ps = &first_stream;
3521  while (*ps != NULL) {
3522  if (*ps == stream)
3523  *ps = (*ps)->next;
3524  else
3525  ps = &(*ps)->next;
3526  }
3527 }
3528 
3529 /* specific mpeg4 handling : we extract the raw parameters */
3531 {
3532  int mpeg4_count, i, size;
3533  AVPacket pkt;
3534  AVStream *st;
3535  const uint8_t *p;
3536 
3537  mpeg4_count = 0;
3538  for(i=0;i<infile->nb_streams;i++) {
3539  st = infile->streams[i];
3540  if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3541  st->codec->extradata_size == 0) {
3542  mpeg4_count++;
3543  }
3544  }
3545  if (!mpeg4_count)
3546  return;
3547 
3548  printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3549  while (mpeg4_count > 0) {
3550  if (av_read_packet(infile, &pkt) < 0)
3551  break;
3552  st = infile->streams[pkt.stream_index];
3553  if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3554  st->codec->extradata_size == 0) {
3555  av_freep(&st->codec->extradata);
3556  /* fill extradata with the header */
3557  /* XXX: we make hard suppositions here ! */
3558  p = pkt.data;
3559  while (p < pkt.data + pkt.size - 4) {
3560  /* stop when vop header is found */
3561  if (p[0] == 0x00 && p[1] == 0x00 &&
3562  p[2] == 0x01 && p[3] == 0xb6) {
3563  size = p - pkt.data;
3564  // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3565  st->codec->extradata = av_malloc(size);
3566  st->codec->extradata_size = size;
3567  memcpy(st->codec->extradata, pkt.data, size);
3568  break;
3569  }
3570  p++;
3571  }
3572  mpeg4_count--;
3573  }
3574  av_free_packet(&pkt);
3575  }
3576 }
3577 
3578 /* compute the needed AVStream for each file */
3579 static void build_file_streams(void)
3580 {
3581  FFStream *stream, *stream_next;
3582  int i, ret;
3583 
3584  /* gather all streams */
3585  for(stream = first_stream; stream != NULL; stream = stream_next) {
3586  AVFormatContext *infile = NULL;
3587  stream_next = stream->next;
3588  if (stream->stream_type == STREAM_TYPE_LIVE &&
3589  !stream->feed) {
3590  /* the stream comes from a file */
3591  /* try to open the file */
3592  /* open stream */
3593  if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3594  /* specific case : if transport stream output to RTP,
3595  we use a raw transport stream reader */
3596  av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3597  }
3598 
3599  http_log("Opening file '%s'\n", stream->feed_filename);
3600  if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3601  http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3602  /* remove stream (no need to spend more time on it) */
3603  fail:
3604  remove_stream(stream);
3605  } else {
3606  /* find all the AVStreams inside and reference them in
3607  'stream' */
3608  if (avformat_find_stream_info(infile, NULL) < 0) {
3609  http_log("Could not find codec parameters from '%s'\n",
3610  stream->feed_filename);
3611  avformat_close_input(&infile);
3612  goto fail;
3613  }
3614  extract_mpeg4_header(infile);
3615 
3616  for(i=0;i<infile->nb_streams;i++)
3617  add_av_stream1(stream, infile->streams[i]->codec, 1);
3618 
3619  avformat_close_input(&infile);
3620  }
3621  }
3622  }
3623 }
3624 
3625 /* compute the needed AVStream for each feed */
3626 static void build_feed_streams(void)
3627 {
3628  FFStream *stream, *feed;
3629  int i;
3630 
3631  /* gather all streams */
3632  for(stream = first_stream; stream != NULL; stream = stream->next) {
3633  feed = stream->feed;
3634  if (feed) {
3635  if (stream->is_feed) {
3636  for(i=0;i<stream->nb_streams;i++)
3637  stream->feed_streams[i] = i;
3638  } else {
3639  /* we handle a stream coming from a feed */
3640  for(i=0;i<stream->nb_streams;i++)
3641  stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3642  }
3643  }
3644  }
3645 
3646  /* create feed files if needed */
3647  for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3648  int fd;
3649 
3650  if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3651  /* See if it matches */
3652  AVFormatContext *s = NULL;
3653  int matches = 0;
3654 
3655  if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3656  /* Now see if it matches */
3657  if (s->nb_streams == feed->nb_streams) {
3658  matches = 1;
3659  for(i=0;i<s->nb_streams;i++) {
3660  AVStream *sf, *ss;
3661  sf = feed->streams[i];
3662  ss = s->streams[i];
3663 
3664  if (sf->index != ss->index ||
3665  sf->id != ss->id) {
3666  http_log("Index & Id do not match for stream %d (%s)\n",
3667  i, feed->feed_filename);
3668  matches = 0;
3669  } else {
3670  AVCodecContext *ccf, *ccs;
3671 
3672  ccf = sf->codec;
3673  ccs = ss->codec;
3674 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3675 
3677  http_log("Codecs do not match for stream %d\n", i);
3678  matches = 0;
3679  } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3680  http_log("Codec bitrates do not match for stream %d\n", i);
3681  matches = 0;
3682  } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3683  if (CHECK_CODEC(time_base.den) ||
3684  CHECK_CODEC(time_base.num) ||
3685  CHECK_CODEC(width) ||
3686  CHECK_CODEC(height)) {
3687  http_log("Codec width, height and framerate do not match for stream %d\n", i);
3688  matches = 0;
3689  }
3690  } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3691  if (CHECK_CODEC(sample_rate) ||
3692  CHECK_CODEC(channels) ||
3693  CHECK_CODEC(frame_size)) {
3694  http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3695  matches = 0;
3696  }
3697  } else {
3698  http_log("Unknown codec type\n");
3699  matches = 0;
3700  }
3701  }
3702  if (!matches)
3703  break;
3704  }
3705  } else
3706  http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3707  feed->feed_filename, s->nb_streams, feed->nb_streams);
3708 
3710  } else
3711  http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3712  feed->feed_filename);
3713 
3714  if (!matches) {
3715  if (feed->readonly) {
3716  http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3717  feed->feed_filename);
3718  exit(1);
3719  }
3720  unlink(feed->feed_filename);
3721  }
3722  }
3723  if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3724  AVFormatContext s1 = {0}, *s = &s1;
3725 
3726  if (feed->readonly) {
3727  http_log("Unable to create feed file '%s' as it is marked readonly\n",
3728  feed->feed_filename);
3729  exit(1);
3730  }
3731 
3732  /* only write the header of the ffm file */
3733  if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3734  http_log("Could not open output feed file '%s'\n",
3735  feed->feed_filename);
3736  exit(1);
3737  }
3738  s->oformat = feed->fmt;
3739  s->nb_streams = feed->nb_streams;
3740  s->streams = feed->streams;
3741  if (avformat_write_header(s, NULL) < 0) {
3742  http_log("Container doesn't supports the required parameters\n");
3743  exit(1);
3744  }
3745  /* XXX: need better api */
3746  av_freep(&s->priv_data);
3747  avio_close(s->pb);
3748  }
3749  /* get feed size and write index */
3750  fd = open(feed->feed_filename, O_RDONLY);
3751  if (fd < 0) {
3752  http_log("Could not open output feed file '%s'\n",
3753  feed->feed_filename);
3754  exit(1);
3755  }
3756 
3758  feed->feed_size = lseek(fd, 0, SEEK_END);
3759  /* ensure that we do not wrap before the end of file */
3760  if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3761  feed->feed_max_size = feed->feed_size;
3762 
3763  close(fd);
3764  }
3765 }
3766 
3767 /* compute the bandwidth used by each stream */
3768 static void compute_bandwidth(void)
3769 {
3770  unsigned bandwidth;
3771  int i;
3772  FFStream *stream;
3773 
3774  for(stream = first_stream; stream != NULL; stream = stream->next) {
3775  bandwidth = 0;
3776  for(i=0;i<stream->nb_streams;i++) {
3777  AVStream *st = stream->streams[i];
3778  switch(st->codec->codec_type) {
3779  case AVMEDIA_TYPE_AUDIO:
3780  case AVMEDIA_TYPE_VIDEO:
3781  bandwidth += st->codec->bit_rate;
3782  break;
3783  default:
3784  break;
3785  }
3786  }
3787  stream->bandwidth = (bandwidth + 999) / 1000;
3788  }
3789 }
3790 
3791 /* add a codec and set the default parameters */
3792 static void add_codec(FFStream *stream, AVCodecContext *av)
3793 {
3794  AVStream *st;
3795 
3796  /* compute default parameters */
3797  switch(av->codec_type) {
3798  case AVMEDIA_TYPE_AUDIO:
3799  if (av->bit_rate == 0)
3800  av->bit_rate = 64000;
3801  if (av->sample_rate == 0)
3802  av->sample_rate = 22050;
3803  if (av->channels == 0)
3804  av->channels = 1;
3805  break;
3806  case AVMEDIA_TYPE_VIDEO:
3807  if (av->bit_rate == 0)
3808  av->bit_rate = 64000;
3809  if (av->time_base.num == 0){
3810  av->time_base.den = 5;
3811  av->time_base.num = 1;
3812  }
3813  if (av->width == 0 || av->height == 0) {
3814  av->width = 160;
3815  av->height = 128;
3816  }
3817  /* Bitrate tolerance is less for streaming */
3818  if (av->bit_rate_tolerance == 0)
3819  av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3820  (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3821  if (av->qmin == 0)
3822  av->qmin = 3;
3823  if (av->qmax == 0)
3824  av->qmax = 31;
3825  if (av->max_qdiff == 0)
3826  av->max_qdiff = 3;
3827  av->qcompress = 0.5;
3828  av->qblur = 0.5;
3829 
3830  if (!av->nsse_weight)
3831  av->nsse_weight = 8;
3832 
3834  if (!av->me_method)
3835  av->me_method = ME_EPZS;
3836  av->rc_buffer_aggressivity = 1.0;
3837 
3838  if (!av->rc_eq)
3839  av->rc_eq = "tex^qComp";
3840  if (!av->i_quant_factor)
3841  av->i_quant_factor = -0.8;
3842  if (!av->b_quant_factor)
3843  av->b_quant_factor = 1.25;
3844  if (!av->b_quant_offset)
3845  av->b_quant_offset = 1.25;
3846  if (!av->rc_max_rate)
3847  av->rc_max_rate = av->bit_rate * 2;
3848 
3849  if (av->rc_max_rate && !av->rc_buffer_size) {
3850  av->rc_buffer_size = av->rc_max_rate;
3851  }
3852 
3853 
3854  break;
3855  default:
3856  abort();
3857  }
3858 
3859  st = av_mallocz(sizeof(AVStream));
3860  if (!st)
3861  return;
3863  stream->streams[stream->nb_streams++] = st;
3864  memcpy(st->codec, av, sizeof(AVCodecContext));
3865 }
3866 
3867 static enum CodecID opt_audio_codec(const char *arg)
3868 {
3870 
3871  if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3872  return CODEC_ID_NONE;
3873 
3874  return p->id;
3875 }
3876 
3877 static enum CodecID opt_video_codec(const char *arg)
3878 {
3880 
3881  if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3882  return CODEC_ID_NONE;
3883 
3884  return p->id;
3885 }
3886 
3887 /* simplistic plugin support */
3888 
3889 #if HAVE_DLOPEN
3890 static void load_module(const char *filename)
3891 {
3892  void *dll;
3893  void (*init_func)(void);
3894  dll = dlopen(filename, RTLD_NOW);
3895  if (!dll) {
3896  fprintf(stderr, "Could not load module '%s' - %s\n",
3897  filename, dlerror());
3898  return;
3899  }
3900 
3901  init_func = dlsym(dll, "avserver_module_init");
3902  if (!init_func) {
3903  fprintf(stderr,
3904  "%s: init function 'avserver_module_init()' not found\n",
3905  filename);
3906  dlclose(dll);
3907  }
3908 
3909  init_func();
3910 }
3911 #endif
3912 
3913 static int avserver_opt_default(const char *opt, const char *arg,
3914  AVCodecContext *avctx, int type)
3915 {
3916  int ret = 0;
3917  const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3918  if(o)
3919  ret = av_opt_set(avctx, opt, arg, 0);
3920  return ret;
3921 }
3922 
3923 static int avserver_opt_preset(const char *arg,
3924  AVCodecContext *avctx, int type,
3925  enum CodecID *audio_id, enum CodecID *video_id)
3926 {
3927  FILE *f=NULL;
3928  char filename[1000], tmp[1000], tmp2[1000], line[1000];
3929  int ret = 0;
3930  AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3931 
3932  if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3933  codec ? codec->name : NULL))) {
3934  fprintf(stderr, "File for preset '%s' not found\n", arg);
3935  return 1;
3936  }
3937 
3938  while(!feof(f)){
3939  int e= fscanf(f, "%999[^\n]\n", line) - 1;
3940  if(line[0] == '#' && !e)
3941  continue;
3942  e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3943  if(e){
3944  fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3945  ret = 1;
3946  break;
3947  }
3948  if(!strcmp(tmp, "acodec")){
3949  *audio_id = opt_audio_codec(tmp2);
3950  }else if(!strcmp(tmp, "vcodec")){
3951  *video_id = opt_video_codec(tmp2);
3952  }else if(!strcmp(tmp, "scodec")){
3953  /* opt_subtitle_codec(tmp2); */
3954  }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){
3955  fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3956  ret = 1;
3957  break;
3958  }
3959  }
3960 
3961  fclose(f);
3962 
3963  return ret;
3964 }
3965 
3966 static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename,
3967  const char *mime_type)
3968 {
3969  AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3970 
3971  if (fmt) {
3972  AVOutputFormat *stream_fmt;
3973  char stream_format_name[64];
3974 
3975  snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3976  stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3977 
3978  if (stream_fmt)
3979  fmt = stream_fmt;
3980  }
3981 
3982  return fmt;
3983 }
3984 
3985 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3986 {
3987  va_list vl;
3988  va_start(vl, fmt);
3989  fprintf(stderr, "%s:%d: ", filename, line_num);
3990  vfprintf(stderr, fmt, vl);
3991  va_end(vl);
3992 
3993  (*errors)++;
3994 }
3995 
3996 static int parse_ffconfig(const char *filename)
3997 {
3998  FILE *f;
3999  char line[1024];
4000  char cmd[64];
4001  char arg[1024];
4002  const char *p;
4003  int val, errors, line_num;
4004  FFStream **last_stream, *stream, *redirect;
4005  FFStream **last_feed, *feed, *s;
4006  AVCodecContext audio_enc, video_enc;
4007  enum CodecID audio_id, video_id;
4008 
4009  f = fopen(filename, "r");
4010  if (!f) {
4011  perror(filename);
4012  return -1;
4013  }
4014 
4015  errors = 0;
4016  line_num = 0;
4017  first_stream = NULL;
4018  last_stream = &first_stream;
4019  first_feed = NULL;
4020  last_feed = &first_feed;
4021  stream = NULL;
4022  feed = NULL;
4023  redirect = NULL;
4024  audio_id = CODEC_ID_NONE;
4025  video_id = CODEC_ID_NONE;
4026 
4027 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4028  for(;;) {
4029  if (fgets(line, sizeof(line), f) == NULL)
4030  break;
4031  line_num++;
4032  p = line;
4033  while (isspace(*p))
4034  p++;
4035  if (*p == '\0' || *p == '#')
4036  continue;
4037 
4038  get_arg(cmd, sizeof(cmd), &p);
4039 
4040  if (!av_strcasecmp(cmd, "Port")) {
4041  get_arg(arg, sizeof(arg), &p);
4042  val = atoi(arg);
4043  if (val < 1 || val > 65536) {
4044  ERROR("Invalid_port: %s\n", arg);
4045  }
4046  my_http_addr.sin_port = htons(val);
4047  } else if (!av_strcasecmp(cmd, "BindAddress")) {
4048  get_arg(arg, sizeof(arg), &p);
4049  if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4050  ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4051  }
4052  } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4053  avserver_daemon = 0;
4054  } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4055  get_arg(arg, sizeof(arg), &p);
4056  val = atoi(arg);
4057  if (val < 1 || val > 65536) {
4058  ERROR("%s:%d: Invalid port: %s\n", arg);
4059  }
4060  my_rtsp_addr.sin_port = htons(atoi(arg));
4061  } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4062  get_arg(arg, sizeof(arg), &p);
4063  if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4064  ERROR("Invalid host/IP address: %s\n", arg);
4065  }
4066  } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4067  get_arg(arg, sizeof(arg), &p);
4068  val = atoi(arg);
4069  if (val < 1 || val > 65536) {
4070  ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4071  }
4073  } else if (!av_strcasecmp(cmd, "MaxClients")) {
4074  get_arg(arg, sizeof(arg), &p);
4075  val = atoi(arg);
4076  if (val < 1 || val > nb_max_http_connections) {
4077  ERROR("Invalid MaxClients: %s\n", arg);
4078  } else {
4079  nb_max_connections = val;
4080  }
4081  } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4082  int64_t llval;
4083  get_arg(arg, sizeof(arg), &p);
4084  llval = atoll(arg);
4085  if (llval < 10 || llval > 10000000) {
4086  ERROR("Invalid MaxBandwidth: %s\n", arg);
4087  } else
4088  max_bandwidth = llval;
4089  } else if (!av_strcasecmp(cmd, "CustomLog")) {
4090  if (!avserver_debug)
4091  get_arg(logfilename, sizeof(logfilename), &p);
4092  } else if (!av_strcasecmp(cmd, "<Feed")) {
4093  /*********************************************/
4094  /* Feed related options */
4095  char *q;
4096  if (stream || feed) {
4097  ERROR("Already in a tag\n");
4098  } else {
4099  feed = av_mallocz(sizeof(FFStream));
4100  get_arg(feed->filename, sizeof(feed->filename), &p);
4101  q = strrchr(feed->filename, '>');
4102  if (*q)
4103  *q = '\0';
4104 
4105  for (s = first_feed; s; s = s->next) {
4106  if (!strcmp(feed->filename, s->filename)) {
4107  ERROR("Feed '%s' already registered\n", s->filename);
4108  }
4109  }
4110 
4111  feed->fmt = av_guess_format("ffm", NULL, NULL);
4112  /* defaut feed file */
4113  snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4114  "/tmp/%s.ffm", feed->filename);
4115  feed->feed_max_size = 5 * 1024 * 1024;
4116  feed->is_feed = 1;
4117  feed->feed = feed; /* self feeding :-) */
4118 
4119  /* add in stream list */
4120  *last_stream = feed;
4121  last_stream = &feed->next;
4122  /* add in feed list */
4123  *last_feed = feed;
4124  last_feed = &feed->next_feed;
4125  }
4126  } else if (!av_strcasecmp(cmd, "Launch")) {
4127  if (feed) {
4128  int i;
4129 
4130  feed->child_argv = av_mallocz(64 * sizeof(char *));
4131 
4132  for (i = 0; i < 62; i++) {
4133  get_arg(arg, sizeof(arg), &p);
4134  if (!arg[0])
4135  break;
4136 
4137  feed->child_argv[i] = av_strdup(arg);
4138  }
4139 
4140  feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4141 
4142  snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4143  "http://%s:%d/%s",
4144  (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4145  inet_ntoa(my_http_addr.sin_addr),
4146  ntohs(my_http_addr.sin_port), feed->filename);
4147  }
4148  } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4149  if (feed) {
4150  get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4151  feed->readonly = 1;
4152  } else if (stream) {
4153  get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4154  }
4155  } else if (!av_strcasecmp(cmd, "File")) {
4156  if (feed) {
4157  get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4158  } else if (stream)
4159  get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4160  } else if (!av_strcasecmp(cmd, "Truncate")) {
4161  if (feed) {
4162  get_arg(arg, sizeof(arg), &p);
4163  feed->truncate = strtod(arg, NULL);
4164  }
4165  } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4166  if (feed) {
4167  char *p1;
4168  double fsize;
4169 
4170  get_arg(arg, sizeof(arg), &p);
4171  p1 = arg;
4172  fsize = strtod(p1, &p1);
4173  switch(toupper(*p1)) {
4174  case 'K':
4175  fsize *= 1024;
4176  break;
4177  case 'M':
4178  fsize *= 1024 * 1024;
4179  break;
4180  case 'G':
4181  fsize *= 1024 * 1024 * 1024;
4182  break;
4183  }
4184  feed->feed_max_size = (int64_t)fsize;
4185  if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4186  ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4187  }
4188  }
4189  } else if (!av_strcasecmp(cmd, "</Feed>")) {
4190  if (!feed) {
4191  ERROR("No corresponding <Feed> for </Feed>\n");
4192  }
4193  feed = NULL;
4194  } else if (!av_strcasecmp(cmd, "<Stream")) {
4195  /*********************************************/
4196  /* Stream related options */
4197  char *q;
4198  if (stream || feed) {
4199  ERROR("Already in a tag\n");
4200  } else {
4201  FFStream *s;
4202  stream = av_mallocz(sizeof(FFStream));
4203  get_arg(stream->filename, sizeof(stream->filename), &p);
4204  q = strrchr(stream->filename, '>');
4205  if (*q)
4206  *q = '\0';
4207 
4208  for (s = first_stream; s; s = s->next) {
4209  if (!strcmp(stream->filename, s->filename)) {
4210  ERROR("Stream '%s' already registered\n", s->filename);
4211  }
4212  }
4213 
4214  stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
4215  avcodec_get_context_defaults3(&video_enc, NULL);
4216  avcodec_get_context_defaults3(&audio_enc, NULL);
4217  audio_id = CODEC_ID_NONE;
4218  video_id = CODEC_ID_NONE;
4219  if (stream->fmt) {
4220  audio_id = stream->fmt->audio_codec;
4221  video_id = stream->fmt->video_codec;
4222  }
4223 
4224  *last_stream = stream;
4225  last_stream = &stream->next;
4226  }
4227  } else if (!av_strcasecmp(cmd, "Feed")) {
4228  get_arg(arg, sizeof(arg), &p);
4229  if (stream) {
4230  FFStream *sfeed;
4231 
4232  sfeed = first_feed;
4233  while (sfeed != NULL) {
4234  if (!strcmp(sfeed->filename, arg))
4235  break;
4236  sfeed = sfeed->next_feed;
4237  }
4238  if (!sfeed)
4239  ERROR("feed '%s' not defined\n", arg);
4240  else
4241  stream->feed = sfeed;
4242  }
4243  } else if (!av_strcasecmp(cmd, "Format")) {
4244  get_arg(arg, sizeof(arg), &p);
4245  if (stream) {
4246  if (!strcmp(arg, "status")) {
4247  stream->stream_type = STREAM_TYPE_STATUS;
4248  stream->fmt = NULL;
4249  } else {
4250  stream->stream_type = STREAM_TYPE_LIVE;
4251  /* jpeg cannot be used here, so use single frame jpeg */
4252  if (!strcmp(arg, "jpeg"))
4253  strcpy(arg, "mjpeg");
4254  stream->fmt = avserver_guess_format(arg, NULL, NULL);
4255  if (!stream->fmt) {
4256  ERROR("Unknown Format: %s\n", arg);
4257  }
4258  }
4259  if (stream->fmt) {
4260  audio_id = stream->fmt->audio_codec;
4261  video_id = stream->fmt->video_codec;
4262  }
4263  }
4264  } else if (!av_strcasecmp(cmd, "InputFormat")) {
4265  get_arg(arg, sizeof(arg), &p);
4266  if (stream) {
4267  stream->ifmt = av_find_input_format(arg);
4268  if (!stream->ifmt) {
4269  ERROR("Unknown input format: %s\n", arg);
4270  }
4271  }
4272  } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4273  if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4274  get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4275  } else {
4276  ERROR("FaviconURL only permitted for status streams\n");
4277  }
4278  } else if (!av_strcasecmp(cmd, "Author")) {
4279  if (stream)
4280  get_arg(stream->author, sizeof(stream->author), &p);
4281  } else if (!av_strcasecmp(cmd, "Comment")) {
4282  if (stream)
4283  get_arg(stream->comment, sizeof(stream->comment), &p);
4284  } else if (!av_strcasecmp(cmd, "Copyright")) {
4285  if (stream)
4286  get_arg(stream->copyright, sizeof(stream->copyright), &p);
4287  } else if (!av_strcasecmp(cmd, "Title")) {
4288  if (stream)
4289  get_arg(stream->title, sizeof(stream->title), &p);
4290  } else if (!av_strcasecmp(cmd, "Preroll")) {
4291  get_arg(arg, sizeof(arg), &p);
4292  if (stream)
4293  stream->prebuffer = atof(arg) * 1000;
4294  } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4295  if (stream)
4296  stream->send_on_key = 1;
4297  } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4298  get_arg(arg, sizeof(arg), &p);
4299  audio_id = opt_audio_codec(arg);
4300  if (audio_id == CODEC_ID_NONE) {
4301  ERROR("Unknown AudioCodec: %s\n", arg);
4302  }
4303  } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4304  get_arg(arg, sizeof(arg), &p);
4305  video_id = opt_video_codec(arg);
4306  if (video_id == CODEC_ID_NONE) {
4307  ERROR("Unknown VideoCodec: %s\n", arg);
4308  }
4309  } else if (!av_strcasecmp(cmd, "MaxTime")) {
4310  get_arg(arg, sizeof(arg), &p);
4311  if (stream)
4312  stream->max_time = atof(arg) * 1000;
4313  } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4314  get_arg(arg, sizeof(arg), &p);
4315  if (stream)
4316  audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4317  } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4318  get_arg(arg, sizeof(arg), &p);
4319  if (stream)
4320  audio_enc.channels = atoi(arg);
4321  } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4322  get_arg(arg, sizeof(arg), &p);
4323  if (stream)
4324  audio_enc.sample_rate = atoi(arg);
4325  } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4326  get_arg(arg, sizeof(arg), &p);
4327  if (stream) {
4328 // audio_enc.quality = atof(arg) * 1000;
4329  }
4330  } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4331  if (stream) {
4332  int minrate, maxrate;
4333 
4334  get_arg(arg, sizeof(arg), &p);
4335 
4336  if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4337  video_enc.rc_min_rate = minrate * 1000;
4338  video_enc.rc_max_rate = maxrate * 1000;
4339  } else {
4340  ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4341  }
4342  }
4343  } else if (!av_strcasecmp(cmd, "Debug")) {
4344  if (stream) {
4345  get_arg(arg, sizeof(arg), &p);
4346  video_enc.debug = strtol(arg,0,0);
4347  }
4348  } else if (!av_strcasecmp(cmd, "Strict")) {
4349  if (stream) {
4350  get_arg(arg, sizeof(arg), &p);
4351  video_enc.strict_std_compliance = atoi(arg);
4352  }
4353  } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4354  if (stream) {
4355  get_arg(arg, sizeof(arg), &p);
4356  video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4357  }
4358  } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4359  if (stream) {
4360  get_arg(arg, sizeof(arg), &p);
4361  video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4362  }
4363  } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4364  get_arg(arg, sizeof(arg), &p);
4365  if (stream) {
4366  video_enc.bit_rate = atoi(arg) * 1000;
4367  }
4368  } else if (!av_strcasecmp(cmd, "VideoSize")) {
4369  get_arg(arg, sizeof(arg), &p);
4370  if (stream) {
4371  av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4372  if ((video_enc.width % 16) != 0 ||
4373  (video_enc.height % 16) != 0) {
4374  ERROR("Image size must be a multiple of 16\n");
4375  }
4376  }
4377  } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4378  get_arg(arg, sizeof(arg), &p);
4379  if (stream) {
4381  if (av_parse_video_rate(&frame_rate, arg) < 0) {
4382  ERROR("Incorrect frame rate: %s\n", arg);
4383  } else {
4384  video_enc.time_base.num = frame_rate.den;
4385  video_enc.time_base.den = frame_rate.num;
4386  }
4387  }
4388  } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4389  get_arg(arg, sizeof(arg), &p);
4390  if (stream)
4391  video_enc.gop_size = atoi(arg);
4392  } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4393  if (stream)
4394  video_enc.gop_size = 1;
4395  } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4396  if (stream)
4397  video_enc.mb_decision = FF_MB_DECISION_BITS;
4398  } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4399  if (stream) {
4400  video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4401  video_enc.flags |= CODEC_FLAG_4MV;
4402  }
4403  } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4404  !av_strcasecmp(cmd, "AVOptionAudio")) {
4405  char arg2[1024];
4406  AVCodecContext *avctx;
4407  int type;
4408  get_arg(arg, sizeof(arg), &p);
4409  get_arg(arg2, sizeof(arg2), &p);
4410  if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4411  avctx = &video_enc;
4412  type = AV_OPT_FLAG_VIDEO_PARAM;
4413  } else {
4414  avctx = &audio_enc;
4415  type = AV_OPT_FLAG_AUDIO_PARAM;
4416  }
4417  if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4418  ERROR("AVOption error: %s %s\n", arg, arg2);
4419  }
4420  } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4421  !av_strcasecmp(cmd, "AVPresetAudio")) {
4422  AVCodecContext *avctx;
4423  int type;
4424  get_arg(arg, sizeof(arg), &p);
4425  if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4426  avctx = &video_enc;
4427  video_enc.codec_id = video_id;
4428  type = AV_OPT_FLAG_VIDEO_PARAM;
4429  } else {
4430  avctx = &audio_enc;
4431  audio_enc.codec_id = audio_id;
4432  type = AV_OPT_FLAG_AUDIO_PARAM;
4433  }
4434  if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4435  ERROR("AVPreset error: %s\n", arg);
4436  }
4437  } else if (!av_strcasecmp(cmd, "VideoTag")) {
4438  get_arg(arg, sizeof(arg), &p);
4439  if ((strlen(arg) == 4) && stream)
4440  video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4441  } else if (!av_strcasecmp(cmd, "BitExact")) {
4442  if (stream)
4443  video_enc.flags |= CODEC_FLAG_BITEXACT;
4444  } else if (!av_strcasecmp(cmd, "DctFastint")) {
4445  if (stream)
4446  video_enc.dct_algo = FF_DCT_FASTINT;
4447  } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4448  if (stream)
4449  video_enc.idct_algo = FF_IDCT_SIMPLE;
4450  } else if (!av_strcasecmp(cmd, "Qscale")) {
4451  get_arg(arg, sizeof(arg), &p);
4452  if (stream) {
4453  video_enc.flags |= CODEC_FLAG_QSCALE;
4454  video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4455  }
4456  } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4457  get_arg(arg, sizeof(arg), &p);
4458  if (stream) {
4459  video_enc.max_qdiff = atoi(arg);
4460  if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4461  ERROR("VideoQDiff out of range\n");
4462  }
4463  }
4464  } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4465  get_arg(arg, sizeof(arg), &p);
4466  if (stream) {
4467  video_enc.qmax = atoi(arg);
4468  if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4469  ERROR("VideoQMax out of range\n");
4470  }
4471  }
4472  } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4473  get_arg(arg, sizeof(arg), &p);
4474  if (stream) {
4475  video_enc.qmin = atoi(arg);
4476  if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4477  ERROR("VideoQMin out of range\n");
4478  }
4479  }
4480  } else if (!av_strcasecmp(cmd, "LumaElim")) {
4481  get_arg(arg, sizeof(arg), &p);
4482  if (stream)
4483  video_enc.luma_elim_threshold = atoi(arg);
4484  } else if (!av_strcasecmp(cmd, "ChromaElim")) {
4485  get_arg(arg, sizeof(arg), &p);
4486  if (stream)
4487  video_enc.chroma_elim_threshold = atoi(arg);
4488  } else if (!av_strcasecmp(cmd, "LumiMask")) {
4489  get_arg(arg, sizeof(arg), &p);
4490  if (stream)
4491  video_enc.lumi_masking = atof(arg);
4492  } else if (!av_strcasecmp(cmd, "DarkMask")) {
4493  get_arg(arg, sizeof(arg), &p);
4494  if (stream)
4495  video_enc.dark_masking = atof(arg);
4496  } else if (!av_strcasecmp(cmd, "NoVideo")) {
4497  video_id = CODEC_ID_NONE;
4498  } else if (!av_strcasecmp(cmd, "NoAudio")) {
4499  audio_id = CODEC_ID_NONE;
4500  } else if (!av_strcasecmp(cmd, "ACL")) {
4501  parse_acl_row(stream, feed, NULL, p, filename, line_num);
4502  } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4503  if (stream) {
4504  get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4505  }
4506  } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4507  get_arg(arg, sizeof(arg), &p);
4508  if (stream) {
4509  av_freep(&stream->rtsp_option);
4510  stream->rtsp_option = av_strdup(arg);
4511  }
4512  } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4513  get_arg(arg, sizeof(arg), &p);
4514  if (stream) {
4515  if (resolve_host(&stream->multicast_ip, arg) != 0) {
4516  ERROR("Invalid host/IP address: %s\n", arg);
4517  }
4518  stream->is_multicast = 1;
4519  stream->loop = 1; /* default is looping */
4520  }
4521  } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4522  get_arg(arg, sizeof(arg), &p);
4523  if (stream)
4524  stream->multicast_port = atoi(arg);
4525  } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4526  get_arg(arg, sizeof(arg), &p);
4527  if (stream)
4528  stream->multicast_ttl = atoi(arg);
4529  } else if (!av_strcasecmp(cmd, "NoLoop")) {
4530  if (stream)
4531  stream->loop = 0;
4532  } else if (!av_strcasecmp(cmd, "</Stream>")) {
4533  if (!stream) {
4534  ERROR("No corresponding <Stream> for </Stream>\n");
4535  } else {
4536  if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4537  if (audio_id != CODEC_ID_NONE) {
4538  audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4539  audio_enc.codec_id = audio_id;
4540  add_codec(stream, &audio_enc);
4541  }
4542  if (video_id != CODEC_ID_NONE) {
4543  video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4544  video_enc.codec_id = video_id;
4545  add_codec(stream, &video_enc);
4546  }
4547  }
4548  stream = NULL;
4549  }
4550  } else if (!av_strcasecmp(cmd, "<Redirect")) {
4551  /*********************************************/
4552  char *q;
4553  if (stream || feed || redirect) {
4554  ERROR("Already in a tag\n");
4555  } else {
4556  redirect = av_mallocz(sizeof(FFStream));
4557  *last_stream = redirect;
4558  last_stream = &redirect->next;
4559 
4560  get_arg(redirect->filename, sizeof(redirect->filename), &p);
4561  q = strrchr(redirect->filename, '>');
4562  if (*q)
4563  *q = '\0';
4564  redirect->stream_type = STREAM_TYPE_REDIRECT;
4565  }
4566  } else if (!av_strcasecmp(cmd, "URL")) {
4567  if (redirect)
4568  get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4569  } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4570  if (!redirect) {
4571  ERROR("No corresponding <Redirect> for </Redirect>\n");
4572  } else {
4573  if (!redirect->feed_filename[0]) {
4574  ERROR("No URL found for <Redirect>\n");
4575  }
4576  redirect = NULL;
4577  }
4578  } else if (!av_strcasecmp(cmd, "LoadModule")) {
4579  get_arg(arg, sizeof(arg), &p);
4580 #if HAVE_DLOPEN
4581  load_module(arg);
4582 #else
4583  ERROR("Module support not compiled into this version: '%s'\n", arg);
4584 #endif
4585  } else {
4586  ERROR("Incorrect keyword: '%s'\n", cmd);
4587  }
4588  }
4589 #undef ERROR
4590 
4591  fclose(f);
4592  if (errors)
4593  return -1;
4594  else
4595  return 0;
4596 }
4597 
4598 static void handle_child_exit(int sig)
4599 {
4600  pid_t pid;
4601  int status;
4602 
4603  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4604  FFStream *feed;
4605 
4606  for (feed = first_feed; feed; feed = feed->next) {
4607  if (feed->pid == pid) {
4608  int uptime = time(0) - feed->pid_start;
4609 
4610  feed->pid = 0;
4611  fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4612 
4613  if (uptime < 30)
4614  /* Turn off any more restarts */
4615  feed->child_argv = 0;
4616  }
4617  }
4618  }
4619 
4621 }
4622 
4623 static void opt_debug(void)
4624 {
4625  avserver_debug = 1;
4626  avserver_daemon = 0;
4627  logfilename[0] = '-';
4628 }
4629 
4630 static void show_help(void)
4631 {
4632  printf("usage: avserver [options]\n"
4633  "Hyper fast multi format Audio/Video streaming server\n");
4634  printf("\n");
4635  show_help_options(options, "Main options:\n", 0, 0);
4636 }
4637 
4638 static const OptionDef options[] = {
4639 #include "cmdutils_common_opts.h"
4640  { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4641  { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4642  { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/avserver.conf", "configfile" },
4643  { NULL },
4644 };
4645 
4646 int main(int argc, char **argv)
4647 {
4648  struct sigaction sigact;
4649 
4650  parse_loglevel(argc, argv, options);
4651  av_register_all();
4653 
4654  show_banner();
4655 
4656  my_program_name = argv[0];
4657  my_program_dir = getcwd(0, 0);
4658  avserver_daemon = 1;
4659 
4660  parse_options(NULL, argc, argv, options, NULL);
4661 
4662  unsetenv("http_proxy"); /* Kill the http_proxy */
4663 
4664  av_lfg_init(&random_state, av_get_random_seed());
4665 
4666  memset(&sigact, 0, sizeof(sigact));
4667  sigact.sa_handler = handle_child_exit;
4668  sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4669  sigaction(SIGCHLD, &sigact, 0);
4670 
4671  if (parse_ffconfig(config_filename) < 0) {
4672  fprintf(stderr, "Incorrect config file - exiting.\n");
4673  exit(1);
4674  }
4675 
4676  /* open log file if needed */
4677  if (logfilename[0] != '\0') {
4678  if (!strcmp(logfilename, "-"))
4679  logfile = stdout;
4680  else
4681  logfile = fopen(logfilename, "a");
4683  }
4684 
4686 
4688 
4690 
4691  /* put the process in background and detach it from its TTY */
4692  if (avserver_daemon) {
4693  int pid;
4694 
4695  pid = fork();
4696  if (pid < 0) {
4697  perror("fork");
4698  exit(1);
4699  } else if (pid > 0) {
4700  /* parent : exit */
4701  exit(0);
4702  } else {
4703  /* child */
4704  setsid();
4705  close(0);
4706  open("/dev/null", O_RDWR);
4707  if (strcmp(logfilename, "-") != 0) {
4708  close(1);
4709  dup(0);
4710  }
4711  close(2);
4712  dup(0);
4713  }
4714  }
4715 
4716  /* signal init */
4717  signal(SIGPIPE, SIG_IGN);
4718 
4719  if (avserver_daemon)
4720  chdir("/");
4721 
4722  if (http_server() < 0) {
4723  http_log("Could not start server\n");
4724  exit(1);
4725  }
4726 
4727  return 0;
4728 }