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