FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ffserver.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * multiple format streaming server based on the FFmpeg libraries
24  */
25 
26 #include "config.h"
27 #if !HAVE_CLOSESOCKET
28 #define closesocket close
29 #endif
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
45 
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
56 
57 #include <stdarg.h>
58 #if HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #include <fcntl.h>
62 #include <sys/ioctl.h>
63 #if HAVE_POLL_H
64 #include <poll.h>
65 #endif
66 #include <errno.h>
67 #include <time.h>
68 #include <sys/wait.h>
69 #include <signal.h>
70 
71 #include "cmdutils.h"
72 #include "ffserver_config.h"
73 
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
76 
77 static const OptionDef options[];
78 
79 enum HTTPState {
83  HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
86  HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
88 
92 };
93 
94 static const char * const http_state[] = {
95  "HTTP_WAIT_REQUEST",
96  "HTTP_SEND_HEADER",
97 
98  "SEND_DATA_HEADER",
99  "SEND_DATA",
100  "SEND_DATA_TRAILER",
101  "RECEIVE_DATA",
102  "WAIT_FEED",
103  "READY",
104 
105  "RTSP_WAIT_REQUEST",
106  "RTSP_SEND_REPLY",
107  "RTSP_SEND_PACKET",
108 };
109 
110 #define IOBUFFER_INIT_SIZE 8192
111 
112 /* timeouts are in ms */
113 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
114 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
115 
116 #define SYNC_TIMEOUT (10 * 1000)
117 
118 typedef struct RTSPActionServerSetup {
119  uint32_t ipaddr;
120  char transport_option[512];
122 
123 typedef struct {
124  int64_t count1, count2;
125  int64_t time1, time2;
126 } DataRateData;
127 
128 /* context associated with one connection */
129 typedef struct HTTPContext {
131  int fd; /* socket file descriptor */
132  struct sockaddr_in from_addr; /* origin */
133  struct pollfd *poll_entry; /* used when polling */
134  int64_t timeout;
137  int post;
139  int chunk_size; /* 0 if it needs to be read */
140  struct HTTPContext *next;
141  int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
142  int64_t data_count;
143  /* feed input */
144  int feed_fd;
145  /* input format handling */
147  int64_t start_time; /* In milliseconds - this wraps fairly often */
148  int64_t first_pts; /* initial pts value */
149  int64_t cur_pts; /* current pts value from the stream in us */
150  int64_t cur_frame_duration; /* duration of the current frame in us */
151  int cur_frame_bytes; /* output frame size, needed to compute
152  the time at which we send each
153  packet */
154  int pts_stream_index; /* stream we choose as clock reference */
155  int64_t cur_clock; /* current clock reference value in us */
156  /* output format handling */
158  /* -1 is invalid stream */
159  int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
160  int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
162  AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
163  int last_packet_sent; /* true if last data packet was sent */
167  char protocol[16];
168  char method[16];
169  char url[128];
172  int is_packetized; /* if true, the stream is packetized */
173  int packet_stream_index; /* current stream for output in state machine */
174 
175  /* RTSP state specific */
176  uint8_t *pb_buffer; /* XXX: use that in all the code */
178  int seq; /* RTSP sequence number */
179 
180  /* RTP state specific */
182  char session_id[32]; /* session id */
184 
185  /* RTP/UDP specific */
187 
188  /* RTP/TCP specific */
191 } HTTPContext;
192 
193 typedef struct FeedData {
194  long long data_count;
195  float avg_frame_size; /* frame size averaged over last frames with exponential mean */
196 } FeedData;
197 
199 
201  .nb_max_http_connections = 2000,
202  .nb_max_connections = 5,
203  .max_bandwidth = 1000,
204  .use_defaults = 1,
205 };
206 
207 static void new_connection(int server_fd, int is_rtsp);
208 static void close_connection(HTTPContext *c);
209 
210 /* HTTP handling */
211 static int handle_connection(HTTPContext *c);
212 static int http_parse_request(HTTPContext *c);
213 static int http_send_data(HTTPContext *c);
214 static void compute_status(HTTPContext *c);
215 static int open_input_stream(HTTPContext *c, const char *info);
217 static int http_receive_data(HTTPContext *c);
218 
219 /* RTSP handling */
220 static int rtsp_parse_request(HTTPContext *c);
221 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
222 static void rtsp_cmd_options(HTTPContext *c, const char *url);
223 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
224  RTSPMessageHeader *h);
225 static void rtsp_cmd_play(HTTPContext *c, const char *url,
226  RTSPMessageHeader *h);
227 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
228  RTSPMessageHeader *h, int pause_only);
229 
230 /* SDP handling */
231 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
232  struct in_addr my_ip);
233 
234 /* RTP handling */
235 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
236  FFServerStream *stream,
237  const char *session_id,
238  enum RTSPLowerTransport rtp_protocol);
239 static int rtp_new_av_stream(HTTPContext *c,
240  int stream_index, struct sockaddr_in *dest_addr,
241  HTTPContext *rtsp_c);
242 
243 static const char *my_program_name;
244 
245 static int no_launch;
247 
248 /* maximum number of simultaneous HTTP connections */
249 static unsigned int nb_connections;
250 
251 static uint64_t current_bandwidth;
252 
253 static int64_t cur_time; // Making this global saves on passing it around everywhere
254 
256 
257 static FILE *logfile = NULL;
258 
259 static void htmlstrip(char *s) {
260  while (s && *s) {
261  s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
262  if (*s)
263  *s++ = '?';
264  }
265 }
266 
267 static int64_t ffm_read_write_index(int fd)
268 {
269  uint8_t buf[8];
270 
271  if (lseek(fd, 8, SEEK_SET) < 0)
272  return AVERROR(EIO);
273  if (read(fd, buf, 8) != 8)
274  return AVERROR(EIO);
275  return AV_RB64(buf);
276 }
277 
278 static int ffm_write_write_index(int fd, int64_t pos)
279 {
280  uint8_t buf[8];
281  int i;
282 
283  for(i=0;i<8;i++)
284  buf[i] = (pos >> (56 - i * 8)) & 0xff;
285  if (lseek(fd, 8, SEEK_SET) < 0)
286  return AVERROR(EIO);
287  if (write(fd, buf, 8) != 8)
288  return AVERROR(EIO);
289  return 8;
290 }
291 
292 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
293  int64_t file_size)
294 {
295  FFMContext *ffm = s->priv_data;
296  ffm->write_index = pos;
297  ffm->file_size = file_size;
298 }
299 
300 static char *ctime1(char *buf2, int buf_size)
301 {
302  time_t ti;
303  char *p;
304 
305  ti = time(NULL);
306  p = ctime(&ti);
307  av_strlcpy(buf2, p, buf_size);
308  p = buf2 + strlen(p) - 1;
309  if (*p == '\n')
310  *p = '\0';
311  return buf2;
312 }
313 
314 static void http_vlog(const char *fmt, va_list vargs)
315 {
316  static int print_prefix = 1;
317 
318  if (!logfile)
319  return;
320 
321  if (print_prefix) {
322  char buf[32];
323  ctime1(buf, sizeof(buf));
324  fprintf(logfile, "%s ", buf);
325  }
326  print_prefix = strstr(fmt, "\n") != NULL;
327  vfprintf(logfile, fmt, vargs);
328  fflush(logfile);
329 }
330 
331 #ifdef __GNUC__
332 __attribute__ ((format (printf, 1, 2)))
333 #endif
334 static void http_log(const char *fmt, ...)
335 {
336  va_list vargs;
337  va_start(vargs, fmt);
338  http_vlog(fmt, vargs);
339  va_end(vargs);
340 }
341 
342 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
343 {
344  static int print_prefix = 1;
345  AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
346  if (level > av_log_get_level())
347  return;
348  if (print_prefix && avc)
349  http_log("[%s @ %p]", avc->item_name(ptr), ptr);
350  print_prefix = strstr(fmt, "\n") != NULL;
351  http_vlog(fmt, vargs);
352 }
353 
355 {
356  if (c->suppress_log)
357  return;
358 
359  http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
360  inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
361  c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
362 }
363 
364 static void update_datarate(DataRateData *drd, int64_t count)
365 {
366  if (!drd->time1 && !drd->count1) {
367  drd->time1 = drd->time2 = cur_time;
368  drd->count1 = drd->count2 = count;
369  } else if (cur_time - drd->time2 > 5000) {
370  drd->time1 = drd->time2;
371  drd->count1 = drd->count2;
372  drd->time2 = cur_time;
373  drd->count2 = count;
374  }
375 }
376 
377 /* In bytes per second */
378 static int compute_datarate(DataRateData *drd, int64_t count)
379 {
380  if (cur_time == drd->time1)
381  return 0;
382 
383  return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
384 }
385 
386 
387 static void start_children(FFServerStream *feed)
388 {
389  char pathname[1024];
390  char *slash;
391  int i;
392 
393  if (no_launch)
394  return;
395 
396  /* replace "ffserver" with "ffmpeg" in the path of current
397  * program. Ignore user provided path */
398  av_strlcpy(pathname, my_program_name, sizeof(pathname));
399 
400  slash = strrchr(pathname, '/');
401  if (!slash)
402  slash = pathname;
403  else
404  slash++;
405  strcpy(slash, "ffmpeg");
406 
407  for (; feed; feed = feed->next) {
408 
409  if (!feed->child_argv || feed->pid)
410  continue;
411 
412  feed->pid_start = time(0);
413 
414  feed->pid = fork();
415  if (feed->pid < 0) {
416  http_log("Unable to create children\n");
417  exit(1);
418  }
419 
420  if (feed->pid)
421  continue;
422 
423  /* In child */
424 
425  http_log("Launch command line: ");
426  http_log("%s ", pathname);
427 
428  for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
429  http_log("%s ", feed->child_argv[i]);
430  http_log("\n");
431 
432  for (i = 3; i < 256; i++)
433  close(i);
434 
435  if (!config.debug) {
436  if (!freopen("/dev/null", "r", stdin))
437  http_log("failed to redirect STDIN to /dev/null\n;");
438  if (!freopen("/dev/null", "w", stdout))
439  http_log("failed to redirect STDOUT to /dev/null\n;");
440  if (!freopen("/dev/null", "w", stderr))
441  http_log("failed to redirect STDERR to /dev/null\n;");
442  }
443 
444  signal(SIGPIPE, SIG_DFL);
445  execvp(pathname, feed->child_argv);
446  _exit(1);
447  }
448 }
449 
450 /* open a listening socket */
451 static int socket_open_listen(struct sockaddr_in *my_addr)
452 {
453  int server_fd, tmp;
454 
455  server_fd = socket(AF_INET,SOCK_STREAM,0);
456  if (server_fd < 0) {
457  perror ("socket");
458  return -1;
459  }
460 
461  tmp = 1;
462  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
463  av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
464 
465  my_addr->sin_family = AF_INET;
466  if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
467  char bindmsg[32];
468  snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
469  perror (bindmsg);
470  closesocket(server_fd);
471  return -1;
472  }
473 
474  if (listen (server_fd, 5) < 0) {
475  perror ("listen");
476  closesocket(server_fd);
477  return -1;
478  }
479 
480  if (ff_socket_nonblock(server_fd, 1) < 0)
481  av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
482 
483  return server_fd;
484 }
485 
486 /* start all multicast streams */
487 static void start_multicast(void)
488 {
489  FFServerStream *stream;
490  char session_id[32];
491  HTTPContext *rtp_c;
492  struct sockaddr_in dest_addr = {0};
493  int default_port, stream_index;
494  unsigned int random0, random1;
495 
496  default_port = 6000;
497  for(stream = config.first_stream; stream; stream = stream->next) {
498 
499  if (!stream->is_multicast)
500  continue;
501 
502  random0 = av_lfg_get(&random_state);
503  random1 = av_lfg_get(&random_state);
504 
505  /* open the RTP connection */
506  snprintf(session_id, sizeof(session_id), "%08x%08x",
507  random0, random1);
508 
509  /* choose a port if none given */
510  if (stream->multicast_port == 0) {
511  stream->multicast_port = default_port;
512  default_port += 100;
513  }
514 
515  dest_addr.sin_family = AF_INET;
516  dest_addr.sin_addr = stream->multicast_ip;
517  dest_addr.sin_port = htons(stream->multicast_port);
518 
519  rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
521  if (!rtp_c)
522  continue;
523 
524  if (open_input_stream(rtp_c, "") < 0) {
525  http_log("Could not open input stream for stream '%s'\n",
526  stream->filename);
527  continue;
528  }
529 
530  /* open each RTP stream */
531  for(stream_index = 0; stream_index < stream->nb_streams;
532  stream_index++) {
533  dest_addr.sin_port = htons(stream->multicast_port +
534  2 * stream_index);
535  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
536  continue;
537 
538  http_log("Could not open output stream '%s/streamid=%d'\n",
539  stream->filename, stream_index);
540  exit(1);
541  }
542 
543  rtp_c->state = HTTPSTATE_SEND_DATA;
544  }
545 }
546 
547 /* main loop of the HTTP server */
548 static int http_server(void)
549 {
550  int server_fd = 0, rtsp_server_fd = 0;
551  int ret, delay;
552  struct pollfd *poll_table, *poll_entry;
553  HTTPContext *c, *c_next;
554 
555  poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
556  sizeof(*poll_table));
557  if(!poll_table) {
558  http_log("Impossible to allocate a poll table handling %d "
559  "connections.\n", config.nb_max_http_connections);
560  return -1;
561  }
562 
563  if (config.http_addr.sin_port) {
564  server_fd = socket_open_listen(&config.http_addr);
565  if (server_fd < 0) {
566  av_free(poll_table);
567  return -1;
568  }
569  }
570 
571  if (config.rtsp_addr.sin_port) {
572  rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
573  if (rtsp_server_fd < 0) {
574  av_free(poll_table);
575  closesocket(server_fd);
576  return -1;
577  }
578  }
579 
580  if (!rtsp_server_fd && !server_fd) {
581  http_log("HTTP and RTSP disabled.\n");
582  av_free(poll_table);
583  return -1;
584  }
585 
586  http_log("FFserver started.\n");
587 
588  start_children(config.first_feed);
589 
590  start_multicast();
591 
592  for(;;) {
593  poll_entry = poll_table;
594  if (server_fd) {
595  poll_entry->fd = server_fd;
596  poll_entry->events = POLLIN;
597  poll_entry++;
598  }
599  if (rtsp_server_fd) {
600  poll_entry->fd = rtsp_server_fd;
601  poll_entry->events = POLLIN;
602  poll_entry++;
603  }
604 
605  /* wait for events on each HTTP handle */
606  c = first_http_ctx;
607  delay = 1000;
608  while (c) {
609  int fd;
610  fd = c->fd;
611  switch(c->state) {
615  c->poll_entry = poll_entry;
616  poll_entry->fd = fd;
617  poll_entry->events = POLLOUT;
618  poll_entry++;
619  break;
621  case HTTPSTATE_SEND_DATA:
623  if (!c->is_packetized) {
624  /* for TCP, we output as much as we can
625  * (may need to put a limit) */
626  c->poll_entry = poll_entry;
627  poll_entry->fd = fd;
628  poll_entry->events = POLLOUT;
629  poll_entry++;
630  } else {
631  /* when ffserver is doing the timing, we work by
632  looking at which packet needs to be sent every
633  10 ms */
634  /* one tick wait XXX: 10 ms assumed */
635  if (delay > 10)
636  delay = 10;
637  }
638  break;
641  case HTTPSTATE_WAIT_FEED:
643  /* need to catch errors */
644  c->poll_entry = poll_entry;
645  poll_entry->fd = fd;
646  poll_entry->events = POLLIN;/* Maybe this will work */
647  poll_entry++;
648  break;
649  default:
650  c->poll_entry = NULL;
651  break;
652  }
653  c = c->next;
654  }
655 
656  /* wait for an event on one connection. We poll at least every
657  second to handle timeouts */
658  do {
659  ret = poll(poll_table, poll_entry - poll_table, delay);
660  if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
661  ff_neterrno() != AVERROR(EINTR)) {
662  av_free(poll_table);
663  return -1;
664  }
665  } while (ret < 0);
666 
667  cur_time = av_gettime() / 1000;
668 
671  start_children(config.first_feed);
672  }
673 
674  /* now handle the events */
675  for(c = first_http_ctx; c; c = c_next) {
676  c_next = c->next;
677  if (handle_connection(c) < 0) {
678  log_connection(c);
679  /* close and free the connection */
680  close_connection(c);
681  }
682  }
683 
684  poll_entry = poll_table;
685  if (server_fd) {
686  /* new HTTP connection request ? */
687  if (poll_entry->revents & POLLIN)
688  new_connection(server_fd, 0);
689  poll_entry++;
690  }
691  if (rtsp_server_fd) {
692  /* new RTSP connection request ? */
693  if (poll_entry->revents & POLLIN)
694  new_connection(rtsp_server_fd, 1);
695  }
696  }
697 }
698 
699 /* start waiting for a new HTTP/RTSP request */
700 static void start_wait_request(HTTPContext *c, int is_rtsp)
701 {
702  c->buffer_ptr = c->buffer;
703  c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
704 
705  if (is_rtsp) {
708  } else {
711  }
712 }
713 
714 static void http_send_too_busy_reply(int fd)
715 {
716  char buffer[400];
717  int len = snprintf(buffer, sizeof(buffer),
718  "HTTP/1.0 503 Server too busy\r\n"
719  "Content-type: text/html\r\n"
720  "\r\n"
721  "<html><head><title>Too busy</title></head><body>\r\n"
722  "<p>The server is too busy to serve your request at this time.</p>\r\n"
723  "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
724  "</body></html>\r\n",
726  av_assert0(len < sizeof(buffer));
727  if (send(fd, buffer, len, 0) < len)
728  av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
729 }
730 
731 
732 static void new_connection(int server_fd, int is_rtsp)
733 {
734  struct sockaddr_in from_addr;
735  socklen_t len;
736  int fd;
737  HTTPContext *c = NULL;
738 
739  len = sizeof(from_addr);
740  fd = accept(server_fd, (struct sockaddr *)&from_addr,
741  &len);
742  if (fd < 0) {
743  http_log("error during accept %s\n", strerror(errno));
744  return;
745  }
746  if (ff_socket_nonblock(fd, 1) < 0)
747  av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
748 
749  if (nb_connections >= config.nb_max_connections) {
751  goto fail;
752  }
753 
754  /* add a new connection */
755  c = av_mallocz(sizeof(HTTPContext));
756  if (!c)
757  goto fail;
758 
759  c->fd = fd;
760  c->poll_entry = NULL;
761  c->from_addr = from_addr;
763  c->buffer = av_malloc(c->buffer_size);
764  if (!c->buffer)
765  goto fail;
766 
767  c->next = first_http_ctx;
768  first_http_ctx = c;
769  nb_connections++;
770 
771  start_wait_request(c, is_rtsp);
772 
773  return;
774 
775  fail:
776  if (c) {
777  av_freep(&c->buffer);
778  av_free(c);
779  }
780  closesocket(fd);
781 }
782 
784 {
785  HTTPContext **cp, *c1;
786  int i, nb_streams;
787  AVFormatContext *ctx;
788  URLContext *h;
789  AVStream *st;
790 
791  /* remove connection from list */
792  cp = &first_http_ctx;
793  while (*cp) {
794  c1 = *cp;
795  if (c1 == c)
796  *cp = c->next;
797  else
798  cp = &c1->next;
799  }
800 
801  /* remove references, if any (XXX: do it faster) */
802  for(c1 = first_http_ctx; c1; c1 = c1->next) {
803  if (c1->rtsp_c == c)
804  c1->rtsp_c = NULL;
805  }
806 
807  /* remove connection associated resources */
808  if (c->fd >= 0)
809  closesocket(c->fd);
810  if (c->fmt_in) {
811  /* close each frame parser */
812  for(i=0;i<c->fmt_in->nb_streams;i++) {
813  st = c->fmt_in->streams[i];
814  if (st->codec->codec)
815  avcodec_close(st->codec);
816  }
818  }
819 
820  /* free RTP output streams if any */
821  nb_streams = 0;
822  if (c->stream)
823  nb_streams = c->stream->nb_streams;
824 
825  for(i=0;i<nb_streams;i++) {
826  ctx = c->rtp_ctx[i];
827  if (ctx) {
828  av_write_trailer(ctx);
829  av_dict_free(&ctx->metadata);
830  av_freep(&ctx->streams[0]);
831  av_freep(&ctx);
832  }
833  h = c->rtp_handles[i];
834  if (h)
835  ffurl_close(h);
836  }
837 
838  ctx = &c->fmt_ctx;
839 
841  /* prepare header */
842  if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
843  av_write_trailer(ctx);
844  av_freep(&c->pb_buffer);
845  avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
846  }
847  }
848 
849  for(i=0; i<ctx->nb_streams; i++)
850  av_freep(&ctx->streams[i]);
851  av_freep(&ctx->streams);
852  av_freep(&ctx->priv_data);
853 
854  if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
856 
857  /* signal that there is no feed if we are the feeder socket */
858  if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
859  c->stream->feed_opened = 0;
860  close(c->feed_fd);
861  }
862 
863  av_freep(&c->pb_buffer);
864  av_freep(&c->packet_buffer);
865  av_freep(&c->buffer);
866  av_free(c);
867  nb_connections--;
868 }
869 
871 {
872  int len, ret;
873  uint8_t *ptr;
874 
875  switch(c->state) {
878  /* timeout ? */
879  if ((c->timeout - cur_time) < 0)
880  return -1;
881  if (c->poll_entry->revents & (POLLERR | POLLHUP))
882  return -1;
883 
884  /* no need to read if no events */
885  if (!(c->poll_entry->revents & POLLIN))
886  return 0;
887  /* read the data */
888  read_loop:
889  if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
890  return -1;
891 
892  if (len < 0) {
893  if (ff_neterrno() != AVERROR(EAGAIN) &&
894  ff_neterrno() != AVERROR(EINTR))
895  return -1;
896  break;
897  }
898  /* search for end of request. */
899  c->buffer_ptr += len;
900  ptr = c->buffer_ptr;
901  if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
902  (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
903  /* request found : parse it and reply */
904  if (c->state == HTTPSTATE_WAIT_REQUEST) {
905  ret = http_parse_request(c);
906  } else {
907  ret = rtsp_parse_request(c);
908  }
909  if (ret < 0)
910  return -1;
911  } else if (ptr >= c->buffer_end) {
912  /* request too long: cannot do anything */
913  return -1;
914  } else goto read_loop;
915 
916  break;
917 
919  if (c->poll_entry->revents & (POLLERR | POLLHUP))
920  return -1;
921 
922  /* no need to write if no events */
923  if (!(c->poll_entry->revents & POLLOUT))
924  return 0;
925  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
926  if (len < 0) {
927  if (ff_neterrno() != AVERROR(EAGAIN) &&
928  ff_neterrno() != AVERROR(EINTR)) {
929  goto close_connection;
930  }
931  break;
932  }
933  c->buffer_ptr += len;
934  if (c->stream)
935  c->stream->bytes_served += len;
936  c->data_count += len;
937  if (c->buffer_ptr >= c->buffer_end) {
938  av_freep(&c->pb_buffer);
939  /* if error, exit */
940  if (c->http_error)
941  return -1;
942  /* all the buffer was sent : synchronize to the incoming
943  * stream */
945  c->buffer_ptr = c->buffer_end = c->buffer;
946  }
947  break;
948 
949  case HTTPSTATE_SEND_DATA:
952  /* for packetized output, we consider we can always write (the
953  input streams set the speed). It may be better to verify
954  that we do not rely too much on the kernel queues */
955  if (!c->is_packetized) {
956  if (c->poll_entry->revents & (POLLERR | POLLHUP))
957  return -1;
958 
959  /* no need to read if no events */
960  if (!(c->poll_entry->revents & POLLOUT))
961  return 0;
962  }
963  if (http_send_data(c) < 0)
964  return -1;
965  /* close connection if trailer sent */
967  return -1;
968  break;
970  /* no need to read if no events */
971  if (c->poll_entry->revents & (POLLERR | POLLHUP))
972  return -1;
973  if (!(c->poll_entry->revents & POLLIN))
974  return 0;
975  if (http_receive_data(c) < 0)
976  return -1;
977  break;
978  case HTTPSTATE_WAIT_FEED:
979  /* no need to read if no events */
980  if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
981  return -1;
982 
983  /* nothing to do, we'll be waken up by incoming feed packets */
984  break;
985 
987  if (c->poll_entry->revents & (POLLERR | POLLHUP))
988  goto close_connection;
989  /* no need to write if no events */
990  if (!(c->poll_entry->revents & POLLOUT))
991  return 0;
992  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
993  if (len < 0) {
994  if (ff_neterrno() != AVERROR(EAGAIN) &&
995  ff_neterrno() != AVERROR(EINTR)) {
996  goto close_connection;
997  }
998  break;
999  }
1000  c->buffer_ptr += len;
1001  c->data_count += len;
1002  if (c->buffer_ptr >= c->buffer_end) {
1003  /* all the buffer was sent : wait for a new request */
1004  av_freep(&c->pb_buffer);
1005  start_wait_request(c, 1);
1006  }
1007  break;
1008  case RTSPSTATE_SEND_PACKET:
1009  if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1010  av_freep(&c->packet_buffer);
1011  return -1;
1012  }
1013  /* no need to write if no events */
1014  if (!(c->poll_entry->revents & POLLOUT))
1015  return 0;
1016  len = send(c->fd, c->packet_buffer_ptr,
1018  if (len < 0) {
1019  if (ff_neterrno() != AVERROR(EAGAIN) &&
1020  ff_neterrno() != AVERROR(EINTR)) {
1021  /* error : close connection */
1022  av_freep(&c->packet_buffer);
1023  return -1;
1024  }
1025  break;
1026  }
1027  c->packet_buffer_ptr += len;
1028  if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1029  /* all the buffer was sent : wait for a new request */
1030  av_freep(&c->packet_buffer);
1032  }
1033  break;
1034  case HTTPSTATE_READY:
1035  /* nothing to do */
1036  break;
1037  default:
1038  return -1;
1039  }
1040  return 0;
1041 
1043  av_freep(&c->pb_buffer);
1044  return -1;
1045 }
1046 
1047 static int extract_rates(char *rates, int ratelen, const char *request)
1048 {
1049  const char *p;
1050 
1051  for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1052  if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1053  const char *q = p + 7;
1054 
1055  while (*q && *q != '\n' && av_isspace(*q))
1056  q++;
1057 
1058  if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1059  int stream_no;
1060  int rate_no;
1061 
1062  q += 20;
1063 
1064  memset(rates, 0xff, ratelen);
1065 
1066  while (1) {
1067  while (*q && *q != '\n' && *q != ':')
1068  q++;
1069 
1070  if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1071  break;
1072 
1073  stream_no--;
1074  if (stream_no < ratelen && stream_no >= 0)
1075  rates[stream_no] = rate_no;
1076 
1077  while (*q && *q != '\n' && !av_isspace(*q))
1078  q++;
1079  }
1080 
1081  return 1;
1082  }
1083  }
1084  p = strchr(p, '\n');
1085  if (!p)
1086  break;
1087 
1088  p++;
1089  }
1090 
1091  return 0;
1092 }
1093 
1094 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec, int bit_rate)
1095 {
1096  int i;
1097  int best_bitrate = 100000000;
1098  int best = -1;
1099 
1100  for (i = 0; i < feed->nb_streams; i++) {
1101  AVCodecContext *feed_codec = feed->streams[i]->codec;
1102 
1103  if (feed_codec->codec_id != codec->codec_id ||
1104  feed_codec->sample_rate != codec->sample_rate ||
1105  feed_codec->width != codec->width ||
1106  feed_codec->height != codec->height)
1107  continue;
1108 
1109  /* Potential stream */
1110 
1111  /* We want the fastest stream less than bit_rate, or the slowest
1112  * faster than bit_rate
1113  */
1114 
1115  if (feed_codec->bit_rate <= bit_rate) {
1116  if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1117  best_bitrate = feed_codec->bit_rate;
1118  best = i;
1119  }
1120  continue;
1121  }
1122  if (feed_codec->bit_rate < best_bitrate) {
1123  best_bitrate = feed_codec->bit_rate;
1124  best = i;
1125  }
1126  }
1127  return best;
1128 }
1129 
1131 {
1132  int i;
1133  FFServerStream *req = c->stream;
1134  int action_required = 0;
1135 
1136  /* Not much we can do for a feed */
1137  if (!req->feed)
1138  return 0;
1139 
1140  for (i = 0; i < req->nb_streams; i++) {
1141  AVCodecContext *codec = req->streams[i]->codec;
1142 
1143  switch(rates[i]) {
1144  case 0:
1145  c->switch_feed_streams[i] = req->feed_streams[i];
1146  break;
1147  case 1:
1148  c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1149  break;
1150  case 2:
1151  /* Wants off or slow */
1152  c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1153 #ifdef WANTS_OFF
1154  /* This doesn't work well when it turns off the only stream! */
1155  c->switch_feed_streams[i] = -2;
1156  c->feed_streams[i] = -2;
1157 #endif
1158  break;
1159  }
1160 
1161  if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1162  action_required = 1;
1163  }
1164 
1165  return action_required;
1166 }
1167 
1168 static void get_word(char *buf, int buf_size, const char **pp)
1169 {
1170  const char *p;
1171  char *q;
1172 
1173  p = *pp;
1174  p += strspn(p, SPACE_CHARS);
1175  q = buf;
1176  while (!av_isspace(*p) && *p != '\0') {
1177  if ((q - buf) < buf_size - 1)
1178  *q++ = *p;
1179  p++;
1180  }
1181  if (buf_size > 0)
1182  *q = '\0';
1183  *pp = p;
1184 }
1185 
1187 {
1188  FILE* f;
1189  char line[1024];
1190  char cmd[1024];
1191  FFServerIPAddressACL *acl = NULL;
1192  int line_num = 0;
1193  const char *p;
1194 
1195  f = fopen(stream->dynamic_acl, "r");
1196  if (!f) {
1197  perror(stream->dynamic_acl);
1198  return NULL;
1199  }
1200 
1201  acl = av_mallocz(sizeof(FFServerIPAddressACL));
1202 
1203  /* Build ACL */
1204  while (fgets(line, sizeof(line), f)) {
1205  line_num++;
1206  p = line;
1207  while (av_isspace(*p))
1208  p++;
1209  if (*p == '\0' || *p == '#')
1210  continue;
1211  ffserver_get_arg(cmd, sizeof(cmd), &p);
1212 
1213  if (!av_strcasecmp(cmd, "ACL"))
1214  ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1215  }
1216  fclose(f);
1217  return acl;
1218 }
1219 
1220 
1222 {
1223  FFServerIPAddressACL *pacl, *pacl2;
1224 
1225  pacl = in_acl;
1226  while(pacl) {
1227  pacl2 = pacl;
1228  pacl = pacl->next;
1229  av_freep(pacl2);
1230  }
1231 }
1232 
1234 {
1235  enum FFServerIPAddressAction last_action = IP_DENY;
1236  FFServerIPAddressACL *acl;
1237  struct in_addr *src = &c->from_addr.sin_addr;
1238  unsigned long src_addr = src->s_addr;
1239 
1240  for (acl = in_acl; acl; acl = acl->next) {
1241  if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1242  return (acl->action == IP_ALLOW) ? 1 : 0;
1243  last_action = acl->action;
1244  }
1245 
1246  /* Nothing matched, so return not the last action */
1247  return (last_action == IP_DENY) ? 1 : 0;
1248 }
1249 
1251 {
1252  int ret = 0;
1253  FFServerIPAddressACL *acl;
1254 
1255  /* if stream->acl is null validate_acl_list will return 1 */
1256  ret = validate_acl_list(stream->acl, c);
1257 
1258  if (stream->dynamic_acl[0]) {
1259  acl = parse_dynamic_acl(stream, c);
1260 
1261  ret = validate_acl_list(acl, c);
1262 
1263  free_acl_list(acl);
1264  }
1265 
1266  return ret;
1267 }
1268 
1269 /* compute the real filename of a file by matching it without its
1270  extensions to all the stream's filenames */
1271 static void compute_real_filename(char *filename, int max_size)
1272 {
1273  char file1[1024];
1274  char file2[1024];
1275  char *p;
1276  FFServerStream *stream;
1277 
1278  /* compute filename by matching without the file extensions */
1279  av_strlcpy(file1, filename, sizeof(file1));
1280  p = strrchr(file1, '.');
1281  if (p)
1282  *p = '\0';
1283  for(stream = config.first_stream; stream; stream = stream->next) {
1284  av_strlcpy(file2, stream->filename, sizeof(file2));
1285  p = strrchr(file2, '.');
1286  if (p)
1287  *p = '\0';
1288  if (!strcmp(file1, file2)) {
1289  av_strlcpy(filename, stream->filename, max_size);
1290  break;
1291  }
1292  }
1293 }
1294 
1302 };
1303 
1304 /* parse HTTP request and prepare header */
1306 {
1307  const char *p;
1308  char *p1;
1309  enum RedirType redir_type;
1310  char cmd[32];
1311  char info[1024], filename[1024];
1312  char url[1024], *q;
1313  char protocol[32];
1314  char msg[1024];
1315  const char *mime_type;
1316  FFServerStream *stream;
1317  int i;
1318  char ratebuf[32];
1319  const char *useragent = 0;
1320 
1321  p = c->buffer;
1322  get_word(cmd, sizeof(cmd), &p);
1323  av_strlcpy(c->method, cmd, sizeof(c->method));
1324 
1325  if (!strcmp(cmd, "GET"))
1326  c->post = 0;
1327  else if (!strcmp(cmd, "POST"))
1328  c->post = 1;
1329  else
1330  return -1;
1331 
1332  get_word(url, sizeof(url), &p);
1333  av_strlcpy(c->url, url, sizeof(c->url));
1334 
1335  get_word(protocol, sizeof(protocol), (const char **)&p);
1336  if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1337  return -1;
1338 
1339  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1340 
1341  if (config.debug)
1342  http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1343 
1344  /* find the filename and the optional info string in the request */
1345  p1 = strchr(url, '?');
1346  if (p1) {
1347  av_strlcpy(info, p1, sizeof(info));
1348  *p1 = '\0';
1349  } else
1350  info[0] = '\0';
1351 
1352  av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1353 
1354  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1355  if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1356  useragent = p + 11;
1357  if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1358  useragent++;
1359  break;
1360  }
1361  p = strchr(p, '\n');
1362  if (!p)
1363  break;
1364 
1365  p++;
1366  }
1367 
1368  redir_type = REDIR_NONE;
1369  if (av_match_ext(filename, "asx")) {
1370  redir_type = REDIR_ASX;
1371  filename[strlen(filename)-1] = 'f';
1372  } else if (av_match_ext(filename, "asf") &&
1373  (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1374  /* if this isn't WMP or lookalike, return the redirector file */
1375  redir_type = REDIR_ASF;
1376  } else if (av_match_ext(filename, "rpm,ram")) {
1377  redir_type = REDIR_RAM;
1378  strcpy(filename + strlen(filename)-2, "m");
1379  } else if (av_match_ext(filename, "rtsp")) {
1380  redir_type = REDIR_RTSP;
1381  compute_real_filename(filename, sizeof(filename) - 1);
1382  } else if (av_match_ext(filename, "sdp")) {
1383  redir_type = REDIR_SDP;
1384  compute_real_filename(filename, sizeof(filename) - 1);
1385  }
1386 
1387  // "redirect" / request to index.html
1388  if (!strlen(filename))
1389  av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1390 
1391  stream = config.first_stream;
1392  while (stream) {
1393  if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1394  break;
1395  stream = stream->next;
1396  }
1397  if (!stream) {
1398  snprintf(msg, sizeof(msg), "File '%s' not found", url);
1399  http_log("File '%s' not found\n", url);
1400  goto send_error;
1401  }
1402 
1403  c->stream = stream;
1404  memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1405  memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1406 
1407  if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1408  c->http_error = 301;
1409  q = c->buffer;
1410  snprintf(q, c->buffer_size,
1411  "HTTP/1.0 301 Moved\r\n"
1412  "Location: %s\r\n"
1413  "Content-type: text/html\r\n"
1414  "\r\n"
1415  "<html><head><title>Moved</title></head><body>\r\n"
1416  "You should be <a href=\"%s\">redirected</a>.\r\n"
1417  "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1418  q += strlen(q);
1419  /* prepare output buffer */
1420  c->buffer_ptr = c->buffer;
1421  c->buffer_end = q;
1423  return 0;
1424  }
1425 
1426  /* If this is WMP, get the rate information */
1427  if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1428  if (modify_current_stream(c, ratebuf)) {
1429  for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1430  if (c->switch_feed_streams[i] >= 0)
1431  c->switch_feed_streams[i] = -1;
1432  }
1433  }
1434  }
1435 
1436  if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1437  current_bandwidth += stream->bandwidth;
1438 
1439  /* If already streaming this feed, do not let start another feeder. */
1440  if (stream->feed_opened) {
1441  snprintf(msg, sizeof(msg), "This feed is already being received.");
1442  http_log("Feed '%s' already being received\n", stream->feed_filename);
1443  goto send_error;
1444  }
1445 
1446  if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1447  c->http_error = 503;
1448  q = c->buffer;
1449  snprintf(q, c->buffer_size,
1450  "HTTP/1.0 503 Server too busy\r\n"
1451  "Content-type: text/html\r\n"
1452  "\r\n"
1453  "<html><head><title>Too busy</title></head><body>\r\n"
1454  "<p>The server is too busy to serve your request at this time.</p>\r\n"
1455  "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1456  "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1457  "</body></html>\r\n", current_bandwidth, config.max_bandwidth);
1458  q += strlen(q);
1459  /* prepare output buffer */
1460  c->buffer_ptr = c->buffer;
1461  c->buffer_end = q;
1463  return 0;
1464  }
1465 
1466  if (redir_type != REDIR_NONE) {
1467  const char *hostinfo = 0;
1468 
1469  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1470  if (av_strncasecmp(p, "Host:", 5) == 0) {
1471  hostinfo = p + 5;
1472  break;
1473  }
1474  p = strchr(p, '\n');
1475  if (!p)
1476  break;
1477 
1478  p++;
1479  }
1480 
1481  if (hostinfo) {
1482  char *eoh;
1483  char hostbuf[260];
1484 
1485  while (av_isspace(*hostinfo))
1486  hostinfo++;
1487 
1488  eoh = strchr(hostinfo, '\n');
1489  if (eoh) {
1490  if (eoh[-1] == '\r')
1491  eoh--;
1492 
1493  if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1494  memcpy(hostbuf, hostinfo, eoh - hostinfo);
1495  hostbuf[eoh - hostinfo] = 0;
1496 
1497  c->http_error = 200;
1498  q = c->buffer;
1499  switch(redir_type) {
1500  case REDIR_ASX:
1501  snprintf(q, c->buffer_size,
1502  "HTTP/1.0 200 ASX Follows\r\n"
1503  "Content-type: video/x-ms-asf\r\n"
1504  "\r\n"
1505  "<ASX Version=\"3\">\r\n"
1506  //"<!-- Autogenerated by ffserver -->\r\n"
1507  "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1508  "</ASX>\r\n", hostbuf, filename, info);
1509  q += strlen(q);
1510  break;
1511  case REDIR_RAM:
1512  snprintf(q, c->buffer_size,
1513  "HTTP/1.0 200 RAM Follows\r\n"
1514  "Content-type: audio/x-pn-realaudio\r\n"
1515  "\r\n"
1516  "# Autogenerated by ffserver\r\n"
1517  "http://%s/%s%s\r\n", hostbuf, filename, info);
1518  q += strlen(q);
1519  break;
1520  case REDIR_ASF:
1521  snprintf(q, c->buffer_size,
1522  "HTTP/1.0 200 ASF Redirect follows\r\n"
1523  "Content-type: video/x-ms-asf\r\n"
1524  "\r\n"
1525  "[Reference]\r\n"
1526  "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1527  q += strlen(q);
1528  break;
1529  case REDIR_RTSP:
1530  {
1531  char hostname[256], *p;
1532  /* extract only hostname */
1533  av_strlcpy(hostname, hostbuf, sizeof(hostname));
1534  p = strrchr(hostname, ':');
1535  if (p)
1536  *p = '\0';
1537  snprintf(q, c->buffer_size,
1538  "HTTP/1.0 200 RTSP Redirect follows\r\n"
1539  /* XXX: incorrect MIME type ? */
1540  "Content-type: application/x-rtsp\r\n"
1541  "\r\n"
1542  "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1543  q += strlen(q);
1544  }
1545  break;
1546  case REDIR_SDP:
1547  {
1548  uint8_t *sdp_data;
1549  int sdp_data_size;
1550  socklen_t len;
1551  struct sockaddr_in my_addr;
1552 
1553  snprintf(q, c->buffer_size,
1554  "HTTP/1.0 200 OK\r\n"
1555  "Content-type: application/sdp\r\n"
1556  "\r\n");
1557  q += strlen(q);
1558 
1559  len = sizeof(my_addr);
1560 
1561  /* XXX: Should probably fail? */
1562  if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1563  http_log("getsockname() failed\n");
1564 
1565  /* XXX: should use a dynamic buffer */
1566  sdp_data_size = prepare_sdp_description(stream,
1567  &sdp_data,
1568  my_addr.sin_addr);
1569  if (sdp_data_size > 0) {
1570  memcpy(q, sdp_data, sdp_data_size);
1571  q += sdp_data_size;
1572  *q = '\0';
1573  av_free(sdp_data);
1574  }
1575  }
1576  break;
1577  default:
1578  abort();
1579  break;
1580  }
1581 
1582  /* prepare output buffer */
1583  c->buffer_ptr = c->buffer;
1584  c->buffer_end = q;
1586  return 0;
1587  }
1588  }
1589  }
1590 
1591  snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1592  goto send_error;
1593  }
1594 
1595  stream->conns_served++;
1596 
1597  /* XXX: add there authenticate and IP match */
1598 
1599  if (c->post) {
1600  /* if post, it means a feed is being sent */
1601  if (!stream->is_feed) {
1602  /* However it might be a status report from WMP! Let us log the
1603  * data as it might come handy one day. */
1604  const char *logline = 0;
1605  int client_id = 0;
1606 
1607  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1608  if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1609  logline = p;
1610  break;
1611  }
1612  if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1613  client_id = strtol(p + 18, 0, 10);
1614  p = strchr(p, '\n');
1615  if (!p)
1616  break;
1617 
1618  p++;
1619  }
1620 
1621  if (logline) {
1622  char *eol = strchr(logline, '\n');
1623 
1624  logline += 17;
1625 
1626  if (eol) {
1627  if (eol[-1] == '\r')
1628  eol--;
1629  http_log("%.*s\n", (int) (eol - logline), logline);
1630  c->suppress_log = 1;
1631  }
1632  }
1633 
1634 #ifdef DEBUG
1635  http_log("\nGot request:\n%s\n", c->buffer);
1636 #endif
1637 
1638  if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1639  HTTPContext *wmpc;
1640 
1641  /* Now we have to find the client_id */
1642  for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1643  if (wmpc->wmp_client_id == client_id)
1644  break;
1645  }
1646 
1647  if (wmpc && modify_current_stream(wmpc, ratebuf))
1648  wmpc->switch_pending = 1;
1649  }
1650 
1651  snprintf(msg, sizeof(msg), "POST command not handled");
1652  c->stream = 0;
1653  goto send_error;
1654  }
1655  if (http_start_receive_data(c) < 0) {
1656  snprintf(msg, sizeof(msg), "could not open feed");
1657  goto send_error;
1658  }
1659  c->http_error = 0;
1661  return 0;
1662  }
1663 
1664 #ifdef DEBUG
1665  if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1666  http_log("\nGot request:\n%s\n", c->buffer);
1667 #endif
1668 
1670  goto send_status;
1671 
1672  /* open input stream */
1673  if (open_input_stream(c, info) < 0) {
1674  snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1675  goto send_error;
1676  }
1677 
1678  /* prepare HTTP header */
1679  c->buffer[0] = 0;
1680  av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1681  mime_type = c->stream->fmt->mime_type;
1682  if (!mime_type)
1683  mime_type = "application/x-octet-stream";
1684  av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1685 
1686  /* for asf, we need extra headers */
1687  if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1688  /* Need to allocate a client id */
1689 
1690  c->wmp_client_id = av_lfg_get(&random_state);
1691 
1692  av_strlcatf(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);
1693  }
1694  av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1695  av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1696  q = c->buffer + strlen(c->buffer);
1697 
1698  /* prepare output buffer */
1699  c->http_error = 0;
1700  c->buffer_ptr = c->buffer;
1701  c->buffer_end = q;
1703  return 0;
1704  send_error:
1705  c->http_error = 404;
1706  q = c->buffer;
1707  htmlstrip(msg);
1708  snprintf(q, c->buffer_size,
1709  "HTTP/1.0 404 Not Found\r\n"
1710  "Content-type: text/html\r\n"
1711  "\r\n"
1712  "<html>\n"
1713  "<head><title>404 Not Found</title></head>\n"
1714  "<body>%s</body>\n"
1715  "</html>\n", msg);
1716  q += strlen(q);
1717  /* prepare output buffer */
1718  c->buffer_ptr = c->buffer;
1719  c->buffer_end = q;
1721  return 0;
1722  send_status:
1723  compute_status(c);
1724  c->http_error = 200; /* horrible : we use this value to avoid
1725  going to the send data state */
1727  return 0;
1728 }
1729 
1730 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1731 {
1732  static const char suffix[] = " kMGTP";
1733  const char *s;
1734 
1735  for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1736 
1737  avio_printf(pb, "%"PRId64"%c", count, *s);
1738 }
1739 
1741 {
1742  HTTPContext *c1;
1743  FFServerStream *stream;
1744  char *p;
1745  time_t ti;
1746  int i, len;
1747  AVIOContext *pb;
1748 
1749  if (avio_open_dyn_buf(&pb) < 0) {
1750  /* XXX: return an error ? */
1751  c->buffer_ptr = c->buffer;
1752  c->buffer_end = c->buffer;
1753  return;
1754  }
1755 
1756  avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1757  avio_printf(pb, "Content-type: text/html\r\n");
1758  avio_printf(pb, "Pragma: no-cache\r\n");
1759  avio_printf(pb, "\r\n");
1760 
1761  avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1762  if (c->stream->feed_filename[0])
1763  avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1764  avio_printf(pb, "</head>\n<body>");
1765  avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1766  /* format status */
1767  avio_printf(pb, "<h2>Available Streams</h2>\n");
1768  avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1769  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");
1770  stream = config.first_stream;
1771  while (stream) {
1772  char sfilename[1024];
1773  char *eosf;
1774 
1775  if (stream->feed == stream) {
1776  stream = stream->next;
1777  continue;
1778  }
1779 
1780  av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1781  eosf = sfilename + strlen(sfilename);
1782  if (eosf - sfilename >= 4) {
1783  if (strcmp(eosf - 4, ".asf") == 0)
1784  strcpy(eosf - 4, ".asx");
1785  else if (strcmp(eosf - 3, ".rm") == 0)
1786  strcpy(eosf - 3, ".ram");
1787  else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1788  /* generate a sample RTSP director if
1789  unicast. Generate an SDP redirector if
1790  multicast */
1791  eosf = strrchr(sfilename, '.');
1792  if (!eosf)
1793  eosf = sfilename + strlen(sfilename);
1794  if (stream->is_multicast)
1795  strcpy(eosf, ".sdp");
1796  else
1797  strcpy(eosf, ".rtsp");
1798  }
1799  }
1800 
1801  avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1802  sfilename, stream->filename);
1803  avio_printf(pb, "<td align=right> %d <td align=right> ",
1804  stream->conns_served);
1805  fmt_bytecount(pb, stream->bytes_served);
1806 
1807  switch(stream->stream_type) {
1808  case STREAM_TYPE_LIVE: {
1809  int audio_bit_rate = 0;
1810  int video_bit_rate = 0;
1811  const char *audio_codec_name = "";
1812  const char *video_codec_name = "";
1813  const char *audio_codec_name_extra = "";
1814  const char *video_codec_name_extra = "";
1815 
1816  for(i=0;i<stream->nb_streams;i++) {
1817  AVStream *st = stream->streams[i];
1818  AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1819 
1820  switch(st->codec->codec_type) {
1821  case AVMEDIA_TYPE_AUDIO:
1822  audio_bit_rate += st->codec->bit_rate;
1823  if (codec) {
1824  if (*audio_codec_name)
1825  audio_codec_name_extra = "...";
1826  audio_codec_name = codec->name;
1827  }
1828  break;
1829  case AVMEDIA_TYPE_VIDEO:
1830  video_bit_rate += st->codec->bit_rate;
1831  if (codec) {
1832  if (*video_codec_name)
1833  video_codec_name_extra = "...";
1834  video_codec_name = codec->name;
1835  }
1836  break;
1837  case AVMEDIA_TYPE_DATA:
1838  video_bit_rate += st->codec->bit_rate;
1839  break;
1840  default:
1841  abort();
1842  }
1843  }
1844 
1845  avio_printf(pb, "<td align=center> %s <td align=right> %d "
1846  "<td align=right> %d <td> %s %s <td align=right> "
1847  "%d <td> %s %s",
1848  stream->fmt->name, stream->bandwidth,
1849  video_bit_rate / 1000, video_codec_name,
1850  video_codec_name_extra, audio_bit_rate / 1000,
1851  audio_codec_name, audio_codec_name_extra);
1852 
1853  if (stream->feed)
1854  avio_printf(pb, "<td>%s", stream->feed->filename);
1855  else
1856  avio_printf(pb, "<td>%s", stream->feed_filename);
1857  avio_printf(pb, "\n");
1858  }
1859  break;
1860  default:
1861  avio_printf(pb, "<td align=center> - <td align=right> - "
1862  "<td align=right> - <td><td align=right> - <td>\n");
1863  break;
1864  }
1865  stream = stream->next;
1866  }
1867  avio_printf(pb, "</table>\n");
1868 
1869  stream = config.first_stream;
1870  while (stream) {
1871 
1872  if (stream->feed != stream) {
1873  stream = stream->next;
1874  continue;
1875  }
1876 
1877  avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1878  if (stream->pid) {
1879  avio_printf(pb, "Running as pid %d.\n", stream->pid);
1880 
1881 #if defined(linux)
1882  {
1883  FILE *pid_stat;
1884  char ps_cmd[64];
1885 
1886  /* This is somewhat linux specific I guess */
1887  snprintf(ps_cmd, sizeof(ps_cmd),
1888  "ps -o \"%%cpu,cputime\" --no-headers %d",
1889  stream->pid);
1890 
1891  pid_stat = popen(ps_cmd, "r");
1892  if (pid_stat) {
1893  char cpuperc[10];
1894  char cpuused[64];
1895 
1896  if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1897  avio_printf(pb, "Currently using %s%% of the cpu. "
1898  "Total time used %s.\n",
1899  cpuperc, cpuused);
1900  }
1901  fclose(pid_stat);
1902  }
1903  }
1904 #endif
1905 
1906  avio_printf(pb, "<p>");
1907  }
1908 
1909  avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1910  "type<th>kbits/s<th align=left>codec<th align=left>"
1911  "Parameters\n");
1912 
1913  for (i = 0; i < stream->nb_streams; i++) {
1914  AVStream *st = stream->streams[i];
1915  AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1916  const char *type = "unknown";
1917  char parameters[64];
1918 
1919  parameters[0] = 0;
1920 
1921  switch(st->codec->codec_type) {
1922  case AVMEDIA_TYPE_AUDIO:
1923  type = "audio";
1924  snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1925  st->codec->channels, st->codec->sample_rate);
1926  break;
1927  case AVMEDIA_TYPE_VIDEO:
1928  type = "video";
1929  snprintf(parameters, sizeof(parameters),
1930  "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1931  st->codec->height, st->codec->qmin, st->codec->qmax,
1932  st->codec->time_base.den / st->codec->time_base.num);
1933  break;
1934  default:
1935  abort();
1936  }
1937 
1938  avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1939  "<td>%s<td>%s\n",
1940  i, type, st->codec->bit_rate/1000,
1941  codec ? codec->name : "", parameters);
1942  }
1943 
1944  avio_printf(pb, "</table>\n");
1945  stream = stream->next;
1946  }
1947 
1948  /* connection status */
1949  avio_printf(pb, "<h2>Connection Status</h2>\n");
1950 
1951  avio_printf(pb, "Number of connections: %d / %d<br>\n",
1953 
1954  avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1956 
1957  avio_printf(pb, "<table>\n");
1958  avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1959  "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1960  c1 = first_http_ctx;
1961  i = 0;
1962  while (c1) {
1963  int bitrate;
1964  int j;
1965 
1966  bitrate = 0;
1967  if (c1->stream) {
1968  for (j = 0; j < c1->stream->nb_streams; j++) {
1969  if (!c1->stream->feed)
1970  bitrate += c1->stream->streams[j]->codec->bit_rate;
1971  else if (c1->feed_streams[j] >= 0)
1972  bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1973  }
1974  }
1975 
1976  i++;
1977  p = inet_ntoa(c1->from_addr.sin_addr);
1978  avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1979  "<td align=right>",
1980  i, c1->stream ? c1->stream->filename : "",
1981  c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1982  c1->protocol, http_state[c1->state]);
1983  fmt_bytecount(pb, bitrate);
1984  avio_printf(pb, "<td align=right>");
1985  fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1986  avio_printf(pb, "<td align=right>");
1987  fmt_bytecount(pb, c1->data_count);
1988  avio_printf(pb, "\n");
1989  c1 = c1->next;
1990  }
1991  avio_printf(pb, "</table>\n");
1992 
1993  /* date */
1994  ti = time(NULL);
1995  p = ctime(&ti);
1996  avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
1997  avio_printf(pb, "</body>\n</html>\n");
1998 
1999  len = avio_close_dyn_buf(pb, &c->pb_buffer);
2000  c->buffer_ptr = c->pb_buffer;
2001  c->buffer_end = c->pb_buffer + len;
2002 }
2003 
2004 static int open_input_stream(HTTPContext *c, const char *info)
2005 {
2006  char buf[128];
2007  char input_filename[1024];
2008  AVFormatContext *s = NULL;
2009  int buf_size, i, ret;
2010  int64_t stream_pos;
2011 
2012  /* find file name */
2013  if (c->stream->feed) {
2014  strcpy(input_filename, c->stream->feed->feed_filename);
2015  buf_size = FFM_PACKET_SIZE;
2016  /* compute position (absolute time) */
2017  if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2018  if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2019  http_log("Invalid date specification '%s' for stream\n", buf);
2020  return ret;
2021  }
2022  } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2023  int prebuffer = strtol(buf, 0, 10);
2024  stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2025  } else
2026  stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2027  } else {
2028  strcpy(input_filename, c->stream->feed_filename);
2029  buf_size = 0;
2030  /* compute position (relative time) */
2031  if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2032  if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2033  http_log("Invalid date specification '%s' for stream\n", buf);
2034  return ret;
2035  }
2036  } else
2037  stream_pos = 0;
2038  }
2039  if (!input_filename[0]) {
2040  http_log("No filename was specified for stream\n");
2041  return AVERROR(EINVAL);
2042  }
2043 
2044  /* open stream */
2045  if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2046  http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2047  return ret;
2048  }
2049 
2050  /* set buffer size */
2051  if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2052 
2053  s->flags |= AVFMT_FLAG_GENPTS;
2054  c->fmt_in = s;
2055  if (strcmp(s->iformat->name, "ffm") &&
2056  (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2057  http_log("Could not find stream info for input '%s'\n", input_filename);
2059  return ret;
2060  }
2061 
2062  /* choose stream as clock source (we favor the video stream if
2063  * present) for packet sending */
2064  c->pts_stream_index = 0;
2065  for(i=0;i<c->stream->nb_streams;i++) {
2066  if (c->pts_stream_index == 0 &&
2068  c->pts_stream_index = i;
2069  }
2070  }
2071 
2072  if (c->fmt_in->iformat->read_seek)
2073  av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2074  /* set the start time (needed for maxtime and RTP packet timing) */
2075  c->start_time = cur_time;
2077  return 0;
2078 }
2079 
2080 /* return the server clock (in us) */
2082 {
2083  /* compute current pts value from system time */
2084  return (cur_time - c->start_time) * 1000;
2085 }
2086 
2087 /* return the estimated time at which the current packet must be sent
2088  (in us) */
2090 {
2091  int bytes_left, bytes_sent, frame_bytes;
2092 
2093  frame_bytes = c->cur_frame_bytes;
2094  if (frame_bytes <= 0)
2095  return c->cur_pts;
2096  else {
2097  bytes_left = c->buffer_end - c->buffer_ptr;
2098  bytes_sent = frame_bytes - bytes_left;
2099  return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2100  }
2101 }
2102 
2103 
2105 {
2106  int i, len, ret;
2107  AVFormatContext *ctx;
2108 
2109  av_freep(&c->pb_buffer);
2110  switch(c->state) {
2112  ctx = avformat_alloc_context();
2113  c->fmt_ctx = *ctx;
2114  av_freep(&ctx);
2115  av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2117 
2118  for(i=0;i<c->stream->nb_streams;i++) {
2119  AVStream *src;
2120  c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2121  /* if file or feed, then just take streams from FFServerStream struct */
2122  if (!c->stream->feed ||
2123  c->stream->feed == c->stream)
2124  src = c->stream->streams[i];
2125  else
2126  src = c->stream->feed->streams[c->stream->feed_streams[i]];
2127 
2128  *(c->fmt_ctx.streams[i]) = *src;
2129  c->fmt_ctx.streams[i]->priv_data = 0;
2130  /* XXX: should be done in AVStream, not in codec */
2131  c->fmt_ctx.streams[i]->codec->frame_number = 0;
2132  }
2133  /* set output format parameters */
2134  c->fmt_ctx.oformat = c->stream->fmt;
2136 
2137  c->got_key_frame = 0;
2138 
2139  /* prepare header and save header data in a stream */
2140  if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2141  /* XXX: potential leak */
2142  return -1;
2143  }
2144  c->fmt_ctx.pb->seekable = 0;
2145 
2146  /*
2147  * HACK to avoid MPEG-PS muxer to spit many underflow errors
2148  * Default value from FFmpeg
2149  * Try to set it using configuration option
2150  */
2151  c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2152 
2153  if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2154  http_log("Error writing output header for stream '%s': %s\n",
2155  c->stream->filename, av_err2str(ret));
2156  return ret;
2157  }
2159 
2160  len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2161  c->buffer_ptr = c->pb_buffer;
2162  c->buffer_end = c->pb_buffer + len;
2163 
2165  c->last_packet_sent = 0;
2166  break;
2167  case HTTPSTATE_SEND_DATA:
2168  /* find a new packet */
2169  /* read a packet from the input stream */
2170  if (c->stream->feed)
2173  c->stream->feed->feed_size);
2174 
2175  if (c->stream->max_time &&
2176  c->stream->max_time + c->start_time - cur_time < 0)
2177  /* We have timed out */
2179  else {
2180  AVPacket pkt;
2181  redo:
2182  ret = av_read_frame(c->fmt_in, &pkt);
2183  if (ret < 0) {
2184  if (c->stream->feed) {
2185  /* if coming from feed, it means we reached the end of the
2186  ffm file, so must wait for more data */
2188  return 1; /* state changed */
2189  } else if (ret == AVERROR(EAGAIN)) {
2190  /* input not ready, come back later */
2191  return 0;
2192  } else {
2193  if (c->stream->loop) {
2195  if (open_input_stream(c, "") < 0)
2196  goto no_loop;
2197  goto redo;
2198  } else {
2199  no_loop:
2200  /* must send trailer now because EOF or error */
2202  }
2203  }
2204  } else {
2205  int source_index = pkt.stream_index;
2206  /* update first pts if needed */
2207  if (c->first_pts == AV_NOPTS_VALUE) {
2209  c->start_time = cur_time;
2210  }
2211  /* send it to the appropriate stream */
2212  if (c->stream->feed) {
2213  /* if coming from a feed, select the right stream */
2214  if (c->switch_pending) {
2215  c->switch_pending = 0;
2216  for(i=0;i<c->stream->nb_streams;i++) {
2217  if (c->switch_feed_streams[i] == pkt.stream_index)
2218  if (pkt.flags & AV_PKT_FLAG_KEY)
2219  c->switch_feed_streams[i] = -1;
2220  if (c->switch_feed_streams[i] >= 0)
2221  c->switch_pending = 1;
2222  }
2223  }
2224  for(i=0;i<c->stream->nb_streams;i++) {
2225  if (c->stream->feed_streams[i] == pkt.stream_index) {
2226  AVStream *st = c->fmt_in->streams[source_index];
2227  pkt.stream_index = i;
2228  if (pkt.flags & AV_PKT_FLAG_KEY &&
2229  (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2230  c->stream->nb_streams == 1))
2231  c->got_key_frame = 1;
2232  if (!c->stream->send_on_key || c->got_key_frame)
2233  goto send_it;
2234  }
2235  }
2236  } else {
2237  AVCodecContext *codec;
2238  AVStream *ist, *ost;
2239  send_it:
2240  ist = c->fmt_in->streams[source_index];
2241  /* specific handling for RTP: we use several
2242  * output streams (one for each RTP connection).
2243  * XXX: need more abstract handling */
2244  if (c->is_packetized) {
2245  /* compute send time and duration */
2246  c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2247  c->cur_pts -= c->first_pts;
2249  /* find RTP context */
2251  ctx = c->rtp_ctx[c->packet_stream_index];
2252  if(!ctx) {
2253  av_free_packet(&pkt);
2254  break;
2255  }
2256  codec = ctx->streams[0]->codec;
2257  /* only one stream per RTP connection */
2258  pkt.stream_index = 0;
2259  } else {
2260  ctx = &c->fmt_ctx;
2261  /* Fudge here */
2262  codec = ctx->streams[pkt.stream_index]->codec;
2263  }
2264 
2265  if (c->is_packetized) {
2266  int max_packet_size;
2268  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2269  else
2270  max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2271  ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2272  } else {
2273  ret = avio_open_dyn_buf(&ctx->pb);
2274  }
2275  if (ret < 0) {
2276  /* XXX: potential leak */
2277  return -1;
2278  }
2279  ost = ctx->streams[pkt.stream_index];
2280 
2281  ctx->pb->seekable = 0;
2282  if (pkt.dts != AV_NOPTS_VALUE)
2283  pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2284  if (pkt.pts != AV_NOPTS_VALUE)
2285  pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2286  pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2287  if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2288  http_log("Error writing frame to output for stream '%s': %s\n",
2289  c->stream->filename, av_err2str(ret));
2291  }
2292 
2293  av_freep(&c->pb_buffer);
2294  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2295  c->cur_frame_bytes = len;
2296  c->buffer_ptr = c->pb_buffer;
2297  c->buffer_end = c->pb_buffer + len;
2298 
2299  codec->frame_number++;
2300  if (len == 0) {
2301  av_free_packet(&pkt);
2302  goto redo;
2303  }
2304  }
2305  av_free_packet(&pkt);
2306  }
2307  }
2308  break;
2309  default:
2311  /* last packet test ? */
2312  if (c->last_packet_sent || c->is_packetized)
2313  return -1;
2314  ctx = &c->fmt_ctx;
2315  /* prepare header */
2316  if (avio_open_dyn_buf(&ctx->pb) < 0) {
2317  /* XXX: potential leak */
2318  return -1;
2319  }
2320  c->fmt_ctx.pb->seekable = 0;
2321  av_write_trailer(ctx);
2322  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2323  c->buffer_ptr = c->pb_buffer;
2324  c->buffer_end = c->pb_buffer + len;
2325 
2326  c->last_packet_sent = 1;
2327  break;
2328  }
2329  return 0;
2330 }
2331 
2332 /* should convert the format at the same time */
2333 /* send data starting at c->buffer_ptr to the output connection
2334  * (either UDP or TCP) */
2336 {
2337  int len, ret;
2338 
2339  for(;;) {
2340  if (c->buffer_ptr >= c->buffer_end) {
2341  ret = http_prepare_data(c);
2342  if (ret < 0)
2343  return -1;
2344  else if (ret)
2345  /* state change requested */
2346  break;
2347  } else {
2348  if (c->is_packetized) {
2349  /* RTP data output */
2350  len = c->buffer_end - c->buffer_ptr;
2351  if (len < 4) {
2352  /* fail safe - should never happen */
2353  fail1:
2354  c->buffer_ptr = c->buffer_end;
2355  return 0;
2356  }
2357  len = (c->buffer_ptr[0] << 24) |
2358  (c->buffer_ptr[1] << 16) |
2359  (c->buffer_ptr[2] << 8) |
2360  (c->buffer_ptr[3]);
2361  if (len > (c->buffer_end - c->buffer_ptr))
2362  goto fail1;
2363  if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2364  /* nothing to send yet: we can wait */
2365  return 0;
2366  }
2367 
2368  c->data_count += len;
2370  if (c->stream)
2371  c->stream->bytes_served += len;
2372 
2374  /* RTP packets are sent inside the RTSP TCP connection */
2375  AVIOContext *pb;
2376  int interleaved_index, size;
2377  uint8_t header[4];
2378  HTTPContext *rtsp_c;
2379 
2380  rtsp_c = c->rtsp_c;
2381  /* if no RTSP connection left, error */
2382  if (!rtsp_c)
2383  return -1;
2384  /* if already sending something, then wait. */
2385  if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2386  break;
2387  if (avio_open_dyn_buf(&pb) < 0)
2388  goto fail1;
2389  interleaved_index = c->packet_stream_index * 2;
2390  /* RTCP packets are sent at odd indexes */
2391  if (c->buffer_ptr[1] == 200)
2392  interleaved_index++;
2393  /* write RTSP TCP header */
2394  header[0] = '$';
2395  header[1] = interleaved_index;
2396  header[2] = len >> 8;
2397  header[3] = len;
2398  avio_write(pb, header, 4);
2399  /* write RTP packet data */
2400  c->buffer_ptr += 4;
2401  avio_write(pb, c->buffer_ptr, len);
2402  size = avio_close_dyn_buf(pb, &c->packet_buffer);
2403  /* prepare asynchronous TCP sending */
2404  rtsp_c->packet_buffer_ptr = c->packet_buffer;
2405  rtsp_c->packet_buffer_end = c->packet_buffer + size;
2406  c->buffer_ptr += len;
2407 
2408  /* send everything we can NOW */
2409  len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2410  rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2411  if (len > 0)
2412  rtsp_c->packet_buffer_ptr += len;
2413  if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2414  /* if we could not send all the data, we will
2415  send it later, so a new state is needed to
2416  "lock" the RTSP TCP connection */
2417  rtsp_c->state = RTSPSTATE_SEND_PACKET;
2418  break;
2419  } else
2420  /* all data has been sent */
2421  av_freep(&c->packet_buffer);
2422  } else {
2423  /* send RTP packet directly in UDP */
2424  c->buffer_ptr += 4;
2426  c->buffer_ptr, len);
2427  c->buffer_ptr += len;
2428  /* here we continue as we can send several packets per 10 ms slot */
2429  }
2430  } else {
2431  /* TCP data output */
2432  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2433  if (len < 0) {
2434  if (ff_neterrno() != AVERROR(EAGAIN) &&
2435  ff_neterrno() != AVERROR(EINTR))
2436  /* error : close connection */
2437  return -1;
2438  else
2439  return 0;
2440  }
2441  c->buffer_ptr += len;
2442 
2443  c->data_count += len;
2445  if (c->stream)
2446  c->stream->bytes_served += len;
2447  break;
2448  }
2449  }
2450  } /* for(;;) */
2451  return 0;
2452 }
2453 
2455 {
2456  int fd;
2457  int ret;
2458 
2459  if (c->stream->feed_opened) {
2460  http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2461  return AVERROR(EINVAL);
2462  }
2463 
2464  /* Don't permit writing to this one */
2465  if (c->stream->readonly) {
2466  http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2467  return AVERROR(EINVAL);
2468  }
2469 
2470  /* open feed */
2471  fd = open(c->stream->feed_filename, O_RDWR);
2472  if (fd < 0) {
2473  ret = AVERROR(errno);
2474  http_log("Could not open feed file '%s': %s\n",
2475  c->stream->feed_filename, strerror(errno));
2476  return ret;
2477  }
2478  c->feed_fd = fd;
2479 
2480  if (c->stream->truncate) {
2481  /* truncate feed file */
2483  http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2484  if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2485  ret = AVERROR(errno);
2486  http_log("Error truncating feed file '%s': %s\n",
2487  c->stream->feed_filename, strerror(errno));
2488  return ret;
2489  }
2490  } else {
2491  ret = ffm_read_write_index(fd);
2492  if (ret < 0) {
2493  http_log("Error reading write index from feed file '%s': %s\n",
2494  c->stream->feed_filename, strerror(errno));
2495  return ret;
2496  } else {
2497  c->stream->feed_write_index = ret;
2498  }
2499  }
2500 
2502  c->stream->feed_size = lseek(fd, 0, SEEK_END);
2503  lseek(fd, 0, SEEK_SET);
2504 
2505  /* init buffer input */
2506  c->buffer_ptr = c->buffer;
2507  c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2508  c->stream->feed_opened = 1;
2509  c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2510  return 0;
2511 }
2512 
2514 {
2515  HTTPContext *c1;
2516  int len, loop_run = 0;
2517 
2518  while (c->chunked_encoding && !c->chunk_size &&
2519  c->buffer_end > c->buffer_ptr) {
2520  /* read chunk header, if present */
2521  len = recv(c->fd, c->buffer_ptr, 1, 0);
2522 
2523  if (len < 0) {
2524  if (ff_neterrno() != AVERROR(EAGAIN) &&
2525  ff_neterrno() != AVERROR(EINTR))
2526  /* error : close connection */
2527  goto fail;
2528  return 0;
2529  } else if (len == 0) {
2530  /* end of connection : close it */
2531  goto fail;
2532  } else if (c->buffer_ptr - c->buffer >= 2 &&
2533  !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2534  c->chunk_size = strtol(c->buffer, 0, 16);
2535  if (c->chunk_size == 0) // end of stream
2536  goto fail;
2537  c->buffer_ptr = c->buffer;
2538  break;
2539  } else if (++loop_run > 10) {
2540  /* no chunk header, abort */
2541  goto fail;
2542  } else {
2543  c->buffer_ptr++;
2544  }
2545  }
2546 
2547  if (c->buffer_end > c->buffer_ptr) {
2548  len = recv(c->fd, c->buffer_ptr,
2549  FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2550  if (len < 0) {
2551  if (ff_neterrno() != AVERROR(EAGAIN) &&
2552  ff_neterrno() != AVERROR(EINTR))
2553  /* error : close connection */
2554  goto fail;
2555  } else if (len == 0)
2556  /* end of connection : close it */
2557  goto fail;
2558  else {
2559  c->chunk_size -= len;
2560  c->buffer_ptr += len;
2561  c->data_count += len;
2563  }
2564  }
2565 
2566  if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2567  if (c->buffer[0] != 'f' ||
2568  c->buffer[1] != 'm') {
2569  http_log("Feed stream has become desynchronized -- disconnecting\n");
2570  goto fail;
2571  }
2572  }
2573 
2574  if (c->buffer_ptr >= c->buffer_end) {
2575  FFServerStream *feed = c->stream;
2576  /* a packet has been received : write it in the store, except
2577  if header */
2578  if (c->data_count > FFM_PACKET_SIZE) {
2579  /* XXX: use llseek or url_seek
2580  * XXX: Should probably fail? */
2581  if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2582  http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2583 
2584  if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2585  http_log("Error writing to feed file: %s\n", strerror(errno));
2586  goto fail;
2587  }
2588 
2590  /* update file size */
2591  if (feed->feed_write_index > c->stream->feed_size)
2592  feed->feed_size = feed->feed_write_index;
2593 
2594  /* handle wrap around if max file size reached */
2595  if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2597 
2598  /* write index */
2599  if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2600  http_log("Error writing index to feed file: %s\n", strerror(errno));
2601  goto fail;
2602  }
2603 
2604  /* wake up any waiting connections */
2605  for(c1 = first_http_ctx; c1; c1 = c1->next) {
2606  if (c1->state == HTTPSTATE_WAIT_FEED &&
2607  c1->stream->feed == c->stream->feed)
2608  c1->state = HTTPSTATE_SEND_DATA;
2609  }
2610  } else {
2611  /* We have a header in our hands that contains useful data */
2613  AVIOContext *pb;
2614  AVInputFormat *fmt_in;
2615  int i;
2616 
2617  if (!s)
2618  goto fail;
2619 
2620  /* use feed output format name to find corresponding input format */
2621  fmt_in = av_find_input_format(feed->fmt->name);
2622  if (!fmt_in)
2623  goto fail;
2624 
2625  pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2626  0, NULL, NULL, NULL, NULL);
2627  pb->seekable = 0;
2628 
2629  s->pb = pb;
2630  if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2631  av_freep(&pb);
2632  goto fail;
2633  }
2634 
2635  /* Now we have the actual streams */
2636  if (s->nb_streams != feed->nb_streams) {
2638  av_freep(&pb);
2639  http_log("Feed '%s' stream number does not match registered feed\n",
2640  c->stream->feed_filename);
2641  goto fail;
2642  }
2643 
2644  for (i = 0; i < s->nb_streams; i++) {
2645  AVStream *fst = feed->streams[i];
2646  AVStream *st = s->streams[i];
2647  avcodec_copy_context(fst->codec, st->codec);
2648  }
2649 
2651  av_freep(&pb);
2652  }
2653  c->buffer_ptr = c->buffer;
2654  }
2655 
2656  return 0;
2657  fail:
2658  c->stream->feed_opened = 0;
2659  close(c->feed_fd);
2660  /* wake up any waiting connections to stop waiting for feed */
2661  for(c1 = first_http_ctx; c1; c1 = c1->next) {
2662  if (c1->state == HTTPSTATE_WAIT_FEED &&
2663  c1->stream->feed == c->stream->feed)
2665  }
2666  return -1;
2667 }
2668 
2669 /********************************************************************/
2670 /* RTSP handling */
2671 
2672 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2673 {
2674  const char *str;
2675  time_t ti;
2676  struct tm *tm;
2677  char buf2[32];
2678 
2679  str = RTSP_STATUS_CODE2STRING(error_number);
2680  if (!str)
2681  str = "Unknown Error";
2682 
2683  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2684  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2685 
2686  /* output GMT time */
2687  ti = time(NULL);
2688  tm = gmtime(&ti);
2689  strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2690  avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2691 }
2692 
2693 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2694 {
2695  rtsp_reply_header(c, error_number);
2696  avio_printf(c->pb, "\r\n");
2697 }
2698 
2700 {
2701  const char *p, *p1, *p2;
2702  char cmd[32];
2703  char url[1024];
2704  char protocol[32];
2705  char line[1024];
2706  int len;
2707  RTSPMessageHeader header1 = { 0 }, *header = &header1;
2708 
2709  c->buffer_ptr[0] = '\0';
2710  p = c->buffer;
2711 
2712  get_word(cmd, sizeof(cmd), &p);
2713  get_word(url, sizeof(url), &p);
2714  get_word(protocol, sizeof(protocol), &p);
2715 
2716  av_strlcpy(c->method, cmd, sizeof(c->method));
2717  av_strlcpy(c->url, url, sizeof(c->url));
2718  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2719 
2720  if (avio_open_dyn_buf(&c->pb) < 0) {
2721  /* XXX: cannot do more */
2722  c->pb = NULL; /* safety */
2723  return -1;
2724  }
2725 
2726  /* check version name */
2727  if (strcmp(protocol, "RTSP/1.0")) {
2729  goto the_end;
2730  }
2731 
2732  /* parse each header line */
2733  /* skip to next line */
2734  while (*p != '\n' && *p != '\0')
2735  p++;
2736  if (*p == '\n')
2737  p++;
2738  while (*p != '\0') {
2739  p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2740  if (!p1)
2741  break;
2742  p2 = p1;
2743  if (p2 > p && p2[-1] == '\r')
2744  p2--;
2745  /* skip empty line */
2746  if (p2 == p)
2747  break;
2748  len = p2 - p;
2749  if (len > sizeof(line) - 1)
2750  len = sizeof(line) - 1;
2751  memcpy(line, p, len);
2752  line[len] = '\0';
2753  ff_rtsp_parse_line(header, line, NULL, NULL);
2754  p = p1 + 1;
2755  }
2756 
2757  /* handle sequence number */
2758  c->seq = header->seq;
2759 
2760  if (!strcmp(cmd, "DESCRIBE"))
2761  rtsp_cmd_describe(c, url);
2762  else if (!strcmp(cmd, "OPTIONS"))
2763  rtsp_cmd_options(c, url);
2764  else if (!strcmp(cmd, "SETUP"))
2765  rtsp_cmd_setup(c, url, header);
2766  else if (!strcmp(cmd, "PLAY"))
2767  rtsp_cmd_play(c, url, header);
2768  else if (!strcmp(cmd, "PAUSE"))
2769  rtsp_cmd_interrupt(c, url, header, 1);
2770  else if (!strcmp(cmd, "TEARDOWN"))
2771  rtsp_cmd_interrupt(c, url, header, 0);
2772  else
2774 
2775  the_end:
2776  len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2777  c->pb = NULL; /* safety */
2778  if (len < 0) {
2779  /* XXX: cannot do more */
2780  return -1;
2781  }
2782  c->buffer_ptr = c->pb_buffer;
2783  c->buffer_end = c->pb_buffer + len;
2785  return 0;
2786 }
2787 
2788 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2789  struct in_addr my_ip)
2790 {
2791  AVFormatContext *avc;
2792  AVStream *avs = NULL;
2793  AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2794  AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2795  int i;
2796 
2797  *pbuffer = NULL;
2798 
2799  avc = avformat_alloc_context();
2800  if (!avc || !rtp_format) {
2801  return -1;
2802  }
2803  avc->oformat = rtp_format;
2804  av_dict_set(&avc->metadata, "title",
2805  entry ? entry->value : "No Title", 0);
2806  avc->nb_streams = stream->nb_streams;
2807  if (stream->is_multicast) {
2808  snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2809  inet_ntoa(stream->multicast_ip),
2810  stream->multicast_port, stream->multicast_ttl);
2811  } else {
2812  snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2813  }
2814 
2815  if (!(avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams))))
2816  goto sdp_done;
2817  if (!(avs = av_malloc_array(avc->nb_streams, sizeof(*avs))))
2818  goto sdp_done;
2819 
2820  for(i = 0; i < stream->nb_streams; i++) {
2821  avc->streams[i] = &avs[i];
2822  avc->streams[i]->codec = stream->streams[i]->codec;
2823  }
2824  *pbuffer = av_mallocz(2048);
2825  av_sdp_create(&avc, 1, *pbuffer, 2048);
2826 
2827  sdp_done:
2828  av_freep(&avc->streams);
2829  av_dict_free(&avc->metadata);
2830  av_free(avc);
2831  av_free(avs);
2832 
2833  return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2834 }
2835 
2836 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2837 {
2838 // rtsp_reply_header(c, RTSP_STATUS_OK);
2839  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2840  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2841  avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2842  avio_printf(c->pb, "\r\n");
2843 }
2844 
2845 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2846 {
2847  FFServerStream *stream;
2848  char path1[1024];
2849  const char *path;
2850  uint8_t *content;
2851  int content_length;
2852  socklen_t len;
2853  struct sockaddr_in my_addr;
2854 
2855  /* find which URL is asked */
2856  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2857  path = path1;
2858  if (*path == '/')
2859  path++;
2860 
2861  for(stream = config.first_stream; stream; stream = stream->next) {
2862  if (!stream->is_feed &&
2863  stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2864  !strcmp(path, stream->filename)) {
2865  goto found;
2866  }
2867  }
2868  /* no stream found */
2870  return;
2871 
2872  found:
2873  /* prepare the media description in SDP format */
2874 
2875  /* get the host IP */
2876  len = sizeof(my_addr);
2877  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2878  content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2879  if (content_length < 0) {
2881  return;
2882  }
2884  avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2885  avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2886  avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2887  avio_printf(c->pb, "\r\n");
2888  avio_write(c->pb, content, content_length);
2889  av_free(content);
2890 }
2891 
2892 static HTTPContext *find_rtp_session(const char *session_id)
2893 {
2894  HTTPContext *c;
2895 
2896  if (session_id[0] == '\0')
2897  return NULL;
2898 
2899  for(c = first_http_ctx; c; c = c->next) {
2900  if (!strcmp(c->session_id, session_id))
2901  return c;
2902  }
2903  return NULL;
2904 }
2905 
2907 {
2909  int i;
2910 
2911  for(i=0;i<h->nb_transports;i++) {
2912  th = &h->transports[i];
2913  if (th->lower_transport == lower_transport)
2914  return th;
2915  }
2916  return NULL;
2917 }
2918 
2919 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2920  RTSPMessageHeader *h)
2921 {
2922  FFServerStream *stream;
2923  int stream_index, rtp_port, rtcp_port;
2924  char buf[1024];
2925  char path1[1024];
2926  const char *path;
2927  HTTPContext *rtp_c;
2929  struct sockaddr_in dest_addr;
2930  RTSPActionServerSetup setup;
2931 
2932  /* find which URL is asked */
2933  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2934  path = path1;
2935  if (*path == '/')
2936  path++;
2937 
2938  /* now check each stream */
2939  for(stream = config.first_stream; stream; stream = stream->next) {
2940  if (stream->is_feed || !stream->fmt ||
2941  strcmp(stream->fmt->name, "rtp")) {
2942  continue;
2943  }
2944  /* accept aggregate filenames only if single stream */
2945  if (!strcmp(path, stream->filename)) {
2946  if (stream->nb_streams != 1) {
2948  return;
2949  }
2950  stream_index = 0;
2951  goto found;
2952  }
2953 
2954  for(stream_index = 0; stream_index < stream->nb_streams;
2955  stream_index++) {
2956  snprintf(buf, sizeof(buf), "%s/streamid=%d",
2957  stream->filename, stream_index);
2958  if (!strcmp(path, buf))
2959  goto found;
2960  }
2961  }
2962  /* no stream found */
2963  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2964  return;
2965  found:
2966 
2967  /* generate session id if needed */
2968  if (h->session_id[0] == '\0') {
2969  unsigned random0 = av_lfg_get(&random_state);
2970  unsigned random1 = av_lfg_get(&random_state);
2971  snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2972  random0, random1);
2973  }
2974 
2975  /* find RTP session, and create it if none found */
2976  rtp_c = find_rtp_session(h->session_id);
2977  if (!rtp_c) {
2978  /* always prefer UDP */
2980  if (!th) {
2982  if (!th) {
2984  return;
2985  }
2986  }
2987 
2988  rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2989  th->lower_transport);
2990  if (!rtp_c) {
2992  return;
2993  }
2994 
2995  /* open input stream */
2996  if (open_input_stream(rtp_c, "") < 0) {
2998  return;
2999  }
3000  }
3001 
3002  /* test if stream is OK (test needed because several SETUP needs
3003  to be done for a given file) */
3004  if (rtp_c->stream != stream) {
3006  return;
3007  }
3008 
3009  /* test if stream is already set up */
3010  if (rtp_c->rtp_ctx[stream_index]) {
3012  return;
3013  }
3014 
3015  /* check transport */
3016  th = find_transport(h, rtp_c->rtp_protocol);
3017  if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3018  th->client_port_min <= 0)) {
3020  return;
3021  }
3022 
3023  /* setup default options */
3024  setup.transport_option[0] = '\0';
3025  dest_addr = rtp_c->from_addr;
3026  dest_addr.sin_port = htons(th->client_port_min);
3027 
3028  /* setup stream */
3029  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3031  return;
3032  }
3033 
3034  /* now everything is OK, so we can send the connection parameters */
3036  /* session ID */
3037  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3038 
3039  switch(rtp_c->rtp_protocol) {
3041  rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3042  rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3043  avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3044  "client_port=%d-%d;server_port=%d-%d",
3046  rtp_port, rtcp_port);
3047  break;
3049  avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3050  stream_index * 2, stream_index * 2 + 1);
3051  break;
3052  default:
3053  break;
3054  }
3055  if (setup.transport_option[0] != '\0')
3056  avio_printf(c->pb, ";%s", setup.transport_option);
3057  avio_printf(c->pb, "\r\n");
3058 
3059 
3060  avio_printf(c->pb, "\r\n");
3061 }
3062 
3063 
3064 /* find an RTP connection by using the session ID. Check consistency
3065  with filename */
3066 static HTTPContext *find_rtp_session_with_url(const char *url,
3067  const char *session_id)
3068 {
3069  HTTPContext *rtp_c;
3070  char path1[1024];
3071  const char *path;
3072  char buf[1024];
3073  int s, len;
3074 
3075  rtp_c = find_rtp_session(session_id);
3076  if (!rtp_c)
3077  return NULL;
3078 
3079  /* find which URL is asked */
3080  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3081  path = path1;
3082  if (*path == '/')
3083  path++;
3084  if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3085  for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3086  snprintf(buf, sizeof(buf), "%s/streamid=%d",
3087  rtp_c->stream->filename, s);
3088  if(!strncmp(path, buf, sizeof(buf))) {
3089  // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3090  return rtp_c;
3091  }
3092  }
3093  len = strlen(path);
3094  if (len > 0 && path[len - 1] == '/' &&
3095  !strncmp(path, rtp_c->stream->filename, len - 1))
3096  return rtp_c;
3097  return NULL;
3098 }
3099 
3100 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3101 {
3102  HTTPContext *rtp_c;
3103 
3104  rtp_c = find_rtp_session_with_url(url, h->session_id);
3105  if (!rtp_c) {
3107  return;
3108  }
3109 
3110  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3111  rtp_c->state != HTTPSTATE_WAIT_FEED &&
3112  rtp_c->state != HTTPSTATE_READY) {
3114  return;
3115  }
3116 
3117  rtp_c->state = HTTPSTATE_SEND_DATA;
3118 
3119  /* now everything is OK, so we can send the connection parameters */
3121  /* session ID */
3122  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3123  avio_printf(c->pb, "\r\n");
3124 }
3125 
3126 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3127 {
3128  HTTPContext *rtp_c;
3129 
3130  rtp_c = find_rtp_session_with_url(url, h->session_id);
3131  if (!rtp_c) {
3133  return;
3134  }
3135 
3136  if (pause_only) {
3137  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3138  rtp_c->state != HTTPSTATE_WAIT_FEED) {
3140  return;
3141  }
3142  rtp_c->state = HTTPSTATE_READY;
3143  rtp_c->first_pts = AV_NOPTS_VALUE;
3144  }
3145 
3146  /* now everything is OK, so we can send the connection parameters */
3148  /* session ID */
3149  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3150  avio_printf(c->pb, "\r\n");
3151 
3152  if (!pause_only)
3153  close_connection(rtp_c);
3154 }
3155 
3156 /********************************************************************/
3157 /* RTP handling */
3158 
3159 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3160  FFServerStream *stream, const char *session_id,
3161  enum RTSPLowerTransport rtp_protocol)
3162 {
3163  HTTPContext *c = NULL;
3164  const char *proto_str;
3165 
3166  /* XXX: should output a warning page when coming
3167  close to the connection limit */
3168  if (nb_connections >= config.nb_max_connections)
3169  goto fail;
3170 
3171  /* add a new connection */
3172  c = av_mallocz(sizeof(HTTPContext));
3173  if (!c)
3174  goto fail;
3175 
3176  c->fd = -1;
3177  c->poll_entry = NULL;
3178  c->from_addr = *from_addr;
3180  c->buffer = av_malloc(c->buffer_size);
3181  if (!c->buffer)
3182  goto fail;
3183  nb_connections++;
3184  c->stream = stream;
3185  av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3186  c->state = HTTPSTATE_READY;
3187  c->is_packetized = 1;
3188  c->rtp_protocol = rtp_protocol;
3189 
3190  /* protocol is shown in statistics */
3191  switch(c->rtp_protocol) {
3193  proto_str = "MCAST";
3194  break;
3196  proto_str = "UDP";
3197  break;
3199  proto_str = "TCP";
3200  break;
3201  default:
3202  proto_str = "???";
3203  break;
3204  }
3205  av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3206  av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3207 
3208  current_bandwidth += stream->bandwidth;
3209 
3210  c->next = first_http_ctx;
3211  first_http_ctx = c;
3212  return c;
3213 
3214  fail:
3215  if (c) {
3216  av_freep(&c->buffer);
3217  av_free(c);
3218  }
3219  return NULL;
3220 }
3221 
3222 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3223  command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3224  used. */
3226  int stream_index, struct sockaddr_in *dest_addr,
3227  HTTPContext *rtsp_c)
3228 {
3229  AVFormatContext *ctx;
3230  AVStream *st;
3231  char *ipaddr;
3232  URLContext *h = NULL;
3233  uint8_t *dummy_buf;
3234  int max_packet_size;
3235 
3236  /* now we can open the relevant output stream */
3237  ctx = avformat_alloc_context();
3238  if (!ctx)
3239  return -1;
3240  ctx->oformat = av_guess_format("rtp", NULL, NULL);
3241 
3242  st = av_mallocz(sizeof(AVStream));
3243  if (!st)
3244  goto fail;
3245  ctx->nb_streams = 1;
3246  ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3247  if (!ctx->streams)
3248  goto fail;
3249  ctx->streams[0] = st;
3250 
3251  if (!c->stream->feed ||
3252  c->stream->feed == c->stream)
3253  memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3254  else
3255  memcpy(st,
3256  c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3257  sizeof(AVStream));
3258  st->priv_data = NULL;
3259 
3260  /* build destination RTP address */
3261  ipaddr = inet_ntoa(dest_addr->sin_addr);
3262 
3263  switch(c->rtp_protocol) {
3266  /* RTP/UDP case */
3267 
3268  /* XXX: also pass as parameter to function ? */
3269  if (c->stream->is_multicast) {
3270  int ttl;
3271  ttl = c->stream->multicast_ttl;
3272  if (!ttl)
3273  ttl = 16;
3274  snprintf(ctx->filename, sizeof(ctx->filename),
3275  "rtp://%s:%d?multicast=1&ttl=%d",
3276  ipaddr, ntohs(dest_addr->sin_port), ttl);
3277  } else {
3278  snprintf(ctx->filename, sizeof(ctx->filename),
3279  "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3280  }
3281 
3282  if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3283  goto fail;
3284  c->rtp_handles[stream_index] = h;
3285  max_packet_size = h->max_packet_size;
3286  break;
3288  /* RTP/TCP case */
3289  c->rtsp_c = rtsp_c;
3290  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3291  break;
3292  default:
3293  goto fail;
3294  }
3295 
3296  http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3297  ipaddr, ntohs(dest_addr->sin_port),
3298  c->stream->filename, stream_index, c->protocol);
3299 
3300  /* normally, no packets should be output here, but the packet size may
3301  * be checked */
3302  if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3303  /* XXX: close stream */
3304  goto fail;
3305  }
3306  if (avformat_write_header(ctx, NULL) < 0) {
3307  fail:
3308  if (h)
3309  ffurl_close(h);
3310  av_free(st);
3311  av_free(ctx);
3312  return -1;
3313  }
3314  avio_close_dyn_buf(ctx->pb, &dummy_buf);
3315  av_free(dummy_buf);
3316 
3317  c->rtp_ctx[stream_index] = ctx;
3318  return 0;
3319 }
3320 
3321 /********************************************************************/
3322 /* ffserver initialization */
3323 
3325 {
3326  AVStream *fst;
3327 
3328  if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3329  return NULL;
3330 
3331  fst = av_mallocz(sizeof(AVStream));
3332  if (!fst)
3333  return NULL;
3334  if (copy) {
3335  fst->codec = avcodec_alloc_context3(codec->codec);
3336  avcodec_copy_context(fst->codec, codec);
3337  } else {
3338  /* live streams must use the actual feed's codec since it may be
3339  * updated later to carry extradata needed by them.
3340  */
3341  fst->codec = codec;
3342  }
3343  fst->priv_data = av_mallocz(sizeof(FeedData));
3344  fst->index = stream->nb_streams;
3345  avpriv_set_pts_info(fst, 33, 1, 90000);
3347  stream->streams[stream->nb_streams++] = fst;
3348  return fst;
3349 }
3350 
3351 /* return the stream number in the feed */
3352 static int add_av_stream(FFServerStream *feed, AVStream *st)
3353 {
3354  AVStream *fst;
3355  AVCodecContext *av, *av1;
3356  int i;
3357 
3358  av = st->codec;
3359  for(i=0;i<feed->nb_streams;i++) {
3360  av1 = feed->streams[i]->codec;
3361  if (av1->codec_id == av->codec_id &&
3362  av1->codec_type == av->codec_type &&
3363  av1->bit_rate == av->bit_rate) {
3364 
3365  switch(av->codec_type) {
3366  case AVMEDIA_TYPE_AUDIO:
3367  if (av1->channels == av->channels &&
3368  av1->sample_rate == av->sample_rate)
3369  return i;
3370  break;
3371  case AVMEDIA_TYPE_VIDEO:
3372  if (av1->width == av->width &&
3373  av1->height == av->height &&
3374  av1->time_base.den == av->time_base.den &&
3375  av1->time_base.num == av->time_base.num &&
3376  av1->gop_size == av->gop_size)
3377  return i;
3378  break;
3379  default:
3380  abort();
3381  }
3382  }
3383  }
3384 
3385  fst = add_av_stream1(feed, av, 0);
3386  if (!fst)
3387  return -1;
3391  return feed->nb_streams - 1;
3392 }
3393 
3394 static void remove_stream(FFServerStream *stream)
3395 {
3396  FFServerStream **ps;
3397  ps = &config.first_stream;
3398  while (*ps) {
3399  if (*ps == stream)
3400  *ps = (*ps)->next;
3401  else
3402  ps = &(*ps)->next;
3403  }
3404 }
3405 
3406 /* specific MPEG4 handling : we extract the raw parameters */
3408 {
3409  int mpeg4_count, i, size;
3410  AVPacket pkt;
3411  AVStream *st;
3412  const uint8_t *p;
3413 
3415 
3416  mpeg4_count = 0;
3417  for(i=0;i<infile->nb_streams;i++) {
3418  st = infile->streams[i];
3419  if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3420  st->codec->extradata_size == 0) {
3421  mpeg4_count++;
3422  }
3423  }
3424  if (!mpeg4_count)
3425  return;
3426 
3427  printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3428  while (mpeg4_count > 0) {
3429  if (av_read_frame(infile, &pkt) < 0)
3430  break;
3431  st = infile->streams[pkt.stream_index];
3432  if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3433  st->codec->extradata_size == 0) {
3434  av_freep(&st->codec->extradata);
3435  /* fill extradata with the header */
3436  /* XXX: we make hard suppositions here ! */
3437  p = pkt.data;
3438  while (p < pkt.data + pkt.size - 4) {
3439  /* stop when vop header is found */
3440  if (p[0] == 0x00 && p[1] == 0x00 &&
3441  p[2] == 0x01 && p[3] == 0xb6) {
3442  size = p - pkt.data;
3443  // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3445  st->codec->extradata_size = size;
3446  memcpy(st->codec->extradata, pkt.data, size);
3447  break;
3448  }
3449  p++;
3450  }
3451  mpeg4_count--;
3452  }
3453  av_free_packet(&pkt);
3454  }
3455 }
3456 
3457 /* compute the needed AVStream for each file */
3458 static void build_file_streams(void)
3459 {
3460  FFServerStream *stream, *stream_next;
3461  int i, ret;
3462 
3463  /* gather all streams */
3464  for(stream = config.first_stream; stream; stream = stream_next) {
3465  AVFormatContext *infile = NULL;
3466  stream_next = stream->next;
3467  if (stream->stream_type == STREAM_TYPE_LIVE &&
3468  !stream->feed) {
3469  /* the stream comes from a file */
3470  /* try to open the file */
3471  /* open stream */
3472  if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3473  /* specific case : if transport stream output to RTP,
3474  we use a raw transport stream reader */
3475  av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3476  }
3477 
3478  if (!stream->feed_filename[0]) {
3479  http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3480  goto fail;
3481  }
3482 
3483  http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3484  if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3485  http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3486  /* remove stream (no need to spend more time on it) */
3487  fail:
3488  remove_stream(stream);
3489  } else {
3490  /* find all the AVStreams inside and reference them in
3491  'stream' */
3492  if (avformat_find_stream_info(infile, NULL) < 0) {
3493  http_log("Could not find codec parameters from '%s'\n",
3494  stream->feed_filename);
3495  avformat_close_input(&infile);
3496  goto fail;
3497  }
3498  extract_mpeg4_header(infile);
3499 
3500  for(i=0;i<infile->nb_streams;i++)
3501  add_av_stream1(stream, infile->streams[i]->codec, 1);
3502 
3503  avformat_close_input(&infile);
3504  }
3505  }
3506  }
3507 }
3508 
3509 /* compute the needed AVStream for each feed */
3510 static void build_feed_streams(void)
3511 {
3512  FFServerStream *stream, *feed;
3513  int i;
3514 
3515  /* gather all streams */
3516  for(stream = config.first_stream; stream; stream = stream->next) {
3517  feed = stream->feed;
3518  if (feed) {
3519  if (stream->is_feed) {
3520  for(i=0;i<stream->nb_streams;i++)
3521  stream->feed_streams[i] = i;
3522  } else {
3523  /* we handle a stream coming from a feed */
3524  for(i=0;i<stream->nb_streams;i++)
3525  stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3526  }
3527  }
3528  }
3529 
3530  /* create feed files if needed */
3531  for(feed = config.first_feed; feed; feed = feed->next_feed) {
3532  int fd;
3533 
3534  if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3535  /* See if it matches */
3536  AVFormatContext *s = NULL;
3537  int matches = 0;
3538 
3539  if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3540  /* set buffer size */
3542  /* Now see if it matches */
3543  if (s->nb_streams == feed->nb_streams) {
3544  matches = 1;
3545  for(i=0;i<s->nb_streams;i++) {
3546  AVStream *sf, *ss;
3547  sf = feed->streams[i];
3548  ss = s->streams[i];
3549 
3550  if (sf->index != ss->index ||
3551  sf->id != ss->id) {
3552  http_log("Index & Id do not match for stream %d (%s)\n",
3553  i, feed->feed_filename);
3554  matches = 0;
3555  } else {
3556  AVCodecContext *ccf, *ccs;
3557 
3558  ccf = sf->codec;
3559  ccs = ss->codec;
3560 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3561 
3563  http_log("Codecs do not match for stream %d\n", i);
3564  matches = 0;
3565  } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3566  http_log("Codec bitrates do not match for stream %d\n", i);
3567  matches = 0;
3568  } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3569  if (CHECK_CODEC(time_base.den) ||
3570  CHECK_CODEC(time_base.num) ||
3571  CHECK_CODEC(width) ||
3572  CHECK_CODEC(height)) {
3573  http_log("Codec width, height and framerate do not match for stream %d\n", i);
3574  matches = 0;
3575  }
3576  } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3577  if (CHECK_CODEC(sample_rate) ||
3578  CHECK_CODEC(channels) ||
3580  http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3581  matches = 0;
3582  }
3583  } else {
3584  http_log("Unknown codec type\n");
3585  matches = 0;
3586  }
3587  }
3588  if (!matches)
3589  break;
3590  }
3591  } else
3592  http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3593  feed->feed_filename, s->nb_streams, feed->nb_streams);
3594 
3596  } else
3597  http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3598  feed->feed_filename);
3599 
3600  if (!matches) {
3601  if (feed->readonly) {
3602  http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3603  feed->feed_filename);
3604  exit(1);
3605  }
3606  unlink(feed->feed_filename);
3607  }
3608  }
3609  if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3611 
3612  if (feed->readonly) {
3613  http_log("Unable to create feed file '%s' as it is marked readonly\n",
3614  feed->feed_filename);
3615  exit(1);
3616  }
3617 
3618  /* only write the header of the ffm file */
3619  if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3620  http_log("Could not open output feed file '%s'\n",
3621  feed->feed_filename);
3622  exit(1);
3623  }
3624  s->oformat = feed->fmt;
3625  s->nb_streams = feed->nb_streams;
3626  s->streams = feed->streams;
3627  if (avformat_write_header(s, NULL) < 0) {
3628  http_log("Container doesn't support the required parameters\n");
3629  exit(1);
3630  }
3631  /* XXX: need better API */
3632  av_freep(&s->priv_data);
3633  avio_closep(&s->pb);
3634  s->streams = NULL;
3635  s->nb_streams = 0;
3637  }
3638  /* get feed size and write index */
3639  fd = open(feed->feed_filename, O_RDONLY);
3640  if (fd < 0) {
3641  http_log("Could not open output feed file '%s'\n",
3642  feed->feed_filename);
3643  exit(1);
3644  }
3645 
3647  feed->feed_size = lseek(fd, 0, SEEK_END);
3648  /* ensure that we do not wrap before the end of file */
3649  if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3650  feed->feed_max_size = feed->feed_size;
3651 
3652  close(fd);
3653  }
3654 }
3655 
3656 /* compute the bandwidth used by each stream */
3657 static void compute_bandwidth(void)
3658 {
3659  unsigned bandwidth;
3660  int i;
3661  FFServerStream *stream;
3662 
3663  for(stream = config.first_stream; stream; stream = stream->next) {
3664  bandwidth = 0;
3665  for(i=0;i<stream->nb_streams;i++) {
3666  AVStream *st = stream->streams[i];
3667  switch(st->codec->codec_type) {
3668  case AVMEDIA_TYPE_AUDIO:
3669  case AVMEDIA_TYPE_VIDEO:
3670  bandwidth += st->codec->bit_rate;
3671  break;
3672  default:
3673  break;
3674  }
3675  }
3676  stream->bandwidth = (bandwidth + 999) / 1000;
3677  }
3678 }
3679 
3680 static void handle_child_exit(int sig)
3681 {
3682  pid_t pid;
3683  int status;
3684 
3685  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3686  FFServerStream *feed;
3687 
3688  for (feed = config.first_feed; feed; feed = feed->next) {
3689  if (feed->pid == pid) {
3690  int uptime = time(0) - feed->pid_start;
3691 
3692  feed->pid = 0;
3693  fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3694 
3695  if (uptime < 30)
3696  /* Turn off any more restarts */
3698  }
3699  }
3700  }
3701 
3703 }
3704 
3705 static void opt_debug(void)
3706 {
3707  config.debug = 1;
3708  snprintf(config.logfilename, sizeof(config.logfilename), "-");
3709 }
3710 
3711 void show_help_default(const char *opt, const char *arg)
3712 {
3713  printf("usage: ffserver [options]\n"
3714  "Hyper fast multi format Audio/Video streaming server\n");
3715  printf("\n");
3716  show_help_options(options, "Main options:", 0, 0, 0);
3717 }
3718 
3719 static const OptionDef options[] = {
3720 #include "cmdutils_common_opts.h"
3721  { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3722  { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3723  { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3724  { NULL },
3725 };
3726 
3727 int main(int argc, char **argv)
3728 {
3729  struct sigaction sigact = { { 0 } };
3730  int ret = 0;
3731 
3732  config.filename = av_strdup("/etc/ffserver.conf");
3733 
3734  parse_loglevel(argc, argv, options);
3735  av_register_all();
3737 
3738  show_banner(argc, argv, options);
3739 
3740  my_program_name = argv[0];
3741 
3742  parse_options(NULL, argc, argv, options, NULL);
3743 
3744  unsetenv("http_proxy"); /* Kill the http_proxy */
3745 
3746  av_lfg_init(&random_state, av_get_random_seed());
3747 
3748  sigact.sa_handler = handle_child_exit;
3749  sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3750  sigaction(SIGCHLD, &sigact, 0);
3751 
3752  if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3753  fprintf(stderr, "Error reading configuration file '%s': %s\n",
3754  config.filename, av_err2str(ret));
3755  exit(1);
3756  }
3757  av_freep(&config.filename);
3758 
3759  /* open log file if needed */
3760  if (config.logfilename[0] != '\0') {
3761  if (!strcmp(config.logfilename, "-"))
3762  logfile = stdout;
3763  else
3764  logfile = fopen(config.logfilename, "a");
3766  }
3767 
3769 
3771 
3773 
3774  /* signal init */
3775  signal(SIGPIPE, SIG_IGN);
3776 
3777  if (http_server() < 0) {
3778  http_log("Could not start server\n");
3779  exit(1);
3780  }
3781 
3782  return 0;
3783 }