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