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