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