]> git.sesse.net Git - ffmpeg/blob - ffserver.c
* Fix a nasty problem with output buffering not have enough (or large enough)
[ffmpeg] / ffserver.c
1 /*
2  * Multiple format streaming server
3  * Copyright (c) 2000,2001 Gerard Lantau.
4  *
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.
9  *
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.
14  *
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.
18  */
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
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>
38 #include <assert.h>
39
40 #include "bswap.h" // needed for the bitstream writer in common.h which is included in avformat.h
41 #include "avformat.h"
42
43 /* maximum number of simultaneous HTTP connections */
44 #define HTTP_MAX_CONNECTIONS 2000
45
46 enum HTTPState {
47     HTTPSTATE_WAIT_REQUEST,
48     HTTPSTATE_SEND_HEADER,
49     HTTPSTATE_SEND_DATA_HEADER,
50     HTTPSTATE_SEND_DATA,
51     HTTPSTATE_SEND_DATA_TRAILER,
52     HTTPSTATE_RECEIVE_DATA,
53     HTTPSTATE_WAIT_FEED,
54 };
55
56 const char *http_state[] = {
57     "WAIT_REQUEST",
58     "SEND_HEADER",
59     "SEND_DATA_HEADER",
60     "SEND_DATA",
61     "SEND_DATA_TRAILER",
62     "RECEIVE_DATA",
63     "WAIT_FEED",
64 };
65
66 #define IOBUFFER_MAX_SIZE 32768
67 #define PACKET_MAX_SIZE 16384
68
69 /* coef for exponential mean for bitrate estimation in statistics */
70 #define AVG_COEF 0.9
71
72 /* timeouts are in ms */
73 #define REQUEST_TIMEOUT (15 * 1000)
74 #define SYNC_TIMEOUT (10 * 1000)
75
76 /* context associated with one connection */
77 typedef struct HTTPContext {
78     enum HTTPState state;
79     int fd; /* socket file descriptor */
80     struct sockaddr_in from_addr; /* origin */
81     struct pollfd *poll_entry; /* used when polling */
82     long timeout;
83     UINT8 *buffer_ptr, *buffer_end;
84     int http_error;
85     struct HTTPContext *next;
86     int got_key_frame[MAX_STREAMS]; /* for each type */
87     INT64 data_count;
88     /* feed input */
89     int feed_fd;
90     /* input format handling */
91     AVFormatContext *fmt_in;
92     /* output format handling */
93     struct FFStream *stream;
94     AVFormatContext fmt_ctx;
95     int last_packet_sent; /* true if last data packet was sent */
96     UINT8 buffer[IOBUFFER_MAX_SIZE];
97     UINT8 pbuffer[PACKET_MAX_SIZE];
98 } HTTPContext;
99
100 /* each generated stream is described here */
101 enum StreamType {
102     STREAM_TYPE_LIVE,
103     STREAM_TYPE_STATUS,
104 };
105
106 /* description of each stream of the ffserver.conf file */
107 typedef struct FFStream {
108     enum StreamType stream_type;
109     char filename[1024];     /* stream filename */
110     struct FFStream *feed;
111     AVFormat *fmt;
112     int nb_streams;
113     AVStream *streams[MAX_STREAMS];
114     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
115     char feed_filename[1024]; /* file name of the feed storage, or
116                                  input file name for a stream */
117     struct FFStream *next;
118     /* feed specific */
119     int feed_opened;     /* true if someone if writing to feed */
120     int is_feed;         /* true if it is a feed */
121     INT64 feed_max_size;      /* maximum storage size */
122     INT64 feed_write_index;   /* current write position in feed (it wraps round) */
123     INT64 feed_size;          /* current size of feed */
124     struct FFStream *next_feed;
125 } FFStream;
126
127 typedef struct FeedData {
128     long long data_count;
129     float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
130 } FeedData;
131
132 struct sockaddr_in my_addr;
133 char logfilename[1024];
134 HTTPContext *first_http_ctx;
135 FFStream *first_feed;   /* contains only feeds */
136 FFStream *first_stream; /* contains all streams, including feeds */
137
138 static int handle_http(HTTPContext *c, long cur_time);
139 static int http_parse_request(HTTPContext *c);
140 static int http_send_data(HTTPContext *c);
141 static void compute_stats(HTTPContext *c);
142 static int open_input_stream(HTTPContext *c, const char *info);
143 static int http_start_receive_data(HTTPContext *c);
144 static int http_receive_data(HTTPContext *c);
145
146 int nb_max_connections;
147 int nb_connections;
148
149 static long gettime_ms(void)
150 {
151     struct timeval tv;
152
153     gettimeofday(&tv,NULL);
154     return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
155 }
156
157 static FILE *logfile = NULL;
158
159 static void http_log(char *fmt, ...)
160 {
161     va_list ap;
162     va_start(ap, fmt);
163     
164     if (logfile)
165         vfprintf(logfile, fmt, ap);
166     va_end(ap);
167 }
168
169 /* main loop of the http server */
170 static int http_server(struct sockaddr_in my_addr)
171 {
172     int server_fd, tmp, ret;
173     struct sockaddr_in from_addr;
174     struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
175     HTTPContext *c, **cp;
176     long cur_time;
177
178     server_fd = socket(AF_INET,SOCK_STREAM,0);
179     if (server_fd < 0) {
180         perror ("socket");
181         return -1;
182     }
183         
184     tmp = 1;
185     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
186
187     if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
188         perror ("bind");
189         close(server_fd);
190         return -1;
191     }
192   
193     if (listen (server_fd, 5) < 0) {
194         perror ("listen");
195         close(server_fd);
196         return -1;
197     }
198
199     http_log("ffserver started.\n");
200
201     fcntl(server_fd, F_SETFL, O_NONBLOCK);
202     first_http_ctx = NULL;
203     nb_connections = 0;
204     first_http_ctx = NULL;
205     for(;;) {
206         poll_entry = poll_table;
207         poll_entry->fd = server_fd;
208         poll_entry->events = POLLIN;
209         poll_entry++;
210
211         /* wait for events on each HTTP handle */
212         c = first_http_ctx;
213         while (c != NULL) {
214             int fd;
215             fd = c->fd;
216             switch(c->state) {
217             case HTTPSTATE_WAIT_REQUEST:
218                 c->poll_entry = poll_entry;
219                 poll_entry->fd = fd;
220                 poll_entry->events = POLLIN;
221                 poll_entry++;
222                 break;
223             case HTTPSTATE_SEND_HEADER:
224             case HTTPSTATE_SEND_DATA_HEADER:
225             case HTTPSTATE_SEND_DATA:
226             case HTTPSTATE_SEND_DATA_TRAILER:
227                 c->poll_entry = poll_entry;
228                 poll_entry->fd = fd;
229                 poll_entry->events = POLLOUT;
230                 poll_entry++;
231                 break;
232             case HTTPSTATE_RECEIVE_DATA:
233                 c->poll_entry = poll_entry;
234                 poll_entry->fd = fd;
235                 poll_entry->events = POLLIN;
236                 poll_entry++;
237                 break;
238             case HTTPSTATE_WAIT_FEED:
239                 /* need to catch errors */
240                 c->poll_entry = poll_entry;
241                 poll_entry->fd = fd;
242                 poll_entry->events = 0;
243                 poll_entry++;
244                 break;
245             default:
246                 c->poll_entry = NULL;
247                 break;
248             }
249             c = c->next;
250         }
251
252         /* wait for an event on one connection. We poll at least every
253            second to handle timeouts */
254         do {
255             ret = poll(poll_table, poll_entry - poll_table, 1000);
256         } while (ret == -1);
257         
258         cur_time = gettime_ms();
259
260         /* now handle the events */
261
262         cp = &first_http_ctx;
263         while ((*cp) != NULL) {
264             c = *cp;
265             if (handle_http (c, cur_time) < 0) {
266                 /* close and free the connection */
267                 close(c->fd);
268                 if (c->fmt_in)
269                     av_close_input_file(c->fmt_in);
270                 *cp = c->next;
271                 free(c);
272                 nb_connections--;
273             } else {
274                 cp = &c->next;
275             }
276         }
277
278         /* new connection request ? */
279         poll_entry = poll_table;
280         if (poll_entry->revents & POLLIN) {
281             int fd, len;
282
283             len = sizeof(from_addr);
284             fd = accept(server_fd, (struct sockaddr *)&from_addr, 
285                         &len);
286             if (fd >= 0) {
287                 fcntl(fd, F_SETFL, O_NONBLOCK);
288                 /* XXX: should output a warning page when coming
289                    close to the connection limit */
290                 if (nb_connections >= nb_max_connections) {
291                     close(fd);
292                 } else {
293                     /* add a new connection */
294                     c = av_mallocz(sizeof(HTTPContext));
295                     c->next = first_http_ctx;
296                     first_http_ctx = c;
297                     c->fd = fd;
298                     c->poll_entry = NULL;
299                     c->from_addr = from_addr;
300                     c->state = HTTPSTATE_WAIT_REQUEST;
301                     c->buffer_ptr = c->buffer;
302                     c->buffer_end = c->buffer + IOBUFFER_MAX_SIZE;
303                     c->timeout = cur_time + REQUEST_TIMEOUT;
304                     nb_connections++;
305                 }
306             }
307         }
308         poll_entry++;
309     }
310 }
311
312 static int handle_http(HTTPContext *c, long cur_time)
313 {
314     int len;
315     
316     switch(c->state) {
317     case HTTPSTATE_WAIT_REQUEST:
318         /* timeout ? */
319         if ((c->timeout - cur_time) < 0)
320             return -1;
321         if (c->poll_entry->revents & (POLLERR | POLLHUP))
322             return -1;
323
324         /* no need to read if no events */
325         if (!(c->poll_entry->revents & POLLIN))
326             return 0;
327         /* read the data */
328         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
329         if (len < 0) {
330             if (errno != EAGAIN && errno != EINTR)
331                 return -1;
332         } else if (len == 0) {
333             return -1;
334         } else {
335             /* search for end of request. XXX: not fully correct since garbage could come after the end */
336             UINT8 *ptr;
337             c->buffer_ptr += len;
338             ptr = c->buffer_ptr;
339             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
340                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
341                 /* request found : parse it and reply */
342                 if (http_parse_request(c) < 0)
343                     return -1;
344             } else if (ptr >= c->buffer_end) {
345                 /* request too long: cannot do anything */
346                 return -1;
347             }
348         }
349         break;
350
351     case HTTPSTATE_SEND_HEADER:
352         if (c->poll_entry->revents & (POLLERR | POLLHUP))
353             return -1;
354
355         /* no need to read if no events */
356         if (!(c->poll_entry->revents & POLLOUT))
357             return 0;
358         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
359         if (len < 0) {
360             if (errno != EAGAIN && errno != EINTR) {
361                 /* error : close connection */
362                 return -1;
363             }
364         } else {
365             c->buffer_ptr += len;
366             if (c->buffer_ptr >= c->buffer_end) {
367                 /* if error, exit */
368                 if (c->http_error)
369                     return -1;
370                 /* all the buffer was send : synchronize to the incoming stream */
371                 c->state = HTTPSTATE_SEND_DATA_HEADER;
372                 c->buffer_ptr = c->buffer_end = c->buffer;
373             }
374         }
375         break;
376
377     case HTTPSTATE_SEND_DATA:
378     case HTTPSTATE_SEND_DATA_HEADER:
379     case HTTPSTATE_SEND_DATA_TRAILER:
380         /* no need to read if no events */
381         if (c->poll_entry->revents & (POLLERR | POLLHUP))
382             return -1;
383         
384         if (!(c->poll_entry->revents & POLLOUT))
385             return 0;
386         if (http_send_data(c) < 0)
387             return -1;
388         break;
389     case HTTPSTATE_RECEIVE_DATA:
390         /* no need to read if no events */
391         if (c->poll_entry->revents & (POLLERR | POLLHUP))
392             return -1;
393         if (!(c->poll_entry->revents & POLLIN))
394             return 0;
395         if (http_receive_data(c) < 0)
396             return -1;
397         break;
398     case HTTPSTATE_WAIT_FEED:
399         /* no need to read if no events */
400         if (c->poll_entry->revents & (POLLERR | POLLHUP))
401             return -1;
402
403         /* nothing to do, we'll be waken up by incoming feed packets */
404         break;
405     default:
406         return -1;
407     }
408     return 0;
409 }
410
411 /* parse http request and prepare header */
412 static int http_parse_request(HTTPContext *c)
413 {
414     char *p;
415     int post;
416     char cmd[32];
417     char info[1024], *filename;
418     char url[1024], *q;
419     char protocol[32];
420     char msg[1024];
421     const char *mime_type;
422     FFStream *stream;
423
424     p = c->buffer;
425     q = cmd;
426     while (!isspace(*p) && *p != '\0') {
427         if ((q - cmd) < sizeof(cmd) - 1)
428             *q++ = *p;
429         p++;
430     }
431     *q = '\0';
432     if (!strcmp(cmd, "GET"))
433         post = 0;
434     else if (!strcmp(cmd, "POST"))
435         post = 1;
436     else
437         return -1;
438
439     while (isspace(*p)) p++;
440     q = url;
441     while (!isspace(*p) && *p != '\0') {
442         if ((q - url) < sizeof(url) - 1)
443             *q++ = *p;
444         p++;
445     }
446     *q = '\0';
447
448     while (isspace(*p)) p++;
449     q = protocol;
450     while (!isspace(*p) && *p != '\0') {
451         if ((q - protocol) < sizeof(protocol) - 1)
452             *q++ = *p;
453         p++;
454     }
455     *q = '\0';
456     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
457         return -1;
458     
459     /* find the filename and the optional info string in the request */
460     p = url;
461     if (*p == '/')
462         p++;
463     filename = p;
464     p = strchr(p, '?');
465     if (p) {
466         strcpy(info, p);
467         *p = '\0';
468     } else {
469         info[0] = '\0';
470     }
471
472     stream = first_stream;
473     while (stream != NULL) {
474         if (!strcmp(stream->filename, filename))
475             break;
476         stream = stream->next;
477     }
478     if (stream == NULL) {
479         sprintf(msg, "File '%s' not found", url);
480         goto send_error;
481     }
482     c->stream = stream;
483     
484     /* should do it after so that the size can be computed */
485     {
486         char buf1[32], buf2[32], *p;
487         time_t ti;
488         /* XXX: reentrant function ? */
489         p = inet_ntoa(c->from_addr.sin_addr);
490         strcpy(buf1, p);
491         ti = time(NULL);
492         p = ctime(&ti);
493         strcpy(buf2, p);
494         p = buf2 + strlen(p) - 1;
495         if (*p == '\n')
496             *p = '\0';
497         http_log("%s - - [%s] \"%s %s %s\" %d %d\n", 
498                  buf1, buf2, cmd, url, protocol, 200, 1024);
499     }
500
501     /* XXX: add there authenticate and IP match */
502
503     if (post) {
504         /* if post, it means a feed is being sent */
505         if (!stream->is_feed) {
506             sprintf(msg, "POST command not handled");
507             goto send_error;
508         }
509         if (http_start_receive_data(c) < 0) {
510             sprintf(msg, "could not open feed");
511             goto send_error;
512         }
513         c->http_error = 0;
514         c->state = HTTPSTATE_RECEIVE_DATA;
515         return 0;
516     }
517
518     if (c->stream->stream_type == STREAM_TYPE_STATUS)
519         goto send_stats;
520
521     /* open input stream */
522     if (open_input_stream(c, info) < 0) {
523         sprintf(msg, "Input stream corresponding to '%s' not found", url);
524         goto send_error;
525     }
526
527     /* prepare http header */
528     q = c->buffer;
529     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
530     mime_type = c->stream->fmt->mime_type;
531     if (!mime_type)
532         mime_type = "application/x-octet_stream";
533     q += sprintf(q, "Pragma: no-cache\r\n");
534
535     /* for asf, we need extra headers */
536     if (!strcmp(c->stream->fmt->name,"asf")) {
537         q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=1234\r\nPragma: features=\"broadcast\"\r\n");
538         mime_type = "application/octet-stream";
539     }
540     q += sprintf(q, "Content-Type: %s\r\n", mime_type);
541     q += sprintf(q, "\r\n");
542     
543     /* prepare output buffer */
544     c->http_error = 0;
545     c->buffer_ptr = c->buffer;
546     c->buffer_end = q;
547     c->state = HTTPSTATE_SEND_HEADER;
548     return 0;
549  send_error:
550     c->http_error = 404;
551     q = c->buffer;
552     q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
553     q += sprintf(q, "Content-type: %s\r\n", "text/html");
554     q += sprintf(q, "\r\n");
555     q += sprintf(q, "<HTML>\n");
556     q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
557     q += sprintf(q, "<BODY>%s</BODY>\n", msg);
558     q += sprintf(q, "</HTML>\n");
559
560     /* prepare output buffer */
561     c->buffer_ptr = c->buffer;
562     c->buffer_end = q;
563     c->state = HTTPSTATE_SEND_HEADER;
564     return 0;
565  send_stats:
566     compute_stats(c);
567     c->http_error = 200; /* horrible : we use this value to avoid
568                             going to the send data state */
569     c->state = HTTPSTATE_SEND_HEADER;
570     return 0;
571 }
572
573 static void compute_stats(HTTPContext *c)
574 {
575     HTTPContext *c1;
576     FFStream *stream;
577     char *q, *p;
578     time_t ti;
579     int i;
580
581     q = c->buffer;
582     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
583     q += sprintf(q, "Content-type: %s\r\n", "text/html");
584     q += sprintf(q, "Pragma: no-cache\r\n");
585     q += sprintf(q, "\r\n");
586     
587     q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE></HEAD>\n<BODY>");
588     q += sprintf(q, "<H1>FFServer Status</H1>\n");
589     /* format status */
590     q += sprintf(q, "<H1>Available Streams</H1>\n");
591     q += sprintf(q, "<TABLE>\n");
592     q += sprintf(q, "<TR><TD>Path<TD>Format<TD>Bit rate (kbits/s)<TD>Video<TD>Audio<TD>Feed\n");
593     stream = first_stream;
594     while (stream != NULL) {
595         q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
596                      stream->filename, stream->filename);
597         switch(stream->stream_type) {
598         case STREAM_TYPE_LIVE:
599             {
600                 int audio_bit_rate = 0;
601                 int video_bit_rate = 0;
602
603                 for(i=0;i<stream->nb_streams;i++) {
604                     AVStream *st = stream->streams[i];
605                     switch(st->codec.codec_type) {
606                     case CODEC_TYPE_AUDIO:
607                         audio_bit_rate += st->codec.bit_rate;
608                         break;
609                     case CODEC_TYPE_VIDEO:
610                         video_bit_rate += st->codec.bit_rate;
611                         break;
612                     default:
613                         abort();
614                     }
615                 }
616                 q += sprintf(q, "<TD> %s <TD> %d <TD> %d <TD> %d", 
617                              stream->fmt->name,
618                              (audio_bit_rate + video_bit_rate) / 1000,
619                              video_bit_rate / 1000, audio_bit_rate / 1000);
620                 if (stream->feed) {
621                     q += sprintf(q, "<TD>%s", stream->feed->filename);
622                 } else {
623                     q += sprintf(q, "<TD>%s", stream->feed_filename);
624                 }
625                 q += sprintf(q, "\n");
626             }
627             break;
628         default:
629             q += sprintf(q, "<TD> - <TD> - <TD> - <TD> -\n");
630             break;
631         }
632         stream = stream->next;
633     }
634     q += sprintf(q, "</TABLE>\n");
635     
636 #if 0
637     {
638         float avg;
639         AVCodecContext *enc;
640         char buf[1024];
641         
642         /* feed status */
643         stream = first_feed;
644         while (stream != NULL) {
645             q += sprintf(q, "<H1>Feed '%s'</H1>\n", stream->filename);
646             q += sprintf(q, "<TABLE>\n");
647             q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
648             for(i=0;i<stream->nb_streams;i++) {
649                 AVStream *st = stream->streams[i];
650                 FeedData *fdata = st->priv_data;
651                 enc = &st->codec;
652             
653                 avcodec_string(buf, sizeof(buf), enc);
654                 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
655                 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
656                     avg /= enc->frame_size;
657                 q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
658                              buf, enc->frame_number, fdata->data_count, avg / 1000.0);
659             }
660             q += sprintf(q, "</TABLE>\n");
661             stream = stream->next_feed;
662         }
663     }
664 #endif
665
666     /* connection status */
667     q += sprintf(q, "<H1>Connection Status</H1>\n");
668
669     q += sprintf(q, "Number of connections: %d / %d<BR>\n",
670                  nb_connections, nb_max_connections);
671
672     q += sprintf(q, "<TABLE>\n");
673     q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n");
674     c1 = first_http_ctx;
675     i = 0;
676     while (c1 != NULL) {
677         i++;
678         p = inet_ntoa(c1->from_addr.sin_addr);
679         q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <TD> %Ld\n", 
680                      i, c1->stream->filename, 
681                      c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
682                      p, 
683                      http_state[c1->state],
684                      c1->data_count);
685         c1 = c1->next;
686     }
687     q += sprintf(q, "</TABLE>\n");
688     
689     /* date */
690     ti = time(NULL);
691     p = ctime(&ti);
692     q += sprintf(q, "<HR>Generated at %s", p);
693     q += sprintf(q, "</BODY>\n</HTML>\n");
694
695     c->buffer_ptr = c->buffer;
696     c->buffer_end = q;
697 }
698
699
700 static void http_write_packet(void *opaque, 
701                               unsigned char *buf, int size)
702 {
703     HTTPContext *c = opaque;
704
705     if (c->buffer_ptr == c->buffer_end || !c->buffer_ptr)
706         c->buffer_ptr = c->buffer_end = c->buffer;
707
708     if (c->buffer_end - c->buffer + size > IOBUFFER_MAX_SIZE)
709         abort();
710
711     memcpy(c->buffer_end, buf, size);
712     c->buffer_end += size;
713 }
714
715 static int open_input_stream(HTTPContext *c, const char *info)
716 {
717     char buf[128];
718     char input_filename[1024];
719     AVFormatContext *s;
720     int buf_size;
721     INT64 stream_pos;
722
723     /* find file name */
724     if (c->stream->feed) {
725         strcpy(input_filename, c->stream->feed->feed_filename);
726         buf_size = FFM_PACKET_SIZE;
727         /* compute position (absolute time) */
728         if (find_info_tag(buf, sizeof(buf), "date", info)) {
729             stream_pos = parse_date(buf, 0);
730         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
731             int prebuffer = strtol(buf, 0, 10);
732             stream_pos = gettime() - prebuffer * 1000000;
733         } else {
734             stream_pos = gettime();
735         }
736     } else {
737         strcpy(input_filename, c->stream->feed_filename);
738         buf_size = 0;
739         /* compute position (relative time) */
740         if (find_info_tag(buf, sizeof(buf), "date", info)) {
741             stream_pos = parse_date(buf, 1);
742         } else {
743             stream_pos = 0;
744         }
745     }
746     if (input_filename[0] == '\0')
747         return -1;
748
749     /* open stream */
750     s = av_open_input_file(input_filename, NULL, buf_size, NULL);
751     if (!s)
752         return -1;
753     c->fmt_in = s;
754
755     if (c->fmt_in->format->read_seek) {
756         c->fmt_in->format->read_seek(c->fmt_in, stream_pos);
757     }
758     
759     //    printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
760     return 0;
761 }
762
763 static int http_prepare_data(HTTPContext *c)
764 {
765     int i;
766
767     switch(c->state) {
768     case HTTPSTATE_SEND_DATA_HEADER:
769         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
770         if (c->stream->feed) {
771             /* open output stream by using specified codecs */
772             c->fmt_ctx.format = c->stream->fmt;
773             c->fmt_ctx.nb_streams = c->stream->nb_streams;
774             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
775                 AVStream *st;
776                 st = av_mallocz(sizeof(AVStream));
777                 c->fmt_ctx.streams[i] = st;
778                 if (c->stream->feed == c->stream)
779                     memcpy(st, c->stream->streams[i], sizeof(AVStream));
780                 else
781                     memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]], sizeof(AVStream));
782
783                 st->codec.frame_number = 0; /* XXX: should be done in
784                                                AVStream, not in codec */
785                 c->got_key_frame[i] = 0;
786             }
787         } else {
788             /* open output stream by using codecs in specified file */
789             c->fmt_ctx.format = c->stream->fmt;
790             c->fmt_ctx.nb_streams = c->fmt_in->nb_streams;
791             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
792                 AVStream *st;
793                 st = av_mallocz(sizeof(AVStream));
794                 c->fmt_ctx.streams[i] = st;
795                 memcpy(st, c->fmt_in->streams[i], sizeof(AVStream));
796                 st->codec.frame_number = 0; /* XXX: should be done in
797                                                AVStream, not in codec */
798                 c->got_key_frame[i] = 0;
799             }
800         }
801         init_put_byte(&c->fmt_ctx.pb, c->pbuffer, PACKET_MAX_SIZE,
802                       1, c, NULL, http_write_packet, NULL);
803         c->fmt_ctx.pb.is_streamed = 1;
804         /* prepare header */
805         c->fmt_ctx.format->write_header(&c->fmt_ctx);
806         c->state = HTTPSTATE_SEND_DATA;
807         c->last_packet_sent = 0;
808         break;
809     case HTTPSTATE_SEND_DATA:
810         /* find a new packet */
811 #if 0
812         fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
813         if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
814             /* overflow : resync. We suppose that wptr is at this
815                point a pointer to a valid packet */
816             c->rptr = http_fifo.wptr;
817             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
818                 c->got_key_frame[i] = 0;
819             }
820         }
821         
822         start_rptr = c->rptr;
823         if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
824             return 0;
825         payload_size = ntohs(hdr.payload_size);
826         payload = malloc(payload_size);
827         if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
828             /* cannot read all the payload */
829             free(payload);
830             c->rptr = start_rptr;
831             return 0;
832         }
833         
834         c->last_http_fifo_write_count = http_fifo_write_count - 
835             fifo_size(&http_fifo, c->rptr);
836         
837         if (c->stream->stream_type != STREAM_TYPE_MASTER) {
838             /* test if the packet can be handled by this format */
839             ret = 0;
840             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
841                 AVStream *st = c->fmt_ctx.streams[i];
842                 if (test_header(&hdr, &st->codec)) {
843                     /* only begin sending when got a key frame */
844                     if (st->codec.key_frame)
845                         c->got_key_frame[i] = 1;
846                     if (c->got_key_frame[i]) {
847                         ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i,
848                                                                    payload, payload_size);
849                     }
850                     break;
851                 }
852             }
853             if (ret) {
854                 /* must send trailer now */
855                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
856             }
857         } else {
858             /* master case : send everything */
859             char *q;
860             q = c->buffer;
861             memcpy(q, &hdr, sizeof(hdr));
862             q += sizeof(hdr);
863             memcpy(q, payload, payload_size);
864             q += payload_size;
865             c->buffer_ptr = c->buffer;
866             c->buffer_end = q;
867         }
868         free(payload);
869 #endif
870         {
871             AVPacket pkt;
872
873             /* read a packet from the input stream */
874             if (c->stream->feed) {
875                 ffm_set_write_index(c->fmt_in, 
876                                     c->stream->feed->feed_write_index,
877                                     c->stream->feed->feed_size);
878             }
879             if (av_read_packet(c->fmt_in, &pkt) < 0) {
880                 if (c->stream->feed && c->stream->feed->feed_opened) {
881                     /* if coming from feed, it means we reached the end of the
882                        ffm file, so must wait for more data */
883                     c->state = HTTPSTATE_WAIT_FEED;
884                     return 1; /* state changed */
885                 } else {
886                     /* must send trailer now because eof or error */
887                     c->state = HTTPSTATE_SEND_DATA_TRAILER;
888                 }
889             } else {
890                 /* send it to the appropriate stream */
891                 if (c->stream->feed) {
892                     /* if coming from a feed, select the right stream */
893                     for(i=0;i<c->stream->nb_streams;i++) {
894                         if (c->stream->feed_streams[i] == pkt.stream_index) {
895                             pkt.stream_index = i;
896                             goto send_it;
897                         }
898                     }
899                 } else {
900                     AVCodecContext *codec;
901                 send_it:
902                     /* Fudge here */
903                     codec = &c->fmt_ctx.streams[pkt.stream_index]->codec;
904
905                     codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
906
907 #ifdef PJSG
908                     if (codec->codec_type == CODEC_TYPE_AUDIO) {
909                         codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
910                         /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
911                     }
912 #endif
913
914                     if (av_write_packet(&c->fmt_ctx, &pkt, 0))
915                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
916
917                     codec->frame_number++;
918                 }
919                 
920                 av_free_packet(&pkt);
921             }
922         }
923         break;
924     default:
925     case HTTPSTATE_SEND_DATA_TRAILER:
926         /* last packet test ? */
927         if (c->last_packet_sent)
928             return -1;
929         /* prepare header */
930         c->fmt_ctx.format->write_trailer(&c->fmt_ctx);
931         c->last_packet_sent = 1;
932         break;
933     }
934     return 0;
935 }
936
937 /* should convert the format at the same time */
938 static int http_send_data(HTTPContext *c)
939 {
940     int len, ret;
941
942     while (c->buffer_ptr >= c->buffer_end) {
943         ret = http_prepare_data(c);
944         if (ret < 0)
945             return -1;
946         else if (ret == 0) {
947             break;
948         } else {
949             /* state change requested */
950             return 0;
951         }
952     }
953
954     if (c->buffer_end > c->buffer_ptr) {
955         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
956         if (len < 0) {
957             if (errno != EAGAIN && errno != EINTR) {
958                 /* error : close connection */
959                 return -1;
960             }
961         } else {
962             c->buffer_ptr += len;
963             c->data_count += len;
964         }
965     }
966     return 0;
967 }
968
969 static int http_start_receive_data(HTTPContext *c)
970 {
971     int fd;
972
973     if (c->stream->feed_opened)
974         return -1;
975
976     /* open feed */
977     fd = open(c->stream->feed_filename, O_RDWR);
978     if (fd < 0)
979         return -1;
980     c->feed_fd = fd;
981     
982     c->stream->feed_write_index = ffm_read_write_index(fd);
983     c->stream->feed_size = lseek(fd, 0, SEEK_END);
984     lseek(fd, 0, SEEK_SET);
985
986     /* init buffer input */
987     c->buffer_ptr = c->buffer;
988     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
989     c->stream->feed_opened = 1;
990     return 0;
991 }
992     
993 static int http_receive_data(HTTPContext *c)
994 {
995     int len;
996     HTTPContext *c1;
997
998     if (c->buffer_ptr >= c->buffer_end) {
999         FFStream *feed = c->stream;
1000         /* a packet has been received : write it in the store, except
1001            if header */
1002         if (c->data_count > FFM_PACKET_SIZE) {
1003             
1004             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
1005             /* XXX: use llseek or url_seek */
1006             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
1007             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
1008             
1009             feed->feed_write_index += FFM_PACKET_SIZE;
1010             /* update file size */
1011             if (feed->feed_write_index > c->stream->feed_size)
1012                 feed->feed_size = feed->feed_write_index;
1013
1014             /* handle wrap around if max file size reached */
1015             if (feed->feed_write_index >= c->stream->feed_max_size)
1016                 feed->feed_write_index = FFM_PACKET_SIZE;
1017
1018             /* write index */
1019             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
1020
1021             /* wake up any waiting connections */
1022             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
1023                 if (c1->state == HTTPSTATE_WAIT_FEED && 
1024                     c1->stream->feed == c->stream->feed) {
1025                     c1->state = HTTPSTATE_SEND_DATA;
1026                 }
1027             }
1028         } else {
1029             /* We have a header in our hands that contains useful data */
1030             AVFormatContext s;
1031             ByteIOContext *pb = &s.pb;
1032             int i;
1033
1034             memset(&s, 0, sizeof(s));
1035
1036             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
1037             pb->buf_end = c->buffer_end;        /* ?? */
1038             pb->is_streamed = 1;
1039
1040             if (feed->fmt->read_header(&s, 0) < 0) {
1041                 goto fail;
1042             }
1043
1044             /* Now we have the actual streams */
1045             if (s.nb_streams != feed->nb_streams) {
1046                 goto fail;
1047             }
1048             for (i = 0; i < s.nb_streams; i++) {
1049                 memcpy(&feed->streams[i]->codec, &s.streams[i]->codec, sizeof(AVCodecContext));
1050             } 
1051         }
1052         c->buffer_ptr = c->buffer;
1053     }
1054
1055     len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1056     if (len < 0) {
1057         if (errno != EAGAIN && errno != EINTR) {
1058             /* error : close connection */
1059             goto fail;
1060         }
1061     } else if (len == 0) {
1062         /* end of connection : close it */
1063         goto fail;
1064     } else {
1065         c->buffer_ptr += len;
1066         c->data_count += len;
1067     }
1068     return 0;
1069  fail:
1070     c->stream->feed_opened = 0;
1071     close(c->feed_fd);
1072     return -1;
1073 }
1074
1075 /* return the stream number in the feed */
1076 int add_av_stream(FFStream *feed,
1077                   AVStream *st)
1078 {
1079     AVStream *fst;
1080     AVCodecContext *av, *av1;
1081     int i;
1082
1083     av = &st->codec;
1084     for(i=0;i<feed->nb_streams;i++) {
1085         st = feed->streams[i];
1086         av1 = &st->codec;
1087         if (av1->codec_id == av->codec_id &&
1088             av1->codec_type == av->codec_type &&
1089             av1->bit_rate == av->bit_rate) {
1090
1091             switch(av->codec_type) {
1092             case CODEC_TYPE_AUDIO:
1093                 if (av1->channels == av->channels &&
1094                     av1->sample_rate == av->sample_rate)
1095                     goto found;
1096                 break;
1097             case CODEC_TYPE_VIDEO:
1098                 if (av1->width == av->width &&
1099                     av1->height == av->height &&
1100                     av1->frame_rate == av->frame_rate &&
1101                     av1->gop_size == av->gop_size)
1102                     goto found;
1103                 break;
1104             default:
1105                 abort();
1106             }
1107         }
1108     }
1109     
1110     fst = av_mallocz(sizeof(AVStream));
1111     if (!fst)
1112         return -1;
1113     fst->priv_data = av_mallocz(sizeof(FeedData));
1114     memcpy(&fst->codec, av, sizeof(AVCodecContext));
1115     feed->streams[feed->nb_streams++] = fst;
1116     return feed->nb_streams - 1;
1117  found:
1118     return i;
1119 }
1120
1121 /* compute the needed AVStream for each feed */
1122 void build_feed_streams(void)
1123 {
1124     FFStream *stream, *feed;
1125     int i;
1126
1127     /* gather all streams */
1128     for(stream = first_stream; stream != NULL; stream = stream->next) {
1129         feed = stream->feed;
1130         if (feed) {
1131             if (!stream->is_feed) {
1132                 for(i=0;i<stream->nb_streams;i++) {
1133                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
1134                 }
1135             } else {
1136                 for(i=0;i<stream->nb_streams;i++) {
1137                     stream->feed_streams[i] = i;
1138                 }
1139             }
1140         }
1141     }
1142
1143     /* create feed files if needed */
1144     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
1145         int fd;
1146
1147         if (!url_exist(feed->feed_filename)) {
1148             AVFormatContext s1, *s = &s1;
1149
1150             /* only write the header of the ffm file */
1151             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
1152                 fprintf(stderr, "Could not open output feed file '%s'\n",
1153                         feed->feed_filename);
1154                 exit(1);
1155             }
1156             s->format = feed->fmt;
1157             s->nb_streams = feed->nb_streams;
1158             for(i=0;i<s->nb_streams;i++) {
1159                 AVStream *st;
1160                 st = feed->streams[i];
1161                 s->streams[i] = st;
1162             }
1163             s->format->write_header(s);
1164
1165             url_fclose(&s->pb);
1166         }
1167         /* get feed size and write index */
1168         fd = open(feed->feed_filename, O_RDONLY);
1169         if (fd < 0) {
1170             fprintf(stderr, "Could not open output feed file '%s'\n",
1171                     feed->feed_filename);
1172             exit(1);
1173         }
1174
1175         feed->feed_write_index = ffm_read_write_index(fd);
1176         feed->feed_size = lseek(fd, 0, SEEK_END);
1177         /* ensure that we do not wrap before the end of file */
1178         if (feed->feed_max_size < feed->feed_size)
1179             feed->feed_max_size = feed->feed_size;
1180
1181         close(fd);
1182     }
1183 }
1184
1185 static void get_arg(char *buf, int buf_size, const char **pp)
1186 {
1187     const char *p;
1188     char *q;
1189     int quote;
1190
1191     p = *pp;
1192     while (isspace(*p)) p++;
1193     q = buf;
1194     quote = 0;
1195     if (*p == '\"' || *p == '\'')
1196         quote = *p++;
1197     for(;;) {
1198         if (quote) {
1199             if (*p == quote)
1200                 break;
1201         } else {
1202             if (isspace(*p))
1203                 break;
1204         }
1205         if (*p == '\0')
1206             break;
1207         if ((q - buf) < buf_size - 1)
1208             *q++ = *p;
1209         p++;
1210     }
1211     *q = '\0';
1212     if (quote && *p == quote)
1213         p++;
1214     *pp = p;
1215 }
1216
1217 /* add a codec and set the default parameters */
1218 void add_codec(FFStream *stream, AVCodecContext *av)
1219 {
1220     AVStream *st;
1221
1222     /* compute default parameters */
1223     switch(av->codec_type) {
1224     case CODEC_TYPE_AUDIO:
1225         if (av->bit_rate == 0)
1226             av->bit_rate = 64000;
1227         if (av->sample_rate == 0)
1228             av->sample_rate = 22050;
1229         if (av->channels == 0)
1230             av->channels = 1;
1231         break;
1232     case CODEC_TYPE_VIDEO:
1233         if (av->bit_rate == 0)
1234             av->bit_rate = 64000;
1235         if (av->frame_rate == 0)
1236             av->frame_rate = 5 * FRAME_RATE_BASE;
1237         if (av->width == 0 || av->height == 0) {
1238             av->width = 160;
1239             av->height = 128;
1240         }
1241         av->bit_rate_tolerance= 128000;
1242         av->qmin= 5;
1243         av->qmax= 31;
1244         av->qcompress= 0.5;
1245         av->qblur= 0.5;
1246         av->max_qdiff= 3;
1247
1248         break;
1249     default:
1250         abort();
1251     }
1252
1253     st = av_mallocz(sizeof(AVStream));
1254     if (!st)
1255         return;
1256     stream->streams[stream->nb_streams++] = st;
1257     memcpy(&st->codec, av, sizeof(AVCodecContext));
1258 }
1259
1260 int opt_audio_codec(const char *arg)
1261 {
1262     AVCodec *p;
1263
1264     p = first_avcodec;
1265     while (p) {
1266         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
1267             break;
1268         p = p->next;
1269     }
1270     if (p == NULL) {
1271         return CODEC_ID_NONE;
1272     }
1273
1274     return p->id;
1275 }
1276
1277 int opt_video_codec(const char *arg)
1278 {
1279     AVCodec *p;
1280
1281     p = first_avcodec;
1282     while (p) {
1283         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
1284             break;
1285         p = p->next;
1286     }
1287     if (p == NULL) {
1288         return CODEC_ID_NONE;
1289     }
1290
1291     return p->id;
1292 }
1293
1294 int parse_ffconfig(const char *filename)
1295 {
1296     FILE *f;
1297     char line[1024];
1298     char cmd[64];
1299     char arg[1024];
1300     const char *p;
1301     int val, errors, line_num;
1302     FFStream **last_stream, *stream;
1303     FFStream **last_feed, *feed;
1304     AVCodecContext audio_enc, video_enc;
1305     int audio_id, video_id;
1306
1307     f = fopen(filename, "r");
1308     if (!f) {
1309         perror(filename);
1310         return -1;
1311     }
1312     
1313     errors = 0;
1314     line_num = 0;
1315     first_stream = NULL;
1316     last_stream = &first_stream;
1317     first_feed = NULL;
1318     last_feed = &first_feed;
1319     stream = NULL;
1320     feed = NULL;
1321     audio_id = CODEC_ID_NONE;
1322     video_id = CODEC_ID_NONE;
1323     for(;;) {
1324         if (fgets(line, sizeof(line), f) == NULL)
1325             break;
1326         line_num++;
1327         p = line;
1328         while (isspace(*p)) 
1329             p++;
1330         if (*p == '\0' || *p == '#')
1331             continue;
1332
1333         get_arg(cmd, sizeof(cmd), &p);
1334         
1335         if (!strcasecmp(cmd, "Port")) {
1336             get_arg(arg, sizeof(arg), &p);
1337             my_addr.sin_port = htons (atoi(arg));
1338         } else if (!strcasecmp(cmd, "BindAddress")) {
1339             get_arg(arg, sizeof(arg), &p);
1340             if (!inet_aton(arg, &my_addr.sin_addr)) {
1341                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
1342                         filename, line_num, arg);
1343                 errors++;
1344             }
1345         } else if (!strcasecmp(cmd, "MaxClients")) {
1346             get_arg(arg, sizeof(arg), &p);
1347             val = atoi(arg);
1348             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
1349                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
1350                         filename, line_num, arg);
1351                 errors++;
1352             } else {
1353                 nb_max_connections = val;
1354             }
1355         } else if (!strcasecmp(cmd, "CustomLog")) {
1356             get_arg(logfilename, sizeof(logfilename), &p);
1357         } else if (!strcasecmp(cmd, "<Feed")) {
1358             /*********************************************/
1359             /* Feed related options */
1360             char *q;
1361             if (stream || feed) {
1362                 fprintf(stderr, "%s:%d: Already in a tag\n",
1363                         filename, line_num);
1364             } else {
1365                 feed = av_mallocz(sizeof(FFStream));
1366                 /* add in stream list */
1367                 *last_stream = feed;
1368                 last_stream = &feed->next;
1369                 /* add in feed list */
1370                 *last_feed = feed;
1371                 last_feed = &feed->next_feed;
1372                 
1373                 get_arg(feed->filename, sizeof(feed->filename), &p);
1374                 q = strrchr(feed->filename, '>');
1375                 if (*q)
1376                     *q = '\0';
1377                 feed->fmt = guess_format("ffm", NULL, NULL);
1378                 /* defaut feed file */
1379                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
1380                          "/tmp/%s.ffm", feed->filename);
1381                 feed->feed_max_size = 5 * 1024 * 1024;
1382                 feed->is_feed = 1;
1383                 feed->feed = feed; /* self feeding :-) */
1384             }
1385         } else if (!strcasecmp(cmd, "File")) {
1386             if (feed) {
1387                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
1388             } else if (stream) {
1389                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
1390             }
1391         } else if (!strcasecmp(cmd, "FileMaxSize")) {
1392             if (feed) {
1393                 const char *p1;
1394                 double fsize;
1395
1396                 get_arg(arg, sizeof(arg), &p);
1397                 p1 = arg;
1398                 fsize = strtod(p1, (char **)&p1);
1399                 switch(toupper(*p1)) {
1400                 case 'K':
1401                     fsize *= 1024;
1402                     break;
1403                 case 'M':
1404                     fsize *= 1024 * 1024;
1405                     break;
1406                 case 'G':
1407                     fsize *= 1024 * 1024 * 1024;
1408                     break;
1409                 }
1410                 feed->feed_max_size = (INT64)fsize;
1411             }
1412         } else if (!strcasecmp(cmd, "</Feed>")) {
1413             if (!feed) {
1414                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
1415                         filename, line_num);
1416                 errors++;
1417             } else {
1418                 /* Make sure that we start out clean */
1419                 unlink(feed->feed_filename);
1420             }
1421             feed = NULL;
1422         } else if (!strcasecmp(cmd, "<Stream")) {
1423             /*********************************************/
1424             /* Stream related options */
1425             char *q;
1426             if (stream || feed) {
1427                 fprintf(stderr, "%s:%d: Already in a tag\n",
1428                         filename, line_num);
1429             } else {
1430                 stream = av_mallocz(sizeof(FFStream));
1431                 *last_stream = stream;
1432                 last_stream = &stream->next;
1433
1434                 get_arg(stream->filename, sizeof(stream->filename), &p);
1435                 q = strrchr(stream->filename, '>');
1436                 if (*q)
1437                     *q = '\0';
1438                 stream->fmt = guess_format(NULL, stream->filename, NULL);
1439                 memset(&audio_enc, 0, sizeof(AVCodecContext));
1440                 memset(&video_enc, 0, sizeof(AVCodecContext));
1441                 audio_id = CODEC_ID_NONE;
1442                 video_id = CODEC_ID_NONE;
1443                 if (stream->fmt) {
1444                     audio_id = stream->fmt->audio_codec;
1445                     video_id = stream->fmt->video_codec;
1446                 }
1447             }
1448         } else if (!strcasecmp(cmd, "Feed")) {
1449             get_arg(arg, sizeof(arg), &p);
1450             if (stream) {
1451                 FFStream *sfeed;
1452                 
1453                 sfeed = first_feed;
1454                 while (sfeed != NULL) {
1455                     if (!strcmp(sfeed->filename, arg))
1456                         break;
1457                     sfeed = sfeed->next_feed;
1458                 }
1459                 if (!sfeed) {
1460                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
1461                             filename, line_num, arg);
1462                 } else {
1463                     stream->feed = sfeed;
1464                 }
1465             }
1466         } else if (!strcasecmp(cmd, "Format")) {
1467             get_arg(arg, sizeof(arg), &p);
1468             if (!strcmp(arg, "status")) {
1469                 stream->stream_type = STREAM_TYPE_STATUS;
1470                 stream->fmt = NULL;
1471             } else {
1472                 stream->stream_type = STREAM_TYPE_LIVE;
1473                 /* jpeg cannot be used here, so use single frame jpeg */
1474                 if (!strcmp(arg, "jpeg"))
1475                     strcpy(arg, "singlejpeg");
1476                 stream->fmt = guess_format(arg, NULL, NULL);
1477                 if (!stream->fmt) {
1478                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
1479                             filename, line_num, arg);
1480                     errors++;
1481                 }
1482             }
1483             if (stream->fmt) {
1484                 audio_id = stream->fmt->audio_codec;
1485                 video_id = stream->fmt->video_codec;
1486             }
1487         } else if (!strcasecmp(cmd, "AudioCodec")) {
1488             get_arg(arg, sizeof(arg), &p);
1489             audio_id = opt_audio_codec(arg);
1490             if (audio_id == CODEC_ID_NONE) {
1491                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
1492                         filename, line_num, arg);
1493                 errors++;
1494             }
1495         } else if (!strcasecmp(cmd, "VideoCodec")) {
1496             get_arg(arg, sizeof(arg), &p);
1497             video_id = opt_video_codec(arg);
1498             if (video_id == CODEC_ID_NONE) {
1499                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
1500                         filename, line_num, arg);
1501                 errors++;
1502             }
1503         } else if (!strcasecmp(cmd, "AudioBitRate")) {
1504             get_arg(arg, sizeof(arg), &p);
1505             if (stream) {
1506                 audio_enc.bit_rate = atoi(arg) * 1000;
1507             }
1508         } else if (!strcasecmp(cmd, "AudioChannels")) {
1509             get_arg(arg, sizeof(arg), &p);
1510             if (stream) {
1511                 audio_enc.channels = atoi(arg);
1512             }
1513         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
1514             get_arg(arg, sizeof(arg), &p);
1515             if (stream) {
1516                 audio_enc.sample_rate = atoi(arg);
1517             }
1518         } else if (!strcasecmp(cmd, "VideoBitRate")) {
1519             get_arg(arg, sizeof(arg), &p);
1520             if (stream) {
1521                 video_enc.bit_rate = atoi(arg) * 1000;
1522             }
1523         } else if (!strcasecmp(cmd, "VideoSize")) {
1524             get_arg(arg, sizeof(arg), &p);
1525             if (stream) {
1526                 parse_image_size(&video_enc.width, &video_enc.height, arg);
1527                 if ((video_enc.width % 16) != 0 ||
1528                     (video_enc.height % 16) != 0) {
1529                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
1530                             filename, line_num);
1531                     errors++;
1532                 }
1533             }
1534         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
1535             get_arg(arg, sizeof(arg), &p);
1536             if (stream) {
1537                 video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
1538             }
1539         } else if (!strcasecmp(cmd, "VideoGopSize")) {
1540             get_arg(arg, sizeof(arg), &p);
1541             if (stream) {
1542                 video_enc.gop_size = atoi(arg);
1543             }
1544         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
1545             if (stream) {
1546                 video_enc.gop_size = 1;
1547             }
1548         } else if (!strcasecmp(cmd, "NoVideo")) {
1549             video_id = CODEC_ID_NONE;
1550         } else if (!strcasecmp(cmd, "NoAudio")) {
1551             audio_id = CODEC_ID_NONE;
1552         } else if (!strcasecmp(cmd, "</Stream>")) {
1553             if (!stream) {
1554                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
1555                         filename, line_num);
1556                 errors++;
1557             }
1558             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
1559                 if (audio_id != CODEC_ID_NONE) {
1560                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
1561                     audio_enc.codec_id = audio_id;
1562                     add_codec(stream, &audio_enc);
1563                 }
1564                 if (video_id != CODEC_ID_NONE) {
1565                     video_enc.codec_type = CODEC_TYPE_VIDEO;
1566                     video_enc.codec_id = video_id;
1567                     add_codec(stream, &video_enc);
1568                 }
1569             }
1570             stream = NULL;
1571         } else {
1572             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
1573                     filename, line_num, cmd);
1574             errors++;
1575         }
1576     }
1577
1578     fclose(f);
1579     if (errors)
1580         return -1;
1581     else
1582         return 0;
1583 }
1584
1585
1586 void *http_server_thread(void *arg)
1587 {
1588     http_server(my_addr);
1589     return NULL;
1590 }
1591
1592 #if 0
1593 static void write_packet(FFCodec *ffenc,
1594                          UINT8 *buf, int size)
1595 {
1596     PacketHeader hdr;
1597     AVCodecContext *enc = &ffenc->enc;
1598     UINT8 *wptr;
1599     mk_header(&hdr, enc, size);
1600     wptr = http_fifo.wptr;
1601     fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
1602     fifo_write(&http_fifo, buf, size, &wptr);
1603     /* atomic modification of wptr */
1604     http_fifo.wptr = wptr;
1605     ffenc->data_count += size;
1606     ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
1607 }
1608 #endif
1609
1610 void help(void)
1611 {
1612     printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000,2001 Gerard Lantau\n"
1613            "usage: ffserver [-L] [-h] [-f configfile]\n"
1614            "Hyper fast multi format Audio/Video streaming server\n"
1615            "\n"
1616            "-L            : print the LICENCE\n"
1617            "-h            : this help\n"
1618            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
1619            );
1620 }
1621
1622 void licence(void)
1623 {
1624     printf(
1625     "ffserver version " FFMPEG_VERSION "\n"
1626     "Copyright (c) 2000,2001 Gerard Lantau\n"
1627     "This program is free software; you can redistribute it and/or modify\n"
1628     "it under the terms of the GNU General Public License as published by\n"
1629     "the Free Software Foundation; either version 2 of the License, or\n"
1630     "(at your option) any later version.\n"
1631     "\n"
1632     "This program is distributed in the hope that it will be useful,\n"
1633     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1634     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1635     "GNU General Public License for more details.\n"
1636     "\n"
1637     "You should have received a copy of the GNU General Public License\n"
1638     "along with this program; if not, write to the Free Software\n"
1639     "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
1640     );
1641 }
1642
1643 int main(int argc, char **argv)
1644 {
1645     const char *config_filename;
1646     int c;
1647
1648     register_all();
1649
1650     config_filename = "/etc/ffserver.conf";
1651
1652     for(;;) {
1653         c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL);
1654         if (c == -1)
1655             break;
1656         switch(c) {
1657         case 'L':
1658             licence();
1659             exit(1);
1660         case '?':
1661         case 'h':
1662             help();
1663             exit(1);
1664         case 'f':
1665             config_filename = optarg;
1666             break;
1667         default:
1668             exit(2);
1669         }
1670     }
1671
1672     /* address on which the server will handle connections */
1673     my_addr.sin_family = AF_INET;
1674     my_addr.sin_port = htons (8080);
1675     my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
1676     nb_max_connections = 5;
1677     first_stream = NULL;
1678     logfilename[0] = '\0';
1679
1680     if (parse_ffconfig(config_filename) < 0) {
1681         fprintf(stderr, "Incorrect config file - exiting.\n");
1682         exit(1);
1683     }
1684
1685     build_feed_streams();
1686
1687     /* signal init */
1688     signal(SIGPIPE, SIG_IGN);
1689
1690     /* open log file if needed */
1691     if (logfilename[0] != '\0') {
1692         if (!strcmp(logfilename, "-"))
1693             logfile = stdout;
1694         else
1695             logfile = fopen(logfilename, "w");
1696     }
1697
1698     if (http_server(my_addr) < 0) {
1699         fprintf(stderr, "Could start http server\n");
1700         exit(1);
1701     }
1702
1703     return 0;
1704 }