PPC970 patch + cpu-specific tuning support by (Romain Dolbeau <dolbeau at irisa dot...
[libav.git] / ffserver.c
</
CommitLineData
85f07f22
FB
1/*
2 * Multiple format streaming server
773a21b8 3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
85f07f22 4 *
773a21b8
FB
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
85f07f22 9 *
773a21b8 10 * This library is distributed in the hope that it will be useful,
85f07f22 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
773a21b8
FB
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
85f07f22 14 *
773a21b8
FB
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
85f07f22 18 */
773a21b8 19#define HAVE_AV_CONFIG_H
ce2749d2 20#include "common.h"
773a21b8
FB
21#include "avformat.h"
22
85f07f22 23#include <stdarg.h>
85f07f22
FB
24#include <unistd.h>
25#include <fcntl.h>
26#include <sys/ioctl.h>
27#include <sys/poll.h>
28#include <errno.h>
29#include <sys/time.h>
30#include <time.h>
85f07f22
FB
31#include <sys/types.h>
32#include <sys/socket.h>
5eb765ef 33#include <sys/wait.h>
9c938e77 34#include <netinet/in.h>
b8a78f41 35#include <arpa/inet.h>
85f07f22
FB
36#include <netdb.h>
37#include <ctype.h>
38#include <signal.h>
6638d424 39#ifdef CONFIG_HAVE_DLFCN
2effd274 40#include <dlfcn.h>
6638d424 41#endif
2effd274
FB
42
43#include "ffserver.h"
85f07f22
FB
44
45/* maximum number of simultaneous HTTP connections */
46#define HTTP_MAX_CONNECTIONS 2000
47
48enum HTTPState {
49 HTTPSTATE_WAIT_REQUEST,
50 HTTPSTATE_SEND_HEADER,
51 HTTPSTATE_SEND_DATA_HEADER,
2effd274 52 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
85f07f22 53 HTTPSTATE_SEND_DATA_TRAILER,
2effd274
FB
54 HTTPSTATE_RECEIVE_DATA,
55 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
56 HTTPSTATE_WAIT, /* wait before sending next packets */
57 HTTPSTATE_WAIT_SHORT, /* short wait for short term
58 bandwidth limitation */
59 HTTPSTATE_READY,
60
61 RTSPSTATE_WAIT_REQUEST,
62 RTSPSTATE_SEND_REPLY,
85f07f22
FB
63};
64
65const char *http_state[] = {
2effd274
FB
66 "HTTP_WAIT_REQUEST",
67 "HTTP_SEND_HEADER",
68
85f07f22
FB
69 "SEND_DATA_HEADER",
70 "SEND_DATA",
71 "SEND_DATA_TRAILER",
72 "RECEIVE_DATA",
73 "WAIT_FEED",
2effd274
FB
74 "WAIT",
75 "WAIT_SHORT",
76 "READY",
77
78 "RTSP_WAIT_REQUEST",
79 "RTSP_SEND_REPLY",
85f07f22
FB
80};
81
cde25790 82#define IOBUFFER_INIT_SIZE 8192
85f07f22
FB
83
84/* coef for exponential mean for bitrate estimation in statistics */
85#define AVG_COEF 0.9
86
87/* timeouts are in ms */
2effd274
FB
88#define HTTP_REQUEST_TIMEOUT (15 * 1000)
89#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
90
85f07f22
FB
91#define SYNC_TIMEOUT (10 * 1000)
92
5eb765ef 93typedef struct {
0c1a9eda 94 int64_t count1, count2;
5eb765ef
PG
95 long time1, time2;
96} DataRateData;
97
85f07f22
FB
98/* context associated with one connection */
99typedef struct HTTPContext {
100 enum HTTPState state;
101 int fd; /* socket file descriptor */
102 struct sockaddr_in from_addr; /* origin */
103 struct pollfd *poll_entry; /* used when polling */
104 long timeout;
0c1a9eda 105 uint8_t *buffer_ptr, *buffer_end;
85f07f22
FB
106 int http_error;
107 struct HTTPContext *next;
42a63c6a 108 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
0c1a9eda 109 int64_t data_count;
85f07f22
FB
110 /* feed input */
111 int feed_fd;
112 /* input format handling */
113 AVFormatContext *fmt_in;
2effd274 114 long start_time; /* In milliseconds - this wraps fairly often */
0c1a9eda 115 int64_t first_pts; /* initial pts value */
2effd274 116 int pts_stream_index; /* stream we choose as clock reference */
85f07f22
FB
117 /* output format handling */
118 struct FFStream *stream;
cde25790
PG
119 /* -1 is invalid stream */
120 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
121 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
122 int switch_pending;
2effd274 123 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
85f07f22 124 int last_packet_sent; /* true if last data packet was sent */
7434ba6d 125 int suppress_log;
5eb765ef 126 DataRateData datarate;
3120d2a2 127 int wmp_client_id;
7434ba6d
PG
128 char protocol[16];
129 char method[16];
130 char url[128];
cde25790 131 int buffer_size;
0c1a9eda 132 uint8_t *buffer;
2effd274
FB
133 int is_packetized; /* if true, the stream is packetized */
134 int packet_stream_index; /* current stream for output in state machine */
135
136 /* RTSP state specific */
0c1a9eda 137 uint8_t *pb_buffer; /* XXX: use that in all the code */
2effd274
FB
138 ByteIOContext *pb;
139 int seq; /* RTSP sequence number */
140
141 /* RTP state specific */
142 enum RTSPProtocol rtp_protocol;
143 char session_id[32]; /* session id */
144 AVFormatContext *rtp_ctx[MAX_STREAMS];
145 URLContext *rtp_handles[MAX_STREAMS];
146 /* RTP short term bandwidth limitation */
147 int packet_byte_count;
148 int packet_start_time_us; /* used for short durations (a few
149 seconds max) */
85f07f22
FB
150} HTTPContext;
151
a4d70941
PG
152static AVFrame dummy_frame;
153
85f07f22
FB
154/* each generated stream is described here */
155enum StreamType {
156 STREAM_TYPE_LIVE,
157 STREAM_TYPE_STATUS,
cde25790 158 STREAM_TYPE_REDIRECT,
85f07f22
FB
159};
160
8256c0a3
PG
161enum IPAddressAction {
162 IP_ALLOW = 1,
163 IP_DENY,
164};
165
166typedef struct IPAddressACL {
167 struct IPAddressACL *next;
168 enum IPAddressAction action;
efa04ce2 169 /* These are in host order */
8256c0a3
PG
170 struct in_addr first;
171 struct in_addr last;
172} IPAddressACL;
173
85f07f22
FB
174/* description of each stream of the ffserver.conf file */
175typedef struct FFStream {
176 enum StreamType stream_type;
177 char filename[1024]; /* stream filename */
2effd274
FB
178 struct FFStream *feed; /* feed we are using (can be null if
179 coming from file) */
bd7cf6ad 180 AVOutputFormat *fmt;
8256c0a3 181 IPAddressACL *acl;
85f07f22 182 int nb_streams;
42a63c6a 183 int prebuffer; /* Number of millseconds early to start */
2ac887ba 184 long max_time; /* Number of milliseconds to run */
79c4ea3c 185 int send_on_key;
85f07f22
FB
186 AVStream *streams[MAX_STREAMS];
187 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
188 char feed_filename[1024]; /* file name of the feed storage, or
189 input file name for a stream */
2ac887ba
PG
190 char author[512];
191 char title[512];
192 char copyright[512];
193 char comment[512];
cde25790 194 pid_t pid; /* Of ffmpeg process */
5eb765ef 195 time_t pid_start; /* Of ffmpeg process */
cde25790 196 char **child_argv;
85f07f22 197 struct FFStream *next;
6edd6884 198 int bandwidth; /* bandwidth, in kbits/s */
2effd274
FB
199 /* RTSP options */
200 char *rtsp_option;
829ac53d
FB
201 /* multicast specific */
202 int is_multicast;
203 struct in_addr multicast_ip;
204 int multicast_port; /* first port used for multicast */
6edd6884
FB
205 int multicast_ttl;
206 int loop; /* if true, send the stream in loops (only meaningful if file) */
829ac53d 207
85f07f22 208 /* feed specific */
2effd274 209 int feed_opened; /* true if someone is writing to the feed */
85f07f22 210 int is_feed; /* true if it is a feed */
e322ea48 211 int readonly; /* True if writing is prohibited to the file */
a6e14edd 212 int conns_served;
0c1a9eda
ZK
213 int64_t bytes_served;
214 int64_t feed_max_size; /* maximum storage size */
215 int64_t feed_write_index; /* current write position in feed (it wraps round) */
216 int64_t feed_size; /* current size of feed */
85f07f22
FB
217 struct FFStream *next_feed;
218} FFStream;
219
220typedef struct FeedData {
221 long long data_count;
222 float avg_frame_size; /* frame size averraged over last frames with exponential mean */
223} FeedData;
224
2effd274
FB
225struct sockaddr_in my_http_addr;
226struct sockaddr_in my_rtsp_addr;
227
85f07f22
FB
228char logfilename[1024];
229HTTPContext *first_http_ctx;
230FFStream *first_feed; /* contains only feeds */
231FFStream *first_stream; /* contains all streams, including feeds */
232
2effd274
FB
233static void new_connection(int server_fd, int is_rtsp);
234static void close_connection(HTTPContext *c);
235
236/* HTTP handling */
237static int handle_connection(HTTPContext *c);
85f07f22 238static int http_parse_request(HTTPContext *c);
5eb765ef 239static int http_send_data(HTTPContext *c);
85f07f22
FB
240static void compute_stats(HTTPContext *c);
241static int open_input_stream(HTTPContext *c, const char *info);
242static int http_start_receive_data(HTTPContext *c);
243static int http_receive_data(HTTPContext *c);
2effd274
FB
244static int compute_send_delay(HTTPContext *c);
245
246/* RTSP handling */
247static int rtsp_parse_request(HTTPContext *c);
248static void rtsp_cmd_describe(HTTPContext *c, const char *url);
0df65975 249static void rtsp_cmd_options(HTTPContext *c, const char *url);
2effd274
FB
250static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
251static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
252static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
253static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
254
829ac53d 255/* SDP handling */
0c1a9eda 256static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d
FB
257 struct in_addr my_ip);
258
2effd274 259/* RTP handling */
6edd6884 260static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
2effd274
FB
261 FFStream *stream, const char *session_id);
262static int rtp_new_av_stream(HTTPContext *c,
263 int stream_index, struct sockaddr_in *dest_addr);
85f07f22 264
cde25790 265static const char *my_program_name;
d6562d2c 266static const char *my_program_dir;
cde25790 267
2ac887ba 268static int ffserver_debug;
2effd274 269static int ffserver_daemon;
2ac887ba 270static int no_launch;
5eb765ef 271static int need_to_start_children;
2ac887ba 272
85f07f22
FB
273int nb_max_connections;
274int nb_connections;
275
6edd6884
FB
276int max_bandwidth;
277int current_bandwidth;
42a63c6a 278
5eb765ef
PG
279static long cur_time; // Making this global saves on passing it around everywhere
280
85f07f22
FB
281static long gettime_ms(void)
282{
283 struct timeval tv;
284
285 gettimeofday(&tv,NULL);
286 return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
287}
288
289static FILE *logfile = NULL;
290
b29f97d1 291static void http_log(const char *fmt, ...)
85f07f22
FB
292{
293 va_list ap;
294 va_start(ap, fmt);
295
7434ba6d 296 if (logfile) {
85f07f22 297 vfprintf(logfile, fmt, ap);
7434ba6d
PG
298 fflush(logfile);
299 }
85f07f22
FB
300 va_end(ap);
301}
302
6edd6884 303static char *ctime1(char *buf2)
7434ba6d 304{
7434ba6d 305 time_t ti;
6edd6884 306 char *p;
7434ba6d 307
7434ba6d
PG
308 ti = time(NULL);
309 p = ctime(&ti);
310 strcpy(buf2, p);
311 p = buf2 + strlen(p) - 1;
312 if (*p == '\n')
313 *p = '\0';
6edd6884
FB
314 return buf2;
315}
316
317static void log_connection(HTTPContext *c)
318{
319 char buf2[32];
320
321 if (c->suppress_log)
322 return;
323
cde25790 324 http_log("%s - - [%s] \"%s %s %s\" %d %lld\n",
6edd6884
FB
325 inet_ntoa(c->from_addr.sin_addr),
326 ctime1(buf2), c->method, c->url,
327 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
cde25790
PG
328}
329
0c1a9eda 330static void update_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
331{
332 if (!drd->time1 && !drd->count1) {
333 drd->time1 = drd->time2 = cur_time;
334 drd->count1 = drd->count2 = count;
335 } else {
336 if (cur_time - drd->time2 > 5000) {
337 drd->time1 = drd->time2;
338 drd->count1 = drd->count2;
339 drd->time2 = cur_time;
340 drd->count2 = count;
341 }
342 }
343}
344
345/* In bytes per second */
0c1a9eda 346static int compute_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
347{
348 if (cur_time == drd->time1)
349 return 0;
6edd6884 350
5eb765ef
PG
351 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
352}
353
0c1a9eda 354static int get_longterm_datarate(DataRateData *drd, int64_t count)
a782f209
PG
355{
356 /* You get the first 3 seconds flat out */
357 if (cur_time - drd->time1 < 3000)
358 return 0;
a782f209
PG
359 return compute_datarate(drd, count);
360}
361
362
cde25790
PG
363static void start_children(FFStream *feed)
364{
2ac887ba
PG
365 if (no_launch)
366 return;
367
cde25790 368 for (; feed; feed = feed->next) {
5eb765ef
PG
369 if (feed->child_argv && !feed->pid) {
370 feed->pid_start = time(0);
371
cde25790
PG
372 feed->pid = fork();
373
374 if (feed->pid < 0) {
375 fprintf(stderr, "Unable to create children\n");
376 exit(1);
377 }
378 if (!feed->pid) {
379 /* In child */
380 char pathname[1024];
381 char *slash;
382 int i;
383
5eb765ef
PG
384 for (i = 3; i < 256; i++) {
385 close(i);
386 }
cde25790 387
5eb765ef 388 if (!ffserver_debug) {
2ac887ba
PG
389 i = open("/dev/null", O_RDWR);
390 if (i)
391 dup2(i, 0);
392 dup2(i, 1);
393 dup2(i, 2);
5eb765ef
PG
394 if (i)
395 close(i);
2ac887ba 396 }
cde25790
PG
397
398 pstrcpy(pathname, sizeof(pathname), my_program_name);
399
400 slash = strrchr(pathname, '/');
401 if (!slash) {
402 slash = pathname;
403 } else {
404 slash++;
405 }
406 strcpy(slash, "ffmpeg");
407
d6562d2c
PG
408 /* This is needed to make relative pathnames work */
409 chdir(my_program_dir);
410
a4d70941
PG
411 signal(SIGPIPE, SIG_DFL);
412
cde25790
PG
413 execvp(pathname, feed->child_argv);
414
415 _exit(1);
416 }
417 }
418 }
7434ba6d
PG
419}
420
2effd274
FB
421/* open a listening socket */
422static int socket_open_listen(struct sockaddr_in *my_addr)
85f07f22 423{
2effd274 424 int server_fd, tmp;
85f07f22
FB
425
426 server_fd = socket(AF_INET,SOCK_STREAM,0);
427 if (server_fd < 0) {
428 perror ("socket");
429 return -1;
430 }
431
432 tmp = 1;
433 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
434
2effd274 435 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
b17d099d
PG
436 char bindmsg[32];
437 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
438 perror (bindmsg);
85f07f22
FB
439 close(server_fd);
440 return -1;
441 }
442
443 if (listen (server_fd, 5) < 0) {
444 perror ("listen");
445 close(server_fd);
446 return -1;
447 }
2effd274
FB
448 fcntl(server_fd, F_SETFL, O_NONBLOCK);
449
450 return server_fd;
451}
452
6edd6884
FB
453/* start all multicast streams */
454static void start_multicast(void)
455{
456 FFStream *stream;
457 char session_id[32];
458 HTTPContext *rtp_c;
459 struct sockaddr_in dest_addr;
460 int default_port, stream_index;
461
462 default_port = 6000;
463 for(stream = first_stream; stream != NULL; stream = stream->next) {
464 if (stream->is_multicast) {
465 /* open the RTP connection */
466 snprintf(session_id, sizeof(session_id),
467 "%08x%08x", (int)random(), (int)random());
468
469 /* choose a port if none given */
470 if (stream->multicast_port == 0) {
471 stream->multicast_port = default_port;
472 default_port += 100;
473 }
474
475 dest_addr.sin_family = AF_INET;
476 dest_addr.sin_addr = stream->multicast_ip;
477 dest_addr.sin_port = htons(stream->multicast_port);
478
479 rtp_c = rtp_new_connection(&dest_addr, stream, session_id);
480 if (!rtp_c) {
481 continue;
482 }
483 if (open_input_stream(rtp_c, "") < 0) {
484 fprintf(stderr, "Could not open input stream for stream '%s'\n",
485 stream->filename);
486 continue;
487 }
488
489 rtp_c->rtp_protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
490
491 /* open each RTP stream */
492 for(stream_index = 0; stream_index < stream->nb_streams;
493 stream_index++) {
494 dest_addr.sin_port = htons(stream->multicast_port +
495 2 * stream_index);
496 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
0fa45e19
FB
497 fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n",
498 stream->filename, stream_index);
499 exit(1);
6edd6884
FB
500 }
501 }
502
503 /* change state to send data */
504 rtp_c->state = HTTPSTATE_SEND_DATA;
505 }
506 }
507}
2effd274
FB
508
509/* main loop of the http server */
510static int http_server(void)
511{
512 int server_fd, ret, rtsp_server_fd, delay, delay1;
513 struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
514 HTTPContext *c, *c_next;
515
516 server_fd = socket_open_listen(&my_http_addr);
517 if (server_fd < 0)
518 return -1;
85f07f22 519
2effd274
FB
520 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
521 if (rtsp_server_fd < 0)
522 return -1;
523
85f07f22
FB
524 http_log("ffserver started.\n");
525
cde25790
PG
526 start_children(first_feed);
527
85f07f22
FB
528 first_http_ctx = NULL;
529 nb_connections = 0;
530 first_http_ctx = NULL;
6edd6884
FB
531
532 start_multicast();
533
85f07f22
FB
534 for(;;) {
535 poll_entry = poll_table;
536 poll_entry->fd = server_fd;
537 poll_entry->events = POLLIN;
538 poll_entry++;
539
2effd274
FB
540 poll_entry->fd = rtsp_server_fd;
541 poll_entry->events = POLLIN;
542 poll_entry++;
543
85f07f22
FB
544 /* wait for events on each HTTP handle */
545 c = first_http_ctx;
2effd274 546 delay = 1000;
85f07f22
FB
547 while (c != NULL) {
548 int fd;
549 fd = c->fd;
550 switch(c->state) {
2effd274
FB
551 case HTTPSTATE_SEND_HEADER:
552 case RTSPSTATE_SEND_REPLY:
85f07f22
FB
553 c->poll_entry = poll_entry;
554 poll_entry->fd = fd;
2effd274 555 poll_entry->events = POLLOUT;
85f07f22
FB
556 poll_entry++;
557 break;
85f07f22
FB
558 case HTTPSTATE_SEND_DATA_HEADER:
559 case HTTPSTATE_SEND_DATA:
560 case HTTPSTATE_SEND_DATA_TRAILER:
2effd274
FB
561 if (!c->is_packetized) {
562 /* for TCP, we output as much as we can (may need to put a limit) */
563 c->poll_entry = poll_entry;
564 poll_entry->fd = fd;
565 poll_entry->events = POLLOUT;
566 poll_entry++;
567 } else {
568 /* not strictly correct, but currently cannot add
569 more than one fd in poll entry */
570 delay = 0;
571 }
85f07f22 572 break;
2effd274 573 case HTTPSTATE_WAIT_REQUEST:
85f07f22 574 case HTTPSTATE_RECEIVE_DATA:
85f07f22 575 case HTTPSTATE_WAIT_FEED:
2effd274 576 case RTSPSTATE_WAIT_REQUEST:
85f07f22
FB
577 /* need to catch errors */
578 c->poll_entry = poll_entry;
579 poll_entry->fd = fd;
a6e14edd 580 poll_entry->events = POLLIN;/* Maybe this will work */
85f07f22
FB
581 poll_entry++;
582 break;
2effd274
FB
583 case HTTPSTATE_WAIT:
584 c->poll_entry = NULL;
585 delay1 = compute_send_delay(c);
586 if (delay1 < delay)
587 delay = delay1;
588 break;
589 case HTTPSTATE_WAIT_SHORT:
590 c->poll_entry = NULL;
591 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
592 if (delay1 < delay)
593 delay = delay1;
594 break;
85f07f22
FB
595 default:
596 c->poll_entry = NULL;
597 break;
598 }
599 c = c->next;
600 }
601
602 /* wait for an event on one connection. We poll at least every
603 second to handle timeouts */
604 do {
2effd274 605 ret = poll(poll_table, poll_entry - poll_table, delay);
85f07f22
FB
606 } while (ret == -1);
607
608 cur_time = gettime_ms();
609
5eb765ef
PG
610 if (need_to_start_children) {
611 need_to_start_children = 0;
612 start_children(first_feed);
613 }
614
85f07f22 615 /* now handle the events */
2effd274
FB
616 for(c = first_http_ctx; c != NULL; c = c_next) {
617 c_next = c->next;
618 if (handle_connection(c) < 0) {
85f07f22 619 /* close and free the connection */
7434ba6d 620 log_connection(c);
2effd274 621 close_connection(c);
85f07f22
FB
622 }
623 }
624
85f07f22 625 poll_entry = poll_table;
2effd274 626 /* new HTTP connection request ? */
85f07f22 627 if (poll_entry->revents & POLLIN) {
2effd274 628 new_connection(server_fd, 0);
85f07f22
FB
629 }
630 poll_entry++;
2effd274
FB
631 /* new RTSP connection request ? */
632 if (poll_entry->revents & POLLIN) {
633 new_connection(rtsp_server_fd, 1);
634 }
85f07f22
FB
635 }
636}
637
2effd274
FB
638/* start waiting for a new HTTP/RTSP request */
639static void start_wait_request(HTTPContext *c, int is_rtsp)
85f07f22 640{
2effd274
FB
641 c->buffer_ptr = c->buffer;
642 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
643
644 if (is_rtsp) {
645 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
646 c->state = RTSPSTATE_WAIT_REQUEST;
647 } else {
648 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
649 c->state = HTTPSTATE_WAIT_REQUEST;
650 }
651}
652
653static void new_connection(int server_fd, int is_rtsp)
654{
655 struct sockaddr_in from_addr;
656 int fd, len;
657 HTTPContext *c = NULL;
658
659 len = sizeof(from_addr);
660 fd = accept(server_fd, (struct sockaddr *)&from_addr,
661 &len);
662 if (fd < 0)
663 return;
664 fcntl(fd, F_SETFL, O_NONBLOCK);
665
666 /* XXX: should output a warning page when coming
667 close to the connection limit */
668 if (nb_connections >= nb_max_connections)
669 goto fail;
670
671 /* add a new connection */
672 c = av_mallocz(sizeof(HTTPContext));
673 if (!c)
674 goto fail;
675
676 c->next = first_http_ctx;
677 first_http_ctx = c;
678 c->fd = fd;
679 c->poll_entry = NULL;
680 c->from_addr = from_addr;
681 c->buffer_size = IOBUFFER_INIT_SIZE;
682 c->buffer = av_malloc(c->buffer_size);
683 if (!c->buffer)
684 goto fail;
685 nb_connections++;
686
687 start_wait_request(c, is_rtsp);
688
689 return;
690
691 fail:
692 if (c) {
693 av_free(c->buffer);
694 av_free(c);
695 }
696 close(fd);
697}
698
699static void close_connection(HTTPContext *c)
700{
701 HTTPContext **cp, *c1;
702 int i, nb_streams;
703 AVFormatContext *ctx;
704 URLContext *h;
705 AVStream *st;
706
707 /* remove connection from list */
708 cp = &first_http_ctx;
709 while ((*cp) != NULL) {
710 c1 = *cp;
711 if (c1 == c) {
712 *cp = c->next;
713 } else {
714 cp = &c1->next;
715 }
716 }
717
718 /* remove connection associated resources */
719 if (c->fd >= 0)
720 close(c->fd);
721 if (c->fmt_in) {
722 /* close each frame parser */
723 for(i=0;i<c->fmt_in->nb_streams;i++) {
724 st = c->fmt_in->streams[i];
725 if (st->codec.codec) {
726 avcodec_close(&st->codec);
727 }
728 }
729 av_close_input_file(c->fmt_in);
730 }
731
732 /* free RTP output streams if any */
733 nb_streams = 0;
734 if (c->stream)
735 nb_streams = c->stream->nb_streams;
736
737 for(i=0;i<nb_streams;i++) {
738 ctx = c->rtp_ctx[i];
739 if (ctx) {
740 av_write_trailer(ctx);
741 av_free(ctx);
742 }
743 h = c->rtp_handles[i];
744 if (h) {
745 url_close(h);
746 }
747 }
748
b88ba823
MH
749 ctx = &c->fmt_ctx;
750
87638494 751 if (!c->last_packet_sent) {
87638494
PG
752 if (ctx->oformat) {
753 /* prepare header */
754 if (url_open_dyn_buf(&ctx->pb) >= 0) {
755 av_write_trailer(ctx);
756 (void) url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
757 }
758 }
759 }
760
f0ef6240
PG
761 for(i=0; i<ctx->nb_streams; i++)
762 av_free(ctx->streams[i]) ;
763
6edd6884
FB
764 if (c->stream)
765 current_bandwidth -= c->stream->bandwidth;
2effd274
FB
766 av_freep(&c->pb_buffer);
767 av_free(c->buffer);
768 av_free(c);
769 nb_connections--;
770}
771
772static int handle_connection(HTTPContext *c)
773{
774 int len, ret;
85f07f22
FB
775
776 switch(c->state) {
777 case HTTPSTATE_WAIT_REQUEST:
2effd274 778 case RTSPSTATE_WAIT_REQUEST:
85f07f22
FB
779 /* timeout ? */
780 if ((c->timeout - cur_time) < 0)
781 return -1;
782 if (c->poll_entry->revents & (POLLERR | POLLHUP))
783 return -1;
784
785 /* no need to read if no events */
786 if (!(c->poll_entry->revents & POLLIN))
787 return 0;
788 /* read the data */
789 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
790 if (len < 0) {
791 if (errno != EAGAIN && errno != EINTR)
792 return -1;
793 } else if (len == 0) {
794 return -1;
795 } else {
796 /* search for end of request. XXX: not fully correct since garbage could come after the end */
0c1a9eda 797 uint8_t *ptr;
85f07f22
FB
798 c->buffer_ptr += len;
799 ptr = c->buffer_ptr;
800 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
801 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
802 /* request found : parse it and reply */
2effd274
FB
803 if (c->state == HTTPSTATE_WAIT_REQUEST) {
804 ret = http_parse_request(c);
805 } else {
806 ret = rtsp_parse_request(c);
807 }
808 if (ret < 0)
85f07f22
FB
809 return -1;
810 } else if (ptr >= c->buffer_end) {
811 /* request too long: cannot do anything */
812 return -1;
813 }
814 }
815 break;
816
817 case HTTPSTATE_SEND_HEADER:
818 if (c->poll_entry->revents & (POLLERR | POLLHUP))
819 return -1;
820
2effd274 821 /* no need to write if no events */
85f07f22
FB
822 if (!(c->poll_entry->revents & POLLOUT))
823 return 0;
824 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
825 if (len < 0) {
826 if (errno != EAGAIN && errno != EINTR) {
827 /* error : close connection */
2effd274 828 av_freep(&c->pb_buffer);
85f07f22
FB
829 return -1;
830 }
831 } else {
832 c->buffer_ptr += len;
2e04edb3
PG
833 if (c->stream)
834 c->stream->bytes_served += len;
a6e14edd 835 c->data_count += len;
85f07f22 836 if (c->buffer_ptr >= c->buffer_end) {
2effd274 837 av_freep(&c->pb_buffer);
85f07f22 838 /* if error, exit */
2effd274 839 if (c->http_error) {
85f07f22 840 return -1;
2effd274
FB
841 }
842 /* all the buffer was sent : synchronize to the incoming stream */
85f07f22
FB
843 c->state = HTTPSTATE_SEND_DATA_HEADER;
844 c->buffer_ptr = c->buffer_end = c->buffer;
845 }
846 }
847 break;
848
849 case HTTPSTATE_SEND_DATA:
850 case HTTPSTATE_SEND_DATA_HEADER:
851 case HTTPSTATE_SEND_DATA_TRAILER:
2effd274
FB
852 /* for packetized output, we consider we can always write (the
853 input streams sets the speed). It may be better to verify
854 that we do not rely too much on the kernel queues */
855 if (!c->is_packetized) {
856 if (c->poll_entry->revents & (POLLERR | POLLHUP))
857 return -1;
858
859 /* no need to read if no events */
860 if (!(c->poll_entry->revents & POLLOUT))
861 return 0;
862 }
5eb765ef 863 if (http_send_data(c) < 0)
85f07f22
FB
864 return -1;
865 break;
866 case HTTPSTATE_RECEIVE_DATA:
867 /* no need to read if no events */
868 if (c->poll_entry->revents & (POLLERR | POLLHUP))
869 return -1;
870 if (!(c->poll_entry->revents & POLLIN))
871 return 0;
872 if (http_receive_data(c) < 0)
873 return -1;
874 break;
875 case HTTPSTATE_WAIT_FEED:
876 /* no need to read if no events */
a6e14edd 877 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
85f07f22
FB
878 return -1;
879
880 /* nothing to do, we'll be waken up by incoming feed packets */
881 break;
2effd274
FB
882
883 case HTTPSTATE_WAIT:
884 /* if the delay expired, we can send new packets */
885 if (compute_send_delay(c) <= 0)
886 c->state = HTTPSTATE_SEND_DATA;
887 break;
888 case HTTPSTATE_WAIT_SHORT:
889 /* just return back to send data */
890 c->state = HTTPSTATE_SEND_DATA;
891 break;
892
893 case RTSPSTATE_SEND_REPLY:
894 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
895 av_freep(&c->pb_buffer);
896 return -1;
897 }
898 /* no need to write if no events */
899 if (!(c->poll_entry->revents & POLLOUT))
900 return 0;
901 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
902 if (len < 0) {
903 if (errno != EAGAIN && errno != EINTR) {
904 /* error : close connection */
905 av_freep(&c->pb_buffer);
906 return -1;
907 }
908 } else {
909 c->buffer_ptr += len;
910 c->data_count += len;
911 if (c->buffer_ptr >= c->buffer_end) {
912 /* all the buffer was sent : wait for a new request */
913 av_freep(&c->pb_buffer);
914 start_wait_request(c, 1);
915 }
916 }
917 break;
918 case HTTPSTATE_READY:
919 /* nothing to do */
920 break;
85f07f22
FB
921 default:
922 return -1;
923 }
924 return 0;
925}
926
3120d2a2
PG
927static int extract_rates(char *rates, int ratelen, const char *request)
928{
929 const char *p;
930
931 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
932 if (strncasecmp(p, "Pragma:", 7) == 0) {
933 const char *q = p + 7;
934
935 while (*q && *q != '\n' && isspace(*q))
936 q++;
937
938 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
939 int stream_no;
940 int rate_no;
941
942 q += 20;
943
cde25790 944 memset(rates, 0xff, ratelen);
3120d2a2
PG
945
946 while (1) {
947 while (*q && *q != '\n' && *q != ':')
948 q++;
949
950 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
951 break;
952 }
953 stream_no--;
954 if (stream_no < ratelen && stream_no >= 0) {
955 rates[stream_no] = rate_no;
956 }
957
958 while (*q && *q != '\n' && !isspace(*q))
959 q++;
960 }
961
962 return 1;
963 }
964 }
965 p = strchr(p, '\n');
966 if (!p)
967 break;
968
969 p++;
970 }
971
972 return 0;
973}
974
cde25790 975static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
3120d2a2
PG
976{
977 int i;
cde25790
PG
978 int best_bitrate = 100000000;
979 int best = -1;
980
981 for (i = 0; i < feed->nb_streams; i++) {
982 AVCodecContext *feed_codec = &feed->streams[i]->codec;
983
984 if (feed_codec->codec_id != codec->codec_id ||
985 feed_codec->sample_rate != codec->sample_rate ||
986 feed_codec->width != codec->width ||
987 feed_codec->height != codec->height) {
988 continue;
989 }
990
991 /* Potential stream */
992
993 /* We want the fastest stream less than bit_rate, or the slowest
994 * faster than bit_rate
995 */
996
997 if (feed_codec->bit_rate <= bit_rate) {
998 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
999 best_bitrate = feed_codec->bit_rate;
1000 best = i;
1001 }
1002 } else {
1003 if (feed_codec->bit_rate < best_bitrate) {
1004 best_bitrate = feed_codec->bit_rate;
1005 best = i;
1006 }
1007 }
1008 }
1009
1010 return best;
1011}
1012
1013static int modify_current_stream(HTTPContext *c, char *rates)
1014{
1015 int i;
1016 FFStream *req = c->stream;
1017 int action_required = 0;
3120d2a2 1018
001bcd29
PG
1019 /* Not much we can do for a feed */
1020 if (!req->feed)
1021 return 0;
1022
3120d2a2
PG
1023 for (i = 0; i < req->nb_streams; i++) {
1024 AVCodecContext *codec = &req->streams[i]->codec;
1025
3120d2a2
PG
1026 switch(rates[i]) {
1027 case 0:
cde25790 1028 c->switch_feed_streams[i] = req->feed_streams[i];
3120d2a2
PG
1029 break;
1030 case 1:
cde25790 1031 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
3120d2a2
PG
1032 break;
1033 case 2:
cde25790
PG
1034 /* Wants off or slow */
1035 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1036#ifdef WANTS_OFF
1037 /* This doesn't work well when it turns off the only stream! */
1038 c->switch_feed_streams[i] = -2;
1039 c->feed_streams[i] = -2;
1040#endif
3120d2a2
PG
1041 break;
1042 }
3120d2a2 1043
cde25790
PG
1044 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1045 action_required = 1;
1046 }
3120d2a2 1047
cde25790
PG
1048 return action_required;
1049}
3120d2a2 1050
3120d2a2 1051
cde25790
PG
1052static void do_switch_stream(HTTPContext *c, int i)
1053{
1054 if (c->switch_feed_streams[i] >= 0) {
1055#ifdef PHILIP
1056 c->feed_streams[i] = c->switch_feed_streams[i];
1057#endif
3120d2a2 1058
cde25790 1059 /* Now update the stream */
3120d2a2 1060 }
cde25790 1061 c->switch_feed_streams[i] = -1;
3120d2a2 1062}
7434ba6d 1063
2effd274
FB
1064/* XXX: factorize in utils.c ? */
1065/* XXX: take care with different space meaning */
1066static void skip_spaces(const char **pp)
1067{
1068 const char *p;
1069 p = *pp;
1070 while (*p == ' ' || *p == '\t')
1071 p++;
1072 *pp = p;
1073}
1074
1075static void get_word(char *buf, int buf_size, const char **pp)
1076{
1077 const char *p;
1078 char *q;
1079
1080 p = *pp;
1081 skip_spaces(&p);
1082 q = buf;
1083 while (!isspace(*p) && *p != '\0') {
1084 if ((q - buf) < buf_size - 1)
1085 *q++ = *p;
1086 p++;
1087 }
1088 if (buf_size > 0)
1089 *q = '\0';
1090 *pp = p;
1091}
1092
8256c0a3
PG
1093static int validate_acl(FFStream *stream, HTTPContext *c)
1094{
1095 enum IPAddressAction last_action = IP_DENY;
1096 IPAddressACL *acl;
1097 struct in_addr *src = &c->from_addr.sin_addr;
efa04ce2 1098 unsigned long src_addr = ntohl(src->s_addr);
8256c0a3
PG
1099
1100 for (acl = stream->acl; acl; acl = acl->next) {
efa04ce2 1101 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
8256c0a3
PG
1102 return (acl->action == IP_ALLOW) ? 1 : 0;
1103 }
1104 last_action = acl->action;
1105 }
1106
1107 /* Nothing matched, so return not the last action */
1108 return (last_action == IP_DENY) ? 1 : 0;
1109}
1110
829ac53d
FB
1111/* compute the real filename of a file by matching it without its
1112 extensions to all the stream filenames */
1113static void compute_real_filename(char *filename, int max_size)
1114{
1115 char file1[1024];
1116 char file2[1024];
1117 char *p;
1118 FFStream *stream;
1119
1120 /* compute filename by matching without the file extensions */
1121 pstrcpy(file1, sizeof(file1), filename);
1122 p = strrchr(file1, '.');
1123 if (p)
1124 *p = '\0';
1125 for(stream = first_stream; stream != NULL; stream = stream->next) {
1126 pstrcpy(file2, sizeof(file2), stream->filename);
1127 p = strrchr(file2, '.');
1128 if (p)
1129 *p = '\0';
1130 if (!strcmp(file1, file2)) {
1131 pstrcpy(filename, max_size, stream->filename);
1132 break;
1133 }
1134 }
1135}
1136
1137enum RedirType {
1138 REDIR_NONE,
1139 REDIR_ASX,
1140 REDIR_RAM,
1141 REDIR_ASF,
1142 REDIR_RTSP,
1143 REDIR_SDP,
1144};
1145
85f07f22
FB
1146/* parse http request and prepare header */
1147static int http_parse_request(HTTPContext *c)
1148{
1149 char *p;
1150 int post;
829ac53d 1151 enum RedirType redir_type;
85f07f22
FB
1152 char cmd[32];
1153 char info[1024], *filename;
1154 char url[1024], *q;
1155 char protocol[32];
1156 char msg[1024];
1157 const char *mime_type;
1158 FFStream *stream;
42a63c6a 1159 int i;
3120d2a2 1160 char ratebuf[32];
cde25790 1161 char *useragent = 0;
85f07f22
FB
1162
1163 p = c->buffer;
2effd274 1164 get_word(cmd, sizeof(cmd), (const char **)&p);
bd7cf6ad 1165 pstrcpy(c->method, sizeof(c->method), cmd);
7434ba6d 1166
85f07f22
FB
1167 if (!strcmp(cmd, "GET"))
1168 post = 0;
1169 else if (!strcmp(cmd, "POST"))
1170 post = 1;
1171 else
1172 return -1;
1173
2effd274 1174 get_word(url, sizeof(url), (const char **)&p);
bd7cf6ad 1175 pstrcpy(c->url, sizeof(c->url), url);
7434ba6d 1176
2effd274 1177 get_word(protocol, sizeof(protocol), (const char **)&p);
85f07f22
FB
1178 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1179 return -1;
7434ba6d 1180
bd7cf6ad 1181 pstrcpy(c->protocol, sizeof(c->protocol), protocol);
85f07f22
FB
1182
1183 /* find the filename and the optional info string in the request */
1184 p = url;
1185 if (*p == '/')
1186 p++;
1187 filename = p;
1188 p = strchr(p, '?');
1189 if (p) {
bd7cf6ad 1190 pstrcpy(info, sizeof(info), p);
85f07f22
FB
1191 *p = '\0';
1192 } else {
1193 info[0] = '\0';
1194 }
1195
cde25790
PG
1196 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1197 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1198 useragent = p + 11;
1199 if (*useragent && *useragent != '\n' && isspace(*useragent))
1200 useragent++;
1201 break;
1202 }
1203 p = strchr(p, '\n');
1204 if (!p)
1205 break;
1206
1207 p++;
1208 }
1209
829ac53d
FB
1210 redir_type = REDIR_NONE;
1211 if (match_ext(filename, "asx")) {
1212 redir_type = REDIR_ASX;
7434ba6d 1213 filename[strlen(filename)-1] = 'f';
c2ce254c 1214 } else if (match_ext(filename, "asf") &&
cde25790
PG
1215 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1216 /* if this isn't WMP or lookalike, return the redirector file */
829ac53d
FB
1217 redir_type = REDIR_ASF;
1218 } else if (match_ext(filename, "rpm,ram")) {
1219 redir_type = REDIR_RAM;
42a63c6a 1220 strcpy(filename + strlen(filename)-2, "m");
829ac53d
FB
1221 } else if (match_ext(filename, "rtsp")) {
1222 redir_type = REDIR_RTSP;
1223 compute_real_filename(filename, sizeof(url) - 1);
1224 } else if (match_ext(filename, "sdp")) {
1225 redir_type = REDIR_SDP;
829ac53d 1226 compute_real_filename(filename, sizeof(url) - 1);
42a63c6a 1227 }
829ac53d 1228
85f07f22
FB
1229 stream = first_stream;
1230 while (stream != NULL) {
8256c0a3 1231 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
85f07f22
FB
1232 break;
1233 stream = stream->next;
1234 }
1235 if (stream == NULL) {
1236 sprintf(msg, "File '%s' not found", url);
1237 goto send_error;
1238 }
42a63c6a 1239
cde25790
PG
1240 c->stream = stream;
1241 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1242 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1243
1244 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1245 c->http_error = 301;
1246 q = c->buffer;
1247 q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
1248 q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
1249 q += sprintf(q, "Content-type: text/html\r\n");
1250 q += sprintf(q, "\r\n");
1251 q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
1252 q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1253 q += sprintf(q, "</body></html>\r\n");
1254
1255 /* prepare output buffer */
1256 c->buffer_ptr = c->buffer;
1257 c->buffer_end = q;
1258 c->state = HTTPSTATE_SEND_HEADER;
1259 return 0;
1260 }
1261
3120d2a2
PG
1262 /* If this is WMP, get the rate information */
1263 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
cde25790
PG
1264 if (modify_current_stream(c, ratebuf)) {
1265 for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1266 if (c->switch_feed_streams[i] >= 0)
1267 do_switch_stream(c, i);
1268 }
1269 }
3120d2a2
PG
1270 }
1271
42a63c6a 1272 if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
6edd6884 1273 current_bandwidth += stream->bandwidth;
42a63c6a 1274 }
6edd6884
FB
1275
1276 if (post == 0 && max_bandwidth < current_bandwidth) {
42a63c6a
PG
1277 c->http_error = 200;
1278 q = c->buffer;
1279 q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
1280 q += sprintf(q, "Content-type: text/html\r\n");
1281 q += sprintf(q, "\r\n");
1282 q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
1283 q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
1284 q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
6edd6884 1285 current_bandwidth, max_bandwidth);
42a63c6a
PG
1286 q += sprintf(q, "</body></html>\r\n");
1287
1288 /* prepare output buffer */
1289 c->buffer_ptr = c->buffer;
1290 c->buffer_end = q;
1291 c->state = HTTPSTATE_SEND_HEADER;
1292 return 0;
1293 }
1294
829ac53d 1295 if (redir_type != REDIR_NONE) {
7434ba6d
PG
1296 char *hostinfo = 0;
1297
1298 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1299 if (strncasecmp(p, "Host:", 5) == 0) {
1300 hostinfo = p + 5;
1301 break;
1302 }
1303 p = strchr(p, '\n');
1304 if (!p)
1305 break;
1306
1307 p++;
1308 }
1309
1310 if (hostinfo) {
1311 char *eoh;
1312 char hostbuf[260];
1313
1314 while (isspace(*hostinfo))
1315 hostinfo++;
1316
1317 eoh = strchr(hostinfo, '\n');
1318 if (eoh) {
1319 if (eoh[-1] == '\r')
1320 eoh--;
1321
1322 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1323 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1324 hostbuf[eoh - hostinfo] = 0;
1325
1326 c->http_error = 200;
1327 q = c->buffer;
829ac53d
FB
1328 switch(redir_type) {
1329 case REDIR_ASX:
42a63c6a
PG
1330 q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
1331 q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1332 q += sprintf(q, "\r\n");
1333 q += sprintf(q, "<ASX Version=\"3\">\r\n");
1334 q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
1335 q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
1336 hostbuf, filename, info);
1337 q += sprintf(q, "</ASX>\r\n");
829ac53d
FB
1338 break;
1339 case REDIR_RAM:
42a63c6a
PG
1340 q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
1341 q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
1342 q += sprintf(q, "\r\n");
1343 q += sprintf(q, "# Autogenerated by ffserver\r\n");
1344 q += sprintf(q, "http://%s/%s%s\r\n",
1345 hostbuf, filename, info);
829ac53d
FB
1346 break;
1347 case REDIR_ASF:
cde25790
PG
1348 q += sprintf(q, "HTTP/1.0 200 ASF Redirect follows\r\n");
1349 q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1350 q += sprintf(q, "\r\n");
1351 q += sprintf(q, "[Reference]\r\n");
1352 q += sprintf(q, "Ref1=http://%s/%s%s\r\n",
1353 hostbuf, filename, info);
829ac53d
FB
1354 break;
1355 case REDIR_RTSP:
1356 {
1357 char hostname[256], *p;
1358 /* extract only hostname */
1359 pstrcpy(hostname, sizeof(hostname), hostbuf);
1360 p = strrchr(hostname, ':');
1361 if (p)
1362 *p = '\0';
1363 q += sprintf(q, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1364 /* XXX: incorrect mime type ? */
1365 q += sprintf(q, "Content-type: application/x-rtsp\r\n");
1366 q += sprintf(q, "\r\n");
1367 q += sprintf(q, "rtsp://%s:%d/%s\r\n",
1368 hostname, ntohs(my_rtsp_addr.sin_port),
1369 filename);
1370 }
1371 break;
1372 case REDIR_SDP:
1373 {
0c1a9eda 1374 uint8_t *sdp_data;
829ac53d
FB
1375 int sdp_data_size, len;
1376 struct sockaddr_in my_addr;
1377
1378 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1379 q += sprintf(q, "Content-type: application/sdp\r\n");
1380 q += sprintf(q, "\r\n");
1381
1382 len = sizeof(my_addr);
1383 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1384
1385 /* XXX: should use a dynamic buffer */
1386 sdp_data_size = prepare_sdp_description(stream,
1387 &sdp_data,
1388 my_addr.sin_addr);
1389 if (sdp_data_size > 0) {
1390 memcpy(q, sdp_data, sdp_data_size);
1391 q += sdp_data_size;
1392 *q = '\0';
1393 av_free(sdp_data);
1394 }
1395 }
1396 break;
1397 default:
ec3b2232 1398 av_abort();
829ac53d 1399 break;
2effd274 1400 }
7434ba6d
PG
1401
1402 /* prepare output buffer */
1403 c->buffer_ptr = c->buffer;
1404 c->buffer_end = q;
1405 c->state = HTTPSTATE_SEND_HEADER;
1406 return 0;
1407 }
1408 }
1409 }
1410
42a63c6a 1411 sprintf(msg, "ASX/RAM file not handled");
7434ba6d 1412 goto send_error;
85f07f22
FB
1413 }
1414
a6e14edd 1415 stream->conns_served++;
7434ba6d 1416
85f07f22
FB
1417 /* XXX: add there authenticate and IP match */
1418
1419 if (post) {
1420 /* if post, it means a feed is being sent */
1421 if (!stream->is_feed) {
7434ba6d
PG
1422 /* However it might be a status report from WMP! Lets log the data
1423 * as it might come in handy one day
1424 */
1425 char *logline = 0;
3120d2a2 1426 int client_id = 0;
7434ba6d
PG
1427
1428 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1429 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1430 logline = p;
1431 break;
1432 }
3120d2a2
PG
1433 if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1434 client_id = strtol(p + 18, 0, 10);
1435 }
7434ba6d
PG
1436 p = strchr(p, '\n');
1437 if (!p)
1438 break;
1439
1440 p++;
1441 }
1442
1443 if (logline) {
1444 char *eol = strchr(logline, '\n');
1445
1446 logline += 17;
1447
1448 if (eol) {
1449 if (eol[-1] == '\r')
1450 eol--;
1451 http_log("%.*s\n", eol - logline, logline);
1452 c->suppress_log = 1;
1453 }
1454 }
3120d2a2 1455
cde25790
PG
1456#ifdef DEBUG_WMP
1457 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1458#endif
1459
1460 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1461 HTTPContext *wmpc;
1462
1463 /* Now we have to find the client_id */
1464 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1465 if (wmpc->wmp_client_id == client_id)
1466 break;
1467 }
1468
1469 if (wmpc) {
cde25790
PG
1470 if (modify_current_stream(wmpc, ratebuf)) {
1471 wmpc->switch_pending = 1;
3120d2a2
PG
1472 }
1473 }
1474 }
7434ba6d 1475
85f07f22 1476 sprintf(msg, "POST command not handled");
cb275dd9 1477 c->stream = 0;
85f07f22
FB
1478 goto send_error;
1479 }
1480 if (http_start_receive_data(c) < 0) {
1481 sprintf(msg, "could not open feed");
1482 goto send_error;
1483 }
1484 c->http_error = 0;
1485 c->state = HTTPSTATE_RECEIVE_DATA;
1486 return 0;
1487 }
1488
cde25790 1489#ifdef DEBUG_WMP
3120d2a2 1490 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
cde25790 1491 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1492 }
1493#endif
1494
85f07f22
FB
1495 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1496 goto send_stats;
1497
1498 /* open input stream */
1499 if (open_input_stream(c, info) < 0) {
1500 sprintf(msg, "Input stream corresponding to '%s' not found", url);
1501 goto send_error;
1502 }
1503
1504 /* prepare http header */
1505 q = c->buffer;
1506 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1507 mime_type = c->stream->fmt->mime_type;
1508 if (!mime_type)
1509 mime_type = "application/x-octet_stream";
85f07f22
FB
1510 q += sprintf(q, "Pragma: no-cache\r\n");
1511
1512 /* for asf, we need extra headers */
8256c0a3 1513 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
3120d2a2 1514 /* Need to allocate a client id */
3120d2a2 1515
8256c0a3 1516 c->wmp_client_id = random() & 0x7fffffff;
3120d2a2
PG
1517
1518 q += sprintf(q, "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);
85f07f22 1519 }
f747e6d3 1520 q += sprintf(q, "Content-Type: %s\r\n", mime_type);
85f07f22
FB
1521 q += sprintf(q, "\r\n");
1522
1523 /* prepare output buffer */
1524 c->http_error = 0;
1525 c->buffer_ptr = c->buffer;
1526 c->buffer_end = q;
1527 c->state = HTTPSTATE_SEND_HEADER;
1528 return 0;
1529 send_error:
1530 c->http_error = 404;
1531 q = c->buffer;
1532 q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
1533 q += sprintf(q, "Content-type: %s\r\n", "text/html");
1534 q += sprintf(q, "\r\n");
1535 q += sprintf(q, "<HTML>\n");
1536 q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1537 q += sprintf(q, "<BODY>%s</BODY>\n", msg);
1538 q += sprintf(q, "</HTML>\n");
1539
1540 /* prepare output buffer */
1541 c->buffer_ptr = c->buffer;
1542 c->buffer_end = q;
1543 c->state = HTTPSTATE_SEND_HEADER;
1544 return 0;
1545 send_stats:
1546 compute_stats(c);
1547 c->http_error = 200; /* horrible : we use this value to avoid
1548 going to the send data state */
1549 c->state = HTTPSTATE_SEND_HEADER;
1550 return 0;
1551}
1552
0c1a9eda 1553static void fmt_bytecount(ByteIOContext *pb, int64_t count)
2ac887ba
PG
1554{
1555 static const char *suffix = " kMGTP";
1556 const char *s;
1557
1558 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1559 }
1560
2effd274 1561 url_fprintf(pb, "%lld%c", count, *s);
2ac887ba
PG
1562}
1563
85f07f22
FB
1564static void compute_stats(HTTPContext *c)
1565{
1566 HTTPContext *c1;
1567 FFStream *stream;
2effd274 1568 char *p;
85f07f22 1569 time_t ti;
2effd274
FB
1570 int i, len;
1571 ByteIOContext pb1, *pb = &pb1;
cde25790 1572
2effd274
FB
1573 if (url_open_dyn_buf(pb) < 0) {
1574 /* XXX: return an error ? */
cde25790 1575 c->buffer_ptr = c->buffer;
2effd274
FB
1576 c->buffer_end = c->buffer;
1577 return;
cde25790 1578 }
85f07f22 1579
2effd274
FB
1580 url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1581 url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1582 url_fprintf(pb, "Pragma: no-cache\r\n");
1583 url_fprintf(pb, "\r\n");
85f07f22 1584
2effd274 1585 url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
cde25790 1586 if (c->stream->feed_filename) {
2effd274 1587 url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
cde25790 1588 }
2effd274
FB
1589 url_fprintf(pb, "</HEAD>\n<BODY>");
1590 url_fprintf(pb, "<H1>FFServer Status</H1>\n");
85f07f22 1591 /* format status */
2effd274
FB
1592 url_fprintf(pb, "<H2>Available Streams</H2>\n");
1593 url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1594 url_fprintf(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");
85f07f22
FB
1595 stream = first_stream;
1596 while (stream != NULL) {
42a63c6a
PG
1597 char sfilename[1024];
1598 char *eosf;
1599
a6e14edd 1600 if (stream->feed != stream) {
2effd274 1601 pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
a6e14edd
PG
1602 eosf = sfilename + strlen(sfilename);
1603 if (eosf - sfilename >= 4) {
1604 if (strcmp(eosf - 4, ".asf") == 0) {
1605 strcpy(eosf - 4, ".asx");
1606 } else if (strcmp(eosf - 3, ".rm") == 0) {
1607 strcpy(eosf - 3, ".ram");
2effd274 1608 } else if (stream->fmt == &rtp_mux) {
829ac53d
FB
1609 /* generate a sample RTSP director if
1610 unicast. Generate an SDP redirector if
1611 multicast */
2effd274
FB
1612 eosf = strrchr(sfilename, '.');
1613 if (!eosf)
1614 eosf = sfilename + strlen(sfilename);
829ac53d
FB
1615 if (stream->is_multicast)
1616 strcpy(eosf, ".sdp");
1617 else
1618 strcpy(eosf, ".rtsp");
a6e14edd 1619 }
42a63c6a 1620 }
a6e14edd 1621
2effd274 1622 url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
a6e14edd 1623 sfilename, stream->filename);
2effd274 1624 url_fprintf(pb, "<td align=right> %d <td align=right> ",
2ac887ba 1625 stream->conns_served);
2effd274 1626 fmt_bytecount(pb, stream->bytes_served);
a6e14edd
PG
1627 switch(stream->stream_type) {
1628 case STREAM_TYPE_LIVE:
1629 {
1630 int audio_bit_rate = 0;
1631 int video_bit_rate = 0;
58445440
ZK
1632 const char *audio_codec_name = "";
1633 const char *video_codec_name = "";
1634 const char *audio_codec_name_extra = "";
1635 const char *video_codec_name_extra = "";
a6e14edd
PG
1636
1637 for(i=0;i<stream->nb_streams;i++) {
1638 AVStream *st = stream->streams[i];
1639 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1640 switch(st->codec.codec_type) {
1641 case CODEC_TYPE_AUDIO:
1642 audio_bit_rate += st->codec.bit_rate;
1643 if (codec) {
1644 if (*audio_codec_name)
1645 audio_codec_name_extra = "...";
1646 audio_codec_name = codec->name;
1647 }
1648 break;
1649 case CODEC_TYPE_VIDEO:
1650 video_bit_rate += st->codec.bit_rate;
1651 if (codec) {
1652 if (*video_codec_name)
1653 video_codec_name_extra = "...";
1654 video_codec_name = codec->name;
1655 }
1656 break;
1657 default:
ec3b2232 1658 av_abort();
79c4ea3c 1659 }
85f07f22 1660 }
2effd274 1661 url_fprintf(pb, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s",
a6e14edd 1662 stream->fmt->name,
6edd6884 1663 stream->bandwidth,
a6e14edd
PG
1664 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1665 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1666 if (stream->feed) {
2effd274 1667 url_fprintf(pb, "<TD>%s", stream->feed->filename);
a6e14edd 1668 } else {
2effd274 1669 url_fprintf(pb, "<TD>%s", stream->feed_filename);
a6e14edd 1670 }
2effd274 1671 url_fprintf(pb, "\n");
85f07f22 1672 }
a6e14edd
PG
1673 break;
1674 default:
2effd274 1675 url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
a6e14edd 1676 break;
85f07f22 1677 }
85f07f22
FB
1678 }
1679 stream = stream->next;
1680 }
2effd274 1681 url_fprintf(pb, "</TABLE>\n");
a6e14edd
PG
1682
1683 stream = first_stream;
1684 while (stream != NULL) {
1685 if (stream->feed == stream) {
2effd274 1686 url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
cde25790 1687 if (stream->pid) {
2effd274 1688 url_fprintf(pb, "Running as pid %d.\n", stream->pid);
cde25790 1689
2effd274
FB
1690#if defined(linux) && !defined(CONFIG_NOCUTILS)
1691 {
1692 FILE *pid_stat;
1693 char ps_cmd[64];
1694
1695 /* This is somewhat linux specific I guess */
1696 snprintf(ps_cmd, sizeof(ps_cmd),
1697 "ps -o \"%%cpu,cputime\" --no-headers %d",
1698 stream->pid);
1699
1700 pid_stat = popen(ps_cmd, "r");
1701 if (pid_stat) {
1702 char cpuperc[10];
1703 char cpuused[64];
1704
1705 if (fscanf(pid_stat, "%10s %64s", cpuperc,
1706 cpuused) == 2) {
1707 url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1708 cpuperc, cpuused);
1709 }
1710 fclose(pid_stat);
cde25790 1711 }
cde25790
PG
1712 }
1713#endif
1714
2effd274 1715 url_fprintf(pb, "<p>");
cde25790 1716 }
2effd274 1717 url_fprintf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
a6e14edd
PG
1718
1719 for (i = 0; i < stream->nb_streams; i++) {
1720 AVStream *st = stream->streams[i];
1721 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
b29f97d1 1722 const char *type = "unknown";
b582f314
PG
1723 char parameters[64];
1724
1725 parameters[0] = 0;
a6e14edd
PG
1726
1727 switch(st->codec.codec_type) {
1728 case CODEC_TYPE_AUDIO:
1729 type = "audio";
1730 break;
1731 case CODEC_TYPE_VIDEO:
1732 type = "video";
cde25790 1733 sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
14bea432 1734 st->codec.qmin, st->codec.qmax, st->codec.frame_rate / st->codec.frame_rate_base);
a6e14edd
PG
1735 break;
1736 default:
ec3b2232 1737 av_abort();
a6e14edd 1738 }
2effd274 1739 url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
b582f314 1740 i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
a6e14edd 1741 }
2effd274 1742 url_fprintf(pb, "</table>\n");
a6e14edd
PG
1743
1744 }
1745 stream = stream->next;
1746 }
85f07f22
FB
1747
1748#if 0
1749 {
1750 float avg;
1751 AVCodecContext *enc;
1752 char buf[1024];
1753
1754 /* feed status */
1755 stream = first_feed;
1756 while (stream != NULL) {
2effd274
FB
1757 url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1758 url_fprintf(pb, "<TABLE>\n");
1759 url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
85f07f22
FB
1760 for(i=0;i<stream->nb_streams;i++) {
1761 AVStream *st = stream->streams[i];
1762 FeedData *fdata = st->priv_data;
1763 enc = &st->codec;
1764
1765 avcodec_string(buf, sizeof(buf), enc);
1766 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1767 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1768 avg /= enc->frame_size;
2effd274 1769 url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n",
85f07f22
FB
1770 buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1771 }
2effd274 1772 url_fprintf(pb, "</TABLE>\n");
85f07f22
FB
1773 stream = stream->next_feed;
1774 }
1775 }
1776#endif
1777
1778 /* connection status */
2effd274 1779 url_fprintf(pb, "<H2>Connection Status</H2>\n");
85f07f22 1780
2effd274 1781 url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
85f07f22
FB
1782 nb_connections, nb_max_connections);
1783
2effd274 1784 url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
6edd6884 1785 current_bandwidth, max_bandwidth);
42a63c6a 1786
2effd274
FB
1787 url_fprintf(pb, "<TABLE>\n");
1788 url_fprintf(pb, "<TR><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
85f07f22
FB
1789 c1 = first_http_ctx;
1790 i = 0;
2effd274 1791 while (c1 != NULL) {
cde25790
PG
1792 int bitrate;
1793 int j;
1794
1795 bitrate = 0;
2effd274
FB
1796 if (c1->stream) {
1797 for (j = 0; j < c1->stream->nb_streams; j++) {
1798 if (!c1->stream->feed) {
1799 bitrate += c1->stream->streams[j]->codec.bit_rate;
1800 } else {
1801 if (c1->feed_streams[j] >= 0) {
1802 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec.bit_rate;
1803 }
1804 }
cde25790
PG
1805 }
1806 }
1807
85f07f22
FB
1808 i++;
1809 p = inet_ntoa(c1->from_addr.sin_addr);
2effd274
FB
1810 url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1811 i,
1812 c1->stream ? c1->stream->filename : "",
1813 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1814 p,
1815 c1->protocol,
1816 http_state[c1->state]);
1817 fmt_bytecount(pb, bitrate);
1818 url_fprintf(pb, "<td align=right>");
1819 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1820 url_fprintf(pb, "<td align=right>");
1821 fmt_bytecount(pb, c1->data_count);
1822 url_fprintf(pb, "\n");
85f07f22
FB
1823 c1 = c1->next;
1824 }
2effd274 1825 url_fprintf(pb, "</TABLE>\n");
85f07f22
FB
1826
1827 /* date */
1828 ti = time(NULL);
1829 p = ctime(&ti);
2effd274
FB
1830 url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1831 url_fprintf(pb, "</BODY>\n</HTML>\n");
85f07f22 1832
2effd274
FB
1833 len = url_close_dyn_buf(pb, &c->pb_buffer);
1834 c->buffer_ptr = c->pb_buffer;
1835 c->buffer_end = c->pb_buffer + len;
85f07f22
FB
1836}
1837
2effd274
FB
1838/* check if the parser needs to be opened for stream i */
1839static void open_parser(AVFormatContext *s, int i)
85f07f22 1840{
2effd274
FB
1841 AVStream *st = s->streams[i];
1842 AVCodec *codec;
31def229 1843
2effd274
FB
1844 if (!st->codec.codec) {
1845 codec = avcodec_find_decoder(st->codec.codec_id);
1846 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1847 st->codec.parse_only = 1;
1848 if (avcodec_open(&st->codec, codec) < 0) {
1849 st->codec.parse_only = 0;
1850 }
cde25790
PG
1851 }
1852 }
85f07f22
FB
1853}
1854
1855static int open_input_stream(HTTPContext *c, const char *info)
1856{
1857 char buf[128];
1858 char input_filename[1024];
1859 AVFormatContext *s;
2effd274 1860 int buf_size, i;
0c1a9eda 1861 int64_t stream_pos;
85f07f22
FB
1862
1863 /* find file name */
1864 if (c->stream->feed) {
1865 strcpy(input_filename, c->stream->feed->feed_filename);
1866 buf_size = FFM_PACKET_SIZE;
1867 /* compute position (absolute time) */
1868 if (find_info_tag(buf, sizeof(buf), "date", info)) {
1869 stream_pos = parse_date(buf, 0);
f747e6d3
PG
1870 } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1871 int prebuffer = strtol(buf, 0, 10);
0c1a9eda 1872 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
85f07f22 1873 } else {
0c1a9eda 1874 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
85f07f22
FB
1875 }
1876 } else {
1877 strcpy(input_filename, c->stream->feed_filename);
1878 buf_size = 0;
1879 /* compute position (relative time) */
1880 if (find_info_tag(buf, sizeof(buf), "date", info)) {
1881 stream_pos = parse_date(buf, 1);
1882 } else {
1883 stream_pos = 0;
1884 }
1885 }
1886 if (input_filename[0] == '\0')
1887 return -1;
1888
8256c0a3
PG
1889#if 0
1890 { time_t when = stream_pos / 1000000;
1891 http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1892 }
1893#endif
1894
85f07f22 1895 /* open stream */
2effd274
FB
1896 if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
1897 http_log("%s not found", input_filename);
85f07f22 1898 return -1;
2effd274 1899 }
85f07f22 1900 c->fmt_in = s;
2effd274
FB
1901
1902 /* open each parser */
1903 for(i=0;i<s->nb_streams;i++)
1904 open_parser(s, i);
1905
1906 /* choose stream as clock source (we favorize video stream if
1907 present) for packet sending */
1908 c->pts_stream_index = 0;
1909 for(i=0;i<c->stream->nb_streams;i++) {
1910 if (c->pts_stream_index == 0 &&
1911 c->stream->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) {
1912 c->pts_stream_index = i;
1913 }
1914 }
85f07f22 1915
bd7cf6ad
FB
1916 if (c->fmt_in->iformat->read_seek) {
1917 c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
85f07f22 1918 }
2effd274
FB
1919 /* set the start time (needed for maxtime and RTP packet timing) */
1920 c->start_time = cur_time;
1921 c->first_pts = AV_NOPTS_VALUE;
85f07f22
FB
1922 return 0;
1923}
1924
2effd274
FB
1925/* currently desactivated because the new PTS handling is not
1926 satisfactory yet */
1927//#define AV_READ_FRAME
1928#ifdef AV_READ_FRAME
85f07f22 1929
2effd274
FB
1930/* XXX: generalize that in ffmpeg for picture/audio/data. Currently
1931 the return packet MUST NOT be freed */
1932int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1933{
1934 AVStream *st;
1935 int len, ret, old_nb_streams, i;
f747e6d3 1936
2effd274
FB
1937 /* see if remaining frames must be parsed */
1938 for(;;) {
1939 if (s->cur_len > 0) {
1940 st = s->streams[s->cur_pkt.stream_index];
1941 len = avcodec_parse_frame(&st->codec, &pkt->data, &pkt->size,
1942 s->cur_ptr, s->cur_len);
1943 if (len < 0) {
1944 /* error: get next packet */
1945 s->cur_len = 0;
1946 } else {
1947 s->cur_ptr += len;
1948 s->cur_len -= len;
1949 if (pkt->size) {
1950 /* init pts counter if not done */
1951 if (st->pts.den == 0) {
1952 switch(st->codec.codec_type) {
1953 case CODEC_TYPE_AUDIO:
0c1a9eda 1954 st->pts_incr = (int64_t)s->pts_den;
2effd274 1955 av_frac_init(&st->pts, st->pts.val, 0,
0c1a9eda 1956 (int64_t)s->pts_num * st->codec.sample_rate);
2effd274
FB
1957 break;
1958 case CODEC_TYPE_VIDEO:
14bea432 1959 st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base;
2effd274 1960 av_frac_init(&st->pts, st->pts.val, 0,
0c1a9eda 1961 (int64_t)s->pts_num * st->codec.frame_rate);
2effd274
FB
1962 break;
1963 default:
1964 av_abort();
1965 }
1966 }
1967
1968 /* a frame was read: return it */
1969 pkt->pts = st->pts.val;
1970#if 0
1971 printf("add pts=%Lx num=%Lx den=%Lx incr=%Lx\n",
1972 st->pts.val, st->pts.num, st->pts.den, st->pts_incr);
1973#endif
1974 switch(st->codec.codec_type) {
1975 case CODEC_TYPE_AUDIO:
1976 av_frac_add(&st->pts, st->pts_incr * st->codec.frame_size);
1977 break;
1978 case CODEC_TYPE_VIDEO:
1979 av_frac_add(&st->pts, st->pts_incr);
1980 break;
1981 default:
1982 av_abort();
1983 }
1984 pkt->stream_index = s->cur_pkt.stream_index;
1985 /* we use the codec indication because it is
1986 more accurate than the demux flags */
1987 pkt->flags = 0;
492cd3a9 1988 if (st->codec.coded_frame->key_frame)
2effd274
FB
1989 pkt->flags |= PKT_FLAG_KEY;
1990 return 0;
1991 }
85f07f22
FB
1992 }
1993 } else {
2effd274
FB
1994 /* free previous packet */
1995 av_free_packet(&s->cur_pkt);
1996
1997 old_nb_streams = s->nb_streams;
1998 ret = av_read_packet(s, &s->cur_pkt);
1999 if (ret)
2000 return ret;
2001 /* open parsers for each new streams */
2002 for(i = old_nb_streams; i < s->nb_streams; i++)
2003 open_parser(s, i);
2004 st = s->streams[s->cur_pkt.stream_index];
2005
2006 /* update current pts (XXX: dts handling) from packet, or
2007 use current pts if none given */
2008 if (s->cur_pkt.pts != AV_NOPTS_VALUE) {
2009 av_frac_set(&st->pts, s->cur_pkt.pts);
2010 } else {
2011 s->cur_pkt.pts = st->pts.val;
2012 }
2013 if (!st->codec.codec) {
2014 /* no codec opened: just return the raw packet */
2015 *pkt = s->cur_pkt;
2016
2017 /* no codec opened: just update the pts by considering we
2018 have one frame and free the packet */
2019 if (st->pts.den == 0) {
2020 switch(st->codec.codec_type) {
2021 case CODEC_TYPE_AUDIO:
0c1a9eda 2022 st->pts_incr = (int64_t)s->pts_den * st->codec.frame_size;
2effd274 2023 av_frac_init(&st->pts, st->pts.val, 0,
0c1a9eda 2024 (int64_t)s->pts_num * st->codec.sample_rate);
2effd274
FB
2025 break;
2026 case CODEC_TYPE_VIDEO:
14bea432 2027 st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base;
2effd274 2028 av_frac_init(&st->pts, st->pts.val, 0,
0c1a9eda 2029 (int64_t)s->pts_num * st->codec.frame_rate);
2effd274
FB
2030 break;
2031 default:
2032 av_abort();
2033 }
2034 }
2035 av_frac_add(&st->pts, st->pts_incr);
2036 return 0;
2037 } else {
2038 s->cur_ptr = s->cur_pkt.data;
2039 s->cur_len = s->cur_pkt.size;
85f07f22
FB
2040 }
2041 }
2effd274
FB
2042 }
2043}
2044
2045static int compute_send_delay(HTTPContext *c)
2046{
0c1a9eda 2047 int64_t cur_pts, delta_pts, next_pts;
2effd274
FB
2048 int delay1;
2049
2050 /* compute current pts value from system time */
0c1a9eda 2051 cur_pts = ((int64_t)(cur_time - c->start_time) * c->fmt_in->pts_den) /
2effd274
FB
2052 (c->fmt_in->pts_num * 1000LL);
2053 /* compute the delta from the stream we choose as
2054 main clock (we do that to avoid using explicit
2055 buffers to do exact packet reordering for each
2056 stream */
2057 /* XXX: really need to fix the number of streams */
2058 if (c->pts_stream_index >= c->fmt_in->nb_streams)
2059 next_pts = cur_pts;
2060 else
2061 next_pts = c->fmt_in->streams[c->pts_stream_index]->pts.val;
2062 delta_pts = next_pts - cur_pts;
2063 if (delta_pts <= 0) {
2064 delay1 = 0;
2065 } else {
2066 delay1 = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
2067 }
2068 return delay1;
2069}
2070#else
2071
2072/* just fall backs */
b29f97d1 2073static int av_read_frame(AVFormatContext *s, AVPacket *pkt)
2effd274
FB
2074{
2075 return av_read_packet(s, pkt);
2076}
2077
2078static int compute_send_delay(HTTPContext *c)
2079{
a782f209
PG
2080 int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count);
2081
6edd6884 2082 if (datarate > c->stream->bandwidth * 2000) {
a782f209
PG
2083 return 1000;
2084 }
2effd274
FB
2085 return 0;
2086}
2087
2088#endif
2089
2090static int http_prepare_data(HTTPContext *c)
2091{
2092 int i, len, ret;
2093 AVFormatContext *ctx;
2094
2095 switch(c->state) {
2096 case HTTPSTATE_SEND_DATA_HEADER:
2097 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2098 pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author),
2099 c->stream->author);
2100 pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment),
2101 c->stream->comment);
2102 pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright),
2103 c->stream->copyright);
2104 pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title),
2105 c->stream->title);
2106
2107 /* open output stream by using specified codecs */
2108 c->fmt_ctx.oformat = c->stream->fmt;
2109 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2110 for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2111 AVStream *st;
2112 st = av_mallocz(sizeof(AVStream));
2113 c->fmt_ctx.streams[i] = st;
2114 /* if file or feed, then just take streams from FFStream struct */
2115 if (!c->stream->feed ||
2116 c->stream->feed == c->stream)
2117 memcpy(st, c->stream->streams[i], sizeof(AVStream));
2118 else
2119 memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]],
2120 sizeof(AVStream));
2121 st->codec.frame_number = 0; /* XXX: should be done in
2122 AVStream, not in codec */
a4d70941
PG
2123 /* I'm pretty sure that this is not correct...
2124 * However, without it, we crash
2125 */
2126 st->codec.coded_frame = &dummy_frame;
2effd274
FB
2127 }
2128 c->got_key_frame = 0;
2129
2130 /* prepare header and save header data in a stream */
2131 if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2132 /* XXX: potential leak */
2133 return -1;
2134 }
2135 c->fmt_ctx.pb.is_streamed = 1;
2136
3c27199b 2137 av_set_parameters(&c->fmt_ctx, NULL);
2effd274
FB
2138 av_write_header(&c->fmt_ctx);
2139
2140 len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2141 c->buffer_ptr = c->pb_buffer;
2142 c->buffer_end = c->pb_buffer + len;
2143
2144 c->state = HTTPSTATE_SEND_DATA;
85f07f22
FB
2145 c->last_packet_sent = 0;
2146 break;
2147 case HTTPSTATE_SEND_DATA:
2148 /* find a new packet */
85f07f22
FB
2149 {
2150 AVPacket pkt;
2effd274 2151
85f07f22
FB
2152 /* read a packet from the input stream */
2153 if (c->stream->feed) {
2154 ffm_set_write_index(c->fmt_in,
2155 c->stream->feed->feed_write_index,
2156 c->stream->feed->feed_size);
2157 }
ec3b2232
PG
2158
2159 if (c->stream->max_time &&
2ac887ba 2160 c->stream->max_time + c->start_time - cur_time < 0) {
ec3b2232
PG
2161 /* We have timed out */
2162 c->state = HTTPSTATE_SEND_DATA_TRAILER;
85f07f22 2163 } else {
a782f209 2164 if (1 || c->is_packetized) {
2effd274
FB
2165 if (compute_send_delay(c) > 0) {
2166 c->state = HTTPSTATE_WAIT;
2167 return 1; /* state changed */
2168 }
2169 }
6edd6884 2170 redo:
2effd274
FB
2171 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2172 if (c->stream->feed && c->stream->feed->feed_opened) {
2173 /* if coming from feed, it means we reached the end of the
2174 ffm file, so must wait for more data */
2175 c->state = HTTPSTATE_WAIT_FEED;
2176 return 1; /* state changed */
2177 } else {
6edd6884
FB
2178 if (c->stream->loop) {
2179 av_close_input_file(c->fmt_in);
2180 c->fmt_in = NULL;
2181 if (open_input_stream(c, "") < 0)
2182 goto no_loop;
2183 goto redo;
2184 } else {
2185 no_loop:
2186 /* must send trailer now because eof or error */
2187 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2188 }
2effd274
FB
2189 }
2190 } else {
2191 /* update first pts if needed */
2192 if (c->first_pts == AV_NOPTS_VALUE)
2193 c->first_pts = pkt.pts;
2194
2195 /* send it to the appropriate stream */
2196 if (c->stream->feed) {
2197 /* if coming from a feed, select the right stream */
2198 if (c->switch_pending) {
2199 c->switch_pending = 0;
2200 for(i=0;i<c->stream->nb_streams;i++) {
2201 if (c->switch_feed_streams[i] == pkt.stream_index) {
2202 if (pkt.flags & PKT_FLAG_KEY) {
2203 do_switch_stream(c, i);
2204 }
2205 }
2206 if (c->switch_feed_streams[i] >= 0) {
2207 c->switch_pending = 1;
2208 }
2209 }
2210 }
cde25790 2211 for(i=0;i<c->stream->nb_streams;i++) {
2effd274
FB
2212 if (c->feed_streams[i] == pkt.stream_index) {
2213 pkt.stream_index = i;
cde25790 2214 if (pkt.flags & PKT_FLAG_KEY) {
2effd274
FB
2215 c->got_key_frame |= 1 << i;
2216 }
2217 /* See if we have all the key frames, then
2218 * we start to send. This logic is not quite
2219 * right, but it works for the case of a
2220 * single video stream with one or more
2221 * audio streams (for which every frame is
2222 * typically a key frame).
2223 */
2224 if (!c->stream->send_on_key ||
2225 ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2226 goto send_it;
cde25790 2227 }
cde25790
PG
2228 }
2229 }
2effd274
FB
2230 } else {
2231 AVCodecContext *codec;
2232
2233 send_it:
2234 /* specific handling for RTP: we use several
2235 output stream (one for each RTP
2236 connection). XXX: need more abstract handling */
2237 if (c->is_packetized) {
2238 c->packet_stream_index = pkt.stream_index;
2239 ctx = c->rtp_ctx[c->packet_stream_index];
2240 codec = &ctx->streams[0]->codec;
6edd6884
FB
2241 /* only one stream per RTP connection */
2242 pkt.stream_index = 0;
2effd274
FB
2243 } else {
2244 ctx = &c->fmt_ctx;
2245 /* Fudge here */
2246 codec = &ctx->streams[pkt.stream_index]->codec;
85f07f22 2247 }
2effd274 2248
492cd3a9 2249 codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2effd274 2250
f747e6d3 2251#ifdef PJSG
2effd274
FB
2252 if (codec->codec_type == CODEC_TYPE_AUDIO) {
2253 codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
2254 /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
2255 }
2256#endif
2257
2258 if (c->is_packetized) {
2259 ret = url_open_dyn_packet_buf(&ctx->pb,
2260 url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]));
2261 c->packet_byte_count = 0;
2262 c->packet_start_time_us = av_gettime();
2263 } else {
2264 ret = url_open_dyn_buf(&ctx->pb);
2265 }
2266 if (ret < 0) {
2267 /* XXX: potential leak */
2268 return -1;
2269 }
90dca141 2270 if (av_write_frame(ctx, pkt.stream_index, pkt.data, pkt.size)) {
2effd274
FB
2271 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2272 }
2273
2274 len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2275 c->buffer_ptr = c->pb_buffer;
2276 c->buffer_end = c->pb_buffer + len;
2277
2278 codec->frame_number++;
f747e6d3 2279 }
2effd274
FB
2280#ifndef AV_READ_FRAME
2281 av_free_packet(&pkt);
f747e6d3 2282#endif
85f07f22 2283 }
85f07f22
FB
2284 }
2285 }
2286 break;
2287 default:
2288 case HTTPSTATE_SEND_DATA_TRAILER:
2289 /* last packet test ? */
2effd274 2290 if (c->last_packet_sent || c->is_packetized)
85f07f22 2291 return -1;
2effd274 2292 ctx = &c->fmt_ctx;
85f07f22 2293 /* prepare header */
2effd274
FB
2294 if (url_open_dyn_buf(&ctx->pb) < 0) {
2295 /* XXX: potential leak */
2296 return -1;
2297 }
2298 av_write_trailer(ctx);
2299 len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2300 c->buffer_ptr = c->pb_buffer;
2301 c->buffer_end = c->pb_buffer + len;
2302
85f07f22
FB
2303 c->last_packet_sent = 1;
2304 break;
2305 }
2306 return 0;
2307}
2308
2effd274
FB
2309/* in bit/s */
2310#define SHORT_TERM_BANDWIDTH 8000000
2311
85f07f22 2312/* should convert the format at the same time */
5eb765ef 2313static int http_send_data(HTTPContext *c)
85f07f22 2314{
2effd274
FB
2315 int len, ret, dt;
2316
85f07f22 2317 while (c->buffer_ptr >= c->buffer_end) {
2effd274 2318 av_freep(&c->pb_buffer);
5eb765ef 2319 ret = http_prepare_data(c);
85f07f22
FB
2320 if (ret < 0)
2321 return -1;
2322 else if (ret == 0) {
a6e14edd 2323 continue;
85f07f22
FB
2324 } else {
2325 /* state change requested */
2326 return 0;
2327 }
2328 }
2329
2effd274
FB
2330 if (c->buffer_ptr < c->buffer_end) {
2331 if (c->is_packetized) {
2332 /* RTP/UDP data output */
2333 len = c->buffer_end - c->buffer_ptr;
2334 if (len < 4) {
2335 /* fail safe - should never happen */
2336 fail1:
2337 c->buffer_ptr = c->buffer_end;
2338 return 0;
2339 }
2340 len = (c->buffer_ptr[0] << 24) |
2341 (c->buffer_ptr[1] << 16) |
2342 (c->buffer_ptr[2] << 8) |
2343 (c->buffer_ptr[3]);
2344 if (len > (c->buffer_end - c->buffer_ptr))
2345 goto fail1;
2346
2347 /* short term bandwidth limitation */
2348 dt = av_gettime() - c->packet_start_time_us;
2349 if (dt < 1)
2350 dt = 1;
2351
0c1a9eda
ZK
2352 if ((c->packet_byte_count + len) * (int64_t)1000000 >=
2353 (SHORT_TERM_BANDWIDTH / 8) * (int64_t)dt) {
2effd274
FB
2354 /* bandwidth overflow : wait at most one tick and retry */
2355 c->state = HTTPSTATE_WAIT_SHORT;
2356 return 0;
f747e6d3 2357 }
2effd274
FB
2358
2359 c->buffer_ptr += 4;
2360 url_write(c->rtp_handles[c->packet_stream_index],
2361 c->buffer_ptr, len);
f747e6d3 2362 c->buffer_ptr += len;
2effd274
FB
2363 c->packet_byte_count += len;
2364 } else {
2365 /* TCP data output */
2366 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2367 if (len < 0) {
2368 if (errno != EAGAIN && errno != EINTR) {
2369 /* error : close connection */
2370 return -1;
2371 } else {
2372 return 0;
2373 }
2374 } else {
2375 c->buffer_ptr += len;
2376 }
85f07f22 2377 }
2effd274
FB
2378 c->data_count += len;
2379 update_datarate(&c->datarate, c->data_count);
2380 if (c->stream)
2381 c->stream->bytes_served += len;
85f07f22
FB
2382 }
2383 return 0;
2384}
2385
2386static int http_start_receive_data(HTTPContext *c)
2387{
2388 int fd;
2389
2390 if (c->stream->feed_opened)
2391 return -1;
2392
e322ea48
PG
2393 /* Don't permit writing to this one */
2394 if (c->stream->readonly)
2395 return -1;
2396
85f07f22
FB
2397 /* open feed */
2398 fd = open(c->stream->feed_filename, O_RDWR);
2399 if (fd < 0)
2400 return -1;
2401 c->feed_fd = fd;
2402
2403 c->stream->feed_write_index = ffm_read_write_index(fd);
2404 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2405 lseek(fd, 0, SEEK_SET);
2406
2407 /* init buffer input */
2408 c->buffer_ptr = c->buffer;
2409 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2410 c->stream->feed_opened = 1;
2411 return 0;
2412}
2413
2414static int http_receive_data(HTTPContext *c)
2415{
85f07f22
FB
2416 HTTPContext *c1;
2417
a6e14edd
PG
2418 if (c->buffer_end > c->buffer_ptr) {
2419 int len;
2420
2421 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2422 if (len < 0) {
2423 if (errno != EAGAIN && errno != EINTR) {
2424 /* error : close connection */
2425 goto fail;
2426 }
2427 } else if (len == 0) {
2428 /* end of connection : close it */
2429 goto fail;
2430 } else {
2431 c->buffer_ptr += len;
2432 c->data_count += len;
5eb765ef 2433 update_datarate(&c->datarate, c->data_count);
a6e14edd
PG
2434 }
2435 }
2436
85f07f22 2437 if (c->buffer_ptr >= c->buffer_end) {
f747e6d3 2438 FFStream *feed = c->stream;
85f07f22
FB
2439 /* a packet has been received : write it in the store, except
2440 if header */
2441 if (c->data_count > FFM_PACKET_SIZE) {
85f07f22
FB
2442
2443 // printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2444 /* XXX: use llseek or url_seek */
2445 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2446 write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2447
2448 feed->feed_write_index += FFM_PACKET_SIZE;
2449 /* update file size */
2450 if (feed->feed_write_index > c->stream->feed_size)
2451 feed->feed_size = feed->feed_write_index;
2452
2453 /* handle wrap around if max file size reached */
2454 if (feed->feed_write_index >= c->stream->feed_max_size)
2455 feed->feed_write_index = FFM_PACKET_SIZE;
2456
2457 /* write index */
2458 ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2459
2460 /* wake up any waiting connections */
2461 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2462 if (c1->state == HTTPSTATE_WAIT_FEED &&
2463 c1->stream->feed == c->stream->feed) {
2464 c1->state = HTTPSTATE_SEND_DATA;
2465 }
2466 }
f747e6d3
PG
2467 } else {
2468 /* We have a header in our hands that contains useful data */
2469 AVFormatContext s;
bd7cf6ad 2470 AVInputFormat *fmt_in;
f747e6d3
PG
2471 ByteIOContext *pb = &s.pb;
2472 int i;
2473
2474 memset(&s, 0, sizeof(s));
2475
2476 url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2477 pb->buf_end = c->buffer_end; /* ?? */
2478 pb->is_streamed = 1;
2479
bd7cf6ad
FB
2480 /* use feed output format name to find corresponding input format */
2481 fmt_in = av_find_input_format(feed->fmt->name);
2482 if (!fmt_in)
2483 goto fail;
2484
98486a6b
RS
2485 if (fmt_in->priv_data_size > 0) {
2486 s.priv_data = av_mallocz(fmt_in->priv_data_size);
2487 if (!s.priv_data)
2488 goto fail;
2489 } else
2490 s.priv_data = NULL;
ec3b2232 2491
bd7cf6ad 2492 if (fmt_in->read_header(&s, 0) < 0) {
ec3b2232 2493 av_freep(&s.priv_data);
f747e6d3
PG
2494 goto fail;
2495 }
2496
2497 /* Now we have the actual streams */
2498 if (s.nb_streams != feed->nb_streams) {
ec3b2232 2499 av_freep(&s.priv_data);
f747e6d3
PG
2500 goto fail;
2501 }
2502 for (i = 0; i < s.nb_streams; i++) {
bd7cf6ad
FB
2503 memcpy(&feed->streams[i]->codec,
2504 &s.streams[i]->codec, sizeof(AVCodecContext));
f747e6d3 2505 }
ec3b2232 2506 av_freep(&s.priv_data);
85f07f22
FB
2507 }
2508 c->buffer_ptr = c->buffer;
2509 }
2510
85f07f22
FB
2511 return 0;
2512 fail:
2513 c->stream->feed_opened = 0;
2514 close(c->feed_fd);
2515 return -1;
2516}
2517
2effd274
FB
2518/********************************************************************/
2519/* RTSP handling */
2520
2521static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2522{
2523 const char *str;
2524 time_t ti;
2525 char *p;
2526 char buf2[32];
2527
2528 switch(error_number) {
2529#define DEF(n, c, s) case c: str = s; break;
2530#include "rtspcodes.h"
2531#undef DEF
2532 default:
2533 str = "Unknown Error";
2534 break;
2535 }
2536
2537 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2538 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2539
2540 /* output GMT time */
2541 ti = time(NULL);
2542 p = ctime(&ti);
2543 strcpy(buf2, p);
2544 p = buf2 + strlen(p) - 1;
2545 if (*p == '\n')
2546 *p = '\0';
2547 url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2548}
2549
2550static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2551{
2552 rtsp_reply_header(c, error_number);
2553 url_fprintf(c->pb, "\r\n");
2554}
2555
2556static int rtsp_parse_request(HTTPContext *c)
2557{
2558 const char *p, *p1, *p2;
2559 char cmd[32];
2560 char url[1024];
2561 char protocol[32];
2562 char line[1024];
2563 ByteIOContext pb1;
2564 int len;
2565 RTSPHeader header1, *header = &header1;
2566
2567 c->buffer_ptr[0] = '\0';
2568 p = c->buffer;
2569
2570 get_word(cmd, sizeof(cmd), &p);
2571 get_word(url, sizeof(url), &p);
2572 get_word(protocol, sizeof(protocol), &p);
2573
2574 pstrcpy(c->method, sizeof(c->method), cmd);
2575 pstrcpy(c->url, sizeof(c->url), url);
2576 pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2577
2578 c->pb = &pb1;
2579 if (url_open_dyn_buf(c->pb) < 0) {
2580 /* XXX: cannot do more */
2581 c->pb = NULL; /* safety */
2582 return -1;
2583 }
2584
2585 /* check version name */
2586 if (strcmp(protocol, "RTSP/1.0") != 0) {
2587 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2588 goto the_end;
2589 }
2590
2591 /* parse each header line */
2592 memset(header, 0, sizeof(RTSPHeader));
2593 /* skip to next line */
2594 while (*p != '\n' && *p != '\0')
2595 p++;
2596 if (*p == '\n')
2597 p++;
2598 while (*p != '\0') {
2599 p1 = strchr(p, '\n');
2600 if (!p1)
2601 break;
2602 p2 = p1;
2603 if (p2 > p && p2[-1] == '\r')
2604 p2--;
2605 /* skip empty line */
2606 if (p2 == p)
2607 break;
2608 len = p2 - p;
2609 if (len > sizeof(line) - 1)
2610 len = sizeof(line) - 1;
2611 memcpy(line, p, len);
2612 line[len] = '\0';
2613 rtsp_parse_line(header, line);
2614 p = p1 + 1;
2615 }
2616
2617 /* handle sequence number */
2618 c->seq = header->seq;
2619
2620 if (!strcmp(cmd, "DESCRIBE")) {
2621 rtsp_cmd_describe(c, url);
0df65975
AR
2622 } else if (!strcmp(cmd, "OPTIONS")) {
2623 rtsp_cmd_options(c, url);
2effd274
FB
2624 } else if (!strcmp(cmd, "SETUP")) {
2625 rtsp_cmd_setup(c, url, header);
2626 } else if (!strcmp(cmd, "PLAY")) {
2627 rtsp_cmd_play(c, url, header);
2628 } else if (!strcmp(cmd, "PAUSE")) {
2629 rtsp_cmd_pause(c, url, header);
2630 } else if (!strcmp(cmd, "TEARDOWN")) {
2631 rtsp_cmd_teardown(c, url, header);
2632 } else {
2633 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2634 }
2635 the_end:
2636 len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2637 c->pb = NULL; /* safety */
2638 if (len < 0) {
2639 /* XXX: cannot do more */
2640 return -1;
2641 }
2642 c->buffer_ptr = c->pb_buffer;
2643 c->buffer_end = c->pb_buffer + len;
2644 c->state = RTSPSTATE_SEND_REPLY;
2645 return 0;
2646}
2647
829ac53d
FB
2648/* XXX: move that to rtsp.c, but would need to replace FFStream by
2649 AVFormatContext */
0c1a9eda 2650static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d 2651 struct in_addr my_ip)
2effd274
FB
2652{
2653 ByteIOContext pb1, *pb = &pb1;
0fa45e19 2654 int i, payload_type, port, private_payload_type, j;
2effd274
FB
2655 const char *ipstr, *title, *mediatype;
2656 AVStream *st;
2657
2effd274
FB
2658 if (url_open_dyn_buf(pb) < 0)
2659 return -1;
2660
2661 /* general media info */
2662
2663 url_fprintf(pb, "v=0\n");
829ac53d 2664 ipstr = inet_ntoa(my_ip);
2effd274
FB
2665 url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2666 title = stream->title;
2667 if (title[0] == '\0')
2668 title = "No Title";
2669 url_fprintf(pb, "s=%s\n", title);
2670 if (stream->comment[0] != '\0')
2671 url_fprintf(pb, "i=%s\n", stream->comment);
829ac53d
FB
2672 if (stream->is_multicast) {
2673 url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2674 }
2effd274 2675 /* for each stream, we output the necessary info */
0fa45e19 2676 private_payload_type = 96;
2effd274
FB
2677 for(i = 0; i < stream->nb_streams; i++) {
2678 st = stream->streams[i];
2679 switch(st->codec.codec_type) {
2680 case CODEC_TYPE_AUDIO:
2681 mediatype = "audio";
2682 break;
2683 case CODEC_TYPE_VIDEO:
2684 mediatype = "video";
2685 break;
2686 default:
2687 mediatype = "application";
2688 break;
2689 }
829ac53d
FB
2690 /* NOTE: the port indication is not correct in case of
2691 unicast. It is not an issue because RTSP gives it */
2effd274 2692 payload_type = rtp_get_payload_type(&st->codec);
0fa45e19
FB
2693 if (payload_type < 0)
2694 payload_type = private_payload_type++;
829ac53d
FB
2695 if (stream->is_multicast) {
2696 port = stream->multicast_port + 2 * i;
2697 } else {
2698 port = 0;
2699 }
2effd274 2700 url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
829ac53d 2701 mediatype, port, payload_type);
0fa45e19
FB
2702 if (payload_type >= 96) {
2703 /* for private payload type, we need to give more info */
2704 switch(st->codec.codec_id) {
2705 case CODEC_ID_MPEG4:
2706 {
2707 uint8_t *data;
2708 url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2709 payload_type, 90000);
2710 /* we must also add the mpeg4 header */
2711 data = st->codec.extradata;
2712 if (data) {
2713 url_fprintf(pb, "a=fmtp:%d config=");
2714 for(j=0;j<st->codec.extradata_size;j++) {
2715 url_fprintf(pb, "%02x", data[j]);
2716 }
2717 url_fprintf(pb, "\n");
2718 }
2719 }
2720 break;
2721 default:
2722 /* XXX: add other codecs ? */
2723 goto fail;
2724 }
2725 }
2effd274
FB
2726 url_fprintf(pb, "a=control:streamid=%d\n", i);
2727 }
2728 return url_close_dyn_buf(pb, pbuffer);
0fa45e19
FB
2729 fail:
2730 url_close_dyn_buf(pb, pbuffer);
2731 av_free(*pbuffer);
2732 return -1;
2effd274
FB
2733}
2734
0df65975
AR
2735static void rtsp_cmd_options(HTTPContext *c, const char *url)
2736{
2737// rtsp_reply_header(c, RTSP_STATUS_OK);
2738 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2739 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2740 url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2741 url_fprintf(c->pb, "\r\n");
2742}
2743
2effd274
FB
2744static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2745{
2746 FFStream *stream;
2747 char path1[1024];
2748 const char *path;
0c1a9eda 2749 uint8_t *content;
829ac53d
FB
2750 int content_length, len;
2751 struct sockaddr_in my_addr;
2effd274
FB
2752
2753 /* find which url is asked */
2754 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2755 path = path1;
2756 if (*path == '/')
2757 path++;
2758
2759 for(stream = first_stream; stream != NULL; stream = stream->next) {
2760 if (!stream->is_feed && stream->fmt == &rtp_mux &&
2761 !strcmp(path, stream->filename)) {
2762 goto found;
2763 }
2764 }
2765 /* no stream found */
2766 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2767 return;
2768
2769 found:
2770 /* prepare the media description in sdp format */
829ac53d
FB
2771
2772 /* get the host IP */
2773 len = sizeof(my_addr);
2774 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2775
2776 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2effd274
FB
2777 if (content_length < 0) {
2778 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2779 return;
2780 }
2781 rtsp_reply_header(c, RTSP_STATUS_OK);
2782 url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2783 url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2784 url_fprintf(c->pb, "\r\n");
2785 put_buffer(c->pb, content, content_length);
2786}
2787
2788static HTTPContext *find_rtp_session(const char *session_id)
2789{
2790 HTTPContext *c;
2791
2792 if (session_id[0] == '\0')
2793 return NULL;
2794
2795 for(c = first_http_ctx; c != NULL; c = c->next) {
2796 if (!strcmp(c->session_id, session_id))
2797 return c;
2798 }
2799 return NULL;
2800}
2801
b29f97d1 2802static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2effd274
FB
2803{
2804 RTSPTransportField *th;
2805 int i;
2806
2807 for(i=0;i<h->nb_transports;i++) {
2808 th = &h->transports[i];
2809 if (th->protocol == protocol)
2810 return th;
2811 }
2812 return NULL;
2813}
2814
2815static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2816 RTSPHeader *h)
2817{
2818 FFStream *stream;
2819 int stream_index, port;
2820 char buf[1024];
2821 char path1[1024];
2822 const char *path;
2823 HTTPContext *rtp_c;
2824 RTSPTransportField *th;
2825 struct sockaddr_in dest_addr;
2826 RTSPActionServerSetup setup;
2827
2828 /* find which url is asked */
2829 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2830 path = path1;
2831 if (*path == '/')
2832 path++;
2833
2834 /* now check each stream */
2835 for(stream = first_stream; stream != NULL; stream = stream->next) {
2836 if (!stream->is_feed && stream->fmt == &rtp_mux) {
2837 /* accept aggregate filenames only if single stream */
2838 if (!strcmp(path, stream->filename)) {
2839 if (stream->nb_streams != 1) {
2840 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2841 return;
2842 }
2843 stream_index = 0;
2844 goto found;
2845 }
2846
2847 for(stream_index = 0; stream_index < stream->nb_streams;
2848 stream_index++) {
2849 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2850 stream->filename, stream_index);
2851 if (!strcmp(path, buf))
2852 goto found;
2853 }
2854 }
2855 }
2856 /* no stream found */
2857 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2858 return;
2859 found:
2860
2861 /* generate session id if needed */
2862 if (h->session_id[0] == '\0') {
2863 snprintf(h->session_id, sizeof(h->session_id),
2864 "%08x%08x", (int)random(), (int)random());
2865 }
2866
2867 /* find rtp session, and create it if none found */
2868 rtp_c = find_rtp_session(h->session_id);
2869 if (!rtp_c) {
6edd6884 2870 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id);
2effd274
FB
2871 if (!rtp_c) {
2872 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2873 return;
2874 }
2875
2876 /* open input stream */
2877 if (open_input_stream(rtp_c, "") < 0) {
2878 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2879 return;
2880 }
2881
2882 /* always prefer UDP */
2883 th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2884 if (!th) {
2885 th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2886 if (!th) {
2887 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2888 return;
2889 }
2890 }
2891 rtp_c->rtp_protocol = th->protocol;
2892 }
2893
2894 /* test if stream is OK (test needed because several SETUP needs
2895 to be done for a given file) */
2896 if (rtp_c->stream != stream) {
2897 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2898 return;
2899 }
2900
2901 /* test if stream is already set up */
2902 if (rtp_c->rtp_ctx[stream_index]) {
2903 rtsp_reply_error(c, RTSP_STATUS_STATE);
2904 return;
2905 }
2906
2907 /* check transport */
2908 th = find_transport(h, rtp_c->rtp_protocol);
2909 if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2910 th->client_port_min <= 0)) {
2911 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2912 return;
2913 }
2914
2915 /* setup default options */
2916 setup.transport_option[0] = '\0';
2917 dest_addr = rtp_c->from_addr;
2918 dest_addr.sin_port = htons(th->client_port_min);
2919
2920 /* add transport option if needed */
2921 if (ff_rtsp_callback) {
2922 setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2923 if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2924 (char *)&setup, sizeof(setup),
2925 stream->rtsp_option) < 0) {
2926 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2927 return;
2928 }
2929 dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2930 }
2931
2932 /* setup stream */
2933 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
2934 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2935 return;
2936 }
2937
2938 /* now everything is OK, so we can send the connection parameters */
2939 rtsp_reply_header(c, RTSP_STATUS_OK);
2940 /* session ID */
2941 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2942
2943 switch(rtp_c->rtp_protocol) {
2944 case RTSP_PROTOCOL_RTP_UDP:
2945 port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2946 url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2947 "client_port=%d-%d;server_port=%d-%d",
2948 th->client_port_min, th->client_port_min + 1,
2949 port, port + 1);
2950 break;
2951 case RTSP_PROTOCOL_RTP_TCP:
2952 url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2953 stream_index * 2, stream_index * 2 + 1);
2954 break;
2955 default:
2956 break;
2957 }
2958 if (setup.transport_option[0] != '\0') {
2959 url_fprintf(c->pb, ";%s", setup.transport_option);
2960 }
2961 url_fprintf(c->pb, "\r\n");
2962
2963
2964 url_fprintf(c->pb, "\r\n");
2965}
2966
2967
2968/* find an rtp connection by using the session ID. Check consistency
2969 with filename */
2970static HTTPContext *find_rtp_session_with_url(const char *url,
2971 const char *session_id)
2972{
2973 HTTPContext *rtp_c;
2974 char path1[1024];
2975 const char *path;
2976
2977 rtp_c = find_rtp_session(session_id);
2978 if (!rtp_c)
2979 return NULL;
2980
2981 /* find which url is asked */
2982 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2983 path = path1;
2984 if (*path == '/')
2985 path++;
2986 if (strcmp(path, rtp_c->stream->filename) != 0)
2987 return NULL;
2988 return rtp_c;
2989}
2990
2991static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2992{
2993 HTTPContext *rtp_c;
2994
2995 rtp_c = find_rtp_session_with_url(url, h->session_id);
2996 if (!rtp_c) {
2997 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2998 return;
2999 }
3000
3001 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3002 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3003 rtp_c->state != HTTPSTATE_READY) {
3004 rtsp_reply_error(c, RTSP_STATUS_STATE);
3005 return;
3006 }
3007
3008 rtp_c->state = HTTPSTATE_SEND_DATA;
3009
3010 /* now everything is OK, so we can send the connection parameters */
3011 rtsp_reply_header(c, RTSP_STATUS_OK);
3012 /* session ID */
3013 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3014 url_fprintf(c->pb, "\r\n");
3015}
3016
3017static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3018{
3019 HTTPContext *rtp_c;
3020
3021 rtp_c = find_rtp_session_with_url(url, h->session_id);
3022 if (!rtp_c) {
3023 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3024 return;
3025 }
3026
3027 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3028 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3029 rtsp_reply_error(c, RTSP_STATUS_STATE);
3030 return;
3031 }
3032
3033 rtp_c->state = HTTPSTATE_READY;
3034
3035 /* now everything is OK, so we can send the connection parameters */
3036 rtsp_reply_header(c, RTSP_STATUS_OK);
3037 /* session ID */
3038 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3039 url_fprintf(c->pb, "\r\n");
3040}
3041
3042static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3043{
3044 HTTPContext *rtp_c;
3045
3046 rtp_c = find_rtp_session_with_url(url, h->session_id);
3047 if (!rtp_c) {
3048 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3049 return;
3050 }
3051
3052 /* abort the session */
3053 close_connection(rtp_c);
3054
3055 if (ff_rtsp_callback) {
3056 ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3057 NULL, 0,
3058 rtp_c->stream->rtsp_option);
3059 }
3060
3061 /* now everything is OK, so we can send the connection parameters */
3062 rtsp_reply_header(c, RTSP_STATUS_OK);
3063 /* session ID */
3064 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3065 url_fprintf(c->pb, "\r\n");
3066}
3067
3068
3069/********************************************************************/
3070/* RTP handling */
3071
6edd6884 3072static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
2effd274
FB
3073 FFStream *stream, const char *session_id)
3074{
3075 HTTPContext *c = NULL;
3076
3077 /* XXX: should output a warning page when coming
3078 close to the connection limit */
3079 if (nb_connections >= nb_max_connections)
3080 goto fail;
3081
3082 /* add a new connection */
3083 c = av_mallocz(sizeof(HTTPContext));
3084 if (!c)
3085 goto fail;
3086
3087 c->fd = -1;
3088 c->poll_entry = NULL;
6edd6884 3089 c->from_addr = *from_addr;
2effd274
FB
3090 c->buffer_size = IOBUFFER_INIT_SIZE;
3091 c->buffer = av_malloc(c->buffer_size);
3092 if (!c->buffer)
3093 goto fail;
3094 nb_connections++;
3095 c->stream = stream;
3096 pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3097 c->state = HTTPSTATE_READY;
3098 c->is_packetized = 1;
3099 /* protocol is shown in statistics */
3100 pstrcpy(c->protocol, sizeof(c->protocol), "RTP");
3101
6edd6884
FB
3102 current_bandwidth += stream->bandwidth;
3103
2effd274
FB
3104 c->next = first_http_ctx;
3105 first_http_ctx = c;
3106 return c;
3107
3108 fail:
3109 if (c) {
3110 av_free(c->buffer);
3111 av_free(c);
3112 }
3113 return NULL;
3114}
3115
3116/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3117 command). if dest_addr is NULL, then TCP tunneling in RTSP is
3118 used. */
3119static int rtp_new_av_stream(HTTPContext *c,
3120 int stream_index, struct sockaddr_in *dest_addr)
3121{
3122 AVFormatContext *ctx;
3123 AVStream *st;
3124 char *ipaddr;
3125 URLContext *h;
0c1a9eda 3126 uint8_t *dummy_buf;
6edd6884
FB
3127 char buf2[32];
3128
2effd274
FB
3129 /* now we can open the relevant output stream */
3130 ctx = av_mallocz(sizeof(AVFormatContext));
3131 if (!ctx)
3132 return -1;
3133 ctx->oformat = &rtp_mux;
3134
3135 st = av_mallocz(sizeof(AVStream));
3136 if (!st)
3137 goto fail;
3138 ctx->nb_streams = 1;
3139 ctx->streams[0] = st;
3140
3141 if (!c->stream->feed ||
3142 c->stream->feed == c->stream) {
3143 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3144 } else {
3145 memcpy(st,
3146 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3147 sizeof(AVStream));
3148 }
3149
3150 if (dest_addr) {
3151 /* build destination RTP address */
3152 ipaddr = inet_ntoa(dest_addr->sin_addr);
3153
6edd6884
FB
3154 /* XXX: also pass as parameter to function ? */
3155 if (c->stream->is_multicast) {
3156 int ttl;
3157 ttl = c->stream->multicast_ttl;
3158 if (!ttl)
3159 ttl = 16;
3160 snprintf(ctx->filename, sizeof(ctx->filename),
3161 "rtp://%s:%d?multicast=1&ttl=%d",
3162 ipaddr, ntohs(dest_addr->sin_port), ttl);
3163 } else {
3164 snprintf(ctx->filename, sizeof(ctx->filename),
3165 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3166 }
2effd274
FB
3167
3168 if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3169 goto fail;
3170 c->rtp_handles[stream_index] = h;
3171 } else {
3172 goto fail;
3173 }
3174
6edd6884
FB
3175 http_log("%s:%d - - [%s] \"RTPSTART %s/streamid=%d\"\n",
3176 ipaddr, ntohs(dest_addr->sin_port),
3177 ctime1(buf2),
3178 c->stream->filename, stream_index);
3179
2effd274
FB
3180 /* normally, no packets should be output here, but the packet size may be checked */
3181 if (url_open_dyn_packet_buf(&ctx->pb,
3182 url_get_max_packet_size(h)) < 0) {
3183 /* XXX: close stream */
3184 goto fail;
3185 }
3c27199b 3186 av_set_parameters(ctx, NULL);
2effd274
FB
3187 if (av_write_header(ctx) < 0) {
3188 fail:
3189 if (h)
3190 url_close(h);
3191 av_free(ctx);
3192 return -1;
3193 }
3194 url_close_dyn_buf(&ctx->pb, &dummy_buf);
3195 av_free(dummy_buf);
3196
3197 c->rtp_ctx[stream_index] = ctx;
3198 return 0;
3199}
3200
3201/********************************************************************/
3202/* ffserver initialization */
3203
b29f97d1 3204static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
2effd274
FB
3205{
3206 AVStream *fst;
3207
3208 fst = av_mallocz(sizeof(AVStream));
3209 if (!fst)
3210 return NULL;
3211 fst->priv_data = av_mallocz(sizeof(FeedData));
3212 memcpy(&fst->codec, codec, sizeof(AVCodecContext));
a4d70941 3213 fst->codec.coded_frame = &dummy_frame;
2effd274
FB
3214 stream->streams[stream->nb_streams++] = fst;
3215 return fst;
3216}
3217
85f07f22 3218/* return the stream number in the feed */
b29f97d1 3219static int add_av_stream(FFStream *feed, AVStream *st)
85f07f22
FB
3220{
3221 AVStream *fst;
3222 AVCodecContext *av, *av1;
3223 int i;
3224
3225 av = &st->codec;
3226 for(i=0;i<feed->nb_streams;i++) {
3227 st = feed->streams[i];
3228 av1 = &st->codec;
f747e6d3
PG
3229 if (av1->codec_id == av->codec_id &&
3230 av1->codec_type == av->codec_type &&
85f07f22
FB
3231 av1->bit_rate == av->bit_rate) {
3232
3233 switch(av->codec_type) {
3234 case CODEC_TYPE_AUDIO:
3235 if (av1->channels == av->channels &&
3236 av1->sample_rate == av->sample_rate)
3237 goto found;
3238 break;
3239 case CODEC_TYPE_VIDEO:
3240 if (av1->width == av->width &&
3241 av1->height == av->height &&
3242 av1->frame_rate == av->frame_rate &&
14bea432 3243 av1->frame_rate_base == av->frame_rate_base &&
85f07f22
FB
3244 av1->gop_size == av->gop_size)
3245 goto found;
3246 break;
f747e6d3 3247 default:
ec3b2232 3248 av_abort();
85f07f22
FB
3249 }
3250 }
3251 }
3252
2effd274 3253 fst = add_av_stream1(feed, av);
85f07f22
FB
3254 if (!fst)
3255 return -1;
85f07f22
FB
3256 return feed->nb_streams - 1;
3257 found:
3258 return i;
3259}
3260
b29f97d1 3261static void remove_stream(FFStream *stream)
2effd274
FB
3262{
3263 FFStream **ps;
3264 ps = &first_stream;
3265 while (*ps != NULL) {
3266 if (*ps == stream) {
3267 *ps = (*ps)->next;
3268 } else {
3269 ps = &(*ps)->next;
3270 }
3271 }
3272}
3273
0fa45e19 3274/* specific mpeg4 handling : we extract the raw parameters */
b29f97d1 3275static void extract_mpeg4_header(AVFormatContext *infile)
0fa45e19
FB
3276{
3277 int mpeg4_count, i, size;
3278 AVPacket pkt;
3279 AVStream *st;
0c1a9eda 3280 const uint8_t *p;
0fa45e19
FB
3281
3282 mpeg4_count = 0;
3283 for(i=0;i<infile->nb_streams;i++) {
3284 st = infile->streams[i];
3285 if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3286 st->codec.extradata == NULL) {
3287 mpeg4_count++;
3288 }
3289 }
3290 if (!mpeg4_count)
3291 return;
3292
3293 printf("MPEG4 without extra data: trying to find header\n");
3294 while (mpeg4_count > 0) {
3295 if (av_read_packet(infile, &pkt) < 0)
3296 break;
3297 st = infile->streams[pkt.stream_index];
3298 if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3299 st->codec.extradata == NULL) {
3300 /* fill extradata with the header */
3301 /* XXX: we make hard suppositions here ! */
3302 p = pkt.data;
3303 while (p < pkt.data + pkt.size - 4) {
3304 /* stop when vop header is found */
3305 if (p[0] == 0x00 && p[1] == 0x00 &&
3306 p[2] == 0x01 && p[3] == 0xb6) {
3307 size = p - pkt.data;
3308 // av_hex_dump(pkt.data, size);
3309 st->codec.extradata = av_malloc(size);
3310 st->codec.extradata_size = size;
3311 memcpy(st->codec.extradata, pkt.data, size);
3312 break;
3313 }
3314 p++;
3315 }
3316 mpeg4_count--;
3317 }
3318 av_free_packet(&pkt);
3319 }
3320}
3321
2effd274 3322/* compute the needed AVStream for each file */
b29f97d1 3323static void build_file_streams(void)
2effd274
FB
3324{
3325 FFStream *stream, *stream_next;
3326 AVFormatContext *infile;
3327 int i;
3328
3329 /* gather all streams */
3330 for(stream = first_stream; stream != NULL; stream = stream_next) {
3331 stream_next = stream->next;
3332 if (stream->stream_type == STREAM_TYPE_LIVE &&
3333 !stream->feed) {
3334 /* the stream comes from a file */
3335 /* try to open the file */
3336 /* open stream */
3337 if (av_open_input_file(&infile, stream->feed_filename,
3338 NULL, 0, NULL) < 0) {
3339 http_log("%s not found", stream->feed_filename);
3340 /* remove stream (no need to spend more time on it) */
3341 fail:
3342 remove_stream(stream);
3343 } else {
3344 /* find all the AVStreams inside and reference them in
3345 'stream' */
3346 if (av_find_stream_info(infile) < 0) {
3347 http_log("Could not find codec parameters from '%s'",
3348 stream->feed_filename);
3349 av_close_input_file(infile);
3350 goto fail;
3351 }
0fa45e19
FB
3352 extract_mpeg4_header(infile);
3353
2effd274
FB
3354 for(i=0;i<infile->nb_streams;i++) {
3355 add_av_stream1(stream, &infile->streams[i]->codec);
3356 }
3357 av_close_input_file(infile);
3358 }
3359 }
3360 }
3361}
3362
85f07f22 3363/* compute the needed AVStream for each feed */
b29f97d1 3364static void build_feed_streams(void)
85f07f22
FB
3365{
3366 FFStream *stream, *feed;
3367 int i;
3368
3369 /* gather all streams */
3370 for(stream = first_stream; stream != NULL; stream = stream->next) {
3371 feed = stream->feed;
3372 if (feed) {
3373 if (!stream->is_feed) {
2effd274 3374 /* we handle a stream coming from a feed */
85f07f22
FB
3375 for(i=0;i<stream->nb_streams;i++) {
3376 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3377 }
cde25790
PG
3378 }
3379 }
3380 }
3381
3382 /* gather all streams */
3383 for(stream = first_stream; stream != NULL; stream = stream->next) {
3384 feed = stream->feed;
3385 if (feed) {
3386 if (stream->is_feed) {
85f07f22
FB
3387 for(i=0;i<stream->nb_streams;i++) {
3388 stream->feed_streams[i] = i;
3389 }
3390 }
3391 }
3392 }
3393
3394 /* create feed files if needed */
3395 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3396 int fd;
3397
59eb2ed1
PG
3398 if (url_exist(feed->feed_filename)) {
3399 /* See if it matches */
3400 AVFormatContext *s;
3401 int matches = 0;
3402
3403 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3404 /* Now see if it matches */
3405 if (s->nb_streams == feed->nb_streams) {
3406 matches = 1;
3407 for(i=0;i<s->nb_streams;i++) {
3408 AVStream *sf, *ss;
3409 sf = feed->streams[i];
3410 ss = s->streams[i];
3411
3412 if (sf->index != ss->index ||
3413 sf->id != ss->id) {
3414 printf("Index & Id do not match for stream %d\n", i);
3415 matches = 0;
3416 } else {
3417 AVCodecContext *ccf, *ccs;
3418
3419 ccf = &sf->codec;
3420 ccs = &ss->codec;
3421#define CHECK_CODEC(x) (ccf->x != ccs->x)
3422
3423 if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3424 printf("Codecs do not match for stream %d\n", i);
3425 matches = 0;
3426 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3427 printf("Codec bitrates do not match for stream %d\n", i);
3428 matches = 0;
3429 } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3430 if (CHECK_CODEC(frame_rate) ||
14bea432 3431 CHECK_CODEC(frame_rate_base) ||
59eb2ed1
PG
3432 CHECK_CODEC(width) ||
3433 CHECK_CODEC(height)) {
3434 printf("Codec width, height and framerate do not match for stream %d\n", i);
3435 matches = 0;
3436 }
3437 } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3438 if (CHECK_CODEC(sample_rate) ||
3439 CHECK_CODEC(channels) ||
3440 CHECK_CODEC(frame_size)) {
3441 printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3442 matches = 0;
3443 }
3444 } else {
3445 printf("Unknown codec type\n");
3446 matches = 0;
3447 }
3448 }
3449 if (!matches) {
3450 break;
3451 }
3452 }
3453 } else {
3454 printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3455 feed->feed_filename, s->nb_streams, feed->nb_streams);
3456 }
3457
3458 av_close_input_file(s);
3459 } else {
3460 printf("Deleting feed file '%s' as it appears to be corrupt\n",
3461 feed->feed_filename);
3462 }
e322ea48
PG
3463 if (!matches) {
3464 if (feed->readonly) {
3465 printf("Unable to delete feed file '%s' as it is marked readonly\n",
3466 feed->feed_filename);
3467 exit(1);
3468 }
59eb2ed1 3469 unlink(feed->feed_filename);
e322ea48 3470 }
59eb2ed1 3471 }
85f07f22
FB
3472 if (!url_exist(feed->feed_filename)) {
3473 AVFormatContext s1, *s = &s1;
3474
e322ea48
PG
3475 if (feed->readonly) {
3476 printf("Unable to create feed file '%s' as it is marked readonly\n",
3477 feed->feed_filename);
3478 exit(1);
3479 }
3480
85f07f22
FB
3481 /* only write the header of the ffm file */
3482 if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3483 fprintf(stderr, "Could not open output feed file '%s'\n",
3484 feed->feed_filename);
3485 exit(1);
3486 }
bd7cf6ad 3487 s->oformat = feed->fmt;
85f07f22
FB
3488 s->nb_streams = feed->nb_streams;
3489 for(i=0;i<s->nb_streams;i++) {
3490 AVStream *st;
3491 st = feed->streams[i];
3492 s->streams[i] = st;
3493 }
3c27199b 3494 av_set_parameters(s, NULL);
bd7cf6ad
FB
3495 av_write_header(s);
3496 /* XXX: need better api */
3497 av_freep(&s->priv_data);
85f07f22
FB
3498 url_fclose(&s->pb);
3499 }
3500 /* get feed size and write index */
3501 fd = open(feed->feed_filename, O_RDONLY);
3502 if (fd < 0) {
3503 fprintf(stderr, "Could not open output feed file '%s'\n",
3504 feed->feed_filename);
3505 exit(1);
3506 }
3507
3508 feed->feed_write_index = ffm_read_write_index(fd);
3509 feed->feed_size = lseek(fd, 0, SEEK_END);
3510 /* ensure that we do not wrap before the end of file */
3511 if (feed->feed_max_size < feed->feed_size)
3512 feed->feed_max_size = feed->feed_size;
3513
3514 close(fd);
3515 }
3516}
3517
6edd6884
FB
3518/* compute the bandwidth used by each stream */
3519static void compute_bandwidth(void)
3520{
3521 int bandwidth, i;
3522 FFStream *stream;
3523
3524 for(stream = first_stream; stream != NULL; stream = stream->next) {
3525 bandwidth = 0;
3526 for(i=0;i<stream->nb_streams;i++) {
3527 AVStream *st = stream->streams[i];
3528 switch(st->codec.codec_type) {
3529 case CODEC_TYPE_AUDIO:
3530 case CODEC_TYPE_VIDEO:
3531 bandwidth += st->codec.bit_rate;
3532 break;
3533 default:
3534 break;
3535 }
3536 }
3537 stream->bandwidth = (bandwidth + 999) / 1000;
3538 }
3539}
3540
85f07f22
FB
3541static void get_arg(char *buf, int buf_size, const char **pp)
3542{
3543 const char *p;
3544 char *q;
3545 int quote;
3546
3547 p = *pp;
3548 while (isspace(*p)) p++;
3549 q = buf;
3550 quote = 0;
3551 if (*p == '\"' || *p == '\'')
3552 quote = *p++;
3553 for(;;) {
3554 if (quote) {
3555 if (*p == quote)
3556 break;
3557 } else {
3558 if (isspace(*p))
3559 break;
3560 }
3561 if (*p == '\0')
3562 break;
3563 if ((q - buf) < buf_size - 1)
3564 *q++ = *p;
3565 p++;
3566 }
3567 *q = '\0';
3568 if (quote && *p == quote)
3569 p++;
3570 *pp = p;
3571}
3572
3573/* add a codec and set the default parameters */
b29f97d1 3574static void add_codec(FFStream *stream, AVCodecContext *av)
85f07f22
FB
3575{
3576 AVStream *st;
3577
3578 /* compute default parameters */
3579 switch(av->codec_type) {
3580 case CODEC_TYPE_AUDIO:
3581 if (av->bit_rate == 0)
3582 av->bit_rate = 64000;
3583 if (av->sample_rate == 0)
3584 av->sample_rate = 22050;
3585 if (av->channels == 0)
3586 av->channels = 1;
3587 break;
3588 case CODEC_TYPE_VIDEO:
3589 if (av->bit_rate == 0)
3590 av->bit_rate = 64000;
14bea432
MN
3591 if (av->frame_rate == 0){
3592 av->frame_rate = 5;
3593 av->frame_rate_base = 1;
3594 }
85f07f22
FB
3595 if (av->width == 0 || av->height == 0) {
3596 av->width = 160;
3597 av->height = 128;
3598 }
ba9b374f 3599 /* Bitrate tolerance is less for streaming */
42a63c6a
PG
3600 if (av->bit_rate_tolerance == 0)
3601 av->bit_rate_tolerance = av->bit_rate / 4;
3602 if (av->qmin == 0)
3603 av->qmin = 3;
3604 if (av->qmax == 0)
3605 av->qmax = 31;
3606 if (av->max_qdiff == 0)
3607 av->max_qdiff = 3;
ba9b374f
J
3608 av->qcompress = 0.5;
3609 av->qblur = 0.5;
68d7eef9 3610
a782f209
PG
3611 if (!av->rc_eq)
3612 av->rc_eq = "tex^qComp";
3613 if (!av->i_quant_factor)
b3a391e8 3614 av->i_quant_factor = -0.8;
a782f209
PG
3615 if (!av->b_quant_factor)
3616 av->b_quant_factor = 1.25;
3617 if (!av->b_quant_offset)
3618 av->b_quant_offset = 1.25;
d6562d2c
PG
3619 if (!av->rc_min_rate)
3620 av->rc_min_rate = av->bit_rate / 2;
3621 if (!av->rc_max_rate)
3622 av->rc_max_rate = av->bit_rate * 2;
a782f209 3623
85f07f22 3624 break;
f747e6d3 3625 default:
ec3b2232 3626 av_abort();
85f07f22
FB
3627 }
3628
3629 st = av_mallocz(sizeof(AVStream));
3630 if (!st)
3631 return;
3632 stream->streams[stream->nb_streams++] = st;
3633 memcpy(&st->codec, av, sizeof(AVCodecContext));
3634}
3635
b29f97d1 3636static int opt_audio_codec(const char *arg)
f747e6d3
PG
3637{
3638 AVCodec *p;
3639
3640 p = first_avcodec;
3641 while (p) {
3642 if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3643 break;
3644 p = p->next;
3645 }
3646 if (p == NULL) {
3647 return CODEC_ID_NONE;
3648 }
3649
3650 return p->id;
3651}
3652
b29f97d1 3653static int opt_video_codec(const char *arg)
f747e6d3
PG
3654{
3655 AVCodec *p;
3656
3657 p = first_avcodec;
3658 while (p) {
3659 if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3660 break;
3661 p = p->next;
3662 }
3663 if (p == NULL) {
3664 return CODEC_ID_NONE;
3665 }
3666
3667 return p->id;
3668}
3669
2effd274
FB
3670/* simplistic plugin support */
3671
6638d424 3672#ifdef CONFIG_HAVE_DLOPEN
2effd274
FB
3673void load_module(const char *filename)
3674{
3675 void *dll;
3676 void (*init_func)(void);
3677 dll = dlopen(filename, RTLD_NOW);
3678 if (!dll) {
3679 fprintf(stderr, "Could not load module '%s' - %s\n",
3680 filename, dlerror());
3681 return;
3682 }
3683
3684 init_func = dlsym(dll, "ffserver_module_init");
3685 if (!init_func) {
3686 fprintf(stderr,
3687 "%s: init function 'ffserver_module_init()' not found\n",
3688 filename);
3689 dlclose(dll);
3690 }
3691
3692 init_func();
3693}
6638d424 3694#endif
2effd274 3695
b29f97d1 3696static int parse_ffconfig(const char *filename)
85f07f22
FB
3697{
3698 FILE *f;
3699 char line[1024];
3700 char cmd[64];
3701 char arg[1024];
3702 const char *p;
3703 int val, errors, line_num;
cde25790 3704 FFStream **last_stream, *stream, *redirect;
85f07f22
FB
3705 FFStream **last_feed, *feed;
3706 AVCodecContext audio_enc, video_enc;
3707 int audio_id, video_id;
3708
3709 f = fopen(filename, "r");
3710 if (!f) {
3711 perror(filename);
3712 return -1;
3713 }
3714
3715 errors = 0;
3716 line_num = 0;
3717 first_stream = NULL;
3718 last_stream = &first_stream;
3719 first_feed = NULL;
3720 last_feed = &first_feed;
3721 stream = NULL;
3722 feed = NULL;
cde25790 3723 redirect = NULL;
85f07f22
FB
3724 audio_id = CODEC_ID_NONE;
3725 video_id = CODEC_ID_NONE;
3726 for(;;) {
3727 if (fgets(line, sizeof(line), f) == NULL)
3728 break;
3729 line_num++;
3730 p = line;
3731 while (isspace(*p))
3732 p++;
3733 if (*p == '\0' || *p == '#')
3734 continue;
3735
3736 get_arg(cmd, sizeof(cmd), &p);
3737
3738 if (!strcasecmp(cmd, "Port")) {
3739 get_arg(arg, sizeof(arg), &p);
2effd274 3740 my_http_addr.sin_port = htons (atoi(arg));
85f07f22
FB
3741 } else if (!strcasecmp(cmd, "BindAddress")) {
3742 get_arg(arg, sizeof(arg), &p);
2effd274
FB
3743 if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3744 fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3745 filename, line_num, arg);
3746 errors++;
3747 }
3748 } else if (!strcasecmp(cmd, "NoDaemon")) {
3749 ffserver_daemon = 0;
3750 } else if (!strcasecmp(cmd, "RTSPPort")) {
3751 get_arg(arg, sizeof(arg), &p);
3752 my_rtsp_addr.sin_port = htons (atoi(arg));
3753 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3754 get_arg(arg, sizeof(arg), &p);
3755 if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
85f07f22
FB
3756 fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3757 filename, line_num, arg);
3758 errors++;
3759 }
3760 } else if (!strcasecmp(cmd, "MaxClients")) {
3761 get_arg(arg, sizeof(arg), &p);
3762 val = atoi(arg);
3763 if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3764 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3765 filename, line_num, arg);
3766 errors++;
3767 } else {
3768 nb_max_connections = val;
3769 }
42a63c6a
PG
3770 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3771 get_arg(arg, sizeof(arg), &p);
3772 val = atoi(arg);
3773 if (val < 10 || val > 100000) {
3774 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3775 filename, line_num, arg);
3776 errors++;
3777 } else {
6edd6884 3778 max_bandwidth = val;
42a63c6a 3779 }
85f07f22
FB
3780 } else if (!strcasecmp(cmd, "CustomLog")) {
3781 get_arg(logfilename, sizeof(logfilename), &p);
3782 } else if (!strcasecmp(cmd, "<Feed")) {
3783 /*********************************************/
3784 /* Feed related options */
3785 char *q;
3786 if (stream || feed) {
3787 fprintf(stderr, "%s:%d: Already in a tag\n",
3788 filename, line_num);
3789 } else {
3790 feed = av_mallocz(sizeof(FFStream));
3791 /* add in stream list */
3792 *last_stream = feed;
3793 last_stream = &feed->next;
3794 /* add in feed list */
3795 *last_feed = feed;
3796 last_feed = &feed->next_feed;
3797
3798 get_arg(feed->filename, sizeof(feed->filename), &p);
3799 q = strrchr(feed->filename, '>');
3800 if (*q)
3801 *q = '\0';
3802 feed->fmt = guess_format("ffm", NULL, NULL);
3803 /* defaut feed file */
3804 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3805 "/tmp/%s.ffm", feed->filename);
3806 feed->feed_max_size = 5 * 1024 * 1024;