Use avf_sdp_create() in ffserver
[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 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2626 struct in_addr my_ip)
2627 {
2628 AVFormatContext *avc;
2629 AVStream avs[MAX_STREAMS];
2630 int i;
2631
2632 avc = av_alloc_format_context();
2633 if (avc == NULL) {
2634 return -1;
2635 }
2636 if (stream->title[0] != 0) {
2637 av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2638 } else {
2639 av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2640 }
2641 avc->nb_streams = stream->nb_streams;
2642 if (stream->is_multicast) {
2643 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2644 inet_ntoa(stream->multicast_ip),
2645 stream->multicast_port, stream->multicast_ttl);
2646 }
2647
2648 for(i = 0; i < stream->nb_streams; i++) {
2649 avc->streams[i] = &avs[i];
2650 avc->streams[i]->codec = stream->streams[i]->codec;
2651 }
2652 *pbuffer = av_mallocz(2048);
2653 avf_sdp_create(&avc, 1, *pbuffer, 2048);
2654 av_free(avc);
2655
2656 return strlen(*pbuffer);
2657 }
2658
2659 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2660 {
2661 // rtsp_reply_header(c, RTSP_STATUS_OK);
2662 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2663 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2664 url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2665 url_fprintf(c->pb, "\r\n");
2666 }
2667
2668 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2669 {
2670 FFStream *stream;
2671 char path1[1024];
2672 const char *path;
2673 uint8_t *content;
2674 int content_length, len;
2675 struct sockaddr_in my_addr;
2676
2677 /* find which url is asked */
2678 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2679 path = path1;
2680 if (*path == '/')
2681 path++;
2682
2683 for(stream = first_stream; stream != NULL; stream = stream->next) {
2684 if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2685 !strcmp(path, stream->filename)) {
2686 goto found;
2687 }
2688 }
2689 /* no stream found */
2690 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2691 return;
2692
2693 found:
2694 /* prepare the media description in sdp format */
2695
2696 /* get the host IP */
2697 len = sizeof(my_addr);
2698 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2699 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2700 if (content_length < 0) {
2701 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2702 return;
2703 }
2704 rtsp_reply_header(c, RTSP_STATUS_OK);
2705 url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2706 url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2707 url_fprintf(c->pb, "\r\n");
2708 put_buffer(c->pb, content, content_length);
2709 }
2710
2711 static HTTPContext *find_rtp_session(const char *session_id)
2712 {
2713 HTTPContext *c;
2714
2715 if (session_id[0] == '\0')
2716 return NULL;
2717
2718 for(c = first_http_ctx; c != NULL; c = c->next) {
2719 if (!strcmp(c->session_id, session_id))
2720 return c;
2721 }
2722 return NULL;
2723 }
2724
2725 static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2726 {
2727 RTSPTransportField *th;
2728 int i;
2729
2730 for(i=0;i<h->nb_transports;i++) {
2731 th = &h->transports[i];
2732 if (th->protocol == protocol)
2733 return th;
2734 }
2735 return NULL;
2736 }
2737
2738 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2739 RTSPHeader *h)
2740 {
2741 FFStream *stream;
2742 int stream_index, port;
2743 char buf[1024];
2744 char path1[1024];
2745 const char *path;
2746 HTTPContext *rtp_c;
2747 RTSPTransportField *th;
2748 struct sockaddr_in dest_addr;
2749 RTSPActionServerSetup setup;
2750
2751 /* find which url is asked */
2752 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2753 path = path1;
2754 if (*path == '/')
2755 path++;
2756
2757 /* now check each stream */
2758 for(stream = first_stream; stream != NULL; stream = stream->next) {
2759 if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2760 /* accept aggregate filenames only if single stream */
2761 if (!strcmp(path, stream->filename)) {
2762 if (stream->nb_streams != 1) {
2763 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2764 return;
2765 }
2766 stream_index = 0;
2767 goto found;
2768 }
2769
2770 for(stream_index = 0; stream_index < stream->nb_streams;
2771 stream_index++) {
2772 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2773 stream->filename, stream_index);
2774 if (!strcmp(path, buf))
2775 goto found;
2776 }
2777 }
2778 }
2779 /* no stream found */
2780 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2781 return;
2782 found:
2783
2784 /* generate session id if needed */
2785 if (h->session_id[0] == '\0')
2786 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2787 av_random(&random_state), av_random(&random_state));
2788
2789 /* find rtp session, and create it if none found */
2790 rtp_c = find_rtp_session(h->session_id);
2791 if (!rtp_c) {
2792 /* always prefer UDP */
2793 th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2794 if (!th) {
2795 th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2796 if (!th) {
2797 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2798 return;
2799 }
2800 }
2801
2802 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2803 th->protocol);
2804 if (!rtp_c) {
2805 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2806 return;
2807 }
2808
2809 /* open input stream */
2810 if (open_input_stream(rtp_c, "") < 0) {
2811 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2812 return;
2813 }
2814 }
2815
2816 /* test if stream is OK (test needed because several SETUP needs
2817 to be done for a given file) */
2818 if (rtp_c->stream != stream) {
2819 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2820 return;
2821 }
2822
2823 /* test if stream is already set up */
2824 if (rtp_c->rtp_ctx[stream_index]) {
2825 rtsp_reply_error(c, RTSP_STATUS_STATE);
2826 return;
2827 }
2828
2829 /* check transport */
2830 th = find_transport(h, rtp_c->rtp_protocol);
2831 if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2832 th->client_port_min <= 0)) {
2833 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2834 return;
2835 }
2836
2837 /* setup default options */
2838 setup.transport_option[0] = '\0';
2839 dest_addr = rtp_c->from_addr;
2840 dest_addr.sin_port = htons(th->client_port_min);
2841
2842 /* setup stream */
2843 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2844 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2845 return;
2846 }
2847
2848 /* now everything is OK, so we can send the connection parameters */
2849 rtsp_reply_header(c, RTSP_STATUS_OK);
2850 /* session ID */
2851 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2852
2853 switch(rtp_c->rtp_protocol) {
2854 case RTSP_PROTOCOL_RTP_UDP:
2855 port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2856 url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2857 "client_port=%d-%d;server_port=%d-%d",
2858 th->client_port_min, th->client_port_min + 1,
2859 port, port + 1);
2860 break;
2861 case RTSP_PROTOCOL_RTP_TCP:
2862 url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2863 stream_index * 2, stream_index * 2 + 1);
2864 break;
2865 default:
2866 break;
2867 }
2868 if (setup.transport_option[0] != '\0')
2869 url_fprintf(c->pb, ";%s", setup.transport_option);
2870 url_fprintf(c->pb, "\r\n");
2871
2872
2873 url_fprintf(c->pb, "\r\n");
2874 }
2875
2876
2877 /* find an rtp connection by using the session ID. Check consistency
2878 with filename */
2879 static HTTPContext *find_rtp_session_with_url(const char *url,
2880 const char *session_id)
2881 {
2882 HTTPContext *rtp_c;
2883 char path1[1024];
2884 const char *path;
2885 char buf[1024];
2886 int s;
2887
2888 rtp_c = find_rtp_session(session_id);
2889 if (!rtp_c)
2890 return NULL;
2891
2892 /* find which url is asked */
2893 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2894 path = path1;
2895 if (*path == '/')
2896 path++;
2897 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2898 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2899 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2900 rtp_c->stream->filename, s);
2901 if(!strncmp(path, buf, sizeof(buf))) {
2902 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2903 return rtp_c;
2904 }
2905 }
2906 return NULL;
2907 }
2908
2909 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2910 {
2911 HTTPContext *rtp_c;
2912
2913 rtp_c = find_rtp_session_with_url(url, h->session_id);
2914 if (!rtp_c) {
2915 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2916 return;
2917 }
2918
2919 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2920 rtp_c->state != HTTPSTATE_WAIT_FEED &&
2921 rtp_c->state != HTTPSTATE_READY) {
2922 rtsp_reply_error(c, RTSP_STATUS_STATE);
2923 return;
2924 }
2925
2926 #if 0
2927 /* XXX: seek in stream */
2928 if (h->range_start != AV_NOPTS_VALUE) {
2929 printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2930 av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2931 }
2932 #endif
2933
2934 rtp_c->state = HTTPSTATE_SEND_DATA;
2935
2936 /* now everything is OK, so we can send the connection parameters */
2937 rtsp_reply_header(c, RTSP_STATUS_OK);
2938 /* session ID */
2939 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2940 url_fprintf(c->pb, "\r\n");
2941 }
2942
2943 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2944 {
2945 HTTPContext *rtp_c;
2946
2947 rtp_c = find_rtp_session_with_url(url, h->session_id);
2948 if (!rtp_c) {
2949 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2950 return;
2951 }
2952
2953 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2954 rtp_c->state != HTTPSTATE_WAIT_FEED) {
2955 rtsp_reply_error(c, RTSP_STATUS_STATE);
2956 return;
2957 }
2958
2959 rtp_c->state = HTTPSTATE_READY;
2960 rtp_c->first_pts = AV_NOPTS_VALUE;
2961 /* now everything is OK, so we can send the connection parameters */
2962 rtsp_reply_header(c, RTSP_STATUS_OK);
2963 /* session ID */
2964 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2965 url_fprintf(c->pb, "\r\n");
2966 }
2967
2968 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2969 {
2970 HTTPContext *rtp_c;
2971 char session_id[32];
2972
2973 rtp_c = find_rtp_session_with_url(url, h->session_id);
2974 if (!rtp_c) {
2975 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2976 return;
2977 }
2978
2979 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
2980
2981 /* abort the session */
2982 close_connection(rtp_c);
2983
2984 /* now everything is OK, so we can send the connection parameters */
2985 rtsp_reply_header(c, RTSP_STATUS_OK);
2986 /* session ID */
2987 url_fprintf(c->pb, "Session: %s\r\n", session_id);
2988 url_fprintf(c->pb, "\r\n");
2989 }
2990
2991
2992 /********************************************************************/
2993 /* RTP handling */
2994
2995 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
2996 FFStream *stream, const char *session_id,
2997 enum RTSPProtocol rtp_protocol)
2998 {
2999 HTTPContext *c = NULL;
3000 const char *proto_str;
3001
3002 /* XXX: should output a warning page when coming
3003 close to the connection limit */
3004 if (nb_connections >= nb_max_connections)
3005 goto fail;
3006
3007 /* add a new connection */
3008 c = av_mallocz(sizeof(HTTPContext));
3009 if (!c)
3010 goto fail;
3011
3012 c->fd = -1;
3013 c->poll_entry = NULL;
3014 c->from_addr = *from_addr;
3015 c->buffer_size = IOBUFFER_INIT_SIZE;
3016 c->buffer = av_malloc(c->buffer_size);
3017 if (!c->buffer)
3018 goto fail;
3019 nb_connections++;
3020 c->stream = stream;
3021 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3022 c->state = HTTPSTATE_READY;
3023 c->is_packetized = 1;
3024 c->rtp_protocol = rtp_protocol;
3025
3026 /* protocol is shown in statistics */
3027 switch(c->rtp_protocol) {
3028 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3029 proto_str = "MCAST";
3030 break;
3031 case RTSP_PROTOCOL_RTP_UDP:
3032 proto_str = "UDP";
3033 break;
3034 case RTSP_PROTOCOL_RTP_TCP:
3035 proto_str = "TCP";
3036 break;
3037 default:
3038 proto_str = "???";
3039 break;
3040 }
3041 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3042 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3043
3044 current_bandwidth += stream->bandwidth;
3045
3046 c->next = first_http_ctx;
3047 first_http_ctx = c;
3048 return c;
3049
3050 fail:
3051 if (c) {
3052 av_free(c->buffer);
3053 av_free(c);
3054 }
3055 return NULL;
3056 }
3057
3058 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3059 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3060 used. */
3061 static int rtp_new_av_stream(HTTPContext *c,
3062 int stream_index, struct sockaddr_in *dest_addr,
3063 HTTPContext *rtsp_c)
3064 {
3065 AVFormatContext *ctx;
3066 AVStream *st;
3067 char *ipaddr;
3068 URLContext *h;
3069 uint8_t *dummy_buf;
3070 char buf2[32];
3071 int max_packet_size;
3072
3073 /* now we can open the relevant output stream */
3074 ctx = av_alloc_format_context();
3075 if (!ctx)
3076 return -1;
3077 ctx->oformat = &rtp_muxer;
3078
3079 st = av_mallocz(sizeof(AVStream));
3080 if (!st)
3081 goto fail;
3082 st->codec= avcodec_alloc_context();
3083 ctx->nb_streams = 1;
3084 ctx->streams[0] = st;
3085
3086 if (!c->stream->feed ||
3087 c->stream->feed == c->stream)
3088 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3089 else
3090 memcpy(st,
3091 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3092 sizeof(AVStream));
3093 st->priv_data = NULL;
3094
3095 /* build destination RTP address */
3096 ipaddr = inet_ntoa(dest_addr->sin_addr);
3097
3098 switch(c->rtp_protocol) {
3099 case RTSP_PROTOCOL_RTP_UDP:
3100 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3101 /* RTP/UDP case */
3102
3103 /* XXX: also pass as parameter to function ? */
3104 if (c->stream->is_multicast) {
3105 int ttl;
3106 ttl = c->stream->multicast_ttl;
3107 if (!ttl)
3108 ttl = 16;
3109 snprintf(ctx->filename, sizeof(ctx->filename),
3110 "rtp://%s:%d?multicast=1&ttl=%d",
3111 ipaddr, ntohs(dest_addr->sin_port), ttl);
3112 } else {
3113 snprintf(ctx->filename, sizeof(ctx->filename),
3114 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3115 }
3116
3117 if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3118 goto fail;
3119 c->rtp_handles[stream_index] = h;
3120 max_packet_size = url_get_max_packet_size(h);
3121 break;
3122 case RTSP_PROTOCOL_RTP_TCP:
3123 /* RTP/TCP case */
3124 c->rtsp_c = rtsp_c;
3125 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3126 break;
3127 default:
3128 goto fail;
3129 }
3130
3131 http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3132 ipaddr, ntohs(dest_addr->sin_port),
3133 ctime1(buf2),
3134 c->stream->filename, stream_index, c->protocol);
3135
3136 /* normally, no packets should be output here, but the packet size may be checked */
3137 if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3138 /* XXX: close stream */
3139 goto fail;
3140 }
3141 av_set_parameters(ctx, NULL);
3142 if (av_write_header(ctx) < 0) {
3143 fail:
3144 if (h)
3145 url_close(h);
3146 av_free(ctx);
3147 return -1;
3148 }
3149 url_close_dyn_buf(&ctx->pb, &dummy_buf);
3150 av_free(dummy_buf);
3151
3152 c->rtp_ctx[stream_index] = ctx;
3153 return 0;
3154 }
3155
3156 /********************************************************************/
3157 /* ffserver initialization */
3158
3159 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3160 {
3161 AVStream *fst;
3162
3163 fst = av_mallocz(sizeof(AVStream));
3164 if (!fst)
3165 return NULL;
3166 fst->codec= avcodec_alloc_context();
3167 fst->priv_data = av_mallocz(sizeof(FeedData));
3168 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3169 fst->codec->coded_frame = &dummy_frame;
3170 fst->index = stream->nb_streams;
3171 av_set_pts_info(fst, 33, 1, 90000);
3172 stream->streams[stream->nb_streams++] = fst;
3173 return fst;
3174 }
3175
3176 /* return the stream number in the feed */
3177 static int add_av_stream(FFStream *feed, AVStream *st)
3178 {
3179 AVStream *fst;
3180 AVCodecContext *av, *av1;
3181 int i;
3182
3183 av = st->codec;
3184 for(i=0;i<feed->nb_streams;i++) {
3185 st = feed->streams[i];
3186 av1 = st->codec;
3187 if (av1->codec_id == av->codec_id &&
3188 av1->codec_type == av->codec_type &&
3189 av1->bit_rate == av->bit_rate) {
3190
3191 switch(av->codec_type) {
3192 case CODEC_TYPE_AUDIO:
3193 if (av1->channels == av->channels &&
3194 av1->sample_rate == av->sample_rate)
3195 goto found;
3196 break;
3197 case CODEC_TYPE_VIDEO:
3198 if (av1->width == av->width &&
3199 av1->height == av->height &&
3200 av1->time_base.den == av->time_base.den &&
3201 av1->time_base.num == av->time_base.num &&
3202 av1->gop_size == av->gop_size)
3203 goto found;
3204 break;
3205 default:
3206 abort();
3207 }
3208 }
3209 }
3210
3211 fst = add_av_stream1(feed, av);
3212 if (!fst)
3213 return -1;
3214 return feed->nb_streams - 1;
3215 found:
3216 return i;
3217 }
3218
3219 static void remove_stream(FFStream *stream)
3220 {
3221 FFStream **ps;