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