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