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