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