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