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