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