2 * Multiple format streaming server
3 * Copyright (c) 2000 Gerard Lantau.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <netinet/in.h>
24 #include <linux/videodev.h>
25 #include <linux/soundcard.h>
28 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <arpa/inet.h>
42 /* maximum number of simultaneous HTTP connections */
43 #define HTTP_MAX_CONNECTIONS 2000
46 HTTPSTATE_WAIT_REQUEST,
47 HTTPSTATE_SEND_HEADER,
48 HTTPSTATE_SEND_DATA_HEADER,
50 HTTPSTATE_SEND_DATA_TRAILER,
54 MASTERSTATE_RECEIVE_HEADER,
55 MASTERSTATE_RECEIVE_DATA,
58 #define IOBUFFER_MAX_SIZE 16384
59 #define FIFO_MAX_SIZE (1024*1024)
61 /* coef for exponential mean for bitrate estimation in statistics */
64 /* timeouts are in ms */
65 #define REQUEST_TIMEOUT (15 * 1000)
66 #define SYNC_TIMEOUT (10 * 1000)
67 #define MASTER_CONNECT_TIMEOUT (10 * 1000)
69 typedef struct HTTPContext {
71 int fd; /* socket file descriptor */
72 struct sockaddr_in from_addr; /* origin */
73 struct pollfd *poll_entry; /* used when polling */
75 UINT8 buffer[IOBUFFER_MAX_SIZE];
76 UINT8 *buffer_ptr, *buffer_end;
78 struct HTTPContext *next;
79 UINT8 *rptr; /* read pointer in the fifo */
80 int got_key_frame[2]; /* for each type */
82 long long last_http_fifo_write_count; /* used to monitor overflow in the fifo */
84 struct FFStream *stream;
85 AVFormatContext fmt_ctx;
86 int last_packet_sent; /* true if last data packet was sent */
89 /* each generated stream is described here */
96 typedef struct FFStream {
97 enum StreamType stream_type;
100 AVEncodeContext *audio_enc;
101 AVEncodeContext *video_enc;
102 struct FFStream *next;
105 typedef struct FifoBuffer {
107 UINT8 *rptr, *wptr, *end;
110 /* each codec is here */
111 typedef struct FFCodec {
112 struct FFCodec *next;
113 FifoBuffer fifo; /* for compression: one audio fifo per codec */
114 ReSampleContext resample; /* for audio resampling */
115 long long data_count;
116 float avg_frame_size; /* frame size averraged over last frames with exponential mean */
129 struct sockaddr_in my_addr;
130 char logfilename[1024];
131 HTTPContext *first_http_ctx;
132 FFStream *first_stream;
133 FFCodec *first_codec;
136 char master_url[1024];
137 enum MasterState master_state;
141 long long http_fifo_write_count;
142 static FifoBuffer http_fifo;
144 static int handle_http(HTTPContext *c, long cur_time);
145 static int http_parse_request(HTTPContext *c);
146 static int http_send_data(HTTPContext *c);
147 static int master_receive(int fd);
148 static void compute_stats(HTTPContext *c);
150 int nb_max_connections;
154 int fifo_init(FifoBuffer *f, int size)
156 f->buffer = malloc(size);
159 f->end = f->buffer + size;
160 f->wptr = f->rptr = f->buffer;
164 static int fifo_size(FifoBuffer *f, UINT8 *rptr)
168 if (f->wptr >= rptr) {
169 size = f->wptr - rptr;
171 size = (f->end - rptr) + (f->wptr - f->buffer);
176 /* get data from the fifo (return -1 if not enough data) */
177 static int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr)
179 UINT8 *rptr = *rptr_ptr;
182 if (f->wptr >= rptr) {
183 size = f->wptr - rptr;
185 size = (f->end - rptr) + (f->wptr - f->buffer);
190 while (buf_size > 0) {
194 memcpy(buf, rptr, len);
205 static void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
214 memcpy(wptr, buf, len);
224 static long gettime_ms(void)
228 gettimeofday(&tv,NULL);
229 return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
232 static FILE *logfile = NULL;
234 static void http_log(char *fmt, ...)
240 vfprintf(logfile, fmt, ap);
245 /* connect to url 'url' and return the connected socket ready to read data */
246 static int url_get(const char *url)
248 struct sockaddr_in dest_addr;
250 int s, port, size, line_size, len;
251 char hostname[1024], *q;
252 const char *p, *path;
256 if (!strstart(url, "http://", &p))
259 while (*p != ':' && *p != '\0' && *p != '/') {
260 if ((q - hostname) < (sizeof(hostname) - 1))
267 port = strtol(p, (char **)&p, 10);
271 dest_addr.sin_family = AF_INET;
272 dest_addr.sin_port = htons(port);
274 if (!inet_aton(hostname, &dest_addr.sin_addr)) {
275 if ((h = gethostbyname(hostname)) == NULL)
277 memcpy(&dest_addr.sin_addr, h->h_addr, sizeof(dest_addr.sin_addr));
280 s=socket(AF_INET, SOCK_STREAM, 0);
284 if (connect(s, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) {
290 /* send http request */
291 snprintf(req, sizeof(req), "GET %s HTTP/1.0\r\n\r\n", path);
295 len = write(s, p, size);
297 if (errno != EAGAIN && errno != EINTR)
308 len = read(s, &ch, 1);
310 if (errno != EAGAIN && errno != EINTR)
312 } else if (len == 0) {
319 } else if (ch != '\r') {
328 /* Each request is served by reading the input FIFO and by adding the
329 right format headers */
330 static int http_server(struct sockaddr_in my_addr)
332 int server_fd, tmp, ret;
333 struct sockaddr_in from_addr;
334 struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
335 HTTPContext *c, **cp;
337 int master_fd, master_timeout;
339 /* will try to connect to master as soon as possible */
341 master_timeout = gettime_ms();
343 server_fd = socket(AF_INET,SOCK_STREAM,0);
350 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
352 if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
358 if (listen (server_fd, 5) < 0) {
364 http_log("ffserver started.\n");
366 fcntl(server_fd, F_SETFL, O_NONBLOCK);
367 first_http_ctx = NULL;
369 first_http_ctx = NULL;
371 poll_entry = poll_table;
372 poll_entry->fd = server_fd;
373 poll_entry->events = POLLIN;
376 if (master_fd >= 0) {
377 poll_entry->fd = master_fd;
378 poll_entry->events = POLLIN;
382 /* wait for events on each HTTP handle */
388 case HTTPSTATE_WAIT_REQUEST:
389 c->poll_entry = poll_entry;
391 poll_entry->events = POLLIN;
394 case HTTPSTATE_SEND_HEADER:
395 case HTTPSTATE_SEND_DATA_HEADER:
396 case HTTPSTATE_SEND_DATA:
397 case HTTPSTATE_SEND_DATA_TRAILER:
398 c->poll_entry = poll_entry;
400 poll_entry->events = POLLOUT;
404 c->poll_entry = NULL;
410 /* wait for an event on one connection. We poll at least every
411 second to handle timeouts */
413 ret = poll(poll_table, poll_entry - poll_table, 1000);
416 cur_time = gettime_ms();
418 /* now handle the events */
420 cp = &first_http_ctx;
421 while ((*cp) != NULL) {
423 if (handle_http (c, cur_time) < 0) {
424 /* close and free the connection */
434 /* new connection request ? */
435 poll_entry = poll_table;
436 if (poll_entry->revents & POLLIN) {
439 len = sizeof(from_addr);
440 fd = accept(server_fd, &from_addr, &len);
442 fcntl(fd, F_SETFL, O_NONBLOCK);
443 /* XXX: should output a warning page when comming
444 close to the connection limit */
445 if (nb_connections >= nb_max_connections) {
448 /* add a new connection */
449 c = malloc(sizeof(HTTPContext));
450 memset(c, 0, sizeof(*c));
451 c->next = first_http_ctx;
454 c->poll_entry = NULL;
455 c->from_addr = from_addr;
456 c->state = HTTPSTATE_WAIT_REQUEST;
457 c->buffer_ptr = c->buffer;
458 c->buffer_end = c->buffer + IOBUFFER_MAX_SIZE;
459 c->timeout = cur_time + REQUEST_TIMEOUT;
467 if (poll_entry->revents & POLLIN) {
468 if (master_receive(master_fd) < 0) {
474 /* master (re)connection handling */
475 if (master_url[0] != '\0' &&
476 master_fd < 0 && (master_timeout - cur_time) <= 0) {
477 master_fd = url_get(master_url);
479 master_timeout = gettime_ms() + MASTER_CONNECT_TIMEOUT;
480 http_log("Connection to master: '%s' failed\n", master_url);
482 fcntl(master_fd, F_SETFL, O_NONBLOCK);
483 master_state = MASTERSTATE_RECEIVE_HEADER;
484 master_count = sizeof(PacketHeader);
485 master_wptr = http_fifo.wptr;
491 static int handle_http(HTTPContext *c, long cur_time)
496 case HTTPSTATE_WAIT_REQUEST:
498 if ((c->timeout - cur_time) < 0)
500 if (c->poll_entry->revents & (POLLERR | POLLHUP))
503 /* no need to read if no events */
504 if (!(c->poll_entry->revents & POLLIN))
507 len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
509 if (errno != EAGAIN && errno != EINTR)
511 } else if (len == 0) {
514 /* search for end of request. XXX: not fully correct since garbage could come after the end */
516 c->buffer_ptr += len;
518 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
519 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
520 /* request found : parse it and reply */
521 if (http_parse_request(c) < 0)
523 } else if (ptr >= c->buffer_end) {
524 /* request too long: cannot do anything */
530 case HTTPSTATE_SEND_HEADER:
531 if (c->poll_entry->revents & (POLLERR | POLLHUP))
534 /* no need to read if no events */
535 if (!(c->poll_entry->revents & POLLOUT))
537 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
539 if (errno != EAGAIN && errno != EINTR) {
540 /* error : close connection */
544 c->buffer_ptr += len;
545 if (c->buffer_ptr >= c->buffer_end) {
549 /* all the buffer was send : synchronize to the incoming stream */
550 c->state = HTTPSTATE_SEND_DATA_HEADER;
551 c->buffer_ptr = c->buffer_end = c->buffer;
556 case HTTPSTATE_SEND_DATA:
557 case HTTPSTATE_SEND_DATA_HEADER:
558 case HTTPSTATE_SEND_DATA_TRAILER:
559 /* no need to read if no events */
560 if (c->poll_entry->revents & (POLLERR | POLLHUP))
563 if (!(c->poll_entry->revents & POLLOUT))
565 if (http_send_data(c) < 0)
574 /* parse http request and prepare header */
575 static int http_parse_request(HTTPContext *c)
587 while (!isspace(*p) && *p != '\0') {
588 if ((q - cmd) < sizeof(cmd) - 1)
593 if (strcmp(cmd, "GET"))
596 while (isspace(*p)) p++;
598 while (!isspace(*p) && *p != '\0') {
599 if ((q - url) < sizeof(url) - 1)
605 while (isspace(*p)) p++;
607 while (!isspace(*p) && *p != '\0') {
608 if ((q - protocol) < sizeof(protocol) - 1)
613 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
616 /* find the filename in the request */
621 stream = first_stream;
622 while (stream != NULL) {
623 if (!strcmp(stream->filename, p))
625 stream = stream->next;
627 if (stream == NULL) {
628 sprintf(msg, "File '%s' not found", url);
633 /* should do it after so that the size can be computed */
635 char buf1[32], buf2[32], *p;
637 /* XXX: reentrant function ? */
638 p = inet_ntoa(c->from_addr.sin_addr);
643 p = buf2 + strlen(p) - 1;
646 http_log("%s - - [%s] \"%s %s %s\" %d %d\n",
647 buf1, buf2, cmd, url, protocol, 200, 1024);
650 if (c->stream->stream_type == STREAM_TYPE_STATUS)
653 /* prepare http header */
655 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
656 mime_type = c->stream->fmt->mime_type;
658 mime_type = "application/x-octet_stream";
659 q += sprintf(q, "Content-type: %s\r\n", mime_type);
660 q += sprintf(q, "Pragma: no-cache\r\n");
661 /* for asf, we need extra headers */
662 if (!strcmp(c->stream->fmt->name,"asf")) {
663 q += sprintf(q, "Pragma: features=broadcast\r\n");
665 q += sprintf(q, "\r\n");
667 /* prepare output buffer */
669 c->buffer_ptr = c->buffer;
671 c->state = HTTPSTATE_SEND_HEADER;
676 q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
677 q += sprintf(q, "Content-type: %s\r\n", "text/html");
678 q += sprintf(q, "\r\n");
679 q += sprintf(q, "<HTML>\n");
680 q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
681 q += sprintf(q, "<BODY>%s</BODY>\n", msg);
682 q += sprintf(q, "</HTML>\n");
684 /* prepare output buffer */
685 c->buffer_ptr = c->buffer;
687 c->state = HTTPSTATE_SEND_HEADER;
691 c->http_error = 200; /* horrible : we use this value to avoid
692 going to the send data state */
693 c->state = HTTPSTATE_SEND_HEADER;
697 static void compute_stats(HTTPContext *c)
699 AVEncodeContext *enc;
704 char buf[1024], *q, *p;
709 q += sprintf(q, "HTTP/1.0 200 OK\r\n");
710 q += sprintf(q, "Content-type: %s\r\n", "text/html");
711 q += sprintf(q, "Pragma: no-cache\r\n");
712 q += sprintf(q, "\r\n");
714 q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE></HEAD>\n<BODY>");
715 q += sprintf(q, "<H1>FFServer Status</H1>\n");
717 q += sprintf(q, "<H1>Available Streams</H1>\n");
718 q += sprintf(q, "<TABLE>\n");
719 q += sprintf(q, "<TR><TD>Path<TD>Format<TD>Bit rate (kbits/s)<TD>Video<TD>Audio\n");
720 stream = first_stream;
721 while (stream != NULL) {
722 q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ",
723 stream->filename, stream->filename);
724 switch(stream->stream_type) {
725 case STREAM_TYPE_LIVE:
727 int audio_bit_rate = 0;
728 int video_bit_rate = 0;
729 if (stream->audio_enc)
730 audio_bit_rate = stream->audio_enc->bit_rate;
731 if (stream->video_enc)
732 video_bit_rate = stream->video_enc->bit_rate;
734 q += sprintf(q, "<TD> %s <TD> %d <TD> %d <TD> %d\n",
736 (audio_bit_rate + video_bit_rate) / 1000,
737 video_bit_rate / 1000, audio_bit_rate / 1000);
740 case STREAM_TYPE_MASTER:
741 q += sprintf(q, "<TD> %s <TD> - <TD> - <TD> -\n",
745 q += sprintf(q, "<TD> - <TD> - <TD> - <TD> -\n");
748 stream = stream->next;
750 q += sprintf(q, "</TABLE>\n");
753 q += sprintf(q, "<H1>Codec Status</H1>\n");
754 q += sprintf(q, "<TABLE>\n");
755 q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
757 while (ffenc != NULL) {
759 avencoder_string(buf, sizeof(buf), enc);
760 avg = ffenc->avg_frame_size * (float)enc->rate * 8.0;
761 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
762 avg /= enc->frame_size;
763 q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n",
764 buf, enc->frame_number, ffenc->data_count, avg / 1000.0);
767 q += sprintf(q, "</TABLE>\n");
769 /* exclude the stat connection */
770 q += sprintf(q, "Number of connections: %d / %d<BR>\n",
771 nb_connections, nb_max_connections);
773 /* connection status */
774 q += sprintf(q, "<H1>Connection Status</H1>\n");
775 q += sprintf(q, "<TABLE>\n");
776 q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>Size\n");
781 p = inet_ntoa(c1->from_addr.sin_addr);
782 q += sprintf(q, "<TR><TD><B>%d</B><TD>%s <TD> %s <TD> %Ld\n",
783 i, c1->stream->filename, p, c1->data_count);
786 q += sprintf(q, "</TABLE>\n");
791 q += sprintf(q, "<HR>Generated at %s", p);
792 q += sprintf(q, "</BODY>\n</HTML>\n");
794 c->buffer_ptr = c->buffer;
799 static void http_write_packet(void *opaque,
800 unsigned char *buf, int size)
802 HTTPContext *c = opaque;
803 if (size > IOBUFFER_MAX_SIZE)
805 memcpy(c->buffer, buf, size);
806 c->buffer_ptr = c->buffer;
807 c->buffer_end = c->buffer + size;
810 /* this headers are used to identify a packet for a given codec */
811 void mk_header(PacketHeader *h, AVEncodeContext *c, int payload_size)
813 h->codec_type = c->codec->type;
814 h->codec_id = c->codec->id;
815 h->bit_rate = htons(c->bit_rate / 1000);
816 switch(c->codec->type) {
817 case CODEC_TYPE_VIDEO:
818 h->data[0] = c->rate;
819 h->data[1] = c->width / 16;
820 h->data[2] = c->height / 16;
822 case CODEC_TYPE_AUDIO:
823 h->data[0] = c->rate / 1000;
824 h->data[1] = c->channels;
828 h->data[3] = c->key_frame;
829 h->payload_size = htons(payload_size);
832 int test_header(PacketHeader *h, AVEncodeContext *c)
837 if (h->codec_type == c->codec->type &&
838 h->codec_id == c->codec->id &&
839 h->bit_rate == htons(c->bit_rate / 1000)) {
841 switch(c->codec->type) {
842 case CODEC_TYPE_VIDEO:
843 if (h->data[0] == c->rate &&
844 h->data[1] == (c->width / 16) &&
845 h->data[2] == (c->height / 16))
848 case CODEC_TYPE_AUDIO:
849 if (h->data[0] == (c->rate / 1000) &&
850 (h->data[1] == c->channels))
858 c->key_frame = h->data[3];
862 static int http_prepare_data(HTTPContext *c)
865 UINT8 *start_rptr, *payload;
866 int payload_size, ret;
867 long long fifo_total_size;
870 case HTTPSTATE_SEND_DATA_HEADER:
871 if (c->stream->stream_type != STREAM_TYPE_MASTER) {
872 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
873 c->fmt_ctx.format = c->stream->fmt;
874 if (c->fmt_ctx.format->audio_codec != CODEC_ID_NONE) {
875 /* create a fake new codec instance */
876 c->fmt_ctx.audio_enc = malloc(sizeof(AVEncodeContext));
877 memcpy(c->fmt_ctx.audio_enc, c->stream->audio_enc,
878 sizeof(AVEncodeContext));
879 c->fmt_ctx.audio_enc->frame_number = 0;
881 if (c->fmt_ctx.format->video_codec != CODEC_ID_NONE) {
882 c->fmt_ctx.video_enc = malloc(sizeof(AVEncodeContext));
883 memcpy(c->fmt_ctx.video_enc, c->stream->video_enc,
884 sizeof(AVEncodeContext));
885 c->fmt_ctx.video_enc->frame_number = 0;
887 init_put_byte(&c->fmt_ctx.pb, c->buffer, IOBUFFER_MAX_SIZE,
888 c, http_write_packet, NULL);
889 c->fmt_ctx.is_streamed = 1;
890 c->got_key_frame[0] = 0;
891 c->got_key_frame[1] = 0;
893 c->fmt_ctx.format->write_header(&c->fmt_ctx);
895 c->state = HTTPSTATE_SEND_DATA;
896 c->last_packet_sent = 0;
897 c->rptr = http_fifo.wptr;
898 c->last_http_fifo_write_count = http_fifo_write_count;
900 case HTTPSTATE_SEND_DATA:
901 /* find a new packet */
902 fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
903 if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
904 /* overflow : resync. We suppose that wptr is at this
905 point a pointer to a valid packet */
906 c->rptr = http_fifo.wptr;
907 c->got_key_frame[0] = 0;
908 c->got_key_frame[1] = 0;
911 start_rptr = c->rptr;
912 if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
914 payload_size = ntohs(hdr.payload_size);
915 payload = malloc(payload_size);
916 if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
917 /* cannot read all the payload */
919 c->rptr = start_rptr;
923 c->last_http_fifo_write_count = http_fifo_write_count -
924 fifo_size(&http_fifo, c->rptr);
926 if (c->stream->stream_type != STREAM_TYPE_MASTER) {
927 /* test if the packet can be handled by this format */
929 if (test_header(&hdr, c->fmt_ctx.audio_enc)) {
930 /* only begin sending when got a key frame */
931 if (c->fmt_ctx.audio_enc->key_frame)
932 c->got_key_frame[1] = 1;
933 if (c->got_key_frame[1]) {
934 ret = c->fmt_ctx.format->write_audio_frame(&c->fmt_ctx,
935 payload, payload_size);
937 } else if (test_header(&hdr, c->fmt_ctx.video_enc)) {
938 if (c->fmt_ctx.video_enc->key_frame)
939 c->got_key_frame[0] = 1;
940 if (c->got_key_frame[0]) {
941 ret = c->fmt_ctx.format->write_video_picture(&c->fmt_ctx,
942 payload, payload_size);
946 /* must send trailer now */
947 c->state = HTTPSTATE_SEND_DATA_TRAILER;
950 /* master case : send everything */
953 memcpy(q, &hdr, sizeof(hdr));
955 memcpy(q, payload, payload_size);
957 c->buffer_ptr = c->buffer;
963 case HTTPSTATE_SEND_DATA_TRAILER:
964 /* last packet test ? */
965 if (c->last_packet_sent)
968 c->fmt_ctx.format->write_trailer(&c->fmt_ctx);
969 c->last_packet_sent = 1;
976 /* should convert the format at the same time */
977 static int http_send_data(HTTPContext *c)
981 while (c->buffer_ptr >= c->buffer_end) {
982 if (http_prepare_data(c) < 0)
986 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
988 if (errno != EAGAIN && errno != EINTR) {
989 /* error : close connection */
993 c->buffer_ptr += len;
994 c->data_count += len;
999 static int master_receive(int fd)
1002 FifoBuffer *f = &http_fifo;
1005 size = f->end - f->wptr;
1006 if (size > master_count)
1007 size = master_count;
1008 len = read(fd, f->wptr, size);
1010 if (errno != EAGAIN && errno != EINTR)
1012 } else if (len == 0) {
1016 if (master_wptr >= f->end)
1017 master_wptr = f->buffer;
1018 master_count -= len;
1019 if (master_count == 0) {
1020 if (master_state == MASTERSTATE_RECEIVE_HEADER) {
1021 /* XXX: use generic fifo read to extract packet header */
1023 if (rptr == f->buffer)
1027 master_count = *rptr;
1028 if (rptr == f->buffer)
1032 master_count |= *rptr << 8;
1033 master_state = MASTERSTATE_RECEIVE_DATA;
1035 /* update fifo wptr */
1036 f->wptr = master_wptr;
1037 master_state = MASTERSTATE_RECEIVE_HEADER;
1044 static void get_arg(char *buf, int buf_size, const char **pp)
1050 while (isspace(*p)) p++;
1052 while (!isspace(*p) && *p != '\0') {
1053 if ((q - buf) < buf_size - 1)
1061 /* add a codec and check if it does not already exists */
1062 AVEncodeContext *add_codec(int codec_id,
1063 AVEncodeContext *av)
1066 FFCodec *ctx, **pctx;
1067 AVEncodeContext *av1;
1069 codec = avencoder_find(codec_id);
1073 /* compute default parameters */
1075 switch(codec->type) {
1076 case CODEC_TYPE_AUDIO:
1077 if (av->bit_rate == 0)
1078 av->bit_rate = 64000;
1081 if (av->channels == 0)
1084 case CODEC_TYPE_VIDEO:
1085 if (av->bit_rate == 0)
1086 av->bit_rate = 64000;
1089 if (av->width == 0 || av->height == 0) {
1096 /* find if the codec already exists */
1097 pctx = &first_codec;
1098 while (*pctx != NULL) {
1099 av1 = &(*pctx)->enc;
1100 if (av1->codec == av->codec &&
1101 av1->bit_rate == av->bit_rate &&
1102 av1->rate == av->rate) {
1104 switch(av->codec->type) {
1105 case CODEC_TYPE_AUDIO:
1106 if (av1->channels == av->channels)
1109 case CODEC_TYPE_VIDEO:
1110 if (av1->width == av->width &&
1111 av1->height == av->height &&
1112 av1->gop_size == av->gop_size)
1117 pctx = &(*pctx)->next;
1120 ctx = malloc(sizeof(FFCodec));
1123 memset(ctx, 0, sizeof(FFCodec));
1126 memcpy(&ctx->enc, av, sizeof(AVEncodeContext));
1133 int parse_ffconfig(const char *filename)
1140 int val, errors, line_num;
1141 FFStream **last_stream, *stream;
1142 AVEncodeContext audio_enc, video_enc;
1144 f = fopen(filename, "r");
1152 first_stream = NULL;
1154 last_stream = &first_stream;
1157 if (fgets(line, sizeof(line), f) == NULL)
1163 if (*p == '\0' || *p == '#')
1166 get_arg(cmd, sizeof(cmd), &p);
1168 if (!strcasecmp(cmd, "Port")) {
1169 get_arg(arg, sizeof(arg), &p);
1170 my_addr.sin_port = htons (atoi(arg));
1171 } else if (!strcasecmp(cmd, "BindAddress")) {
1172 get_arg(arg, sizeof(arg), &p);
1173 if (!inet_aton(arg, &my_addr.sin_addr)) {
1174 fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
1175 filename, line_num, arg);
1178 } else if (!strcasecmp(cmd, "MasterServer")) {
1179 get_arg(master_url, sizeof(master_url), &p);
1180 if (!strstart(master_url, "http://", NULL)) {
1181 fprintf(stderr, "%s:%d: Invalid URL for master server: %s\n",
1182 filename, line_num, master_url);
1185 } else if (!strcasecmp(cmd, "MaxClients")) {
1186 get_arg(arg, sizeof(arg), &p);
1188 if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
1189 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
1190 filename, line_num, arg);
1193 nb_max_connections = val;
1195 } else if (!strcasecmp(cmd, "CustomLog")) {
1196 get_arg(logfilename, sizeof(logfilename), &p);
1197 } else if (!strcasecmp(cmd, "<Stream")) {
1200 fprintf(stderr, "%s:%d: Already in a stream tag\n",
1201 filename, line_num);
1203 stream = malloc(sizeof(FFStream));
1204 memset(stream, 0, sizeof(FFStream));
1205 *last_stream = stream;
1206 last_stream = &stream->next;
1208 get_arg(stream->filename, sizeof(stream->filename), &p);
1209 q = strrchr(stream->filename, '>');
1212 stream->fmt = guess_format(NULL, stream->filename, NULL);
1213 memset(&audio_enc, 0, sizeof(AVEncodeContext));
1214 memset(&video_enc, 0, sizeof(AVEncodeContext));
1216 } else if (!strcasecmp(cmd, "Format")) {
1217 get_arg(arg, sizeof(arg), &p);
1218 if (!strcmp(arg, "master")) {
1219 stream->stream_type = STREAM_TYPE_MASTER;
1221 } else if (!strcmp(arg, "status")) {
1222 stream->stream_type = STREAM_TYPE_STATUS;
1225 stream->stream_type = STREAM_TYPE_LIVE;
1226 stream->fmt = guess_format(arg, NULL, NULL);
1228 fprintf(stderr, "%s:%d: Unknown Format: %s\n",
1229 filename, line_num, arg);
1233 } else if (!strcasecmp(cmd, "AudioBitRate")) {
1234 get_arg(arg, sizeof(arg), &p);
1236 audio_enc.bit_rate = atoi(arg) * 1000;
1238 } else if (!strcasecmp(cmd, "AudioChannels")) {
1239 get_arg(arg, sizeof(arg), &p);
1241 audio_enc.channels = atoi(arg);
1243 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
1244 get_arg(arg, sizeof(arg), &p);
1246 audio_enc.rate = atoi(arg);
1248 } else if (!strcasecmp(cmd, "VideoBitRate")) {
1249 get_arg(arg, sizeof(arg), &p);
1251 video_enc.bit_rate = atoi(arg) * 1000;
1253 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
1254 get_arg(arg, sizeof(arg), &p);
1256 video_enc.rate = atoi(arg);
1258 } else if (!strcasecmp(cmd, "VideoGopSize")) {
1259 get_arg(arg, sizeof(arg), &p);
1261 video_enc.gop_size = atoi(arg);
1263 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
1265 video_enc.gop_size = 1;
1267 } else if (!strcasecmp(cmd, "</Stream>")) {
1269 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
1270 filename, line_num);
1274 if (stream->fmt->audio_codec != CODEC_ID_NONE) {
1275 stream->audio_enc = add_codec(stream->fmt->audio_codec,
1279 if (stream->fmt->video_codec != CODEC_ID_NONE)
1280 stream->video_enc = add_codec(stream->fmt->video_codec,
1285 fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
1286 filename, line_num, cmd);
1299 void *http_server_thread(void *arg)
1301 http_server(my_addr);
1305 static void write_packet(FFCodec *ffenc,
1306 UINT8 *buf, int size)
1309 AVEncodeContext *enc = &ffenc->enc;
1311 mk_header(&hdr, enc, size);
1312 wptr = http_fifo.wptr;
1313 fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
1314 fifo_write(&http_fifo, buf, size, &wptr);
1315 /* atomic modification of wptr */
1316 http_fifo.wptr = wptr;
1317 ffenc->data_count += size;
1318 ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
1321 #define AUDIO_FIFO_SIZE 8192
1325 UINT8 audio_buf[AUDIO_FIFO_SIZE/2];
1326 UINT8 audio_buf1[AUDIO_FIFO_SIZE/2];
1327 UINT8 audio_out[AUDIO_FIFO_SIZE/2];
1328 UINT8 video_buffer[128*1024];
1334 AVEncodeContext *enc;
1335 int frame_size, frame_bytes;
1336 int use_audio, use_video;
1337 int frame_rate, sample_rate, channels;
1338 int width, height, frame_number;
1350 ffenc = first_codec;
1351 while (ffenc != NULL) {
1353 avencoder_string(buf, sizeof(buf), enc);
1354 fprintf(stderr, " %s\n", buf);
1355 if (avencoder_open(enc, enc->codec) < 0) {
1356 fprintf(stderr, "Incorrect encode parameters\n");
1359 switch(enc->codec->type) {
1360 case CODEC_TYPE_AUDIO:
1362 if (enc->rate > sample_rate)
1363 sample_rate = enc->rate;
1364 if (enc->frame_size > frame_size)
1365 frame_size = enc->frame_size;
1366 if (enc->channels > channels)
1367 channels = enc->channels;
1368 fifo_init(&ffenc->fifo, AUDIO_FIFO_SIZE);
1370 case CODEC_TYPE_VIDEO:
1372 if (enc->rate > frame_rate)
1373 frame_rate = enc->rate;
1374 if (enc->width > width)
1376 if (enc->height > height)
1377 height = enc->height;
1380 ffenc = ffenc->next;
1387 printf("Audio sampling: %d Hz, %s\n",
1388 sample_rate, channels == 2 ? "stereo" : "mono");
1389 audio_fd = audio_open(sample_rate, channels);
1391 fprintf(stderr, "Could not open audio device\n");
1396 ffenc = first_codec;
1397 while (ffenc != NULL) {
1399 if (enc->codec->type == CODEC_TYPE_AUDIO &&
1400 (enc->channels != channels ||
1401 enc->rate != sample_rate)) {
1402 audio_resample_init(&ffenc->resample, enc->channels, channels,
1403 enc->rate, sample_rate);
1405 ffenc = ffenc->next;
1410 printf("Video sampling: %dx%d, %d fps\n",
1411 width, height, frame_rate);
1412 ret = v4l_init(frame_rate, width, height);
1414 fprintf(stderr,"Could not init video 4 linux capture\n");
1420 /* read & compress audio frames */
1422 int ret, nb_samples, nb_samples_out;
1426 ret = read(audio_fd, audio_buf, AUDIO_FIFO_SIZE/2);
1429 /* fill each codec fifo by doing the right sample
1430 rate conversion. This is not optimal because we
1431 do too much work, but it is easy to do */
1432 nb_samples = ret / (channels * 2);
1433 ffenc = first_codec;
1434 while (ffenc != NULL) {
1436 if (enc->codec->type == CODEC_TYPE_AUDIO) {
1437 /* rate & stereo convertion */
1438 if (enc->channels == channels &&
1439 enc->rate == sample_rate) {
1441 nb_samples_out = nb_samples;
1443 buftmp = audio_buf1;
1444 nb_samples_out = audio_resample(&ffenc->resample,
1445 (short *)buftmp, (short *)audio_buf,
1449 fifo_write(&ffenc->fifo, buftmp, nb_samples_out * enc->channels * 2,
1452 ffenc = ffenc->next;
1455 /* compress as many frame as possible with each audio codec */
1456 ffenc = first_codec;
1457 while (ffenc != NULL) {
1459 if (enc->codec->type == CODEC_TYPE_AUDIO) {
1460 frame_bytes = enc->frame_size * 2 * enc->channels;
1462 while (fifo_read(&ffenc->fifo, audio_buf, frame_bytes, &ffenc->fifo.rptr) == 0) {
1463 ret = avencoder_encode(enc,
1464 audio_out, sizeof(audio_out), audio_buf);
1465 write_packet(ffenc, audio_out, ret);
1468 ffenc = ffenc->next;
1474 ret = v4l_read_picture (picture, width, height,
1478 ffenc = first_codec;
1479 while (ffenc != NULL) {
1481 if (enc->codec->type == CODEC_TYPE_VIDEO) {
1483 /* feed each codec with its requested frame rate */
1484 n1 = (frame_number * enc->rate) / frame_rate;
1485 n2 = ((frame_number + 1) * enc->rate) / frame_rate;
1487 ret = avencoder_encode(enc, video_buffer, sizeof(video_buffer), picture);
1488 write_packet(ffenc, video_buffer, ret);
1491 ffenc = ffenc->next;
1497 ffenc = first_codec;
1498 while (ffenc != NULL) {
1500 avencoder_close(enc);
1501 ffenc = ffenc->next;
1510 printf("ffserver version 1.0, Copyright (c) 2000 Gerard Lantau\n"
1511 "usage: ffserver [-L] [-h] [-f configfile]\n"
1512 "Hyper fast multi format Audio/Video streaming server\n"
1514 "-L : print the LICENCE\n"
1516 "-f configfile : use configfile instead of /etc/ffserver.conf\n"
1523 "ffserver version 1.0\n"
1524 "Copyright (c) 2000 Gerard Lantau\n"
1525 "This program is free software; you can redistribute it and/or modify\n"
1526 "it under the terms of the GNU General Public License as published by\n"
1527 "the Free Software Foundation; either version 2 of the License, or\n"
1528 "(at your option) any later version.\n"
1530 "This program is distributed in the hope that it will be useful,\n"
1531 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1532 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1533 "GNU General Public License for more details.\n"
1535 "You should have received a copy of the GNU General Public License\n"
1536 "along with this program; if not, write to the Free Software\n"
1537 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
1541 int main(int argc, char **argv)
1543 pthread_t http_server_tid;
1544 const char *config_filename;
1548 register_avencoder(&ac3_encoder);
1549 register_avencoder(&mp2_encoder);
1550 register_avencoder(&mpeg1video_encoder);
1551 register_avencoder(&h263_encoder);
1552 register_avencoder(&rv10_encoder);
1553 register_avencoder(&mjpeg_encoder);
1555 /* audio video formats */
1556 register_avformat(&mp2_format);
1557 register_avformat(&ac3_format);
1558 register_avformat(&mpeg_mux_format);
1559 register_avformat(&mpeg1video_format);
1560 register_avformat(&h263_format);
1561 register_avformat(&rm_format);
1562 register_avformat(&ra_format);
1563 register_avformat(&asf_format);
1564 register_avformat(&mpjpeg_format);
1565 register_avformat(&jpeg_format);
1566 register_avformat(&swf_format);
1568 config_filename = "/etc/ffserver.conf";
1571 c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL);
1583 config_filename = optarg;
1590 /* address on which the server will handle connections */
1591 my_addr.sin_family = AF_INET;
1592 my_addr.sin_port = htons (8080);
1593 my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
1594 nb_max_connections = 5;
1595 first_stream = NULL;
1596 logfilename[0] = '\0';
1598 if (parse_ffconfig(config_filename) < 0) {
1599 fprintf(stderr, "Incorrect config file - exiting.\n");
1603 /* open log file if needed */
1604 if (logfilename[0] != '\0') {
1605 if (!strcmp(logfilename, "-"))
1608 logfile = fopen(logfilename, "w");
1612 http_fifo_write_count = 0;
1613 if (fifo_init(&http_fifo, FIFO_MAX_SIZE) < 0) {
1614 fprintf(stderr, "Could not allow receive fifo\n");
1618 if (master_url[0] == '\0') {
1619 /* no master server: we grab ourself */
1621 /* launch server thread */
1622 if (pthread_create(&http_server_tid, NULL,
1623 http_server_thread, NULL) != 0) {
1624 fprintf(stderr, "Could not create http server thread\n");
1628 /* launch the audio / video grab */
1629 if (av_grab() < 0) {
1630 fprintf(stderr, "Could not start audio/video grab\n");
1634 /* master server : no thread are needed */
1635 if (http_server(my_addr) < 0) {
1636 fprintf(stderr, "Could start http server\n");