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