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