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