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