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