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