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