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