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