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