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