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