fixed imlib2.c pixel format (imlib2 seems to use CPU endianness in RGBA32 as libavcodec)
[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
287static void http_log(char *fmt, ...)
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);
1701 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 */
2052int av_read_frame(AVFormatContext *s, AVPacket *pkt)
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
ec3b2232
PG
2460 s.priv_data = av_mallocz(fmt_in->priv_data_size);
2461 if (!s.priv_data)
2462 goto fail;
2463
bd7cf6ad 2464 if (fmt_in->read_header(&s, 0) < 0) {
ec3b2232 2465 av_freep(&s.priv_data);
f747e6d3
PG
2466 goto fail;
2467 }
2468
2469 /* Now we have the actual streams */
2470 if (s.nb_streams != feed->nb_streams) {
ec3b2232 2471 av_freep(&s.priv_data);
f747e6d3
PG
2472 goto fail;
2473 }
2474 for (i = 0; i < s.nb_streams; i++) {
bd7cf6ad
FB
2475 memcpy(&feed->streams[i]->codec,
2476 &s.streams[i]->codec, sizeof(AVCodecContext));
f747e6d3 2477 }
ec3b2232 2478 av_freep(&s.priv_data);
85f07f22
FB
2479 }
2480 c->buffer_ptr = c->buffer;
2481 }
2482
85f07f22
FB
2483 return 0;
2484 fail:
2485 c->stream->feed_opened = 0;
2486 close(c->feed_fd);
2487 return -1;
2488}
2489
2effd274
FB
2490/********************************************************************/
2491/* RTSP handling */
2492
2493static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2494{
2495 const char *str;
2496 time_t ti;
2497 char *p;
2498 char buf2[32];
2499
2500 switch(error_number) {
2501#define DEF(n, c, s) case c: str = s; break;
2502#include "rtspcodes.h"
2503#undef DEF
2504 default:
2505 str = "Unknown Error";
2506 break;
2507 }
2508
2509 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2510 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2511
2512 /* output GMT time */
2513 ti = time(NULL);
2514 p = ctime(&ti);
2515 strcpy(buf2, p);
2516 p = buf2 + strlen(p) - 1;
2517 if (*p == '\n')
2518 *p = '\0';
2519 url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2520}
2521
2522static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2523{
2524 rtsp_reply_header(c, error_number);
2525 url_fprintf(c->pb, "\r\n");
2526}
2527
2528static int rtsp_parse_request(HTTPContext *c)
2529{
2530 const char *p, *p1, *p2;
2531 char cmd[32];
2532 char url[1024];
2533 char protocol[32];
2534 char line[1024];
2535 ByteIOContext pb1;
2536 int len;
2537 RTSPHeader header1, *header = &header1;
2538
2539 c->buffer_ptr[0] = '\0';
2540 p = c->buffer;
2541
2542 get_word(cmd, sizeof(cmd), &p);
2543 get_word(url, sizeof(url), &p);
2544 get_word(protocol, sizeof(protocol), &p);
2545
2546 pstrcpy(c->method, sizeof(c->method), cmd);
2547 pstrcpy(c->url, sizeof(c->url), url);
2548 pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2549
2550 c->pb = &pb1;
2551 if (url_open_dyn_buf(c->pb) < 0) {
2552 /* XXX: cannot do more */
2553 c->pb = NULL; /* safety */
2554 return -1;
2555 }
2556
2557 /* check version name */
2558 if (strcmp(protocol, "RTSP/1.0") != 0) {
2559 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2560 goto the_end;
2561 }
2562
2563 /* parse each header line */
2564 memset(header, 0, sizeof(RTSPHeader));
2565 /* skip to next line */
2566 while (*p != '\n' && *p != '\0')
2567 p++;
2568 if (*p == '\n')
2569 p++;
2570 while (*p != '\0') {
2571 p1 = strchr(p, '\n');
2572 if (!p1)
2573 break;
2574 p2 = p1;
2575 if (p2 > p && p2[-1] == '\r')
2576 p2--;
2577 /* skip empty line */
2578 if (p2 == p)
2579 break;
2580 len = p2 - p;
2581 if (len > sizeof(line) - 1)
2582 len = sizeof(line) - 1;
2583 memcpy(line, p, len);
2584 line[len] = '\0';
2585 rtsp_parse_line(header, line);
2586 p = p1 + 1;
2587 }
2588
2589 /* handle sequence number */
2590 c->seq = header->seq;
2591
2592 if (!strcmp(cmd, "DESCRIBE")) {
2593 rtsp_cmd_describe(c, url);
2594 } else if (!strcmp(cmd, "SETUP")) {
2595 rtsp_cmd_setup(c, url, header);
2596 } else if (!strcmp(cmd, "PLAY")) {
2597 rtsp_cmd_play(c, url, header);
2598 } else if (!strcmp(cmd, "PAUSE")) {
2599 rtsp_cmd_pause(c, url, header);
2600 } else if (!strcmp(cmd, "TEARDOWN")) {
2601 rtsp_cmd_teardown(c, url, header);
2602 } else {
2603 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2604 }
2605 the_end:
2606 len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2607 c->pb = NULL; /* safety */
2608 if (len < 0) {
2609 /* XXX: cannot do more */
2610 return -1;
2611 }
2612 c->buffer_ptr = c->pb_buffer;
2613 c->buffer_end = c->pb_buffer + len;
2614 c->state = RTSPSTATE_SEND_REPLY;
2615 return 0;
2616}
2617
829ac53d
FB
2618/* XXX: move that to rtsp.c, but would need to replace FFStream by
2619 AVFormatContext */
2620static int prepare_sdp_description(FFStream *stream, UINT8 **pbuffer,
2621 struct in_addr my_ip)
2effd274
FB
2622{
2623 ByteIOContext pb1, *pb = &pb1;
0fa45e19 2624 int i, payload_type, port, private_payload_type, j;
2effd274
FB
2625 const char *ipstr, *title, *mediatype;
2626 AVStream *st;
2627
2effd274
FB
2628 if (url_open_dyn_buf(pb) < 0)
2629 return -1;
2630
2631 /* general media info */
2632
2633 url_fprintf(pb, "v=0\n");
829ac53d 2634 ipstr = inet_ntoa(my_ip);
2effd274
FB
2635 url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2636 title = stream->title;
2637 if (title[0] == '\0')
2638 title = "No Title";
2639 url_fprintf(pb, "s=%s\n", title);
2640 if (stream->comment[0] != '\0')
2641 url_fprintf(pb, "i=%s\n", stream->comment);
829ac53d
FB
2642 if (stream->is_multicast) {
2643 url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2644 }
2effd274 2645 /* for each stream, we output the necessary info */
0fa45e19 2646 private_payload_type = 96;
2effd274
FB
2647 for(i = 0; i < stream->nb_streams; i++) {
2648 st = stream->streams[i];
2649 switch(st->codec.codec_type) {
2650 case CODEC_TYPE_AUDIO:
2651 mediatype = "audio";
2652 break;
2653 case CODEC_TYPE_VIDEO:
2654 mediatype = "video";
2655 break;
2656 default:
2657 mediatype = "application";
2658 break;
2659 }
829ac53d
FB
2660 /* NOTE: the port indication is not correct in case of
2661 unicast. It is not an issue because RTSP gives it */
2effd274 2662 payload_type = rtp_get_payload_type(&st->codec);
0fa45e19
FB
2663 if (payload_type < 0)
2664 payload_type = private_payload_type++;
829ac53d
FB
2665 if (stream->is_multicast) {
2666 port = stream->multicast_port + 2 * i;
2667 } else {
2668 port = 0;
2669 }
2effd274 2670 url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
829ac53d 2671 mediatype, port, payload_type);
0fa45e19
FB
2672 if (payload_type >= 96) {
2673 /* for private payload type, we need to give more info */
2674 switch(st->codec.codec_id) {
2675 case CODEC_ID_MPEG4:
2676 {
2677 uint8_t *data;
2678 url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2679 payload_type, 90000);
2680 /* we must also add the mpeg4 header */
2681 data = st->codec.extradata;
2682 if (data) {
2683 url_fprintf(pb, "a=fmtp:%d config=");
2684 for(j=0;j<st->codec.extradata_size;j++) {
2685 url_fprintf(pb, "%02x", data[j]);
2686 }
2687 url_fprintf(pb, "\n");
2688 }
2689 }
2690 break;
2691 default:
2692 /* XXX: add other codecs ? */
2693 goto fail;
2694 }
2695 }
2effd274
FB
2696 url_fprintf(pb, "a=control:streamid=%d\n", i);
2697 }
2698 return url_close_dyn_buf(pb, pbuffer);
0fa45e19
FB
2699 fail:
2700 url_close_dyn_buf(pb, pbuffer);
2701 av_free(*pbuffer);
2702 return -1;
2effd274
FB
2703}
2704
2705static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2706{
2707 FFStream *stream;
2708 char path1[1024];
2709 const char *path;
2710 UINT8 *content;
829ac53d
FB
2711 int content_length, len;
2712 struct sockaddr_in my_addr;
2effd274
FB
2713
2714 /* find which url is asked */
2715 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2716 path = path1;
2717 if (*path == '/')
2718 path++;
2719
2720 for(stream = first_stream; stream != NULL; stream = stream->next) {
2721 if (!stream->is_feed && stream->fmt == &rtp_mux &&
2722 !strcmp(path, stream->filename)) {
2723 goto found;
2724 }
2725 }
2726 /* no stream found */
2727 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2728 return;
2729
2730 found:
2731 /* prepare the media description in sdp format */
829ac53d
FB
2732
2733 /* get the host IP */
2734 len = sizeof(my_addr);
2735 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2736
2737 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2effd274
FB
2738 if (content_length < 0) {
2739 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2740 return;
2741 }
2742 rtsp_reply_header(c, RTSP_STATUS_OK);
2743 url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2744 url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2745 url_fprintf(c->pb, "\r\n");
2746 put_buffer(c->pb, content, content_length);
2747}
2748
2749static HTTPContext *find_rtp_session(const char *session_id)
2750{
2751 HTTPContext *c;
2752
2753 if (session_id[0] == '\0')
2754 return NULL;
2755
2756 for(c = first_http_ctx; c != NULL; c = c->next) {
2757 if (!strcmp(c->session_id, session_id))
2758 return c;
2759 }
2760 return NULL;
2761}
2762
2763RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2764{
2765 RTSPTransportField *th;
2766 int i;
2767
2768 for(i=0;i<h->nb_transports;i++) {
2769 th = &h->transports[i];
2770 if (th->protocol == protocol)
2771 return th;
2772 }
2773 return NULL;
2774}
2775
2776static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2777 RTSPHeader *h)
2778{
2779 FFStream *stream;
2780 int stream_index, port;
2781 char buf[1024];
2782 char path1[1024];
2783 const char *path;
2784 HTTPContext *rtp_c;
2785 RTSPTransportField *th;
2786 struct sockaddr_in dest_addr;
2787 RTSPActionServerSetup setup;
2788
2789 /* find which url is asked */
2790 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2791 path = path1;
2792 if (*path == '/')
2793 path++;
2794
2795 /* now check each stream */
2796 for(stream = first_stream; stream != NULL; stream = stream->next) {
2797 if (!stream->is_feed && stream->fmt == &rtp_mux) {
2798 /* accept aggregate filenames only if single stream */
2799 if (!strcmp(path, stream->filename)) {
2800 if (stream->nb_streams != 1) {
2801 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2802 return;
2803 }
2804 stream_index = 0;
2805 goto found;
2806 }
2807
2808 for(stream_index = 0; stream_index < stream->nb_streams;
2809 stream_index++) {
2810 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2811 stream->filename, stream_index);
2812 if (!strcmp(path, buf))
2813 goto found;
2814 }
2815 }
2816 }
2817 /* no stream found */
2818 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2819 return;
2820 found:
2821
2822 /* generate session id if needed */
2823 if (h->session_id[0] == '\0') {
2824 snprintf(h->session_id, sizeof(h->session_id),
2825 "%08x%08x", (int)random(), (int)random());
2826 }
2827
2828 /* find rtp session, and create it if none found */
2829 rtp_c = find_rtp_session(h->session_id);
2830 if (!rtp_c) {
6edd6884 2831 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id);
2effd274
FB
2832 if (!rtp_c) {
2833 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2834 return;
2835 }
2836
2837 /* open input stream */
2838 if (open_input_stream(rtp_c, "") < 0) {
2839 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2840 return;
2841 }
2842
2843 /* always prefer UDP */
2844 th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2845 if (!th) {
2846 th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2847 if (!th) {
2848 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2849 return;
2850 }
2851 }
2852 rtp_c->rtp_protocol = th->protocol;
2853 }
2854
2855 /* test if stream is OK (test needed because several SETUP needs
2856 to be done for a given file) */
2857 if (rtp_c->stream != stream) {
2858 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2859 return;
2860 }
2861
2862 /* test if stream is already set up */
2863 if (rtp_c->rtp_ctx[stream_index]) {
2864 rtsp_reply_error(c, RTSP_STATUS_STATE);
2865 return;
2866 }
2867
2868 /* check transport */
2869 th = find_transport(h, rtp_c->rtp_protocol);
2870 if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2871 th->client_port_min <= 0)) {
2872 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2873 return;
2874 }
2875
2876 /* setup default options */
2877 setup.transport_option[0] = '\0';
2878 dest_addr = rtp_c->from_addr;
2879 dest_addr.sin_port = htons(th->client_port_min);
2880
2881 /* add transport option if needed */
2882 if (ff_rtsp_callback) {
2883 setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2884 if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2885 (char *)&setup, sizeof(setup),
2886 stream->rtsp_option) < 0) {
2887 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2888 return;
2889 }
2890 dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2891 }
2892
2893 /* setup stream */
2894 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
2895 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2896 return;
2897 }
2898
2899 /* now everything is OK, so we can send the connection parameters */
2900 rtsp_reply_header(c, RTSP_STATUS_OK);
2901 /* session ID */
2902 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2903
2904 switch(rtp_c->rtp_protocol) {
2905 case RTSP_PROTOCOL_RTP_UDP:
2906 port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2907 url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2908 "client_port=%d-%d;server_port=%d-%d",
2909 th->client_port_min, th->client_port_min + 1,
2910 port, port + 1);
2911 break;
2912 case RTSP_PROTOCOL_RTP_TCP:
2913 url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2914 stream_index * 2, stream_index * 2 + 1);
2915 break;
2916 default:
2917 break;
2918 }
2919 if (setup.transport_option[0] != '\0') {
2920 url_fprintf(c->pb, ";%s", setup.transport_option);
2921 }
2922 url_fprintf(c->pb, "\r\n");
2923
2924
2925 url_fprintf(c->pb, "\r\n");
2926}
2927
2928
2929/* find an rtp connection by using the session ID. Check consistency
2930 with filename */
2931static HTTPContext *find_rtp_session_with_url(const char *url,
2932 const char *session_id)
2933{
2934 HTTPContext *rtp_c;
2935 char path1[1024];
2936 const char *path;
2937
2938 rtp_c = find_rtp_session(session_id);
2939 if (!rtp_c)
2940 return NULL;
2941
2942 /* find which url is asked */
2943 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2944 path = path1;
2945 if (*path == '/')
2946 path++;
2947 if (strcmp(path, rtp_c->stream->filename) != 0)
2948 return NULL;
2949 return rtp_c;
2950}
2951
2952static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2953{
2954 HTTPContext *rtp_c;
2955
2956 rtp_c = find_rtp_session_with_url(url, h->session_id);
2957 if (!rtp_c) {
2958 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2959 return;
2960 }
2961
2962 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2963 rtp_c->state != HTTPSTATE_WAIT_FEED &&
2964 rtp_c->state != HTTPSTATE_READY) {
2965 rtsp_reply_error(c, RTSP_STATUS_STATE);
2966 return;
2967 }
2968
2969 rtp_c->state = HTTPSTATE_SEND_DATA;
2970
2971 /* now everything is OK, so we can send the connection parameters */
2972 rtsp_reply_header(c, RTSP_STATUS_OK);
2973 /* session ID */
2974 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2975 url_fprintf(c->pb, "\r\n");
2976}
2977
2978static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2979{
2980 HTTPContext *rtp_c;
2981
2982 rtp_c = find_rtp_session_with_url(url, h->session_id);
2983 if (!rtp_c) {
2984 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2985 return;
2986 }
2987
2988 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2989 rtp_c->state != HTTPSTATE_WAIT_FEED) {
2990 rtsp_reply_error(c, RTSP_STATUS_STATE);
2991 return;
2992 }
2993
2994 rtp_c->state = HTTPSTATE_READY;
2995
2996 /* now everything is OK, so we can send the connection parameters */
2997 rtsp_reply_header(c, RTSP_STATUS_OK);
2998 /* session ID */
2999 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3000 url_fprintf(c->pb, "\r\n");
3001}
3002
3003static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3004{
3005 HTTPContext *rtp_c;
3006
3007 rtp_c = find_rtp_session_with_url(url, h->session_id);
3008 if (!rtp_c) {
3009 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3010 return;
3011 }
3012
3013 /* abort the session */
3014 close_connection(rtp_c);
3015
3016 if (ff_rtsp_callback) {
3017 ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3018 NULL, 0,
3019 rtp_c->stream->rtsp_option);
3020 }
3021
3022 /* now everything is OK, so we can send the connection parameters */
3023 rtsp_reply_header(c, RTSP_STATUS_OK);
3024 /* session ID */
3025 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3026 url_fprintf(c->pb, "\r\n");
3027}
3028
3029
3030/********************************************************************/
3031/* RTP handling */
3032
6edd6884 3033static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
2effd274
FB
3034 FFStream *stream, const char *session_id)
3035{
3036 HTTPContext *c = NULL;
3037
3038 /* XXX: should output a warning page when coming
3039 close to the connection limit */
3040 if (nb_connections >= nb_max_connections)
3041 goto fail;
3042
3043 /* add a new connection */
3044 c = av_mallocz(sizeof(HTTPContext));
3045 if (!c)
3046 goto fail;
3047
3048 c->fd = -1;
3049 c->poll_entry = NULL;
6edd6884 3050 c->from_addr = *from_addr;
2effd274
FB
3051 c->buffer_size = IOBUFFER_INIT_SIZE;
3052 c->buffer = av_malloc(c->buffer_size);
3053 if (!c->buffer)
3054 goto fail;
3055 nb_connections++;
3056 c->stream = stream;
3057 pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3058 c->state = HTTPSTATE_READY;
3059 c->is_packetized = 1;
3060 /* protocol is shown in statistics */
3061 pstrcpy(c->protocol, sizeof(c->protocol), "RTP");
3062
6edd6884
FB
3063 current_bandwidth += stream->bandwidth;
3064
2effd274
FB
3065 c->next = first_http_ctx;
3066 first_http_ctx = c;
3067 return c;
3068
3069 fail:
3070 if (c) {
3071 av_free(c->buffer);
3072 av_free(c);
3073 }
3074 return NULL;
3075}
3076
3077/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3078 command). if dest_addr is NULL, then TCP tunneling in RTSP is
3079 used. */
3080static int rtp_new_av_stream(HTTPContext *c,
3081 int stream_index, struct sockaddr_in *dest_addr)
3082{
3083 AVFormatContext *ctx;
3084 AVStream *st;
3085 char *ipaddr;
3086 URLContext *h;
3087 UINT8 *dummy_buf;
6edd6884
FB
3088 char buf2[32];
3089
2effd274
FB
3090 /* now we can open the relevant output stream */
3091 ctx = av_mallocz(sizeof(AVFormatContext));
3092 if (!ctx)
3093 return -1;
3094 ctx->oformat = &rtp_mux;
3095
3096 st = av_mallocz(sizeof(AVStream));
3097 if (!st)
3098 goto fail;
3099 ctx->nb_streams = 1;
3100 ctx->streams[0] = st;
3101
3102 if (!c->stream->feed ||
3103 c->stream->feed == c->stream) {
3104 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3105 } else {
3106 memcpy(st,
3107 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3108 sizeof(AVStream));
3109 }
3110
3111 if (dest_addr) {
3112 /* build destination RTP address */
3113 ipaddr = inet_ntoa(dest_addr->sin_addr);
3114
6edd6884
FB
3115 /* XXX: also pass as parameter to function ? */
3116 if (c->stream->is_multicast) {
3117 int ttl;
3118 ttl = c->stream->multicast_ttl;
3119 if (!ttl)
3120 ttl = 16;
3121 snprintf(ctx->filename, sizeof(ctx->filename),
3122 "rtp://%s:%d?multicast=1&ttl=%d",
3123 ipaddr, ntohs(dest_addr->sin_port), ttl);
3124 } else {
3125 snprintf(ctx->filename, sizeof(ctx->filename),
3126 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3127 }
2effd274
FB
3128
3129 if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3130 goto fail;
3131 c->rtp_handles[stream_index] = h;
3132 } else {
3133 goto fail;
3134 }
3135
6edd6884
FB
3136 http_log("%s:%d - - [%s] \"RTPSTART %s/streamid=%d\"\n",
3137 ipaddr, ntohs(dest_addr->sin_port),
3138 ctime1(buf2),
3139 c->stream->filename, stream_index);
3140
2effd274
FB
3141 /* normally, no packets should be output here, but the packet size may be checked */
3142 if (url_open_dyn_packet_buf(&ctx->pb,
3143 url_get_max_packet_size(h)) < 0) {
3144 /* XXX: close stream */
3145 goto fail;
3146 }
3c27199b 3147 av_set_parameters(ctx, NULL);
2effd274
FB
3148 if (av_write_header(ctx) < 0) {
3149 fail:
3150 if (h)
3151 url_close(h);
3152 av_free(ctx);
3153 return -1;
3154 }
3155 url_close_dyn_buf(&ctx->pb, &dummy_buf);
3156 av_free(dummy_buf);
3157
3158 c->rtp_ctx[stream_index] = ctx;
3159 return 0;
3160}
3161
3162/********************************************************************/
3163/* ffserver initialization */
3164
3165AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3166{
3167 AVStream *fst;
3168
3169 fst = av_mallocz(sizeof(AVStream));
3170 if (!fst)
3171 return NULL;
3172 fst->priv_data = av_mallocz(sizeof(FeedData));
3173 memcpy(&fst->codec, codec, sizeof(AVCodecContext));
a4d70941 3174 fst->codec.coded_frame = &dummy_frame;
2effd274
FB
3175 stream->streams[stream->nb_streams++] = fst;
3176 return fst;
3177}
3178
85f07f22
FB
3179/* return the stream number in the feed */
3180int add_av_stream(FFStream *feed,
3181 AVStream *st)
3182{
3183 AVStream *fst;
3184 AVCodecContext *av, *av1;
3185 int i;
3186
3187 av = &st->codec;
3188 for(i=0;i<feed->nb_streams;i++) {
3189 st = feed->streams[i];
3190 av1 = &st->codec;
f747e6d3
PG
3191 if (av1->codec_id == av->codec_id &&
3192 av1->codec_type == av->codec_type &&
85f07f22
FB
3193 av1->bit_rate == av->bit_rate) {
3194
3195 switch(av->codec_type) {
3196 case CODEC_TYPE_AUDIO:
3197 if (av1->channels == av->channels &&
3198 av1->sample_rate == av->sample_rate)
3199 goto found;
3200 break;
3201 case CODEC_TYPE_VIDEO:
3202 if (av1->width == av->width &&
3203 av1->height == av->height &&
3204 av1->frame_rate == av->frame_rate &&
3205 av1->gop_size == av->gop_size)
3206 goto found;
3207 break;
f747e6d3 3208 default:
ec3b2232 3209 av_abort();
85f07f22
FB
3210 }
3211 }
3212 }
3213
2effd274 3214 fst = add_av_stream1(feed, av);
85f07f22
FB
3215 if (!fst)
3216 return -1;
85f07f22
FB
3217 return feed->nb_streams - 1;
3218 found:
3219 return i;
3220}
3221
2effd274
FB
3222void remove_stream(FFStream *stream)
3223{
3224 FFStream **ps;
3225 ps = &first_stream;
3226 while (*ps != NULL) {
3227 if (*ps == stream) {
3228 *ps = (*ps)->next;
3229 } else {
3230 ps = &(*ps)->next;
3231 }
3232 }
3233}
3234
0fa45e19
FB
3235/* specific mpeg4 handling : we extract the raw parameters */
3236void extract_mpeg4_header(AVFormatContext *infile)
3237{
3238 int mpeg4_count, i, size;
3239 AVPacket pkt;
3240 AVStream *st;
3241 const UINT8 *p;
3242
3243 mpeg4_count = 0;
3244 for(i=0;i<infile->nb_streams;i++) {
3245 st = infile->streams[i];
3246 if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3247 st->codec.extradata == NULL) {
3248 mpeg4_count++;
3249 }
3250 }
3251 if (!mpeg4_count)
3252 return;
3253
3254 printf("MPEG4 without extra data: trying to find header\n");
3255 while (mpeg4_count > 0) {
3256 if (av_read_packet(infile, &pkt) < 0)
3257 break;
3258 st = infile->streams[pkt.stream_index];
3259 if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3260 st->codec.extradata == NULL) {
3261 /* fill extradata with the header */
3262 /* XXX: we make hard suppositions here ! */
3263 p = pkt.data;
3264 while (p < pkt.data + pkt.size - 4) {
3265 /* stop when vop header is found */
3266 if (p[0] == 0x00 && p[1] == 0x00 &&
3267 p[2] == 0x01 && p[3] == 0xb6) {
3268 size = p - pkt.data;
3269 // av_hex_dump(pkt.data, size);
3270 st->codec.extradata = av_malloc(size);
3271 st->codec.extradata_size = size;
3272 memcpy(st->codec.extradata, pkt.data, size);
3273 break;
3274 }
3275 p++;
3276 }
3277 mpeg4_count--;
3278 }
3279 av_free_packet(&pkt);
3280 }
3281}
3282
2effd274
FB
3283/* compute the needed AVStream for each file */
3284void build_file_streams(void)
3285{
3286 FFStream *stream, *stream_next;
3287 AVFormatContext *infile;
3288 int i;
3289
3290 /* gather all streams */
3291 for(stream = first_stream; stream != NULL; stream = stream_next) {
3292 stream_next = stream->next;
3293 if (stream->stream_type == STREAM_TYPE_LIVE &&
3294 !stream->feed) {
3295 /* the stream comes from a file */
3296 /* try to open the file */
3297 /* open stream */
3298 if (av_open_input_file(&infile, stream->feed_filename,
3299 NULL, 0, NULL) < 0) {
3300 http_log("%s not found", stream->feed_filename);
3301 /* remove stream (no need to spend more time on it) */
3302 fail:
3303 remove_stream(stream);
3304 } else {
3305 /* find all the AVStreams inside and reference them in
3306 'stream' */
3307 if (av_find_stream_info(infile) < 0) {
3308 http_log("Could not find codec parameters from '%s'",
3309 stream->feed_filename);
3310 av_close_input_file(infile);
3311 goto fail;
3312 }
0fa45e19
FB
3313 extract_mpeg4_header(infile);
3314
2effd274
FB
3315 for(i=0;i<infile->nb_streams;i++) {
3316 add_av_stream1(stream, &infile->streams[i]->codec);
3317 }
3318 av_close_input_file(infile);
3319 }
3320 }
3321 }
3322}
3323
85f07f22
FB
3324/* compute the needed AVStream for each feed */
3325void build_feed_streams(void)
3326{
3327 FFStream *stream, *feed;
3328 int i;
3329
3330 /* gather all streams */
3331 for(stream = first_stream; stream != NULL; stream = stream->next) {
3332 feed = stream->feed;
3333 if (feed) {
3334 if (!stream->is_feed) {
2effd274 3335 /* we handle a stream coming from a feed */
85f07f22
FB
3336 for(i=0;i<stream->nb_streams;i++) {
3337 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3338 }
cde25790
PG
3339 }
3340 }
3341 }
3342
3343 /* gather all streams */
3344 for(stream = first_stream; stream != NULL; stream = stream->next) {
3345 feed = stream->feed;
3346 if (feed) {
3347 if (stream->is_feed) {
85f07f22
FB
3348 for(i=0;i<stream->nb_streams;i++) {
3349 stream->feed_streams[i] = i;
3350 }
3351 }
3352 }
3353 }
3354
3355 /* create feed files if needed */
3356 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3357 int fd;
3358
59eb2ed1
PG
3359 if (url_exist(feed->feed_filename)) {
3360 /* See if it matches */
3361 AVFormatContext *s;
3362 int matches = 0;
3363
3364 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3365 /* Now see if it matches */
3366 if (s->nb_streams == feed->nb_streams) {
3367 matches = 1;
3368 for(i=0;i<s->nb_streams;i++) {
3369 AVStream *sf, *ss;
3370 sf = feed->streams[i];
3371 ss = s->streams[i];
3372
3373 if (sf->index != ss->index ||
3374 sf->id != ss->id) {
3375 printf("Index & Id do not match for stream %d\n", i);
3376 matches = 0;
3377 } else {
3378 AVCodecContext *ccf, *ccs;
3379
3380 ccf = &sf->codec;
3381 ccs = &ss->codec;
3382#define CHECK_CODEC(x) (ccf->x != ccs->x)
3383
3384 if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3385 printf("Codecs do not match for stream %d\n", i);
3386 matches = 0;
3387 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3388 printf("Codec bitrates do not match for stream %d\n", i);
3389 matches = 0;
3390 } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3391 if (CHECK_CODEC(frame_rate) ||
3392 CHECK_CODEC(width) ||
3393 CHECK_CODEC(height)) {
3394 printf("Codec width, height and framerate do not match for stream %d\n", i);
3395 matches = 0;
3396 }
3397 } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3398 if (CHECK_CODEC(sample_rate) ||
3399 CHECK_CODEC(channels) ||
3400 CHECK_CODEC(frame_size)) {
3401 printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3402 matches = 0;
3403 }
3404 } else {
3405 printf("Unknown codec type\n");
3406 matches = 0;
3407 }
3408 }
3409 if (!matches) {
3410 break;
3411 }
3412 }
3413 } else {
3414 printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3415 feed->feed_filename, s->nb_streams, feed->nb_streams);
3416 }
3417
3418 av_close_input_file(s);
3419 } else {
3420 printf("Deleting feed file '%s' as it appears to be corrupt\n",
3421 feed->feed_filename);
3422 }
3423 if (!matches)
3424 unlink(feed->feed_filename);
3425 }
85f07f22
FB
3426 if (!url_exist(feed->feed_filename)) {
3427 AVFormatContext s1, *s = &s1;
3428
3429 /* only write the header of the ffm file */
3430 if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3431 fprintf(stderr, "Could not open output feed file '%s'\n",
3432 feed->feed_filename);
3433 exit(1);
3434 }
bd7cf6ad 3435 s->oformat = feed->fmt;
85f07f22
FB
3436 s->nb_streams = feed->nb_streams;
3437 for(i=0;i<s->nb_streams;i++) {
3438 AVStream *st;
3439 st = feed->streams[i];
3440 s->streams[i] = st;
3441 }
3c27199b 3442 av_set_parameters(s, NULL);
bd7cf6ad
FB
3443 av_write_header(s);
3444 /* XXX: need better api */
3445 av_freep(&s->priv_data);
85f07f22
FB
3446 url_fclose(&s->pb);
3447 }
3448 /* get feed size and write index */
3449 fd = open(feed->feed_filename, O_RDONLY);
3450 if (fd < 0) {
3451 fprintf(stderr, "Could not open output feed file '%s'\n",
3452 feed->feed_filename);
3453 exit(1);
3454 }
3455
3456 feed->feed_write_index = ffm_read_write_index(fd);
3457 feed->feed_size = lseek(fd, 0, SEEK_END);
3458 /* ensure that we do not wrap before the end of file */
3459 if (feed->feed_max_size < feed->feed_size)
3460 feed->feed_max_size = feed->feed_size;
3461
3462 close(fd);
3463 }
3464}
3465
6edd6884
FB
3466/* compute the bandwidth used by each stream */
3467static void compute_bandwidth(void)
3468{
3469 int bandwidth, i;
3470 FFStream *stream;
3471
3472 for(stream = first_stream; stream != NULL; stream = stream->next) {
3473 bandwidth = 0;
3474 for(i=0;i<stream->nb_streams;i++) {
3475 AVStream *st = stream->streams[i];
3476 switch(st->codec.codec_type) {
3477 case CODEC_TYPE_AUDIO:
3478 case CODEC_TYPE_VIDEO:
3479 bandwidth += st->codec.bit_rate;
3480 break;
3481 default:
3482 break;
3483 }
3484 }
3485 stream->bandwidth = (bandwidth + 999) / 1000;
3486 }
3487}
3488
85f07f22
FB
3489static void get_arg(char *buf, int buf_size, const char **pp)
3490{
3491 const char *p;
3492 char *q;
3493 int quote;
3494
3495 p = *pp;
3496 while (isspace(*p)) p++;
3497 q = buf;
3498 quote = 0;
3499 if (*p == '\"' || *p == '\'')
3500 quote = *p++;
3501 for(;;) {
3502 if (quote) {
3503 if (*p == quote)
3504 break;
3505 } else {
3506 if (isspace(*p))
3507 break;
3508 }
3509 if (*p == '\0')
3510 break;
3511 if ((q - buf) < buf_size - 1)
3512 *q++ = *p;
3513 p++;
3514 }
3515 *q = '\0';
3516 if (quote && *p == quote)
3517 p++;
3518 *pp = p;
3519}
3520
3521/* add a codec and set the default parameters */
3522void add_codec(FFStream *stream, AVCodecContext *av)
3523{
3524 AVStream *st;
3525
3526 /* compute default parameters */
3527 switch(av->codec_type) {
3528 case CODEC_TYPE_AUDIO:
3529 if (av->bit_rate == 0)
3530 av->bit_rate = 64000;
3531 if (av->sample_rate == 0)
3532 av->sample_rate = 22050;
3533 if (av->channels == 0)
3534 av->channels = 1;
3535 break;
3536 case CODEC_TYPE_VIDEO:
3537 if (av->bit_rate == 0)
3538 av->bit_rate = 64000;
3539 if (av->frame_rate == 0)
3540 av->frame_rate = 5 * FRAME_RATE_BASE;
3541 if (av->width == 0 || av->height == 0) {
3542 av->width = 160;
3543 av->height = 128;
3544 }
ba9b374f 3545 /* Bitrate tolerance is less for streaming */
42a63c6a
PG
3546 if (av->bit_rate_tolerance == 0)
3547 av->bit_rate_tolerance = av->bit_rate / 4;
3548 if (av->qmin == 0)
3549 av->qmin = 3;
3550 if (av->qmax == 0)
3551 av->qmax = 31;
3552 if (av->max_qdiff == 0)
3553 av->max_qdiff = 3;
ba9b374f
J
3554 av->qcompress = 0.5;
3555 av->qblur = 0.5;
68d7eef9 3556
a782f209
PG
3557 if (!av->rc_eq)
3558 av->rc_eq = "tex^qComp";
3559 if (!av->i_quant_factor)
b3a391e8 3560 av->i_quant_factor = -0.8;
a782f209
PG
3561 if (!av->b_quant_factor)
3562 av->b_quant_factor = 1.25;
3563 if (!av->b_quant_offset)
3564 av->b_quant_offset = 1.25;
d6562d2c
PG
3565 if (!av->rc_min_rate)
3566 av->rc_min_rate = av->bit_rate / 2;
3567 if (!av->rc_max_rate)
3568 av->rc_max_rate = av->bit_rate * 2;
a782f209 3569
85f07f22 3570 break;
f747e6d3 3571 default:
ec3b2232 3572 av_abort();
85f07f22
FB
3573 }
3574
3575 st = av_mallocz(sizeof(AVStream));
3576 if (!st)
3577 return;
3578 stream->streams[stream->nb_streams++] = st;
3579 memcpy(&st->codec, av, sizeof(AVCodecContext));
3580}
3581
f747e6d3
PG
3582int opt_audio_codec(const char *arg)
3583{
3584 AVCodec *p;
3585
3586 p = first_avcodec;
3587 while (p) {
3588 if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3589 break;
3590 p = p->next;
3591 }
3592 if (p == NULL) {
3593 return CODEC_ID_NONE;
3594 }
3595
3596 return p->id;
3597}
3598
3599int opt_video_codec(const char *arg)
3600{
3601 AVCodec *p;
3602
3603 p = first_avcodec;
3604 while (p) {
3605 if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3606 break;
3607 p = p->next;
3608 }
3609 if (p == NULL) {
3610 return CODEC_ID_NONE;
3611 }
3612
3613 return p->id;
3614}
3615
2effd274
FB
3616/* simplistic plugin support */
3617
6638d424 3618#ifdef CONFIG_HAVE_DLOPEN
2effd274
FB
3619void load_module(const char *filename)
3620{
3621 void *dll;
3622 void (*init_func)(void);
3623 dll = dlopen(filename, RTLD_NOW);
3624 if (!dll) {
3625 fprintf(stderr, "Could not load module '%s' - %s\n",
3626 filename, dlerror());
3627 return;
3628 }
3629
3630 init_func = dlsym(dll, "ffserver_module_init");
3631 if (!init_func) {
3632 fprintf(stderr,
3633 "%s: init function 'ffserver_module_init()' not found\n",
3634 filename);
3635 dlclose(dll);
3636 }
3637
3638 init_func();
3639}
6638d424 3640#endif
2effd274 3641
85f07f22
FB
3642int parse_ffconfig(const char *filename)
3643{
3644 FILE *f;
3645 char line[1024];
3646 char cmd[64];
3647 char arg[1024];
3648 const char *p;
3649 int val, errors, line_num;
cde25790 3650 FFStream **last_stream, *stream, *redirect;
85f07f22
FB
3651 FFStream **last_feed, *feed;
3652 AVCodecContext audio_enc, video_enc;
3653 int audio_id, video_id;
3654
3655 f = fopen(filename, "r");
3656 if (!f) {
3657 perror(filename);
3658 return -1;
3659 }
3660
3661 errors = 0;
3662 line_num = 0;
3663 first_stream = NULL;
3664 last_stream = &first_stream;
3665 first_feed = NULL;
3666 last_feed = &first_feed;
3667 stream = NULL;
3668 feed = NULL;
cde25790 3669 redirect = NULL;
85f07f22
FB
3670 audio_id = CODEC_ID_NONE;
3671 video_id = CODEC_ID_NONE;
3672 for(;;) {
3673 if (fgets(line, sizeof(line), f) == NULL)
3674 break;
3675 line_num++;
3676 p = line;
3677 while (isspace(*p))
3678 p++;
3679 if (*p == '\0' || *p == '#')
3680 continue;
3681
3682 get_arg(cmd, sizeof(cmd), &p);
3683
3684 if (!strcasecmp(cmd, "Port")) {
3685 get_arg(arg, sizeof(arg), &p);
2effd274 3686 my_http_addr.sin_port = htons (atoi(arg));
85f07f22
FB
3687 } else if (!strcasecmp(cmd, "BindAddress")) {
3688 get_arg(arg, sizeof(arg), &p);
2effd274
FB
3689 if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3690 fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3691 filename, line_num, arg);
3692 errors++;
3693 }
3694 } else if (!strcasecmp(cmd, "NoDaemon")) {
3695 ffserver_daemon = 0;
3696 } else if (!strcasecmp(cmd, "RTSPPort")) {
3697 get_arg(arg, sizeof(arg), &p);
3698 my_rtsp_addr.sin_port = htons (atoi(arg));
3699 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3700 get_arg(arg, sizeof(arg), &p);
3701 if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
85f07f22
FB
3702 fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3703 filename, line_num, arg);
3704 errors++;
3705 }
3706 } else if (!strcasecmp(cmd, "MaxClients")) {
3707 get_arg(arg, sizeof(arg), &p);
3708 val = atoi(arg);
3709 if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3710 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3711 filename, line_num, arg);
3712 errors++;
3713 } else {
3714 nb_max_connections = val;
3715 }
42a63c6a
PG
3716 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3717 get_arg(arg, sizeof(arg), &p);
3718 val = atoi(arg);
3719 if (val < 10 || val > 100000) {
3720 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3721 filename, line_num, arg);
3722 errors++;
3723 } else {
6edd6884 3724 max_bandwidth = val;
42a63c6a 3725 }
85f07f22
FB
3726 } else if (!strcasecmp(cmd, "CustomLog")) {
3727 get_arg(logfilename, sizeof(logfilename), &p);
3728 } else if (!strcasecmp(cmd, "<Feed")) {
3729 /*********************************************/
3730 /* Feed related options */
3731 char *q;
3732 if (stream || feed) {
3733 fprintf(stderr, "%s:%d: Already in a tag\n",
3734 filename, line_num);
3735 } else {
3736 feed = av_mallocz(sizeof(FFStream));
3737 /* add in stream list */
3738 *last_stream = feed;
3739 last_stream = &feed->next;
3740 /* add in feed list */
3741 *last_feed = feed;
3742 last_feed = &feed->next_feed;
3743
3744 get_arg(feed->filename, sizeof(feed->filename), &p);
3745 q = strrchr(feed->filename, '>');
3746 if (*q)
3747 *q = '\0';
3748 feed->fmt = guess_format("ffm", NULL, NULL);
3749 /* defaut feed file */
3750 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3751 "/tmp/%s.ffm", feed->filename);
3752 feed->feed_max_size = 5 * 1024 * 1024;
3753 feed->is_feed = 1;
3754 feed->feed = feed; /* self feeding :-) */
3755 }
cde25790
PG
3756 } else if (!strcasecmp(cmd, "Launch")) {
3757 if (feed) {
3758 int i;
3759
3760 feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3761
3762 feed->child_argv[0] = av_malloc(7);
3763 strcpy(feed->child_argv[0], "ffmpeg");
3764
3765 for (i = 1; i < 62; i++) {
3766 char argbuf[256];
3767
3768 get_arg(argbuf, sizeof(argbuf), &p);
3769 if (!argbuf[0])
3770 break;
3771
3772 feed->child_argv[i] = av_malloc(strlen(argbuf + 1));
3773 strcpy(feed->child_argv[i], argbuf);
3774 }
3775
3776 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3777
3778 snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s",
2effd274 3779 ntohs(my_http_addr.sin_port), feed->filename);
cde25790 3780 }
85f07f22
FB
3781 } else if (!strcasecmp(cmd, "File")) {
3782 if (feed) {
3783 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3784 } else if (stream) {
3785 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3786 }
3787 } else if (!strcasecmp(cmd, "FileMaxSize")) {
3788 if (feed) {
3789 const char *p1;
3790 double fsize;
3791
3792 get_arg(arg, sizeof(arg), &p);
3793 p1 = arg;
3794 fsize = strtod(p1, (char **)&p1);
3795 switch(toupper(*p1)) {
3796 case 'K':
3797 fsize *= 1024;
3798 break;
3799 case 'M':
3800 fsize *= 1024 * 1024;
3801 break;
3802 case 'G':
3803 fsize *= 1024 * 1024 * 1024;
3804 break;
3805 }
3806 feed->feed_max_size = (INT64)fsize;
3807 }
3808 } else if (!strcasecmp(cmd, "</Feed>")) {
3809 if (!feed) {
3810 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3811 filename, line_num);
3812 errors++;
59eb2ed1 3813#if 0
f747e6d3
PG
3814 } else {
3815 /* Make sure that we start out clean */
42a63c6a
PG
3816 if (unlink(feed->feed_filename) < 0
3817 && errno != ENOENT) {
3818 fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3819 filename, line_num, feed->feed_filename, strerror(errno));
3820 errors++;
3821 }
59eb2ed1 3822#endif
85f07f22
FB
3823 }
3824 feed = NULL;
3825 } else if (!strcasecmp(cmd, "<Stream")) {
3826 /*********************************************/
3827 /* Stream related options */
3828 char *q;
3829 if (stream || feed) {
3830 fprintf(stderr, "%s:%d: Already in a tag\n",
3831 filename, line_num);
3832 } else {
3833 stream = av_mallocz(sizeof(FFStream));
3834 *last_stream = stream;
3835 last_stream = &stream->next;
3836
3837 get_arg(stream->filename, sizeof(stream->filename), &p);
3838 q = strrchr(stream->filename, '>');
3839 if (*q)
3840 *q = '\0';
8256c0a3 3841 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
85f07f22
FB
3842 memset(&audio_enc, 0, sizeof(AVCodecContext));
3843 memset(&video_enc, 0, sizeof(AVCodecContext));
3844 audio_id = CODEC_ID_NONE;
3845 video_id = CODEC_ID_NONE;
3846 if (stream->fmt) {
3847 audio_id = stream->fmt->audio_codec;
3848 video_id = stream->fmt->video_codec;
3849 }
3850 }
3851 } else if (!strcasecmp(cmd, "Feed")) {
3852 get_arg(arg, sizeof(arg), &p);
3853 if (stream) {
3854 FFStream *sfeed;
3855
3856 sfeed = first_feed;
3857 while (sfeed != NULL) {
3858 if (!strcmp(sfeed->filename, arg))
3859 break;
3860 sfeed = sfeed->next_feed;
3861 }
3862 if (!sfeed) {
3863 fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3864 filename, line_num, arg);
3865 } else {
3866 stream->feed = sfeed;
3867 }
3868 }
3869 } else if (!strcasecmp(cmd, "Format")) {
3870 get_arg(arg, sizeof(arg), &p);
3871 if (!strcmp(arg, "status")) {
3872 stream->stream_type = STREAM_TYPE_STATUS;
3873 stream->fmt = NULL;
3874 } else {
3875 stream->stream_type = STREAM_TYPE_LIVE;