Improve bind failure message to indicate the port that failed
[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 char bindmsg[32];
433 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
434 perror (bindmsg);
435 close(server_fd);
436 return -1;
437 }
438
439 if (listen (server_fd, 5) < 0) {
440 perror ("listen");
441 close(server_fd);
442 return -1;
443 }
444 fcntl(server_fd, F_SETFL, O_NONBLOCK);
445
446 return server_fd;
447 }
448
449 /* start all multicast streams */
450 static void start_multicast(void)
451 {
452 FFStream *stream;
453 char session_id[32];
454 HTTPContext *rtp_c;
455 struct sockaddr_in dest_addr;
456 int default_port, stream_index;
457
458 default_port = 6000;
459 for(stream = first_stream; stream != NULL; stream = stream->next) {
460 if (stream->is_multicast) {
461 /* open the RTP connection */
462 snprintf(session_id, sizeof(session_id),
463 "%08x%08x", (int)random(), (int)random());
464
465 /* choose a port if none given */
466 if (stream->multicast_port == 0) {
467 stream->multicast_port = default_port;
468 default_port += 100;
469 }
470
471 dest_addr.sin_family = AF_INET;
472 dest_addr.sin_addr = stream->multicast_ip;
473 dest_addr.sin_port = htons(stream->multicast_port);
474
475 rtp_c = rtp_new_connection(&dest_addr, stream, session_id);
476 if (!rtp_c) {
477 continue;
478 }
479 if (open_input_stream(rtp_c, "") < 0) {
480 fprintf(stderr, "Could not open input stream for stream '%s'\n",
481 stream->filename);
482 continue;
483 }
484
485 rtp_c->rtp_protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
486
487 /* open each RTP stream */
488 for(stream_index = 0; stream_index < stream->nb_streams;
489 stream_index++) {
490 dest_addr.sin_port = htons(stream->multicast_port +
491 2 * stream_index);
492 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
493 fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n",
494 stream->filename, stream_index);
495 exit(1);
496 }
497 }
498
499 /* change state to send data */
500 rtp_c->state = HTTPSTATE_SEND_DATA;
501 }
502 }
503 }
504
505 /* main loop of the http server */
506 static int http_server(void)
507 {
508 int server_fd, ret, rtsp_server_fd, delay, delay1;
509 struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
510 HTTPContext *c, *c_next;
511
512 server_fd = socket_open_listen(&my_http_addr);
513 if (server_fd < 0)
514 return -1;
515
516 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
517 if (rtsp_server_fd < 0)
518 return -1;
519
520 http_log("ffserver started.\n");
521
522 start_children(first_feed);
523
524 first_http_ctx = NULL;
525 nb_connections = 0;
526 first_http_ctx = NULL;
527
528 start_multicast();
529
530 for(;;) {
531 poll_entry = poll_table;
532 poll_entry->fd = server_fd;
533 poll_entry->events = POLLIN;
534 poll_entry++;
535
536 poll_entry->fd = rtsp_server_fd;
537 poll_entry->events = POLLIN;
538 poll_entry++;
539
540 /* wait for events on each HTTP handle */
541 c = first_http_ctx;
542 delay = 1000;
543 while (c != NULL) {
544 int fd;
545 fd = c->fd;
546 switch(c->state) {
547 case HTTPSTATE_SEND_HEADER:
548 case RTSPSTATE_SEND_REPLY:
549 c->poll_entry = poll_entry;
550 poll_entry->fd = fd;
551 poll_entry->events = POLLOUT;
552 poll_entry++;
553 break;
554 case HTTPSTATE_SEND_DATA_HEADER:
555 case HTTPSTATE_SEND_DATA:
556 case HTTPSTATE_SEND_DATA_TRAILER:
557 if (!c->is_packetized) {
558 /* for TCP, we output as much as we can (may need to put a limit) */
559 c->poll_entry = poll_entry;
560 poll_entry->fd = fd;
561 poll_entry->events = POLLOUT;
562 poll_entry++;
563 } else {
564 /* not strictly correct, but currently cannot add
565 more than one fd in poll entry */
566 delay = 0;
567 }
568 break;
569 case HTTPSTATE_WAIT_REQUEST:
570 case HTTPSTATE_RECEIVE_DATA:
571 case HTTPSTATE_WAIT_FEED:
572 case RTSPSTATE_WAIT_REQUEST:
573 /* need to catch errors */
574 c->poll_entry = poll_entry;
575 poll_entry->fd = fd;
576 poll_entry->events = POLLIN;/* Maybe this will work */
577 poll_entry++;
578 break;
579 case HTTPSTATE_WAIT:
580 c->poll_entry = NULL;
581 delay1 = compute_send_delay(c);
582 if (delay1 < delay)
583 delay = delay1;
584 break;
585 case HTTPSTATE_WAIT_SHORT:
586 c->poll_entry = NULL;
587 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
588 if (delay1 < delay)
589 delay = delay1;
590 break;
591 default:
592 c->poll_entry = NULL;
593 break;
594 }
595 c = c->next;
596 }
597
598 /* wait for an event on one connection. We poll at least every
599 second to handle timeouts */
600 do {
601 ret = poll(poll_table, poll_entry - poll_table, delay);
602 } while (ret == -1);
603
604 cur_time = gettime_ms();
605
606 if (need_to_start_children) {
607 need_to_start_children = 0;
608 start_children(first_feed);
609 }
610
611 /* now handle the events */
612 for(c = first_http_ctx; c != NULL; c = c_next) {
613 c_next = c->next;
614 if (handle_connection(c) < 0) {
615 /* close and free the connection */
616 log_connection(c);
617 close_connection(c);
618 }
619 }
620
621 poll_entry = poll_table;
622 /* new HTTP connection request ? */
623 if (poll_entry->revents & POLLIN) {
624 new_connection(server_fd, 0);
625 }
626 poll_entry++;
627 /* new RTSP connection request ? */
628 if (poll_entry->revents & POLLIN) {
629 new_connection(rtsp_server_fd, 1);
630 }
631 }
632 }
633
634 /* start waiting for a new HTTP/RTSP request */
635 static void start_wait_request(HTTPContext *c, int is_rtsp)
636 {
637 c->buffer_ptr = c->buffer;
638 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
639
640 if (is_rtsp) {
641 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
642 c->state = RTSPSTATE_WAIT_REQUEST;
643 } else {
644 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
645 c->state = HTTPSTATE_WAIT_REQUEST;
646 }
647 }
648
649 static void new_connection(int server_fd, int is_rtsp)
650 {
651 struct sockaddr_in from_addr;
652 int fd, len;
653 HTTPContext *c = NULL;
654
655 len = sizeof(from_addr);
656 fd = accept(server_fd, (struct sockaddr *)&from_addr,
657 &len);
658 if (fd < 0)
659 return;
660 fcntl(fd, F_SETFL, O_NONBLOCK);
661
662 /* XXX: should output a warning page when coming
663 close to the connection limit */
664 if (nb_connections >= nb_max_connections)
665 goto fail;
666
667 /* add a new connection */
668 c = av_mallocz(sizeof(HTTPContext));
669 if (!c)
670 goto fail;
671
672 c->next = first_http_ctx;
673 first_http_ctx = c;
674 c->fd = fd;
675 c->poll_entry = NULL;
676 c->from_addr = from_addr;
677 c->buffer_size = IOBUFFER_INIT_SIZE;
678 c->buffer = av_malloc(c->buffer_size);
679 if (!c->buffer)
680 goto fail;
681 nb_connections++;
682
683 start_wait_request(c, is_rtsp);
684
685 return;
686
687 fail:
688 if (c) {
689 av_free(c->buffer);
690 av_free(c);
691 }
692 close(fd);
693 }
694
695 static void close_connection(HTTPContext *c)
696 {
697 HTTPContext **cp, *c1;
698 int i, nb_streams;
699 AVFormatContext *ctx;
700 URLContext *h;
701 AVStream *st;
702
703 /* remove connection from list */
704 cp = &first_http_ctx;
705 while ((*cp) != NULL) {
706 c1 = *cp;
707 if (c1 == c) {
708 *cp = c->next;
709 } else {
710 cp = &c1->next;
711 }
712 }
713
714 /* remove connection associated resources */
715 if (c->fd >= 0)
716 close(c->fd);
717 if (c->fmt_in) {
718 /* close each frame parser */
719 for(i=0;i<c->fmt_in->nb_streams;i++) {
720 st = c->fmt_in->streams[i];
721 if (st->codec.codec) {
722 avcodec_close(&st->codec);
723 }
724 }
725 av_close_input_file(c->fmt_in);
726 }
727
728 /* free RTP output streams if any */
729 nb_streams = 0;
730 if (c->stream)
731 nb_streams = c->stream->nb_streams;
732
733 for(i=0;i<nb_streams;i++) {
734 ctx = c->rtp_ctx[i];
735 if (ctx) {
736 av_write_trailer(ctx);
737 av_free(ctx);
738 }
739 h = c->rtp_handles[i];
740 if (h) {
741 url_close(h);
742 }
743 }
744
745 if (c->stream)
746 current_bandwidth -= c->stream->bandwidth;
747 av_freep(&c->pb_buffer);
748 av_free(c->buffer);
749 av_free(c);
750 nb_connections--;
751 }
752
753 static int handle_connection(HTTPContext *c)
754 {
755 int len, ret;
756
757 switch(c->state) {
758 case HTTPSTATE_WAIT_REQUEST:
759 case RTSPSTATE_WAIT_REQUEST:
760 /* timeout ? */
761 if ((c->timeout - cur_time) < 0)
762 return -1;
763 if (c->poll_entry->revents & (POLLERR | POLLHUP))
764 return -1;
765
766 /* no need to read if no events */
767 if (!(c->poll_entry->revents & POLLIN))
768 return 0;
769 /* read the data */
770 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
771 if (len < 0) {
772 if (errno != EAGAIN && errno != EINTR)
773 return -1;
774 } else if (len == 0) {
775 return -1;
776 } else {
777 /* search for end of request. XXX: not fully correct since garbage could come after the end */
778 UINT8 *ptr;
779 c->buffer_ptr += len;
780 ptr = c->buffer_ptr;
781 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
782 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
783 /* request found : parse it and reply */
784 if (c->state == HTTPSTATE_WAIT_REQUEST) {
785 ret = http_parse_request(c);
786 } else {
787 ret = rtsp_parse_request(c);
788 }
789 if (ret < 0)
790 return -1;
791 } else if (ptr >= c->buffer_end) {
792 /* request too long: cannot do anything */
793 return -1;
794 }
795 }
796 break;
797
798 case HTTPSTATE_SEND_HEADER:
799 if (c->poll_entry->revents & (POLLERR | POLLHUP))
800 return -1;
801
802 /* no need to write if no events */
803 if (!(c->poll_entry->revents & POLLOUT))
804 return 0;
805 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
806 if (len < 0) {
807 if (errno != EAGAIN && errno != EINTR) {
808 /* error : close connection */
809 av_freep(&c->pb_buffer);
810 return -1;
811 }
812 } else {
813 c->buffer_ptr += len;
814 if (c->stream)
815 c->stream->bytes_served += len;
816 c->data_count += len;
817 if (c->buffer_ptr >= c->buffer_end) {
818 av_freep(&c->pb_buffer);
819 /* if error, exit */
820 if (c->http_error) {
821 return -1;
822 }
823 /* all the buffer was sent : synchronize to the incoming stream */
824 c->state = HTTPSTATE_SEND_DATA_HEADER;
825 c->buffer_ptr = c->buffer_end = c->buffer;
826 }
827 }
828 break;
829
830 case HTTPSTATE_SEND_DATA:
831 case HTTPSTATE_SEND_DATA_HEADER:
832 case HTTPSTATE_SEND_DATA_TRAILER:
833 /* for packetized output, we consider we can always write (the
834 input streams sets the speed). It may be better to verify
835 that we do not rely too much on the kernel queues */
836 if (!c->is_packetized) {
837 if (c->poll_entry->revents & (POLLERR | POLLHUP))
838 return -1;
839
840 /* no need to read if no events */
841 if (!(c->poll_entry->revents & POLLOUT))
842 return 0;
843 }
844 if (http_send_data(c) < 0)
845 return -1;
846 break;
847 case HTTPSTATE_RECEIVE_DATA:
848 /* no need to read if no events */
849 if (c->poll_entry->revents & (POLLERR | POLLHUP))
850 return -1;
851 if (!(c->poll_entry->revents & POLLIN))
852 return 0;
853 if (http_receive_data(c) < 0)
854 return -1;
855 break;
856 case HTTPSTATE_WAIT_FEED:
857 /* no need to read if no events */
858 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
859 return -1;
860
861 /* nothing to do, we'll be waken up by incoming feed packets */
862 break;
863
864 case HTTPSTATE_WAIT:
865 /* if the delay expired, we can send new packets */
866 if (compute_send_delay(c) <= 0)
867 c->state = HTTPSTATE_SEND_DATA;
868 break;
869 case HTTPSTATE_WAIT_SHORT:
870 /* just return back to send data */
871 c->state = HTTPSTATE_SEND_DATA;
872 break;
873
874 case RTSPSTATE_SEND_REPLY:
875 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
876 av_freep(&c->pb_buffer);
877 return -1;
878 }
879 /* no need to write if no events */
880 if (!(c->poll_entry->revents & POLLOUT))
881 return 0;
882 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
883 if (len < 0) {
884 if (errno != EAGAIN && errno != EINTR) {
885 /* error : close connection */
886 av_freep(&c->pb_buffer);
887 return -1;
888 }
889 } else {
890 c->buffer_ptr += len;
891 c->data_count += len;
892 if (c->buffer_ptr >= c->buffer_end) {
893 /* all the buffer was sent : wait for a new request */
894 av_freep(&c->pb_buffer);
895 start_wait_request(c, 1);
896 }
897 }
898 break;
899 case HTTPSTATE_READY:
900 /* nothing to do */
901 break;
902 default:
903 return -1;
904 }
905 return 0;
906 }
907
908 static int extract_rates(char *rates, int ratelen, const char *request)
909 {
910 const char *p;
911
912 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
913 if (strncasecmp(p, "Pragma:", 7) == 0) {
914 const char *q = p + 7;
915
916 while (*q && *q != '\n' && isspace(*q))
917 q++;
918
919 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
920 int stream_no;
921 int rate_no;
922
923 q += 20;
924
925 memset(rates, 0xff, ratelen);
926
927 while (1) {
928 while (*q && *q != '\n' && *q != ':')
929 q++;
930
931 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
932 break;
933 }
934 stream_no--;
935 if (stream_no < ratelen && stream_no >= 0) {
936 rates[stream_no] = rate_no;
937 }
938
939 while (*q && *q != '\n' && !isspace(*q))
940 q++;
941 }
942
943 return 1;
944 }
945 }
946 p = strchr(p, '\n');
947 if (!p)
948 break;
949
950 p++;
951 }
952
953 return 0;
954 }
955
956 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
957 {
958 int i;
959 int best_bitrate = 100000000;
960 int best = -1;
961
962 for (i = 0; i < feed->nb_streams; i++) {
963 AVCodecContext *feed_codec = &feed->streams[i]->codec;
964
965 if (feed_codec->codec_id != codec->codec_id ||
966 feed_codec->sample_rate != codec->sample_rate ||
967 feed_codec->width != codec->width ||
968 feed_codec->height != codec->height) {
969 continue;
970 }
971
972 /* Potential stream */
973
974 /* We want the fastest stream less than bit_rate, or the slowest
975 * faster than bit_rate
976 */
977
978 if (feed_codec->bit_rate <= bit_rate) {
979 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
980 best_bitrate = feed_codec->bit_rate;
981 best = i;
982 }
983 } else {
984 if (feed_codec->bit_rate < best_bitrate) {
985 best_bitrate = feed_codec->bit_rate;
986 best = i;
987 }
988 }
989 }
990
991 return best;
992 }
993
994 static int modify_current_stream(HTTPContext *c, char *rates)
995 {
996 int i;
997 FFStream *req = c->stream;
998 int action_required = 0;
999
1000 /* Not much we can do for a feed */
1001 if (!req->feed)
1002 return 0;
1003
1004 for (i = 0; i < req->nb_streams; i++) {
1005 AVCodecContext *codec = &req->streams[i]->codec;
1006
1007 switch(rates[i]) {
1008 case 0:
1009 c->switch_feed_streams[i] = req->feed_streams[i];
1010 break;
1011 case 1:
1012 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1013 break;
1014 case 2:
1015 /* Wants off or slow */
1016 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1017 #ifdef WANTS_OFF
1018 /* This doesn't work well when it turns off the only stream! */
1019 c->switch_feed_streams[i] = -2;
1020 c->feed_streams[i] = -2;
1021 #endif
1022 break;
1023 }
1024
1025 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1026 action_required = 1;
1027 }
1028
1029 return action_required;
1030 }
1031
1032
1033 static void do_switch_stream(HTTPContext *c, int i)
1034 {
1035 if (c->switch_feed_streams[i] >= 0) {
1036 #ifdef PHILIP
1037 c->feed_streams[i] = c->switch_feed_streams[i];
1038 #endif
1039
1040 /* Now update the stream */
1041 }
1042 c->switch_feed_streams[i] = -1;
1043 }
1044
1045 /* XXX: factorize in utils.c ? */
1046 /* XXX: take care with different space meaning */
1047 static void skip_spaces(const char **pp)
1048 {
1049 const char *p;
1050 p = *pp;
1051 while (*p == ' ' || *p == '\t')
1052 p++;
1053 *pp = p;
1054 }
1055
1056 static void get_word(char *buf, int buf_size, const char **pp)
1057 {
1058 const char *p;
1059 char *q;
1060
1061 p = *pp;
1062 skip_spaces(&p);
1063 q = buf;
1064 while (!isspace(*p) && *p != '\0') {
1065 if ((q - buf) < buf_size - 1)
1066 *q++ = *p;
1067 p++;
1068 }
1069 if (buf_size > 0)
1070 *q = '\0';
1071 *pp = p;
1072 }
1073
1074 static int validate_acl(FFStream *stream, HTTPContext *c)
1075 {
1076 enum IPAddressAction last_action = IP_DENY;
1077 IPAddressACL *acl;
1078 struct in_addr *src = &c->from_addr.sin_addr;
1079
1080 for (acl = stream->acl; acl; acl = acl->next) {
1081 if (src->s_addr >= acl->first.s_addr && src->s_addr <= acl->last.s_addr) {
1082 return (acl->action == IP_ALLOW) ? 1 : 0;
1083 }
1084 last_action = acl->action;
1085 }
1086
1087 /* Nothing matched, so return not the last action */
1088 return (last_action == IP_DENY) ? 1 : 0;
1089 }
1090
1091 /* compute the real filename of a file by matching it without its
1092 extensions to all the stream filenames */
1093 static void compute_real_filename(char *filename, int max_size)
1094 {
1095 char file1[1024];
1096 char file2[1024];
1097 char *p;
1098 FFStream *stream;
1099
1100 /* compute filename by matching without the file extensions */
1101 pstrcpy(file1, sizeof(file1), filename);
1102 p = strrchr(file1, '.');
1103 if (p)
1104 *p = '\0';
1105 for(stream = first_stream; stream != NULL; stream = stream->next) {
1106 pstrcpy(file2, sizeof(file2), stream->filename);
1107 p = strrchr(file2, '.');
1108 if (p)
1109 *p = '\0';
1110 if (!strcmp(file1, file2)) {
1111 pstrcpy(filename, max_size, stream->filename);
1112 break;
1113 }
1114 }
1115 }
1116
1117 enum RedirType {
1118 REDIR_NONE,
1119 REDIR_ASX,
1120 REDIR_RAM,
1121 REDIR_ASF,
1122 REDIR_RTSP,
1123 REDIR_SDP,
1124 };
1125
1126 /* parse http request and prepare header */
1127 static int http_parse_request(HTTPContext *c)
1128 {
1129 char *p;
1130 int post;
1131 enum RedirType redir_type;
1132 char cmd[32];
1133 char info[1024], *filename;
1134 char url[1024], *q;
1135 char protocol[32];
1136 char msg[1024];
1137 const char *mime_type;
1138 FFStream *stream;
1139 int i;
1140 char ratebuf[32];
1141 char *useragent = 0;
1142
1143 p = c->buffer;
1144 get_word(cmd, sizeof(cmd), (const char **)&p);
1145 pstrcpy(c->method, sizeof(c->method), cmd);
1146
1147 if (!strcmp(cmd, "GET"))
1148 post = 0;
1149 else if (!strcmp(cmd, "POST"))
1150 post = 1;
1151 else
1152 return -1;
1153
1154 get_word(url, sizeof(url), (const char **)&p);
1155 pstrcpy(c->url, sizeof(c->url), url);
1156
1157 get_word(protocol, sizeof(protocol), (const char **)&p);
1158 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1159 return -1;
1160
1161 pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1162
1163 /* find the filename and the optional info string in the request */
1164 p = url;
1165 if (*p == '/')
1166 p++;
1167 filename = p;
1168 p = strchr(p, '?');
1169 if (p) {
1170 pstrcpy(info, sizeof(info), p);
1171 *p = '\0';
1172 } else {
1173 info[0] = '\0';
1174 }
1175
1176 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1177 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1178 useragent = p + 11;
1179 if (*useragent && *useragent != '\n' && isspace(*useragent))
1180 useragent++;
1181 break;
1182 }
1183 p = strchr(p, '\n');
1184 if (!p)
1185 break;
1186
1187 p++;
1188 }
1189
1190 redir_type = REDIR_NONE;
1191 if (match_ext(filename, "asx")) {
1192 redir_type = REDIR_ASX;
1193 filename[strlen(filename)-1] = 'f';
1194 } else if (match_ext(filename, "asf") &&
1195 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1196 /* if this isn't WMP or lookalike, return the redirector file */
1197 redir_type = REDIR_ASF;
1198 } else if (match_ext(filename, "rpm,ram")) {
1199 redir_type = REDIR_RAM;
1200 strcpy(filename + strlen(filename)-2, "m");
1201 } else if (match_ext(filename, "rtsp")) {
1202 redir_type = REDIR_RTSP;
1203 compute_real_filename(filename, sizeof(url) - 1);
1204 } else if (match_ext(filename, "sdp")) {
1205 redir_type = REDIR_SDP;
1206 compute_real_filename(filename, sizeof(url) - 1);
1207 }
1208
1209 stream = first_stream;
1210 while (stream != NULL) {
1211 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1212 break;
1213 stream = stream->next;
1214 }
1215 if (stream == NULL) {
1216 sprintf(msg, "File '%s' not found", url);
1217 goto send_error;
1218 }
1219
1220 c->stream = stream;
1221 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1222 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1223
1224 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1225 c->http_error = 301;
1226 q = c->buffer;
1227 q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
1228 q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
1229 q += sprintf(q, "Content-type: text/html\r\n");
1230 q += sprintf(q, "\r\n");
1231 q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
1232 q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1233 q += sprintf(q, "</body></html>\r\n");
1234
1235 /* prepare output buffer */
1236 c->buffer_ptr = c->buffer;
1237 c->buffer_end = q;
1238 c->state = HTTPSTATE_SEND_HEADER;
1239 return 0;
1240 }
1241
1242 /* If this is WMP, get the rate information */
1243 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1244 if (modify_current_stream(c, ratebuf)) {
1245 for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1246 if (c->switch_feed_streams[i] >= 0)
1247 do_switch_stream(c, i);
1248 }
1249 }
1250 }
1251
1252 if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1253 current_bandwidth += stream->bandwidth;
1254 }
1255
1256 if (post == 0 && max_bandwidth < current_bandwidth) {
1257 c->http_error = 200;
1258 q = c->buffer;
1259 q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
1260 q += sprintf(q, "Content-type: text/html\r\n");
1261 q += sprintf(q, "\r\n");
1262 q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
1263 q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
1264 q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
1265 current_bandwidth, max_bandwidth);
1266 q += sprintf(q, "</body></html>\r\n");
1267
1268 /* prepare output buffer */
1269 c->buffer_ptr = c->buffer;
1270 c->buffer_end = q;
1271 c->state = HTTPSTATE_SEND_HEADER;
1272 return 0;
1273 }
1274
1275 if (redir_type != REDIR_NONE) {
1276 char *hostinfo = 0;
1277
1278 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1279 if (strncasecmp(p, "Host:", 5) == 0) {
1280 hostinfo = p + 5;
1281 break;
1282 }
1283 p = strchr(p, '\n');
1284 if (!p)
1285 break;
1286
1287 p++;
1288 }
1289
1290 if (hostinfo) {
1291 char *eoh;
1292 char hostbuf[260];
1293
1294 while (isspace(*hostinfo))
1295 hostinfo++;
1296
1297 eoh = strchr(hostinfo, '\n');
1298 if (eoh) {
1299 if (eoh[-1] == '\r')
1300 eoh--;
1301
1302 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1303 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1304 hostbuf[eoh - hostinfo] = 0;
1305
1306 c->http_error = 200;
1307 q = c->buffer;
1308 switch(redir_type) {
1309 case REDIR_ASX:
1310 q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
1311 q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1312 q += sprintf(q, "\r\n");
1313 q += sprintf(q, "<ASX Version=\"3\">\r\n");
1314 q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
1315 q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
1316 hostbuf, filename, info);
1317 q += sprintf(q, "</ASX>\r\n");
1318 break;
1319 case REDIR_RAM:
1320 q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
1321 q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
1322 q += sprintf(q, "\r\n");
1323 q += sprintf(q, "# Autogenerated by ffserver\r\n");
1324 q += sprintf(q, "http://%s/%s%s\r\n",
1325 hostbuf, filename, info);
1326 break;
1327 case REDIR_ASF:
1328 q += sprintf(q, "HTTP/1.0 200 ASF Redirect follows\r\n");
1329 q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1330 q += sprintf(q, "\r\n");
1331 q += sprintf(q, "[Reference]\r\n");
1332 q += sprintf(q, "Ref1=http://%s/%s%s\r\n",
1333 hostbuf, filename, info);
1334 break;
1335 case REDIR_RTSP:
1336 {
1337 char hostname[256], *p;
1338 /* extract only hostname */
1339 pstrcpy(hostname, sizeof(hostname), hostbuf);
1340 p = strrchr(hostname, ':');
1341 if (p)
1342 *p = '\0';
1343 q += sprintf(q, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1344 /* XXX: incorrect mime type ? */
1345 q += sprintf(q, "Content-type: application/x-rtsp\r\n");
1346 q += sprintf(q, "\r\n");
1347 q += sprintf(q, "rtsp://%s:%d/%s\r\n",
1348 hostname, ntohs(my_rtsp_addr.sin_port),
1349 filename);
1350 }
1351 break;
1352 case REDIR_SDP:
1353 {
1354 UINT8 *sdp_data;
1355 int sdp_data_size, len;
1356 struct sockaddr_in my_addr;
1357
1358 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1359 q += sprintf(q, "Content-type: application/sdp\r\n");
1360 q += sprintf(q, "\r\n");
1361
1362 len = sizeof(my_addr);
1363 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1364
1365 /* XXX: should use a dynamic buffer */
1366 sdp_data_size = prepare_sdp_description(stream,
1367 &sdp_data,
1368 my_addr.sin_addr);
1369 if (sdp_data_size > 0) {
1370 memcpy(q, sdp_data, sdp_data_size);
1371 q += sdp_data_size;
1372 *q = '\0';
1373 av_free(sdp_data);
1374 }
1375 }
1376 break;
1377 default:
1378 av_abort();
1379 break;
1380 }
1381
1382 /* prepare output buffer */
1383 c->buffer_ptr = c->buffer;
1384 c->buffer_end = q;
1385 c->state = HTTPSTATE_SEND_HEADER;
1386 return 0;
1387 }
1388 }
1389 }
1390
1391 sprintf(msg, "ASX/RAM file not handled");
1392 goto send_error;
1393 }
1394
1395 stream->conns_served++;
1396
1397 /* XXX: add there authenticate and IP match */
1398
1399 if (post) {
1400 /* if post, it means a feed is being sent */
1401 if (!stream->is_feed) {
1402 /* However it might be a status report from WMP! Lets log the data
1403 * as it might come in handy one day
1404 */
1405 char *logline = 0;
1406 int client_id = 0;
1407
1408 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1409 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1410 logline = p;
1411 break;
1412 }
1413 if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1414 client_id = strtol(p + 18, 0, 10);
1415 }
1416 p = strchr(p, '\n');
1417 if (!p)
1418 break;
1419
1420 p++;
1421 }
1422
1423 if (logline) {
1424 char *eol = strchr(logline, '\n');
1425
1426 logline += 17;
1427
1428 if (eol) {
1429 if (eol[-1] == '\r')
1430 eol--;
1431 http_log("%.*s\n", eol - logline, logline);
1432 c->suppress_log = 1;
1433 }
1434 }
1435
1436 #ifdef DEBUG_WMP
1437 http_log("\nGot request:\n%s\n", c->buffer);
1438 #endif
1439
1440 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1441 HTTPContext *wmpc;
1442
1443 /* Now we have to find the client_id */
1444 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1445 if (wmpc->wmp_client_id == client_id)
1446 break;
1447 }
1448
1449 if (wmpc) {
1450 if (modify_current_stream(wmpc, ratebuf)) {
1451 wmpc->switch_pending = 1;
1452 }
1453 }
1454 }
1455
1456 sprintf(msg, "POST command not handled");
1457 goto send_error;
1458 }
1459 if (http_start_receive_data(c) < 0) {
1460 sprintf(msg, "could not open feed");
1461 goto send_error;
1462 }
1463 c->http_error = 0;
1464 c->state = HTTPSTATE_RECEIVE_DATA;
1465 return 0;
1466 }
1467
1468 #ifdef DEBUG_WMP
1469 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1470 http_log("\nGot request:\n%s\n", c->buffer);
1471 }
1472 #endif
1473
1474 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1475 goto send_stats;
1476
1477 /* open input stream */
1478 if (open_input_stream(c, info) < 0) {
1479 sprintf(msg, "Input stream corresponding to '%s' not found", url);
1480 goto send_error;
1481 }
1482
1483 /* prepare http header */
1484 q = c->buffer;
1485 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1486 mime_type = c->stream->fmt->mime_type;
1487 if (!mime_type)
1488 mime_type = "application/x-octet_stream";
1489 q += sprintf(q, "Pragma: no-cache\r\n");
1490
1491 /* for asf, we need extra headers */
1492 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1493 /* Need to allocate a client id */
1494
1495 c->wmp_client_id = random() & 0x7fffffff;
1496
1497 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);
1498 }
1499 q += sprintf(q, "Content-Type: %s\r\n", mime_type);
1500 q += sprintf(q, "\r\n");
1501
1502 /* prepare output buffer */
1503 c->http_error = 0;
1504 c->buffer_ptr = c->buffer;
1505 c->buffer_end = q;
1506 c->state = HTTPSTATE_SEND_HEADER;
1507 return 0;
1508 send_error:
1509 c->http_error = 404;
1510 q = c->buffer;
1511 q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
1512 q += sprintf(q, "Content-type: %s\r\n", "text/html");
1513 q += sprintf(q, "\r\n");
1514 q += sprintf(q, "<HTML>\n");
1515 q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1516 q += sprintf(q, "<BODY>%s</BODY>\n", msg);
1517 q += sprintf(q, "</HTML>\n");
1518
1519 /* prepare output buffer */
1520 c->buffer_ptr = c->buffer;
1521 c->buffer_end = q;
1522 c->state = HTTPSTATE_SEND_HEADER;
1523 return 0;
1524 send_stats:
1525 compute_stats(c);
1526 c->http_error = 200; /* horrible : we use this value to avoid
1527 going to the send data state */
1528 c->state = HTTPSTATE_SEND_HEADER;
1529 return 0;
1530 }
1531
1532 static void fmt_bytecount(ByteIOContext *pb, INT64 count)
1533 {
1534 static const char *suffix = " kMGTP";
1535 const char *s;
1536
1537 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1538 }
1539
1540 url_fprintf(pb, "%lld%c", count, *s);
1541 }
1542
1543 static void compute_stats(HTTPContext *c)
1544 {
1545 HTTPContext *c1;
1546 FFStream *stream;
1547 char *p;
1548 time_t ti;
1549 int i, len;
1550 ByteIOContext pb1, *pb = &pb1;
1551
1552 if (url_open_dyn_buf(pb) < 0) {
1553 /* XXX: return an error ? */
1554 c->buffer_ptr = c->buffer;
1555 c->buffer_end = c->buffer;
1556 return;
1557 }
1558
1559 url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1560 url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1561 url_fprintf(pb, "Pragma: no-cache\r\n");
1562 url_fprintf(pb, "\r\n");
1563
1564 url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1565 if (c->stream->feed_filename) {
1566 url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1567 }
1568 url_fprintf(pb, "</HEAD>\n<BODY>");
1569 url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1570 /* format status */
1571 url_fprintf(pb, "<H2>Available Streams</H2>\n");
1572 url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1573 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");
1574 stream = first_stream;
1575 while (stream != NULL) {
1576 char sfilename[1024];
1577 char *eosf;
1578
1579 if (stream->feed != stream) {
1580 pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1581 eosf = sfilename + strlen(sfilename);
1582 if (eosf - sfilename >= 4) {
1583 if (strcmp(eosf - 4, ".asf") == 0) {
1584 strcpy(eosf - 4, ".asx");
1585 } else if (strcmp(eosf - 3, ".rm") == 0) {
1586 strcpy(eosf - 3, ".ram");
1587 } else if (stream->fmt == &rtp_mux) {
1588 /* generate a sample RTSP director if
1589 unicast. Generate an SDP redirector if
1590 multicast */
1591 eosf = strrchr(sfilename, '.');
1592 if (!eosf)
1593 eosf = sfilename + strlen(sfilename);
1594 if (stream->is_multicast)
1595 strcpy(eosf, ".sdp");
1596 else
1597 strcpy(eosf, ".rtsp");
1598 }
1599 }
1600
1601 url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1602 sfilename, stream->filename);
1603 url_fprintf(pb, "<td align=right> %d <td align=right> ",
1604 stream->conns_served);
1605 fmt_bytecount(pb, stream->bytes_served);
1606 switch(stream->stream_type) {
1607 case STREAM_TYPE_LIVE:
1608 {
1609 int audio_bit_rate = 0;
1610 int video_bit_rate = 0;
1611 const char *audio_codec_name = "";
1612 const char *video_codec_name = "";
1613 const char *audio_codec_name_extra = "";
1614 const char *video_codec_name_extra = "";
1615
1616 for(i=0;i<stream->nb_streams;i++) {
1617 AVStream *st = stream->streams[i];
1618 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1619 switch(st->codec.codec_type) {
1620 case CODEC_TYPE_AUDIO:
1621 audio_bit_rate += st->codec.bit_rate;
1622 if (codec) {
1623 if (*audio_codec_name)
1624 audio_codec_name_extra = "...";
1625 audio_codec_name = codec->name;
1626 }
1627 break;
1628 case CODEC_TYPE_VIDEO:
1629 video_bit_rate += st->codec.bit_rate;
1630 if (codec) {
1631 if (*video_codec_name)
1632 video_codec_name_extra = "...";
1633 video_codec_name = codec->name;
1634 }
1635 break;
1636 default:
1637 av_abort();
1638 }
1639 }
1640 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",
1641 stream->fmt->name,
1642 stream->bandwidth,
1643 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1644 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1645 if (stream->feed) {
1646 url_fprintf(pb, "<TD>%s", stream->feed->filename);
1647 } else {
1648 url_fprintf(pb, "<TD>%s", stream->feed_filename);
1649 }
1650 url_fprintf(pb, "\n");
1651 }
1652 break;
1653 default:
1654 url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1655 break;
1656 }
1657 }
1658 stream = stream->next;
1659 }
1660 url_fprintf(pb, "</TABLE>\n");
1661
1662 stream = first_stream;
1663 while (stream != NULL) {
1664 if (stream->feed == stream) {
1665 url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1666 if (stream->pid) {
1667 url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1668
1669 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1670 {
1671 FILE *pid_stat;
1672 char ps_cmd[64];
1673
1674 /* This is somewhat linux specific I guess */
1675 snprintf(ps_cmd, sizeof(ps_cmd),
1676 "ps -o \"%%cpu,cputime\" --no-headers %d",
1677 stream->pid);
1678
1679 pid_stat = popen(ps_cmd, "r");
1680 if (pid_stat) {
1681 char cpuperc[10];
1682 char cpuused[64];
1683
1684 if (fscanf(pid_stat, "%10s %64s", cpuperc,
1685 cpuused) == 2) {
1686 url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1687 cpuperc, cpuused);
1688 }
1689 fclose(pid_stat);
1690 }
1691 }
1692 #endif
1693
1694 url_fprintf(pb, "<p>");
1695 }
1696 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");
1697
1698 for (i = 0; i < stream->nb_streams; i++) {
1699 AVStream *st = stream->streams[i];
1700 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1701 char *type = "unknown";
1702 char parameters[64];
1703
1704 parameters[0] = 0;
1705
1706 switch(st->codec.codec_type) {
1707 case CODEC_TYPE_AUDIO:
1708 type = "audio";
1709 break;
1710 case CODEC_TYPE_VIDEO:
1711 type = "video";
1712 sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
1713 st->codec.qmin, st->codec.qmax, st->codec.frame_rate / FRAME_RATE_BASE);
1714 break;
1715 default:
1716 av_abort();
1717 }
1718 url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1719 i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
1720 }
1721 url_fprintf(pb, "</table>\n");
1722
1723 }
1724 stream = stream->next;
1725 }
1726
1727 #if 0
1728 {
1729 float avg;
1730 AVCodecContext *enc;
1731 char buf[1024];
1732
1733 /* feed status */
1734 stream = first_feed;
1735 while (stream != NULL) {
1736 url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1737 url_fprintf(pb, "<TABLE>\n");
1738 url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1739 for(i=0;i<stream->nb_streams;i++) {
1740 AVStream *st = stream->streams[i];
1741 FeedData *fdata = st->priv_data;
1742 enc = &st->codec;
1743
1744 avcodec_string(buf, sizeof(buf), enc);
1745 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1746 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1747 avg /= enc->frame_size;
1748 url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n",
1749 buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1750 }
1751 url_fprintf(pb, "</TABLE>\n");
1752 stream = stream->next_feed;
1753 }
1754 }
1755 #endif
1756
1757 /* connection status */
1758 url_fprintf(pb, "<H2>Connection Status</H2>\n");
1759
1760 url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1761 nb_connections, nb_max_connections);
1762
1763 url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1764 current_bandwidth, max_bandwidth);
1765
1766 url_fprintf(pb, "<TABLE>\n");
1767 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");
1768 c1 = first_http_ctx;
1769 i = 0;
1770 while (c1 != NULL) {
1771 int bitrate;
1772 int j;
1773
1774 bitrate = 0;
1775 if (c1->stream) {
1776 for (j = 0; j < c1->stream->nb_streams; j++) {
1777 if (!c1->stream->feed) {
1778 bitrate += c1->stream->streams[j]->codec.bit_rate;
1779 } else {
1780 if (c1->feed_streams[j] >= 0) {
1781 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec.bit_rate;
1782 }
1783 }
1784 }
1785 }
1786
1787 i++;
1788 p = inet_ntoa(c1->from_addr.sin_addr);
1789 url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1790 i,
1791 c1->stream ? c1->stream->filename : "",
1792 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1793 p,
1794 c1->protocol,
1795 http_state[c1->state]);
1796 fmt_bytecount(pb, bitrate);
1797 url_fprintf(pb, "<td align=right>");
1798 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1799 url_fprintf(pb, "<td align=right>");
1800 fmt_bytecount(pb, c1->data_count);
1801 url_fprintf(pb, "\n");
1802 c1 = c1->next;
1803 }
1804 url_fprintf(pb, "</TABLE>\n");
1805
1806 /* date */
1807 ti = time(NULL);
1808 p = ctime(&ti);
1809 url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1810 url_fprintf(pb, "</BODY>\n</HTML>\n");
1811
1812 len = url_close_dyn_buf(pb, &c->pb_buffer);
1813 c->buffer_ptr = c->pb_buffer;
1814 c->buffer_end = c->pb_buffer + len;
1815 }
1816
1817 /* check if the parser needs to be opened for stream i */
1818 static void open_parser(AVFormatContext *s, int i)
1819 {
1820 AVStream *st = s->streams[i];
1821 AVCodec *codec;
1822
1823 if (!st->codec.codec) {
1824 codec = avcodec_find_decoder(st->codec.codec_id);
1825 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1826 st->codec.parse_only = 1;
1827 if (avcodec_open(&st->codec, codec) < 0) {
1828 st->codec.parse_only = 0;
1829 }
1830 }
1831 }
1832 }
1833
1834 static int open_input_stream(HTTPContext *c, const char *info)
1835 {
1836 char buf[128];
1837 char input_filename[1024];
1838 AVFormatContext *s;
1839 int buf_size, i;
1840 INT64 stream_pos;
1841
1842 /* find file name */
1843 if (c->stream->feed) {
1844 strcpy(input_filename, c->stream->feed->feed_filename);
1845 buf_size = FFM_PACKET_SIZE;
1846 /* compute position (absolute time) */
1847 if (find_info_tag(buf, sizeof(buf), "date", info)) {
1848 stream_pos = parse_date(buf, 0);
1849 } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1850 int prebuffer = strtol(buf, 0, 10);
1851 stream_pos = av_gettime() - prebuffer * (INT64)1000000;
1852 } else {
1853 stream_pos = av_gettime() - c->stream->prebuffer * (INT64)1000;
1854 }
1855 } else {
1856 strcpy(input_filename, c->stream->feed_filename);
1857 buf_size = 0;
1858 /* compute position (relative time) */
1859 if (find_info_tag(buf, sizeof(buf), "date", info)) {
1860 stream_pos = parse_date(buf, 1);
1861 } else {
1862 stream_pos = 0;
1863 }
1864 }
1865 if (input_filename[0] == '\0')
1866 return -1;
1867
1868 #if 0
1869 { time_t when = stream_pos / 1000000;
1870 http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1871 }
1872 #endif
1873
1874 /* open stream */
1875 if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
1876 http_log("%s not found", input_filename);
1877 return -1;
1878 }
1879 c->fmt_in = s;
1880
1881 /* open each parser */
1882 for(i=0;i<s->nb_streams;i++)
1883 open_parser(s, i);
1884
1885 /* choose stream as clock source (we favorize video stream if
1886 present) for packet sending */
1887 c->pts_stream_index = 0;
1888 for(i=0;i<c->stream->nb_streams;i++) {
1889 if (c->pts_stream_index == 0 &&
1890 c->stream->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) {
1891 c->pts_stream_index = i;
1892 }
1893 }
1894
1895 if (c->fmt_in->iformat->read_seek) {
1896 c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
1897 }
1898 /* set the start time (needed for maxtime and RTP packet timing) */
1899 c->start_time = cur_time;
1900 c->first_pts = AV_NOPTS_VALUE;
1901 return 0;
1902 }
1903
1904 /* currently desactivated because the new PTS handling is not
1905 satisfactory yet */
1906 //#define AV_READ_FRAME
1907 #ifdef AV_READ_FRAME
1908
1909 /* XXX: generalize that in ffmpeg for picture/audio/data. Currently
1910 the return packet MUST NOT be freed */
1911 int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1912 {
1913 AVStream *st;
1914 int len, ret, old_nb_streams, i;
1915
1916 /* see if remaining frames must be parsed */
1917 for(;;) {
1918 if (s->cur_len > 0) {
1919 st = s->streams[s->cur_pkt.stream_index];
1920 len = avcodec_parse_frame(&st->codec, &pkt->data, &pkt->size,
1921 s->cur_ptr, s->cur_len);
1922 if (len < 0) {
1923 /* error: get next packet */
1924 s->cur_len = 0;
1925 } else {
1926 s->cur_ptr += len;
1927 s->cur_len -= len;
1928 if (pkt->size) {
1929 /* init pts counter if not done */
1930 if (st->pts.den == 0) {
1931 switch(st->codec.codec_type) {
1932 case CODEC_TYPE_AUDIO:
1933 st->pts_incr = (INT64)s->pts_den;
1934 av_frac_init(&st->pts, st->pts.val, 0,
1935 (INT64)s->pts_num * st->codec.sample_rate);
1936 break;
1937 case CODEC_TYPE_VIDEO:
1938 st->pts_incr = (INT64)s->pts_den * FRAME_RATE_BASE;
1939 av_frac_init(&st->pts, st->pts.val, 0,
1940 (INT64)s->pts_num * st->codec.frame_rate);
1941 break;
1942 default:
1943 av_abort();
1944 }
1945 }
1946
1947 /* a frame was read: return it */
1948 pkt->pts = st->pts.val;
1949 #if 0
1950 printf("add pts=%Lx num=%Lx den=%Lx incr=%Lx\n",
1951 st->pts.val, st->pts.num, st->pts.den, st->pts_incr);
1952 #endif
1953 switch(st->codec.codec_type) {
1954 case CODEC_TYPE_AUDIO:
1955 av_frac_add(&st->pts, st->pts_incr * st->codec.frame_size);
1956 break;
1957 case CODEC_TYPE_VIDEO:
1958 av_frac_add(&st->pts, st->pts_incr);
1959 break;
1960 default:
1961 av_abort();
1962 }
1963 pkt->stream_index = s->cur_pkt.stream_index;
1964 /* we use the codec indication because it is
1965 more accurate than the demux flags */
1966 pkt->flags = 0;
1967 if (st->codec.coded_frame->key_frame)
1968 pkt->flags |= PKT_FLAG_KEY;
1969 return 0;
1970 }
1971 }
1972 } else {
1973 /* free previous packet */
1974 av_free_packet(&s->cur_pkt);
1975
1976 old_nb_streams = s->nb_streams;
1977 ret = av_read_packet(s, &s->cur_pkt);
1978 if (ret)
1979 return ret;
1980 /* open parsers for each new streams */
1981 for(i = old_nb_streams; i < s->nb_streams; i++)
1982 open_parser(s, i);
1983 st = s->streams[s->cur_pkt.stream_index];
1984
1985 /* update current pts (XXX: dts handling) from packet, or
1986 use current pts if none given */
1987 if (s->cur_pkt.pts != AV_NOPTS_VALUE) {
1988 av_frac_set(&st->pts, s->cur_pkt.pts);
1989 } else {
1990 s->cur_pkt.pts = st->pts.val;
1991 }
1992 if (!st->codec.codec) {
1993 /* no codec opened: just return the raw packet */
1994 *pkt = s->cur_pkt;
1995
1996 /* no codec opened: just update the pts by considering we
1997 have one frame and free the packet */
1998 if (st->pts.den == 0) {
1999 switch(st->codec.codec_type) {
2000 case CODEC_TYPE_AUDIO:
2001 st->pts_incr = (INT64)s->pts_den * st->codec.frame_size;
2002 av_frac_init(&st->pts, st->pts.val, 0,
2003 (INT64)s->pts_num * st->codec.sample_rate);
2004 break;
2005 case CODEC_TYPE_VIDEO:
2006 st->pts_incr = (INT64)s->pts_den * FRAME_RATE_BASE;
2007 av_frac_init(&st->pts, st->pts.val, 0,
2008 (INT64)s->pts_num * st->codec.frame_rate);
2009 break;
2010 default:
2011 av_abort();
2012 }
2013 }
2014 av_frac_add(&st->pts, st->pts_incr);
2015 return 0;
2016 } else {
2017 s->cur_ptr = s->cur_pkt.data;
2018 s->cur_len = s->cur_pkt.size;
2019 }
2020 }
2021 }
2022 }
2023
2024 static int compute_send_delay(HTTPContext *c)
2025 {
2026 INT64 cur_pts, delta_pts, next_pts;
2027 int delay1;
2028
2029 /* compute current pts value from system time */
2030 cur_pts = ((INT64)(cur_time - c->start_time) * c->fmt_in->pts_den) /
2031 (c->fmt_in->pts_num * 1000LL);
2032 /* compute the delta from the stream we choose as
2033 main clock (we do that to avoid using explicit
2034 buffers to do exact packet reordering for each
2035 stream */
2036 /* XXX: really need to fix the number of streams */
2037 if (c->pts_stream_index >= c->fmt_in->nb_streams)
2038 next_pts = cur_pts;
2039 else
2040 next_pts = c->fmt_in->streams[c->pts_stream_index]->pts.val;
2041 delta_pts = next_pts - cur_pts;
2042 if (delta_pts <= 0) {
2043 delay1 = 0;
2044 } else {
2045 delay1 = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
2046 }
2047 return delay1;
2048 }
2049 #else
2050
2051 /* just fall backs */
2052 int av_read_frame(AVFormatContext *s, AVPacket *pkt)
2053 {
2054 return av_read_packet(s, pkt);
2055 }
2056
2057 static int compute_send_delay(HTTPContext *c)
2058 {
2059 int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count);
2060
2061 if (datarate > c->stream->bandwidth * 2000) {
2062 return 1000;
2063 }
2064 return 0;
2065 }
2066
2067 #endif
2068
2069 static int http_prepare_data(HTTPContext *c)
2070 {
2071 int i, len, ret;
2072 AVFormatContext *ctx;
2073
2074 switch(c->state) {
2075 case HTTPSTATE_SEND_DATA_HEADER:
2076 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2077 pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author),
2078 c->stream->author);
2079 pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment),
2080 c->stream->comment);
2081 pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright),
2082 c->stream->copyright);
2083 pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title),
2084 c->stream->title);
2085
2086 /* open output stream by using specified codecs */
2087 c->fmt_ctx.oformat = c->stream->fmt;
2088 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2089 for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2090 AVStream *st;
2091 st = av_mallocz(sizeof(AVStream));
2092 c->fmt_ctx.streams[i] = st;
2093 /* if file or feed, then just take streams from FFStream struct */
2094 if (!c->stream->feed ||
2095 c->stream->feed == c->stream)
2096 memcpy(st, c->stream->streams[i], sizeof(AVStream));
2097 else
2098 memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]],
2099 sizeof(AVStream));
2100 st->codec.frame_number = 0; /* XXX: should be done in
2101 AVStream, not in codec */
2102 /* I'm pretty sure that this is not correct...
2103 * However, without it, we crash
2104 */
2105 st->codec.coded_frame = &dummy_frame;
2106 }
2107 c->got_key_frame = 0;
2108
2109 /* prepare header and save header data in a stream */
2110 if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2111 /* XXX: potential leak */
2112 return -1;
2113 }
2114 c->fmt_ctx.pb.is_streamed = 1;
2115
2116 av_write_header(&c->fmt_ctx);
2117
2118 len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2119 c->buffer_ptr = c->pb_buffer;
2120 c->buffer_end = c->pb_buffer + len;
2121
2122 c->state = HTTPSTATE_SEND_DATA;
2123 c->last_packet_sent = 0;
2124 break;
2125 case HTTPSTATE_SEND_DATA:
2126 /* find a new packet */
2127 {
2128 AVPacket pkt;
2129
2130 /* read a packet from the input stream */
2131 if (c->stream->feed) {
2132 ffm_set_write_index(c->fmt_in,
2133 c->stream->feed->feed_write_index,
2134 c->stream->feed->feed_size);
2135 }
2136
2137 if (c->stream->max_time &&
2138 c->stream->max_time + c->start_time - cur_time < 0) {
2139 /* We have timed out */
2140 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2141 } else {
2142 if (1 || c->is_packetized) {
2143 if (compute_send_delay(c) > 0) {
2144 c->state = HTTPSTATE_WAIT;
2145 return 1; /* state changed */
2146 }
2147 }
2148 redo:
2149 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2150 if (c->stream->feed && c->stream->feed->feed_opened) {
2151 /* if coming from feed, it means we reached the end of the
2152 ffm file, so must wait for more data */
2153 c->state = HTTPSTATE_WAIT_FEED;
2154 return 1; /* state changed */
2155 } else {
2156 if (c->stream->loop) {
2157 av_close_input_file(c->fmt_in);
2158 c->fmt_in = NULL;
2159 if (open_input_stream(c, "") < 0)
2160 goto no_loop;
2161 goto redo;
2162 } else {
2163 no_loop:
2164 /* must send trailer now because eof or error */
2165 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2166 }
2167 }
2168 } else {
2169 /* update first pts if needed */
2170 if (c->first_pts == AV_NOPTS_VALUE)
2171 c->first_pts = pkt.pts;
2172
2173 /* send it to the appropriate stream */
2174 if (c->stream->feed) {
2175 /* if coming from a feed, select the right stream */
2176 if (c->switch_pending) {
2177 c->switch_pending = 0;
2178 for(i=0;i<c->stream->nb_streams;i++) {
2179 if (c->switch_feed_streams[i] == pkt.stream_index) {
2180 if (pkt.flags & PKT_FLAG_KEY) {
2181 do_switch_stream(c, i);
2182 }
2183 }
2184 if (c->switch_feed_streams[i] >= 0) {
2185 c->switch_pending = 1;
2186 }
2187 }
2188 }
2189 for(i=0;i<c->stream->nb_streams;i++) {
2190 if (c->feed_streams[i] == pkt.stream_index) {
2191 pkt.stream_index = i;
2192 if (pkt.flags & PKT_FLAG_KEY) {
2193 c->got_key_frame |= 1 << i;
2194 }
2195 /* See if we have all the key frames, then
2196 * we start to send. This logic is not quite
2197 * right, but it works for the case of a
2198 * single video stream with one or more
2199 * audio streams (for which every frame is
2200 * typically a key frame).
2201 */
2202 if (!c->stream->send_on_key ||
2203 ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2204 goto send_it;
2205 }
2206 }
2207 }
2208 } else {
2209 AVCodecContext *codec;
2210
2211 send_it:
2212 /* specific handling for RTP: we use several
2213 output stream (one for each RTP
2214 connection). XXX: need more abstract handling */
2215 if (c->is_packetized) {
2216 c->packet_stream_index = pkt.stream_index;
2217 ctx = c->rtp_ctx[c->packet_stream_index];
2218 codec = &ctx->streams[0]->codec;
2219 /* only one stream per RTP connection */
2220 pkt.stream_index = 0;
2221 } else {
2222 ctx = &c->fmt_ctx;
2223 /* Fudge here */
2224 codec = &ctx->streams[pkt.stream_index]->codec;
2225 }
2226
2227 codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2228
2229 #ifdef PJSG
2230 if (codec->codec_type == CODEC_TYPE_AUDIO) {
2231 codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
2232 /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
2233 }
2234 #endif
2235
2236 if (c->is_packetized) {
2237 ret = url_open_dyn_packet_buf(&ctx->pb,
2238 url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]));
2239 c->packet_byte_count = 0;
2240 c->packet_start_time_us = av_gettime();
2241 } else {
2242 ret = url_open_dyn_buf(&ctx->pb);
2243 }
2244 if (ret < 0) {
2245 /* XXX: potential leak */
2246 return -1;
2247 }
2248 if (av_write_frame(ctx, pkt.stream_index, pkt.data, pkt.size)) {
2249 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2250 }
2251
2252 len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2253 c->buffer_ptr = c->pb_buffer;
2254 c->buffer_end = c->pb_buffer + len;
2255
2256 codec->frame_number++;
2257 }
2258 #ifndef AV_READ_FRAME
2259 av_free_packet(&pkt);
2260 #endif
2261 }
2262 }
2263 }
2264 break;
2265 default:
2266 case HTTPSTATE_SEND_DATA_TRAILER:
2267 /* last packet test ? */
2268 if (c->last_packet_sent || c->is_packetized)
2269 return -1;
2270 ctx = &c->fmt_ctx;
2271 /* prepare header */
2272 if (url_open_dyn_buf(&ctx->pb) < 0) {
2273 /* XXX: potential leak */
2274 return -1;
2275 }
2276 av_write_trailer(ctx);
2277 len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2278 c->buffer_ptr = c->pb_buffer;
2279 c->buffer_end = c->pb_buffer + len;
2280
2281 c->last_packet_sent = 1;
2282 break;
2283 }
2284 return 0;
2285 }
2286
2287 /* in bit/s */
2288 #define SHORT_TERM_BANDWIDTH 8000000
2289
2290 /* should convert the format at the same time */
2291 static int http_send_data(HTTPContext *c)
2292 {
2293 int len, ret, dt;
2294
2295 while (c->buffer_ptr >= c->buffer_end) {
2296 av_freep(&c->pb_buffer);
2297 ret = http_prepare_data(c);
2298 if (ret < 0)
2299 return -1;
2300 else if (ret == 0) {
2301 continue;
2302 } else {
2303 /* state change requested */
2304 return 0;
2305 }
2306 }
2307
2308 if (c->buffer_ptr < c->buffer_end) {
2309 if (c->is_packetized) {
2310 /* RTP/UDP data output */
2311 len = c->buffer_end - c->buffer_ptr;
2312 if (len < 4) {
2313 /* fail safe - should never happen */
2314 fail1:
2315 c->buffer_ptr = c->buffer_end;
2316 return 0;
2317 }
2318 len = (c->buffer_ptr[0] << 24) |
2319 (c->buffer_ptr[1] << 16) |
2320 (c->buffer_ptr[2] << 8) |
2321 (c->buffer_ptr[3]);
2322 if (len > (c->buffer_end - c->buffer_ptr))
2323 goto fail1;
2324
2325 /* short term bandwidth limitation */
2326 dt = av_gettime() - c->packet_start_time_us;
2327 if (dt < 1)
2328 dt = 1;
2329
2330 if ((c->packet_byte_count + len) * (INT64)1000000 >=
2331 (SHORT_TERM_BANDWIDTH / 8) * (INT64)dt) {
2332 /* bandwidth overflow : wait at most one tick and retry */
2333 c->state = HTTPSTATE_WAIT_SHORT;
2334 return 0;
2335 }
2336
2337 c->buffer_ptr += 4;
2338 url_write(c->rtp_handles[c->packet_stream_index],
2339 c->buffer_ptr, len);
2340 c->buffer_ptr += len;
2341 c->packet_byte_count += len;
2342 } else {
2343 /* TCP data output */
2344 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2345 if (len < 0) {
2346 if (errno != EAGAIN && errno != EINTR) {
2347 /* error : close connection */
2348 return -1;
2349 } else {
2350 return 0;
2351 }
2352 } else {
2353 c->buffer_ptr += len;
2354 }
2355 }
2356 c->data_count += len;
2357 update_datarate(&c->datarate, c->data_count);
2358 if (c->stream)
2359 c->stream->bytes_served += len;
2360 }
2361 return 0;
2362 }
2363
2364 static int http_start_receive_data(HTTPContext *c)
2365 {
2366 int fd;
2367
2368 if (c->stream->feed_opened)
2369 return -1;
2370
2371 /* open feed */
2372 fd = open(c->stream->feed_filename, O_RDWR);
2373 if (fd < 0)
2374 return -1;
2375 c->feed_fd = fd;
2376
2377 c->stream->feed_write_index = ffm_read_write_index(fd);
2378 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2379 lseek(fd, 0, SEEK_SET);
2380
2381 /* init buffer input */
2382 c->buffer_ptr = c->buffer;
2383 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2384 c->stream->feed_opened = 1;
2385 return 0;
2386 }
2387
2388 static int http_receive_data(HTTPContext *c)
2389 {
2390 HTTPContext *c1;
2391
2392 if (c->buffer_end > c->buffer_ptr) {
2393 int len;
2394
2395 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2396 if (len < 0) {
2397 if (errno != EAGAIN && errno != EINTR) {
2398 /* error : close connection */
2399 goto fail;
2400 }
2401 } else if (len == 0) {
2402 /* end of connection : close it */
2403 goto fail;
2404 } else {
2405 c->buffer_ptr += len;
2406 c->data_count += len;
2407 update_datarate(&c->datarate, c->data_count);
2408 }
2409 }
2410
2411 if (c->buffer_ptr >= c->buffer_end) {
2412 FFStream *feed = c->stream;
2413 /* a packet has been received : write it in the store, except
2414 if header */
2415 if (c->data_count > FFM_PACKET_SIZE) {
2416
2417 // printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2418 /* XXX: use llseek or url_seek */
2419 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2420 write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2421
2422 feed->feed_write_index += FFM_PACKET_SIZE;
2423 /* update file size */
2424 if (feed->feed_write_index > c->stream->feed_size)
2425 feed->feed_size = feed->feed_write_index;
2426
2427 /* handle wrap around if max file size reached */
2428 if (feed->feed_write_index >= c->stream->feed_max_size)
2429 feed->feed_write_index = FFM_PACKET_SIZE;
2430
2431 /* write index */
2432 ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2433
2434 /* wake up any waiting connections */
2435 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2436 if (c1->state == HTTPSTATE_WAIT_FEED &&
2437 c1->stream->feed == c->stream->feed) {
2438 c1->state = HTTPSTATE_SEND_DATA;
2439 }
2440 }
2441 } else {
2442 /* We have a header in our hands that contains useful data */
2443 AVFormatContext s;
2444 AVInputFormat *fmt_in;
2445 ByteIOContext *pb = &s.pb;
2446 int i;
2447
2448 memset(&s, 0, sizeof(s));
2449
2450 url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2451 pb->buf_end = c->buffer_end; /* ?? */
2452 pb->is_streamed = 1;
2453
2454 /* use feed output format name to find corresponding input format */
2455 fmt_in = av_find_input_format(feed->fmt->name);
2456 if (!fmt_in)
2457 goto fail;
2458
2459 s.priv_data = av_mallocz(fmt_in->priv_data_size);
2460 if (!s.priv_data)
2461 goto fail;
2462
2463 if (fmt_in->read_header(&s, 0) < 0) {
2464 av_freep(&s.priv_data);
2465 goto fail;
2466 }
2467
2468 /* Now we have the actual streams */
2469 if (s.nb_streams != feed->nb_streams) {
2470 av_freep(&s.priv_data);
2471 goto fail;
2472 }
2473 for (i = 0; i < s.nb_streams; i++) {
2474 memcpy(&feed->streams[i]->codec,
2475 &s.streams[i]->codec, sizeof(AVCodecContext));
2476 }
2477 av_freep(&s.priv_data);
2478 }
2479 c->buffer_ptr = c->buffer;
2480 }
2481
2482 return 0;
2483 fail:
2484 c->stream->feed_opened = 0;
2485 close(c->feed_fd);
2486 return -1;
2487 }
2488
2489 /********************************************************************/
2490 /* RTSP handling */
2491
2492 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2493 {
2494 const char *str;
2495 time_t ti;
2496 char *p;
2497 char buf2[32];
2498
2499 switch(error_number) {
2500 #define DEF(n, c, s) case c: str = s; break;
2501 #include "rtspcodes.h"
2502 #undef DEF
2503 default:
2504 str = "Unknown Error";
2505 break;
2506 }
2507
2508 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2509 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2510
2511 /* output GMT time */
2512 ti = time(NULL);
2513 p = ctime(&ti);
2514 strcpy(buf2, p);
2515 p = buf2 + strlen(p) - 1;
2516 if (*p == '\n')
2517 *p = '\0';
2518 url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2519 }
2520
2521 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2522 {
2523 rtsp_reply_header(c, error_number);
2524 url_fprintf(c->pb, "\r\n");
2525 }
2526
2527 static int rtsp_parse_request(HTTPContext *c)
2528 {
2529 const char *p, *p1, *p2;
2530 char cmd[32];
2531 char url[1024];
2532 char protocol[32];
2533 char line[1024];
2534 ByteIOContext pb1;
2535 int len;
2536 RTSPHeader header1, *header = &header1;
2537
2538 c->buffer_ptr[0] = '\0';
2539 p = c->buffer;
2540
2541 get_word(cmd, sizeof(cmd), &p);
2542 get_word(url, sizeof(url), &p);
2543 get_word(protocol, sizeof(protocol), &p);
2544
2545 pstrcpy(c->method, sizeof(c->method), cmd);
2546 pstrcpy(c->url, sizeof(c->url), url);
2547 pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2548
2549 c->pb = &pb1;
2550 if (url_open_dyn_buf(c->pb) < 0) {
2551 /* XXX: cannot do more */
2552 c->pb = NULL; /* safety */
2553 return -1;
2554 }
2555
2556 /* check version name */
2557 if (strcmp(protocol, "RTSP/1.0") != 0) {
2558 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2559 goto the_end;
2560 }
2561
2562 /* parse each header line */
2563 memset(header, 0, sizeof(RTSPHeader));
2564 /* skip to next line */
2565 while (*p != '\n' && *p != '\0')
2566 p++;
2567 if (*p == '\n')
2568 p++;
2569 while (*p != '\0') {
2570 p1 = strchr(p, '\n');
2571 if (!p1)
2572 break;
2573 p2 = p1;
2574 if (p2 > p && p2[-1] == '\r')
2575 p2--;
2576 /* skip empty line */
2577 if (p2 == p)
2578 break;
2579 len = p2 - p;
2580 if (len > sizeof(line) - 1)
2581 len = sizeof(line) - 1;
2582 memcpy(line, p, len);
2583 line[len] = '\0';
2584 rtsp_parse_line(header, line);
2585 p = p1 + 1;
2586 }
2587
2588 /* handle sequence number */
2589 c->seq = header->seq;
2590
2591 if (!strcmp(cmd, "DESCRIBE")) {
2592 rtsp_cmd_describe(c, url);
2593 } else if (!strcmp(cmd, "SETUP")) {
2594 rtsp_cmd_setup(c, url, header);
2595 } else if (!strcmp(cmd, "PLAY")) {
2596 rtsp_cmd_play(c, url, header);
2597 } else if (!strcmp(cmd, "PAUSE")) {
2598 rtsp_cmd_pause(c, url, header);
2599 } else if (!strcmp(cmd, "TEARDOWN")) {
2600 rtsp_cmd_teardown(c, url, header);
2601 } else {
2602 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2603 }
2604 the_end:
2605 len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2606 c->pb = NULL; /* safety */
2607 if (len < 0) {
2608 /* XXX: cannot do more */
2609 return -1;
2610 }
2611 c->buffer_ptr = c->pb_buffer;
2612 c->buffer_end = c->pb_buffer + len;
2613 c->state = RTSPSTATE_SEND_REPLY;
2614 return 0;
2615 }
2616
2617 /* XXX: move that to rtsp.c, but would need to replace FFStream by
2618 AVFormatContext */
2619 static int prepare_sdp_description(FFStream *stream, UINT8 **pbuffer,
2620 struct in_addr my_ip)
2621 {
2622 ByteIOContext pb1, *pb = &pb1;
2623 int i, payload_type, port, private_payload_type, j;
2624 const char *ipstr, *title, *mediatype;
2625 AVStream *st;
2626
2627 if (url_open_dyn_buf(pb) < 0)
2628 return -1;
2629
2630 /* general media info */
2631
2632 url_fprintf(pb, "v=0\n");
2633 ipstr = inet_ntoa(my_ip);
2634 url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2635 title = stream->title;
2636 if (title[0] == '\0')
2637 title = "No Title";
2638 url_fprintf(pb, "s=%s\n", title);
2639 if (stream->comment[0] != '\0')
2640 url_fprintf(pb, "i=%s\n", stream->comment);
2641 if (stream->is_multicast) {
2642 url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2643 }
2644 /* for each stream, we output the necessary info */
2645 private_payload_type = 96;
2646 for(i = 0; i < stream->nb_streams; i++) {
2647 st = stream->streams[i];
2648 switch(st->codec.codec_type) {
2649 case CODEC_TYPE_AUDIO:
2650 mediatype = "audio";
2651 break;
2652 case CODEC_TYPE_VIDEO:
2653 mediatype = "video";
2654 break;
2655 default:
2656 mediatype = "application";
2657 break;
2658 }
2659 /* NOTE: the port indication is not correct in case of
2660 unicast. It is not an issue because RTSP gives it */
2661 payload_type = rtp_get_payload_type(&st->codec);
2662 if (payload_type < 0)
2663 payload_type = private_payload_type++;
2664 if (stream->is_multicast) {
2665 port = stream->multicast_port + 2 * i;
2666 } else {
2667 port = 0;
2668 }
2669 url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2670 mediatype, port, payload_type);
2671 if (payload_type >= 96) {
2672 /* for private payload type, we need to give more info */
2673 switch(st->codec.codec_id) {
2674 case CODEC_ID_MPEG4:
2675 {
2676 uint8_t *data;
2677 url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2678 payload_type, 90000);
2679 /* we must also add the mpeg4 header */
2680 data = st->codec.extradata;
2681 if (data) {
2682 url_fprintf(pb, "a=fmtp:%d config=");
2683 for(j=0;j<st->codec.extradata_size;j++) {
2684 url_fprintf(pb, "%02x", data[j]);
2685 }
2686 url_fprintf(pb, "\n");
2687 }
2688 }
2689 break;
2690 default:
2691 /* XXX: add other codecs ? */
2692 goto fail;
2693 }
2694 }
2695 url_fprintf(pb, "a=control:streamid=%d\n", i);
2696 }
2697 return url_close_dyn_buf(pb, pbuffer);
2698 fail:
2699 url_close_dyn_buf(pb, pbuffer);
2700 av_free(*pbuffer);
2701 return -1;
2702 }
2703
2704 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2705 {
2706 FFStream *stream;
2707 char path1[1024];
2708 const char *path;
2709 UINT8 *content;
2710 int content_length, len;
2711 struct sockaddr_in my_addr;
2712
2713 /* find which url is asked */
2714 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2715 path = path1;
2716 if (*path == '/')
2717 path++;
2718
2719 for(stream = first_stream; stream != NULL; stream = stream->next) {
2720 if (!stream->is_feed && stream->fmt == &rtp_mux &&
2721 !strcmp(path, stream->filename)) {
2722 goto found;
2723 }
2724 }
2725 /* no stream found */
2726 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2727 return;
2728
2729 found:
2730 /* prepare the media description in sdp format */
2731
2732 /* get the host IP */
2733 len = sizeof(my_addr);
2734 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2735
2736 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2737 if (content_length < 0) {
2738 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2739 return;
2740 }
2741 rtsp_reply_header(c, RTSP_STATUS_OK);
2742 url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2743 url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2744 url_fprintf(c->pb, "\r\n");
2745 put_buffer(c->pb, content, content_length);
2746 }
2747
2748 static HTTPContext *find_rtp_session(const char *session_id)
2749 {
2750 HTTPContext *c;
2751
2752 if (session_id[0] == '\0')
2753 return NULL;
2754
2755 for(c = first_http_ctx; c != NULL; c = c->next) {
2756 if (!strcmp(c->session_id, session_id))
2757 return c;
2758 }
2759 return NULL;
2760 }
2761
2762 RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2763 {
2764 RTSPTransportField *th;
2765 int i;
2766
2767 for(i=0;i<h->nb_transports;i++) {
2768 th = &h->transports[i];
2769 if (th->protocol == protocol)
2770 return th;
2771 }
2772 return NULL;
2773 }
2774
2775 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2776 RTSPHeader *h)
2777 {
2778 FFStream *stream;
2779 int stream_index, port;
2780 char buf[1024];
2781 char path1[1024];
2782 const char *path;
2783 HTTPContext *rtp_c;
2784 RTSPTransportField *th;
2785 struct sockaddr_in dest_addr;
2786 RTSPActionServerSetup setup;
2787
2788 /* find which url is asked */
2789 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2790 path = path1;
2791 if (*path == '/')
2792 path++;
2793
2794 /* now check each stream */
2795 for(stream = first_stream; stream != NULL; stream = stream->next) {
2796 if (!stream->is_feed && stream->fmt == &rtp_mux) {
2797 /* accept aggregate filenames only if single stream */
2798 if (!strcmp(path, stream->filename)) {
2799 if (stream->nb_streams != 1) {
2800 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2801 return;
2802 }
2803 stream_index = 0;
2804 goto found;
2805 }
2806
2807 for(stream_index = 0; stream_index < stream->nb_streams;
2808 stream_index++) {
2809 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2810 stream->filename, stream_index);
2811 if (!strcmp(path, buf))
2812 goto found;
2813 }
2814 }
2815 }
2816 /* no stream found */
2817 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2818 return;
2819 found:
2820
2821 /* generate session id if needed */
2822 if (h->session_id[0] == '\0') {
2823 snprintf(h->session_id, sizeof(h->session_id),
2824 "%08x%08x", (int)random(), (int)random());
2825 }
2826
2827 /* find rtp session, and create it if none found */
2828 rtp_c = find_rtp_session(h->session_id);
2829 if (!rtp_c) {
2830 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id);
2831 if (!rtp_c) {
2832 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2833 return;
2834 }
2835
2836 /* open input stream */
2837 if (open_input_stream(rtp_c, "") < 0) {
2838 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2839 return;
2840 }
2841
2842 /* always prefer UDP */
2843 th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2844 if (!th) {
2845 th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2846 if (!th) {
2847 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2848 return;
2849 }
2850 }
2851 rtp_c->rtp_protocol = th->protocol;
2852 }
2853
2854 /* test if stream is OK (test needed because several SETUP needs
2855 to be done for a given file) */
2856 if (rtp_c->stream != stream) {
2857 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2858 return;
2859 }
2860
2861 /* test if stream is already set up */
2862 if (rtp_c->rtp_ctx[stream_index]) {
2863 rtsp_reply_error(c, RTSP_STATUS_STATE);
2864 return;
2865 }
2866
2867 /* check transport */
2868 th = find_transport(h, rtp_c->rtp_protocol);
2869 if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2870 th->client_port_min <= 0)) {
2871 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2872 return;
2873 }
2874
2875 /* setup default options */
2876 setup.transport_option[0] = '\0';
2877 dest_addr = rtp_c->from_addr;
2878 dest_addr.sin_port = htons(th->client_port_min);
2879
2880 /* add transport option if needed */
2881 if (ff_rtsp_callback) {
2882 setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2883 if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2884 (char *)&setup, sizeof(setup),
2885 stream->rtsp_option) < 0) {
2886 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2887 return;
2888 }
2889 dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2890 }
2891
2892 /* setup stream */
2893 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
2894 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2895 return;
2896 }
2897
2898 /* now everything is OK, so we can send the connection parameters */
2899 rtsp_reply_header(c, RTSP_STATUS_OK);
2900 /* session ID */
2901 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2902
2903 switch(rtp_c->rtp_protocol) {
2904 case RTSP_PROTOCOL_RTP_UDP:
2905 port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2906 url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2907 "client_port=%d-%d;server_port=%d-%d",
2908 th->client_port_min, th->client_port_min + 1,
2909 port, port + 1);
2910 break;
2911 case RTSP_PROTOCOL_RTP_TCP:
2912 url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2913 stream_index * 2, stream_index * 2 + 1);
2914 break;
2915 default:
2916 break;
2917 }
2918 if (setup.transport_option[0] != '\0') {
2919 url_fprintf(c->pb, ";%s", setup.transport_option);
2920 }
2921 url_fprintf(c->pb, "\r\n");
2922
2923
2924 url_fprintf(c->pb, "\r\n");
2925 }
2926
2927
2928 /* find an rtp connection by using the session ID. Check consistency
2929 with filename */
2930 static HTTPContext *find_rtp_session_with_url(const char *url,
2931 const char *session_id)
2932 {
2933 HTTPContext *rtp_c;
2934 char path1[1024];
2935 const char *path;
2936
2937 rtp_c = find_rtp_session(session_id);
2938 if (!rtp_c)
2939 return NULL;
2940
2941 /* find which url is asked */
2942 url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2943 path = path1;
2944 if (*path == '/')
2945 path++;
2946 if (strcmp(path, rtp_c->stream->filename) != 0)
2947 return NULL;
2948 return rtp_c;
2949 }
2950
2951 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2952 {
2953 HTTPContext *rtp_c;
2954
2955 rtp_c = find_rtp_session_with_url(url, h->session_id);
2956 if (!rtp_c) {
2957 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2958 return;
2959 }
2960
2961 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2962 rtp_c->state != HTTPSTATE_WAIT_FEED &&
2963 rtp_c->state != HTTPSTATE_READY) {
2964 rtsp_reply_error(c, RTSP_STATUS_STATE);
2965 return;
2966 }
2967
2968 rtp_c->state = HTTPSTATE_SEND_DATA;
2969
2970 /* now everything is OK, so we can send the connection parameters */
2971 rtsp_reply_header(c, RTSP_STATUS_OK);
2972 /* session ID */
2973 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2974 url_fprintf(c->pb, "\r\n");
2975 }
2976
2977 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2978 {
2979 HTTPContext *rtp_c;
2980
2981 rtp_c = find_rtp_session_with_url(url, h->session_id);
2982 if (!rtp_c) {
2983 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2984 return;
2985 }
2986
2987 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2988 rtp_c->state != HTTPSTATE_WAIT_FEED) {
2989 rtsp_reply_error(c, RTSP_STATUS_STATE);
2990 return;
2991 }
2992
2993 rtp_c->state = HTTPSTATE_READY;
2994
2995 /* now everything is OK, so we can send the connection parameters */
2996 rtsp_reply_header(c, RTSP_STATUS_OK);
2997 /* session ID */
2998 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2999 url_fprintf(c->pb, "\r\n");
3000 }
3001
3002 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3003 {
3004 HTTPContext *rtp_c;
3005
3006 rtp_c = find_rtp_session_with_url(url, h->session_id);
3007 if (!rtp_c) {
3008 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3009 return;
3010 }
3011
3012 /* abort the session */
3013 close_connection(rtp_c);
3014
3015 if (ff_rtsp_callback) {
3016 ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3017 NULL, 0,
3018 rtp_c->stream->rtsp_option);
3019 }
3020
3021 /* now everything is OK, so we can send the connection parameters */
3022 rtsp_reply_header(c, RTSP_STATUS_OK);
3023 /* session ID */
3024 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3025 url_fprintf(c->pb, "\r\n");
3026 }
3027
3028
3029 /********************************************************************/
3030 /* RTP handling */
3031
3032 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3033 FFStream *stream, const char *session_id)
3034 {
3035 HTTPContext *c = NULL;
3036
3037 /* XXX: should output a warning page when coming
3038 close to the connection limit */
3039 if (nb_connections >= nb_max_connections)
3040 goto fail;
3041
3042 /* add a new connection */
3043 c = av_mallocz(sizeof(HTTPContext));
3044 if (!c)
3045 goto fail;
3046
3047 c->fd = -1;
3048 c->poll_entry = NULL;
3049 c->from_addr = *from_addr;
3050 c->buffer_size = IOBUFFER_INIT_SIZE;
3051 c->buffer = av_malloc(c->buffer_size);
3052 if (!c->buffer)
3053 goto fail;
3054 nb_connections++;
3055 c->stream = stream;
3056 pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3057 c->state = HTTPSTATE_READY;
3058 c->is_packetized = 1;
3059 /* protocol is shown in statistics */
3060 pstrcpy(c->protocol, sizeof(c->protocol), "RTP");
3061
3062 current_bandwidth += stream->bandwidth;
3063
3064 c->next = first_http_ctx;
3065 first_http_ctx = c;
3066 return c;
3067
3068 fail:
3069 if (c) {
3070 av_free(c->buffer);
3071 av_free(c);
3072 }
3073 return NULL;
3074 }
3075
3076 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3077 command). if dest_addr is NULL, then TCP tunneling in RTSP is
3078 used. */
3079 static int rtp_new_av_stream(HTTPContext *c,
3080 int stream_index, struct sockaddr_in *dest_addr)
3081 {
3082 AVFormatContext *ctx;
3083 AVStream *st;
3084 char *ipaddr;
3085 URLContext *h;
3086 UINT8 *dummy_buf;
3087 char buf2[32];
3088
3089 /* now we can open the relevant output stream */
3090 ctx = av_mallocz(sizeof(AVFormatContext));
3091 if (!ctx)
3092 return -1;
3093 ctx->oformat = &rtp_mux;
3094
3095 st = av_mallocz(sizeof(AVStream));
3096 if (!st)
3097 goto fail;
3098 ctx->nb_streams = 1;
3099 ctx->streams[0] = st;
3100
3101 if (!c->stream->feed ||
3102 c->stream->feed == c->stream) {
3103 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3104 } else {
3105 memcpy(st,
3106 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3107 sizeof(AVStream));
3108 }
3109
3110 if (dest_addr) {
3111 /* build destination RTP address */
3112 ipaddr = inet_ntoa(dest_addr->sin_addr);
3113
3114 /* XXX: also pass as parameter to function ? */
3115 if (c->stream->is_multicast) {
3116 int ttl;
3117 ttl = c->stream->multicast_ttl;
3118 if (!ttl)
3119 ttl = 16;
3120 snprintf(ctx->filename, sizeof(ctx->filename),
3121 "rtp://%s:%d?multicast=1&ttl=%d",
3122 ipaddr, ntohs(dest_addr->sin_port), ttl);
3123 } else {
3124 snprintf(ctx->filename, sizeof(ctx->filename),
3125 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3126 }
3127
3128 if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3129 goto fail;
3130 c->rtp_handles[stream_index] = h;
3131 } else {
3132 goto fail;
3133 }
3134
3135 http_log("%s:%d - - [%s] \"RTPSTART %s/streamid=%d\"\n",
3136 ipaddr, ntohs(dest_addr->sin_port),
3137 ctime1(buf2),
3138 c->stream->filename, stream_index);
3139
3140 /* normally, no packets should be output here, but the packet size may be checked */
3141 if (url_open_dyn_packet_buf(&ctx->pb,
3142 url_get_max_packet_size(h)) < 0) {
3143 /* XXX: close stream */
3144 goto fail;
3145 }
3146 if (av_write_header(ctx) < 0) {
3147 fail:
3148 if (h)
3149 url_close(h);
3150 av_free(ctx);
3151 return -1;
3152 }
3153 url_close_dyn_buf(&ctx->pb, &dummy_buf);
3154 av_free(dummy_buf);
3155
3156 c->rtp_ctx[stream_index] = ctx;
3157 return 0;
3158 }
3159
3160 /********************************************************************/
3161 /* ffserver initialization */
3162
3163 AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3164 {
3165 AVStream *fst;
3166
3167 fst = av_mallocz(sizeof(AVStream));
3168 if (!fst)
3169 return NULL;
3170 fst->priv_data = av_mallocz(sizeof(FeedData));
3171 memcpy(&fst->codec, codec, sizeof(AVCodecContext));
3172 fst->codec.coded_frame = &dummy_frame;
3173 stream->streams[stream->nb_streams++] = fst;
3174 return fst;
3175 }
3176
3177 /* return the stream number in the feed */
3178 int add_av_stream(FFStream *feed,
3179 AVStream *st)
3180 {
3181 AVStream *fst;
3182 AVCodecContext *av, *av1;
3183 int i;
3184
3185 av = &st->codec;
3186 for(i=0;i<feed->nb_streams;i++) {
3187 st = feed->streams[i];
3188 av1 = &st->codec;
3189 if (av1->codec_id == av->codec_id &&
3190 av1->codec_type == av->codec_type &&
3191 av1->bit_rate == av->bit_rate) {
3192
3193 switch(av->codec_type) {
3194 case CODEC_TYPE_AUDIO:
3195 if (av1->channels == av->channels &&
3196 av1->sample_rate == av->sample_rate)
3197 goto found;
3198 break;
3199 case CODEC_TYPE_VIDEO:
3200 if (av1->width == av->width &&
3201 av1->height == av->height &&
3202 av1->frame_rate == av->frame_rate &&
3203 av1->gop_size == av->gop_size)
3204 goto found;
3205 break;
3206 default:
3207 av_abort();
3208 }
3209 }
3210 }
3211
3212 fst = add_av_stream1(feed, av);
3213 if (!fst)
3214 return -1;
3215 return feed->nb_streams - 1;
3216 found:
3217 return i;
3218 }
3219
3220 void remove_stream(FFStream *stream)
3221 {
3222 FFStream **ps;
3223 ps = &first_stream;
3224 while (*ps != NULL) {
3225 if (*ps == stream) {
3226 *ps = (*ps)->next;
3227 } else {
3228 ps = &(*ps)->next;
3229 }
3230 }
3231 }
3232
3233 /* specific mpeg4 handling : we extract the raw parameters */
3234 void extract_mpeg4_header(AVFormatContext *infile)
3235 {
3236 int mpeg4_count, i, size;
3237 AVPacket pkt;
3238 AVStream *st;
3239 const UINT8 *p;
3240
3241 mpeg4_count = 0;
3242 for(i=0;i<infile->nb_streams;i++) {
3243 st = infile->streams[i];
3244 if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3245 st->codec.extradata == NULL) {
3246 mpeg4_count++;
3247 }
3248 }
3249 if (!mpeg4_count)
3250 return;
3251
3252 printf("MPEG4 without extra data: trying to find header\n");
3253 while (mpeg4_count > 0) {
3254 if (av_read_packet(infile, &pkt) < 0)
3255 break;
3256 st = infile->streams[pkt.stream_index];
3257 if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3258 st->codec.extradata == NULL) {
3259 /* fill extradata with the header */
3260 /* XXX: we make hard suppositions here ! */
3261 p = pkt.data;
3262 while (p < pkt.data + pkt.size - 4) {
3263 /* stop when vop header is found */
3264 if (p[0] == 0x00 && p[1] == 0x00 &&
3265 p[2] == 0x01 && p[3] == 0xb6) {
3266 size = p - pkt.data;
3267 // av_hex_dump(pkt.data, size);
3268 st->codec.extradata = av_malloc(size);
3269 st->codec.extradata_size = size;
3270 memcpy(st->codec.extradata, pkt.data, size);
3271 break;
3272 }
3273 p++;
3274 }
3275 mpeg4_count--;
3276 }
3277 av_free_packet(&pkt);
3278 }
3279 }
3280
3281 /* compute the needed AVStream for each file */
3282 void build_file_streams(void)
3283 {
3284 FFStream *stream, *stream_next;
3285 AVFormatContext *infile;
3286 int i;
3287
3288 /* gather all streams */
3289