Libav
avserver.c
Go to the documentation of this file.
1 /*
2  * Multiple format streaming server
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "config.h"
23 #if !HAVE_CLOSESOCKET
24 #define closesocket close
25 #endif
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include "libavformat/avformat.h"
30 // FIXME those are internal headers, avserver _really_ shouldn't use them
31 #include "libavformat/ffm.h"
32 #include "libavformat/network.h"
33 #include "libavformat/os_support.h"
34 #include "libavformat/rtpdec.h"
35 #include "libavformat/rtpproto.h"
36 #include "libavformat/rtsp.h"
38 #include "libavformat/internal.h"
39 #include "libavformat/url.h"
40 
41 #include "libavutil/avstring.h"
42 #include "libavutil/lfg.h"
43 #include "libavutil/dict.h"
44 #include "libavutil/intreadwrite.h"
45 #include "libavutil/mathematics.h"
46 #include "libavutil/random_seed.h"
47 #include "libavutil/parseutils.h"
48 #include "libavutil/opt.h"
49 #include "libavutil/time.h"
50 
51 #include <stdarg.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54 #include <sys/ioctl.h>
55 #if HAVE_POLL_H
56 #include <poll.h>
57 #endif
58 #include <errno.h>
59 #include <time.h>
60 #include <sys/wait.h>
61 #include <signal.h>
62 
63 #include "cmdutils.h"
64 
65 const char program_name[] = "avserver";
66 const int program_birth_year = 2000;
67 
68 static const OptionDef options[];
69 
70 enum HTTPState {
74  HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
77  HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
79 
83 };
84 
85 static const char *http_state[] = {
86  "HTTP_WAIT_REQUEST",
87  "HTTP_SEND_HEADER",
88 
89  "SEND_DATA_HEADER",
90  "SEND_DATA",
91  "SEND_DATA_TRAILER",
92  "RECEIVE_DATA",
93  "WAIT_FEED",
94  "READY",
95 
96  "RTSP_WAIT_REQUEST",
97  "RTSP_SEND_REPLY",
98  "RTSP_SEND_PACKET",
99 };
100 
101 #define MAX_STREAMS 20
102 
103 #define IOBUFFER_INIT_SIZE 8192
104 
105 /* timeouts are in ms */
106 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
107 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
108 
109 #define SYNC_TIMEOUT (10 * 1000)
110 
111 typedef struct RTSPActionServerSetup {
112  uint32_t ipaddr;
113  char transport_option[512];
115 
116 typedef struct {
117  int64_t count1, count2;
118  int64_t time1, time2;
119 } DataRateData;
120 
121 /* context associated with one connection */
122 typedef struct HTTPContext {
124  int fd; /* socket file descriptor */
125  struct sockaddr_in from_addr; /* origin */
126  struct pollfd *poll_entry; /* used when polling */
127  int64_t timeout;
130  int post;
132  int chunk_size; /* 0 if it needs to be read */
133  struct HTTPContext *next;
134  int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
135  int64_t data_count;
136  /* feed input */
137  int feed_fd;
138  /* input format handling */
140  int64_t start_time; /* In milliseconds - this wraps fairly often */
141  int64_t first_pts; /* initial pts value */
142  int64_t cur_pts; /* current pts value from the stream in us */
143  int64_t cur_frame_duration; /* duration of the current frame in us */
144  int cur_frame_bytes; /* output frame size, needed to compute
145  the time at which we send each
146  packet */
147  int pts_stream_index; /* stream we choose as clock reference */
148  int64_t cur_clock; /* current clock reference value in us */
149  /* output format handling */
150  struct FFStream *stream;
151  /* -1 is invalid stream */
152  int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
153  int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
155  AVFormatContext fmt_ctx; /* instance of FFStream for one user */
156  int last_packet_sent; /* true if last data packet was sent */
160  char protocol[16];
161  char method[16];
162  char url[128];
165  int is_packetized; /* if true, the stream is packetized */
166  int packet_stream_index; /* current stream for output in state machine */
167 
168  /* RTSP state specific */
169  uint8_t *pb_buffer; /* XXX: use that in all the code */
171  int seq; /* RTSP sequence number */
172 
173  /* RTP state specific */
175  char session_id[32]; /* session id */
177 
178  /* RTP/UDP specific */
180 
181  /* RTP/TCP specific */
184 } HTTPContext;
185 
186 /* each generated stream is described here */
191 };
192 
194  IP_ALLOW = 1,
196 };
197 
198 typedef struct IPAddressACL {
201  /* These are in host order */
202  struct in_addr first;
203  struct in_addr last;
204 } IPAddressACL;
205 
206 /* description of each stream of the avserver.conf file */
207 typedef struct FFStream {
209  char filename[1024]; /* stream filename */
210  struct FFStream *feed; /* feed we are using (can be null if
211  coming from file) */
212  AVDictionary *in_opts; /* input parameters */
213  AVInputFormat *ifmt; /* if non NULL, force input format */
216  char dynamic_acl[1024];
218  int prebuffer; /* Number of millseconds early to start */
219  int64_t max_time; /* Number of milliseconds to run */
222  int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
223  char feed_filename[1024]; /* file name of the feed storage, or
224  input file name for a stream */
225  char author[512];
226  char title[512];
227  char copyright[512];
228  char comment[512];
229  pid_t pid; /* of avconv process */
230  time_t pid_start; /* of avconv process */
231  char **child_argv;
232  struct FFStream *next;
233  unsigned bandwidth; /* bandwidth, in kbits/s */
234  /* RTSP options */
235  char *rtsp_option;
236  /* multicast specific */
238  struct in_addr multicast_ip;
239  int multicast_port; /* first port used for multicast */
241  int loop; /* if true, send the stream in loops (only meaningful if file) */
242 
243  /* feed specific */
244  int feed_opened; /* true if someone is writing to the feed */
245  int is_feed; /* true if it is a feed */
246  int readonly; /* True if writing is prohibited to the file */
247  int truncate; /* True if feeder connection truncate the feed file */
249  int64_t bytes_served;
250  int64_t feed_max_size; /* maximum storage size, zero means unlimited */
251  int64_t feed_write_index; /* current write position in feed (it wraps around) */
252  int64_t feed_size; /* current size of feed */
254 } FFStream;
255 
256 typedef struct FeedData {
257  long long data_count;
258  float avg_frame_size; /* frame size averaged over last frames with exponential mean */
259 } FeedData;
260 
261 static struct sockaddr_in my_http_addr;
262 static struct sockaddr_in my_rtsp_addr;
263 
264 static char logfilename[1024];
266 static FFStream *first_feed; /* contains only feeds */
267 static FFStream *first_stream; /* contains all streams, including feeds */
268 
269 static void new_connection(int server_fd, int is_rtsp);
270 static void close_connection(HTTPContext *c);
271 
272 /* HTTP handling */
273 static int handle_connection(HTTPContext *c);
274 static int http_parse_request(HTTPContext *c);
275 static int http_send_data(HTTPContext *c);
276 static void compute_status(HTTPContext *c);
277 static int open_input_stream(HTTPContext *c, const char *info);
278 static int http_start_receive_data(HTTPContext *c);
279 static int http_receive_data(HTTPContext *c);
280 
281 /* RTSP handling */
282 static int rtsp_parse_request(HTTPContext *c);
283 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
284 static void rtsp_cmd_options(HTTPContext *c, const char *url);
285 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
288 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
289 
290 /* SDP handling */
291 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
292  struct in_addr my_ip);
293 
294 /* RTP handling */
295 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
296  FFStream *stream, const char *session_id,
297  enum RTSPLowerTransport rtp_protocol);
298 static int rtp_new_av_stream(HTTPContext *c,
299  int stream_index, struct sockaddr_in *dest_addr,
300  HTTPContext *rtsp_c);
301 
302 static const char *my_program_name;
303 
304 static const char *config_filename;
305 
306 static int avserver_debug;
307 static int no_launch;
309 
310 /* maximum number of simultaneous HTTP connections */
311 static unsigned int nb_max_http_connections = 2000;
312 static unsigned int nb_max_connections = 5;
313 static unsigned int nb_connections;
314 
315 static uint64_t max_bandwidth = 1000;
316 static uint64_t current_bandwidth;
317 
318 static int64_t cur_time; // Making this global saves on passing it around everywhere
319 
321 
322 static FILE *logfile = NULL;
323 
324 static int64_t ffm_read_write_index(int fd)
325 {
326  uint8_t buf[8];
327 
328  lseek(fd, 8, SEEK_SET);
329  if (read(fd, buf, 8) != 8)
330  return AVERROR(EIO);
331  return AV_RB64(buf);
332 }
333 
334 static int ffm_write_write_index(int fd, int64_t pos)
335 {
336  uint8_t buf[8];
337  int i;
338 
339  for(i=0;i<8;i++)
340  buf[i] = (pos >> (56 - i * 8)) & 0xff;
341  lseek(fd, 8, SEEK_SET);
342  if (write(fd, buf, 8) != 8)
343  return AVERROR(EIO);
344  return 8;
345 }
346 
347 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
348  int64_t file_size)
349 {
350  FFMContext *ffm = s->priv_data;
351  ffm->write_index = pos;
352  ffm->file_size = file_size;
353 }
354 
355 /* FIXME: make avserver work with IPv6 */
356 /* resolve host with also IP address parsing */
357 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
358 {
359 
360  if (!ff_inet_aton(hostname, sin_addr)) {
361 #if HAVE_GETADDRINFO
362  struct addrinfo *ai, *cur;
363  struct addrinfo hints = { 0 };
364  hints.ai_family = AF_INET;
365  if (getaddrinfo(hostname, NULL, &hints, &ai))
366  return -1;
367  /* getaddrinfo returns a linked list of addrinfo structs.
368  * Even if we set ai_family = AF_INET above, make sure
369  * that the returned one actually is of the correct type. */
370  for (cur = ai; cur; cur = cur->ai_next) {
371  if (cur->ai_family == AF_INET) {
372  *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
373  freeaddrinfo(ai);
374  return 0;
375  }
376  }
377  freeaddrinfo(ai);
378  return -1;
379 #else
380  struct hostent *hp;
381  hp = gethostbyname(hostname);
382  if (!hp)
383  return -1;
384  memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
385 #endif
386  }
387  return 0;
388 }
389 
390 static char *ctime1(char *buf2)
391 {
392  time_t ti;
393  char *p;
394 
395  ti = time(NULL);
396  p = ctime(&ti);
397  strcpy(buf2, p);
398  p = buf2 + strlen(p) - 1;
399  if (*p == '\n')
400  *p = '\0';
401  return buf2;
402 }
403 
404 static void http_vlog(const char *fmt, va_list vargs)
405 {
406  static int print_prefix = 1;
407  if (logfile) {
408  if (print_prefix) {
409  char buf[32];
410  ctime1(buf);
411  fprintf(logfile, "%s ", buf);
412  }
413  print_prefix = strstr(fmt, "\n") != NULL;
414  vfprintf(logfile, fmt, vargs);
415  fflush(logfile);
416  }
417 }
418 
419 #ifdef __GNUC__
420 __attribute__ ((format (printf, 1, 2)))
421 #endif
422 static void http_log(const char *fmt, ...)
423 {
424  va_list vargs;
425  va_start(vargs, fmt);
426  http_vlog(fmt, vargs);
427  va_end(vargs);
428 }
429 
430 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
431 {
432  static int print_prefix = 1;
433  AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
434  if (level > av_log_get_level())
435  return;
436  if (print_prefix && avc)
437  http_log("[%s @ %p]", avc->item_name(ptr), ptr);
438  print_prefix = strstr(fmt, "\n") != NULL;
439  http_vlog(fmt, vargs);
440 }
441 
443 {
444  if (c->suppress_log)
445  return;
446 
447  http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
448  inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
449  c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
450 }
451 
452 static void update_datarate(DataRateData *drd, int64_t count)
453 {
454  if (!drd->time1 && !drd->count1) {
455  drd->time1 = drd->time2 = cur_time;
456  drd->count1 = drd->count2 = count;
457  } else if (cur_time - drd->time2 > 5000) {
458  drd->time1 = drd->time2;
459  drd->count1 = drd->count2;
460  drd->time2 = cur_time;
461  drd->count2 = count;
462  }
463 }
464 
465 /* In bytes per second */
466 static int compute_datarate(DataRateData *drd, int64_t count)
467 {
468  if (cur_time == drd->time1)
469  return 0;
470 
471  return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
472 }
473 
474 
475 static void start_children(FFStream *feed)
476 {
477  if (no_launch)
478  return;
479 
480  for (; feed; feed = feed->next) {
481  if (feed->child_argv && !feed->pid) {
482  feed->pid_start = time(0);
483 
484  feed->pid = fork();
485 
486  if (feed->pid < 0) {
487  http_log("Unable to create children\n");
488  exit(1);
489  }
490  if (!feed->pid) {
491  /* In child */
492  char pathname[1024];
493  char *slash;
494  int i;
495 
496  av_strlcpy(pathname, my_program_name, sizeof(pathname));
497 
498  slash = strrchr(pathname, '/');
499  if (!slash)
500  slash = pathname;
501  else
502  slash++;
503  strcpy(slash, "avconv");
504 
505  http_log("Launch command line: ");
506  http_log("%s ", pathname);
507  for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
508  http_log("%s ", feed->child_argv[i]);
509  http_log("\n");
510 
511  for (i = 3; i < 256; i++)
512  close(i);
513 
514  if (!avserver_debug) {
515  if (!freopen("/dev/null", "r", stdin))
516  http_log("failed to redirect STDIN to /dev/null\n;");
517  if (!freopen("/dev/null", "w", stdout))
518  http_log("failed to redirect STDOUT to /dev/null\n;");
519  if (!freopen("/dev/null", "w", stderr))
520  http_log("failed to redirect STDERR to /dev/null\n;");
521  }
522 
523  signal(SIGPIPE, SIG_DFL);
524 
525  execvp(pathname, feed->child_argv);
526 
527  _exit(1);
528  }
529  }
530  }
531 }
532 
533 /* open a listening socket */
534 static int socket_open_listen(struct sockaddr_in *my_addr)
535 {
536  int server_fd, tmp;
537 
538  server_fd = socket(AF_INET,SOCK_STREAM,0);
539  if (server_fd < 0) {
540  perror ("socket");
541  return -1;
542  }
543 
544  tmp = 1;
545  setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
546 
547  my_addr->sin_family = AF_INET;
548  if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
549  char bindmsg[32];
550  snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
551  perror (bindmsg);
552  closesocket(server_fd);
553  return -1;
554  }
555 
556  if (listen (server_fd, 5) < 0) {
557  perror ("listen");
558  closesocket(server_fd);
559  return -1;
560  }
561  ff_socket_nonblock(server_fd, 1);
562 
563  return server_fd;
564 }
565 
566 /* start all multicast streams */
567 static void start_multicast(void)
568 {
569  FFStream *stream;
570  char session_id[32];
571  HTTPContext *rtp_c;
572  struct sockaddr_in dest_addr;
573  int default_port, stream_index;
574 
575  default_port = 6000;
576  for(stream = first_stream; stream != NULL; stream = stream->next) {
577  if (stream->is_multicast) {
578  /* open the RTP connection */
579  snprintf(session_id, sizeof(session_id), "%08x%08x",
580  av_lfg_get(&random_state), av_lfg_get(&random_state));
581 
582  /* choose a port if none given */
583  if (stream->multicast_port == 0) {
584  stream->multicast_port = default_port;
585  default_port += 100;
586  }
587 
588  dest_addr.sin_family = AF_INET;
589  dest_addr.sin_addr = stream->multicast_ip;
590  dest_addr.sin_port = htons(stream->multicast_port);
591 
592  rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
594  if (!rtp_c)
595  continue;
596 
597  if (open_input_stream(rtp_c, "") < 0) {
598  http_log("Could not open input stream for stream '%s'\n",
599  stream->filename);
600  continue;
601  }
602 
603  /* open each RTP stream */
604  for(stream_index = 0; stream_index < stream->nb_streams;
605  stream_index++) {
606  dest_addr.sin_port = htons(stream->multicast_port +
607  2 * stream_index);
608  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
609  http_log("Could not open output stream '%s/streamid=%d'\n",
610  stream->filename, stream_index);
611  exit(1);
612  }
613  }
614 
615  /* change state to send data */
616  rtp_c->state = HTTPSTATE_SEND_DATA;
617  }
618  }
619 }
620 
621 /* main loop of the http server */
622 static int http_server(void)
623 {
624  int server_fd = 0, rtsp_server_fd = 0;
625  int ret, delay, delay1;
626  struct pollfd *poll_table, *poll_entry;
627  HTTPContext *c, *c_next;
628 
629  if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
630  http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
631  return -1;
632  }
633 
634  if (my_http_addr.sin_port) {
635  server_fd = socket_open_listen(&my_http_addr);
636  if (server_fd < 0)
637  return -1;
638  }
639 
640  if (my_rtsp_addr.sin_port) {
641  rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
642  if (rtsp_server_fd < 0)
643  return -1;
644  }
645 
646  if (!rtsp_server_fd && !server_fd) {
647  http_log("HTTP and RTSP disabled.\n");
648  return -1;
649  }
650 
651  http_log("AVserver started.\n");
652 
653  start_children(first_feed);
654 
655  start_multicast();
656 
657  for(;;) {
658  poll_entry = poll_table;
659  if (server_fd) {
660  poll_entry->fd = server_fd;
661  poll_entry->events = POLLIN;
662  poll_entry++;
663  }
664  if (rtsp_server_fd) {
665  poll_entry->fd = rtsp_server_fd;
666  poll_entry->events = POLLIN;
667  poll_entry++;
668  }
669 
670  /* wait for events on each HTTP handle */
671  c = first_http_ctx;
672  delay = 1000;
673  while (c != NULL) {
674  int fd;
675  fd = c->fd;
676  switch(c->state) {
680  c->poll_entry = poll_entry;
681  poll_entry->fd = fd;
682  poll_entry->events = POLLOUT;
683  poll_entry++;
684  break;
686  case HTTPSTATE_SEND_DATA:
688  if (!c->is_packetized) {
689  /* for TCP, we output as much as we can (may need to put a limit) */
690  c->poll_entry = poll_entry;
691  poll_entry->fd = fd;
692  poll_entry->events = POLLOUT;
693  poll_entry++;
694  } else {
695  /* when avserver is doing the timing, we work by
696  looking at which packet need to be sent every
697  10 ms */
698  delay1 = 10; /* one tick wait XXX: 10 ms assumed */
699  if (delay1 < delay)
700  delay = delay1;
701  }
702  break;
705  case HTTPSTATE_WAIT_FEED:
707  /* need to catch errors */
708  c->poll_entry = poll_entry;
709  poll_entry->fd = fd;
710  poll_entry->events = POLLIN;/* Maybe this will work */
711  poll_entry++;
712  break;
713  default:
714  c->poll_entry = NULL;
715  break;
716  }
717  c = c->next;
718  }
719 
720  /* wait for an event on one connection. We poll at least every
721  second to handle timeouts */
722  do {
723  ret = poll(poll_table, poll_entry - poll_table, delay);
724  if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
725  ff_neterrno() != AVERROR(EINTR))
726  return -1;
727  } while (ret < 0);
728 
729  cur_time = av_gettime() / 1000;
730 
733  start_children(first_feed);
734  }
735 
736  /* now handle the events */
737  for(c = first_http_ctx; c != NULL; c = c_next) {
738  c_next = c->next;
739  if (handle_connection(c) < 0) {
740  /* close and free the connection */
741  log_connection(c);
742  close_connection(c);
743  }
744  }
745 
746  poll_entry = poll_table;
747  if (server_fd) {
748  /* new HTTP connection request ? */
749  if (poll_entry->revents & POLLIN)
750  new_connection(server_fd, 0);
751  poll_entry++;
752  }
753  if (rtsp_server_fd) {
754  /* new RTSP connection request ? */
755  if (poll_entry->revents & POLLIN)
756  new_connection(rtsp_server_fd, 1);
757  }
758  }
759 }
760 
761 /* start waiting for a new HTTP/RTSP request */
762 static void start_wait_request(HTTPContext *c, int is_rtsp)
763 {
764  c->buffer_ptr = c->buffer;
765  c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
766 
767  if (is_rtsp) {
770  } else {
773  }
774 }
775 
776 static void http_send_too_busy_reply(int fd)
777 {
778  char buffer[300];
779  int len = snprintf(buffer, sizeof(buffer),
780  "HTTP/1.0 503 Server too busy\r\n"
781  "Content-type: text/html\r\n"
782  "\r\n"
783  "<html><head><title>Too busy</title></head><body>\r\n"
784  "<p>The server is too busy to serve your request at this time.</p>\r\n"
785  "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
786  "</body></html>\r\n",
788  send(fd, buffer, len, 0);
789 }
790 
791 
792 static void new_connection(int server_fd, int is_rtsp)
793 {
794  struct sockaddr_in from_addr;
795  socklen_t len;
796  int fd;
797  HTTPContext *c = NULL;
798 
799  len = sizeof(from_addr);
800  fd = accept(server_fd, (struct sockaddr *)&from_addr,
801  &len);
802  if (fd < 0) {
803  http_log("error during accept %s\n", strerror(errno));
804  return;
805  }
806  ff_socket_nonblock(fd, 1);
807 
810  goto fail;
811  }
812 
813  /* add a new connection */
814  c = av_mallocz(sizeof(HTTPContext));
815  if (!c)
816  goto fail;
817 
818  c->fd = fd;
819  c->poll_entry = NULL;
820  c->from_addr = from_addr;
822  c->buffer = av_malloc(c->buffer_size);
823  if (!c->buffer)
824  goto fail;
825 
826  c->next = first_http_ctx;
827  first_http_ctx = c;
828  nb_connections++;
829 
830  start_wait_request(c, is_rtsp);
831 
832  return;
833 
834  fail:
835  if (c) {
836  av_free(c->buffer);
837  av_free(c);
838  }
839  closesocket(fd);
840 }
841 
843 {
844  HTTPContext **cp, *c1;
845  int i, nb_streams;
846  AVFormatContext *ctx;
847  URLContext *h;
848  AVStream *st;
849 
850  /* remove connection from list */
851  cp = &first_http_ctx;
852  while ((*cp) != NULL) {
853  c1 = *cp;
854  if (c1 == c)
855  *cp = c->next;
856  else
857  cp = &c1->next;
858  }
859 
860  /* remove references, if any (XXX: do it faster) */
861  for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
862  if (c1->rtsp_c == c)
863  c1->rtsp_c = NULL;
864  }
865 
866  /* remove connection associated resources */
867  if (c->fd >= 0)
868  closesocket(c->fd);
869  if (c->fmt_in) {
870  /* close each frame parser */
871  for(i=0;i<c->fmt_in->nb_streams;i++) {
872  st = c->fmt_in->streams[i];
873  if (st->codec->codec)
874  avcodec_close(st->codec);
875  }
877  }
878 
879  /* free RTP output streams if any */
880  nb_streams = 0;
881  if (c->stream)
882  nb_streams = c->stream->nb_streams;
883 
884  for(i=0;i<nb_streams;i++) {
885  ctx = c->rtp_ctx[i];
886  if (ctx) {
887  av_write_trailer(ctx);
888  av_dict_free(&ctx->metadata);
889  av_free(ctx->streams[0]);
890  av_free(ctx);
891  }
892  h = c->rtp_handles[i];
893  if (h)
894  ffurl_close(h);
895  }
896 
897  ctx = &c->fmt_ctx;
898 
900  if (ctx->oformat) {
901  /* prepare header */
902  if (avio_open_dyn_buf(&ctx->pb) >= 0) {
903  av_write_trailer(ctx);
904  av_freep(&c->pb_buffer);
905  avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
906  }
907  }
908  }
909 
910  for(i=0; i<ctx->nb_streams; i++)
911  av_free(ctx->streams[i]);
912 
913  if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
915 
916  /* signal that there is no feed if we are the feeder socket */
917  if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
918  c->stream->feed_opened = 0;
919  close(c->feed_fd);
920  }
921 
922  av_freep(&c->pb_buffer);
923  av_freep(&c->packet_buffer);
924  av_free(c->buffer);
925  av_free(c);
926  nb_connections--;
927 }
928 
930 {
931  int len, ret;
932 
933  switch(c->state) {
936  /* timeout ? */
937  if ((c->timeout - cur_time) < 0)
938  return -1;
939  if (c->poll_entry->revents & (POLLERR | POLLHUP))
940  return -1;
941 
942  /* no need to read if no events */
943  if (!(c->poll_entry->revents & POLLIN))
944  return 0;
945  /* read the data */
946  read_loop:
947  len = recv(c->fd, c->buffer_ptr, 1, 0);
948  if (len < 0) {
949  if (ff_neterrno() != AVERROR(EAGAIN) &&
950  ff_neterrno() != AVERROR(EINTR))
951  return -1;
952  } else if (len == 0) {
953  return -1;
954  } else {
955  /* search for end of request. */
956  uint8_t *ptr;
957  c->buffer_ptr += len;
958  ptr = c->buffer_ptr;
959  if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
960  (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
961  /* request found : parse it and reply */
962  if (c->state == HTTPSTATE_WAIT_REQUEST) {
963  ret = http_parse_request(c);
964  } else {
965  ret = rtsp_parse_request(c);
966  }
967  if (ret < 0)
968  return -1;
969  } else if (ptr >= c->buffer_end) {
970  /* request too long: cannot do anything */
971  return -1;
972  } else goto read_loop;
973  }
974  break;
975 
977  if (c->poll_entry->revents & (POLLERR | POLLHUP))
978  return -1;
979 
980  /* no need to write if no events */
981  if (!(c->poll_entry->revents & POLLOUT))
982  return 0;
983  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
984  if (len < 0) {
985  if (ff_neterrno() != AVERROR(EAGAIN) &&
986  ff_neterrno() != AVERROR(EINTR)) {
987  /* error : close connection */
988  av_freep(&c->pb_buffer);
989  return -1;
990  }
991  } else {
992  c->buffer_ptr += len;
993  if (c->stream)
994  c->stream->bytes_served += len;
995  c->data_count += len;
996  if (c->buffer_ptr >= c->buffer_end) {
997  av_freep(&c->pb_buffer);
998  /* if error, exit */
999  if (c->http_error)
1000  return -1;
1001  /* all the buffer was sent : synchronize to the incoming stream */
1003  c->buffer_ptr = c->buffer_end = c->buffer;
1004  }
1005  }
1006  break;
1007 
1008  case HTTPSTATE_SEND_DATA:
1011  /* for packetized output, we consider we can always write (the
1012  input streams sets the speed). It may be better to verify
1013  that we do not rely too much on the kernel queues */
1014  if (!c->is_packetized) {
1015  if (c->poll_entry->revents & (POLLERR | POLLHUP))
1016  return -1;
1017 
1018  /* no need to read if no events */
1019  if (!(c->poll_entry->revents & POLLOUT))
1020  return 0;
1021  }
1022  if (http_send_data(c) < 0)
1023  return -1;
1024  /* close connection if trailer sent */
1026  return -1;
1027  break;
1029  /* no need to read if no events */
1030  if (c->poll_entry->revents & (POLLERR | POLLHUP))
1031  return -1;
1032  if (!(c->poll_entry->revents & POLLIN))
1033  return 0;
1034  if (http_receive_data(c) < 0)
1035  return -1;
1036  break;
1037  case HTTPSTATE_WAIT_FEED:
1038  /* no need to read if no events */
1039  if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1040  return -1;
1041 
1042  /* nothing to do, we'll be waken up by incoming feed packets */
1043  break;
1044 
1045  case RTSPSTATE_SEND_REPLY:
1046  if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1047  av_freep(&c->pb_buffer);
1048  return -1;
1049  }
1050  /* no need to write if no events */
1051  if (!(c->poll_entry->revents & POLLOUT))
1052  return 0;
1053  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1054  if (len < 0) {
1055  if (ff_neterrno() != AVERROR(EAGAIN) &&
1056  ff_neterrno() != AVERROR(EINTR)) {
1057  /* error : close connection */
1058  av_freep(&c->pb_buffer);
1059  return -1;
1060  }
1061  } else {
1062  c->buffer_ptr += len;
1063  c->data_count += len;
1064  if (c->buffer_ptr >= c->buffer_end) {
1065  /* all the buffer was sent : wait for a new request */
1066  av_freep(&c->pb_buffer);
1067  start_wait_request(c, 1);
1068  }
1069  }
1070  break;
1071  case RTSPSTATE_SEND_PACKET:
1072  if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1073  av_freep(&c->packet_buffer);
1074  return -1;
1075  }
1076  /* no need to write if no events */
1077  if (!(c->poll_entry->revents & POLLOUT))
1078  return 0;
1079  len = send(c->fd, c->packet_buffer_ptr,
1081  if (len < 0) {
1082  if (ff_neterrno() != AVERROR(EAGAIN) &&
1083  ff_neterrno() != AVERROR(EINTR)) {
1084  /* error : close connection */
1085  av_freep(&c->packet_buffer);
1086  return -1;
1087  }
1088  } else {
1089  c->packet_buffer_ptr += len;
1090  if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1091  /* all the buffer was sent : wait for a new request */
1092  av_freep(&c->packet_buffer);
1094  }
1095  }
1096  break;
1097  case HTTPSTATE_READY:
1098  /* nothing to do */
1099  break;
1100  default:
1101  return -1;
1102  }
1103  return 0;
1104 }
1105 
1106 static int extract_rates(char *rates, int ratelen, const char *request)
1107 {
1108  const char *p;
1109 
1110  for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1111  if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1112  const char *q = p + 7;
1113 
1114  while (*q && *q != '\n' && av_isspace(*q))
1115  q++;
1116 
1117  if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1118  int stream_no;
1119  int rate_no;
1120 
1121  q += 20;
1122 
1123  memset(rates, 0xff, ratelen);
1124 
1125  while (1) {
1126  while (*q && *q != '\n' && *q != ':')
1127  q++;
1128 
1129  if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1130  break;
1131 
1132  stream_no--;
1133  if (stream_no < ratelen && stream_no >= 0)
1134  rates[stream_no] = rate_no;
1135 
1136  while (*q && *q != '\n' && !av_isspace(*q))
1137  q++;
1138  }
1139 
1140  return 1;
1141  }
1142  }
1143  p = strchr(p, '\n');
1144  if (!p)
1145  break;
1146 
1147  p++;
1148  }
1149 
1150  return 0;
1151 }
1152 
1153 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1154 {
1155  int i;
1156  int best_bitrate = 100000000;
1157  int best = -1;
1158 
1159  for (i = 0; i < feed->nb_streams; i++) {
1160  AVCodecContext *feed_codec = feed->streams[i]->codec;
1161 
1162  if (feed_codec->codec_id != codec->codec_id ||
1163  feed_codec->sample_rate != codec->sample_rate ||
1164  feed_codec->width != codec->width ||
1165  feed_codec->height != codec->height)
1166  continue;
1167 
1168  /* Potential stream */
1169 
1170  /* We want the fastest stream less than bit_rate, or the slowest
1171  * faster than bit_rate
1172  */
1173 
1174  if (feed_codec->bit_rate <= bit_rate) {
1175  if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1176  best_bitrate = feed_codec->bit_rate;
1177  best = i;
1178  }
1179  } else {
1180  if (feed_codec->bit_rate < best_bitrate) {
1181  best_bitrate = feed_codec->bit_rate;
1182  best = i;
1183  }
1184  }
1185  }
1186 
1187  return best;
1188 }
1189 
1191 {
1192  int i;
1193  FFStream *req = c->stream;
1194  int action_required = 0;
1195 
1196  /* Not much we can do for a feed */
1197  if (!req->feed)
1198  return 0;
1199 
1200  for (i = 0; i < req->nb_streams; i++) {
1201  AVCodecContext *codec = req->streams[i]->codec;
1202 
1203  switch(rates[i]) {
1204  case 0:
1205  c->switch_feed_streams[i] = req->feed_streams[i];
1206  break;
1207  case 1:
1208  c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1209  break;
1210  case 2:
1211  /* Wants off or slow */
1212  c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1213 #ifdef WANTS_OFF
1214  /* This doesn't work well when it turns off the only stream! */
1215  c->switch_feed_streams[i] = -2;
1216  c->feed_streams[i] = -2;
1217 #endif
1218  break;
1219  }
1220 
1221  if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1222  action_required = 1;
1223  }
1224 
1225  return action_required;
1226 }
1227 
1228 /* XXX: factorize in utils.c ? */
1229 /* XXX: take care with different space meaning */
1230 static void skip_spaces(const char **pp)
1231 {
1232  const char *p;
1233  p = *pp;
1234  while (*p == ' ' || *p == '\t')
1235  p++;
1236  *pp = p;
1237 }
1238 
1239 static void get_word(char *buf, int buf_size, const char **pp)
1240 {
1241  const char *p;
1242  char *q;
1243 
1244  p = *pp;
1245  skip_spaces(&p);
1246  q = buf;
1247  while (!av_isspace(*p) && *p != '\0') {
1248  if ((q - buf) < buf_size - 1)
1249  *q++ = *p;
1250  p++;
1251  }
1252  if (buf_size > 0)
1253  *q = '\0';
1254  *pp = p;
1255 }
1256 
1257 static void get_arg(char *buf, int buf_size, const char **pp)
1258 {
1259  const char *p;
1260  char *q;
1261  int quote;
1262 
1263  p = *pp;
1264  while (av_isspace(*p)) p++;
1265  q = buf;
1266  quote = 0;
1267  if (*p == '\"' || *p == '\'')
1268  quote = *p++;
1269  for(;;) {
1270  if (quote) {
1271  if (*p == quote)
1272  break;
1273  } else {
1274  if (av_isspace(*p))
1275  break;
1276  }
1277  if (*p == '\0')
1278  break;
1279  if ((q - buf) < buf_size - 1)
1280  *q++ = *p;
1281  p++;
1282  }
1283  *q = '\0';
1284  if (quote && *p == quote)
1285  p++;
1286  *pp = p;
1287 }
1288 
1289 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1290  const char *p, const char *filename, int line_num)
1291 {
1292  char arg[1024];
1293  IPAddressACL acl;
1294  int errors = 0;
1295 
1296  get_arg(arg, sizeof(arg), &p);
1297  if (av_strcasecmp(arg, "allow") == 0)
1298  acl.action = IP_ALLOW;
1299  else if (av_strcasecmp(arg, "deny") == 0)
1300  acl.action = IP_DENY;
1301  else {
1302  fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1303  filename, line_num, arg);
1304  errors++;
1305  }
1306 
1307  get_arg(arg, sizeof(arg), &p);
1308 
1309  if (resolve_host(&acl.first, arg) != 0) {
1310  fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1311  filename, line_num, arg);
1312  errors++;
1313  } else
1314  acl.last = acl.first;
1315 
1316  get_arg(arg, sizeof(arg), &p);
1317 
1318  if (arg[0]) {
1319  if (resolve_host(&acl.last, arg) != 0) {
1320  fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1321  filename, line_num, arg);
1322  errors++;
1323  }
1324  }
1325 
1326  if (!errors) {
1327  IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1328  IPAddressACL **naclp = 0;
1329 
1330  acl.next = 0;
1331  *nacl = acl;
1332 
1333  if (stream)
1334  naclp = &stream->acl;
1335  else if (feed)
1336  naclp = &feed->acl;
1337  else if (ext_acl)
1338  naclp = &ext_acl;
1339  else {
1340  fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1341  filename, line_num);
1342  errors++;
1343  }
1344 
1345  if (naclp) {
1346  while (*naclp)
1347  naclp = &(*naclp)->next;
1348 
1349  *naclp = nacl;
1350  }
1351  }
1352 }
1353 
1354 
1356 {
1357  FILE* f;
1358  char line[1024];
1359  char cmd[1024];
1360  IPAddressACL *acl = NULL;
1361  int line_num = 0;
1362  const char *p;
1363 
1364  f = fopen(stream->dynamic_acl, "r");
1365  if (!f) {
1366  perror(stream->dynamic_acl);
1367  return NULL;
1368  }
1369 
1370  acl = av_mallocz(sizeof(IPAddressACL));
1371 
1372  /* Build ACL */
1373  for(;;) {
1374  if (fgets(line, sizeof(line), f) == NULL)
1375  break;
1376  line_num++;
1377  p = line;
1378  while (av_isspace(*p))
1379  p++;
1380  if (*p == '\0' || *p == '#')
1381  continue;
1382  get_arg(cmd, sizeof(cmd), &p);
1383 
1384  if (!av_strcasecmp(cmd, "ACL"))
1385  parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1386  }
1387  fclose(f);
1388  return acl;
1389 }
1390 
1391 
1392 static void free_acl_list(IPAddressACL *in_acl)
1393 {
1394  IPAddressACL *pacl,*pacl2;
1395 
1396  pacl = in_acl;
1397  while(pacl) {
1398  pacl2 = pacl;
1399  pacl = pacl->next;
1400  av_freep(pacl2);
1401  }
1402 }
1403 
1405 {
1406  enum IPAddressAction last_action = IP_DENY;
1407  IPAddressACL *acl;
1408  struct in_addr *src = &c->from_addr.sin_addr;
1409  unsigned long src_addr = src->s_addr;
1410 
1411  for (acl = in_acl; acl; acl = acl->next) {
1412  if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1413  return (acl->action == IP_ALLOW) ? 1 : 0;
1414  last_action = acl->action;
1415  }
1416 
1417  /* Nothing matched, so return not the last action */
1418  return (last_action == IP_DENY) ? 1 : 0;
1419 }
1420 
1421 static int validate_acl(FFStream *stream, HTTPContext *c)
1422 {
1423  int ret = 0;
1424  IPAddressACL *acl;
1425 
1426 
1427  /* if stream->acl is null validate_acl_list will return 1 */
1428  ret = validate_acl_list(stream->acl, c);
1429 
1430  if (stream->dynamic_acl[0]) {
1431  acl = parse_dynamic_acl(stream, c);
1432 
1433  ret = validate_acl_list(acl, c);
1434 
1435  free_acl_list(acl);
1436  }
1437 
1438  return ret;
1439 }
1440 
1441 /* compute the real filename of a file by matching it without its
1442  extensions to all the stream filenames */
1443 static void compute_real_filename(char *filename, int max_size)
1444 {
1445  char file1[1024];
1446  char file2[1024];
1447  char *p;
1448  FFStream *stream;
1449 
1450  /* compute filename by matching without the file extensions */
1451  av_strlcpy(file1, filename, sizeof(file1));
1452  p = strrchr(file1, '.');
1453  if (p)
1454  *p = '\0';
1455  for(stream = first_stream; stream != NULL; stream = stream->next) {
1456  av_strlcpy(file2, stream->filename, sizeof(file2));
1457  p = strrchr(file2, '.');
1458  if (p)
1459  *p = '\0';
1460  if (!strcmp(file1, file2)) {
1461  av_strlcpy(filename, stream->filename, max_size);
1462  break;
1463  }
1464  }
1465 }
1466 
1474 };
1475 
1476 /* parse http request and prepare header */
1478 {
1479  const char *p;
1480  char *p1;
1481  enum RedirType redir_type;
1482  char cmd[32];
1483  char info[1024], filename[1024];
1484  char url[1024], *q;
1485  char protocol[32];
1486  char msg[1024];
1487  const char *mime_type;
1488  FFStream *stream;
1489  int i;
1490  char ratebuf[32];
1491  const char *useragent = 0;
1492 
1493  p = c->buffer;
1494  get_word(cmd, sizeof(cmd), &p);
1495  av_strlcpy(c->method, cmd, sizeof(c->method));
1496 
1497  if (!strcmp(cmd, "GET"))
1498  c->post = 0;
1499  else if (!strcmp(cmd, "POST"))
1500  c->post = 1;
1501  else
1502  return -1;
1503 
1504  get_word(url, sizeof(url), &p);
1505  av_strlcpy(c->url, url, sizeof(c->url));
1506 
1507  get_word(protocol, sizeof(protocol), (const char **)&p);
1508  if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1509  return -1;
1510 
1511  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1512 
1513  if (avserver_debug)
1514  http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1515 
1516  /* find the filename and the optional info string in the request */
1517  p1 = strchr(url, '?');
1518  if (p1) {
1519  av_strlcpy(info, p1, sizeof(info));
1520  *p1 = '\0';
1521  } else
1522  info[0] = '\0';
1523 
1524  av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1525 
1526  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1527  if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1528  useragent = p + 11;
1529  if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1530  useragent++;
1531  break;
1532  }
1533  p = strchr(p, '\n');
1534  if (!p)
1535  break;
1536 
1537  p++;
1538  }
1539 
1540  redir_type = REDIR_NONE;
1541  if (av_match_ext(filename, "asx")) {
1542  redir_type = REDIR_ASX;
1543  filename[strlen(filename)-1] = 'f';
1544  } else if (av_match_ext(filename, "asf") &&
1545  (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1546  /* if this isn't WMP or lookalike, return the redirector file */
1547  redir_type = REDIR_ASF;
1548  } else if (av_match_ext(filename, "rpm,ram")) {
1549  redir_type = REDIR_RAM;
1550  strcpy(filename + strlen(filename)-2, "m");
1551  } else if (av_match_ext(filename, "rtsp")) {
1552  redir_type = REDIR_RTSP;
1553  compute_real_filename(filename, sizeof(filename) - 1);
1554  } else if (av_match_ext(filename, "sdp")) {
1555  redir_type = REDIR_SDP;
1556  compute_real_filename(filename, sizeof(filename) - 1);
1557  }
1558 
1559  // "redirect" / request to index.html
1560  if (!strlen(filename))
1561  av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1562 
1563  stream = first_stream;
1564  while (stream != NULL) {
1565  if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1566  break;
1567  stream = stream->next;
1568  }
1569  if (stream == NULL) {
1570  snprintf(msg, sizeof(msg), "File '%s' not found", url);
1571  http_log("File '%s' not found\n", url);
1572  goto send_error;
1573  }
1574 
1575  c->stream = stream;
1576  memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1577  memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1578 
1579  if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1580  c->http_error = 301;
1581  q = c->buffer;
1582  q += snprintf(q, c->buffer_size,
1583  "HTTP/1.0 301 Moved\r\n"
1584  "Location: %s\r\n"
1585  "Content-type: text/html\r\n"
1586  "\r\n"
1587  "<html><head><title>Moved</title></head><body>\r\n"
1588  "You should be <a href=\"%s\">redirected</a>.\r\n"
1589  "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1590  /* prepare output buffer */
1591  c->buffer_ptr = c->buffer;
1592  c->buffer_end = q;
1594  return 0;
1595  }
1596 
1597  /* If this is WMP, get the rate information */
1598  if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1599  if (modify_current_stream(c, ratebuf)) {
1600  for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1601  if (c->switch_feed_streams[i] >= 0)
1602  c->switch_feed_streams[i] = -1;
1603  }
1604  }
1605  }
1606 
1607  if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1608  current_bandwidth += stream->bandwidth;
1609 
1610  /* If already streaming this feed, do not let start another feeder. */
1611  if (stream->feed_opened) {
1612  snprintf(msg, sizeof(msg), "This feed is already being received.");
1613  http_log("Feed '%s' already being received\n", stream->feed_filename);
1614  goto send_error;
1615  }
1616 
1617  if (c->post == 0 && max_bandwidth < current_bandwidth) {
1618  c->http_error = 503;
1619  q = c->buffer;
1620  q += snprintf(q, c->buffer_size,
1621  "HTTP/1.0 503 Server too busy\r\n"
1622  "Content-type: text/html\r\n"
1623  "\r\n"
1624  "<html><head><title>Too busy</title></head><body>\r\n"
1625  "<p>The server is too busy to serve your request at this time.</p>\r\n"
1626  "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1627  "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1628  "</body></html>\r\n", current_bandwidth, max_bandwidth);
1629  /* prepare output buffer */
1630  c->buffer_ptr = c->buffer;
1631  c->buffer_end = q;
1633  return 0;
1634  }
1635 
1636  if (redir_type != REDIR_NONE) {
1637  const char *hostinfo = 0;
1638 
1639  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1640  if (av_strncasecmp(p, "Host:", 5) == 0) {
1641  hostinfo = p + 5;
1642  break;
1643  }
1644  p = strchr(p, '\n');
1645  if (!p)
1646  break;
1647 
1648  p++;
1649  }
1650 
1651  if (hostinfo) {
1652  char *eoh;
1653  char hostbuf[260];
1654 
1655  while (av_isspace(*hostinfo))
1656  hostinfo++;
1657 
1658  eoh = strchr(hostinfo, '\n');
1659  if (eoh) {
1660  if (eoh[-1] == '\r')
1661  eoh--;
1662 
1663  if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1664  memcpy(hostbuf, hostinfo, eoh - hostinfo);
1665  hostbuf[eoh - hostinfo] = 0;
1666 
1667  c->http_error = 200;
1668  q = c->buffer;
1669  switch(redir_type) {
1670  case REDIR_ASX:
1671  q += snprintf(q, c->buffer_size,
1672  "HTTP/1.0 200 ASX Follows\r\n"
1673  "Content-type: video/x-ms-asf\r\n"
1674  "\r\n"
1675  "<ASX Version=\"3\">\r\n"
1676  //"<!-- Autogenerated by avserver -->\r\n"
1677  "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1678  "</ASX>\r\n", hostbuf, filename, info);
1679  break;
1680  case REDIR_RAM:
1681  q += snprintf(q, c->buffer_size,
1682  "HTTP/1.0 200 RAM Follows\r\n"
1683  "Content-type: audio/x-pn-realaudio\r\n"
1684  "\r\n"
1685  "# Autogenerated by avserver\r\n"
1686  "http://%s/%s%s\r\n", hostbuf, filename, info);
1687  break;
1688  case REDIR_ASF:
1689  q += snprintf(q, c->buffer_size,
1690  "HTTP/1.0 200 ASF Redirect follows\r\n"
1691  "Content-type: video/x-ms-asf\r\n"
1692  "\r\n"
1693  "[Reference]\r\n"
1694  "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1695  break;
1696  case REDIR_RTSP:
1697  {
1698  char hostname[256], *p;
1699  /* extract only hostname */
1700  av_strlcpy(hostname, hostbuf, sizeof(hostname));
1701  p = strrchr(hostname, ':');
1702  if (p)
1703  *p = '\0';
1704  q += snprintf(q, c->buffer_size,
1705  "HTTP/1.0 200 RTSP Redirect follows\r\n"
1706  /* XXX: incorrect mime type ? */
1707  "Content-type: application/x-rtsp\r\n"
1708  "\r\n"
1709  "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1710  }
1711  break;
1712  case REDIR_SDP:
1713  {
1714  uint8_t *sdp_data;
1715  int sdp_data_size;
1716  socklen_t len;
1717  struct sockaddr_in my_addr;
1718 
1719  q += snprintf(q, c->buffer_size,
1720  "HTTP/1.0 200 OK\r\n"
1721  "Content-type: application/sdp\r\n"
1722  "\r\n");
1723 
1724  len = sizeof(my_addr);
1725  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1726 
1727  /* XXX: should use a dynamic buffer */
1728  sdp_data_size = prepare_sdp_description(stream,
1729  &sdp_data,
1730  my_addr.sin_addr);
1731  if (sdp_data_size > 0) {
1732  memcpy(q, sdp_data, sdp_data_size);
1733  q += sdp_data_size;
1734  *q = '\0';
1735  av_free(sdp_data);
1736  }
1737  }
1738  break;
1739  default:
1740  abort();
1741  break;
1742  }
1743 
1744  /* prepare output buffer */
1745  c->buffer_ptr = c->buffer;
1746  c->buffer_end = q;
1748  return 0;
1749  }
1750  }
1751  }
1752 
1753  snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1754  goto send_error;
1755  }
1756 
1757  stream->conns_served++;
1758 
1759  /* XXX: add there authenticate and IP match */
1760 
1761  if (c->post) {
1762  /* if post, it means a feed is being sent */
1763  if (!stream->is_feed) {
1764  /* However it might be a status report from WMP! Let us log the
1765  * data as it might come in handy one day. */
1766  const char *logline = 0;
1767  int client_id = 0;
1768 
1769  for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1770  if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1771  logline = p;
1772  break;
1773  }
1774  if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1775  client_id = strtol(p + 18, 0, 10);
1776  p = strchr(p, '\n');
1777  if (!p)
1778  break;
1779 
1780  p++;
1781  }
1782 
1783  if (logline) {
1784  char *eol = strchr(logline, '\n');
1785 
1786  logline += 17;
1787 
1788  if (eol) {
1789  if (eol[-1] == '\r')
1790  eol--;
1791  http_log("%.*s\n", (int) (eol - logline), logline);
1792  c->suppress_log = 1;
1793  }
1794  }
1795 
1796 #ifdef DEBUG
1797  http_log("\nGot request:\n%s\n", c->buffer);
1798 #endif
1799 
1800  if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1801  HTTPContext *wmpc;
1802 
1803  /* Now we have to find the client_id */
1804  for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1805  if (wmpc->wmp_client_id == client_id)
1806  break;
1807  }
1808 
1809  if (wmpc && modify_current_stream(wmpc, ratebuf))
1810  wmpc->switch_pending = 1;
1811  }
1812 
1813  snprintf(msg, sizeof(msg), "POST command not handled");
1814  c->stream = 0;
1815  goto send_error;
1816  }
1817  if (http_start_receive_data(c) < 0) {
1818  snprintf(msg, sizeof(msg), "could not open feed");
1819  goto send_error;
1820  }
1821  c->http_error = 0;
1823  return 0;
1824  }
1825 
1826 #ifdef DEBUG
1827  if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1828  http_log("\nGot request:\n%s\n", c->buffer);
1829 #endif
1830 
1832  goto send_status;
1833 
1834  /* open input stream */
1835  if (open_input_stream(c, info) < 0) {
1836  snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1837  goto send_error;
1838  }
1839 
1840  /* prepare http header */
1841  q = c->buffer;
1842  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1843  mime_type = c->stream->fmt->mime_type;
1844  if (!mime_type)
1845  mime_type = "application/x-octet-stream";
1846  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1847 
1848  /* for asf, we need extra headers */
1849  if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1850  /* Need to allocate a client id */
1851 
1852  c->wmp_client_id = av_lfg_get(&random_state);
1853 
1854  q += snprintf(q, q - (char *) 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);
1855  }
1856  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1857  q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1858 
1859  /* prepare output buffer */
1860  c->http_error = 0;
1861  c->buffer_ptr = c->buffer;
1862  c->buffer_end = q;
1864  return 0;
1865  send_error:
1866  c->http_error = 404;
1867  q = c->buffer;
1868  q += snprintf(q, c->buffer_size,
1869  "HTTP/1.0 404 Not Found\r\n"
1870  "Content-type: text/html\r\n"
1871  "\r\n"
1872  "<html>\n"
1873  "<head><title>404 Not Found</title></head>\n"
1874  "<body>%s</body>\n"
1875  "</html>\n", msg);
1876  /* prepare output buffer */
1877  c->buffer_ptr = c->buffer;
1878  c->buffer_end = q;
1880  return 0;
1881  send_status:
1882  compute_status(c);
1883  c->http_error = 200; /* horrible : we use this value to avoid
1884  going to the send data state */
1886  return 0;
1887 }
1888 
1889 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1890 {
1891  static const char suffix[] = " kMGTP";
1892  const char *s;
1893 
1894  for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1895 
1896  avio_printf(pb, "%"PRId64"%c", count, *s);
1897 }
1898 
1900 {
1901  HTTPContext *c1;
1902  FFStream *stream;
1903  char *p;
1904  time_t ti;
1905  int i, len;
1906  AVIOContext *pb;
1907 
1908  if (avio_open_dyn_buf(&pb) < 0) {
1909  /* XXX: return an error ? */
1910  c->buffer_ptr = c->buffer;
1911  c->buffer_end = c->buffer;
1912  return;
1913  }
1914 
1915  avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1916  avio_printf(pb, "Content-type: %s\r\n", "text/html");
1917  avio_printf(pb, "Pragma: no-cache\r\n");
1918  avio_printf(pb, "\r\n");
1919 
1920  avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1921  if (c->stream->feed_filename[0])
1922  avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1923  avio_printf(pb, "</head>\n<body>");
1924  avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1925  /* format status */
1926  avio_printf(pb, "<h2>Available Streams</h2>\n");
1927  avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1928  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");
1929  stream = first_stream;
1930  while (stream != NULL) {
1931  char sfilename[1024];
1932  char *eosf;
1933 
1934  if (stream->feed != stream) {
1935  av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1936  eosf = sfilename + strlen(sfilename);
1937  if (eosf - sfilename >= 4) {
1938  if (strcmp(eosf - 4, ".asf") == 0)
1939  strcpy(eosf - 4, ".asx");
1940  else if (strcmp(eosf - 3, ".rm") == 0)
1941  strcpy(eosf - 3, ".ram");
1942  else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1943  /* generate a sample RTSP director if
1944  unicast. Generate an SDP redirector if
1945  multicast */
1946  eosf = strrchr(sfilename, '.');
1947  if (!eosf)
1948  eosf = sfilename + strlen(sfilename);
1949  if (stream->is_multicast)
1950  strcpy(eosf, ".sdp");
1951  else
1952  strcpy(eosf, ".rtsp");
1953  }
1954  }
1955 
1956  avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1957  sfilename, stream->filename);
1958  avio_printf(pb, "<td align=right> %d <td align=right> ",
1959  stream->conns_served);
1960  fmt_bytecount(pb, stream->bytes_served);
1961  switch(stream->stream_type) {
1962  case STREAM_TYPE_LIVE: {
1963  int audio_bit_rate = 0;
1964  int video_bit_rate = 0;
1965  const char *audio_codec_name = "";
1966  const char *video_codec_name = "";
1967  const char *audio_codec_name_extra = "";
1968  const char *video_codec_name_extra = "";
1969 
1970  for(i=0;i<stream->nb_streams;i++) {
1971  AVStream *st = stream->streams[i];
1972  AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1973  switch(st->codec->codec_type) {
1974  case AVMEDIA_TYPE_AUDIO:
1975  audio_bit_rate += st->codec->bit_rate;
1976  if (codec) {
1977  if (*audio_codec_name)
1978  audio_codec_name_extra = "...";
1979  audio_codec_name = codec->name;
1980  }
1981  break;
1982  case AVMEDIA_TYPE_VIDEO:
1983  video_bit_rate += st->codec->bit_rate;
1984  if (codec) {
1985  if (*video_codec_name)
1986  video_codec_name_extra = "...";
1987  video_codec_name = codec->name;
1988  }
1989  break;
1990  case AVMEDIA_TYPE_DATA:
1991  video_bit_rate += st->codec->bit_rate;
1992  break;
1993  default:
1994  abort();
1995  }
1996  }
1997  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",
1998  stream->fmt->name,
1999  stream->bandwidth,
2000  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2001  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2002  if (stream->feed)
2003  avio_printf(pb, "<td>%s", stream->feed->filename);
2004  else
2005  avio_printf(pb, "<td>%s", stream->feed_filename);
2006  avio_printf(pb, "\n");
2007  }
2008  break;
2009  default:
2010  avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2011  break;
2012  }
2013  }
2014  stream = stream->next;
2015  }
2016  avio_printf(pb, "</table>\n");
2017 
2018  stream = first_stream;
2019  while (stream != NULL) {
2020  if (stream->feed == stream) {
2021  avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2022  if (stream->pid) {
2023  avio_printf(pb, "Running as pid %d.\n", stream->pid);
2024 
2025 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2026  {
2027  FILE *pid_stat;
2028  char ps_cmd[64];
2029 
2030  /* This is somewhat linux specific I guess */
2031  snprintf(ps_cmd, sizeof(ps_cmd),
2032  "ps -o \"%%cpu,cputime\" --no-headers %d",
2033  stream->pid);
2034 
2035  pid_stat = popen(ps_cmd, "r");
2036  if (pid_stat) {
2037  char cpuperc[10];
2038  char cpuused[64];
2039 
2040  if (fscanf(pid_stat, "%10s %64s", cpuperc,
2041  cpuused) == 2) {
2042  avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2043  cpuperc, cpuused);
2044  }
2045  fclose(pid_stat);
2046  }
2047  }
2048 #endif
2049 
2050  avio_printf(pb, "<p>");
2051  }
2052  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");
2053 
2054  for (i = 0; i < stream->nb_streams; i++) {
2055  AVStream *st = stream->streams[i];
2056  AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2057  const char *type = "unknown";
2058  char parameters[64];
2059 
2060  parameters[0] = 0;
2061 
2062  switch(st->codec->codec_type) {
2063  case AVMEDIA_TYPE_AUDIO:
2064  type = "audio";
2065  snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2066  break;
2067  case AVMEDIA_TYPE_VIDEO:
2068  type = "video";
2069  snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2070  st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2071  break;
2072  default:
2073  abort();
2074  }
2075  avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2076  i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2077  }
2078  avio_printf(pb, "</table>\n");
2079 
2080  }
2081  stream = stream->next;
2082  }
2083 
2084  /* connection status */
2085  avio_printf(pb, "<h2>Connection Status</h2>\n");
2086 
2087  avio_printf(pb, "Number of connections: %d / %d<br>\n",
2089 
2090  avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2092 
2093  avio_printf(pb, "<table>\n");
2094  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");
2095  c1 = first_http_ctx;
2096  i = 0;
2097  while (c1 != NULL) {
2098  int bitrate;
2099  int j;
2100 
2101  bitrate = 0;
2102  if (c1->stream) {
2103  for (j = 0; j < c1->stream->nb_streams; j++) {
2104  if (!c1->stream->feed)
2105  bitrate += c1->stream->streams[j]->codec->bit_rate;
2106  else if (c1->feed_streams[j] >= 0)
2107  bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2108  }
2109  }
2110 
2111  i++;
2112  p = inet_ntoa(c1->from_addr.sin_addr);
2113  avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2114  i,
2115  c1->stream ? c1->stream->filename : "",
2116  c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2117  p,
2118  c1->protocol,
2119  http_state[c1->state]);
2120  fmt_bytecount(pb, bitrate);
2121  avio_printf(pb, "<td align=right>");
2122  fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2123  avio_printf(pb, "<td align=right>");
2124  fmt_bytecount(pb, c1->data_count);
2125  avio_printf(pb, "\n");
2126  c1 = c1->next;
2127  }
2128  avio_printf(pb, "</table>\n");
2129 
2130  /* date */
2131  ti = time(NULL);
2132  p = ctime(&ti);
2133  avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2134  avio_printf(pb, "</body>\n</html>\n");
2135 
2136  len = avio_close_dyn_buf(pb, &c->pb_buffer);
2137  c->buffer_ptr = c->pb_buffer;
2138  c->buffer_end = c->pb_buffer + len;
2139 }
2140 
2141 static int open_input_stream(HTTPContext *c, const char *info)
2142 {
2143  char buf[128];
2144  char input_filename[1024];
2145  AVFormatContext *s = NULL;
2146  int i, ret;
2147  int64_t stream_pos;
2148 
2149  /* find file name */
2150  if (c->stream->feed) {
2151  strcpy(input_filename, c->stream->feed->feed_filename);
2152  /* compute position (absolute time) */
2153  if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2154  if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2155  return ret;
2156  } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2157  int prebuffer = strtol(buf, 0, 10);
2158  stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2159  } else
2160  stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2161  } else {
2162  strcpy(input_filename, c->stream->feed_filename);
2163  /* compute position (relative time) */
2164  if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2165  if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2166  return ret;
2167  } else
2168  stream_pos = 0;
2169  }
2170  if (input_filename[0] == '\0')
2171  return -1;
2172 
2173  /* open stream */
2174  if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2175  http_log("could not open %s: %d\n", input_filename, ret);
2176  return -1;
2177  }
2178  s->flags |= AVFMT_FLAG_GENPTS;
2179  c->fmt_in = s;
2180  if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2181  http_log("Could not find stream info '%s'\n", input_filename);
2183  return -1;
2184  }
2185 
2186  /* choose stream as clock source (we favorize video stream if
2187  present) for packet sending */
2188  c->pts_stream_index = 0;
2189  for(i=0;i<c->stream->nb_streams;i++) {
2190  if (c->pts_stream_index == 0 &&
2192  c->pts_stream_index = i;
2193  }
2194  }
2195 
2196  if (c->fmt_in->iformat->read_seek)
2197  av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2198  /* set the start time (needed for maxtime and RTP packet timing) */
2199  c->start_time = cur_time;
2201  return 0;
2202 }
2203 
2204 /* return the server clock (in us) */
2205 static int64_t get_server_clock(HTTPContext *c)
2206 {
2207  /* compute current pts value from system time */
2208  return (cur_time - c->start_time) * 1000;
2209 }
2210 
2211 /* return the estimated time at which the current packet must be sent
2212  (in us) */
2214 {
2215  int bytes_left, bytes_sent, frame_bytes;
2216 
2217  frame_bytes = c->cur_frame_bytes;
2218  if (frame_bytes <= 0)
2219  return c->cur_pts;
2220  else {
2221  bytes_left = c->buffer_end - c->buffer_ptr;
2222  bytes_sent = frame_bytes - bytes_left;
2223  return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2224  }
2225 }
2226 
2227 
2229 {
2230  int i, len, ret;
2231  AVFormatContext *ctx;
2232 
2233  av_freep(&c->pb_buffer);
2234  switch(c->state) {
2236  memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2237  av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2238  av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2239  av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2240  av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2241 
2242  c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2243 
2244  for(i=0;i<c->stream->nb_streams;i++) {
2245  AVStream *src;
2246  c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2247  /* if file or feed, then just take streams from FFStream struct */
2248  if (!c->stream->feed ||
2249  c->stream->feed == c->stream)
2250  src = c->stream->streams[i];
2251  else
2252  src = c->stream->feed->streams[c->stream->feed_streams[i]];
2253 
2254  *(c->fmt_ctx.streams[i]) = *src;
2255  c->fmt_ctx.streams[i]->priv_data = 0;
2256  c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2257  AVStream, not in codec */
2258  }
2259  /* set output format parameters */
2260  c->fmt_ctx.oformat = c->stream->fmt;
2262 
2263  c->got_key_frame = 0;
2264 
2265  /* prepare header and save header data in a stream */
2266  if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2267  /* XXX: potential leak */
2268  return -1;
2269  }
2270  c->fmt_ctx.pb->seekable = 0;
2271 
2272  /*
2273  * HACK to avoid mpeg ps muxer to spit many underflow errors
2274  * Default value from Libav
2275  * Try to set it use configuration option
2276  */
2277  c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2278 
2279  if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2280  http_log("Error writing output header\n");
2281  return -1;
2282  }
2284 
2285  len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2286  c->buffer_ptr = c->pb_buffer;
2287  c->buffer_end = c->pb_buffer + len;
2288 
2290  c->last_packet_sent = 0;
2291  break;
2292  case HTTPSTATE_SEND_DATA:
2293  /* find a new packet */
2294  /* read a packet from the input stream */
2295  if (c->stream->feed)
2298  c->stream->feed->feed_size);
2299 
2300  if (c->stream->max_time &&
2301  c->stream->max_time + c->start_time - cur_time < 0)
2302  /* We have timed out */
2304  else {
2305  AVPacket pkt;
2306  redo:
2307  ret = av_read_frame(c->fmt_in, &pkt);
2308  if (ret < 0) {
2309  if (c->stream->feed) {
2310  /* if coming from feed, it means we reached the end of the
2311  ffm file, so must wait for more data */
2313  return 1; /* state changed */
2314  } else if (ret == AVERROR(EAGAIN)) {
2315  /* input not ready, come back later */
2316  return 0;
2317  } else {
2318  if (c->stream->loop) {
2320  if (open_input_stream(c, "") < 0)
2321  goto no_loop;
2322  goto redo;
2323  } else {
2324  no_loop:
2325  /* must send trailer now because eof or error */
2327  }
2328  }
2329  } else {
2330  int source_index = pkt.stream_index;
2331  /* update first pts if needed */
2332  if (c->first_pts == AV_NOPTS_VALUE) {
2334  c->start_time = cur_time;
2335  }
2336  /* send it to the appropriate stream */
2337  if (c->stream->feed) {
2338  /* if coming from a feed, select the right stream */
2339  if (c->switch_pending) {
2340  c->switch_pending = 0;
2341  for(i=0;i<c->stream->nb_streams;i++) {
2342  if (c->switch_feed_streams[i] == pkt.stream_index)
2343  if (pkt.flags & AV_PKT_FLAG_KEY)
2344  c->switch_feed_streams[i] = -1;
2345  if (c->switch_feed_streams[i] >= 0)
2346  c->switch_pending = 1;
2347  }
2348  }
2349  for(i=0;i<c->stream->nb_streams;i++) {
2350  if (c->stream->feed_streams[i] == pkt.stream_index) {
2351  AVStream *st = c->fmt_in->streams[source_index];
2352  pkt.stream_index = i;
2353  if (pkt.flags & AV_PKT_FLAG_KEY &&
2354  (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2355  c->stream->nb_streams == 1))
2356  c->got_key_frame = 1;
2357  if (!c->stream->send_on_key || c->got_key_frame)
2358  goto send_it;
2359  }
2360  }
2361  } else {
2362  AVCodecContext *codec;
2363  AVStream *ist, *ost;
2364  send_it:
2365  ist = c->fmt_in->streams[source_index];
2366  /* specific handling for RTP: we use several
2367  output stream (one for each RTP
2368  connection). XXX: need more abstract handling */
2369  if (c->is_packetized) {
2370  /* compute send time and duration */
2371  c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2372  c->cur_pts -= c->first_pts;
2374  /* find RTP context */
2376  ctx = c->rtp_ctx[c->packet_stream_index];
2377  if(!ctx) {
2378  av_free_packet(&pkt);
2379  break;
2380  }
2381  codec = ctx->streams[0]->codec;
2382  /* only one stream per RTP connection */
2383  pkt.stream_index = 0;
2384  } else {
2385  ctx = &c->fmt_ctx;
2386  /* Fudge here */
2387  codec = ctx->streams[pkt.stream_index]->codec;
2388  }
2389 
2390  if (c->is_packetized) {
2391  int max_packet_size;
2393  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2394  else
2395  max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2396  ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2397  } else {
2398  ret = avio_open_dyn_buf(&ctx->pb);
2399  }
2400  if (ret < 0) {
2401  /* XXX: potential leak */
2402  return -1;
2403  }
2404  ost = ctx->streams[pkt.stream_index];
2405 
2406  ctx->pb->seekable = 0;
2407  if (pkt.dts != AV_NOPTS_VALUE)
2408  pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2409  if (pkt.pts != AV_NOPTS_VALUE)
2410  pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2411  pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2412  if (av_write_frame(ctx, &pkt) < 0) {
2413  http_log("Error writing frame to output\n");
2415  }
2416 
2417  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2418  c->cur_frame_bytes = len;
2419  c->buffer_ptr = c->pb_buffer;
2420  c->buffer_end = c->pb_buffer + len;
2421 
2422  codec->frame_number++;
2423  if (len == 0) {
2424  av_free_packet(&pkt);
2425  goto redo;
2426  }
2427  }
2428  av_free_packet(&pkt);
2429  }
2430  }
2431  break;
2432  default:
2434  /* last packet test ? */
2435  if (c->last_packet_sent || c->is_packetized)
2436  return -1;
2437  ctx = &c->fmt_ctx;
2438  /* prepare header */
2439  if (avio_open_dyn_buf(&ctx->pb) < 0) {
2440  /* XXX: potential leak */
2441  return -1;
2442  }
2443  c->fmt_ctx.pb->seekable = 0;
2444  av_write_trailer(ctx);
2445  len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2446  c->buffer_ptr = c->pb_buffer;
2447  c->buffer_end = c->pb_buffer + len;
2448 
2449  c->last_packet_sent = 1;
2450  break;
2451  }
2452  return 0;
2453 }
2454 
2455 /* should convert the format at the same time */
2456 /* send data starting at c->buffer_ptr to the output connection
2457  (either UDP or TCP connection) */
2459 {
2460  int len, ret;
2461 
2462  for(;;) {
2463  if (c->buffer_ptr >= c->buffer_end) {
2464  ret = http_prepare_data(c);
2465  if (ret < 0)
2466  return -1;
2467  else if (ret != 0)
2468  /* state change requested */
2469  break;
2470  } else {
2471  if (c->is_packetized) {
2472  /* RTP data output */
2473  len = c->buffer_end - c->buffer_ptr;
2474  if (len < 4) {
2475  /* fail safe - should never happen */
2476  fail1:
2477  c->buffer_ptr = c->buffer_end;
2478  return 0;
2479  }
2480  len = (c->buffer_ptr[0] << 24) |
2481  (c->buffer_ptr[1] << 16) |
2482  (c->buffer_ptr[2] << 8) |
2483  (c->buffer_ptr[3]);
2484  if (len > (c->buffer_end - c->buffer_ptr))
2485  goto fail1;
2486  if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2487  /* nothing to send yet: we can wait */
2488  return 0;
2489  }
2490 
2491  c->data_count += len;
2493  if (c->stream)
2494  c->stream->bytes_served += len;
2495 
2497  /* RTP packets are sent inside the RTSP TCP connection */
2498  AVIOContext *pb;
2499  int interleaved_index, size;
2500  uint8_t header[4];
2501  HTTPContext *rtsp_c;
2502 
2503  rtsp_c = c->rtsp_c;
2504  /* if no RTSP connection left, error */
2505  if (!rtsp_c)
2506  return -1;
2507  /* if already sending something, then wait. */
2508  if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2509  break;
2510  if (avio_open_dyn_buf(&pb) < 0)
2511  goto fail1;
2512  interleaved_index = c->packet_stream_index * 2;
2513  /* RTCP packets are sent at odd indexes */
2514  if (c->buffer_ptr[1] == 200)
2515  interleaved_index++;
2516  /* write RTSP TCP header */
2517  header[0] = '$';
2518  header[1] = interleaved_index;
2519  header[2] = len >> 8;
2520  header[3] = len;
2521  avio_write(pb, header, 4);
2522  /* write RTP packet data */
2523  c->buffer_ptr += 4;
2524  avio_write(pb, c->buffer_ptr, len);
2525  size = avio_close_dyn_buf(pb, &c->packet_buffer);
2526  /* prepare asynchronous TCP sending */
2527  rtsp_c->packet_buffer_ptr = c->packet_buffer;
2528  rtsp_c->packet_buffer_end = c->packet_buffer + size;
2529  c->buffer_ptr += len;
2530 
2531  /* send everything we can NOW */
2532  len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2533  rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2534  if (len > 0)
2535  rtsp_c->packet_buffer_ptr += len;
2536  if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2537  /* if we could not send all the data, we will
2538  send it later, so a new state is needed to
2539  "lock" the RTSP TCP connection */
2540  rtsp_c->state = RTSPSTATE_SEND_PACKET;
2541  break;
2542  } else
2543  /* all data has been sent */
2544  av_freep(&c->packet_buffer);
2545  } else {
2546  /* send RTP packet directly in UDP */
2547  c->buffer_ptr += 4;
2549  c->buffer_ptr, len);
2550  c->buffer_ptr += len;
2551  /* here we continue as we can send several packets per 10 ms slot */
2552  }
2553  } else {
2554  /* TCP data output */
2555  len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2556  if (len < 0) {
2557  if (ff_neterrno() != AVERROR(EAGAIN) &&
2558  ff_neterrno() != AVERROR(EINTR))
2559  /* error : close connection */
2560  return -1;
2561  else
2562  return 0;
2563  } else
2564  c->buffer_ptr += len;
2565 
2566  c->data_count += len;
2568  if (c->stream)
2569  c->stream->bytes_served += len;
2570  break;
2571  }
2572  }
2573  } /* for(;;) */
2574  return 0;
2575 }
2576 
2578 {
2579  int fd;
2580 
2581  if (c->stream->feed_opened)
2582  return -1;
2583 
2584  /* Don't permit writing to this one */
2585  if (c->stream->readonly)
2586  return -1;
2587 
2588  /* open feed */
2589  fd = open(c->stream->feed_filename, O_RDWR);
2590  if (fd < 0) {
2591  http_log("Error opening feeder file: %s\n", strerror(errno));
2592  return -1;
2593  }
2594  c->feed_fd = fd;
2595 
2596  if (c->stream->truncate) {
2597  /* truncate feed file */
2599  http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2600  if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2601  http_log("Error truncating feed file: %s\n", strerror(errno));
2602  return -1;
2603  }
2604  } else {
2605  if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2606  http_log("Error reading write index from feed file: %s\n", strerror(errno));
2607  return -1;
2608  }
2609  }
2610 
2612  c->stream->feed_size = lseek(fd, 0, SEEK_END);
2613  lseek(fd, 0, SEEK_SET);
2614 
2615  /* init buffer input */
2616  c->buffer_ptr = c->buffer;
2617  c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2618  c->stream->feed_opened = 1;
2619  c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2620  return 0;
2621 }
2622 
2624 {
2625  HTTPContext *c1;
2626  int len, loop_run = 0;
2627 
2628  while (c->chunked_encoding && !c->chunk_size &&
2629  c->buffer_end > c->buffer_ptr) {
2630  /* read chunk header, if present */
2631  len = recv(c->fd, c->buffer_ptr, 1, 0);
2632 
2633  if (len < 0) {
2634  if (ff_neterrno() != AVERROR(EAGAIN) &&
2635  ff_neterrno() != AVERROR(EINTR))
2636  /* error : close connection */
2637  goto fail;
2638  return 0;
2639  } else if (len == 0) {
2640  /* end of connection : close it */
2641  goto fail;
2642  } else if (c->buffer_ptr - c->buffer >= 2 &&
2643  !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2644  c->chunk_size = strtol(c->buffer, 0, 16);
2645  if (c->chunk_size == 0) // end of stream
2646  goto fail;
2647  c->buffer_ptr = c->buffer;
2648  break;
2649  } else if (++loop_run > 10) {
2650  /* no chunk header, abort */
2651  goto fail;
2652  } else {
2653  c->buffer_ptr++;
2654  }
2655  }
2656 
2657  if (c->buffer_end > c->buffer_ptr) {
2658  len = recv(c->fd, c->buffer_ptr,
2659  FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2660  if (len < 0) {
2661  if (ff_neterrno() != AVERROR(EAGAIN) &&
2662  ff_neterrno() != AVERROR(EINTR))
2663  /* error : close connection */
2664  goto fail;
2665  } else if (len == 0)
2666  /* end of connection : close it */
2667  goto fail;
2668  else {
2669  c->chunk_size -= len;
2670  c->buffer_ptr += len;
2671  c->data_count += len;
2673  }
2674  }
2675 
2676  if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2677  if (c->buffer[0] != 'f' ||
2678  c->buffer[1] != 'm') {
2679  http_log("Feed stream has become desynchronized -- disconnecting\n");
2680  goto fail;
2681  }
2682  }
2683 
2684  if (c->buffer_ptr >= c->buffer_end) {
2685  FFStream *feed = c->stream;
2686  /* a packet has been received : write it in the store, except
2687  if header */
2688  if (c->data_count > FFM_PACKET_SIZE) {
2689  /* XXX: use llseek or url_seek */
2690  lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2691  if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2692  http_log("Error writing to feed file: %s\n", strerror(errno));
2693  goto fail;
2694  }
2695 
2697  /* update file size */
2698  if (feed->feed_write_index > c->stream->feed_size)
2699  feed->feed_size = feed->feed_write_index;
2700 
2701  /* handle wrap around if max file size reached */
2702  if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2704 
2705  /* write index */
2706  if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2707  http_log("Error writing index to feed file: %s\n", strerror(errno));
2708  goto fail;
2709  }
2710 
2711  /* wake up any waiting connections */
2712  for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2713  if (c1->state == HTTPSTATE_WAIT_FEED &&
2714  c1->stream->feed == c->stream->feed)
2715  c1->state = HTTPSTATE_SEND_DATA;
2716  }
2717  } else {
2718  /* We have a header in our hands that contains useful data */
2720  AVIOContext *pb;
2721  AVInputFormat *fmt_in;
2722  int i;
2723 
2724  if (!s)
2725  goto fail;
2726 
2727  /* use feed output format name to find corresponding input format */
2728  fmt_in = av_find_input_format(feed->fmt->name);
2729  if (!fmt_in)
2730  goto fail;
2731 
2732  pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2733  0, NULL, NULL, NULL, NULL);
2734  pb->seekable = 0;
2735 
2736  s->pb = pb;
2737  if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2738  av_free(pb);
2739  goto fail;
2740  }
2741 
2742  /* Now we have the actual streams */
2743  if (s->nb_streams != feed->nb_streams) {
2745  av_free(pb);
2746  http_log("Feed '%s' stream number does not match registered feed\n",
2747  c->stream->feed_filename);
2748  goto fail;
2749  }
2750 
2751  for (i = 0; i < s->nb_streams; i++) {
2752  AVStream *fst = feed->streams[i];
2753  AVStream *st = s->streams[i];
2754  avcodec_copy_context(fst->codec, st->codec);
2755  }
2756 
2758  av_free(pb);
2759  }
2760  c->buffer_ptr = c->buffer;
2761  }
2762 
2763  return 0;
2764  fail:
2765  c->stream->feed_opened = 0;
2766  close(c->feed_fd);
2767  /* wake up any waiting connections to stop waiting for feed */
2768  for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2769  if (c1->state == HTTPSTATE_WAIT_FEED &&
2770  c1->stream->feed == c->stream->feed)
2772  }
2773  return -1;
2774 }
2775 
2776 /********************************************************************/
2777 /* RTSP handling */
2778 
2779 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2780 {
2781  const char *str;
2782  time_t ti;
2783  struct tm *tm;
2784  char buf2[32];
2785 
2786  switch(error_number) {
2787  case RTSP_STATUS_OK:
2788  str = "OK";
2789  break;
2790  case RTSP_STATUS_METHOD:
2791  str = "Method Not Allowed";
2792  break;
2793  case RTSP_STATUS_BANDWIDTH:
2794  str = "Not Enough Bandwidth";
2795  break;
2796  case RTSP_STATUS_SESSION:
2797  str = "Session Not Found";
2798  break;
2799  case RTSP_STATUS_STATE:
2800  str = "Method Not Valid in This State";
2801  break;
2802  case RTSP_STATUS_AGGREGATE:
2803  str = "Aggregate operation not allowed";
2804  break;
2806  str = "Only aggregate operation allowed";
2807  break;
2808  case RTSP_STATUS_TRANSPORT:
2809  str = "Unsupported transport";
2810  break;
2811  case RTSP_STATUS_INTERNAL:
2812  str = "Internal Server Error";
2813  break;
2814  case RTSP_STATUS_SERVICE:
2815  str = "Service Unavailable";
2816  break;
2817  case RTSP_STATUS_VERSION:
2818  str = "RTSP Version not supported";
2819  break;
2820  default:
2821  str = "Unknown Error";
2822  break;
2823  }
2824 
2825  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2826  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2827 
2828  /* output GMT time */
2829  ti = time(NULL);
2830  tm = gmtime(&ti);
2831  strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2832  avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2833 }
2834 
2835 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2836 {
2837  rtsp_reply_header(c, error_number);
2838  avio_printf(c->pb, "\r\n");
2839 }
2840 
2842 {
2843  const char *p, *p1, *p2;
2844  char cmd[32];
2845  char url[1024];
2846  char protocol[32];
2847  char line[1024];
2848  int len;
2849  RTSPMessageHeader header1 = { 0 }, *header = &header1;
2850 
2851  c->buffer_ptr[0] = '\0';
2852  p = c->buffer;
2853 
2854  get_word(cmd, sizeof(cmd), &p);
2855  get_word(url, sizeof(url), &p);
2856  get_word(protocol, sizeof(protocol), &p);
2857 
2858  av_strlcpy(c->method, cmd, sizeof(c->method));
2859  av_strlcpy(c->url, url, sizeof(c->url));
2860  av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2861 
2862  if (avio_open_dyn_buf(&c->pb) < 0) {
2863  /* XXX: cannot do more */
2864  c->pb = NULL; /* safety */
2865  return -1;
2866  }
2867 
2868  /* check version name */
2869  if (strcmp(protocol, "RTSP/1.0") != 0) {
2871  goto the_end;
2872  }
2873 
2874  /* parse each header line */
2875  /* skip to next line */
2876  while (*p != '\n' && *p != '\0')
2877  p++;
2878  if (*p == '\n')
2879  p++;
2880  while (*p != '\0') {
2881  p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2882  if (!p1)
2883  break;
2884  p2 = p1;
2885  if (p2 > p && p2[-1] == '\r')
2886  p2--;
2887  /* skip empty line */
2888  if (p2 == p)
2889  break;
2890  len = p2 - p;
2891  if (len > sizeof(line) - 1)
2892  len = sizeof(line) - 1;
2893  memcpy(line, p, len);
2894  line[len] = '\0';
2895  ff_rtsp_parse_line(header, line, NULL, NULL);
2896  p = p1 + 1;
2897  }
2898 
2899  /* handle sequence number */
2900  c->seq = header->seq;
2901 
2902  if (!strcmp(cmd, "DESCRIBE"))
2903  rtsp_cmd_describe(c, url);
2904  else if (!strcmp(cmd, "OPTIONS"))
2905  rtsp_cmd_options(c, url);
2906  else if (!strcmp(cmd, "SETUP"))
2907  rtsp_cmd_setup(c, url, header);
2908  else if (!strcmp(cmd, "PLAY"))
2909  rtsp_cmd_play(c, url, header);
2910  else if (!strcmp(cmd, "PAUSE"))
2911  rtsp_cmd_pause(c, url, header);
2912  else if (!strcmp(cmd, "TEARDOWN"))
2913  rtsp_cmd_teardown(c, url, header);
2914  else
2916 
2917  the_end:
2918  len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2919  c->pb = NULL; /* safety */
2920  if (len < 0) {
2921  /* XXX: cannot do more */
2922  return -1;
2923  }
2924  c->buffer_ptr = c->pb_buffer;
2925  c->buffer_end = c->pb_buffer + len;
2927  return 0;
2928 }
2929 
2930 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2931  struct in_addr my_ip)
2932 {
2933  AVFormatContext *avc;
2934  AVStream *avs = NULL;
2935  int i;
2936 
2937  avc = avformat_alloc_context();
2938  if (avc == NULL) {
2939  return -1;
2940  }
2941  av_dict_set(&avc->metadata, "title",
2942  stream->title[0] ? stream->title : "No Title", 0);
2943  avc->nb_streams = stream->nb_streams;
2944  if (stream->is_multicast) {
2945  snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2946  inet_ntoa(stream->multicast_ip),
2947  stream->multicast_port, stream->multicast_ttl);
2948  } else {
2949  snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2950  }
2951 
2952  if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2953  !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2954  goto sdp_done;
2955  if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2956  !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2957  goto sdp_done;
2958 
2959  for(i = 0; i < stream->nb_streams; i++) {
2960  avc->streams[i] = &avs[i];
2961  avc->streams[i]->codec = stream->streams[i]->codec;
2962  }
2963  *pbuffer = av_mallocz(2048);
2964  av_sdp_create(&avc, 1, *pbuffer, 2048);
2965 
2966  sdp_done:
2967  av_free(avc->streams);
2968  av_dict_free(&avc->metadata);
2969  av_free(avc);
2970  av_free(avs);
2971 
2972  return strlen(*pbuffer);
2973 }
2974 
2975 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2976 {
2977 // rtsp_reply_header(c, RTSP_STATUS_OK);
2978  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2979  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2980  avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2981  avio_printf(c->pb, "\r\n");
2982 }
2983 
2984 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2985 {
2986  FFStream *stream;
2987  char path1[1024];
2988  const char *path;
2989  uint8_t *content;
2990  int content_length;
2991  socklen_t len;
2992  struct sockaddr_in my_addr;
2993 
2994  /* find which url is asked */
2995  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2996  path = path1;
2997  if (*path == '/')
2998  path++;
2999 
3000  for(stream = first_stream; stream != NULL; stream = stream->next) {
3001  if (!stream->is_feed &&
3002  stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3003  !strcmp(path, stream->filename)) {
3004  goto found;
3005  }
3006  }
3007  /* no stream found */
3008  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3009  return;
3010 
3011  found:
3012  /* prepare the media description in sdp format */
3013 
3014  /* get the host IP */
3015  len = sizeof(my_addr);
3016  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3017  content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3018  if (content_length < 0) {
3020  return;
3021  }
3023  avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3024  avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3025  avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3026  avio_printf(c->pb, "\r\n");
3027  avio_write(c->pb, content, content_length);
3028  av_free(content);
3029 }
3030 
3031 static HTTPContext *find_rtp_session(const char *session_id)
3032 {
3033  HTTPContext *c;
3034 
3035  if (session_id[0] == '\0')
3036  return NULL;
3037 
3038  for(c = first_http_ctx; c != NULL; c = c->next) {
3039  if (!strcmp(c->session_id, session_id))
3040  return c;
3041  }
3042  return NULL;
3043 }
3044 
3046 {
3047  RTSPTransportField *th;
3048  int i;
3049 
3050  for(i=0;i<h->nb_transports;i++) {
3051  th = &h->transports[i];
3052  if (th->lower_transport == lower_transport)
3053  return th;
3054  }
3055  return NULL;
3056 }
3057 
3058 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3059  RTSPMessageHeader *h)
3060 {
3061  FFStream *stream;
3062  int stream_index, rtp_port, rtcp_port;
3063  char buf[1024];
3064  char path1[1024];
3065  const char *path;
3066  HTTPContext *rtp_c;
3067  RTSPTransportField *th;
3068  struct sockaddr_in dest_addr;
3069  RTSPActionServerSetup setup;
3070 
3071  /* find which url is asked */
3072  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3073  path = path1;
3074  if (*path == '/')
3075  path++;
3076 
3077  /* now check each stream */
3078  for(stream = first_stream; stream != NULL; stream = stream->next) {
3079  if (!stream->is_feed &&
3080  stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3081  /* accept aggregate filenames only if single stream */
3082  if (!strcmp(path, stream->filename)) {
3083  if (stream->nb_streams != 1) {
3085  return;
3086  }
3087  stream_index = 0;
3088  goto found;
3089  }
3090 
3091  for(stream_index = 0; stream_index < stream->nb_streams;
3092  stream_index++) {
3093  snprintf(buf, sizeof(buf), "%s/streamid=%d",
3094  stream->filename, stream_index);
3095  if (!strcmp(path, buf))
3096  goto found;
3097  }
3098  }
3099  }
3100  /* no stream found */
3101  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3102  return;
3103  found:
3104 
3105  /* generate session id if needed */
3106  if (h->session_id[0] == '\0')
3107  snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3108  av_lfg_get(&random_state), av_lfg_get(&random_state));
3109 
3110  /* find rtp session, and create it if none found */
3111  rtp_c = find_rtp_session(h->session_id);
3112  if (!rtp_c) {
3113  /* always prefer UDP */
3115  if (!th) {
3117  if (!th) {
3119  return;
3120  }
3121  }
3122 
3123  rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3124  th->lower_transport);
3125  if (!rtp_c) {
3127  return;
3128  }
3129 
3130  /* open input stream */
3131  if (open_input_stream(rtp_c, "") < 0) {
3133  return;
3134  }
3135  }
3136 
3137  /* test if stream is OK (test needed because several SETUP needs
3138  to be done for a given file) */
3139  if (rtp_c->stream != stream) {
3141  return;
3142  }
3143 
3144  /* test if stream is already set up */
3145  if (rtp_c->rtp_ctx[stream_index]) {
3147  return;
3148  }
3149 
3150  /* check transport */
3151  th = find_transport(h, rtp_c->rtp_protocol);
3152  if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3153  th->client_port_min <= 0)) {
3155  return;
3156  }
3157 
3158  /* setup default options */
3159  setup.transport_option[0] = '\0';
3160  dest_addr = rtp_c->from_addr;
3161  dest_addr.sin_port = htons(th->client_port_min);
3162 
3163  /* setup stream */
3164  if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3166  return;
3167  }
3168 
3169  /* now everything is OK, so we can send the connection parameters */
3171  /* session ID */
3172  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3173 
3174  switch(rtp_c->rtp_protocol) {
3176  rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3177  rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3178  avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3179  "client_port=%d-%d;server_port=%d-%d",
3181  rtp_port, rtcp_port);
3182  break;
3184  avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3185  stream_index * 2, stream_index * 2 + 1);
3186  break;
3187  default:
3188  break;
3189  }
3190  if (setup.transport_option[0] != '\0')
3191  avio_printf(c->pb, ";%s", setup.transport_option);
3192  avio_printf(c->pb, "\r\n");
3193 
3194 
3195  avio_printf(c->pb, "\r\n");
3196 }
3197 
3198 
3199 /* find an rtp connection by using the session ID. Check consistency
3200  with filename */
3201 static HTTPContext *find_rtp_session_with_url(const char *url,
3202  const char *session_id)
3203 {
3204  HTTPContext *rtp_c;
3205  char path1[1024];
3206  const char *path;
3207  char buf[1024];
3208  int s, len;
3209 
3210  rtp_c = find_rtp_session(session_id);
3211  if (!rtp_c)
3212  return NULL;
3213 
3214  /* find which url is asked */
3215  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3216  path = path1;
3217  if (*path == '/')
3218  path++;
3219  if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3220  for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3221  snprintf(buf, sizeof(buf), "%s/streamid=%d",
3222  rtp_c->stream->filename, s);
3223  if(!strncmp(path, buf, sizeof(buf))) {
3224  // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3225  return rtp_c;
3226  }
3227  }
3228  len = strlen(path);
3229  if (len > 0 && path[len - 1] == '/' &&
3230  !strncmp(path, rtp_c->stream->filename, len - 1))
3231  return rtp_c;
3232  return NULL;
3233 }
3234 
3235 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3236 {
3237  HTTPContext *rtp_c;
3238 
3239  rtp_c = find_rtp_session_with_url(url, h->session_id);
3240  if (!rtp_c) {
3242  return;
3243  }
3244 
3245  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3246  rtp_c->state != HTTPSTATE_WAIT_FEED &&
3247  rtp_c->state != HTTPSTATE_READY) {
3249  return;
3250  }
3251 
3252  rtp_c->state = HTTPSTATE_SEND_DATA;
3253 
3254  /* now everything is OK, so we can send the connection parameters */
3256  /* session ID */
3257  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3258  avio_printf(c->pb, "\r\n");
3259 }
3260 
3261 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3262 {
3263  HTTPContext *rtp_c;
3264 
3265  rtp_c = find_rtp_session_with_url(url, h->session_id);
3266  if (!rtp_c) {
3268  return;
3269  }
3270 
3271  if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3272  rtp_c->state != HTTPSTATE_WAIT_FEED) {
3274  return;
3275  }
3276 
3277  rtp_c->state = HTTPSTATE_READY;
3278  rtp_c->first_pts = AV_NOPTS_VALUE;
3279  /* now everything is OK, so we can send the connection parameters */
3281  /* session ID */
3282  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3283  avio_printf(c->pb, "\r\n");
3284 }
3285 
3286 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3287 {
3288  HTTPContext *rtp_c;
3289 
3290  rtp_c = find_rtp_session_with_url(url, h->session_id);
3291  if (!rtp_c) {
3293  return;
3294  }
3295 
3296  /* now everything is OK, so we can send the connection parameters */
3298  /* session ID */
3299  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3300  avio_printf(c->pb, "\r\n");
3301 
3302  /* abort the session */
3303  close_connection(rtp_c);
3304 }
3305 
3306 
3307 /********************************************************************/
3308 /* RTP handling */
3309 
3310 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3311  FFStream *stream, const char *session_id,
3312  enum RTSPLowerTransport rtp_protocol)
3313 {
3314  HTTPContext *c = NULL;
3315  const char *proto_str;
3316 
3317  /* XXX: should output a warning page when coming
3318  close to the connection limit */
3320  goto fail;
3321 
3322  /* add a new connection */
3323  c = av_mallocz(sizeof(HTTPContext));
3324  if (!c)
3325  goto fail;
3326 
3327  c->fd = -1;
3328  c->poll_entry = NULL;
3329  c->from_addr = *from_addr;
3331  c->buffer = av_malloc(c->buffer_size);
3332  if (!c->buffer)
3333  goto fail;
3334  nb_connections++;
3335  c->stream = stream;
3336  av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3337  c->state = HTTPSTATE_READY;
3338  c->is_packetized = 1;
3339  c->rtp_protocol = rtp_protocol;
3340 
3341  /* protocol is shown in statistics */
3342  switch(c->rtp_protocol) {
3344  proto_str = "MCAST";
3345  break;
3347  proto_str = "UDP";
3348  break;
3350  proto_str = "TCP";
3351  break;
3352  default:
3353  proto_str = "???";
3354  break;
3355  }
3356  av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3357  av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3358 
3359  current_bandwidth += stream->bandwidth;
3360 
3361  c->next = first_http_ctx;
3362  first_http_ctx = c;
3363  return c;
3364 
3365  fail:
3366  if (c) {
3367  av_free(c->buffer);
3368  av_free(c);
3369  }
3370  return NULL;
3371 }
3372 
3373 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3374  command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3375  used. */
3377  int stream_index, struct sockaddr_in *dest_addr,
3378  HTTPContext *rtsp_c)
3379 {
3380  AVFormatContext *ctx;
3381  AVStream *st;
3382  char *ipaddr;
3383  URLContext *h = NULL;
3384  uint8_t *dummy_buf;
3385  int max_packet_size;
3386 
3387  /* now we can open the relevant output stream */
3388  ctx = avformat_alloc_context();
3389  if (!ctx)
3390  return -1;
3391  ctx->oformat = av_guess_format("rtp", NULL, NULL);
3392 
3393  st = av_mallocz(sizeof(AVStream));
3394  if (!st)
3395  goto fail;
3396  ctx->nb_streams = 1;
3397  ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3398  if (!ctx->streams)
3399  goto fail;
3400  ctx->streams[0] = st;
3401 
3402  if (!c->stream->feed ||
3403  c->stream->feed == c->stream)
3404  memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3405  else
3406  memcpy(st,
3407  c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3408  sizeof(AVStream));
3409  st->priv_data = NULL;
3410 
3411  /* build destination RTP address */
3412  ipaddr = inet_ntoa(dest_addr->sin_addr);
3413 
3414  switch(c->rtp_protocol) {
3417  /* RTP/UDP case */
3418 
3419  /* XXX: also pass as parameter to function ? */
3420  if (c->stream->is_multicast) {
3421  int ttl;
3422  ttl = c->stream->multicast_ttl;
3423  if (!ttl)
3424  ttl = 16;
3425  snprintf(ctx->filename, sizeof(ctx->filename),
3426  "rtp://%s:%d?multicast=1&ttl=%d",
3427  ipaddr, ntohs(dest_addr->sin_port), ttl);
3428  } else {
3429  snprintf(ctx->filename, sizeof(ctx->filename),
3430  "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3431  }
3432 
3433  if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3434  goto fail;
3435  c->rtp_handles[stream_index] = h;
3436  max_packet_size = h->max_packet_size;
3437  break;
3439  /* RTP/TCP case */
3440  c->rtsp_c = rtsp_c;
3441  max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3442  break;
3443  default:
3444  goto fail;
3445  }
3446 
3447  http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3448  ipaddr, ntohs(dest_addr->sin_port),
3449  c->stream->filename, stream_index, c->protocol);
3450 
3451  /* normally, no packets should be output here, but the packet size may be checked */
3452  if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3453  /* XXX: close stream */
3454  goto fail;
3455  }
3456  if (avformat_write_header(ctx, NULL) < 0) {
3457  fail:
3458  if (h)
3459  ffurl_close(h);
3460  av_free(ctx);
3461  return -1;
3462  }
3463  avio_close_dyn_buf(ctx->pb, &dummy_buf);
3464  av_free(dummy_buf);
3465 
3466  c->rtp_ctx[stream_index] = ctx;
3467  return 0;
3468 }
3469 
3470 /********************************************************************/
3471 /* avserver initialization */
3472 
3473 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3474 {
3475  AVStream *fst;
3476 
3477  fst = av_mallocz(sizeof(AVStream));
3478  if (!fst)
3479  return NULL;
3480  if (copy) {
3482  memcpy(fst->codec, codec, sizeof(AVCodecContext));
3483  if (codec->extradata_size) {
3484  fst->codec->extradata = av_malloc(codec->extradata_size);
3485  memcpy(fst->codec->extradata, codec->extradata,
3486  codec->extradata_size);
3487  }
3488  } else {
3489  /* live streams must use the actual feed's codec since it may be
3490  * updated later to carry extradata needed by the streams.
3491  */
3492  fst->codec = codec;
3493  }
3494  fst->priv_data = av_mallocz(sizeof(FeedData));
3495  fst->index = stream->nb_streams;
3496  avpriv_set_pts_info(fst, 33, 1, 90000);
3498  stream->streams[stream->nb_streams++] = fst;
3499  return fst;
3500 }
3501 
3502 /* return the stream number in the feed */
3503 static int add_av_stream(FFStream *feed, AVStream *st)
3504 {
3505  AVStream *fst;
3506  AVCodecContext *av, *av1;
3507  int i;
3508 
3509  av = st->codec;
3510  for(i=0;i<feed->nb_streams;i++) {
3511  st = feed->streams[i];
3512  av1 = st->codec;
3513  if (av1->codec_id == av->codec_id &&
3514  av1->codec_type == av->codec_type &&
3515  av1->bit_rate == av->bit_rate) {
3516 
3517  switch(av->codec_type) {
3518  case AVMEDIA_TYPE_AUDIO:
3519  if (av1->channels == av->channels &&
3520  av1->sample_rate == av->sample_rate)
3521  return i;
3522  break;
3523  case AVMEDIA_TYPE_VIDEO:
3524  if (av1->width == av->width &&
3525  av1->height == av->height &&
3526  av1->time_base.den == av->time_base.den &&
3527  av1->time_base.num == av->time_base.num &&
3528  av1->gop_size == av->gop_size)
3529  return i;
3530  break;
3531  default:
3532  abort();
3533  }
3534  }
3535  }
3536 
3537  fst = add_av_stream1(feed, av, 0);
3538  if (!fst)
3539  return -1;
3540  return feed->nb_streams - 1;
3541 }
3542 
3543 static void remove_stream(FFStream *stream)
3544 {
3545  FFStream **ps;
3546  ps = &first_stream;
3547  while (*ps != NULL) {
3548  if (*ps == stream)
3549  *ps = (*ps)->next;
3550  else
3551  ps = &(*ps)->next;
3552  }
3553 }
3554 
3555 /* specific mpeg4 handling : we extract the raw parameters */
3557 {
3558  int mpeg4_count, i, size;
3559  AVPacket pkt;
3560  AVStream *st;
3561  const uint8_t *p;
3562 
3564 
3565  mpeg4_count = 0;
3566  for(i=0;i<infile->nb_streams;i++) {
3567  st = infile->streams[i];
3568  if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3569  st->codec->extradata_size == 0) {
3570  mpeg4_count++;
3571  }
3572  }
3573  if (!mpeg4_count)
3574  return;
3575 
3576  printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3577  while (mpeg4_count > 0) {
3578  if (av_read_frame(infile, &pkt) < 0)
3579  break;
3580  st = infile->streams[pkt.stream_index];
3581  if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3582  st->codec->extradata_size == 0) {
3583  av_freep(&st->codec->extradata);
3584  /* fill extradata with the header */
3585  /* XXX: we make hard suppositions here ! */
3586  p = pkt.data;
3587  while (p < pkt.data + pkt.size - 4) {
3588  /* stop when vop header is found */
3589  if (p[0] == 0x00 && p[1] == 0x00 &&
3590  p[2] == 0x01 && p[3] == 0xb6) {
3591  size = p - pkt.data;
3592  // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3593  st->codec->extradata = av_malloc(size);
3594  st->codec->extradata_size = size;
3595  memcpy(st->codec->extradata, pkt.data, size);
3596  break;
3597  }
3598  p++;
3599  }
3600  mpeg4_count--;
3601  }
3602  av_free_packet(&pkt);
3603  }
3604 }
3605 
3606 /* compute the needed AVStream for each file */
3607 static void build_file_streams(void)
3608 {
3609  FFStream *stream, *stream_next;
3610  int i, ret;
3611 
3612  /* gather all streams */
3613  for(stream = first_stream; stream != NULL; stream = stream_next) {
3614  AVFormatContext *infile = NULL;
3615  stream_next = stream->next;
3616  if (stream->stream_type == STREAM_TYPE_LIVE &&
3617  !stream->feed) {
3618  /* the stream comes from a file */
3619  /* try to open the file */
3620  /* open stream */
3621  if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3622  /* specific case : if transport stream output to RTP,
3623  we use a raw transport stream reader */
3624  av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3625  }
3626 
3627  http_log("Opening file '%s'\n", stream->feed_filename);
3628  if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3629  http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3630  /* remove stream (no need to spend more time on it) */
3631  fail:
3632  remove_stream(stream);
3633  } else {
3634  /* find all the AVStreams inside and reference them in
3635  'stream' */
3636  if (avformat_find_stream_info(infile, NULL) < 0) {
3637  http_log("Could not find codec parameters from '%s'\n",
3638  stream->feed_filename);
3639  avformat_close_input(&infile);
3640  goto fail;
3641  }
3642  extract_mpeg4_header(infile);
3643 
3644  for(i=0;i<infile->nb_streams;i++)
3645  add_av_stream1(stream, infile->streams[i]->codec, 1);
3646 
3647  avformat_close_input(&infile);
3648  }
3649  }
3650  }
3651 }
3652 
3653 /* compute the needed AVStream for each feed */
3654 static void build_feed_streams(void)
3655 {
3656  FFStream *stream, *feed;
3657  int i;
3658 
3659  /* gather all streams */
3660  for(stream = first_stream; stream != NULL; stream = stream->next) {
3661  feed = stream->feed;
3662  if (feed) {
3663  if (stream->is_feed) {
3664  for(i=0;i<stream->nb_streams;i++)
3665  stream->feed_streams[i] = i;
3666  } else {
3667  /* we handle a stream coming from a feed */
3668  for(i=0;i<stream->nb_streams;i++)
3669  stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3670  }
3671  }
3672  }
3673 
3674  /* create feed files if needed */
3675  for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3676  int fd;
3677 
3678  if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3679  /* See if it matches */
3680  AVFormatContext *s = NULL;
3681  int matches = 0;
3682 
3683  if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3684  /* Now see if it matches */
3685  if (s->nb_streams == feed->nb_streams) {
3686  matches = 1;
3687  for(i=0;i<s->nb_streams;i++) {
3688  AVStream *sf, *ss;
3689  sf = feed->streams[i];
3690  ss = s->streams[i];
3691 
3692  if (sf->index != ss->index ||
3693  sf->id != ss->id) {
3694  http_log("Index & Id do not match for stream %d (%s)\n",
3695  i, feed->feed_filename);
3696  matches = 0;
3697  } else {
3698  AVCodecContext *ccf, *ccs;
3699 
3700  ccf = sf->codec;
3701  ccs = ss->codec;
3702 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3703 
3705  http_log("Codecs do not match for stream %d\n", i);
3706  matches = 0;
3707  } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3708  http_log("Codec bitrates do not match for stream %d\n", i);
3709  matches = 0;
3710  } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3711  if (CHECK_CODEC(time_base.den) ||
3712  CHECK_CODEC(time_base.num) ||
3713  CHECK_CODEC(width) ||
3714  CHECK_CODEC(height)) {
3715  http_log("Codec width, height and framerate do not match for stream %d\n", i);
3716  matches = 0;
3717  }
3718  } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3719  if (CHECK_CODEC(sample_rate) ||
3720  CHECK_CODEC(channels) ||
3722  http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3723  matches = 0;
3724  }
3725  } else {
3726  http_log("Unknown codec type\n");
3727  matches = 0;
3728  }
3729  }
3730  if (!matches)
3731  break;
3732  }
3733  } else
3734  http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3735  feed->feed_filename, s->nb_streams, feed->nb_streams);
3736 
3738  } else
3739  http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3740  feed->feed_filename);
3741 
3742  if (!matches) {
3743  if (feed->readonly) {
3744  http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3745  feed->feed_filename);
3746  exit(1);
3747  }
3748  unlink(feed->feed_filename);
3749  }
3750  }
3751  if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3752  AVFormatContext s1 = {0}, *s = &s1;
3753 
3754  if (feed->readonly) {
3755  http_log("Unable to create feed file '%s' as it is marked readonly\n",
3756  feed->feed_filename);
3757  exit(1);
3758  }
3759 
3760  /* only write the header of the ffm file */
3761  if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3762  http_log("Could not open output feed file '%s'\n",
3763  feed->feed_filename);
3764  exit(1);
3765  }
3766  s->oformat = feed->fmt;
3767  s->nb_streams = feed->nb_streams;
3768  s->streams = feed->streams;
3769  if (avformat_write_header(s, NULL) < 0) {
3770  http_log("Container doesn't supports the required parameters\n");
3771  exit(1);
3772  }
3773  /* XXX: need better api */
3774  av_freep(&s->priv_data);
3775  avio_close(s->pb);
3776  }
3777  /* get feed size and write index */
3778  fd = open(feed->feed_filename, O_RDONLY);
3779  if (fd < 0) {
3780  http_log("Could not open output feed file '%s'\n",
3781  feed->feed_filename);
3782  exit(1);
3783  }
3784 
3786  feed->feed_size = lseek(fd, 0, SEEK_END);
3787  /* ensure that we do not wrap before the end of file */
3788  if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3789  feed->feed_max_size = feed->feed_size;
3790 
3791  close(fd);
3792  }
3793 }
3794 
3795 /* compute the bandwidth used by each stream */
3796 static void compute_bandwidth(void)
3797 {
3798  unsigned bandwidth;
3799  int i;
3800  FFStream *stream;
3801 
3802  for(stream = first_stream; stream != NULL; stream = stream->next) {
3803  bandwidth = 0;
3804  for(i=0;i<stream->nb_streams;i++) {
3805  AVStream *st = stream->streams[i];
3806  switch(st->codec->codec_type) {
3807  case AVMEDIA_TYPE_AUDIO:
3808  case AVMEDIA_TYPE_VIDEO:
3809  bandwidth += st->codec->bit_rate;
3810  break;
3811  default:
3812  break;
3813  }
3814  }
3815  stream->bandwidth = (bandwidth + 999) / 1000;
3816  }
3817 }
3818 
3819 /* add a codec and set the default parameters */
3820 static void add_codec(FFStream *stream, AVCodecContext *av)
3821 {
3822  AVStream *st;
3823 
3824  /* compute default parameters */
3825  switch(av->codec_type) {
3826  case AVMEDIA_TYPE_AUDIO:
3827  if (av->bit_rate == 0)
3828  av->bit_rate = 64000;
3829  if (av->sample_rate == 0)
3830  av->sample_rate = 22050;
3831  if (av->channels == 0)
3832  av->channels = 1;
3833  break;
3834  case AVMEDIA_TYPE_VIDEO:
3835  if (av->bit_rate == 0)
3836  av->bit_rate = 64000;
3837  if (av->time_base.num == 0){
3838  av->time_base.den = 5;
3839  av->time_base.num = 1;
3840  }
3841  if (av->width == 0 || av->height == 0) {
3842  av->width = 160;
3843  av->height = 128;
3844  }
3845  /* Bitrate tolerance is less for streaming */
3846  if (av->bit_rate_tolerance == 0)
3847  av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3848  (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3849  if (av->qmin == 0)
3850  av->qmin = 3;
3851  if (av->qmax == 0)
3852  av->qmax = 31;
3853  if (av->max_qdiff == 0)
3854  av->max_qdiff = 3;
3855  av->qcompress = 0.5;
3856  av->qblur = 0.5;
3857 
3858  if (!av->nsse_weight)
3859  av->nsse_weight = 8;
3860 
3862  if (!av->me_method)
3863  av->me_method = ME_EPZS;
3864  av->rc_buffer_aggressivity = 1.0;
3865 
3866  if (!av->rc_eq)
3867  av->rc_eq = "tex^qComp";
3868  if (!av->i_quant_factor)
3869  av->i_quant_factor = -0.8;
3870  if (!av->b_quant_factor)
3871  av->b_quant_factor = 1.25;
3872  if (!av->b_quant_offset)
3873  av->b_quant_offset = 1.25;
3874  if (!av->rc_max_rate)
3875  av->rc_max_rate = av->bit_rate * 2;
3876 
3877  if (av->rc_max_rate && !av->rc_buffer_size) {
3878  av->rc_buffer_size = av->rc_max_rate;
3879  }
3880 
3881 
3882  break;
3883  default:
3884  abort();
3885  }
3886 
3887  st = av_mallocz(sizeof(AVStream));
3888  if (!st)
3889  return;
3891  stream->streams[stream->nb_streams++] = st;
3892  memcpy(st->codec, av, sizeof(AVCodecContext));
3893 }
3894 
3895 static enum AVCodecID opt_audio_codec(const char *arg)
3896 {
3898 
3899  if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3900  return AV_CODEC_ID_NONE;
3901 
3902  return p->id;
3903 }
3904 
3905 static enum AVCodecID opt_video_codec(const char *arg)
3906 {
3908 
3909  if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3910  return AV_CODEC_ID_NONE;
3911 
3912  return p->id;
3913 }
3914 
3915 static int avserver_opt_default(const char *opt, const char *arg,
3916  AVCodecContext *avctx, int type)
3917 {
3918  int ret = 0;
3919  const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3920  if(o)
3921  ret = av_opt_set(avctx, opt, arg, 0);
3922  return ret;
3923 }
3924 
3925 static int avserver_opt_preset(const char *arg,
3926  AVCodecContext *avctx, int type,
3927  enum AVCodecID *audio_id, enum AVCodecID *video_id)
3928 {
3929  FILE *f=NULL;
3930  char filename[1000], tmp[1000], tmp2[1000], line[1000];
3931  int ret = 0;
3932  AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3933 
3934  if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3935  codec ? codec->name : NULL))) {
3936  fprintf(stderr, "File for preset '%s' not found\n", arg);
3937  return 1;
3938  }
3939 
3940  while(!feof(f)){
3941  int e= fscanf(f, "%999[^\n]\n", line) - 1;
3942  if(line[0] == '#' && !e)
3943  continue;
3944  e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3945  if(e){
3946  fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3947  ret = 1;
3948  break;
3949  }
3950  if(!strcmp(tmp, "acodec")){
3951  *audio_id = opt_audio_codec(tmp2);
3952  }else if(!strcmp(tmp, "vcodec")){
3953  *video_id = opt_video_codec(tmp2);
3954  }else if(!strcmp(tmp, "scodec")){
3955  /* opt_subtitle_codec(tmp2); */
3956  }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){
3957  fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3958  ret = 1;
3959  break;
3960  }
3961  }
3962 
3963  fclose(f);
3964 
3965  return ret;
3966 }
3967 
3968 static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename,
3969  const char *mime_type)
3970 {
3971  AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3972 
3973  if (fmt) {
3974  AVOutputFormat *stream_fmt;
3975  char stream_format_name[64];
3976 
3977  snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3978  stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3979 
3980  if (stream_fmt)
3981  fmt = stream_fmt;
3982  }
3983 
3984  return fmt;
3985 }
3986 
3987 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3988 {
3989  va_list vl;
3990  va_start(vl, fmt);
3991  fprintf(stderr, "%s:%d: ", filename, line_num);
3992  vfprintf(stderr, fmt, vl);
3993  va_end(vl);
3994 
3995  (*errors)++;
3996 }
3997 
3998 static int parse_ffconfig(const char *filename)
3999 {
4000  FILE *f;
4001  char line[1024];
4002  char cmd[64];
4003  char arg[1024];
4004  const char *p;
4005  int val, errors, line_num;
4006  FFStream **last_stream, *stream, *redirect;
4007  FFStream **last_feed, *feed, *s;
4008  AVCodecContext audio_enc, video_enc;
4009  enum AVCodecID audio_id, video_id;
4010 
4011  f = fopen(filename, "r");
4012  if (!f) {
4013  perror(filename);
4014  return -1;
4015  }
4016 
4017  errors = 0;
4018  line_num = 0;
4019  first_stream = NULL;
4020  last_stream = &first_stream;
4021  first_feed = NULL;
4022  last_feed = &first_feed;
4023  stream = NULL;
4024  feed = NULL;
4025  redirect = NULL;
4026  audio_id = AV_CODEC_ID_NONE;
4027  video_id = AV_CODEC_ID_NONE;
4028 
4029 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4030  for(;;) {
4031  if (fgets(line, sizeof(line), f) == NULL)
4032  break;
4033  line_num++;
4034  p = line;
4035  while (av_isspace(*p))
4036  p++;
4037  if (*p == '\0' || *p == '#')
4038  continue;
4039 
4040  get_arg(cmd, sizeof(cmd), &p);
4041 
4042  if (!av_strcasecmp(cmd, "Port")) {
4043  get_arg(arg, sizeof(arg), &p);
4044  val = atoi(arg);
4045  if (val < 1 || val > 65536) {
4046  ERROR("Invalid_port: %s\n", arg);
4047  }
4048  my_http_addr.sin_port = htons(val);
4049  } else if (!av_strcasecmp(cmd, "BindAddress")) {
4050  get_arg(arg, sizeof(arg), &p);
4051  if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4052  ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4053  }
4054  } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4055  get_arg(arg, sizeof(arg), &p);
4056  val = atoi(arg);
4057  if (val < 1 || val > 65536) {
4058  ERROR("%s:%d: Invalid port: %s\n", arg);
4059  }
4060  my_rtsp_addr.sin_port = htons(atoi(arg));
4061  } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4062  get_arg(arg, sizeof(arg), &p);
4063  if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4064  ERROR("Invalid host/IP address: %s\n", arg);
4065  }
4066  } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4067  get_arg(arg, sizeof(arg), &p);
4068  val = atoi(arg);
4069  if (val < 1 || val > 65536) {
4070  ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4071  }
4073  } else if (!av_strcasecmp(cmd, "MaxClients")) {
4074  get_arg(arg, sizeof(arg), &p);
4075  val = atoi(arg);
4076  if (val < 1 || val > nb_max_http_connections) {
4077  ERROR("Invalid MaxClients: %s\n", arg);
4078  } else {
4079  nb_max_connections = val;
4080  }
4081  } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4082  int64_t llval;
4083  get_arg(arg, sizeof(arg), &p);
4084  llval = atoll(arg);
4085  if (llval < 10 || llval > 10000000) {
4086  ERROR("Invalid MaxBandwidth: %s\n", arg);
4087  } else
4088  max_bandwidth = llval;
4089  } else if (!av_strcasecmp(cmd, "CustomLog")) {
4090  if (!avserver_debug)
4091  get_arg(logfilename, sizeof(logfilename), &p);
4092  } else if (!av_strcasecmp(cmd, "<Feed")) {
4093  /*********************************************/
4094  /* Feed related options */
4095  char *q;
4096  if (stream || feed) {
4097  ERROR("Already in a tag\n");
4098  } else {
4099  feed = av_mallocz(sizeof(FFStream));
4100  get_arg(feed->filename, sizeof(feed->filename), &p);
4101  q = strrchr(feed->filename, '>');
4102  if (*q)
4103  *q = '\0';
4104 
4105  for (s = first_feed; s; s = s->next) {
4106  if (!strcmp(feed->filename, s->filename)) {
4107  ERROR("Feed '%s' already registered\n", s->filename);
4108  }
4109  }
4110 
4111  feed->fmt = av_guess_format("ffm", NULL, NULL);
4112  /* defaut feed file */
4113  snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4114  "/tmp/%s.ffm", feed->filename);
4115  feed->feed_max_size = 5 * 1024 * 1024;
4116  feed->is_feed = 1;
4117  feed->feed = feed; /* self feeding :-) */
4118 
4119  /* add in stream list */
4120  *last_stream = feed;
4121  last_stream = &feed->next;
4122  /* add in feed list */
4123  *last_feed = feed;
4124  last_feed = &feed->next_feed;
4125  }
4126  } else if (!av_strcasecmp(cmd, "Launch")) {
4127  if (feed) {
4128  int i;
4129 
4130  feed->child_argv = av_mallocz(64 * sizeof(char *));
4131 
4132  for (i = 0; i < 62; i++) {
4133  get_arg(arg, sizeof(arg), &p);
4134  if (!arg[0])
4135  break;
4136 
4137  feed->child_argv[i] = av_strdup(arg);
4138  }
4139 
4140  feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4141 
4142  snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4143  "http://%s:%d/%s",
4144  (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4145  inet_ntoa(my_http_addr.sin_addr),
4146  ntohs(my_http_addr.sin_port), feed->filename);
4147  }
4148  } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4149  if (feed) {
4150  get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4151  feed->readonly = 1;
4152  } else if (stream) {
4153  get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4154  }
4155  } else if (!av_strcasecmp(cmd, "File")) {
4156  if (feed) {
4157  get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4158  } else if (stream)
4159  get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4160  } else if (!av_strcasecmp(cmd, "Truncate")) {
4161  if (feed) {
4162  get_arg(arg, sizeof(arg), &p);
4163  feed->truncate = strtod(arg, NULL);
4164  }
4165  } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4166  if (feed) {
4167  char *p1;
4168  double fsize;
4169 
4170  get_arg(arg, sizeof(arg), &p);
4171  p1 = arg;
4172  fsize = strtod(p1, &p1);
4173  switch(av_toupper(*p1)) {
4174  case 'K':
4175  fsize *= 1024;
4176  break;
4177  case 'M':
4178  fsize *= 1024 * 1024;
4179  break;
4180  case 'G':
4181  fsize *= 1024 * 1024 * 1024;
4182  break;
4183  }
4184  feed->feed_max_size = (int64_t)fsize;
4185  if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4186  ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4187  }
4188  }
4189  } else if (!av_strcasecmp(cmd, "</Feed>")) {
4190  if (!feed) {
4191  ERROR("No corresponding <Feed> for </Feed>\n");
4192  }
4193  feed = NULL;
4194  } else if (!av_strcasecmp(cmd, "<Stream")) {
4195  /*********************************************/
4196  /* Stream related options */
4197  char *q;
4198  if (stream || feed) {
4199  ERROR("Already in a tag\n");
4200  } else {
4201  FFStream *s;
4202  stream = av_mallocz(sizeof(FFStream));
4203  get_arg(stream->filename, sizeof(stream->filename), &p);
4204  q = strrchr(stream->filename, '>');
4205  if (*q)
4206  *q = '\0';
4207 
4208  for (s = first_stream; s; s = s->next) {
4209  if (!strcmp(stream->filename, s->filename)) {
4210  ERROR("Stream '%s' already registered\n", s->filename);
4211  }
4212  }
4213 
4214  stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
4215  avcodec_get_context_defaults3(&video_enc, NULL);
4216  avcodec_get_context_defaults3(&audio_enc, NULL);
4217  audio_id = AV_CODEC_ID_NONE;
4218  video_id = AV_CODEC_ID_NONE;
4219  if (stream->fmt) {
4220  audio_id = stream->fmt->audio_codec;
4221  video_id = stream->fmt->video_codec;
4222  }
4223 
4224  *last_stream = stream;
4225  last_stream = &stream->next;
4226  }
4227  } else if (!av_strcasecmp(cmd, "Feed")) {
4228  get_arg(arg, sizeof(arg), &p);
4229  if (stream) {
4230  FFStream *sfeed;
4231 
4232  sfeed = first_feed;
4233  while (sfeed != NULL) {
4234  if (!strcmp(sfeed->filename, arg))
4235  break;
4236  sfeed = sfeed->next_feed;
4237  }
4238  if (!sfeed)
4239  ERROR("feed '%s' not defined\n", arg);
4240  else
4241  stream->feed = sfeed;
4242  }
4243  } else if (!av_strcasecmp(cmd, "Format")) {
4244  get_arg(arg, sizeof(arg), &p);
4245  if (stream) {
4246  if (!strcmp(arg, "status")) {
4247  stream->stream_type = STREAM_TYPE_STATUS;
4248  stream->fmt = NULL;
4249  } else {
4250  stream->stream_type = STREAM_TYPE_LIVE;
4251  /* jpeg cannot be used here, so use single frame jpeg */
4252  if (!strcmp(arg, "jpeg"))
4253  strcpy(arg, "mjpeg");
4254  stream->fmt = avserver_guess_format(arg, NULL, NULL);
4255  if (!stream->fmt) {
4256  ERROR("Unknown Format: %s\n", arg);
4257  }
4258  }
4259  if (stream->fmt) {
4260  audio_id = stream->fmt->audio_codec;
4261  video_id = stream->fmt->video_codec;
4262  }
4263  }
4264  } else if (!av_strcasecmp(cmd, "InputFormat")) {
4265  get_arg(arg, sizeof(arg), &p);
4266  if (stream) {
4267  stream->ifmt = av_find_input_format(arg);
4268  if (!stream->ifmt) {
4269  ERROR("Unknown input format: %s\n", arg);
4270  }
4271  }
4272  } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4273  if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4274  get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4275  } else {
4276  ERROR("FaviconURL only permitted for status streams\n");
4277  }
4278  } else if (!av_strcasecmp(cmd, "Author")) {
4279  if (stream)
4280  get_arg(stream->author, sizeof(stream->author), &p);
4281  } else if (!av_strcasecmp(cmd, "Comment")) {
4282  if (stream)
4283  get_arg(stream->comment, sizeof(stream->comment), &p);
4284  } else if (!av_strcasecmp(cmd, "Copyright")) {
4285  if (stream)
4286  get_arg(stream->copyright, sizeof(stream->copyright), &p);
4287  } else if (!av_strcasecmp(cmd, "Title")) {
4288  if (stream)
4289  get_arg(stream->title, sizeof(stream->title), &p);
4290  } else if (!av_strcasecmp(cmd, "Preroll")) {
4291  get_arg(arg, sizeof(arg), &p);
4292  if (stream)
4293  stream->prebuffer = atof(arg) * 1000;
4294  } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4295  if (stream)
4296  stream->send_on_key = 1;
4297  } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4298  get_arg(arg, sizeof(arg), &p);
4299  audio_id = opt_audio_codec(arg);
4300  if (audio_id == AV_CODEC_ID_NONE) {
4301  ERROR("Unknown AudioCodec: %s\n", arg);
4302  }
4303  } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4304  get_arg(arg, sizeof(arg), &p);
4305  video_id = opt_video_codec(arg);
4306  if (video_id == AV_CODEC_ID_NONE) {
4307  ERROR("Unknown VideoCodec: %s\n", arg);
4308  }
4309  } else if (!av_strcasecmp(cmd, "MaxTime")) {
4310  get_arg(arg, sizeof(arg), &p);
4311  if (stream)
4312  stream->max_time = atof(arg) * 1000;
4313  } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4314  get_arg(arg, sizeof(arg), &p);
4315  if (stream)
4316  audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4317  } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4318  get_arg(arg, sizeof(arg), &p);
4319  if (stream)
4320  audio_enc.channels = atoi(arg);
4321  } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4322  get_arg(arg, sizeof(arg), &p);
4323  if (stream)
4324  audio_enc.sample_rate = atoi(arg);
4325  } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4326  get_arg(arg, sizeof(arg), &p);
4327  if (stream) {
4328 // audio_enc.quality = atof(arg) * 1000;
4329  }
4330  } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4331  if (stream) {
4332  int minrate, maxrate;
4333 
4334  get_arg(arg, sizeof(arg), &p);
4335 
4336  if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4337  video_enc.rc_min_rate = minrate * 1000;
4338  video_enc.rc_max_rate = maxrate * 1000;
4339  } else {
4340  ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4341  }
4342  }
4343  } else if (!av_strcasecmp(cmd, "Debug")) {
4344  if (stream) {
4345  get_arg(arg, sizeof(arg), &p);
4346  video_enc.debug = strtol(arg,0,0);
4347  }
4348  } else if (!av_strcasecmp(cmd, "Strict")) {
4349  if (stream) {
4350  get_arg(arg, sizeof(arg), &p);
4351  video_enc.strict_std_compliance = atoi(arg);
4352  }
4353  } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4354  if (stream) {
4355  get_arg(arg, sizeof(arg), &p);
4356  video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4357  }
4358  } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4359  if (stream) {
4360  get_arg(arg, sizeof(arg), &p);
4361  video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4362  }
4363  } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4364  get_arg(arg, sizeof(arg), &p);
4365  if (stream) {
4366  video_enc.bit_rate = atoi(arg) * 1000;
4367  }
4368  } else if (!av_strcasecmp(cmd, "VideoSize")) {
4369  get_arg(arg, sizeof(arg), &p);
4370  if (stream) {
4371  av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4372  if ((video_enc.width % 16) != 0 ||
4373  (video_enc.height % 16) != 0) {
4374  ERROR("Image size must be a multiple of 16\n");
4375  }
4376  }
4377  } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4378  get_arg(arg, sizeof(arg), &p);
4379  if (stream) {
4380  AVRational frame_rate;
4381  if (av_parse_video_rate(&frame_rate, arg) < 0) {
4382  ERROR("Incorrect frame rate: %s\n", arg);
4383  } else {
4384  video_enc.time_base.num = frame_rate.den;
4385  video_enc.time_base.den = frame_rate.num;
4386  }
4387  }
4388  } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4389  get_arg(arg, sizeof(arg), &p);
4390  if (stream)
4391  video_enc.gop_size = atoi(arg);
4392  } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4393  if (stream)
4394  video_enc.gop_size = 1;
4395  } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4396  if (stream)
4397  video_enc.mb_decision = FF_MB_DECISION_BITS;
4398  } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4399  if (stream) {
4400  video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4401  video_enc.flags |= CODEC_FLAG_4MV;
4402  }
4403  } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4404  !av_strcasecmp(cmd, "AVOptionAudio")) {
4405  char arg2[1024];
4406  AVCodecContext *avctx;
4407  int type;
4408  get_arg(arg, sizeof(arg), &p);
4409  get_arg(arg2, sizeof(arg2), &p);
4410  if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4411  avctx = &video_enc;
4412  type = AV_OPT_FLAG_VIDEO_PARAM;
4413  } else {
4414  avctx = &audio_enc;
4415  type = AV_OPT_FLAG_AUDIO_PARAM;
4416  }
4417  if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4418  ERROR("AVOption error: %s %s\n", arg, arg2);
4419  }
4420  } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4421  !av_strcasecmp(cmd, "AVPresetAudio")) {
4422  AVCodecContext *avctx;
4423  int type;
4424  get_arg(arg, sizeof(arg), &p);
4425  if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4426  avctx = &video_enc;
4427  video_enc.codec_id = video_id;
4428  type = AV_OPT_FLAG_VIDEO_PARAM;
4429  } else {
4430  avctx = &audio_enc;
4431  audio_enc.codec_id = audio_id;
4432  type = AV_OPT_FLAG_AUDIO_PARAM;
4433  }
4434  if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4435  ERROR("AVPreset error: %s\n", arg);
4436  }
4437  } else if (!av_strcasecmp(cmd, "VideoTag")) {
4438  get_arg(arg, sizeof(arg), &p);
4439  if ((strlen(arg) == 4) && stream)
4440  video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4441  } else if (!av_strcasecmp(cmd, "BitExact")) {
4442  if (stream)
4443  video_enc.flags |= CODEC_FLAG_BITEXACT;
4444  } else if (!av_strcasecmp(cmd, "DctFastint")) {
4445  if (stream)
4446  video_enc.dct_algo = FF_DCT_FASTINT;
4447  } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4448  if (stream)
4449  video_enc.idct_algo = FF_IDCT_SIMPLE;
4450  } else if (!av_strcasecmp(cmd, "Qscale")) {
4451  get_arg(arg, sizeof(arg), &p);
4452  if (stream) {
4453  video_enc.flags |= CODEC_FLAG_QSCALE;
4454  video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4455  }
4456  } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4457  get_arg(arg, sizeof(arg), &p);
4458  if (stream) {
4459  video_enc.max_qdiff = atoi(arg);
4460  if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4461  ERROR("VideoQDiff out of range\n");
4462  }
4463  }
4464  } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4465  get_arg(arg, sizeof(arg), &p);
4466  if (stream) {
4467  video_enc.qmax = atoi(arg);
4468  if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4469  ERROR("VideoQMax out of range\n");
4470  }
4471  }
4472  } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4473  get_arg(arg, sizeof(arg), &p);
4474  if (stream) {
4475  video_enc.qmin = atoi(arg);
4476  if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4477  ERROR("VideoQMin out of range\n");
4478  }
4479  }
4480  } else if (!av_strcasecmp(cmd, "LumiMask")) {
4481  get_arg(arg, sizeof(arg), &p);
4482  if (stream)
4483  video_enc.lumi_masking = atof(arg);
4484  } else if (!av_strcasecmp(cmd, "DarkMask")) {
4485  get_arg(arg, sizeof(arg), &p);
4486  if (stream)
4487  video_enc.dark_masking = atof(arg);
4488  } else if (!av_strcasecmp(cmd, "NoVideo")) {
4489  video_id = AV_CODEC_ID_NONE;
4490  } else if (!av_strcasecmp(cmd, "NoAudio")) {
4491  audio_id = AV_CODEC_ID_NONE;
4492  } else if (!av_strcasecmp(cmd, "ACL")) {
4493  parse_acl_row(stream, feed, NULL, p, filename, line_num);
4494  } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4495  if (stream) {
4496  get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4497  }
4498  } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4499  get_arg(arg, sizeof(arg), &p);
4500  if (stream) {
4501  av_freep(&stream->rtsp_option);
4502  stream->rtsp_option = av_strdup(arg);
4503  }
4504  } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4505  get_arg(arg, sizeof(arg), &p);
4506  if (stream) {
4507  if (resolve_host(&stream->multicast_ip, arg) != 0) {
4508  ERROR("Invalid host/IP address: %s\n", arg);
4509  }
4510  stream->is_multicast = 1;
4511  stream->loop = 1; /* default is looping */
4512  }
4513  } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4514  get_arg(arg, sizeof(arg), &p);
4515  if (stream)
4516  stream->multicast_port = atoi(arg);
4517  } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4518  get_arg(arg, sizeof(arg), &p);
4519  if (stream)
4520  stream->multicast_ttl = atoi(arg);
4521  } else if (!av_strcasecmp(cmd, "NoLoop")) {
4522  if (stream)
4523  stream->loop = 0;
4524  } else if (!av_strcasecmp(cmd, "</Stream>")) {
4525  if (!stream) {
4526  ERROR("No corresponding <Stream> for </Stream>\n");
4527  } else {
4528  if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4529  if (audio_id != AV_CODEC_ID_NONE) {
4530  audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4531  audio_enc.codec_id = audio_id;
4532  add_codec(stream, &audio_enc);
4533  }
4534  if (video_id != AV_CODEC_ID_NONE) {
4535  video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4536  video_enc.codec_id = video_id;
4537  add_codec(stream, &video_enc);
4538  }
4539  }
4540  stream = NULL;
4541  }
4542  } else if (!av_strcasecmp(cmd, "<Redirect")) {
4543  /*********************************************/
4544  char *q;
4545  if (stream || feed || redirect) {
4546  ERROR("Already in a tag\n");
4547  } else {
4548  redirect = av_mallocz(sizeof(FFStream));
4549  *last_stream = redirect;
4550  last_stream = &redirect->next;
4551 
4552  get_arg(redirect->filename, sizeof(redirect->filename), &p);
4553  q = strrchr(redirect->filename, '>');
4554  if (*q)
4555  *q = '\0';
4556  redirect->stream_type = STREAM_TYPE_REDIRECT;
4557  }
4558  } else if (!av_strcasecmp(cmd, "URL")) {
4559  if (redirect)
4560  get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4561  } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4562  if (!redirect) {
4563  ERROR("No corresponding <Redirect> for </Redirect>\n");
4564  } else {
4565  if (!redirect->feed_filename[0]) {
4566  ERROR("No URL found for <Redirect>\n");
4567  }
4568  redirect = NULL;
4569  }
4570  } else if (!av_strcasecmp(cmd, "LoadModule")) {
4571  ERROR("Loadable modules no longer supported\n");
4572  } else {
4573  ERROR("Incorrect keyword: '%s'\n", cmd);
4574  }
4575  }
4576 #undef ERROR
4577 
4578  fclose(f);
4579  if (errors)
4580  return -1;
4581  else
4582  return 0;
4583 }
4584 
4585 static void handle_child_exit(int sig)
4586 {
4587  pid_t pid;
4588  int status;
4589 
4590  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4591  FFStream *feed;
4592 
4593  for (feed = first_feed; feed; feed = feed->next) {
4594  if (feed->pid == pid) {
4595  int uptime = time(0) - feed->pid_start;
4596 
4597  feed->pid = 0;
4598  fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4599 
4600  if (uptime < 30)
4601  /* Turn off any more restarts */
4602  feed->child_argv = 0;
4603  }
4604  }
4605  }
4606 
4608 }
4609 
4610 static void opt_debug(void)
4611 {
4612  avserver_debug = 1;
4613  logfilename[0] = '-';
4614 }
4615 
4616 void show_help_default(const char *opt, const char *arg)
4617 {
4618  printf("usage: avserver [options]\n"
4619  "Hyper fast multi format Audio/Video streaming server\n");
4620  printf("\n");
4621  show_help_options(options, "Main options:", 0, 0, 0);
4622 }
4623 
4624 static const OptionDef options[] = {
4625 #include "cmdutils_common_opts.h"
4626  { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4627  { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4628  { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/avserver.conf", "configfile" },
4629  { NULL },
4630 };
4631 
4632 int main(int argc, char **argv)
4633 {
4634  struct sigaction sigact = { { 0 } };
4635 
4636  config_filename = av_strdup("/etc/avserver.conf");
4637 
4638  parse_loglevel(argc, argv, options);
4639  av_register_all();
4641 
4642  show_banner();
4643 
4644  my_program_name = argv[0];
4645 
4646  parse_options(NULL, argc, argv, options, NULL);
4647 
4648  unsetenv("http_proxy"); /* Kill the http_proxy */
4649 
4650  av_lfg_init(&random_state, av_get_random_seed());
4651 
4652  sigact.sa_handler = handle_child_exit;
4653  sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4654  sigaction(SIGCHLD, &sigact, 0);
4655 
4656  if (parse_ffconfig(config_filename) < 0) {
4657  fprintf(stderr, "Incorrect config file - exiting.\n");
4658  exit(1);
4659  }
4660 
4661  /* open log file if needed */
4662  if (logfilename[0] != '\0') {
4663  if (!strcmp(logfilename, "-"))
4664  logfile = stdout;
4665  else
4666  logfile = fopen(logfilename, "a");
4668  }
4669 
4671 
4673 
4675 
4676  /* signal init */
4677  signal(SIGPIPE, SIG_IGN);
4678 
4679  if (http_server() < 0) {
4680  http_log("Could not start server\n");
4681  exit(1);
4682  }
4683 
4684  return 0;
4685 }
static int http_start_receive_data(HTTPContext *c)
Definition: avserver.c:2577
Definition: lfg.h:25
int avio_open(AVIOContext **s, const char *url, int flags)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:772
int is_multicast
Definition: avserver.c:237
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition: utils.c:3092
static HTTPContext * find_rtp_session(const char *session_id)
Definition: avserver.c:3031
int64_t count1
Definition: avserver.c:117
const struct AVCodec * codec
Definition: avcodec.h:1063
static const char * my_program_name
Definition: avserver.c:302
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:62
static void http_log(const char *fmt,...)
Definition: avserver.c:422
char ** child_argv
Definition: avserver.c:231
Bytestream IO Context.
Definition: avio.h:68
static const char * config_filename
Definition: avserver.c:304
int ff_rtp_get_local_rtp_port(URLContext *h)
Return the local rtp port used by the RTP connection.
Definition: rtpproto.c:498
int size
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:242
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
Definition: avserver.c:430
int chunked_encoding
Definition: avserver.c:131
RTSPLowerTransport
Network layer over which RTP/etc packet data will be transported.
Definition: rtsp.h:37
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
Definition: parseutils.c:122
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
Definition: avserver.c:2835
AVCodec * avcodec_find_encoder(enum AVCodecID id)
Find a registered encoder with a matching codec ID.
Definition: utils.c:1654
int packet_stream_index
Definition: avserver.c:166
#define FF_CMP_DCTMAX
Definition: avcodec.h:1459
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:960
int dct_algo
DCT algorithm, see FF_DCT_* below.
Definition: avcodec.h:2443
#define FF_MB_DECISION_BITS
chooses the one which needs the fewest bits
Definition: avcodec.h:1573
AVOption.
Definition: opt.h:233
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
Parse str and put in width_ptr and height_ptr the detected values.
Definition: parseutils.c:95
int64_t time2
Definition: avserver.c:118
float avg_frame_size
Definition: avserver.c:258
static int validate_acl(FFStream *stream, HTTPContext *c)
Definition: avserver.c:1421
int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition: mux.c:302
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:454
static void build_file_streams(void)
Definition: avserver.c:3607
float qblur
amount of qscale smoothing over time (0.0-1.0)
Definition: avcodec.h:2054
AVInputFormat * ifmt
Definition: avserver.c:213
#define FF_IDCT_SIMPLE
Definition: avcodec.h:2459
#define AV_RB64
Definition: intreadwrite.h:164
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: utils.c:381
HTTPState
Definition: avserver.c:70
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:3208
int av_parse_time(int64_t *timeval, const char *timestr, int duration)
Parse timestr and return in *time a corresponding number of microseconds.
Definition: parseutils.c:482
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: avio.c:276
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle...
Definition: avstring.c:54
struct HTTPContext * next
Definition: avserver.c:133
void show_banner(void)
Print the program banner to stderr.
Definition: cmdutils.c:815
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
Definition: avserver.c:2779
static int64_t cur_time
Definition: avserver.c:318
enum AVCodecID video_codec
default video codec
Definition: avformat.h:448
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt,...)
Definition: avserver.c:3987
int multicast_port
Definition: avserver.c:239
int feed_opened
Definition: avserver.c:244
struct in_addr last
Definition: avserver.c:203
AVFormatContext * fmt_in
Definition: avserver.c:139
char protocol[16]
Definition: avserver.c:160
uint8_t * packet_buffer_end
Definition: avserver.c:183
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:747
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
Definition: avserver.c:3235
int num
numerator
Definition: rational.h:44
#define AV_OPT_FLAG_AUDIO_PARAM
Definition: opt.h:266
int index
stream index in AVFormatContext
Definition: avformat.h:684
int size
Definition: avcodec.h:974
static int parse_ffconfig(const char *filename)
Definition: avserver.c:3998
#define AVIO_FLAG_READ
read-only
Definition: avio.h:292
enhanced predictive zonal search
Definition: avcodec.h:528
int64_t feed_write_index
Definition: avserver.c:251
static void parse_acl_row(FFStream *stream, FFStream *feed, IPAddressACL *ext_acl, const char *p, const char *filename, int line_num)
Definition: avserver.c:1289
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:293
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown) That is the width of a pixel divided by the height of the pixel...
Definition: avcodec.h:1422
static int rtsp_parse_request(HTTPContext *c)
Definition: avserver.c:2841
AVOutputFormat * fmt
Definition: avserver.c:214
enum AVMediaType codec_type
Definition: rtp.c:36
static void free_acl_list(IPAddressACL *in_acl)
Definition: avserver.c:1392
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:166
struct IPAddressACL * next
Definition: avserver.c:199
int64_t timeout
Definition: avserver.c:127
UDP/unicast.
Definition: rtsp.h:38
struct pollfd * poll_entry
Definition: avserver.c:126
void * priv_data
Definition: avformat.h:703
enum AVMediaType type
Definition: avcodec.h:2768
#define FF_ARRAY_ELEMS(a)
static AVOutputFormat * avserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
Definition: avserver.c:3968
#define freeaddrinfo
Definition: network.h:183
static void remove_stream(FFStream *stream)
Definition: avserver.c:3543
RedirType
Definition: avserver.c:1467
void show_help_default(const char *opt, const char *arg)
Per-avtool specific help handler.
Definition: avserver.c:4616
int frame_skip_cmp
frame skip comparison function
Definition: avcodec.h:2213
AVCodec.
Definition: avcodec.h:2755
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:948
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
Copy the settings of the source AVCodecContext into the destination AVCodecContext.
Definition: options.c:138
char feed_filename[1024]
Definition: avserver.c:223
enum RTSPLowerTransport lower_transport
network layer transport protocol; e.g.
Definition: rtsp.h:120
static void build_feed_streams(void)
Definition: avserver.c:3654
char dynamic_acl[1024]
Definition: avserver.c:216
This describes the server response to each RTSP command.
Definition: rtsp.h:126
int multicast_ttl
Definition: avserver.c:240
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avcodec.h:1173
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
RTSPTransportField transports[RTSP_MAX_TRANSPORTS]
describes the complete "Transport:" line of the server in response to a SETUP RTSP command by the cli...
Definition: rtsp.h:141
#define IOBUFFER_INIT_SIZE
Definition: avserver.c:103
IPAddressACL * acl
Definition: avserver.c:215
Format I/O context.
Definition: avformat.h:871
const int program_birth_year
program birth year, defined by the program for show_banner()
Definition: avserver.c:66
int avio_check(const char *url, int flags)
Return AVIO_FLAG_* access flags corresponding to the access permissions of the resource in url...
Definition: avio.c:318
#define AVFMT_FLAG_NOPARSE
Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no...
Definition: avformat.h:980
int64_t file_size
Definition: ffm.h:46
Public dictionary API.
int feed_streams[MAX_STREAMS]
Definition: avserver.c:152
int bit_rate_tolerance
number of bits the bitstream is allowed to diverge from the reference.
Definition: avcodec.h:1120
uint8_t
int feed_streams[MAX_STREAMS]
Definition: avserver.c:222
char session_id[512]
the "Session:" field.
Definition: rtsp.h:147
Opaque data information usually continuous.
Definition: avutil.h:189
static void http_vlog(const char *fmt, va_list vargs)
Definition: avserver.c:404
int64_t bytes_served
Definition: avserver.c:249
AVOptions.
uint8_t * packet_buffer_ptr
Definition: avserver.c:183
#define HAS_ARG
Definition: cmdutils.h:142
static void opt_debug(void)
Definition: avserver.c:4610
static unsigned int nb_connections
Definition: avserver.c:313
miscellaneous OS support macros and functions.
static void compute_real_filename(char *filename, int max_size)
Definition: avserver.c:1443
float b_quant_factor
qscale factor between IP and B-frames If > 0 then the last P-frame quantizer will be used (q= lastp_q...
Definition: avcodec.h:1311
int id
Format-specific stream ID.
Definition: avformat.h:690
const char program_name[]
program name, defined by the program for show_version().
Definition: avserver.c:65
static int http_parse_request(HTTPContext *c)
Definition: avserver.c:1477
static void get_arg(char *buf, int buf_size, const char **pp)
Definition: avserver.c:1257
static void get_word(char *buf, int buf_size, const char **pp)
Definition: avserver.c:1239
void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, RTSPState *rt, const char *method)
int loop
Definition: avserver.c:241
static void start_children(FFStream *feed)
Definition: avserver.c:475
#define AVFMT_FLAG_GENPTS
Generate missing pts even if it requires parsing future frames.
Definition: avformat.h:975
static HTTPContext * rtp_new_connection(struct sockaddr_in *from_addr, FFStream *stream, const char *session_id, enum RTSPLowerTransport rtp_protocol)
Definition: avserver.c:3310
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1162
static uint64_t max_bandwidth
Definition: avserver.c:315
static int http_send_data(HTTPContext *c)
Definition: avserver.c:2458
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:935
double strtod(const char *, char **)
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:98
Aggregate operation not allowed.
Definition: rtspcodes.h:32
struct FFStream * next_feed
Definition: avserver.c:253
static FFStream * first_feed
Definition: avserver.c:266
Service Unavailable.
Definition: rtspcodes.h:36
uint8_t * data
Definition: avcodec.h:973
void parse_options(void *optctx, int argc, char **argv, const OptionDef *options, void(*parse_arg_function)(void *, const char *))
Definition: cmdutils.c:333
static int flags
Definition: log.c:44
int avformat_network_init(void)
Do global initialization of network components.
Definition: utils.c:3329
struct in_addr multicast_ip
Definition: avserver.c:238
static HTTPContext * find_rtp_session_with_url(const char *url, const char *session_id)
Definition: avserver.c:3201
int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
Generate an SDP for an RTP session.
Definition: sdp.c:689
int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
Attempt to find a specific tag in a URL.
Definition: parseutils.c:606
static AVStream * add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
Definition: avserver.c:3473
#define CODEC_FLAG_BITEXACT
Use only bitexact stuff (except (I)DCT).
Definition: avcodec.h:685
int av_match_ext(const char *filename, const char *extensions)
Return a positive value if the given filename has one of the given extensions, 0 otherwise.
Definition: format.c:73
static void copy(LZOContext *c, int cnt)
Copies bytes from input to output buffer with checking.
Definition: lzo.c:79
void parse_loglevel(int argc, char **argv, const OptionDef *options)
Find the '-loglevel' option in the command line args and apply it.
Definition: cmdutils.c:423
int readonly
Definition: avserver.c:246
static int http_receive_data(HTTPContext *c)
Definition: avserver.c:2623
void show_help_options(const OptionDef *options, const char *msg, int req_flags, int rej_flags, int alt_flags)
Print help for all options matching specified flags.
Definition: cmdutils.c:135
float lumi_masking
luminance masking (0-> disabled)
Definition: avcodec.h:1362
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:165
int chunk_size
Definition: avserver.c:132
int duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:995
static FILE * logfile
Definition: avserver.c:322
DataRateData datarate
Definition: avserver.c:158
static unsigned int nb_max_http_connections
Definition: avserver.c:311
int nb_transports
number of items in the 'transports' variable below
Definition: rtsp.h:133
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:263
Only aggregate operation allowed.
Definition: rtspcodes.h:33
static const int rates[]
struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:890
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1023
AVCodec * avcodec_find_encoder_by_name(const char *name)
Find a registered encoder with the specified name.
Definition: utils.c:1659
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:122
static const uint8_t frame_size[4]
Definition: g723_1_data.h:47
int avcodec_close(AVCodecContext *avctx)
Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext its...
Definition: utils.c:1590
static int extract_rates(char *rates, int ratelen, const char *request)
Definition: avserver.c:1106
static void http_send_too_busy_reply(int fd)
Definition: avserver.c:776
int64_t feed_size
Definition: avserver.c:252
AVIOContext * avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Allocate and initialize an AVIOContext for buffered I/O.
Definition: aviobuf.c:107
int64_t cur_clock
Definition: avserver.c:148
enum AVCodecID id
Definition: avcodec.h:2769
int nb_streams
Definition: avserver.c:217
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:105
uint8_t * buffer_end
Definition: avserver.c:128
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1064
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:186
int last_packet_sent
Definition: avserver.c:156
int main(int argc, char **argv)
Definition: avserver.c:4632
static int handle_connection(HTTPContext *c)
Definition: avserver.c:929
int got_key_frame
Definition: avserver.c:134
int suppress_log
Definition: avserver.c:157
#define closesocket
Definition: avserver.c:24
static void rtsp_cmd_options(HTTPContext *c, const char *url)
Definition: avserver.c:2975
static int64_t get_server_clock(HTTPContext *c)
Definition: avserver.c:2205
int64_t data_count
Definition: avserver.c:135
#define AVERROR(e)
Definition: error.h:43
int qmax
maximum quantizer
Definition: avcodec.h:2068
static uint64_t current_bandwidth
Definition: avserver.c:316
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:794
AVIOContext * pb
Definition: avserver.c:170
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:159
char copyright[512]
Definition: avserver.c:227
int flags
CODEC_FLAG_*.
Definition: avcodec.h:1142
int64_t cur_pts
Definition: avserver.c:142
static FFStream * first_stream
Definition: avserver.c:267
Definition: graph2dot.c:49
#define CODEC_FLAG_QSCALE
Use fixed qscale.
Definition: avcodec.h:656
int rc_max_rate
maximum bitrate
Definition: avcodec.h:2115
int av_log_get_level(void)
Get the current log level.
Definition: log.c:165
const char * name
Name of the codec implementation.
Definition: avcodec.h:2762
struct in_addr first
Definition: avserver.c:202
float i_quant_factor
qscale factor between P and I-frames If > 0 then the last p frame quantizer will be used (q= lastp_q*...
Definition: avcodec.h:1348
const char * rc_eq
rate control equation
Definition: avcodec.h:2108
static int socket_open_listen(struct sockaddr_in *my_addr)
Definition: avserver.c:534
uint8_t * packet_buffer
Definition: avserver.c:183
int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.c:225
enum AVCodecID codec_id
Definition: mov_chan.c:432
int buffer_size
Definition: avserver.c:163
#define FFMAX(a, b)
Definition: common.h:55
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:81
static char logfilename[1024]
Definition: avserver.c:264
static int ffm_write_write_index(int fd, int64_t pos)
Definition: avserver.c:334
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:979
#define CHECK_CODEC(x)
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:702
int rc_buffer_size
decoder bitstream buffer size
Definition: avcodec.h:2093
AVFormatContext fmt_ctx
Definition: avserver.c:155
static int avserver_opt_preset(const char *arg, AVCodecContext *avctx, int type, enum AVCodecID *audio_id, enum AVCodecID *video_id)
Definition: avserver.c:3925
const AVOption * av_opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags)
Look for an option in an object.
Definition: opt.c:642
static HTTPContext * first_http_ctx
Definition: avserver.c:265
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:923
#define MAX_STREAMS
Definition: avserver.c:101
#define RTSP_REQUEST_TIMEOUT
Definition: avserver.c:107
static int open_input_stream(HTTPContext *c, const char *info)
Definition: avserver.c:2141
static void log_connection(HTTPContext *c)
Definition: avserver.c:442
AVInputFormat * av_find_input_format(const char *short_name)
Find AVInputFormat based on the short name of the input format.
Definition: format.c:176
enum StreamType stream_type
Definition: avserver.c:208
static int modify_current_stream(HTTPContext *c, char *rates)
Definition: avserver.c:1190
char method[16]
Definition: avserver.c:161
struct FFStream * feed
Definition: avserver.c:210
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:117
int bit_rate
the average bitrate
Definition: avcodec.h:1112
int is_packetized
Definition: avserver.c:165
char filename[1024]
input or output filename
Definition: avformat.h:943
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:234
#define FFMIN(a, b)
Definition: common.h:57
enum IPAddressAction action
Definition: avserver.c:200
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
Definition: avserver.c:2984
int64_t start_time
Definition: avserver.c:140
int av_strcasecmp(const char *a, const char *b)
Definition: avstring.c:156
void av_log_set_callback(void(*callback)(void *, int, const char *, va_list))
Set the logging callback.
Definition: log.c:180
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition: options.c:124
int ff_inet_aton(const char *str, struct in_addr *add)
int width
picture width / height.
Definition: avcodec.h:1217
int idct_algo
IDCT algorithm, see FF_IDCT_* below.
Definition: avcodec.h:2456
int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size)
Open a write only packetized memory stream with a maximum packet size of 'max_packet_size'.
Definition: aviobuf.c:953
#define RTSP_TCP_MAX_PACKET_SIZE
Definition: rtsp.h:74
#define ff_neterrno()
Definition: network.h:63
Method Not Allowed.
Definition: rtspcodes.h:28
static enum AVCodecID opt_audio_codec(const char *arg)
Definition: avserver.c:3895
const char * name
Definition: avformat.h:437
time_t pid_start
Definition: avserver.c:230
static av_always_inline av_const long int lrintf(float x)
Definition: libm.h:144
This describes a single item in the "Transport:" line of one stream as negotiated by the SETUP RTSP c...
Definition: rtsp.h:87
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
Definition: avserver.c:1404
static char buffer[20]
Definition: seek-test.c:31
int switch_pending
Definition: avserver.c:154
URLContext * rtp_handles[MAX_STREAMS]
Definition: avserver.c:179
struct HTTPContext * rtsp_c
Definition: avserver.c:182
AVOutputFormat * av_guess_format(const char *short_name, const char *filename, const char *mime_type)
Return the output format in the list of registered output formats which best matches the provided par...
Definition: format.c:118
static int need_to_start_children
Definition: avserver.c:308
int mb_decision
macroblock decision mode
Definition: avcodec.h:1571
static AVLFG random_state
Definition: avserver.c:320
int max_qdiff
maximum quantizer difference between frames
Definition: avcodec.h:2075
const char *(* item_name)(void *ctx)
A pointer to a function which returns the name of a context instance ctx associated with the class...
Definition: log.h:44
int ff_socket_nonblock(int socket, int enable)
int cur_frame_bytes
Definition: avserver.c:144
static int64_t ffm_read_write_index(int fd)
Definition: avserver.c:324
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:37
Stream structure.
Definition: avformat.h:683
enum RTSPLowerTransport rtp_protocol
Definition: avserver.c:174
struct sockaddr_in from_addr
Definition: avserver.c:125
NULL
Definition: eval.c:55
static int width
Definition: utils.c:156
int http_error
Definition: avserver.c:129
#define ERROR(...)
static void start_multicast(void)
Definition: avserver.c:567
enum AVMediaType codec_type
Definition: avcodec.h:1062
int(* read_seek)(struct AVFormatContext *, int stream_index, int64_t timestamp, int flags)
Seek to a given timestamp relative to the frames in stream component stream_index.
Definition: avformat.h:601
static void compute_status(HTTPContext *c)
Definition: avserver.c:1899
enum AVCodecID codec_id
Definition: avcodec.h:1065
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:240
long long data_count
Definition: avserver.c:257
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:213
int sample_rate
samples per second
Definition: avcodec.h:1779
AVIOContext * pb
I/O context.
Definition: avformat.h:913
static const char * http_state[]
Definition: avserver.c:85
int debug
debug
Definition: avcodec.h:2348
Definition: ffm.h:44
#define AV_OPT_FLAG_VIDEO_PARAM
Definition: opt.h:267
main external API structure.
Definition: avcodec.h:1054
char author[512]
Definition: avserver.c:225
static void close(AVCodecParserContext *s)
Definition: h264_parser.c:489
int qmin
minimum quantizer
Definition: avcodec.h:2061
int wmp_client_id
Definition: avserver.c:159
int64_t time1
Definition: avserver.c:118
int send_on_key
Definition: avserver.c:220
unsigned int codec_tag
fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
Definition: avcodec.h:1080
int prebuffer
Definition: avserver.c:218
int64_t max_time
Definition: avserver.c:219
static int compute_datarate(DataRateData *drd, int64_t count)
Definition: avserver.c:466
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:38
struct FFStream * stream
Definition: avserver.c:150
static void close_connection(HTTPContext *c)
Definition: avserver.c:842
Definition: url.h:41
char url[128]
Definition: avserver.c:162
int extradata_size
Definition: avcodec.h:1163
char filename[1024]
Definition: avserver.c:209
static int http_server(void)
Definition: avserver.c:622
static RTSPTransportField * find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
Definition: avserver.c:3045
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:62
FILE * get_preset_file(char *filename, size_t filename_size, const char *preset_name, int is_path, const char *codec_name)
Get a file corresponding to a preset file.
Definition: cmdutils.c:1455
int client_port_max
Definition: rtsp.h:100
Describe the class of an AVClass context structure.
Definition: log.h:33
static IPAddressACL * parse_dynamic_acl(FFStream *stream, HTTPContext *c)
Definition: avserver.c:1355
float rc_buffer_aggressivity
Definition: avcodec.h:2124
rational number numerator/denominator
Definition: rational.h:43
static void update_datarate(DataRateData *drd, int64_t count)
Definition: avserver.c:452
uint8_t * buffer_ptr
Definition: avserver.c:128
#define OPT_STRING
Definition: cmdutils.h:145
static void start_wait_request(HTTPContext *c, int is_rtsp)
Definition: avserver.c:762
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:30
int64_t first_pts
Definition: avserver.c:141
static const char * input_filename
Definition: avplay.c:228
float b_quant_offset
qscale offset between IP and B-frames
Definition: avcodec.h:1324
static const OptionDef options[]
Definition: avserver.c:68
misc parsing utilities
float qcompress
amount of qscale change between easy & hard scenes (0.0-1.0)
Definition: avcodec.h:2053
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
Definition: avserver.c:1153
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
Return the next frame of a stream.
Definition: utils.c:1120
static struct sockaddr_in my_http_addr
Definition: avserver.c:261
int switch_feed_streams[MAX_STREAMS]
Definition: avserver.c:153
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes...
Definition: avstring.c:91
static enum AVCodecID opt_video_codec(const char *arg)
Definition: avserver.c:3905
float dark_masking
darkness masking (0-> disabled)
Definition: avcodec.h:1390
int global_quality
Global quality for codecs which cannot change it per frame.
Definition: avcodec.h:1128
RTSPStatusCode
RTSP handling.
Definition: rtspcodes.h:26
int ffurl_close(URLContext *h)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:297
static int64_t get_packet_send_clock(HTTPContext *c)
Definition: avserver.c:2213
static void extract_mpeg4_header(AVFormatContext *infile)
Definition: avserver.c:3556
uint8_t level
Definition: svq3.c:143
pid_t pid
Definition: avserver.c:229
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Seek to the keyframe at timestamp.
Definition: utils.c:1662
int height
Definition: gxfenc.c:72
Not Enough Bandwidth.
Definition: rtspcodes.h:29
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
Definition: avserver.c:357
int gop_size
the number of pictures in a group of pictures, or 0 for intra_only
Definition: avcodec.h:1238
static int av_toupper(int c)
Locale-independent conversion of ASCII characters to uppercase.
Definition: avstring.h:172
int truncate
Definition: avserver.c:247
#define OPT_BOOL
Definition: cmdutils.h:143
int is_feed
Definition: avserver.c:245
#define getaddrinfo
Definition: network.h:182
char transport_option[512]
Definition: avserver.c:113
Main libavformat public API header.
int conns_served
Definition: avserver.c:248
int64_t feed_max_size
Definition: avserver.c:250
static char * ctime1(char *buf2)
Definition: avserver.c:390
static struct sockaddr_in my_rtsp_addr
Definition: avserver.c:262
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:211
int nsse_weight
noise vs.
Definition: avcodec.h:2589
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, struct in_addr my_ip)
Definition: avserver.c:2930
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
Read packets of a media file to get stream information.
Definition: utils.c:2201
struct addrinfo * ai_next
Definition: network.h:110
struct FFStream * next
Definition: avserver.c:232
char comment[512]
Definition: avserver.c:228
int den
denominator
Definition: rational.h:45
int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec)
Set the fields of the given AVCodecContext to default values corresponding to the given codec (defaul...
Definition: options.c:80
struct AVInputFormat * iformat
The input container format.
Definition: avformat.h:883
int64_t count2
Definition: avserver.c:117
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: utils.c:2640
int ff_rtp_get_local_rtcp_port(URLContext *h)
Return the local rtcp port used by the RTP connection.
Definition: rtpproto.c:510
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
Definition: avserver.c:3286
static void compute_bandwidth(void)
Definition: avserver.c:3796
char title[512]
Definition: avserver.c:226
uint8_t * pb_buffer
Definition: avserver.c:169
TCP; interleaved in RTSP.
Definition: rtsp.h:39
#define FF_DCT_FASTINT
Definition: avcodec.h:2445
int len
IPAddressAction
Definition: avserver.c:193
static void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size)
Definition: avserver.c:347
uint8_t * buffer
Definition: avserver.c:164
int channels
number of audio channels
Definition: avcodec.h:1780
enum AVCodecID audio_codec
default audio codec
Definition: avformat.h:447
Unsupported transport.
Definition: rtspcodes.h:34
void * priv_data
Format private data.
Definition: avformat.h:899
static int avserver_debug
Definition: avserver.c:306
Method Not Valid in This State.
Definition: rtspcodes.h:31
#define FF_QP2LAMBDA
factor to convert from H.263 QP to lambda
Definition: avutil.h:207
static void new_connection(int server_fd, int is_rtsp)
Definition: avserver.c:792
char session_id[32]
Definition: avserver.c:175
int64_t write_index
Definition: ffm.h:46
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:972
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:684
int frame_number
Frame counter, set by libavcodec.
Definition: avcodec.h:1810
int max_packet_size
if non zero, the stream is packetized with this max packet size
Definition: url.h:47
AVFormatContext * rtp_ctx[MAX_STREAMS]
Definition: avserver.c:176
RTSP Version not supported.
Definition: rtspcodes.h:37
int pts_stream_index
Definition: avserver.c:147
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h)
Definition: avserver.c:3058
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:516
unbuffered private I/O API
static int avserver_opt_default(const char *opt, const char *arg, AVCodecContext *avctx, int type)
Definition: avserver.c:3915
uint32_t av_get_random_seed(void)
Get random data.
Definition: random_seed.c:95
unsigned bandwidth
Definition: avserver.c:233
Internal Server Error.
Definition: rtspcodes.h:35
static int add_av_stream(FFStream *feed, AVStream *st)
Definition: avserver.c:3503
int me_method
Motion estimation algorithm used for video coding.
Definition: avcodec.h:1256
enum HTTPState state
Definition: avserver.c:123
Session Not Found.
Definition: rtspcodes.h:30
int stream_index
Definition: avcodec.h:975
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:719
int rc_min_rate
minimum bitrate
Definition: avcodec.h:2122
AVStream * streams[MAX_STREAMS]
Definition: avserver.c:221
#define MKTAG(a, b, c, d)
Definition: common.h:238
struct sockaddr * ai_addr
Definition: network.h:108
#define CODEC_FLAG_4MV
4 MV per MB allowed / advanced prediction for H.263.
Definition: avcodec.h:657
const char * mime_type
Definition: avformat.h:444
static void handle_child_exit(int sig)
Definition: avserver.c:4585
static unsigned int nb_max_connections
Definition: avserver.c:312
This structure stores compressed data.
Definition: avcodec.h:950
void av_register_all(void)
Initialize libavformat and register all the muxers, demuxers and protocols.
Definition: allformats.c:51
static void fmt_bytecount(AVIOContext *pb, int64_t count)
Definition: avserver.c:1889
char * rtsp_option
Definition: avserver.c:235
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:210
#define AVFMT_FLAG_NOFILLIN
Do not infer any values from other values, just return what is stored in the container.
Definition: avformat.h:979
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
int strict_std_compliance
strictly follow the standard (MPEG4, ...).
Definition: avcodec.h:2327
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:966
AVDictionary * in_opts
Definition: avserver.c:212
static void skip_spaces(const char **pp)
Definition: avserver.c:1230
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:228
#define c1
Definition: idct_sh4.c:26
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
static int no_launch
Definition: avserver.c:307
#define FFM_PACKET_SIZE
Definition: ffm.h:31
#define HTTP_REQUEST_TIMEOUT
Definition: avserver.c:106
int client_port_min
UDP client ports; these should be the local ports of the UDP RTP (and RTCP) sockets over which we rec...
Definition: rtsp.h:100
int64_t cur_frame_duration
Definition: avserver.c:143
static int http_prepare_data(HTTPContext *c)
Definition: avserver.c:2228
int feed_fd
Definition: avserver.c:137
static int rtp_new_av_stream(HTTPContext *c, int stream_index, struct sockaddr_in *dest_addr, HTTPContext *rtsp_c)
Definition: avserver.c:3376
int ai_family
Definition: network.h:104
static void add_codec(FFStream *stream, AVCodecContext *av)
Definition: avserver.c:3820
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
Definition: avserver.c:3261