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