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