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