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