* Go faster stripes: don't check to see if the user presses 'q' if stdin
[libav.git] / ffserver.c
CommitLineData
85f07f22
FB
1/*
2 * Multiple format streaming server
773a21b8 3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
85f07f22 4 *
773a21b8
FB
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
85f07f22 9 *
773a21b8 10 * This library is distributed in the hope that it will be useful,
85f07f22 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
773a21b8
FB
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
85f07f22 14 *
773a21b8
FB
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
85f07f22 18 */
773a21b8
FB
19#define HAVE_AV_CONFIG_H
20#include "avformat.h"
21
85f07f22 22#include <stdarg.h>
85f07f22
FB
23#include <netinet/in.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <sys/ioctl.h>
27#include <sys/poll.h>
28#include <errno.h>
29#include <sys/time.h>
30#include <time.h>
31#include <getopt.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <arpa/inet.h>
35#include <netdb.h>
36#include <ctype.h>
37#include <signal.h>
85f07f22
FB
38
39/* maximum number of simultaneous HTTP connections */
40#define HTTP_MAX_CONNECTIONS 2000
41
42enum HTTPState {
43 HTTPSTATE_WAIT_REQUEST,
44 HTTPSTATE_SEND_HEADER,
45 HTTPSTATE_SEND_DATA_HEADER,
46 HTTPSTATE_SEND_DATA,
47 HTTPSTATE_SEND_DATA_TRAILER,
48 HTTPSTATE_RECEIVE_DATA,
49 HTTPSTATE_WAIT_FEED,
50};
51
52const char *http_state[] = {
53 "WAIT_REQUEST",
54 "SEND_HEADER",
55 "SEND_DATA_HEADER",
56 "SEND_DATA",
57 "SEND_DATA_TRAILER",
58 "RECEIVE_DATA",
59 "WAIT_FEED",
60};
61
f747e6d3
PG
62#define IOBUFFER_MAX_SIZE 32768
63#define PACKET_MAX_SIZE 16384
85f07f22
FB
64
65/* coef for exponential mean for bitrate estimation in statistics */
66#define AVG_COEF 0.9
67
68/* timeouts are in ms */
69#define REQUEST_TIMEOUT (15 * 1000)
70#define SYNC_TIMEOUT (10 * 1000)
71
72/* context associated with one connection */
73typedef struct HTTPContext {
74 enum HTTPState state;
75 int fd; /* socket file descriptor */
76 struct sockaddr_in from_addr; /* origin */
77 struct pollfd *poll_entry; /* used when polling */
78 long timeout;
85f07f22
FB
79 UINT8 *buffer_ptr, *buffer_end;
80 int http_error;
81 struct HTTPContext *next;
42a63c6a 82 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
85f07f22
FB
83 INT64 data_count;
84 /* feed input */
85 int feed_fd;
86 /* input format handling */
87 AVFormatContext *fmt_in;
88 /* output format handling */
89 struct FFStream *stream;
90 AVFormatContext fmt_ctx;
91 int last_packet_sent; /* true if last data packet was sent */
7434ba6d 92 int suppress_log;
42a63c6a 93 int bandwidth;
ec3b2232 94 time_t start_time;
3120d2a2 95 int wmp_client_id;
7434ba6d
PG
96 char protocol[16];
97 char method[16];
98 char url[128];
f747e6d3
PG
99 UINT8 buffer[IOBUFFER_MAX_SIZE];
100 UINT8 pbuffer[PACKET_MAX_SIZE];
85f07f22
FB
101} HTTPContext;
102
103/* each generated stream is described here */
104enum StreamType {
105 STREAM_TYPE_LIVE,
106 STREAM_TYPE_STATUS,
107};
108
109/* description of each stream of the ffserver.conf file */
110typedef struct FFStream {
111 enum StreamType stream_type;
112 char filename[1024]; /* stream filename */
113 struct FFStream *feed;
bd7cf6ad 114 AVOutputFormat *fmt;
85f07f22 115 int nb_streams;
42a63c6a 116 int prebuffer; /* Number of millseconds early to start */
ec3b2232 117 time_t max_time;
79c4ea3c 118 int send_on_key;
85f07f22
FB
119 AVStream *streams[MAX_STREAMS];
120 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
121 char feed_filename[1024]; /* file name of the feed storage, or
122 input file name for a stream */
123 struct FFStream *next;
124 /* feed specific */
125 int feed_opened; /* true if someone if writing to feed */
126 int is_feed; /* true if it is a feed */
a6e14edd
PG
127 int conns_served;
128 INT64 bytes_served;
85f07f22
FB
129 INT64 feed_max_size; /* maximum storage size */
130 INT64 feed_write_index; /* current write position in feed (it wraps round) */
131 INT64 feed_size; /* current size of feed */
132 struct FFStream *next_feed;
133} FFStream;
134
135typedef struct FeedData {
136 long long data_count;
137 float avg_frame_size; /* frame size averraged over last frames with exponential mean */
138} FeedData;
139
140struct sockaddr_in my_addr;
141char logfilename[1024];
142HTTPContext *first_http_ctx;
143FFStream *first_feed; /* contains only feeds */
144FFStream *first_stream; /* contains all streams, including feeds */
145
146static int handle_http(HTTPContext *c, long cur_time);
147static int http_parse_request(HTTPContext *c);
148static int http_send_data(HTTPContext *c);
149static void compute_stats(HTTPContext *c);
150static int open_input_stream(HTTPContext *c, const char *info);
151static int http_start_receive_data(HTTPContext *c);
152static int http_receive_data(HTTPContext *c);
153
154int nb_max_connections;
155int nb_connections;
156
42a63c6a
PG
157int nb_max_bandwidth;
158int nb_bandwidth;
159
85f07f22
FB
160static long gettime_ms(void)
161{
162 struct timeval tv;
163
164 gettimeofday(&tv,NULL);
165 return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
166}
167
168static FILE *logfile = NULL;
169
170static void http_log(char *fmt, ...)
171{
172 va_list ap;
173 va_start(ap, fmt);
174
7434ba6d 175 if (logfile) {
85f07f22 176 vfprintf(logfile, fmt, ap);
7434ba6d
PG
177 fflush(logfile);
178 }
85f07f22
FB
179 va_end(ap);
180}
181
7434ba6d
PG
182static void log_connection(HTTPContext *c)
183{
184 char buf1[32], buf2[32], *p;
185 time_t ti;
186
187 if (c->suppress_log)
188 return;
189
190 /* XXX: reentrant function ? */
191 p = inet_ntoa(c->from_addr.sin_addr);
192 strcpy(buf1, p);
193 ti = time(NULL);
194 p = ctime(&ti);
195 strcpy(buf2, p);
196 p = buf2 + strlen(p) - 1;
197 if (*p == '\n')
198 *p = '\0';
3120d2a2
PG
199 http_log("%s - - [%s] \"%s %s %s\" %d %lld %s\n",
200 buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count,
201 c->stream ? c->stream->filename : "");
7434ba6d
PG
202}
203
85f07f22
FB
204/* main loop of the http server */
205static int http_server(struct sockaddr_in my_addr)
206{
207 int server_fd, tmp, ret;
208 struct sockaddr_in from_addr;
209 struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
210 HTTPContext *c, **cp;
211 long cur_time;
212
213 server_fd = socket(AF_INET,SOCK_STREAM,0);
214 if (server_fd < 0) {
215 perror ("socket");
216 return -1;
217 }
218
219 tmp = 1;
220 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
221
222 if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
223 perror ("bind");
224 close(server_fd);
225 return -1;
226 }
227
228 if (listen (server_fd, 5) < 0) {
229 perror ("listen");
230 close(server_fd);
231 return -1;
232 }
233
234 http_log("ffserver started.\n");
235
236 fcntl(server_fd, F_SETFL, O_NONBLOCK);
237 first_http_ctx = NULL;
238 nb_connections = 0;
239 first_http_ctx = NULL;
240 for(;;) {
241 poll_entry = poll_table;
242 poll_entry->fd = server_fd;
243 poll_entry->events = POLLIN;
244 poll_entry++;
245
246 /* wait for events on each HTTP handle */
247 c = first_http_ctx;
248 while (c != NULL) {
249 int fd;
250 fd = c->fd;
251 switch(c->state) {
252 case HTTPSTATE_WAIT_REQUEST:
253 c->poll_entry = poll_entry;
254 poll_entry->fd = fd;
255 poll_entry->events = POLLIN;
256 poll_entry++;
257 break;
258 case HTTPSTATE_SEND_HEADER:
259 case HTTPSTATE_SEND_DATA_HEADER:
260 case HTTPSTATE_SEND_DATA:
261 case HTTPSTATE_SEND_DATA_TRAILER:
262 c->poll_entry = poll_entry;
263 poll_entry->fd = fd;
264 poll_entry->events = POLLOUT;
265 poll_entry++;
266 break;
267 case HTTPSTATE_RECEIVE_DATA:
268 c->poll_entry = poll_entry;
269 poll_entry->fd = fd;
270 poll_entry->events = POLLIN;
271 poll_entry++;
272 break;
273 case HTTPSTATE_WAIT_FEED:
274 /* need to catch errors */
275 c->poll_entry = poll_entry;
276 poll_entry->fd = fd;
a6e14edd 277 poll_entry->events = POLLIN;/* Maybe this will work */
85f07f22
FB
278 poll_entry++;
279 break;
280 default:
281 c->poll_entry = NULL;
282 break;
283 }
284 c = c->next;
285 }
286
287 /* wait for an event on one connection. We poll at least every
288 second to handle timeouts */
289 do {
290 ret = poll(poll_table, poll_entry - poll_table, 1000);
291 } while (ret == -1);
292
293 cur_time = gettime_ms();
294
295 /* now handle the events */
296
297 cp = &first_http_ctx;
298 while ((*cp) != NULL) {
299 c = *cp;
300 if (handle_http (c, cur_time) < 0) {
301 /* close and free the connection */
7434ba6d 302 log_connection(c);
85f07f22
FB
303 close(c->fd);
304 if (c->fmt_in)
305 av_close_input_file(c->fmt_in);
306 *cp = c->next;
42a63c6a 307 nb_bandwidth -= c->bandwidth;
0f1578af 308 av_free(c);
85f07f22
FB
309 nb_connections--;
310 } else {
311 cp = &c->next;
312 }
313 }
314
315 /* new connection request ? */
316 poll_entry = poll_table;
317 if (poll_entry->revents & POLLIN) {
318 int fd, len;
319
320 len = sizeof(from_addr);
321 fd = accept(server_fd, (struct sockaddr *)&from_addr,
322 &len);
323 if (fd >= 0) {
324 fcntl(fd, F_SETFL, O_NONBLOCK);
325 /* XXX: should output a warning page when coming
326 close to the connection limit */
327 if (nb_connections >= nb_max_connections) {
328 close(fd);
329 } else {
330 /* add a new connection */
331 c = av_mallocz(sizeof(HTTPContext));
332 c->next = first_http_ctx;
333 first_http_ctx = c;
334 c->fd = fd;
335 c->poll_entry = NULL;
336 c->from_addr = from_addr;
337 c->state = HTTPSTATE_WAIT_REQUEST;
338 c->buffer_ptr = c->buffer;
339 c->buffer_end = c->buffer + IOBUFFER_MAX_SIZE;
340 c->timeout = cur_time + REQUEST_TIMEOUT;
341 nb_connections++;
342 }
343 }
344 }
345 poll_entry++;
346 }
347}
348
349static int handle_http(HTTPContext *c, long cur_time)
350{
351 int len;
352
353 switch(c->state) {
354 case HTTPSTATE_WAIT_REQUEST:
355 /* timeout ? */
356 if ((c->timeout - cur_time) < 0)
357 return -1;
358 if (c->poll_entry->revents & (POLLERR | POLLHUP))
359 return -1;
360
361 /* no need to read if no events */
362 if (!(c->poll_entry->revents & POLLIN))
363 return 0;
364 /* read the data */
365 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
366 if (len < 0) {
367 if (errno != EAGAIN && errno != EINTR)
368 return -1;
369 } else if (len == 0) {
370 return -1;
371 } else {
372 /* search for end of request. XXX: not fully correct since garbage could come after the end */
373 UINT8 *ptr;
374 c->buffer_ptr += len;
375 ptr = c->buffer_ptr;
376 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
377 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
378 /* request found : parse it and reply */
379 if (http_parse_request(c) < 0)
380 return -1;
381 } else if (ptr >= c->buffer_end) {
382 /* request too long: cannot do anything */
383 return -1;
384 }
385 }
386 break;
387
388 case HTTPSTATE_SEND_HEADER:
389 if (c->poll_entry->revents & (POLLERR | POLLHUP))
390 return -1;
391
392 /* no need to read if no events */
393 if (!(c->poll_entry->revents & POLLOUT))
394 return 0;
395 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
396 if (len < 0) {
397 if (errno != EAGAIN && errno != EINTR) {
398 /* error : close connection */
399 return -1;
400 }
401 } else {
402 c->buffer_ptr += len;
2e04edb3
PG
403 if (c->stream)
404 c->stream->bytes_served += len;
a6e14edd 405 c->data_count += len;
85f07f22
FB
406 if (c->buffer_ptr >= c->buffer_end) {
407 /* if error, exit */
408 if (c->http_error)
409 return -1;
410 /* all the buffer was send : synchronize to the incoming stream */
411 c->state = HTTPSTATE_SEND_DATA_HEADER;
412 c->buffer_ptr = c->buffer_end = c->buffer;
413 }
414 }
415 break;
416
417 case HTTPSTATE_SEND_DATA:
418 case HTTPSTATE_SEND_DATA_HEADER:
419 case HTTPSTATE_SEND_DATA_TRAILER:
420 /* no need to read if no events */
421 if (c->poll_entry->revents & (POLLERR | POLLHUP))
422 return -1;
423
424 if (!(c->poll_entry->revents & POLLOUT))
425 return 0;
426 if (http_send_data(c) < 0)
427 return -1;
428 break;
429 case HTTPSTATE_RECEIVE_DATA:
430 /* no need to read if no events */
431 if (c->poll_entry->revents & (POLLERR | POLLHUP))
432 return -1;
433 if (!(c->poll_entry->revents & POLLIN))
434 return 0;
435 if (http_receive_data(c) < 0)
436 return -1;
437 break;
438 case HTTPSTATE_WAIT_FEED:
439 /* no need to read if no events */
a6e14edd 440 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
85f07f22
FB
441 return -1;
442
443 /* nothing to do, we'll be waken up by incoming feed packets */
444 break;
445 default:
446 return -1;
447 }
448 return 0;
449}
450
3120d2a2
PG
451static int extract_rates(char *rates, int ratelen, const char *request)
452{
453 const char *p;
454
455 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
456 if (strncasecmp(p, "Pragma:", 7) == 0) {
457 const char *q = p + 7;
458
459 while (*q && *q != '\n' && isspace(*q))
460 q++;
461
462 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
463 int stream_no;
464 int rate_no;
465
466 q += 20;
467
468 memset(rates, 0, ratelen);
469
470 while (1) {
471 while (*q && *q != '\n' && *q != ':')
472 q++;
473
474 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
475 break;
476 }
477 stream_no--;
478 if (stream_no < ratelen && stream_no >= 0) {
479 rates[stream_no] = rate_no;
480 }
481
482 while (*q && *q != '\n' && !isspace(*q))
483 q++;
484 }
485
486 return 1;
487 }
488 }
489 p = strchr(p, '\n');
490 if (!p)
491 break;
492
493 p++;
494 }
495
496 return 0;
497}
498
499static FFStream *find_optimal_stream(FFStream *req, char *rates)
500{
501 int i;
502 FFStream *rover;
503 int req_bitrate = 0;
504 int want_bitrate = 0;
505 FFStream *best = 0;
506 int best_bitrate;
507
508 for (i = 0; i < req->nb_streams; i++) {
509 AVCodecContext *codec = &req->streams[i]->codec;
510
511 req_bitrate += codec->bit_rate;
512
513 switch(rates[i]) {
514 case 0:
515 want_bitrate += codec->bit_rate;
516 break;
517 case 1:
518 want_bitrate += codec->bit_rate / 2;
519 break;
520 case 2:
521 break;
522 }
523 }
524
525 best_bitrate = req_bitrate;
526 if (best_bitrate <= want_bitrate)
527 return 0; /* We are OK */
528
529 /* Now we have the actual rates that we can use. Now find the stream that uses most of it! */
530
531 for (rover = first_stream; rover; rover = rover->next) {
532 if (rover->feed != req->feed ||
533 rover->fmt != req->fmt ||
534 rover->nb_streams != req->nb_streams ||
535 rover == req) {
536 continue;
537 }
538
539 /* Now see if the codecs all match */
540
541 for (i = 0; i < req->nb_streams; i++) {
542 AVCodecContext *codec = &req->streams[i]->codec;
543 AVCodecContext *rovercodec = &rover->streams[i]->codec;
544
545 if (rovercodec->codec_id != codec->codec_id ||
546 rovercodec->sample_rate != codec->sample_rate) {
547 /* Does the video width and height have to match?? */
548 break;
549 }
550 }
551
552 if (i == req->nb_streams) {
553 /* The rovercodec is another possible stream */
554 int rover_bitrate = 0;
555
556 for (i = 0; i < req->nb_streams; i++) {
557 AVCodecContext *codec = &rover->streams[i]->codec;
558
559 rover_bitrate += codec->bit_rate;
560 }
561
562 /* We want to choose the largest rover_bitrate <= want_bitrate, or the smallest
563 * rover_bitrate if none <= want_bitrate
564 */
565 if (rover_bitrate <= want_bitrate) {
566 if (best_bitrate > want_bitrate || rover_bitrate > best_bitrate) {
567 best_bitrate = rover_bitrate;
568 best = rover;
569 }
570 } else {
571 if (rover_bitrate < best_bitrate) {
572 best_bitrate = rover_bitrate;
573 best = rover;
574 }
575 }
576 }
577 }
578
579 return best;
580}
7434ba6d 581
85f07f22
FB
582/* parse http request and prepare header */
583static int http_parse_request(HTTPContext *c)
584{
585 char *p;
586 int post;
7434ba6d 587 int doing_asx;
42a63c6a 588 int doing_ram;
85f07f22
FB
589 char cmd[32];
590 char info[1024], *filename;
591 char url[1024], *q;
592 char protocol[32];
593 char msg[1024];
594 const char *mime_type;
595 FFStream *stream;
42a63c6a 596 int i;
3120d2a2 597 char ratebuf[32];
85f07f22
FB
598
599 p = c->buffer;
600 q = cmd;
601 while (!isspace(*p) && *p != '\0') {
602 if ((q - cmd) < sizeof(cmd) - 1)
603 *q++ = *p;
604 p++;
605 }
606 *q = '\0';
7434ba6d 607
bd7cf6ad 608 pstrcpy(c->method, sizeof(c->method), cmd);
7434ba6d 609
85f07f22
FB
610 if (!strcmp(cmd, "GET"))
611 post = 0;
612 else if (!strcmp(cmd, "POST"))
613 post = 1;
614 else
615 return -1;
616
617 while (isspace(*p)) p++;
618 q = url;
619 while (!isspace(*p) && *p != '\0') {
620 if ((q - url) < sizeof(url) - 1)
621 *q++ = *p;
622 p++;
623 }
624 *q = '\0';
625
bd7cf6ad 626 pstrcpy(c->url, sizeof(c->url), url);
7434ba6d 627
85f07f22
FB
628 while (isspace(*p)) p++;
629 q = protocol;
630 while (!isspace(*p) && *p != '\0') {
631 if ((q - protocol) < sizeof(protocol) - 1)
632 *q++ = *p;
633 p++;
634 }
635 *q = '\0';
636 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
637 return -1;
7434ba6d 638
bd7cf6ad 639 pstrcpy(c->protocol, sizeof(c->protocol), protocol);
85f07f22
FB
640
641 /* find the filename and the optional info string in the request */
642 p = url;
643 if (*p == '/')
644 p++;
645 filename = p;
646 p = strchr(p, '?');
647 if (p) {
bd7cf6ad 648 pstrcpy(info, sizeof(info), p);
85f07f22
FB
649 *p = '\0';
650 } else {
651 info[0] = '\0';
652 }
653
7434ba6d
PG
654 if (strlen(filename) > 4 && strcmp(".asx", filename + strlen(filename) - 4) == 0) {
655 doing_asx = 1;
656 filename[strlen(filename)-1] = 'f';
657 } else {
658 doing_asx = 0;
659 }
660
42a63c6a
PG
661 if (strlen(filename) > 4 &&
662 (strcmp(".rpm", filename + strlen(filename) - 4) == 0 ||
663 strcmp(".ram", filename + strlen(filename) - 4) == 0)) {
664 doing_ram = 1;
665 strcpy(filename + strlen(filename)-2, "m");
666 } else {
667 doing_ram = 0;
668 }
669
85f07f22
FB
670 stream = first_stream;
671 while (stream != NULL) {
672 if (!strcmp(stream->filename, filename))
673 break;
674 stream = stream->next;
675 }
676 if (stream == NULL) {
677 sprintf(msg, "File '%s' not found", url);
678 goto send_error;
679 }
42a63c6a 680
3120d2a2
PG
681 /* If this is WMP, get the rate information */
682 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
683 FFStream *optimal;
684
685 optimal = find_optimal_stream(stream, ratebuf);
686 if (optimal)
687 stream = optimal;
688 }
689
42a63c6a
PG
690 if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
691 /* See if we meet the bandwidth requirements */
692 for(i=0;i<stream->nb_streams;i++) {
693 AVStream *st = stream->streams[i];
694 switch(st->codec.codec_type) {
695 case CODEC_TYPE_AUDIO:
696 c->bandwidth += st->codec.bit_rate;
697 break;
698 case CODEC_TYPE_VIDEO:
699 c->bandwidth += st->codec.bit_rate;
700 break;
701 default:
ec3b2232 702 av_abort();
42a63c6a
PG
703 }
704 }
705 }
706
707 c->bandwidth /= 1000;
708 nb_bandwidth += c->bandwidth;
709
710 if (post == 0 && nb_max_bandwidth < nb_bandwidth) {
711 c->http_error = 200;
712 q = c->buffer;
713 q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
714 q += sprintf(q, "Content-type: text/html\r\n");
715 q += sprintf(q, "\r\n");
716 q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
717 q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
718 q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
719 nb_bandwidth, nb_max_bandwidth);
720 q += sprintf(q, "</body></html>\r\n");
721
722 /* prepare output buffer */
723 c->buffer_ptr = c->buffer;
724 c->buffer_end = q;
725 c->state = HTTPSTATE_SEND_HEADER;
726 return 0;
727 }
728
729 if (doing_asx || doing_ram) {
7434ba6d
PG
730 char *hostinfo = 0;
731
732 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
733 if (strncasecmp(p, "Host:", 5) == 0) {
734 hostinfo = p + 5;
735 break;
736 }
737 p = strchr(p, '\n');
738 if (!p)
739 break;
740
741 p++;
742 }
743
744 if (hostinfo) {
745 char *eoh;
746 char hostbuf[260];
747
748 while (isspace(*hostinfo))
749 hostinfo++;
750
751 eoh = strchr(hostinfo, '\n');
752 if (eoh) {
753 if (eoh[-1] == '\r')
754 eoh--;
755
756 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
757 memcpy(hostbuf, hostinfo, eoh - hostinfo);
758 hostbuf[eoh - hostinfo] = 0;
759
760 c->http_error = 200;
761 q = c->buffer;
42a63c6a
PG
762 if (doing_asx) {
763 q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
764 q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
765 q += sprintf(q, "\r\n");
766 q += sprintf(q, "<ASX Version=\"3\">\r\n");
767 q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
768 q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
769 hostbuf, filename, info);
770 q += sprintf(q, "</ASX>\r\n");
771 } else if (doing_ram) {
772 q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
773 q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
774 q += sprintf(q, "\r\n");
775 q += sprintf(q, "# Autogenerated by ffserver\r\n");
776 q += sprintf(q, "http://%s/%s%s\r\n",
777 hostbuf, filename, info);
778 } else
ec3b2232 779 av_abort();
7434ba6d
PG
780
781 /* prepare output buffer */
782 c->buffer_ptr = c->buffer;
783 c->buffer_end = q;
784 c->state = HTTPSTATE_SEND_HEADER;
785 return 0;
786 }
787 }
788 }
789
42a63c6a 790 sprintf(msg, "ASX/RAM file not handled");
7434ba6d 791 goto send_error;
85f07f22
FB
792 }
793
7434ba6d 794 c->stream = stream;
a6e14edd 795 stream->conns_served++;
7434ba6d 796
85f07f22
FB
797 /* XXX: add there authenticate and IP match */
798
799 if (post) {
800 /* if post, it means a feed is being sent */
801 if (!stream->is_feed) {
7434ba6d
PG
802 /* However it might be a status report from WMP! Lets log the data
803 * as it might come in handy one day
804 */
805 char *logline = 0;
3120d2a2 806 int client_id = 0;
7434ba6d
PG
807
808 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
809 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
810 logline = p;
811 break;
812 }
3120d2a2
PG
813 if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
814 client_id = strtol(p + 18, 0, 10);
815 }
7434ba6d
PG
816 p = strchr(p, '\n');
817 if (!p)
818 break;
819
820 p++;
821 }
822
823 if (logline) {
824 char *eol = strchr(logline, '\n');
825
826 logline += 17;
827
828 if (eol) {
829 if (eol[-1] == '\r')
830 eol--;
831 http_log("%.*s\n", eol - logline, logline);
832 c->suppress_log = 1;
833 }
834 }
3120d2a2
PG
835
836#ifdef DEBUG
837 fprintf(stderr, "\nGot request:\n%s\n", c->buffer);
838#endif
839
840 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
841 HTTPContext *wmpc;
842
843 /* Now we have to find the client_id */
844 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
845 if (wmpc->wmp_client_id == client_id)
846 break;
847 }
848
849 if (wmpc) {
850 FFStream *optimal;
851 optimal = find_optimal_stream(wmpc->stream, ratebuf);
852 if (optimal) {
853 fprintf(stderr, "Would like to switch stream from %s to %s\n",
854 wmpc->stream->filename, optimal->filename);
855 }
856 }
857 }
7434ba6d 858
85f07f22
FB
859 sprintf(msg, "POST command not handled");
860 goto send_error;
861 }
862 if (http_start_receive_data(c) < 0) {
863 sprintf(msg, "could not open feed");
864 goto send_error;
865 }
866 c->http_error = 0;
867 c->state = HTTPSTATE_RECEIVE_DATA;
868 return 0;
869 }
870
3120d2a2
PG
871#ifdef DEBUG
872 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
873 fprintf(stderr, "\nGot request:\n%s\n", c->buffer);
874 }
875#endif
876
85f07f22
FB
877 if (c->stream->stream_type == STREAM_TYPE_STATUS)
878 goto send_stats;
879
880 /* open input stream */
881 if (open_input_stream(c, info) < 0) {
882 sprintf(msg, "Input stream corresponding to '%s' not found", url);
883 goto send_error;
884 }
885
886 /* prepare http header */
887 q = c->buffer;
888 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
889 mime_type = c->stream->fmt->mime_type;
890 if (!mime_type)
891 mime_type = "application/x-octet_stream";
85f07f22
FB
892 q += sprintf(q, "Pragma: no-cache\r\n");
893
894 /* for asf, we need extra headers */
895 if (!strcmp(c->stream->fmt->name,"asf")) {
3120d2a2
PG
896 /* Need to allocate a client id */
897 static int wmp_session;
898
899 if (!wmp_session)
900 wmp_session = time(0) & 0xffffff;
901
902 c->wmp_client_id = ++wmp_session;
903
904 q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
7434ba6d
PG
905 /* mime_type = "application/octet-stream"; */
906 /* video/x-ms-asf seems better -- netscape doesn't crash any more! */
907 mime_type = "video/x-ms-asf";
85f07f22 908 }
f747e6d3 909 q += sprintf(q, "Content-Type: %s\r\n", mime_type);
85f07f22
FB
910 q += sprintf(q, "\r\n");
911
912 /* prepare output buffer */
913 c->http_error = 0;
914 c->buffer_ptr = c->buffer;
915 c->buffer_end = q;
916 c->state = HTTPSTATE_SEND_HEADER;
917 return 0;
918 send_error:
919 c->http_error = 404;
920 q = c->buffer;
921 q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
922 q += sprintf(q, "Content-type: %s\r\n", "text/html");
923 q += sprintf(q, "\r\n");
924 q += sprintf(q, "<HTML>\n");
925 q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
926 q += sprintf(q, "<BODY>%s</BODY>\n", msg);
927 q += sprintf(q, "</HTML>\n");
928
929 /* prepare output buffer */
930 c->buffer_ptr = c->buffer;
931 c->buffer_end = q;
932 c->state = HTTPSTATE_SEND_HEADER;
933 return 0;
934 send_stats:
935 compute_stats(c);
936 c->http_error = 200; /* horrible : we use this value to avoid
937 going to the send data state */
938 c->state = HTTPSTATE_SEND_HEADER;
939 return 0;
940}
941
942static void compute_stats(HTTPContext *c)
943{
944 HTTPContext *c1;
945 FFStream *stream;
946 char *q, *p;
947 time_t ti;
948 int i;
949
950 q = c->buffer;
951 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
952 q += sprintf(q, "Content-type: %s\r\n", "text/html");
953 q += sprintf(q, "Pragma: no-cache\r\n");
954 q += sprintf(q, "\r\n");
955
956 q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE></HEAD>\n<BODY>");
957 q += sprintf(q, "<H1>FFServer Status</H1>\n");
958 /* format status */
79c4ea3c 959 q += sprintf(q, "<H2>Available Streams</H2>\n");
a6e14edd
PG
960 q += sprintf(q, "<TABLE cellspacing=0 cellpadding=4>\n");
961 q += sprintf(q, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>kbytes<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");
85f07f22
FB
962 stream = first_stream;
963 while (stream != NULL) {
42a63c6a
PG
964 char sfilename[1024];
965 char *eosf;
966
a6e14edd 967 if (stream->feed != stream) {
bd7cf6ad 968 pstrcpy(sfilename, sizeof(sfilename) - 1, stream->filename);
a6e14edd
PG
969 eosf = sfilename + strlen(sfilename);
970 if (eosf - sfilename >= 4) {
971 if (strcmp(eosf - 4, ".asf") == 0) {
972 strcpy(eosf - 4, ".asx");
973 } else if (strcmp(eosf - 3, ".rm") == 0) {
974 strcpy(eosf - 3, ".ram");
975 }
42a63c6a 976 }
a6e14edd
PG
977
978 q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ",
979 sfilename, stream->filename);
980 q += sprintf(q, "<td align=right> %d <td align=right> %lld",
981 stream->conns_served, stream->bytes_served / 1000);
982 switch(stream->stream_type) {
983 case STREAM_TYPE_LIVE:
984 {
985 int audio_bit_rate = 0;
986 int video_bit_rate = 0;
987 char *audio_codec_name = "";
988 char *video_codec_name = "";
989 char *audio_codec_name_extra = "";
990 char *video_codec_name_extra = "";
991
992 for(i=0;i<stream->nb_streams;i++) {
993 AVStream *st = stream->streams[i];
994 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
995 switch(st->codec.codec_type) {
996 case CODEC_TYPE_AUDIO:
997 audio_bit_rate += st->codec.bit_rate;
998 if (codec) {
999 if (*audio_codec_name)
1000 audio_codec_name_extra = "...";
1001 audio_codec_name = codec->name;
1002 }
1003 break;
1004 case CODEC_TYPE_VIDEO:
1005 video_bit_rate += st->codec.bit_rate;
1006 if (codec) {
1007 if (*video_codec_name)
1008 video_codec_name_extra = "...";
1009 video_codec_name = codec->name;
1010 }
1011 break;
1012 default:
ec3b2232 1013 av_abort();
79c4ea3c 1014 }
85f07f22 1015 }
a6e14edd
PG
1016 q += sprintf(q, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s",
1017 stream->fmt->name,
1018 (audio_bit_rate + video_bit_rate) / 1000,
1019 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1020 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1021 if (stream->feed) {
1022 q += sprintf(q, "<TD>%s", stream->feed->filename);
1023 } else {
1024 q += sprintf(q, "<TD>%s", stream->feed_filename);
1025 }
1026 q += sprintf(q, "\n");
85f07f22 1027 }
a6e14edd
PG
1028 break;
1029 default:
1030 q += sprintf(q, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1031 break;
85f07f22 1032 }
85f07f22
FB
1033 }
1034 stream = stream->next;
1035 }
1036 q += sprintf(q, "</TABLE>\n");
a6e14edd
PG
1037
1038 stream = first_stream;
1039 while (stream != NULL) {
1040 if (stream->feed == stream) {
1041 q += sprintf(q, "<h2>Feed %s</h2>", stream->filename);
b582f314 1042 q += sprintf(q, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
a6e14edd
PG
1043
1044 for (i = 0; i < stream->nb_streams; i++) {
1045 AVStream *st = stream->streams[i];
1046 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1047 char *type = "unknown";
b582f314
PG
1048 char parameters[64];
1049
1050 parameters[0] = 0;
a6e14edd
PG
1051
1052 switch(st->codec.codec_type) {
1053 case CODEC_TYPE_AUDIO:
1054 type = "audio";
1055 break;
1056 case CODEC_TYPE_VIDEO:
1057 type = "video";
b582f314
PG
1058 sprintf(parameters, "%dx%d, q=%d-%d", st->codec.width, st->codec.height,
1059 st->codec.qmin, st->codec.qmax);
a6e14edd
PG
1060 break;
1061 default:
ec3b2232 1062 av_abort();
a6e14edd 1063 }
b582f314
PG
1064 q += sprintf(q, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1065 i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
a6e14edd
PG
1066 }
1067 q += sprintf(q, "</table>\n");
1068
1069 }
1070 stream = stream->next;
1071 }
85f07f22
FB
1072
1073#if 0
1074 {
1075 float avg;
1076 AVCodecContext *enc;
1077 char buf[1024];
1078
1079 /* feed status */
1080 stream = first_feed;
1081 while (stream != NULL) {
1082 q += sprintf(q, "<H1>Feed '%s'</H1>\n", stream->filename);
1083 q += sprintf(q, "<TABLE>\n");
1084 q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1085 for(i=0;i<stream->nb_streams;i++) {
1086 AVStream *st = stream->streams[i];
1087 FeedData *fdata = st->priv_data;
1088 enc = &st->codec;
1089
1090 avcodec_string(buf, sizeof(buf), enc);
1091 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1092 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1093 avg /= enc->frame_size;
1094 q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n",
1095 buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1096 }
1097 q += sprintf(q, "</TABLE>\n");
1098 stream = stream->next_feed;
1099 }
1100 }
1101#endif
1102
1103 /* connection status */
79c4ea3c 1104 q += sprintf(q, "<H2>Connection Status</H2>\n");
85f07f22
FB
1105
1106 q += sprintf(q, "Number of connections: %d / %d<BR>\n",
1107 nb_connections, nb_max_connections);
1108
42a63c6a
PG
1109 q += sprintf(q, "Bandwidth in use: %dk / %dk<BR>\n",
1110 nb_bandwidth, nb_max_bandwidth);
1111
85f07f22
FB
1112 q += sprintf(q, "<TABLE>\n");
1113 q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n");
1114 c1 = first_http_ctx;
1115 i = 0;
a6e14edd 1116 while (c1 != NULL && q < (char *) c->buffer + sizeof(c->buffer) - 2048) {
85f07f22
FB
1117 i++;
1118 p = inet_ntoa(c1->from_addr.sin_addr);
1119 q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <TD> %Ld\n",
1120 i, c1->stream->filename,
1121 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1122 p,
1123 http_state[c1->state],
1124 c1->data_count);
1125 c1 = c1->next;
1126 }
1127 q += sprintf(q, "</TABLE>\n");
1128
1129 /* date */
1130 ti = time(NULL);
1131 p = ctime(&ti);
a6e14edd 1132 q += sprintf(q, "<HR size=1 noshade>Generated at %s", p);
85f07f22
FB
1133 q += sprintf(q, "</BODY>\n</HTML>\n");
1134
1135 c->buffer_ptr = c->buffer;
1136 c->buffer_end = q;
1137}
1138
1139
1140static void http_write_packet(void *opaque,
1141 unsigned char *buf, int size)
1142{
1143 HTTPContext *c = opaque;
f747e6d3
PG
1144
1145 if (c->buffer_ptr == c->buffer_end || !c->buffer_ptr)
1146 c->buffer_ptr = c->buffer_end = c->buffer;
1147
1148 if (c->buffer_end - c->buffer + size > IOBUFFER_MAX_SIZE)
ec3b2232 1149 av_abort();
f747e6d3
PG
1150
1151 memcpy(c->buffer_end, buf, size);
1152 c->buffer_end += size;
85f07f22
FB
1153}
1154
1155static int open_input_stream(HTTPContext *c, const char *info)
1156{
1157 char buf[128];
1158 char input_filename[1024];
1159 AVFormatContext *s;
1160 int buf_size;
1161 INT64 stream_pos;
1162
1163 /* find file name */
1164 if (c->stream->feed) {
1165 strcpy(input_filename, c->stream->feed->feed_filename);
1166 buf_size = FFM_PACKET_SIZE;
1167 /* compute position (absolute time) */
1168 if (find_info_tag(buf, sizeof(buf), "date", info)) {
1169 stream_pos = parse_date(buf, 0);
f747e6d3
PG
1170 } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1171 int prebuffer = strtol(buf, 0, 10);
1172 stream_pos = gettime() - prebuffer * 1000000;
85f07f22 1173 } else {
42a63c6a 1174 stream_pos = gettime() - c->stream->prebuffer * 1000;
85f07f22
FB
1175 }
1176 } else {
1177 strcpy(input_filename, c->stream->feed_filename);
1178 buf_size = 0;
1179 /* compute position (relative time) */
1180 if (find_info_tag(buf, sizeof(buf), "date", info)) {
1181 stream_pos = parse_date(buf, 1);
1182 } else {
1183 stream_pos = 0;
1184 }
1185 }
1186 if (input_filename[0] == '\0')
1187 return -1;
1188
1189 /* open stream */
bd7cf6ad 1190 if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0)
85f07f22
FB
1191 return -1;
1192 c->fmt_in = s;
1193
bd7cf6ad
FB
1194 if (c->fmt_in->iformat->read_seek) {
1195 c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
85f07f22
FB
1196 }
1197
1198 // printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
1199 return 0;
1200}
1201
1202static int http_prepare_data(HTTPContext *c)
1203{
1204 int i;
1205
1206 switch(c->state) {
1207 case HTTPSTATE_SEND_DATA_HEADER:
1208 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1209 if (c->stream->feed) {
1210 /* open output stream by using specified codecs */
bd7cf6ad 1211 c->fmt_ctx.oformat = c->stream->fmt;
85f07f22
FB
1212 c->fmt_ctx.nb_streams = c->stream->nb_streams;
1213 for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1214 AVStream *st;
1215 st = av_mallocz(sizeof(AVStream));
1216 c->fmt_ctx.streams[i] = st;
f747e6d3
PG
1217 if (c->stream->feed == c->stream)
1218 memcpy(st, c->stream->streams[i], sizeof(AVStream));
1219 else
1220 memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]], sizeof(AVStream));
1221
85f07f22
FB
1222 st->codec.frame_number = 0; /* XXX: should be done in
1223 AVStream, not in codec */
85f07f22 1224 }
42a63c6a 1225 c->got_key_frame = 0;
85f07f22
FB
1226 } else {
1227 /* open output stream by using codecs in specified file */
bd7cf6ad 1228 c->fmt_ctx.oformat = c->stream->fmt;
85f07f22
FB
1229 c->fmt_ctx.nb_streams = c->fmt_in->nb_streams;
1230 for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1231 AVStream *st;
1232 st = av_mallocz(sizeof(AVStream));
1233 c->fmt_ctx.streams[i] = st;
1234 memcpy(st, c->fmt_in->streams[i], sizeof(AVStream));
1235 st->codec.frame_number = 0; /* XXX: should be done in
1236 AVStream, not in codec */
85f07f22 1237 }
42a63c6a 1238 c->got_key_frame = 0;
85f07f22 1239 }
f747e6d3 1240 init_put_byte(&c->fmt_ctx.pb, c->pbuffer, PACKET_MAX_SIZE,
85f07f22
FB
1241 1, c, NULL, http_write_packet, NULL);
1242 c->fmt_ctx.pb.is_streamed = 1;
1243 /* prepare header */
bd7cf6ad 1244 av_write_header(&c->fmt_ctx);
85f07f22
FB
1245 c->state = HTTPSTATE_SEND_DATA;
1246 c->last_packet_sent = 0;
1247 break;
1248 case HTTPSTATE_SEND_DATA:
1249 /* find a new packet */
1250#if 0
1251 fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
1252 if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
1253 /* overflow : resync. We suppose that wptr is at this
1254 point a pointer to a valid packet */
1255 c->rptr = http_fifo.wptr;
42a63c6a 1256 c->got_key_frame = 0;
85f07f22
FB
1257 }
1258
1259 start_rptr = c->rptr;
1260 if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
1261 return 0;
1262 payload_size = ntohs(hdr.payload_size);
0f1578af 1263 payload = av_malloc(payload_size);
85f07f22
FB
1264 if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
1265 /* cannot read all the payload */
0f1578af 1266 av_free(payload);
85f07f22
FB
1267 c->rptr = start_rptr;
1268 return 0;
1269 }
1270
1271 c->last_http_fifo_write_count = http_fifo_write_count -
1272 fifo_size(&http_fifo, c->rptr);
1273
1274 if (c->stream->stream_type != STREAM_TYPE_MASTER) {
1275 /* test if the packet can be handled by this format */
1276 ret = 0;
1277 for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1278 AVStream *st = c->fmt_ctx.streams[i];
1279 if (test_header(&hdr, &st->codec)) {
1280 /* only begin sending when got a key frame */
1281 if (st->codec.key_frame)
42a63c6a
PG
1282 c->got_key_frame |= 1 << i;
1283 if (c->got_key_frame & (1 << i)) {
85f07f22
FB
1284 ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i,
1285 payload, payload_size);
1286 }
1287 break;
1288 }
1289 }
1290 if (ret) {
1291 /* must send trailer now */
1292 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1293 }
1294 } else {
1295 /* master case : send everything */
1296 char *q;
1297 q = c->buffer;
1298 memcpy(q, &hdr, sizeof(hdr));
1299 q += sizeof(hdr);
1300 memcpy(q, payload, payload_size);
1301 q += payload_size;
1302 c->buffer_ptr = c->buffer;
1303 c->buffer_end = q;
1304 }
0f1578af 1305 av_free(payload);
85f07f22
FB
1306#endif
1307 {
1308 AVPacket pkt;
1309
1310 /* read a packet from the input stream */
1311 if (c->stream->feed) {
1312 ffm_set_write_index(c->fmt_in,
1313 c->stream->feed->feed_write_index,
1314 c->stream->feed->feed_size);
1315 }
ec3b2232
PG
1316
1317 if (c->stream->max_time &&
1318 c->stream->max_time + c->start_time > time(0)) {
1319 /* We have timed out */
1320 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1321 } else if (av_read_packet(c->fmt_in, &pkt) < 0) {
85f07f22
FB
1322 if (c->stream->feed && c->stream->feed->feed_opened) {
1323 /* if coming from feed, it means we reached the end of the
1324 ffm file, so must wait for more data */
1325 c->state = HTTPSTATE_WAIT_FEED;
1326 return 1; /* state changed */
1327 } else {
1328 /* must send trailer now because eof or error */
1329 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1330 }
1331 } else {
1332 /* send it to the appropriate stream */
1333 if (c->stream->feed) {
1334 /* if coming from a feed, select the right stream */
1335 for(i=0;i<c->stream->nb_streams;i++) {
1336 if (c->stream->feed_streams[i] == pkt.stream_index) {
1337 pkt.stream_index = i;
42a63c6a
PG
1338 if (pkt.flags & PKT_FLAG_KEY) {
1339 c->got_key_frame |= 1 << i;
1340 }
1341 /* See if we have all the key frames, then
1342 * we start to send. This logic is not quite
1343 * right, but it works for the case of a
1344 * single video stream with one or more
1345 * audio streams (for which every frame is
1346 * typically a key frame).
1347 */
79c4ea3c 1348 if (!c->stream->send_on_key || ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
42a63c6a
PG
1349 goto send_it;
1350 }
85f07f22
FB
1351 }
1352 }
1353 } else {
f747e6d3
PG
1354 AVCodecContext *codec;
1355 send_it:
1356 /* Fudge here */
1357 codec = &c->fmt_ctx.streams[pkt.stream_index]->codec;
1358
1359 codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
1360
1361#ifdef PJSG
1362 if (codec->codec_type == CODEC_TYPE_AUDIO) {
1363 codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
1364 /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
1365 }
1366#endif
1367
10bb7023 1368 if (av_write_packet(&c->fmt_ctx, &pkt, 0))
f747e6d3
PG
1369 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1370
1371 codec->frame_number++;
85f07f22 1372 }
42a63c6a 1373
85f07f22
FB
1374 av_free_packet(&pkt);
1375 }
1376 }
1377 break;
1378 default:
1379 case HTTPSTATE_SEND_DATA_TRAILER:
1380 /* last packet test ? */
1381 if (c->last_packet_sent)
1382 return -1;
1383 /* prepare header */
bd7cf6ad 1384 av_write_trailer(&c->fmt_ctx);
85f07f22
FB
1385 c->last_packet_sent = 1;
1386 break;
1387 }
1388 return 0;
1389}
1390
1391/* should convert the format at the same time */
1392static int http_send_data(HTTPContext *c)
1393{
1394 int len, ret;
1395
1396 while (c->buffer_ptr >= c->buffer_end) {
1397 ret = http_prepare_data(c);
1398 if (ret < 0)
1399 return -1;
1400 else if (ret == 0) {
a6e14edd 1401 continue;
85f07f22
FB
1402 } else {
1403 /* state change requested */
1404 return 0;
1405 }
1406 }
1407
f747e6d3
PG
1408 if (c->buffer_end > c->buffer_ptr) {
1409 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1410 if (len < 0) {
1411 if (errno != EAGAIN && errno != EINTR) {
1412 /* error : close connection */
1413 return -1;
1414 }
1415 } else {
1416 c->buffer_ptr += len;
1417 c->data_count += len;
2e04edb3
PG
1418 if (c->stream)
1419 c->stream->bytes_served += len;
85f07f22 1420 }
85f07f22
FB
1421 }
1422 return 0;
1423}
1424
1425static int http_start_receive_data(HTTPContext *c)
1426{
1427 int fd;
1428
1429 if (c->stream->feed_opened)
1430 return -1;
1431
1432 /* open feed */
1433 fd = open(c->stream->feed_filename, O_RDWR);
1434 if (fd < 0)
1435 return -1;
1436 c->feed_fd = fd;
1437
1438 c->stream->feed_write_index = ffm_read_write_index(fd);
1439 c->stream->feed_size = lseek(fd, 0, SEEK_END);
1440 lseek(fd, 0, SEEK_SET);
1441
1442 /* init buffer input */
1443 c->buffer_ptr = c->buffer;
1444 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
1445 c->stream->feed_opened = 1;
1446 return 0;
1447}
1448
1449static int http_receive_data(HTTPContext *c)
1450{
85f07f22
FB
1451 HTTPContext *c1;
1452
a6e14edd
PG
1453 if (c->buffer_end > c->buffer_ptr) {
1454 int len;
1455
1456 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1457 if (len < 0) {
1458 if (errno != EAGAIN && errno != EINTR) {
1459 /* error : close connection */
1460 goto fail;
1461 }
1462 } else if (len == 0) {
1463 /* end of connection : close it */
1464 goto fail;
1465 } else {
1466 c->buffer_ptr += len;
1467 c->data_count += len;
1468 }
1469 }
1470
85f07f22 1471 if (c->buffer_ptr >= c->buffer_end) {
f747e6d3 1472 FFStream *feed = c->stream;
85f07f22
FB
1473 /* a packet has been received : write it in the store, except
1474 if header */
1475 if (c->data_count > FFM_PACKET_SIZE) {
85f07f22
FB
1476
1477 // printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
1478 /* XXX: use llseek or url_seek */
1479 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
1480 write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
1481
1482 feed->feed_write_index += FFM_PACKET_SIZE;
1483 /* update file size */
1484 if (feed->feed_write_index > c->stream->feed_size)
1485 feed->feed_size = feed->feed_write_index;
1486
1487 /* handle wrap around if max file size reached */
1488 if (feed->feed_write_index >= c->stream->feed_max_size)
1489 feed->feed_write_index = FFM_PACKET_SIZE;
1490
1491 /* write index */
1492 ffm_write_write_index(c->feed_fd, feed->feed_write_index);
1493
1494 /* wake up any waiting connections */
1495 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
1496 if (c1->state == HTTPSTATE_WAIT_FEED &&
1497 c1->stream->feed == c->stream->feed) {
1498 c1->state = HTTPSTATE_SEND_DATA;
1499 }
1500 }
f747e6d3
PG
1501 } else {
1502 /* We have a header in our hands that contains useful data */
1503 AVFormatContext s;
bd7cf6ad 1504 AVInputFormat *fmt_in;
f747e6d3
PG
1505 ByteIOContext *pb = &s.pb;
1506 int i;
1507
1508 memset(&s, 0, sizeof(s));
1509
1510 url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
1511 pb->buf_end = c->buffer_end; /* ?? */
1512 pb->is_streamed = 1;
1513
bd7cf6ad
FB
1514 /* use feed output format name to find corresponding input format */
1515 fmt_in = av_find_input_format(feed->fmt->name);
1516 if (!fmt_in)
1517 goto fail;
1518
ec3b2232
PG
1519 s.priv_data = av_mallocz(fmt_in->priv_data_size);
1520 if (!s.priv_data)
1521 goto fail;
1522
bd7cf6ad 1523 if (fmt_in->read_header(&s, 0) < 0) {
ec3b2232 1524 av_freep(&s.priv_data);
f747e6d3
PG
1525 goto fail;
1526 }
1527
1528 /* Now we have the actual streams */
1529 if (s.nb_streams != feed->nb_streams) {
ec3b2232 1530 av_freep(&s.priv_data);
f747e6d3
PG
1531 goto fail;
1532 }
1533 for (i = 0; i < s.nb_streams; i++) {
bd7cf6ad
FB
1534 memcpy(&feed->streams[i]->codec,
1535 &s.streams[i]->codec, sizeof(AVCodecContext));
f747e6d3 1536 }
ec3b2232 1537 av_freep(&s.priv_data);
85f07f22
FB
1538 }
1539 c->buffer_ptr = c->buffer;
1540 }
1541
85f07f22
FB
1542 return 0;
1543 fail:
1544 c->stream->feed_opened = 0;
1545 close(c->feed_fd);
1546 return -1;
1547}
1548
1549/* return the stream number in the feed */
1550int add_av_stream(FFStream *feed,
1551 AVStream *st)
1552{
1553 AVStream *fst;
1554 AVCodecContext *av, *av1;
1555 int i;
1556
1557 av = &st->codec;
1558 for(i=0;i<feed->nb_streams;i++) {
1559 st = feed->streams[i];
1560 av1 = &st->codec;
f747e6d3
PG
1561 if (av1->codec_id == av->codec_id &&
1562 av1->codec_type == av->codec_type &&
85f07f22
FB
1563 av1->bit_rate == av->bit_rate) {
1564
1565 switch(av->codec_type) {
1566 case CODEC_TYPE_AUDIO:
1567 if (av1->channels == av->channels &&
1568 av1->sample_rate == av->sample_rate)
1569 goto found;
1570 break;
1571 case CODEC_TYPE_VIDEO:
1572 if (av1->width == av->width &&
1573 av1->height == av->height &&
1574 av1->frame_rate == av->frame_rate &&
1575 av1->gop_size == av->gop_size)
1576 goto found;
1577 break;
f747e6d3 1578 default:
ec3b2232 1579 av_abort();
85f07f22
FB
1580 }
1581 }
1582 }
1583
1584 fst = av_mallocz(sizeof(AVStream));
1585 if (!fst)
1586 return -1;
1587 fst->priv_data = av_mallocz(sizeof(FeedData));
1588 memcpy(&fst->codec, av, sizeof(AVCodecContext));
1589 feed->streams[feed->nb_streams++] = fst;
1590 return feed->nb_streams - 1;
1591 found:
1592 return i;
1593}
1594
1595/* compute the needed AVStream for each feed */
1596void build_feed_streams(void)
1597{
1598 FFStream *stream, *feed;
1599 int i;
1600
1601 /* gather all streams */
1602 for(stream = first_stream; stream != NULL; stream = stream->next) {
1603 feed = stream->feed;
1604 if (feed) {
1605 if (!stream->is_feed) {
1606 for(i=0;i<stream->nb_streams;i++) {
1607 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
1608 }
1609 } else {
1610 for(i=0;i<stream->nb_streams;i++) {
1611 stream->feed_streams[i] = i;
1612 }
1613 }
1614 }
1615 }
1616
1617 /* create feed files if needed */
1618 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
1619 int fd;
1620
1621 if (!url_exist(feed->feed_filename)) {
1622 AVFormatContext s1, *s = &s1;
1623
1624 /* only write the header of the ffm file */
1625 if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
1626 fprintf(stderr, "Could not open output feed file '%s'\n",
1627 feed->feed_filename);
1628 exit(1);
1629 }
bd7cf6ad 1630 s->oformat = feed->fmt;
85f07f22
FB
1631 s->nb_streams = feed->nb_streams;
1632 for(i=0;i<s->nb_streams;i++) {
1633 AVStream *st;
1634 st = feed->streams[i];
1635 s->streams[i] = st;
1636 }
bd7cf6ad
FB
1637 av_write_header(s);
1638 /* XXX: need better api */
1639 av_freep(&s->priv_data);
85f07f22
FB
1640 url_fclose(&s->pb);
1641 }
1642 /* get feed size and write index */
1643 fd = open(feed->feed_filename, O_RDONLY);
1644 if (fd < 0) {
1645 fprintf(stderr, "Could not open output feed file '%s'\n",
1646 feed->feed_filename);
1647 exit(1);
1648 }
1649
1650 feed->feed_write_index = ffm_read_write_index(fd);
1651 feed->feed_size = lseek(fd, 0, SEEK_END);
1652 /* ensure that we do not wrap before the end of file */
1653 if (feed->feed_max_size < feed->feed_size)
1654 feed->feed_max_size = feed->feed_size;
1655
1656 close(fd);
1657 }
1658}
1659
1660static void get_arg(char *buf, int buf_size, const char **pp)
1661{
1662 const char *p;
1663 char *q;
1664 int quote;
1665
1666 p = *pp;
1667 while (isspace(*p)) p++;
1668 q = buf;
1669 quote = 0;
1670 if (*p == '\"' || *p == '\'')
1671 quote = *p++;
1672 for(;;) {
1673 if (quote) {
1674 if (*p == quote)
1675 break;
1676 } else {
1677 if (isspace(*p))
1678 break;
1679 }
1680 if (*p == '\0')
1681 break;
1682 if ((q - buf) < buf_size - 1)
1683 *q++ = *p;
1684 p++;
1685 }
1686 *q = '\0';
1687 if (quote && *p == quote)
1688 p++;
1689 *pp = p;
1690}
1691
1692/* add a codec and set the default parameters */
1693void add_codec(FFStream *stream, AVCodecContext *av)
1694{
1695 AVStream *st;
1696
1697 /* compute default parameters */
1698 switch(av->codec_type) {
1699 case CODEC_TYPE_AUDIO:
1700 if (av->bit_rate == 0)
1701 av->bit_rate = 64000;
1702 if (av->sample_rate == 0)
1703 av->sample_rate = 22050;
1704 if (av->channels == 0)
1705 av->channels = 1;
1706 break;
1707 case CODEC_TYPE_VIDEO:
1708 if (av->bit_rate == 0)
1709 av->bit_rate = 64000;
1710 if (av->frame_rate == 0)
1711 av->frame_rate = 5 * FRAME_RATE_BASE;
1712 if (av->width == 0 || av->height == 0) {
1713 av->width = 160;
1714 av->height = 128;
1715 }
ba9b374f 1716 /* Bitrate tolerance is less for streaming */
42a63c6a
PG
1717 if (av->bit_rate_tolerance == 0)
1718 av->bit_rate_tolerance = av->bit_rate / 4;
1719 if (av->qmin == 0)
1720 av->qmin = 3;
1721 if (av->qmax == 0)
1722 av->qmax = 31;
1723 if (av->max_qdiff == 0)
1724 av->max_qdiff = 3;
ba9b374f
J
1725 av->qcompress = 0.5;
1726 av->qblur = 0.5;
68d7eef9 1727
85f07f22 1728 break;
f747e6d3 1729 default:
ec3b2232 1730 av_abort();
85f07f22
FB
1731 }
1732
1733 st = av_mallocz(sizeof(AVStream));
1734 if (!st)
1735 return;
1736 stream->streams[stream->nb_streams++] = st;
1737 memcpy(&st->codec, av, sizeof(AVCodecContext));
1738}
1739
f747e6d3
PG
1740int opt_audio_codec(const char *arg)
1741{
1742 AVCodec *p;
1743
1744 p = first_avcodec;
1745 while (p) {
1746 if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
1747 break;
1748 p = p->next;
1749 }
1750 if (p == NULL) {
1751 return CODEC_ID_NONE;
1752 }
1753
1754 return p->id;
1755}
1756
1757int opt_video_codec(const char *arg)
1758{
1759 AVCodec *p;
1760
1761 p = first_avcodec;
1762 while (p) {
1763 if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
1764 break;
1765 p = p->next;
1766 }
1767 if (p == NULL) {
1768 return CODEC_ID_NONE;
1769 }
1770
1771 return p->id;
1772}
1773
85f07f22
FB
1774int parse_ffconfig(const char *filename)
1775{
1776 FILE *f;
1777 char line[1024];
1778 char cmd[64];
1779 char arg[1024];
1780 const char *p;
1781 int val, errors, line_num;
1782 FFStream **last_stream, *stream;
1783 FFStream **last_feed, *feed;
1784 AVCodecContext audio_enc, video_enc;
1785 int audio_id, video_id;
1786
1787 f = fopen(filename, "r");
1788 if (!f) {
1789 perror(filename);
1790 return -1;
1791 }
1792
1793 errors = 0;
1794 line_num = 0;
1795 first_stream = NULL;
1796 last_stream = &first_stream;
1797 first_feed = NULL;
1798 last_feed = &first_feed;
1799 stream = NULL;
1800 feed = NULL;
1801 audio_id = CODEC_ID_NONE;
1802 video_id = CODEC_ID_NONE;
1803 for(;;) {
1804 if (fgets(line, sizeof(line), f) == NULL)
1805 break;
1806 line_num++;
1807 p = line;
1808 while (isspace(*p))
1809 p++;
1810 if (*p == '\0' || *p == '#')
1811 continue;
1812
1813 get_arg(cmd, sizeof(cmd), &p);
1814
1815 if (!strcasecmp(cmd, "Port")) {
1816 get_arg(arg, sizeof(arg), &p);
1817 my_addr.sin_port = htons (atoi(arg));
1818 } else if (!strcasecmp(cmd, "BindAddress")) {
1819 get_arg(arg, sizeof(arg), &p);
1820 if (!inet_aton(arg, &my_addr.sin_addr)) {
1821 fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
1822 filename, line_num, arg);
1823 errors++;
1824 }
1825 } else if (!strcasecmp(cmd, "MaxClients")) {
1826 get_arg(arg, sizeof(arg), &p);
1827 val = atoi(arg);
1828 if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
1829 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
1830 filename, line_num, arg);
1831 errors++;
1832 } else {
1833 nb_max_connections = val;
1834 }
42a63c6a
PG
1835 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
1836 get_arg(arg, sizeof(arg), &p);
1837 val = atoi(arg);
1838 if (val < 10 || val > 100000) {
1839 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
1840 filename, line_num, arg);
1841 errors++;
1842 } else {
1843 nb_max_bandwidth = val;
1844 }
85f07f22
FB
1845 } else if (!strcasecmp(cmd, "CustomLog")) {
1846 get_arg(logfilename, sizeof(logfilename), &p);
1847 } else if (!strcasecmp(cmd, "<Feed")) {
1848 /*********************************************/
1849 /* Feed related options */
1850 char *q;
1851 if (stream || feed) {
1852 fprintf(stderr, "%s:%d: Already in a tag\n",
1853 filename, line_num);
1854 } else {
1855 feed = av_mallocz(sizeof(FFStream));
1856 /* add in stream list */
1857 *last_stream = feed;
1858 last_stream = &feed->next;
1859 /* add in feed list */
1860 *last_feed = feed;
1861 last_feed = &feed->next_feed;
1862
1863 get_arg(feed->filename, sizeof(feed->filename), &p);
1864 q = strrchr(feed->filename, '>');
1865 if (*q)
1866 *q = '\0';
1867 feed->fmt = guess_format("ffm", NULL, NULL);
1868 /* defaut feed file */
1869 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
1870 "/tmp/%s.ffm", feed->filename);
1871 feed->feed_max_size = 5 * 1024 * 1024;
1872 feed->is_feed = 1;
1873 feed->feed = feed; /* self feeding :-) */
1874 }
1875 } else if (!strcasecmp(cmd, "File")) {
1876 if (feed) {
1877 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
1878 } else if (stream) {
1879 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
1880 }
1881 } else if (!strcasecmp(cmd, "FileMaxSize")) {
1882 if (feed) {
1883 const char *p1;
1884 double fsize;
1885
1886 get_arg(arg, sizeof(arg), &p);
1887 p1 = arg;
1888 fsize = strtod(p1, (char **)&p1);
1889 switch(toupper(*p1)) {
1890 case 'K':
1891 fsize *= 1024;
1892 break;
1893 case 'M':
1894 fsize *= 1024 * 1024;
1895 break;
1896 case 'G':
1897 fsize *= 1024 * 1024 * 1024;
1898 break;
1899 }
1900 feed->feed_max_size = (INT64)fsize;
1901 }
1902 } else if (!strcasecmp(cmd, "</Feed>")) {
1903 if (!feed) {
1904 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
1905 filename, line_num);
1906 errors++;
f747e6d3
PG
1907 } else {
1908 /* Make sure that we start out clean */
42a63c6a
PG
1909 if (unlink(feed->feed_filename) < 0
1910 && errno != ENOENT) {
1911 fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
1912 filename, line_num, feed->feed_filename, strerror(errno));
1913 errors++;
1914 }
85f07f22
FB
1915 }
1916 feed = NULL;
1917 } else if (!strcasecmp(cmd, "<Stream")) {
1918 /*********************************************/
1919 /* Stream related options */
1920 char *q;
1921 if (stream || feed) {
1922 fprintf(stderr, "%s:%d: Already in a tag\n",
1923 filename, line_num);
1924 } else {
1925 stream = av_mallocz(sizeof(FFStream));
1926 *last_stream = stream;
1927 last_stream = &stream->next;
1928
1929 get_arg(stream->filename, sizeof(stream->filename), &p);
1930 q = strrchr(stream->filename, '>');
1931 if (*q)
1932 *q = '\0';
1933 stream->fmt = guess_format(NULL, stream->filename, NULL);
1934 memset(&audio_enc, 0, sizeof(AVCodecContext));
1935 memset(&video_enc, 0, sizeof(AVCodecContext));
1936 audio_id = CODEC_ID_NONE;
1937 video_id = CODEC_ID_NONE;
1938 if (stream->fmt) {
1939 audio_id = stream->fmt->audio_codec;
1940 video_id = stream->fmt->video_codec;
1941 }
1942 }
1943 } else if (!strcasecmp(cmd, "Feed")) {
1944 get_arg(arg, sizeof(arg), &p);
1945 if (stream) {
1946 FFStream *sfeed;
1947
1948 sfeed = first_feed;
1949 while (sfeed != NULL) {
1950 if (!strcmp(sfeed->filename, arg))
1951 break;
1952 sfeed = sfeed->next_feed;
1953 }
1954 if (!sfeed) {
1955 fprintf(stderr, "%s:%d: feed '%s' not defined\n",
1956 filename, line_num, arg);
1957 } else {
1958 stream->feed = sfeed;
1959 }
1960 }
1961 } else if (!strcasecmp(cmd, "Format")) {
1962 get_arg(arg, sizeof(arg), &p);
1963 if (!strcmp(arg, "status")) {
1964 stream->stream_type = STREAM_TYPE_STATUS;
1965 stream->fmt = NULL;
1966 } else {
1967 stream->stream_type = STREAM_TYPE_LIVE;
dd2af5aa
FB
1968 /* jpeg cannot be used here, so use single frame jpeg */
1969 if (!strcmp(arg, "jpeg"))
1970 strcpy(arg, "singlejpeg");
85f07f22
FB
1971 stream->fmt = guess_format(arg, NULL, NULL);
1972 if (!stream->fmt) {
1973 fprintf(stderr, "%s:%d: Unknown Format: %s\n",
1974 filename, line_num, arg);
1975 errors++;
1976 }
1977 }
1978 if (stream->fmt) {
1979 audio_id = stream->fmt->audio_codec;
1980 video_id = stream->fmt->video_codec;
1981 }
42a63c6a
PG
1982 } else if (!strcasecmp(cmd, "Preroll")) {
1983 get_arg(arg, sizeof(arg), &p);
1984 if (stream) {
1985 stream->prebuffer = atoi(arg) * 1000;
1986 }
79c4ea3c
PG
1987 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
1988 if (stream) {
1989 stream->send_on_key = 1;
1990 }
f747e6d3
PG
1991 } else if (!strcasecmp(cmd, "AudioCodec")) {
1992 get_arg(arg, sizeof(arg), &p);
1993 audio_id = opt_audio_codec(arg);
1994 if (audio_id == CODEC_ID_NONE) {
1995 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
1996 filename, line_num, arg);
1997 errors++;
1998 }
1999 } else if (!strcasecmp(cmd, "VideoCodec")) {
2000 get_arg(arg, sizeof(arg), &p);
2001 video_id = opt_video_codec(arg);
2002 if (video_id == CODEC_ID_NONE) {
2003 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
2004 filename, line_num, arg);
2005 errors++;
2006 }
ec3b2232
PG
2007 } else if (!strcasecmp(cmd, "MaxTime")) {
2008 get_arg(arg, sizeof(arg), &p);
2009 if (stream) {
2010 stream->max_time = atoi(arg);
2011 }
85f07f22
FB
2012 } else if (!strcasecmp(cmd, "AudioBitRate")) {
2013 get_arg(arg, sizeof(arg), &p);
2014 if (stream) {
2015 audio_enc.bit_rate = atoi(arg) * 1000;
2016 }
2017 } else if (!strcasecmp(cmd, "AudioChannels")) {
2018 get_arg(arg, sizeof(arg), &p);
2019 if (stream) {
2020 audio_enc.channels = atoi(arg);
2021 }
2022 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
2023 get_arg(arg, sizeof(arg), &p);
2024 if (stream) {
2025 audio_enc.sample_rate = atoi(arg);
2026 }
2027 } else if (!strcasecmp(cmd, "VideoBitRate")) {
2028 get_arg(arg, sizeof(arg), &p);
2029 if (stream) {
2030 video_enc.bit_rate = atoi(arg) * 1000;
2031 }
2032 } else if (!strcasecmp(cmd, "VideoSize")) {
2033 get_arg(arg, sizeof(arg), &p);
2034 if (stream) {
2035 parse_image_size(&video_enc.width, &video_enc.height, arg);
2036 if ((video_enc.width % 16) != 0 ||
2037 (video_enc.height % 16) != 0) {
2038 fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
2039 filename, line_num);
2040 errors++;
2041 }
2042 }
2043 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
2044 get_arg(arg, sizeof(arg), &p);
2045 if (stream) {
2046 video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
2047 }
2048 } else if (!strcasecmp(cmd, "VideoGopSize")) {
2049 get_arg(arg, sizeof(arg), &p);
2050 if (stream) {
2051 video_enc.gop_size = atoi(arg);
2052 }
2053 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
2054 if (stream) {
2055 video_enc.gop_size = 1;
2056 }
e7f9c674
J
2057 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
2058 if (stream) {
2059 video_enc.flags |= CODEC_FLAG_HQ;
2060 }
42a63c6a
PG
2061 } else if (!strcasecmp(cmd, "VideoQDiff")) {
2062 if (stream) {
2063 video_enc.max_qdiff = atoi(arg);
2064 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
2065 fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
2066 filename, line_num);
2067 errors++;
2068 }
2069 }
2070 } else if (!strcasecmp(cmd, "VideoQMax")) {
2071 if (stream) {
2072 video_enc.qmax = atoi(arg);
2073 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
2074 fprintf(stderr, "%s:%d: VideoQMax out of range\n",
2075 filename, line_num);
2076 errors++;
2077 }
2078 }
2079 } else if (!strcasecmp(cmd, "VideoQMin")) {
2080 if (stream) {
2081 video_enc.qmin = atoi(arg);
2082 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
2083 fprintf(stderr, "%s:%d: VideoQMin out of range\n",
2084 filename, line_num);
2085 errors++;
2086 }
2087 }
85f07f22
FB
2088 } else if (!strcasecmp(cmd, "NoVideo")) {
2089 video_id = CODEC_ID_NONE;
2090 } else if (!strcasecmp(cmd, "NoAudio")) {
2091 audio_id = CODEC_ID_NONE;
2092 } else if (!strcasecmp(cmd, "</Stream>")) {
2093 if (!stream) {
2094 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
2095 filename, line_num);
2096 errors++;
2097 }
2098 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
2099 if (audio_id != CODEC_ID_NONE) {
2100 audio_enc.codec_type = CODEC_TYPE_AUDIO;
2101 audio_enc.codec_id = audio_id;
2102 add_codec(stream, &audio_enc);
2103 }
2104 if (video_id != CODEC_ID_NONE) {
2105 video_enc.codec_type = CODEC_TYPE_VIDEO;
2106 video_enc.codec_id = video_id;
2107 add_codec(stream, &video_enc);
2108 }
2109 }
2110 stream = NULL;
2111 } else {
2112 fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
2113 filename, line_num, cmd);
2114 errors++;
2115 }
2116 }
2117
2118 fclose(f);
2119 if (errors)
2120 return -1;
2121 else
2122 return 0;
2123}
2124
2125
2126void *http_server_thread(void *arg)
2127{
2128 http_server(my_addr);
2129 return NULL;
2130}
2131
2132#if 0
2133static void write_packet(FFCodec *ffenc,
2134 UINT8 *buf, int size)
2135{
2136 PacketHeader hdr;
2137 AVCodecContext *enc = &ffenc->enc;
2138 UINT8 *wptr;
2139 mk_header(&hdr, enc, size);
2140 wptr = http_fifo.wptr;
2141 fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
2142 fifo_write(&http_fifo, buf, size, &wptr);
2143 /* atomic modification of wptr */
2144 http_fifo.wptr = wptr;
2145 ffenc->data_count += size;
2146 ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
2147}
2148#endif
2149
2150void help(void)
2151{
773a21b8 2152 printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
85f07f22
FB
2153 "usage: ffserver [-L] [-h] [-f configfile]\n"
2154 "Hyper fast multi format Audio/Video streaming server\n"
2155 "\n"
2156 "-L : print the LICENCE\n"
2157 "-h : this help\n"
2158 "-f configfile : use configfile instead of /etc/ffserver.conf\n"
2159 );
2160}
2161
2162void licence(void)
2163{
2164 printf(
2165 "ffserver version " FFMPEG_VERSION "\n"
773a21b8
FB
2166 "Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
2167 "This library is free software; you can redistribute it and/or\n"
2168 "modify it under the terms of the GNU Lesser General Public\n"
2169 "License as published by the Free Software Foundation; either\n"
2170 "version 2 of the License, or (at your option) any later version.\n"
85f07f22 2171 "\n"
773a21b8 2172 "This library is distributed in the hope that it will be useful,\n"
85f07f22 2173 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
773a21b8
FB
2174 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
2175 "Lesser General Public License for more details.\n"
85f07f22 2176 "\n"
773a21b8
FB
2177 "You should have received a copy of the GNU Lesser General Public\n"
2178 "License along with this library; if not, write to the Free Software\n"
2179 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
85f07f22
FB
2180 );
2181}
2182
2183int main(int argc, char **argv)
2184{
2185 const char *config_filename;
2186 int c;
2187
2188 register_all();
2189
2190 config_filename = "/etc/ffserver.conf";
2191
2192 for(;;) {
2193 c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL);
2194 if (c == -1)
2195 break;
2196 switch(c) {
2197 case 'L':
2198 licence();
2199 exit(1);
2200 case '?':
2201 case 'h':
2202 help();
2203 exit(1);
2204 case 'f':
2205 config_filename = optarg;
2206 break;
2207 default:
2208 exit(2);
2209 }
2210 }
2211
2212 /* address on which the server will handle connections */
2213 my_addr.sin_family = AF_INET;
2214 my_addr.sin_port = htons (8080);
2215 my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
2216 nb_max_connections = 5;
42a63c6a 2217 nb_max_bandwidth = 1000;
85f07f22
FB
2218 first_stream = NULL;
2219 logfilename[0] = '\0';
2220
2221 if (parse_ffconfig(config_filename) < 0) {
2222 fprintf(stderr, "Incorrect config file - exiting.\n");
2223 exit(1);
2224 }
2225
2226 build_feed_streams();
2227
2228 /* signal init */
2229 signal(SIGPIPE, SIG_IGN);
2230
2231 /* open log file if needed */
2232 if (logfilename[0] != '\0') {
2233 if (!strcmp(logfilename, "-"))
2234 logfile = stdout;
2235 else
2236 logfile = fopen(logfilename, "w");
2237 }
2238
2239 if (http_server(my_addr) < 0) {
773a21b8 2240 fprintf(stderr, "Could not start http server\n");
85f07f22
FB
2241 exit(1);
2242 }
2243
2244 return 0;
2245}