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