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