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