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