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