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