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", input_filename, av_err2str(ret));
2059  return ret;
2060  }
2061 
2062  /* set buffer size */
2063  if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2064 
2065  s->flags |= AVFMT_FLAG_GENPTS;
2066  c->fmt_in = s;
2067  if (strcmp(s->iformat->name, "ffm") &&
2068  (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2069  http_log("Could not find stream info for input '%s'\n", input_filename);
2071  return ret;
2072  }
2073 
2074  /* choose stream as clock source (we favor the video stream if
2075  * present) for packet sending */
2076  c->pts_stream_index = 0;
2077  for(i=0;i<c->stream->nb_streams;i++) {
2078  if (c->pts_stream_index == 0 &&
2080  c->pts_stream_index = i;
2081  }
2082  }
2083 
2084  if (c->fmt_in->iformat->read_seek)
2085  av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2086  /* set the start time (needed for maxtime and RTP packet timing) */
2087  c->start_time = cur_time;
2089  return 0;
2090 }
2091 
2092 /* return the server clock (in us) */
2094 {
2095  /* compute current pts value from system time */
2096  return (cur_time - c->start_time) * 1000;
2097 }
2098 
2099 /* return the estimated time at which the current packet must be sent
2100  (in us) */
2102 {
2103  int bytes_left, bytes_sent, frame_bytes;
2104 
2105  frame_bytes = c->cur_frame_bytes;
2106  if (frame_bytes <= 0)
2107  return c->cur_pts;
2108  else {
2109  bytes_left = c->buffer_end - c->buffer_ptr;
2110  bytes_sent = frame_bytes - bytes_left;
2111  return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2112  }
2113 }
2114 
2115 
2117 {
2118  int i, len, ret;
2119  AVFormatContext *ctx;
2120 
2121  av_freep(&c->pb_buffer);
2122  switch(c->state) {
2124  ctx = avformat_alloc_context();
2125  c->fmt_ctx = *ctx;
2126  av_freep(&ctx);
2127  av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2129 
2130  for(i=0;i<c->stream->nb_streams;i++) {
2131  AVStream *src;
2132  c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2133  /* if file or feed, then just take streams from FFServerStream struct */
2134  if (!c->stream->feed ||
2135  c->stream->feed == c->stream)
2136  src = c->stream->streams[i];
2137  else
2138  src = c->stream->feed->streams[c->stream->feed_streams[i]];
2139 
2140  *(c->fmt_ctx.streams[i]) = *src;
2141  c->fmt_ctx.streams[i]->priv_data = 0;
2142  /* XXX: should be done in AVStream, not in codec */
2143  c->fmt_ctx.streams[i]->codec->frame_number = 0;
2144  }
2145  /* set output format parameters */
2146  c->fmt_ctx.oformat = c->stream->fmt;
2148 
2149  c->got_key_frame = 0;
2150 
2151  /* prepare header and save header data in a stream */
2152  if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2153  /* XXX: potential leak */
2154  return -1;
2155  }
2156  c->fmt_ctx.pb->seekable = 0;
2157 
2158  /*
2159  * HACK to avoid MPEG-PS muxer to spit many underflow errors
2160  * Default value from FFmpeg
2161  * Try to set it using configuration option
2162  */
2163  c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2164 
2165  if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2166  http_log("Error writing output header for stream '%s': %s\n",
2167  c->stream->filename, av_err2str(ret));
2168  return ret;
2169  }
2171 
2172  len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2173  c->buffer_ptr = c->pb_buffer;
2174  c->buffer_end = c->pb_buffer + len;
2175 
2177  c->last_packet_sent = 0;
2178  break;
2179  case HTTPSTATE_SEND_DATA:
2180  /* find a new packet */
2181  /* read a packet from the input stream */
2182  if (c->stream->feed)
2185  c->stream->feed->feed_size);
2186 
2187  if (c->stream->max_time &&
2188  c->stream->max_time + c->start_time - cur_time < 0)
2189  /* We have timed out */
2191  else {
2192  AVPacket pkt;
2193  redo:
2194  ret = av_read_frame(c->fmt_in, &pkt);
2195  if (ret < 0) {
2196  if (c->stream->feed) {
2197  /* if coming from feed, it means we reached the end of the
2198  ffm file, so must wait for more data */
2200  return 1; /* state changed */
2201  } else if (ret == AVERROR(EAGAIN)) {
2202  /* input not ready, come back later */
2203  return 0;
2204  } else {
2205  if (c->stream->loop) {
2207  if (open_input_stream(c, "") < 0)
2208  goto no_loop;
2209  goto redo;
2210  } else {
2211  no_loop:
2212  /* must send trailer now because EOF or error */
2214  }
2215  }
2216  } else {
2217  int source_index = pkt.stream_index;
2218  /* update first pts if needed */
2219  if (c->first_pts == AV_NOPTS_VALUE) {
2221  c->start_time = cur_time;
2222  }
2223  /* send it to the appropriate stream */
2224  if (c->stream->feed) {
2225  /* if coming from a feed, select the right stream */
2226  if (c->switch_pending) {
2227  c->switch_pending = 0;
2228  for(i=0;i<c->stream->nb_streams;i++) {
2229  if (c->switch_feed_streams[i] == pkt.stream_index)
2230  if (pkt.flags & AV_PKT_FLAG_KEY)
2231  c->switch_feed_streams[i] = -1;
2232  if (c->switch_feed_streams[i] >= 0)
2233  c->switch_pending = 1;
2234  }
2235  }
2236  for(i=0;i<c->stream->nb_streams;i++) {
2237  if (c->stream->feed_streams[i] == pkt.stream_index) {
2238  AVStream *st = c->fmt_in->streams[source_index];
2239  pkt.stream_index = i;
2240  if (pkt.flags & AV_PKT_FLAG_KEY &&
2241  (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2242  c->stream->nb_streams == 1))
2243  c->got_key_frame = 1;
2244  if (!c->stream->send_on_key || c->got_key_frame)
2245  goto send_it;
2246  }
2247  }
2248  } else {
2249  AVCodecContext *codec;
2250  AVStream *ist, *ost;
2251  send_it:
2252  ist = c->fmt_in->streams[source_index];
2253  /* specific handling for RTP: we use several
2254  * output streams (one for each RTP connection).
2255  * XXX: need more abstract handling */
2256  if (c->is_packetized) {
2257  /* compute send time and duration */
2258  c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2259  c->cur_pts -= c->first_pts;
2261  /* find RTP context */
2263  ctx = c->rtp_ctx[c->packet_stream_index];
2264  if(!ctx) {
2265  av_free_packet(&pkt);
2266  break;
2267  }
2268  codec = ctx->streams[0]->codec;
2269  /* only one stream per RTP connection */
2270  pkt.stream_index = 0;
2271  } else {
2272  ctx = &c->fmt_ctx;
2273  /* Fudge here */
2274  codec = ctx->streams[pkt.stream_index]->codec;
2275  }
2276 
2277  if (c->is_packetized) {
2278  int max_packet_size;
2280  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2281  else
2282  max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2283  ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2284  } else {
2285  ret = avio_open_dyn_buf(&ctx->pb);
2286  }
2287  if (ret < 0) {
2288  /* XXX: potential leak */
2289  return -1;
2290  }
2291  ost = ctx->streams[pkt.stream_index];
2292 
2293  ctx->pb->seekable = 0;
2294  if (pkt.dts != AV_NOPTS_VALUE)
2295  pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2296  if (pkt.pts != AV_NOPTS_VALUE)
2297  pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2298  pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2299  if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2300  http_log("Error writing frame to output for stream '%s': %s\n",
2301  c->stream->filename, av_err2str(ret));
2303  }
2304 
2305  av_freep(&c->pb_buffer);
2306  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2307  c->cur_frame_bytes = len;
2308  c->buffer_ptr = c->pb_buffer;
2309  c->buffer_end = c->pb_buffer + len;
2310 
2311  codec->frame_number++;
2312  if (len == 0) {
2313  av_free_packet(&pkt);
2314  goto redo;
2315  }
2316  }
2317  av_free_packet(&pkt);
2318  }
2319  }
2320  break;
2321  default:
2323  /* last packet test ? */
2324  if (c->last_packet_sent || c->is_packetized)
2325  return -1;
2326  ctx = &c->fmt_ctx;
2327  /* prepare header */
2328  if (avio_open_dyn_buf(&ctx->pb) < 0) {
2329  /* XXX: potential leak */
2330  return -1;
2331  }
2332  c->fmt_ctx.pb->seekable = 0;
2333  av_write_trailer(ctx);
2334  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2335  c->buffer_ptr = c->pb_buffer;
2336  c->buffer_end = c->pb_buffer + len;
2337 
2338  c->last_packet_sent = 1;
2339  break;
2340  }
2341  return 0;
2342 }
2343 
2344 /* should convert the format at the same time */
2345 /* send data starting at c->buffer_ptr to the output connection
2346  * (either UDP or TCP) */
2348 {
2349  int len, ret;
2350 
2351  for(;;) {
2352  if (c->buffer_ptr >= c->buffer_end) {
2353  ret = http_prepare_data(c);
2354  if (ret < 0)
2355  return -1;
2356  else if (ret)
2357  /* state change requested */
2358  break;
2359  } else {
2360  if (c->is_packetized) {
2361  /* RTP data output */
2362  len = c->buffer_end - c->buffer_ptr;
2363  if (len < 4) {
2364  /* fail safe - should never happen */
2365  fail1:
2366  c->buffer_ptr = c->buffer_end;
2367  return 0;
2368  }
2369  len = (c->buffer_ptr[0] << 24) |
2370  (c->buffer_ptr[1] << 16) |
2371  (c->buffer_ptr[2] << 8) |
2372  (c->buffer_ptr[3]);
2373  if (len > (c->buffer_end - c->buffer_ptr))
2374  goto fail1;
2375  if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2376  /* nothing to send yet: we can wait */
2377  return 0;
2378  }
2379 
2380  c->data_count += len;
2382  if (c->stream)
2383  c->stream->bytes_served += len;
2384 
2386  /* RTP packets are sent inside the RTSP TCP connection */
2387  AVIOContext *pb;
2388  int interleaved_index, size;
2389  uint8_t header[4];
2390  HTTPContext *rtsp_c;
2391 
2392  rtsp_c = c->rtsp_c;
2393  /* if no RTSP connection left, error */
2394  if (!rtsp_c)
2395  return -1;
2396  /* if already sending something, then wait. */
2397  if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2398  break;
2399  if (avio_open_dyn_buf(&pb) < 0)
2400  goto fail1;
2401  interleaved_index = c->packet_stream_index * 2;
2402  /* RTCP packets are sent at odd indexes */
2403  if (c->buffer_ptr[1] == 200)
2404  interleaved_index++;
2405  /* write RTSP TCP header */
2406  header[0] = '$';
2407  header[1] = interleaved_index;
2408  header[2] = len >> 8;
2409  header[3] = len;
2410  avio_write(pb, header, 4);
2411  /* write RTP packet data */
2412  c->buffer_ptr += 4;
2413  avio_write(pb, c->buffer_ptr, len);
2414  size = avio_close_dyn_buf(pb, &c->packet_buffer);
2415  /* prepare asynchronous TCP sending */
2416  rtsp_c->packet_buffer_ptr = c->packet_buffer;
2417  rtsp_c->packet_buffer_end = c->packet_buffer + size;
2418  c->buffer_ptr += len;
2419 
2420  /* send everything we can NOW */
2421  len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2422  rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2423  if (len > 0)
2424  rtsp_c->packet_buffer_ptr += len;
2425  if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2426  /* if we could not send all the data, we will
2427  send it later, so a new state is needed to
2428  "lock" the RTSP TCP connection */
2429  rtsp_c->state = RTSPSTATE_SEND_PACKET;
2430  break;
2431  } else
2432  /* all data has been sent */
2433  av_freep(&c->packet_buffer);
2434  } else {
2435  /* send RTP packet directly in UDP */
2436  c->buffer_ptr += 4;
2438  c->buffer_ptr, len);
2439  c->buffer_ptr += len;
2440  /* here we continue as we can send several packets per 10 ms slot */
2441  }
2442  } else {
2443  /* TCP data output */
2444  len = send(c->fd, c->buffer_ptr,
2445  c->buffer_end - c->buffer_ptr, 0);
2446  if (len < 0) {
2447  if (ff_neterrno() != AVERROR(EAGAIN) &&
2448  ff_neterrno() != AVERROR(EINTR))
2449  /* error : close connection */
2450  return -1;
2451  else
2452  return 0;
2453  }
2454  c->buffer_ptr += len;
2455 
2456  c->data_count += len;
2458  if (c->stream)
2459  c->stream->bytes_served += len;
2460  break;
2461  }
2462  }
2463  } /* for(;;) */
2464  return 0;
2465 }
2466 
2468 {
2469  int fd;
2470  int ret;
2471 
2472  if (c->stream->feed_opened) {
2473  http_log("Stream feed '%s' was not opened\n",
2474  c->stream->feed_filename);
2475  return AVERROR(EINVAL);
2476  }
2477 
2478  /* Don't permit writing to this one */
2479  if (c->stream->readonly) {
2480  http_log("Cannot write to read-only file '%s'\n",
2481  c->stream->feed_filename);
2482  return AVERROR(EINVAL);
2483  }
2484 
2485  /* open feed */
2486  fd = open(c->stream->feed_filename, O_RDWR);
2487  if (fd < 0) {
2488  ret = AVERROR(errno);
2489  http_log("Could not open feed file '%s': %s\n",
2490  c->stream->feed_filename, strerror(errno));
2491  return ret;
2492  }
2493  c->feed_fd = fd;
2494 
2495  if (c->stream->truncate) {
2496  /* truncate feed file */
2498  http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2499  if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2500  ret = AVERROR(errno);
2501  http_log("Error truncating feed file '%s': %s\n",
2502  c->stream->feed_filename, strerror(errno));
2503  return ret;
2504  }
2505  } else {
2506  ret = ffm_read_write_index(fd);
2507  if (ret < 0) {
2508  http_log("Error reading write index from feed file '%s': %s\n",
2509  c->stream->feed_filename, strerror(errno));
2510  return ret;
2511  } else {
2512  c->stream->feed_write_index = ret;
2513  }
2514  }
2515 
2517  FFM_PACKET_SIZE);
2518  c->stream->feed_size = lseek(fd, 0, SEEK_END);
2519  lseek(fd, 0, SEEK_SET);
2520 
2521  /* init buffer input */
2522  c->buffer_ptr = c->buffer;
2523  c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2524  c->stream->feed_opened = 1;
2525  c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2526  return 0;
2527 }
2528 
2530 {
2531  HTTPContext *c1;
2532  int len, loop_run = 0;
2533 
2534  while (c->chunked_encoding && !c->chunk_size &&
2535  c->buffer_end > c->buffer_ptr) {
2536  /* read chunk header, if present */
2537  len = recv(c->fd, c->buffer_ptr, 1, 0);
2538 
2539  if (len < 0) {
2540  if (ff_neterrno() != AVERROR(EAGAIN) &&
2541  ff_neterrno() != AVERROR(EINTR))
2542  /* error : close connection */
2543  goto fail;
2544  return 0;
2545  } else if (len == 0) {
2546  /* end of connection : close it */
2547  goto fail;
2548  } else if (c->buffer_ptr - c->buffer >= 2 &&
2549  !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2550  c->chunk_size = strtol(c->buffer, 0, 16);
2551  if (c->chunk_size == 0) // end of stream
2552  goto fail;
2553  c->buffer_ptr = c->buffer;
2554  break;
2555  } else if (++loop_run > 10) {
2556  /* no chunk header, abort */
2557  goto fail;
2558  } else {
2559  c->buffer_ptr++;
2560  }
2561  }
2562 
2563  if (c->buffer_end > c->buffer_ptr) {
2564  len = recv(c->fd, c->buffer_ptr,
2565  FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2566  if (len < 0) {
2567  if (ff_neterrno() != AVERROR(EAGAIN) &&
2568  ff_neterrno() != AVERROR(EINTR))
2569  /* error : close connection */
2570  goto fail;
2571  } else if (len == 0)
2572  /* end of connection : close it */
2573  goto fail;
2574  else {
2575  c->chunk_size -= len;
2576  c->buffer_ptr += len;
2577  c->data_count += len;
2579  }
2580  }
2581 
2582  if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2583  if (c->buffer[0] != 'f' ||
2584  c->buffer[1] != 'm') {
2585  http_log("Feed stream has become desynchronized -- disconnecting\n");
2586  goto fail;
2587  }
2588  }
2589 
2590  if (c->buffer_ptr >= c->buffer_end) {
2591  FFServerStream *feed = c->stream;
2592  /* a packet has been received : write it in the store, except
2593  if header */
2594  if (c->data_count > FFM_PACKET_SIZE) {
2595  /* XXX: use llseek or url_seek
2596  * XXX: Should probably fail? */
2597  if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2598  http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2599 
2600  if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2601  http_log("Error writing to feed file: %s\n", strerror(errno));
2602  goto fail;
2603  }
2604 
2606  /* update file size */
2607  if (feed->feed_write_index > c->stream->feed_size)
2608  feed->feed_size = feed->feed_write_index;
2609 
2610  /* handle wrap around if max file size reached */
2611  if (c->stream->feed_max_size &&
2612  feed->feed_write_index >= c->stream->feed_max_size)
2614 
2615  /* write index */
2616  if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2617  http_log("Error writing index to feed file: %s\n",
2618  strerror(errno));
2619  goto fail;
2620  }
2621 
2622  /* wake up any waiting connections */
2623  for(c1 = first_http_ctx; c1; c1 = c1->next) {
2624  if (c1->state == HTTPSTATE_WAIT_FEED &&
2625  c1->stream->feed == c->stream->feed)
2626  c1->state = HTTPSTATE_SEND_DATA;
2627  }
2628  } else {
2629  /* We have a header in our hands that contains useful data */
2631  AVIOContext *pb;
2632  AVInputFormat *fmt_in;
2633  int i;
2634 
2635  if (!s)
2636  goto fail;
2637 
2638  /* use feed output format name to find corresponding input format */
2639  fmt_in = av_find_input_format(feed->fmt->name);
2640  if (!fmt_in)
2641  goto fail;
2642 
2643  pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2644  0, NULL, NULL, NULL, NULL);
2645  pb->seekable = 0;
2646 
2647  s->pb = pb;
2648  if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2649  av_freep(&pb);
2650  goto fail;
2651  }
2652 
2653  /* Now we have the actual streams */
2654  if (s->nb_streams != feed->nb_streams) {
2656  av_freep(&pb);
2657  http_log("Feed '%s' stream number does not match registered feed\n",
2658  c->stream->feed_filename);
2659  goto fail;
2660  }
2661 
2662  for (i = 0; i < s->nb_streams; i++) {
2663  AVStream *fst = feed->streams[i];
2664  AVStream *st = s->streams[i];
2665  avcodec_copy_context(fst->codec, st->codec);
2666  }
2667 
2669  av_freep(&pb);
2670  }
2671  c->buffer_ptr = c->buffer;
2672  }
2673 
2674  return 0;
2675  fail:
2676  c->stream->feed_opened = 0;
2677  close(c->feed_fd);
2678  /* wake up any waiting connections to stop waiting for feed */
2679  for(c1 = first_http_ctx; c1; c1 = c1->next) {
2680  if (c1->state == HTTPSTATE_WAIT_FEED &&
2681  c1->stream->feed == c->stream->feed)
2683  }
2684  return -1;
2685 }
2686 
2687 /********************************************************************/
2688 /* RTSP handling */
2689 
2690 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2691 {
2692  const char *str;
2693  time_t ti;
2694  struct tm *tm;
2695  char buf2[32];
2696 
2697  str = RTSP_STATUS_CODE2STRING(error_number);
2698  if (!str)
2699  str = "Unknown Error";
2700 
2701  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2702  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2703 
2704  /* output GMT time */
2705  ti = time(NULL);
2706  tm = gmtime(&ti);
2707  strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2708  avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2709 }
2710 
2711 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2712 {
2713  rtsp_reply_header(c, error_number);
2714  avio_printf(c->pb, "\r\n");
2715 }
2716 
2718 {
2719  const char *p, *p1, *p2;
2720  char cmd[32];
2721  char url[1024];
2722  char protocol[32];
2723  char line[1024];
2724  int len;
2725  RTSPMessageHeader header1 = { 0 }, *header = &header1;
2726 
2727  c->buffer_ptr[0] = '\0';
2728  p = c->buffer;
2729 
2730  get_word(cmd, sizeof(cmd), &p);
2731  get_word(url, sizeof(url), &p);
2732  get_word(protocol, sizeof(protocol), &p);
2733 
2734  av_strlcpy(c->method, cmd, sizeof(c->method));
2735  av_strlcpy(c->url, url, sizeof(c->url));
2736  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2737 
2738  if (avio_open_dyn_buf(&c->pb) < 0) {
2739  /* XXX: cannot do more */
2740  c->pb = NULL; /* safety */
2741  return -1;
2742  }
2743 
2744  /* check version name */
2745  if (strcmp(protocol, "RTSP/1.0")) {
2747  goto the_end;
2748  }
2749 
2750  /* parse each header line */
2751  /* skip to next line */
2752  while (*p != '\n' && *p != '\0')
2753  p++;
2754  if (*p == '\n')
2755  p++;
2756  while (*p != '\0') {
2757  p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2758  if (!p1)
2759  break;
2760  p2 = p1;
2761  if (p2 > p && p2[-1] == '\r')
2762  p2--;
2763  /* skip empty line */
2764  if (p2 == p)
2765  break;
2766  len = p2 - p;
2767  if (len > sizeof(line) - 1)
2768  len = sizeof(line) - 1;
2769  memcpy(line, p, len);
2770  line[len] = '\0';
2772  p = p1 + 1;
2773  }
2774 
2775  /* handle sequence number */
2776  c->seq = header->seq;
2777 
2778  if (!strcmp(cmd, "DESCRIBE"))
2779  rtsp_cmd_describe(c, url);
2780  else if (!strcmp(cmd, "OPTIONS"))
2781  rtsp_cmd_options(c, url);
2782  else if (!strcmp(cmd, "SETUP"))
2783  rtsp_cmd_setup(c, url, header);
2784  else if (!strcmp(cmd, "PLAY"))
2785  rtsp_cmd_play(c, url, header);
2786  else if (!strcmp(cmd, "PAUSE"))
2787  rtsp_cmd_interrupt(c, url, header, 1);
2788  else if (!strcmp(cmd, "TEARDOWN"))
2789  rtsp_cmd_interrupt(c, url, header, 0);
2790  else
2792 
2793  the_end:
2794  len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2795  c->pb = NULL; /* safety */
2796  if (len < 0) {
2797  /* XXX: cannot do more */
2798  return -1;
2799  }
2800  c->buffer_ptr = c->pb_buffer;
2801  c->buffer_end = c->pb_buffer + len;
2803  return 0;
2804 }
2805 
2806 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2807  struct in_addr my_ip)
2808 {
2809  AVFormatContext *avc;
2810  AVStream *avs = NULL;
2811  AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2812  AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2813  int i;
2814 
2815  *pbuffer = NULL;
2816 
2817  avc = avformat_alloc_context();
2818  if (!avc || !rtp_format) {
2819  return -1;
2820  }
2821  avc->oformat = rtp_format;
2822  av_dict_set(&avc->metadata, "title",
2823  entry ? entry->value : "No Title", 0);
2824  avc->nb_streams = stream->nb_streams;
2825  if (stream->is_multicast) {
2826  snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2827  inet_ntoa(stream->multicast_ip),
2828  stream->multicast_port, stream->multicast_ttl);
2829  } else {
2830  snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2831  }
2832 
2833  if (!(avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams))))
2834  goto sdp_done;
2835  if (!(avs = av_malloc_array(avc->nb_streams, sizeof(*avs))))
2836  goto sdp_done;
2837 
2838  for(i = 0; i < stream->nb_streams; i++) {
2839  avc->streams[i] = &avs[i];
2840  avc->streams[i]->codec = stream->streams[i]->codec;
2841  }
2842  *pbuffer = av_mallocz(2048);
2843  av_sdp_create(&avc, 1, *pbuffer, 2048);
2844 
2845  sdp_done:
2846  av_freep(&avc->streams);
2847  av_dict_free(&avc->metadata);
2848  av_free(avc);
2849  av_free(avs);
2850 
2851  return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2852 }
2853 
2854 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2855 {
2856 // rtsp_reply_header(c, RTSP_STATUS_OK);
2857  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2858  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2859  avio_printf(c->pb, "Public: %s\r\n",
2860  "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2861  avio_printf(c->pb, "\r\n");
2862 }
2863 
2864 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2865 {
2866  FFServerStream *stream;
2867  char path1[1024];
2868  const char *path;
2869  uint8_t *content;
2870  int content_length;
2871  socklen_t len;
2872  struct sockaddr_in my_addr;
2873 
2874  /* find which URL is asked */
2875  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2876  path = path1;
2877  if (*path == '/')
2878  path++;
2879 
2880  for(stream = config.first_stream; stream; stream = stream->next) {
2881  if (!stream->is_feed &&
2882  stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2883  !strcmp(path, stream->filename)) {
2884  goto found;
2885  }
2886  }
2887  /* no stream found */
2889  return;
2890 
2891  found:
2892  /* prepare the media description in SDP format */
2893 
2894  /* get the host IP */
2895  len = sizeof(my_addr);
2896  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2897  content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2898  if (content_length < 0) {
2900  return;
2901  }
2903  avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2904  avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2905  avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2906  avio_printf(c->pb, "\r\n");
2907  avio_write(c->pb, content, content_length);
2908  av_free(content);
2909 }
2910 
2911 static HTTPContext *find_rtp_session(const char *session_id)
2912 {
2913  HTTPContext *c;
2914 
2915  if (session_id[0] == '\0')
2916  return NULL;
2917 
2918  for(c = first_http_ctx; c; c = c->next) {
2919  if (!strcmp(c->session_id, session_id))
2920  return c;
2921  }
2922  return NULL;
2923 }
2924 
2926 {
2928  int i;
2929 
2930  for(i=0;i<h->nb_transports;i++) {
2931  th = &h->transports[i];
2932  if (th->lower_transport == lower_transport)
2933  return th;
2934  }
2935  return NULL;
2936 }
2937 
2938 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2939  RTSPMessageHeader *h)
2940 {
2941  FFServerStream *stream;
2942  int stream_index, rtp_port, rtcp_port;
2943  char buf[1024];
2944  char path1[1024];
2945  const char *path;
2946  HTTPContext *rtp_c;
2948  struct sockaddr_in dest_addr;
2949  RTSPActionServerSetup setup;
2950 
2951  /* find which URL is asked */
2952  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2953  path = path1;
2954  if (*path == '/')
2955  path++;
2956 
2957  /* now check each stream */
2958  for(stream = config.first_stream; stream; stream = stream->next) {
2959  if (stream->is_feed || !stream->fmt ||
2960  strcmp(stream->fmt->name, "rtp")) {
2961  continue;
2962  }
2963  /* accept aggregate filenames only if single stream */
2964  if (!strcmp(path, stream->filename)) {
2965  if (stream->nb_streams != 1) {
2967  return;
2968  }
2969  stream_index = 0;
2970  goto found;
2971  }
2972 
2973  for(stream_index = 0; stream_index < stream->nb_streams;
2974  stream_index++) {
2975  snprintf(buf, sizeof(buf), "%s/streamid=%d",
2976  stream->filename, stream_index);
2977  if (!strcmp(path, buf))
2978  goto found;
2979  }
2980  }
2981  /* no stream found */
2982  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2983  return;
2984  found:
2985 
2986  /* generate session id if needed */
2987  if (h->session_id[0] == '\0') {
2988  unsigned random0 = av_lfg_get(&random_state);
2989  unsigned random1 = av_lfg_get(&random_state);
2990  snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2991  random0, random1);
2992  }
2993 
2994  /* find RTP session, and create it if none found */
2995  rtp_c = find_rtp_session(h->session_id);
2996  if (!rtp_c) {
2997  /* always prefer UDP */
2999  if (!th) {
3001  if (!th) {
3003  return;
3004  }
3005  }
3006 
3007  rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3008  th->lower_transport);
3009  if (!rtp_c) {
3011  return;
3012  }
3013 
3014  /* open input stream */
3015  if (open_input_stream(rtp_c, "") < 0) {
3017  return;
3018  }
3019  }
3020 
3021  /* test if stream is OK (test needed because several SETUP needs
3022  to be done for a given file) */
3023  if (rtp_c->stream != stream) {
3025  return;
3026  }
3027 
3028  /* test if stream is already set up */
3029  if (rtp_c->rtp_ctx[stream_index]) {
3031  return;
3032  }
3033 
3034  /* check transport */
3035  th = find_transport(h, rtp_c->rtp_protocol);
3036  if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3037  th->client_port_min <= 0)) {
3039  return;
3040  }
3041 
3042  /* setup default options */
3043  setup.transport_option[0] = '\0';
3044  dest_addr = rtp_c->from_addr;
3045  dest_addr.sin_port = htons(th->client_port_min);
3046 
3047  /* setup stream */
3048  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3050  return;
3051  }
3052 
3053  /* now everything is OK, so we can send the connection parameters */
3055  /* session ID */
3056  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3057 
3058  switch(rtp_c->rtp_protocol) {
3060  rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3061  rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3062  avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3063  "client_port=%d-%d;server_port=%d-%d",
3065  rtp_port, rtcp_port);
3066  break;
3068  avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3069  stream_index * 2, stream_index * 2 + 1);
3070  break;
3071  default:
3072  break;
3073  }
3074  if (setup.transport_option[0] != '\0')
3075  avio_printf(c->pb, ";%s", setup.transport_option);
3076  avio_printf(c->pb, "\r\n");
3077 
3078 
3079  avio_printf(c->pb, "\r\n");
3080 }
3081 
3082 
3083 /* find an RTP connection by using the session ID. Check consistency
3084  with filename */
3085 static HTTPContext *find_rtp_session_with_url(const char *url,
3086  const char *session_id)
3087 {
3088  HTTPContext *rtp_c;
3089  char path1[1024];
3090  const char *path;
3091  char buf[1024];
3092  int s, len;
3093 
3094  rtp_c = find_rtp_session(session_id);
3095  if (!rtp_c)
3096  return NULL;
3097 
3098  /* find which URL is asked */
3099  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3100  path = path1;
3101  if (*path == '/')
3102  path++;
3103  if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3104  for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3105  snprintf(buf, sizeof(buf), "%s/streamid=%d",
3106  rtp_c->stream->filename, s);
3107  if(!strncmp(path, buf, sizeof(buf))) {
3108  // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3109  return rtp_c;
3110  }
3111  }
3112  len = strlen(path);
3113  if (len > 0 && path[len - 1] == '/' &&
3114  !strncmp(path, rtp_c->stream->filename, len - 1))
3115  return rtp_c;
3116  return NULL;
3117 }
3118 
3119 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3120 {
3121  HTTPContext *rtp_c;
3122 
3123  rtp_c = find_rtp_session_with_url(url, h->session_id);
3124  if (!rtp_c) {
3126  return;
3127  }
3128 
3129  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3130  rtp_c->state != HTTPSTATE_WAIT_FEED &&
3131  rtp_c->state != HTTPSTATE_READY) {
3133  return;
3134  }
3135 
3136  rtp_c->state = HTTPSTATE_SEND_DATA;
3137 
3138  /* now everything is OK, so we can send the connection parameters */
3140  /* session ID */
3141  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3142  avio_printf(c->pb, "\r\n");
3143 }
3144 
3145 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
3146  RTSPMessageHeader *h, int pause_only)
3147 {
3148  HTTPContext *rtp_c;
3149 
3150  rtp_c = find_rtp_session_with_url(url, h->session_id);
3151  if (!rtp_c) {
3153  return;
3154  }
3155 
3156  if (pause_only) {
3157  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3158  rtp_c->state != HTTPSTATE_WAIT_FEED) {
3160  return;
3161  }
3162  rtp_c->state = HTTPSTATE_READY;
3163  rtp_c->first_pts = AV_NOPTS_VALUE;
3164  }
3165 
3166  /* now everything is OK, so we can send the connection parameters */
3168  /* session ID */
3169  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3170  avio_printf(c->pb, "\r\n");
3171 
3172  if (!pause_only)
3173  close_connection(rtp_c);
3174 }
3175 
3176 /********************************************************************/
3177 /* RTP handling */
3178 
3179 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3180  FFServerStream *stream,
3181  const char *session_id,
3182  enum RTSPLowerTransport rtp_protocol)
3183 {
3184  HTTPContext *c = NULL;
3185  const char *proto_str;
3186 
3187  /* XXX: should output a warning page when coming
3188  close to the connection limit */
3189  if (nb_connections >= config.nb_max_connections)
3190  goto fail;
3191 
3192  /* add a new connection */
3193  c = av_mallocz(sizeof(HTTPContext));
3194  if (!c)
3195  goto fail;
3196 
3197  c->fd = -1;
3198  c->poll_entry = NULL;
3199  c->from_addr = *from_addr;
3201  c->buffer = av_malloc(c->buffer_size);
3202  if (!c->buffer)
3203  goto fail;
3204  nb_connections++;
3205  c->stream = stream;
3206  av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3207  c->state = HTTPSTATE_READY;
3208  c->is_packetized = 1;
3209  c->rtp_protocol = rtp_protocol;
3210 
3211  /* protocol is shown in statistics */
3212  switch(c->rtp_protocol) {
3214  proto_str = "MCAST";
3215  break;
3217  proto_str = "UDP";
3218  break;
3220  proto_str = "TCP";
3221  break;
3222  default:
3223  proto_str = "???";
3224  break;
3225  }
3226  av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3227  av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3228 
3229  current_bandwidth += stream->bandwidth;
3230 
3231  c->next = first_http_ctx;
3232  first_http_ctx = c;
3233  return c;
3234 
3235  fail:
3236  if (c) {
3237  av_freep(&c->buffer);
3238  av_free(c);
3239  }
3240  return NULL;
3241 }
3242 
3243 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3244  command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3245  used. */
3247  int stream_index, struct sockaddr_in *dest_addr,
3248  HTTPContext *rtsp_c)
3249 {
3250  AVFormatContext *ctx;
3251  AVStream *st;
3252  char *ipaddr;
3253  URLContext *h = NULL;
3254  uint8_t *dummy_buf;
3255  int max_packet_size;
3256 
3257  /* now we can open the relevant output stream */
3258  ctx = avformat_alloc_context();
3259  if (!ctx)
3260  return -1;
3261  ctx->oformat = av_guess_format("rtp", NULL, NULL);
3262 
3263  st = av_mallocz(sizeof(AVStream));
3264  if (!st)
3265  goto fail;
3266  ctx->nb_streams = 1;
3267  ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3268  if (!ctx->streams)
3269  goto fail;
3270  ctx->streams[0] = st;
3271 
3272  if (!c->stream->feed ||
3273  c->stream->feed == c->stream)
3274  memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3275  else
3276  memcpy(st,
3277  c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3278  sizeof(AVStream));
3279  st->priv_data = NULL;
3280 
3281  /* build destination RTP address */
3282  ipaddr = inet_ntoa(dest_addr->sin_addr);
3283 
3284  switch(c->rtp_protocol) {
3287  /* RTP/UDP case */
3288 
3289  /* XXX: also pass as parameter to function ? */
3290  if (c->stream->is_multicast) {
3291  int ttl;
3292  ttl = c->stream->multicast_ttl;
3293  if (!ttl)
3294  ttl = 16;
3295  snprintf(ctx->filename, sizeof(ctx->filename),
3296  "rtp://%s:%d?multicast=1&ttl=%d",
3297  ipaddr, ntohs(dest_addr->sin_port), ttl);
3298  } else {
3299  snprintf(ctx->filename, sizeof(ctx->filename),
3300  "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3301  }
3302 
3303  if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3304  goto fail;
3305  c->rtp_handles[stream_index] = h;
3306  max_packet_size = h->max_packet_size;
3307  break;
3309  /* RTP/TCP case */
3310  c->rtsp_c = rtsp_c;
3311  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3312  break;
3313  default:
3314  goto fail;
3315  }
3316 
3317  http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3318  ipaddr, ntohs(dest_addr->sin_port),
3319  c->stream->filename, stream_index, c->protocol);
3320 
3321  /* normally, no packets should be output here, but the packet size may
3322  * be checked */
3323  if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3324  /* XXX: close stream */
3325  goto fail;
3326  }
3327  if (avformat_write_header(ctx, NULL) < 0) {
3328  fail:
3329  if (h)
3330  ffurl_close(h);
3331  av_free(st);
3332  av_free(ctx);
3333  return -1;
3334  }
3335  avio_close_dyn_buf(ctx->pb, &dummy_buf);
3336  av_free(dummy_buf);
3337 
3338  c->rtp_ctx[stream_index] = ctx;
3339  return 0;
3340 }
3341 
3342 /********************************************************************/
3343 /* ffserver initialization */
3344 
3346  AVCodecContext *codec, int copy)
3347 {
3348  AVStream *fst;
3349 
3350  if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3351  return NULL;
3352 
3353  fst = av_mallocz(sizeof(AVStream));
3354  if (!fst)
3355  return NULL;
3356  if (copy) {
3357  fst->codec = avcodec_alloc_context3(codec->codec);
3358  avcodec_copy_context(fst->codec, codec);
3359  } else {
3360  /* live streams must use the actual feed's codec since it may be
3361  * updated later to carry extradata needed by them.
3362  */
3363  fst->codec = codec;
3364  }
3365  fst->priv_data = av_mallocz(sizeof(FeedData));
3366  fst->index = stream->nb_streams;
3367  avpriv_set_pts_info(fst, 33, 1, 90000);
3369  stream->streams[stream->nb_streams++] = fst;
3370  return fst;
3371 }
3372 
3373 /* return the stream number in the feed */
3374 static int add_av_stream(FFServerStream *feed, AVStream *st)
3375 {
3376  AVStream *fst;
3377  AVCodecContext *av, *av1;
3378  int i;
3379 
3380  av = st->codec;
3381  for(i=0;i<feed->nb_streams;i++) {
3382  av1 = feed->streams[i]->codec;
3383  if (av1->codec_id == av->codec_id &&
3384  av1->codec_type == av->codec_type &&
3385  av1->bit_rate == av->bit_rate) {
3386 
3387  switch(av->codec_type) {
3388  case AVMEDIA_TYPE_AUDIO:
3389  if (av1->channels == av->channels &&
3390  av1->sample_rate == av->sample_rate)
3391  return i;
3392  break;
3393  case AVMEDIA_TYPE_VIDEO:
3394  if (av1->width == av->width &&
3395  av1->height == av->height &&
3396  av1->time_base.den == av->time_base.den &&
3397  av1->time_base.num == av->time_base.num &&
3398  av1->gop_size == av->gop_size)
3399  return i;
3400  break;
3401  default:
3402  abort();
3403  }
3404  }
3405  }
3406 
3407  fst = add_av_stream1(feed, av, 0);
3408  if (!fst)
3409  return -1;
3413  return feed->nb_streams - 1;
3414 }
3415 
3416 static void remove_stream(FFServerStream *stream)
3417 {
3418  FFServerStream **ps;
3419  ps = &config.first_stream;
3420  while (*ps) {
3421  if (*ps == stream)
3422  *ps = (*ps)->next;
3423  else
3424  ps = &(*ps)->next;
3425  }
3426 }
3427 
3428 /* specific MPEG4 handling : we extract the raw parameters */
3430 {
3431  int mpeg4_count, i, size;
3432  AVPacket pkt;
3433  AVStream *st;
3434  const uint8_t *p;
3435 
3437 
3438  mpeg4_count = 0;
3439  for(i=0;i<infile->nb_streams;i++) {
3440  st = infile->streams[i];
3441  if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3442  st->codec->extradata_size == 0) {
3443  mpeg4_count++;
3444  }
3445  }
3446  if (!mpeg4_count)
3447  return;
3448 
3449  printf("MPEG4 without extra data: trying to find header in %s\n",
3450  infile->filename);
3451  while (mpeg4_count > 0) {
3452  if (av_read_frame(infile, &pkt) < 0)
3453  break;
3454  st = infile->streams[pkt.stream_index];
3455  if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3456  st->codec->extradata_size == 0) {
3457  av_freep(&st->codec->extradata);
3458  /* fill extradata with the header */
3459  /* XXX: we make hard suppositions here ! */
3460  p = pkt.data;
3461  while (p < pkt.data + pkt.size - 4) {
3462  /* stop when vop header is found */
3463  if (p[0] == 0x00 && p[1] == 0x00 &&
3464  p[2] == 0x01 && p[3] == 0xb6) {
3465  size = p - pkt.data;
3466  // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3468  st->codec->extradata_size = size;
3469  memcpy(st->codec->extradata, pkt.data, size);
3470  break;
3471  }
3472  p++;
3473  }
3474  mpeg4_count--;
3475  }
3476  av_free_packet(&pkt);
3477  }
3478 }
3479 
3480 /* compute the needed AVStream for each file */
3481 static void build_file_streams(void)
3482 {
3483  FFServerStream *stream, *stream_next;
3484  int i, ret;
3485 
3486  /* gather all streams */
3487  for(stream = config.first_stream; stream; stream = stream_next) {
3488  AVFormatContext *infile = NULL;
3489  stream_next = stream->next;
3490  if (stream->stream_type == STREAM_TYPE_LIVE &&
3491  !stream->feed) {
3492  /* the stream comes from a file */
3493  /* try to open the file */
3494  /* open stream */
3495  if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3496  /* specific case : if transport stream output to RTP,
3497  we use a raw transport stream reader */
3498  av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3499  }
3500 
3501  if (!stream->feed_filename[0]) {
3502  http_log("Unspecified feed file for stream '%s'\n",
3503  stream->filename);
3504  goto fail;
3505  }
3506 
3507  http_log("Opening feed file '%s' for stream '%s'\n",
3508  stream->feed_filename, stream->filename);
3509  ret = avformat_open_input(&infile, stream->feed_filename,
3510  stream->ifmt, &stream->in_opts);
3511  if (ret < 0) {
3512  http_log("Could not open '%s': %s\n", stream->feed_filename,
3513  av_err2str(ret));
3514  /* remove stream (no need to spend more time on it) */
3515  fail:
3516  remove_stream(stream);
3517  } else {
3518  /* find all the AVStreams inside and reference them in
3519  'stream' */
3520  if (avformat_find_stream_info(infile, NULL) < 0) {
3521  http_log("Could not find codec parameters from '%s'\n",
3522  stream->feed_filename);
3523  avformat_close_input(&infile);
3524  goto fail;
3525  }
3526  extract_mpeg4_header(infile);
3527 
3528  for(i=0;i<infile->nb_streams;i++)
3529  add_av_stream1(stream, infile->streams[i]->codec, 1);
3530 
3531  avformat_close_input(&infile);
3532  }
3533  }
3534  }
3535 }
3536 
3537 /* compute the needed AVStream for each feed */
3538 static void build_feed_streams(void)
3539 {
3540  FFServerStream *stream, *feed;
3541  int i;
3542 
3543  /* gather all streams */
3544  for(stream = config.first_stream; stream; stream = stream->next) {
3545  feed = stream->feed;
3546  if (feed) {
3547  if (stream->is_feed) {
3548  for(i=0;i<stream->nb_streams;i++)
3549  stream->feed_streams[i] = i;
3550  } else {
3551  /* we handle a stream coming from a feed */
3552  for(i=0;i<stream->nb_streams;i++)
3553  stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3554  }
3555  }
3556  }
3557 
3558  /* create feed files if needed */
3559  for(feed = config.first_feed; feed; feed = feed->next_feed) {
3560  int fd;
3561 
3562  if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3563  /* See if it matches */
3564  AVFormatContext *s = NULL;
3565  int matches = 0;
3566 
3567  if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3568  /* set buffer size */
3570  /* Now see if it matches */
3571  if (s->nb_streams == feed->nb_streams) {
3572  matches = 1;
3573  for(i=0;i<s->nb_streams;i++) {
3574  AVStream *sf, *ss;
3575  sf = feed->streams[i];
3576  ss = s->streams[i];
3577 
3578  if (sf->index != ss->index ||
3579  sf->id != ss->id) {
3580  http_log("Index & Id do not match for stream %d (%s)\n",
3581  i, feed->feed_filename);
3582  matches = 0;
3583  } else {
3584  AVCodecContext *ccf, *ccs;
3585 
3586  ccf = sf->codec;
3587  ccs = ss->codec;
3588 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3589 
3591  http_log("Codecs do not match for stream %d\n", i);
3592  matches = 0;
3593  } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3594  http_log("Codec bitrates do not match for stream %d\n", i);
3595  matches = 0;
3596  } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3597  if (CHECK_CODEC(time_base.den) ||
3598  CHECK_CODEC(time_base.num) ||
3599  CHECK_CODEC(width) ||
3600  CHECK_CODEC(height)) {
3601  http_log("Codec width, height and framerate do not match for stream %d\n", i);
3602  matches = 0;
3603  }
3604  } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3605  if (CHECK_CODEC(sample_rate) ||
3606  CHECK_CODEC(channels) ||
3608  http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3609  matches = 0;
3610  }
3611  } else {
3612  http_log("Unknown codec type\n");
3613  matches = 0;
3614  }
3615  }
3616  if (!matches)
3617  break;
3618  }
3619  } else
3620  http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3621  feed->feed_filename, s->nb_streams, feed->nb_streams);
3622 
3624  } else
3625  http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3626  feed->feed_filename);
3627 
3628  if (!matches) {
3629  if (feed->readonly) {
3630  http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3631  feed->feed_filename);
3632  exit(1);
3633  }
3634  unlink(feed->feed_filename);
3635  }
3636  }
3637  if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3639 
3640  if (feed->readonly) {
3641  http_log("Unable to create feed file '%s' as it is marked readonly\n",
3642  feed->feed_filename);
3643  exit(1);
3644  }
3645 
3646  /* only write the header of the ffm file */
3647  if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3648  http_log("Could not open output feed file '%s'\n",
3649  feed->feed_filename);
3650  exit(1);
3651  }
3652  s->oformat = feed->fmt;
3653  s->nb_streams = feed->nb_streams;
3654  s->streams = feed->streams;
3655  if (avformat_write_header(s, NULL) < 0) {
3656  http_log("Container doesn't support the required parameters\n");
3657  exit(1);
3658  }
3659  /* XXX: need better API */
3660  av_freep(&s->priv_data);
3661  avio_closep(&s->pb);
3662  s->streams = NULL;
3663  s->nb_streams = 0;
3665  }
3666  /* get feed size and write index */
3667  fd = open(feed->feed_filename, O_RDONLY);
3668  if (fd < 0) {
3669  http_log("Could not open output feed file '%s'\n",
3670  feed->feed_filename);
3671  exit(1);
3672  }
3673 
3675  feed->feed_size = lseek(fd, 0, SEEK_END);
3676  /* ensure that we do not wrap before the end of file */
3677  if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3678  feed->feed_max_size = feed->feed_size;
3679 
3680  close(fd);
3681  }
3682 }
3683 
3684 /* compute the bandwidth used by each stream */
3685 static void compute_bandwidth(void)
3686 {
3687  unsigned bandwidth;
3688  int i;
3689  FFServerStream *stream;
3690 
3691  for(stream = config.first_stream; stream; stream = stream->next) {
3692  bandwidth = 0;
3693  for(i=0;i<stream->nb_streams;i++) {
3694  AVStream *st = stream->streams[i];
3695  switch(st->codec->codec_type) {
3696  case AVMEDIA_TYPE_AUDIO:
3697  case AVMEDIA_TYPE_VIDEO:
3698  bandwidth += st->codec->bit_rate;
3699  break;
3700  default:
3701  break;
3702  }
3703  }
3704  stream->bandwidth = (bandwidth + 999) / 1000;
3705  }
3706 }
3707 
3708 static void handle_child_exit(int sig)
3709 {
3710  pid_t pid;
3711  int status;
3712 
3713  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3714  FFServerStream *feed;
3715 
3716  for (feed = config.first_feed; feed; feed = feed->next) {
3717  if (feed->pid == pid) {
3718  int uptime = time(0) - feed->pid_start;
3719 
3720  feed->pid = 0;
3721  fprintf(stderr,
3722  "%s: Pid %d exited with status %d after %d seconds\n",
3723  feed->filename, pid, status, uptime);
3724 
3725  if (uptime < 30)
3726  /* Turn off any more restarts */
3728  }
3729  }
3730  }
3731 
3733 }
3734 
3735 static void opt_debug(void)
3736 {
3737  config.debug = 1;
3738  snprintf(config.logfilename, sizeof(config.logfilename), "-");
3739 }
3740 
3741 void show_help_default(const char *opt, const char *arg)
3742 {
3743  printf("usage: ffserver [options]\n"
3744  "Hyper fast multi format Audio/Video streaming server\n");
3745  printf("\n");
3746  show_help_options(options, "Main options:", 0, 0, 0);
3747 }
3748 
3749 static const OptionDef options[] = {
3750 #include "cmdutils_common_opts.h"
3751  { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3752  { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3753  { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3754  { NULL },
3755 };
3756 
3757 int main(int argc, char **argv)
3758 {
3759  struct sigaction sigact = { { 0 } };
3760  int ret = 0;
3761 
3762  config.filename = av_strdup("/etc/ffserver.conf");
3763 
3764  parse_loglevel(argc, argv, options);
3765  av_register_all();
3767 
3768  show_banner(argc, argv, options);
3769 
3770  my_program_name = argv[0];
3771 
3772  parse_options(NULL, argc, argv, options, NULL);
3773 
3774  unsetenv("http_proxy"); /* Kill the http_proxy */
3775 
3776  av_lfg_init(&random_state, av_get_random_seed());
3777 
3778  sigact.sa_handler = handle_child_exit;
3779  sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3780  sigaction(SIGCHLD, &sigact, 0);
3781 
3782  if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3783  fprintf(stderr, "Error reading configuration file '%s': %s\n",
3784  config.filename, av_err2str(ret));
3785  exit(1);
3786  }
3787  av_freep(&config.filename);
3788 
3789  /* open log file if needed */
3790  if (config.logfilename[0] != '\0') {
3791  if (!strcmp(config.logfilename, "-"))
3792  logfile = stdout;
3793  else
3794  logfile = fopen(config.logfilename, "a");
3796  }
3797 
3799 
3801 
3803 
3804  /* signal init */
3805  signal(SIGPIPE, SIG_IGN);
3806 
3807  if (http_server() < 0) {
3808  http_log("Could not start server\n");
3809  exit(1);
3810  }
3811 
3812  return 0;
3813 }