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