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