Patch check script.
[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);
2effd274
FB
276static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
277static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
278static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
279static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
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;
357 if (level > av_log_level)
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
755bfeab 1358 /* If already streaming this feed, do not let start another feeder. */
d0a5513b
AB
1359 if (stream->feed_opened) {
1360 snprintf(msg, sizeof(msg), "This feed is already being received.");
14c43f91 1361 http_log("feed %s already being received\n", stream->feed_filename);
d0a5513b
AB
1362 goto send_error;
1363 }
1364
611c5741 1365 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
6edd6884 1366 current_bandwidth += stream->bandwidth;
115329f1 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));
f7d78f36
MR
2046 av_strlcpy(c->fmt_ctx.author, c->stream->author,
2047 sizeof(c->fmt_ctx.author));
2048 av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2049 sizeof(c->fmt_ctx.comment));
2050 av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2051 sizeof(c->fmt_ctx.copyright));
2052 av_strlcpy(c->fmt_ctx.title, c->stream->title,
2053 sizeof(c->fmt_ctx.title));
2effd274 2054
3d9cc27d 2055 for(i=0;i<c->stream->nb_streams;i++) {
2effd274 2056 AVStream *st;
bb270c08 2057 AVStream *src;
2effd274
FB
2058 st = av_mallocz(sizeof(AVStream));
2059 c->fmt_ctx.streams[i] = st;
2060 /* if file or feed, then just take streams from FFStream struct */
115329f1 2061 if (!c->stream->feed ||
2effd274 2062 c->stream->feed == c->stream)
7c054ea7 2063 src = c->stream->streams[i];
2effd274 2064 else
7c054ea7
PG
2065 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2066
bb270c08
DB
2067 *st = *src;
2068 st->priv_data = 0;
01f4895c 2069 st->codec->frame_number = 0; /* XXX: should be done in
2effd274
FB
2070 AVStream, not in codec */
2071 }
3d9cc27d
BC
2072 /* set output format parameters */
2073 c->fmt_ctx.oformat = c->stream->fmt;
2074 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2075
2effd274
FB
2076 c->got_key_frame = 0;
2077
2078 /* prepare header and save header data in a stream */
2079 if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2080 /* XXX: potential leak */
2081 return -1;
2082 }
899681cd 2083 c->fmt_ctx.pb->is_streamed = 1;
2effd274 2084
8aae202e
BC
2085 /*
2086 * HACK to avoid mpeg ps muxer to spit many underflow errors
2087 * Default value from FFmpeg
2088 * Try to set it use configuration option
2089 */
2090 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2091 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2092
3c27199b 2093 av_set_parameters(&c->fmt_ctx, NULL);
929a9b75
BC
2094 if (av_write_header(&c->fmt_ctx) < 0) {
2095 http_log("Error writing output header\n");
f75cdda7 2096 return -1;
929a9b75 2097 }
2effd274 2098
899681cd 2099 len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2effd274
FB
2100 c->buffer_ptr = c->pb_buffer;
2101 c->buffer_end = c->pb_buffer + len;
2102
2103 c->state = HTTPSTATE_SEND_DATA;
85f07f22
FB
2104 c->last_packet_sent = 0;
2105 break;
2106 case HTTPSTATE_SEND_DATA:
2107 /* find a new packet */
3b371676
BC
2108 /* read a packet from the input stream */
2109 if (c->stream->feed)
2110 ffm_set_write_index(c->fmt_in,
2111 c->stream->feed->feed_write_index,
2112 c->stream->feed->feed_size);
2113
2114 if (c->stream->max_time &&
2115 c->stream->max_time + c->start_time - cur_time < 0)
2116 /* We have timed out */
2117 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2118 else {
2119 AVPacket pkt;
2120 redo:
2121 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2122 if (c->stream->feed && c->stream->feed->feed_opened) {
2123 /* if coming from feed, it means we reached the end of the
2124 ffm file, so must wait for more data */
2125 c->state = HTTPSTATE_WAIT_FEED;
2126 return 1; /* state changed */
2effd274 2127 } else {
3b371676
BC
2128 if (c->stream->loop) {
2129 av_close_input_file(c->fmt_in);
2130 c->fmt_in = NULL;
2131 if (open_input_stream(c, "") < 0)
2132 goto no_loop;
2133 goto redo;
2134 } else {
2135 no_loop:
2136 /* must send trailer now because eof or error */
2137 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1bc1cfdd 2138 }
3b371676
BC
2139 }
2140 } else {
084a8912 2141 int source_index = pkt.stream_index;
3b371676
BC
2142 /* update first pts if needed */
2143 if (c->first_pts == AV_NOPTS_VALUE) {
2144 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2145 c->start_time = cur_time;
2146 }
2147 /* send it to the appropriate stream */
2148 if (c->stream->feed) {
2149 /* if coming from a feed, select the right stream */
2150 if (c->switch_pending) {
2151 c->switch_pending = 0;
cde25790 2152 for(i=0;i<c->stream->nb_streams;i++) {
3b371676 2153 if (c->switch_feed_streams[i] == pkt.stream_index)
611c5741 2154 if (pkt.flags & PKT_FLAG_KEY)
3b371676
BC
2155 do_switch_stream(c, i);
2156 if (c->switch_feed_streams[i] >= 0)
2157 c->switch_pending = 1;
cde25790 2158 }
3b371676
BC
2159 }
2160 for(i=0;i<c->stream->nb_streams;i++) {
2161 if (c->feed_streams[i] == pkt.stream_index) {
78728064 2162 AVStream *st = c->fmt_in->streams[source_index];
3b371676 2163 pkt.stream_index = i;
180b7026
BC
2164 if (pkt.flags & PKT_FLAG_KEY &&
2165 (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2166 c->stream->nb_streams == 1))
0332f549
BC
2167 c->got_key_frame = 1;
2168 if (!c->stream->send_on_key || c->got_key_frame)
3b371676
BC
2169 goto send_it;
2170 }
2171 }
2172 } else {
2173 AVCodecContext *codec;
dc3a6a36
BC
2174 AVStream *ist, *ost;
2175 send_it:
2176 ist = c->fmt_in->streams[source_index];
3b371676
BC
2177 /* specific handling for RTP: we use several
2178 output stream (one for each RTP
2179 connection). XXX: need more abstract handling */
2180 if (c->is_packetized) {
3b371676 2181 /* compute send time and duration */
8f56ccca
BC
2182 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2183 if (ist->start_time != AV_NOPTS_VALUE)
2184 c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2185 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
e240a0bb 2186#if 0
3b371676
BC
2187 printf("index=%d pts=%0.3f duration=%0.6f\n",
2188 pkt.stream_index,
2189 (double)c->cur_pts /
2190 AV_TIME_BASE,
2191 (double)c->cur_frame_duration /
2192 AV_TIME_BASE);
e240a0bb 2193#endif
3b371676
BC
2194 /* find RTP context */
2195 c->packet_stream_index = pkt.stream_index;
2196 ctx = c->rtp_ctx[c->packet_stream_index];
2197 if(!ctx) {
8a0b55ff 2198 av_free_packet(&pkt);
3b371676 2199 break;
8a0b55ff 2200 }
3b371676
BC
2201 codec = ctx->streams[0]->codec;
2202 /* only one stream per RTP connection */
2203 pkt.stream_index = 0;
2204 } else {
2205 ctx = &c->fmt_ctx;
2206 /* Fudge here */
3ab29d8e 2207 codec = ctx->streams[pkt.stream_index]->codec;
3b371676
BC
2208 }
2209
2210 if (c->is_packetized) {
2211 int max_packet_size;
90abbdba 2212 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
3b371676
BC
2213 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2214 else
2215 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2216 ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2217 } else {
2218 ret = url_open_dyn_buf(&ctx->pb);
2219 }
2220 if (ret < 0) {
2221 /* XXX: potential leak */
2222 return -1;
2223 }
3ab29d8e
BC
2224 ost = ctx->streams[pkt.stream_index];
2225
b0675954 2226 ctx->pb->is_streamed = 1;
3b371676 2227 if (pkt.dts != AV_NOPTS_VALUE)
d80904cc 2228 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
3b371676 2229 if (pkt.pts != AV_NOPTS_VALUE)
d80904cc
BC
2230 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2231 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
3766ed72
BC
2232 if (av_write_frame(ctx, &pkt) < 0) {
2233 http_log("Error writing frame to output\n");
3b371676 2234 c->state = HTTPSTATE_SEND_DATA_TRAILER;
3766ed72 2235 }
3b371676
BC
2236
2237 len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2238 c->cur_frame_bytes = len;
2239 c->buffer_ptr = c->pb_buffer;
2240 c->buffer_end = c->pb_buffer + len;
2241
2242 codec->frame_number++;
2243 if (len == 0) {
2244 av_free_packet(&pkt);
2245 goto redo;
f747e6d3 2246 }
85f07f22 2247 }
3b371676 2248 av_free_packet(&pkt);
85f07f22 2249 }
3b371676 2250 }
85f07f22
FB
2251 break;
2252 default:
2253 case HTTPSTATE_SEND_DATA_TRAILER:
2254 /* last packet test ? */
2effd274 2255 if (c->last_packet_sent || c->is_packetized)
85f07f22 2256 return -1;
2effd274 2257 ctx = &c->fmt_ctx;
85f07f22 2258 /* prepare header */
2effd274
FB
2259 if (url_open_dyn_buf(&ctx->pb) < 0) {
2260 /* XXX: potential leak */
2261 return -1;
2262 }
58bd615f 2263 c->fmt_ctx.pb->is_streamed = 1;
2effd274 2264 av_write_trailer(ctx);
899681cd 2265 len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2effd274
FB
2266 c->buffer_ptr = c->pb_buffer;
2267 c->buffer_end = c->pb_buffer + len;
2268
85f07f22
FB
2269 c->last_packet_sent = 1;
2270 break;
2271 }
2272 return 0;
2273}
2274
2275/* should convert the format at the same time */
bc351386
FB
2276/* send data starting at c->buffer_ptr to the output connection
2277 (either UDP or TCP connection) */
5eb765ef 2278static int http_send_data(HTTPContext *c)
85f07f22 2279{
e240a0bb 2280 int len, ret;
85f07f22 2281
bc351386
FB
2282 for(;;) {
2283 if (c->buffer_ptr >= c->buffer_end) {
2284 ret = http_prepare_data(c);
2285 if (ret < 0)
2286 return -1;
611c5741 2287 else if (ret != 0)
bc351386
FB
2288 /* state change requested */
2289 break;
2effd274 2290 } else {
bc351386
FB
2291 if (c->is_packetized) {
2292 /* RTP data output */
2293 len = c->buffer_end - c->buffer_ptr;
2294 if (len < 4) {
2295 /* fail safe - should never happen */
2296 fail1:
2297 c->buffer_ptr = c->buffer_end;
2effd274
FB
2298 return 0;
2299 }
bc351386
FB
2300 len = (c->buffer_ptr[0] << 24) |
2301 (c->buffer_ptr[1] << 16) |
2302 (c->buffer_ptr[2] << 8) |
2303 (c->buffer_ptr[3]);
2304 if (len > (c->buffer_end - c->buffer_ptr))
2305 goto fail1;
e240a0bb
FB
2306 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2307 /* nothing to send yet: we can wait */
2308 return 0;
2309 }
2310
2311 c->data_count += len;
2312 update_datarate(&c->datarate, c->data_count);
2313 if (c->stream)
2314 c->stream->bytes_served += len;
2315
90abbdba 2316 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
bc351386 2317 /* RTP packets are sent inside the RTSP TCP connection */
899681cd 2318 ByteIOContext *pb;
bc351386
FB
2319 int interleaved_index, size;
2320 uint8_t header[4];
2321 HTTPContext *rtsp_c;
115329f1 2322
bc351386
FB
2323 rtsp_c = c->rtsp_c;
2324 /* if no RTSP connection left, error */
2325 if (!rtsp_c)
2326 return -1;
2327 /* if already sending something, then wait. */
611c5741 2328 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
bc351386 2329 break;
899681cd 2330 if (url_open_dyn_buf(&pb) < 0)
bc351386
FB
2331 goto fail1;
2332 interleaved_index = c->packet_stream_index * 2;
2333 /* RTCP packets are sent at odd indexes */
2334 if (c->buffer_ptr[1] == 200)
2335 interleaved_index++;
2336 /* write RTSP TCP header */
2337 header[0] = '$';
2338 header[1] = interleaved_index;
2339 header[2] = len >> 8;
2340 header[3] = len;
2341 put_buffer(pb, header, 4);
2342 /* write RTP packet data */
2343 c->buffer_ptr += 4;
2344 put_buffer(pb, c->buffer_ptr, len);
2345 size = url_close_dyn_buf(pb, &c->packet_buffer);
2346 /* prepare asynchronous TCP sending */
2347 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2348 rtsp_c->packet_buffer_end = c->packet_buffer + size;
e240a0bb 2349 c->buffer_ptr += len;
115329f1 2350
e240a0bb 2351 /* send everything we can NOW */
c60202df
AB
2352 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2353 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
611c5741 2354 if (len > 0)
e240a0bb 2355 rtsp_c->packet_buffer_ptr += len;
e240a0bb
FB
2356 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2357 /* if we could not send all the data, we will
2358 send it later, so a new state is needed to
2359 "lock" the RTSP TCP connection */
2360 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2361 break;
611c5741 2362 } else
e240a0bb
FB
2363 /* all data has been sent */
2364 av_freep(&c->packet_buffer);
e240a0bb
FB
2365 } else {
2366 /* send RTP packet directly in UDP */
bc351386 2367 c->buffer_ptr += 4;
115329f1 2368 url_write(c->rtp_handles[c->packet_stream_index],
bc351386 2369 c->buffer_ptr, len);
e240a0bb
FB
2370 c->buffer_ptr += len;
2371 /* here we continue as we can send several packets per 10 ms slot */
bc351386 2372 }
bc351386
FB
2373 } else {
2374 /* TCP data output */
c60202df 2375 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
bc351386 2376 if (len < 0) {
8da4034f 2377 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
611c5741 2378 ff_neterrno() != FF_NETERROR(EINTR))
bc351386
FB
2379 /* error : close connection */
2380 return -1;
611c5741 2381 else
bc351386 2382 return 0;
611c5741 2383 } else
bc351386 2384 c->buffer_ptr += len;
611c5741 2385
e240a0bb
FB
2386 c->data_count += len;
2387 update_datarate(&c->datarate, c->data_count);
2388 if (c->stream)
2389 c->stream->bytes_served += len;
2390 break;
2effd274 2391 }
85f07f22 2392 }
bc351386 2393 } /* for(;;) */
85f07f22
FB
2394 return 0;
2395}
2396
2397static int http_start_receive_data(HTTPContext *c)
2398{
2399 int fd;
2400
2401 if (c->stream->feed_opened)
2402 return -1;
2403
e322ea48
PG
2404 /* Don't permit writing to this one */
2405 if (c->stream->readonly)
2406 return -1;
2407
85f07f22
FB
2408 /* open feed */
2409 fd = open(c->stream->feed_filename, O_RDWR);
929a9b75
BC
2410 if (fd < 0) {
2411 http_log("Error opening feeder file: %s\n", strerror(errno));
85f07f22 2412 return -1;
929a9b75 2413 }
85f07f22 2414 c->feed_fd = fd;
115329f1 2415
85f07f22
FB
2416 c->stream->feed_write_index = ffm_read_write_index(fd);
2417 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2418 lseek(fd, 0, SEEK_SET);
2419
2420 /* init buffer input */
2421 c->buffer_ptr = c->buffer;
2422 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2423 c->stream->feed_opened = 1;
2424 return 0;
2425}
115329f1 2426
85f07f22
FB
2427static int http_receive_data(HTTPContext *c)
2428{
85f07f22
FB
2429 HTTPContext *c1;
2430
a6e14edd
PG
2431 if (c->buffer_end > c->buffer_ptr) {
2432 int len;
2433
c60202df 2434 len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
a6e14edd 2435 if (len < 0) {
8da4034f 2436 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
611c5741 2437 ff_neterrno() != FF_NETERROR(EINTR))
a6e14edd
PG
2438 /* error : close connection */
2439 goto fail;
611c5741 2440 } else if (len == 0)
a6e14edd
PG
2441 /* end of connection : close it */
2442 goto fail;
611c5741 2443 else {
a6e14edd
PG
2444 c->buffer_ptr += len;
2445 c->data_count += len;
5eb765ef 2446 update_datarate(&c->datarate, c->data_count);
a6e14edd
PG
2447 }
2448 }
2449
d445a7e9
PG
2450 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2451 if (c->buffer[0] != 'f' ||
2452 c->buffer[1] != 'm') {
2453 http_log("Feed stream has become desynchronized -- disconnecting\n");
2454 goto fail;
2455 }
2456 }
2457
85f07f22 2458 if (c->buffer_ptr >= c->buffer_end) {
f747e6d3 2459 FFStream *feed = c->stream;
85f07f22
FB
2460 /* a packet has been received : write it in the store, except
2461 if header */
2462 if (c->data_count > FFM_PACKET_SIZE) {
115329f1 2463
949b1a13 2464 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
85f07f22
FB
2465 /* XXX: use llseek or url_seek */
2466 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
929a9b75
BC
2467 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2468 http_log("Error writing to feed file: %s\n", strerror(errno));
2469 goto fail;
2470 }
115329f1 2471
85f07f22
FB
2472 feed->feed_write_index += FFM_PACKET_SIZE;
2473 /* update file size */
2474 if (feed->feed_write_index > c->stream->feed_size)
2475 feed->feed_size = feed->feed_write_index;
2476
2477 /* handle wrap around if max file size reached */
6b0bdc75 2478 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
85f07f22
FB
2479 feed->feed_write_index = FFM_PACKET_SIZE;
2480
2481 /* write index */
2482 ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2483
2484 /* wake up any waiting connections */
2485 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
115329f1 2486 if (c1->state == HTTPSTATE_WAIT_FEED &&
611c5741 2487 c1->stream->feed == c->stream->feed)
85f07f22 2488 c1->state = HTTPSTATE_SEND_DATA;
85f07f22 2489 }
f747e6d3
PG
2490 } else {
2491 /* We have a header in our hands that contains useful data */
f2972c8c
BC
2492 AVFormatContext *s = NULL;
2493 ByteIOContext *pb;
bd7cf6ad 2494 AVInputFormat *fmt_in;
f747e6d3
PG
2495 int i;
2496
bd7cf6ad
FB
2497 /* use feed output format name to find corresponding input format */
2498 fmt_in = av_find_input_format(feed->fmt->name);
2499 if (!fmt_in)
2500 goto fail;
2501
697efa36
BC
2502 url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2503 pb->is_streamed = 1;
2504
e6f0deab
BC
2505 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2506 av_free(pb);
2507 goto fail;
2508 }
f747e6d3
PG
2509
2510 /* Now we have the actual streams */
f2972c8c
BC
2511 if (s->nb_streams != feed->nb_streams) {
2512 av_close_input_stream(s);
86771c68 2513 av_free(pb);
f747e6d3
PG
2514 goto fail;
2515 }
f2972c8c 2516
cb51aef1
BC
2517 for (i = 0; i < s->nb_streams; i++) {
2518 AVStream *fst = feed->streams[i];
2519 AVStream *st = s->streams[i];
2520 memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2521 if (fst->codec->extradata_size) {
2522 fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2523 if (!fst->codec->extradata)
2524 goto fail;
2525 memcpy(fst->codec->extradata, st->codec->extradata,
2526 fst->codec->extradata_size);
2527 }
2528 }
f2972c8c
BC
2529
2530 av_close_input_stream(s);
86771c68 2531 av_free(pb);
85f07f22
FB
2532 }
2533 c->buffer_ptr = c->buffer;
2534 }
2535
85f07f22
FB
2536 return 0;
2537 fail:
2538 c->stream->feed_opened = 0;
2539 close(c->feed_fd);
c1593d0e
BC
2540 /* wake up any waiting connections to stop waiting for feed */
2541 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2542 if (c1->state == HTTPSTATE_WAIT_FEED &&
2543 c1->stream->feed == c->stream->feed)
2544 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2545 }
85f07f22
FB
2546 return -1;
2547}
2548
2effd274
FB
2549/********************************************************************/
2550/* RTSP handling */
2551
2552static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2553{
2554 const char *str;
2555 time_t ti;
2556 char *p;
2557 char buf2[32];
2558
2559 switch(error_number) {
7e665cd3
LA
2560 case RTSP_STATUS_OK:
2561 str = "OK";
2562 break;
2563 case RTSP_STATUS_METHOD:
2564 str = "Method Not Allowed";
2565 break;
2566 case RTSP_STATUS_BANDWIDTH:
2567 str = "Not Enough Bandwidth";
2568 break;
2569 case RTSP_STATUS_SESSION:
2570 str = "Session Not Found";
2571 break;
2572 case RTSP_STATUS_STATE:
2573 str = "Method Not Valid in This State";
2574 break;
2575 case RTSP_STATUS_AGGREGATE:
2576 str = "Aggregate operation not allowed";
2577 break;
2578 case RTSP_STATUS_ONLY_AGGREGATE:
2579 str = "Only aggregate operation allowed";
2580 break;
2581 case RTSP_STATUS_TRANSPORT:
2582 str = "Unsupported transport";
2583 break;
2584 case RTSP_STATUS_INTERNAL:
2585 str = "Internal Server Error";
2586 break;
2587 case RTSP_STATUS_SERVICE:
2588 str = "Service Unavailable";
2589 break;
2590 case RTSP_STATUS_VERSION:
2591 str = "RTSP Version not supported";
2592 break;
2effd274
FB
2593 default:
2594 str = "Unknown Error";
2595 break;
2596 }
115329f1 2597
2effd274
FB
2598 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2599 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2600
2601 /* output GMT time */
2602 ti = time(NULL);
2603 p = ctime(&ti);
2604 strcpy(buf2, p);
2605 p = buf2 + strlen(p) - 1;
2606 if (*p == '\n')
2607 *p = '\0';
2608 url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2609}
2610
2611static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2612{
2613 rtsp_reply_header(c, error_number);
2614 url_fprintf(c->pb, "\r\n");
2615}
2616
2617static int rtsp_parse_request(HTTPContext *c)
2618{
2619 const char *p, *p1, *p2;
2620 char cmd[32];
2621 char url[1024];
2622 char protocol[32];
2623 char line[1024];
2effd274
FB
2624 int len;
2625 RTSPHeader header1, *header = &header1;
115329f1 2626
2effd274
FB
2627 c->buffer_ptr[0] = '\0';
2628 p = c->buffer;
115329f1 2629
2effd274
FB
2630 get_word(cmd, sizeof(cmd), &p);
2631 get_word(url, sizeof(url), &p);
2632 get_word(protocol, sizeof(protocol), &p);
2633
f7d78f36
MR
2634 av_strlcpy(c->method, cmd, sizeof(c->method));
2635 av_strlcpy(c->url, url, sizeof(c->url));
2636 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2effd274 2637
899681cd 2638 if (url_open_dyn_buf(&c->pb) < 0) {
2effd274
FB
2639 /* XXX: cannot do more */
2640 c->pb = NULL; /* safety */
2641 return -1;
2642 }
2643
2644 /* check version name */
2645 if (strcmp(protocol, "RTSP/1.0") != 0) {
2646 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2647 goto the_end;
2648 }
2649
2650 /* parse each header line */
2651 memset(header, 0, sizeof(RTSPHeader));
2652 /* skip to next line */
2653 while (*p != '\n' && *p != '\0')
2654 p++;
2655 if (*p == '\n')
2656 p++;
2657 while (*p != '\0') {
2658 p1 = strchr(p, '\n');
2659 if (!p1)
2660 break;
2661 p2 = p1;
2662 if (p2 > p && p2[-1] == '\r')
2663 p2--;
2664 /* skip empty line */
2665 if (p2 == p)
2666 break;
2667 len = p2 - p;
2668 if (len > sizeof(line) - 1)
2669 len = sizeof(line) - 1;
2670 memcpy(line, p, len);
2671 line[len] = '\0';
2672 rtsp_parse_line(header, line);
2673 p = p1 + 1;
2674 }
2675
2676 /* handle sequence number */
2677 c->seq = header->seq;
2678
611c5741 2679 if (!strcmp(cmd, "DESCRIBE"))
2effd274 2680 rtsp_cmd_describe(c, url);
611c5741 2681 else if (!strcmp(cmd, "OPTIONS"))
0df65975 2682 rtsp_cmd_options(c, url);
611c5741 2683 else if (!strcmp(cmd, "SETUP"))
2effd274 2684 rtsp_cmd_setup(c, url, header);
611c5741 2685 else if (!strcmp(cmd, "PLAY"))
2effd274 2686 rtsp_cmd_play(c, url, header);
611c5741 2687 else if (!strcmp(cmd, "PAUSE"))
2effd274 2688 rtsp_cmd_pause(c, url, header);
611c5741 2689 else if (!strcmp(cmd, "TEARDOWN"))
2effd274 2690 rtsp_cmd_teardown(c, url, header);
611c5741 2691 else
2effd274 2692 rtsp_reply_error(c, RTSP_STATUS_METHOD);
611c5741 2693
2effd274
FB
2694 the_end:
2695 len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2696 c->pb = NULL; /* safety */
2697 if (len < 0) {
2698 /* XXX: cannot do more */
2699 return -1;
2700 }
2701 c->buffer_ptr = c->pb_buffer;
2702 c->buffer_end = c->pb_buffer + len;
2703 c->state = RTSPSTATE_SEND_REPLY;
2704 return 0;
2705}
2706
115329f1 2707static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d 2708 struct in_addr my_ip)
2effd274 2709{
dd723472
LA
2710 AVFormatContext *avc;
2711 AVStream avs[MAX_STREAMS];
2712 int i;
115329f1 2713
8e2fd8e1 2714 avc = avformat_alloc_context();
dd723472 2715 if (avc == NULL) {
2effd274 2716 return -1;
dd723472
LA
2717 }
2718 if (stream->title[0] != 0) {
2719 av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2720 } else {
2721 av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2722 }
2723 avc->nb_streams = stream->nb_streams;
2724 if (stream->is_multicast) {
2725 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2726 inet_ntoa(stream->multicast_ip),
2727 stream->multicast_port, stream->multicast_ttl);
2728 }
115329f1 2729
2effd274 2730 for(i = 0; i < stream->nb_streams; i++) {
dd723472
LA
2731 avc->streams[i] = &avs[i];
2732 avc->streams[i]->codec = stream->streams[i]->codec;
2effd274 2733 }
dd723472
LA
2734 *pbuffer = av_mallocz(2048);
2735 avf_sdp_create(&avc, 1, *pbuffer, 2048);
2736 av_free(avc);
2737
2738 return strlen(*pbuffer);
2effd274
FB
2739}
2740
0df65975
AR
2741static void rtsp_cmd_options(HTTPContext *c, const char *url)
2742{
2743// rtsp_reply_header(c, RTSP_STATUS_OK);
2744 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2745 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2746 url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2747 url_fprintf(c->pb, "\r\n");
2748}
2749
2effd274
FB
2750static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2751{
2752 FFStream *stream;
2753 char path1[1024];
2754 const char *path;
0c1a9eda 2755 uint8_t *content;
829ac53d
FB
2756 int content_length, len;
2757 struct sockaddr_in my_addr;
115329f1 2758
2effd274 2759 /* find which url is asked */
6ba5cbc6 2760 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2761 path = path1;
2762 if (*path == '/')
2763 path++;
2764
2765 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
2766 if (!stream->is_feed &&
2767 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2effd274
FB
2768 !strcmp(path, stream->filename)) {
2769 goto found;
2770 }
2771 }
2772 /* no stream found */
2773 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2774 return;
2775
2776 found:
2777 /* prepare the media description in sdp format */
829ac53d
FB
2778
2779 /* get the host IP */
2780 len = sizeof(my_addr);
2781 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
829ac53d 2782 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2effd274
FB
2783 if (content_length < 0) {
2784 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2785 return;
2786 }
2787 rtsp_reply_header(c, RTSP_STATUS_OK);
2788 url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2789 url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2790 url_fprintf(c->pb, "\r\n");
2791 put_buffer(c->pb, content, content_length);
2792}
2793
2794static HTTPContext *find_rtp_session(const char *session_id)
2795{
2796 HTTPContext *c;
2797
2798 if (session_id[0] == '\0')
2799 return NULL;
2800
2801 for(c = first_http_ctx; c != NULL; c = c->next) {
2802 if (!strcmp(c->session_id, session_id))
2803 return c;
2804 }
2805 return NULL;
2806}
2807
90abbdba 2808static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPLowerTransport lower_transport)
2effd274
FB
2809{
2810 RTSPTransportField *th;
2811 int i;
2812
2813 for(i=0;i<h->nb_transports;i++) {
2814 th = &h->transports[i];
90abbdba 2815 if (th->lower_transport == lower_transport)
2effd274
FB
2816 return th;
2817 }
2818 return NULL;
2819}
2820
115329f1 2821static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2effd274
FB
2822 RTSPHeader *h)
2823{
2824 FFStream *stream;
2825 int stream_index, port;
2826 char buf[1024];
2827 char path1[1024];
2828 const char *path;
2829 HTTPContext *rtp_c;
2830 RTSPTransportField *th;
2831 struct sockaddr_in dest_addr;
2832 RTSPActionServerSetup setup;
115329f1 2833
2effd274 2834 /* find which url is asked */
6ba5cbc6 2835 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2836 path = path1;
2837 if (*path == '/')
2838 path++;
2839
2840 /* now check each stream */
2841 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
2842 if (!stream->is_feed &&
2843 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2effd274
FB
2844 /* accept aggregate filenames only if single stream */
2845 if (!strcmp(path, stream->filename)) {
2846 if (stream->nb_streams != 1) {
2847 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2848 return;
2849 }
2850 stream_index = 0;
2851 goto found;
2852 }
115329f1 2853
2effd274
FB
2854 for(stream_index = 0; stream_index < stream->nb_streams;
2855 stream_index++) {
115329f1 2856 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2effd274
FB
2857 stream->filename, stream_index);
2858 if (!strcmp(path, buf))
2859 goto found;
2860 }
2861 }
2862 }
2863 /* no stream found */
2864 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2865 return;
2866 found:
2867
2868 /* generate session id if needed */
611c5741 2869 if (h->session_id[0] == '\0')
1df93ae9
AB
2870 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2871 av_random(&random_state), av_random(&random_state));
2effd274
FB
2872
2873 /* find rtp session, and create it if none found */
2874 rtp_c = find_rtp_session(h->session_id);
2875 if (!rtp_c) {
bc351386 2876 /* always prefer UDP */
90abbdba 2877 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
bc351386 2878 if (!th) {
90abbdba 2879 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
bc351386
FB
2880 if (!th) {
2881 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2882 return;
2883 }
2884 }
2885
2886 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
90abbdba 2887 th->lower_transport);
2effd274
FB
2888 if (!rtp_c) {
2889 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2890 return;
2891 }
2892
2893 /* open input stream */
2894 if (open_input_stream(rtp_c, "") < 0) {
2895 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2896 return;
2897 }
2effd274 2898 }
115329f1 2899
2effd274
FB
2900 /* test if stream is OK (test needed because several SETUP needs
2901 to be done for a given file) */
2902 if (rtp_c->stream != stream) {
2903 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2904 return;
2905 }
115329f1 2906
2effd274
FB
2907 /* test if stream is already set up */
2908 if (rtp_c->rtp_ctx[stream_index]) {
2909 rtsp_reply_error(c, RTSP_STATUS_STATE);
2910 return;
2911 }
2912
2913 /* check transport */
2914 th = find_transport(h, rtp_c->rtp_protocol);
90abbdba 2915 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2effd274
FB
2916 th->client_port_min <= 0)) {
2917 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2918 return;
2919 }
2920
2921 /* setup default options */
2922 setup.transport_option[0] = '\0';
2923 dest_addr = rtp_c->from_addr;
2924 dest_addr.sin_port = htons(th->client_port_min);
115329f1 2925
2effd274 2926 /* setup stream */
bc351386 2927 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2effd274
FB
2928 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2929 return;
2930 }
2931
2932 /* now everything is OK, so we can send the connection parameters */
2933 rtsp_reply_header(c, RTSP_STATUS_OK);
2934 /* session ID */
2935 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2936
2937 switch(rtp_c->rtp_protocol) {
90abbdba 2938 case RTSP_LOWER_TRANSPORT_UDP:
2effd274
FB
2939 port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2940 url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2941 "client_port=%d-%d;server_port=%d-%d",
2942 th->client_port_min, th->client_port_min + 1,
2943 port, port + 1);
2944 break;
90abbdba 2945 case RTSP_LOWER_TRANSPORT_TCP:
2effd274
FB
2946 url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2947 stream_index * 2, stream_index * 2 + 1);
2948 break;
2949 default:
2950 break;
2951 }
611c5741 2952 if (setup.transport_option[0] != '\0')
2effd274 2953 url_fprintf(c->pb, ";%s", setup.transport_option);
2effd274 2954 url_fprintf(c->pb, "\r\n");
115329f1 2955
2effd274
FB
2956
2957 url_fprintf(c->pb, "\r\n");
2958}
2959
2960
2961/* find an rtp connection by using the session ID. Check consistency
2962 with filename */
115329f1 2963static HTTPContext *find_rtp_session_with_url(const char *url,
2effd274
FB
2964 const char *session_id)
2965{
2966 HTTPContext *rtp_c;
2967 char path1[1024];
2968 const char *path;
94d9ad5f
GF
2969 char buf[1024];
2970 int s;
2effd274
FB
2971
2972 rtp_c = find_rtp_session(session_id);
2973 if (!rtp_c)
2974 return NULL;
2975
2976 /* find which url is asked */
6ba5cbc6 2977 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2978 path = path1;
2979 if (*path == '/')
2980 path++;
94d9ad5f
GF
2981 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2982 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2983 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2984 rtp_c->stream->filename, s);
2985 if(!strncmp(path, buf, sizeof(buf))) {
2986 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2987 return rtp_c;
2988 }
2989 }
2990 return NULL;
2effd274
FB
2991}
2992
2993static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2994{
2995 HTTPContext *rtp_c;
2996
2997 rtp_c = find_rtp_session_with_url(url, h->session_id);
2998 if (!rtp_c) {
2999 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3000 return;
3001 }
115329f1 3002
2effd274
FB
3003 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3004 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3005 rtp_c->state != HTTPSTATE_READY) {
3006 rtsp_reply_error(c, RTSP_STATUS_STATE);
3007 return;
3008 }
3009
e240a0bb
FB
3010#if 0
3011 /* XXX: seek in stream */
3012 if (h->range_start != AV_NOPTS_VALUE) {
3013 printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3014 av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3015 }
3016#endif
3017
2effd274 3018 rtp_c->state = HTTPSTATE_SEND_DATA;
115329f1 3019
2effd274
FB
3020 /* now everything is OK, so we can send the connection parameters */
3021 rtsp_reply_header(c, RTSP_STATUS_OK);
3022 /* session ID */
3023 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3024 url_fprintf(c->pb, "\r\n");
3025}
3026
3027static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3028{
3029 HTTPContext *rtp_c;
3030
3031 rtp_c = find_rtp_session_with_url(url, h->session_id);
3032 if (!rtp_c) {
3033 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3034 return;
3035 }
115329f1 3036
2effd274
FB
3037 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3038 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3039 rtsp_reply_error(c, RTSP_STATUS_STATE);
3040 return;
3041 }
115329f1 3042
2effd274 3043 rtp_c->state = HTTPSTATE_READY;
1bc1cfdd 3044 rtp_c->first_pts = AV_NOPTS_VALUE;
2effd274
FB
3045 /* now everything is OK, so we can send the connection parameters */
3046 rtsp_reply_header(c, RTSP_STATUS_OK);
3047 /* session ID */
3048 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3049 url_fprintf(c->pb, "\r\n");
3050}
3051
3052static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3053{
3054 HTTPContext *rtp_c;
b0b2faa7 3055 char session_id[32];
2effd274
FB
3056
3057 rtp_c = find_rtp_session_with_url(url, h->session_id);
3058 if (!rtp_c) {
3059 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3060 return;
3061 }
115329f1 3062
f7d78f36 3063 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
b0b2faa7 3064
2effd274
FB
3065 /* abort the session */
3066 close_connection(rtp_c);
3067
2effd274
FB
3068 /* now everything is OK, so we can send the connection parameters */
3069 rtsp_reply_header(c, RTSP_STATUS_OK);
3070 /* session ID */
b0b2faa7 3071 url_fprintf(c->pb, "Session: %s\r\n", session_id);
2effd274
FB
3072 url_fprintf(c->pb, "\r\n");
3073}
3074
3075
3076/********************************************************************/
3077/* RTP handling */
3078
115329f1 3079static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386 3080 FFStream *stream, const char *session_id,
90abbdba 3081 enum RTSPLowerTransport rtp_protocol)
2effd274
FB
3082{
3083 HTTPContext *c = NULL;
bc351386 3084 const char *proto_str;
115329f1 3085
2effd274
FB
3086 /* XXX: should output a warning page when coming
3087 close to the connection limit */
3088 if (nb_connections >= nb_max_connections)
3089 goto fail;
115329f1 3090
2effd274
FB
3091 /* add a new connection */
3092 c = av_mallocz(sizeof(HTTPContext));
3093 if (!c)
3094 goto fail;
115329f1 3095
2effd274
FB
3096 c->fd = -1;
3097 c->poll_entry = NULL;
6edd6884 3098 c->from_addr = *from_addr;
2effd274
FB
3099 c->buffer_size = IOBUFFER_INIT_SIZE;
3100 c->buffer = av_malloc(c->buffer_size);
3101 if (!c->buffer)
3102 goto fail;
3103 nb_connections++;
3104 c->stream = stream;
f7d78f36 3105 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
2effd274
FB
3106 c->state = HTTPSTATE_READY;
3107 c->is_packetized = 1;
bc351386
FB
3108 c->rtp_protocol = rtp_protocol;
3109
2effd274 3110 /* protocol is shown in statistics */
bc351386 3111 switch(c->rtp_protocol) {
90abbdba 3112 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
bc351386
FB
3113 proto_str = "MCAST";
3114 break;
90abbdba 3115 case RTSP_LOWER_TRANSPORT_UDP:
bc351386
FB
3116 proto_str = "UDP";
3117 break;
90abbdba 3118 case RTSP_LOWER_TRANSPORT_TCP:
bc351386
FB
3119 proto_str = "TCP";
3120 break;
3121 default:
3122 proto_str = "???";
3123 break;
3124 }
f7d78f36
MR
3125 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3126 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
2effd274 3127
6edd6884
FB
3128 current_bandwidth += stream->bandwidth;
3129
2effd274
FB
3130 c->next = first_http_ctx;
3131 first_http_ctx = c;
3132 return c;
115329f1 3133
2effd274
FB
3134 fail:
3135 if (c) {
3136 av_free(c->buffer);
3137 av_free(c);
3138 }
3139 return NULL;
3140}
3141
3142/* add a new RTP stream in an RTP connection (used in RTSP SETUP
bc351386 3143 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
2effd274 3144 used. */
115329f1 3145static int rtp_new_av_stream(HTTPContext *c,
bc351386
FB
3146 int stream_index, struct sockaddr_in *dest_addr,
3147 HTTPContext *rtsp_c)
2effd274
FB
3148{
3149 AVFormatContext *ctx;
3150 AVStream *st;
3151 char *ipaddr;
75480e86 3152 URLContext *h = NULL;
0c1a9eda 3153 uint8_t *dummy_buf;
bc351386 3154 int max_packet_size;
115329f1 3155
2effd274 3156 /* now we can open the relevant output stream */
8e2fd8e1 3157 ctx = avformat_alloc_context();
2effd274
FB
3158 if (!ctx)
3159 return -1;
b156b88c 3160 ctx->oformat = guess_format("rtp", NULL, NULL);
2effd274
FB
3161
3162 st = av_mallocz(sizeof(AVStream));
3163 if (!st)
3164 goto fail;
8d931070 3165 st->codec= avcodec_alloc_context();
2effd274
FB
3166 ctx->nb_streams = 1;
3167 ctx->streams[0] = st;
3168
115329f1 3169 if (!c->stream->feed ||
611c5741 3170 c->stream->feed == c->stream)
2effd274 3171 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
611c5741 3172 else
115329f1 3173 memcpy(st,
2effd274
FB
3174 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3175 sizeof(AVStream));
57dbe08b 3176 st->priv_data = NULL;
115329f1 3177
bc351386
FB
3178 /* build destination RTP address */
3179 ipaddr = inet_ntoa(dest_addr->sin_addr);
3180
3181 switch(c->rtp_protocol) {
90abbdba
RB
3182 case RTSP_LOWER_TRANSPORT_UDP:
3183 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
bc351386 3184 /* RTP/UDP case */
115329f1 3185
6edd6884
FB
3186 /* XXX: also pass as parameter to function ? */
3187 if (c->stream->is_multicast) {
3188 int ttl;
3189 ttl = c->stream->multicast_ttl;
3190 if (!ttl)
3191 ttl = 16;
3192 snprintf(ctx->filename, sizeof(ctx->filename),
115329f1 3193 "rtp://%s:%d?multicast=1&ttl=%d",
6edd6884
FB
3194 ipaddr, ntohs(dest_addr->sin_port), ttl);
3195 } else {
3196 snprintf(ctx->filename, sizeof(ctx->filename),
3197 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3198 }
2effd274
FB
3199
3200 if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3201 goto fail;
3202 c->rtp_handles[stream_index] = h;
bc351386
FB
3203 max_packet_size = url_get_max_packet_size(h);
3204 break;
90abbdba 3205 case RTSP_LOWER_TRANSPORT_TCP:
bc351386
FB
3206 /* RTP/TCP case */
3207 c->rtsp_c = rtsp_c;
3208 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3209 break;
3210 default:
2effd274
FB
3211 goto fail;
3212 }
3213
e21ac209 3214 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
115329f1 3215 ipaddr, ntohs(dest_addr->sin_port),
bc351386 3216 c->stream->filename, stream_index, c->protocol);
6edd6884 3217
2effd274 3218 /* normally, no packets should be output here, but the packet size may be checked */
bc351386 3219 if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
2effd274
FB
3220 /* XXX: close stream */
3221 goto fail;
3222 }
3c27199b 3223 av_set_parameters(ctx, NULL);
2effd274
FB
3224 if (av_write_header(ctx) < 0) {
3225 fail:
3226 if (h)
3227 url_close(h);
3228 av_free(ctx);
3229 return -1;
3230 }
899681cd 3231 url_close_dyn_buf(ctx->pb, &dummy_buf);
2effd274 3232 av_free(dummy_buf);
115329f1 3233
2effd274
FB
3234 c->rtp_ctx[stream_index] = ctx;
3235 return 0;
3236}
3237
3238/********************************************************************/
3239/* ffserver initialization */
3240
b29f97d1 3241static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
2effd274
FB
3242{
3243 AVStream *fst;
3244
3245 fst = av_mallocz(sizeof(AVStream));
3246 if (!fst)
3247 return NULL;
8d931070 3248 fst->codec= avcodec_alloc_context();
2effd274 3249 fst->priv_data = av_mallocz(sizeof(FeedData));
01f4895c 3250 memcpy(fst->codec, codec, sizeof(AVCodecContext));
d445a7e9 3251 fst->index = stream->nb_streams;
7c054ea7 3252 av_set_pts_info(fst, 33, 1, 90000);
2effd274
FB
3253 stream->streams[stream->nb_streams++] = fst;
3254 return fst;
3255}
3256
85f07f22 3257/* return the stream number in the feed */
b29f97d1 3258static int add_av_stream(FFStream *feed, AVStream *st)
85f07f22
FB
3259{
3260 AVStream *fst;
3261 AVCodecContext *av, *av1;
3262 int i;
3263
01f4895c 3264 av = st->codec;
85f07f22
FB
3265 for(i=0;i<feed->nb_streams;i++) {
3266 st = feed->streams[i];
01f4895c 3267 av1 = st->codec;
f747e6d3
PG
3268 if (av1->codec_id == av->codec_id &&
3269 av1->codec_type == av->codec_type &&
85f07f22
FB
3270 av1->bit_rate == av->bit_rate) {
3271
3272 switch(av->codec_type) {
3273 case CODEC_TYPE_AUDIO:
3274 if (av1->channels == av->channels &&
3275 av1->sample_rate == av->sample_rate)
3276 goto found;
3277 break;
3278 case CODEC_TYPE_VIDEO:
3279 if (av1->width == av->width &&
3280 av1->height == av->height &&
c0df9d75
MN
3281 av1->time_base.den == av->time_base.den &&
3282 av1->time_base.num == av->time_base.num &&
85f07f22
FB
3283 av1->gop_size == av->gop_size)
3284 goto found;
3285 break;
f747e6d3 3286 default:
0f4e8165 3287 abort();
85f07f22
FB
3288 }
3289 }
3290 }
115329f1 3291
2effd274 3292 fst = add_av_stream1(feed, av);
85f07f22
FB
3293 if (!fst)
3294 return -1;
85f07f22
FB
3295 return feed->nb_streams - 1;
3296 found:
3297 return i;
3298}
3299
b29f97d1 3300static void remove_stream(FFStream *stream)
2effd274
FB
3301{
3302 FFStream **ps;
3303 ps = &first_stream;
3304 while (*ps != NULL) {
611c5741 3305 if (*ps == stream)
2effd274 3306 *ps = (*ps)->next;
611c5741 3307 else
2effd274 3308 ps = &(*ps)->next;
2effd274
FB
3309 }
3310}
3311
0fa45e19 3312/* specific mpeg4 handling : we extract the raw parameters */
b29f97d1 3313static void extract_mpeg4_header(AVFormatContext *infile)
0fa45e19
FB
3314{
3315 int mpeg4_count, i, size;
3316 AVPacket pkt;
3317 AVStream *st;
0c1a9eda 3318 const uint8_t *p;
0fa45e19
FB
3319
3320 mpeg4_count = 0;
3321 for(i=0;i<infile->nb_streams;i++) {
3322 st = infile->streams[i];
01f4895c
MN
3323 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3324 st->codec->extradata_size == 0) {
0fa45e19
FB
3325 mpeg4_count++;
3326 }
3327 }
3328 if (!mpeg4_count)
3329 return;
3330
d445a7e9 3331 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
0fa45e19
FB
3332 while (mpeg4_count > 0) {
3333 if (av_read_packet(infile, &pkt) < 0)
3334 break;
3335 st = infile->streams[pkt.stream_index];
01f4895c
MN
3336 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3337 st->codec->extradata_size == 0) {
3338 av_freep(&st->codec->extradata);
0fa45e19
FB
3339 /* fill extradata with the header */
3340 /* XXX: we make hard suppositions here ! */
3341 p = pkt.data;
3342 while (p < pkt.data + pkt.size - 4) {
3343 /* stop when vop header is found */
115329f1 3344 if (p[0] == 0x00 && p[1] == 0x00 &&
0fa45e19
FB
3345 p[2] == 0x01 && p[3] == 0xb6) {
3346 size = p - pkt.data;
750f0e1f 3347 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
01f4895c
MN
3348 st->codec->extradata = av_malloc(size);
3349 st->codec->extradata_size = size;
3350 memcpy(st->codec->extradata, pkt.data, size);
0fa45e19
FB
3351 break;
3352 }
3353 p++;
3354 }
3355 mpeg4_count--;
3356 }
3357 av_free_packet(&pkt);
3358 }
3359}
3360
2effd274 3361/* compute the needed AVStream for each file */
b29f97d1 3362static void build_file_streams(void)
2effd274
FB
3363{
3364 FFStream *stream, *stream_next;
3365 AVFormatContext *infile;
f61d45c9 3366 int i, ret;
2effd274
FB
3367
3368 /* gather all streams */
3369 for(stream = first_stream; stream != NULL; stream = stream_next) {
3370 stream_next = stream->next;
3371 if (stream->stream_type == STREAM_TYPE_LIVE &&
3372 !stream->feed) {
3373