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