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