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