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