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