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