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