Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ d8cf5aea

History | View | Annotate | Download (48.7 KB)

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

    
39
#include "bswap.h" // needed for the bitstream writer in common.h which is included in avformat.h
40
#include "avformat.h"
41

    
42
/* maximum number of simultaneous HTTP connections */
43
#define HTTP_MAX_CONNECTIONS 2000
44

    
45
enum HTTPState {
46
    HTTPSTATE_WAIT_REQUEST,
47
    HTTPSTATE_SEND_HEADER,
48
    HTTPSTATE_SEND_DATA_HEADER,
49
    HTTPSTATE_SEND_DATA,
50
    HTTPSTATE_SEND_DATA_TRAILER,
51
    HTTPSTATE_RECEIVE_DATA,
52
    HTTPSTATE_WAIT_FEED,
53
};
54

    
55
const char *http_state[] = {
56
    "WAIT_REQUEST",
57
    "SEND_HEADER",
58
    "SEND_DATA_HEADER",
59
    "SEND_DATA",
60
    "SEND_DATA_TRAILER",
61
    "RECEIVE_DATA",
62
    "WAIT_FEED",
63
};
64

    
65
#define IOBUFFER_MAX_SIZE 16384
66

    
67
/* coef for exponential mean for bitrate estimation in statistics */
68
#define AVG_COEF 0.9
69

    
70
/* timeouts are in ms */
71
#define REQUEST_TIMEOUT (15 * 1000)
72
#define SYNC_TIMEOUT (10 * 1000)
73

    
74
/* context associated with one connection */
75
typedef struct HTTPContext {
76
    enum HTTPState state;
77
    int fd; /* socket file descriptor */
78
    struct sockaddr_in from_addr; /* origin */
79
    struct pollfd *poll_entry; /* used when polling */
80
    long timeout;
81
    UINT8 buffer[IOBUFFER_MAX_SIZE];
82
    UINT8 *buffer_ptr, *buffer_end;
83
    int http_error;
84
    struct HTTPContext *next;
85
    int got_key_frame[MAX_STREAMS]; /* for each type */
86
    INT64 data_count;
87
    /* feed input */
88
    int feed_fd;
89
    /* input format handling */
90
    AVFormatContext *fmt_in;
91
    /* output format handling */
92
    struct FFStream *stream;
93
    AVFormatContext fmt_ctx;
94
    int last_packet_sent; /* true if last data packet was sent */
95
} HTTPContext;
96

    
97
/* each generated stream is described here */
98
enum StreamType {
99
    STREAM_TYPE_LIVE,
100
    STREAM_TYPE_STATUS,
101
};
102

    
103
/* description of each stream of the ffserver.conf file */
104
typedef struct FFStream {
105
    enum StreamType stream_type;
106
    char filename[1024];     /* stream filename */
107
    struct FFStream *feed;
108
    AVFormat *fmt;
109
    int nb_streams;
110
    AVStream *streams[MAX_STREAMS];
111
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
112
    char feed_filename[1024]; /* file name of the feed storage, or
113
                                 input file name for a stream */
114
    struct FFStream *next;
115
    /* feed specific */
116
    int feed_opened;     /* true if someone if writing to feed */
117
    int is_feed;         /* true if it is a feed */
118
    INT64 feed_max_size;      /* maximum storage size */
119
    INT64 feed_write_index;   /* current write position in feed (it wraps round) */
120
    INT64 feed_size;          /* current size of feed */
121
    struct FFStream *next_feed;
122
} FFStream;
123

    
124
typedef struct FeedData {
125
    long long data_count;
126
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
127
} FeedData;
128

    
129
struct sockaddr_in my_addr;
130
char logfilename[1024];
131
HTTPContext *first_http_ctx;
132
FFStream *first_feed;   /* contains only feeds */
133
FFStream *first_stream; /* contains all streams, including feeds */
134

    
135
static int handle_http(HTTPContext *c, long cur_time);
136
static int http_parse_request(HTTPContext *c);
137
static int http_send_data(HTTPContext *c);
138
static void compute_stats(HTTPContext *c);
139
static int open_input_stream(HTTPContext *c, const char *info);
140
static int http_start_receive_data(HTTPContext *c);
141
static int http_receive_data(HTTPContext *c);
142

    
143
int nb_max_connections;
144
int nb_connections;
145

    
146
static long gettime_ms(void)
147
{
148
    struct timeval tv;
149

    
150
    gettimeofday(&tv,NULL);
151
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
152
}
153

    
154
static FILE *logfile = NULL;
155

    
156
static void http_log(char *fmt, ...)
157
{
158
    va_list ap;
159
    va_start(ap, fmt);
160
    
161
    if (logfile)
162
        vfprintf(logfile, fmt, ap);
163
    va_end(ap);
164
}
165

    
166
/* main loop of the http server */
167
static int http_server(struct sockaddr_in my_addr)
168
{
169
    int server_fd, tmp, ret;
170
    struct sockaddr_in from_addr;
171
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
172
    HTTPContext *c, **cp;
173
    long cur_time;
174

    
175
    server_fd = socket(AF_INET,SOCK_STREAM,0);
176
    if (server_fd < 0) {
177
        perror ("socket");
178
        return -1;
179
    }
180
        
181
    tmp = 1;
182
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
183

    
184
    if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
185
        perror ("bind");
186
        close(server_fd);
187
        return -1;
188
    }
189
  
190
    if (listen (server_fd, 5) < 0) {
191
        perror ("listen");
192
        close(server_fd);
193
        return -1;
194
    }
195

    
196
    http_log("ffserver started.\n");
197

    
198
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
199
    first_http_ctx = NULL;
200
    nb_connections = 0;
201
    first_http_ctx = NULL;
202
    for(;;) {
203
        poll_entry = poll_table;
204
        poll_entry->fd = server_fd;
205
        poll_entry->events = POLLIN;
206
        poll_entry++;
207

    
208
        /* wait for events on each HTTP handle */
209
        c = first_http_ctx;
210
        while (c != NULL) {
211
            int fd;
212
            fd = c->fd;
213
            switch(c->state) {
214
            case HTTPSTATE_WAIT_REQUEST:
215
                c->poll_entry = poll_entry;
216
                poll_entry->fd = fd;
217
                poll_entry->events = POLLIN;
218
                poll_entry++;
219
                break;
220
            case HTTPSTATE_SEND_HEADER:
221
            case HTTPSTATE_SEND_DATA_HEADER:
222
            case HTTPSTATE_SEND_DATA:
223
            case HTTPSTATE_SEND_DATA_TRAILER:
224
                c->poll_entry = poll_entry;
225
                poll_entry->fd = fd;
226
                poll_entry->events = POLLOUT;
227
                poll_entry++;
228
                break;
229
            case HTTPSTATE_RECEIVE_DATA:
230
                c->poll_entry = poll_entry;
231
                poll_entry->fd = fd;
232
                poll_entry->events = POLLIN;
233
                poll_entry++;
234
                break;
235
            case HTTPSTATE_WAIT_FEED:
236
                /* need to catch errors */
237
                c->poll_entry = poll_entry;
238
                poll_entry->fd = fd;
239
                poll_entry->events = 0;
240
                poll_entry++;
241
                break;
242
            default:
243
                c->poll_entry = NULL;
244
                break;
245
            }
246
            c = c->next;
247
        }
248

    
249
        /* wait for an event on one connection. We poll at least every
250
           second to handle timeouts */
251
        do {
252
            ret = poll(poll_table, poll_entry - poll_table, 1000);
253
        } while (ret == -1);
254
        
255
        cur_time = gettime_ms();
256

    
257
        /* now handle the events */
258

    
259
        cp = &first_http_ctx;
260
        while ((*cp) != NULL) {
261
            c = *cp;
262
            if (handle_http (c, cur_time) < 0) {
263
                /* close and free the connection */
264
                close(c->fd);
265
                if (c->fmt_in)
266
                    av_close_input_file(c->fmt_in);
267
                *cp = c->next;
268
                free(c);
269
                nb_connections--;
270
            } else {
271
                cp = &c->next;
272
            }
273
        }
274

    
275
        /* new connection request ? */
276
        poll_entry = poll_table;
277
        if (poll_entry->revents & POLLIN) {
278
            int fd, len;
279

    
280
            len = sizeof(from_addr);
281
            fd = accept(server_fd, (struct sockaddr *)&from_addr, 
282
                        &len);
283
            if (fd >= 0) {
284
                fcntl(fd, F_SETFL, O_NONBLOCK);
285
                /* XXX: should output a warning page when coming
286
                   close to the connection limit */
287
                if (nb_connections >= nb_max_connections) {
288
                    close(fd);
289
                } else {
290
                    /* add a new connection */
291
                    c = av_mallocz(sizeof(HTTPContext));
292
                    c->next = first_http_ctx;
293
                    first_http_ctx = c;
294
                    c->fd = fd;
295
                    c->poll_entry = NULL;
296
                    c->from_addr = from_addr;
297
                    c->state = HTTPSTATE_WAIT_REQUEST;
298
                    c->buffer_ptr = c->buffer;
299
                    c->buffer_end = c->buffer + IOBUFFER_MAX_SIZE;
300
                    c->timeout = cur_time + REQUEST_TIMEOUT;
301
                    nb_connections++;
302
                }
303
            }
304
        }
305
        poll_entry++;
306
    }
307
}
308

    
309
static int handle_http(HTTPContext *c, long cur_time)
310
{
311
    int len;
312
    
313
    switch(c->state) {
314
    case HTTPSTATE_WAIT_REQUEST:
315
        /* timeout ? */
316
        if ((c->timeout - cur_time) < 0)
317
            return -1;
318
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
319
            return -1;
320

    
321
        /* no need to read if no events */
322
        if (!(c->poll_entry->revents & POLLIN))
323
            return 0;
324
        /* read the data */
325
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
326
        if (len < 0) {
327
            if (errno != EAGAIN && errno != EINTR)
328
                return -1;
329
        } else if (len == 0) {
330
            return -1;
331
        } else {
332
            /* search for end of request. XXX: not fully correct since garbage could come after the end */
333
            UINT8 *ptr;
334
            c->buffer_ptr += len;
335
            ptr = c->buffer_ptr;
336
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
337
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
338
                /* request found : parse it and reply */
339
                if (http_parse_request(c) < 0)
340
                    return -1;
341
            } else if (ptr >= c->buffer_end) {
342
                /* request too long: cannot do anything */
343
                return -1;
344
            }
345
        }
346
        break;
347

    
348
    case HTTPSTATE_SEND_HEADER:
349
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
350
            return -1;
351

    
352
        /* no need to read if no events */
353
        if (!(c->poll_entry->revents & POLLOUT))
354
            return 0;
355
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
356
        if (len < 0) {
357
            if (errno != EAGAIN && errno != EINTR) {
358
                /* error : close connection */
359
                return -1;
360
            }
361
        } else {
362
            c->buffer_ptr += len;
363
            if (c->buffer_ptr >= c->buffer_end) {
364
                /* if error, exit */
365
                if (c->http_error)
366
                    return -1;
367
                /* all the buffer was send : synchronize to the incoming stream */
368
                c->state = HTTPSTATE_SEND_DATA_HEADER;
369
                c->buffer_ptr = c->buffer_end = c->buffer;
370
            }
371
        }
372
        break;
373

    
374
    case HTTPSTATE_SEND_DATA:
375
    case HTTPSTATE_SEND_DATA_HEADER:
376
    case HTTPSTATE_SEND_DATA_TRAILER:
377
        /* no need to read if no events */
378
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
379
            return -1;
380
        
381
        if (!(c->poll_entry->revents & POLLOUT))
382
            return 0;
383
        if (http_send_data(c) < 0)
384
            return -1;
385
        break;
386
    case HTTPSTATE_RECEIVE_DATA:
387
        /* no need to read if no events */
388
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
389
            return -1;
390
        if (!(c->poll_entry->revents & POLLIN))
391
            return 0;
392
        if (http_receive_data(c) < 0)
393
            return -1;
394
        break;
395
    case HTTPSTATE_WAIT_FEED:
396
        /* no need to read if no events */
397
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
398
            return -1;
399

    
400
        /* nothing to do, we'll be waken up by incoming feed packets */
401
        break;
402
    default:
403
        return -1;
404
    }
405
    return 0;
406
}
407

    
408
/* parse http request and prepare header */
409
static int http_parse_request(HTTPContext *c)
410
{
411
    char *p;
412
    int post;
413
    char cmd[32];
414
    char info[1024], *filename;
415
    char url[1024], *q;
416
    char protocol[32];
417
    char msg[1024];
418
    const char *mime_type;
419
    FFStream *stream;
420

    
421
    p = c->buffer;
422
    q = cmd;
423
    while (!isspace(*p) && *p != '\0') {
424
        if ((q - cmd) < sizeof(cmd) - 1)
425
            *q++ = *p;
426
        p++;
427
    }
428
    *q = '\0';
429
    if (!strcmp(cmd, "GET"))
430
        post = 0;
431
    else if (!strcmp(cmd, "POST"))
432
        post = 1;
433
    else
434
        return -1;
435

    
436
    while (isspace(*p)) p++;
437
    q = url;
438
    while (!isspace(*p) && *p != '\0') {
439
        if ((q - url) < sizeof(url) - 1)
440
            *q++ = *p;
441
        p++;
442
    }
443
    *q = '\0';
444

    
445
    while (isspace(*p)) p++;
446
    q = protocol;
447
    while (!isspace(*p) && *p != '\0') {
448
        if ((q - protocol) < sizeof(protocol) - 1)
449
            *q++ = *p;
450
        p++;
451
    }
452
    *q = '\0';
453
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
454
        return -1;
455
    
456
    /* find the filename and the optional info string in the request */
457
    p = url;
458
    if (*p == '/')
459
        p++;
460
    filename = p;
461
    p = strchr(p, '?');
462
    if (p) {
463
        strcpy(info, p);
464
        *p = '\0';
465
    } else {
466
        info[0] = '\0';
467
    }
468

    
469
    stream = first_stream;
470
    while (stream != NULL) {
471
        if (!strcmp(stream->filename, filename))
472
            break;
473
        stream = stream->next;
474
    }
475
    if (stream == NULL) {
476
        sprintf(msg, "File '%s' not found", url);
477
        goto send_error;
478
    }
479
    c->stream = stream;
480
    
481
    /* should do it after so that the size can be computed */
482
    {
483
        char buf1[32], buf2[32], *p;
484
        time_t ti;
485
        /* XXX: reentrant function ? */
486
        p = inet_ntoa(c->from_addr.sin_addr);
487
        strcpy(buf1, p);
488
        ti = time(NULL);
489
        p = ctime(&ti);
490
        strcpy(buf2, p);
491
        p = buf2 + strlen(p) - 1;
492
        if (*p == '\n')
493
            *p = '\0';
494
        http_log("%s - - [%s] \"%s %s %s\" %d %d\n", 
495
                 buf1, buf2, cmd, url, protocol, 200, 1024);
496
    }
497

    
498
    /* XXX: add there authenticate and IP match */
499

    
500
    if (post) {
501
        /* if post, it means a feed is being sent */
502
        if (!stream->is_feed) {
503
            sprintf(msg, "POST command not handled");
504
            goto send_error;
505
        }
506
        if (http_start_receive_data(c) < 0) {
507
            sprintf(msg, "could not open feed");
508
            goto send_error;
509
        }
510
        c->http_error = 0;
511
        c->state = HTTPSTATE_RECEIVE_DATA;
512
        return 0;
513
    }
514

    
515
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
516
        goto send_stats;
517

    
518
    /* open input stream */
519
    if (open_input_stream(c, info) < 0) {
520
        sprintf(msg, "Input stream corresponding to '%s' not found", url);
521
        goto send_error;
522
    }
523

    
524
    /* prepare http header */
525
    q = c->buffer;
526
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
527
    mime_type = c->stream->fmt->mime_type;
528
    if (!mime_type)
529
        mime_type = "application/x-octet_stream";
530
    q += sprintf(q, "Content-type: %s\r\n", mime_type);
531
    q += sprintf(q, "Pragma: no-cache\r\n");
532

    
533
    /* for asf, we need extra headers */
534
    if (!strcmp(c->stream->fmt->name,"asf")) {
535
        q += sprintf(q, "Pragma: features=broadcast\r\n");
536
    }
537
    q += sprintf(q, "\r\n");
538
    
539
    /* prepare output buffer */
540
    c->http_error = 0;
541
    c->buffer_ptr = c->buffer;
542
    c->buffer_end = q;
543
    c->state = HTTPSTATE_SEND_HEADER;
544
    return 0;
545
 send_error:
546
    c->http_error = 404;
547
    q = c->buffer;
548
    q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
549
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
550
    q += sprintf(q, "\r\n");
551
    q += sprintf(q, "<HTML>\n");
552
    q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
553
    q += sprintf(q, "<BODY>%s</BODY>\n", msg);
554
    q += sprintf(q, "</HTML>\n");
555

    
556
    /* prepare output buffer */
557
    c->buffer_ptr = c->buffer;
558
    c->buffer_end = q;
559
    c->state = HTTPSTATE_SEND_HEADER;
560
    return 0;
561
 send_stats:
562
    compute_stats(c);
563
    c->http_error = 200; /* horrible : we use this value to avoid
564
                            going to the send data state */
565
    c->state = HTTPSTATE_SEND_HEADER;
566
    return 0;
567
}
568

    
569
static void compute_stats(HTTPContext *c)
570
{
571
    HTTPContext *c1;
572
    FFStream *stream;
573
    char *q, *p;
574
    time_t ti;
575
    int i;
576

    
577
    q = c->buffer;
578
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
579
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
580
    q += sprintf(q, "Pragma: no-cache\r\n");
581
    q += sprintf(q, "\r\n");
582
    
583
    q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE></HEAD>\n<BODY>");
584
    q += sprintf(q, "<H1>FFServer Status</H1>\n");
585
    /* format status */
586
    q += sprintf(q, "<H1>Available Streams</H1>\n");
587
    q += sprintf(q, "<TABLE>\n");
588
    q += sprintf(q, "<TR><TD>Path<TD>Format<TD>Bit rate (kbits/s)<TD>Video<TD>Audio<TD>Feed\n");
589
    stream = first_stream;
590
    while (stream != NULL) {
591
        q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
592
                     stream->filename, stream->filename);
593
        switch(stream->stream_type) {
594
        case STREAM_TYPE_LIVE:
595
            {
596
                int audio_bit_rate = 0;
597
                int video_bit_rate = 0;
598

    
599
                for(i=0;i<stream->nb_streams;i++) {
600
                    AVStream *st = stream->streams[i];
601
                    switch(st->codec.codec_type) {
602
                    case CODEC_TYPE_AUDIO:
603
                        audio_bit_rate += st->codec.bit_rate;
604
                        break;
605
                    case CODEC_TYPE_VIDEO:
606
                        video_bit_rate += st->codec.bit_rate;
607
                        break;
608
                    }
609
                }
610
                q += sprintf(q, "<TD> %s <TD> %d <TD> %d <TD> %d", 
611
                             stream->fmt->name,
612
                             (audio_bit_rate + video_bit_rate) / 1000,
613
                             video_bit_rate / 1000, audio_bit_rate / 1000);
614
                if (stream->feed) {
615
                    q += sprintf(q, "<TD>%s", stream->feed->filename);
616
                } else {
617
                    q += sprintf(q, "<TD>%s", stream->feed_filename);
618
                }
619
                q += sprintf(q, "\n");
620
            }
621
            break;
622
        default:
623
            q += sprintf(q, "<TD> - <TD> - <TD> - <TD> -\n");
624
            break;
625
        }
626
        stream = stream->next;
627
    }
628
    q += sprintf(q, "</TABLE>\n");
629
    
630
#if 0
631
    {
632
        float avg;
633
        AVCodecContext *enc;
634
        char buf[1024];
635
        
636
        /* feed status */
637
        stream = first_feed;
638
        while (stream != NULL) {
639
            q += sprintf(q, "<H1>Feed '%s'</H1>\n", stream->filename);
640
            q += sprintf(q, "<TABLE>\n");
641
            q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
642
            for(i=0;i<stream->nb_streams;i++) {
643
                AVStream *st = stream->streams[i];
644
                FeedData *fdata = st->priv_data;
645
                enc = &st->codec;
646
            
647
                avcodec_string(buf, sizeof(buf), enc);
648
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
649
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
650
                    avg /= enc->frame_size;
651
                q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
652
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
653
            }
654
            q += sprintf(q, "</TABLE>\n");
655
            stream = stream->next_feed;
656
        }
657
    }
658
#endif
659

    
660
    /* connection status */
661
    q += sprintf(q, "<H1>Connection Status</H1>\n");
662

    
663
    q += sprintf(q, "Number of connections: %d / %d<BR>\n",
664
                 nb_connections, nb_max_connections);
665

    
666
    q += sprintf(q, "<TABLE>\n");
667
    q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n");
668
    c1 = first_http_ctx;
669
    i = 0;
670
    while (c1 != NULL) {
671
        i++;
672
        p = inet_ntoa(c1->from_addr.sin_addr);
673
        q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <TD> %Ld\n", 
674
                     i, c1->stream->filename, 
675
                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
676
                     p, 
677
                     http_state[c1->state],
678
                     c1->data_count);
679
        c1 = c1->next;
680
    }
681
    q += sprintf(q, "</TABLE>\n");
682
    
683
    /* date */
684
    ti = time(NULL);
685
    p = ctime(&ti);
686
    q += sprintf(q, "<HR>Generated at %s", p);
687
    q += sprintf(q, "</BODY>\n</HTML>\n");
688

    
689
    c->buffer_ptr = c->buffer;
690
    c->buffer_end = q;
691
}
692

    
693

    
694
static void http_write_packet(void *opaque, 
695
                              unsigned char *buf, int size)
696
{
697
    HTTPContext *c = opaque;
698
    if (size > IOBUFFER_MAX_SIZE)
699
        abort();
700
    memcpy(c->buffer, buf, size);
701
    c->buffer_ptr = c->buffer;
702
    c->buffer_end = c->buffer + size;
703
}
704

    
705
static int open_input_stream(HTTPContext *c, const char *info)
706
{
707
    char buf[128];
708
    char input_filename[1024];
709
    AVFormatContext *s;
710
    int buf_size;
711
    INT64 stream_pos;
712

    
713
    /* find file name */
714
    if (c->stream->feed) {
715
        strcpy(input_filename, c->stream->feed->feed_filename);
716
        buf_size = FFM_PACKET_SIZE;
717
        /* compute position (absolute time) */
718
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
719
            stream_pos = parse_date(buf, 0);
720
        } else {
721
            stream_pos = gettime();
722
        }
723
    } else {
724
        strcpy(input_filename, c->stream->feed_filename);
725
        buf_size = 0;
726
        /* compute position (relative time) */
727
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
728
            stream_pos = parse_date(buf, 1);
729
        } else {
730
            stream_pos = 0;
731
        }
732
    }
733
    if (input_filename[0] == '\0')
734
        return -1;
735

    
736
    /* open stream */
737
    s = av_open_input_file(input_filename, NULL, buf_size, NULL);
738
    if (!s)
739
        return -1;
740
    c->fmt_in = s;
741

    
742
    if (c->fmt_in->format->read_seek) {
743
        c->fmt_in->format->read_seek(c->fmt_in, stream_pos);
744
    }
745
    
746
    //    printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
747
    return 0;
748
}
749

    
750
static int http_prepare_data(HTTPContext *c)
751
{
752
    int i;
753

    
754
    switch(c->state) {
755
    case HTTPSTATE_SEND_DATA_HEADER:
756
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
757
        if (c->stream->feed) {
758
            /* open output stream by using specified codecs */
759
            c->fmt_ctx.format = c->stream->fmt;
760
            c->fmt_ctx.nb_streams = c->stream->nb_streams;
761
            for(i=0;i<c->fmt_ctx.nb_streams;i++) {
762
                AVStream *st;
763
                st = av_mallocz(sizeof(AVStream));
764
                c->fmt_ctx.streams[i] = st;
765
                memcpy(st, c->stream->streams[i], sizeof(AVStream));
766
                st->codec.frame_number = 0; /* XXX: should be done in
767
                                               AVStream, not in codec */
768
                c->got_key_frame[i] = 0;
769
            }
770
        } else {
771
            /* open output stream by using codecs in specified file */
772
            c->fmt_ctx.format = c->stream->fmt;
773
            c->fmt_ctx.nb_streams = c->fmt_in->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
                memcpy(st, c->fmt_in->streams[i], sizeof(AVStream));
779
                st->codec.frame_number = 0; /* XXX: should be done in
780
                                               AVStream, not in codec */
781
                c->got_key_frame[i] = 0;
782
            }
783
        }
784
        init_put_byte(&c->fmt_ctx.pb, c->buffer, IOBUFFER_MAX_SIZE,
785
                      1, c, NULL, http_write_packet, NULL);
786
        c->fmt_ctx.pb.is_streamed = 1;
787
        /* prepare header */
788
        c->fmt_ctx.format->write_header(&c->fmt_ctx);
789
        c->state = HTTPSTATE_SEND_DATA;
790
        c->last_packet_sent = 0;
791
        break;
792
    case HTTPSTATE_SEND_DATA:
793
        /* find a new packet */
794
#if 0
795
        fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
796
        if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
797
            /* overflow : resync. We suppose that wptr is at this
798
               point a pointer to a valid packet */
799
            c->rptr = http_fifo.wptr;
800
            for(i=0;i<c->fmt_ctx.nb_streams;i++) {
801
                c->got_key_frame[i] = 0;
802
            }
803
        }
804
        
805
        start_rptr = c->rptr;
806
        if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
807
            return 0;
808
        payload_size = ntohs(hdr.payload_size);
809
        payload = malloc(payload_size);
810
        if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
811
            /* cannot read all the payload */
812
            free(payload);
813
            c->rptr = start_rptr;
814
            return 0;
815
        }
816
        
817
        c->last_http_fifo_write_count = http_fifo_write_count - 
818
            fifo_size(&http_fifo, c->rptr);
819
        
820
        if (c->stream->stream_type != STREAM_TYPE_MASTER) {
821
            /* test if the packet can be handled by this format */
822
            ret = 0;
823
            for(i=0;i<c->fmt_ctx.nb_streams;i++) {
824
                AVStream *st = c->fmt_ctx.streams[i];
825
                if (test_header(&hdr, &st->codec)) {
826
                    /* only begin sending when got a key frame */
827
                    if (st->codec.key_frame)
828
                        c->got_key_frame[i] = 1;
829
                    if (c->got_key_frame[i]) {
830
                        ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i,
831
                                                                   payload, payload_size);
832
                    }
833
                    break;
834
                }
835
            }
836
            if (ret) {
837
                /* must send trailer now */
838
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
839
            }
840
        } else {
841
            /* master case : send everything */
842
            char *q;
843
            q = c->buffer;
844
            memcpy(q, &hdr, sizeof(hdr));
845
            q += sizeof(hdr);
846
            memcpy(q, payload, payload_size);
847
            q += payload_size;
848
            c->buffer_ptr = c->buffer;
849
            c->buffer_end = q;
850
        }
851
        free(payload);
852
#endif
853
        {
854
            AVPacket pkt;
855

    
856
            /* read a packet from the input stream */
857
            if (c->stream->feed) {
858
                ffm_set_write_index(c->fmt_in, 
859
                                    c->stream->feed->feed_write_index,
860
                                    c->stream->feed->feed_size);
861
            }
862
            if (av_read_packet(c->fmt_in, &pkt) < 0) {
863
                if (c->stream->feed && c->stream->feed->feed_opened) {
864
                    /* if coming from feed, it means we reached the end of the
865
                       ffm file, so must wait for more data */
866
                    c->state = HTTPSTATE_WAIT_FEED;
867
                    return 1; /* state changed */
868
                } else {
869
                    /* must send trailer now because eof or error */
870
                    c->state = HTTPSTATE_SEND_DATA_TRAILER;
871
                }
872
            } else {
873
                /* send it to the appropriate stream */
874
                if (c->stream->feed) {
875
                    /* if coming from a feed, select the right stream */
876
                    for(i=0;i<c->stream->nb_streams;i++) {
877
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
878
                            pkt.stream_index = i;
879
                            goto send_it;
880
                        }
881
                    }
882
                } else {
883
                send_it:
884
                    av_write_packet(&c->fmt_ctx, &pkt);
885
                }
886
                
887
                av_free_packet(&pkt);
888
            }
889
        }
890
        break;
891
    default:
892
    case HTTPSTATE_SEND_DATA_TRAILER:
893
        /* last packet test ? */
894
        if (c->last_packet_sent)
895
            return -1;
896
        /* prepare header */
897
        c->fmt_ctx.format->write_trailer(&c->fmt_ctx);
898
        c->last_packet_sent = 1;
899
        break;
900
    }
901
    return 0;
902
}
903

    
904
/* should convert the format at the same time */
905
static int http_send_data(HTTPContext *c)
906
{
907
    int len, ret;
908

    
909
    while (c->buffer_ptr >= c->buffer_end) {
910
        ret = http_prepare_data(c);
911
        if (ret < 0)
912
            return -1;
913
        else if (ret == 0) {
914
            break;
915
        } else {
916
            /* state change requested */
917
            return 0;
918
        }
919
    }
920

    
921
    len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
922
    if (len < 0) {
923
        if (errno != EAGAIN && errno != EINTR) {
924
            /* error : close connection */
925
            return -1;
926
        }
927
    } else {
928
        c->buffer_ptr += len;
929
        c->data_count += len;
930
    }
931
    return 0;
932
}
933

    
934
static int http_start_receive_data(HTTPContext *c)
935
{
936
    int fd;
937

    
938
    if (c->stream->feed_opened)
939
        return -1;
940

    
941
    /* open feed */
942
    fd = open(c->stream->feed_filename, O_RDWR);
943
    if (fd < 0)
944
        return -1;
945
    c->feed_fd = fd;
946
    
947
    c->stream->feed_write_index = ffm_read_write_index(fd);
948
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
949
    lseek(fd, 0, SEEK_SET);
950

    
951
    /* init buffer input */
952
    c->buffer_ptr = c->buffer;
953
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
954
    c->stream->feed_opened = 1;
955
    return 0;
956
}
957
    
958
static int http_receive_data(HTTPContext *c)
959
{
960
    int len;
961
    HTTPContext *c1;
962

    
963
    if (c->buffer_ptr >= c->buffer_end) {
964
        /* a packet has been received : write it in the store, except
965
           if header */
966
        if (c->data_count > FFM_PACKET_SIZE) {
967
            FFStream *feed = c->stream;
968
            
969
            //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
970
            /* XXX: use llseek or url_seek */
971
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
972
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
973
            
974
            feed->feed_write_index += FFM_PACKET_SIZE;
975
            /* update file size */
976
            if (feed->feed_write_index > c->stream->feed_size)
977
                feed->feed_size = feed->feed_write_index;
978

    
979
            /* handle wrap around if max file size reached */
980
            if (feed->feed_write_index >= c->stream->feed_max_size)
981
                feed->feed_write_index = FFM_PACKET_SIZE;
982

    
983
            /* write index */
984
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
985

    
986
            /* wake up any waiting connections */
987
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
988
                if (c1->state == HTTPSTATE_WAIT_FEED && 
989
                    c1->stream->feed == c->stream->feed) {
990
                    c1->state = HTTPSTATE_SEND_DATA;
991
                }
992
            }
993
        }
994
        c->buffer_ptr = c->buffer;
995
    }
996

    
997
    len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
998
    if (len < 0) {
999
        if (errno != EAGAIN && errno != EINTR) {
1000
            /* error : close connection */
1001
            goto fail;
1002
        }
1003
    } else if (len == 0) {
1004
        /* end of connection : close it */
1005
        goto fail;
1006
    } else {
1007
        c->buffer_ptr += len;
1008
        c->data_count += len;
1009
    }
1010
    return 0;
1011
 fail:
1012
    c->stream->feed_opened = 0;
1013
    close(c->feed_fd);
1014
    return -1;
1015
}
1016

    
1017
/* return the stream number in the feed */
1018
int add_av_stream(FFStream *feed,
1019
                  AVStream *st)
1020
{
1021
    AVStream *fst;
1022
    AVCodecContext *av, *av1;
1023
    int i;
1024

    
1025
    av = &st->codec;
1026
    for(i=0;i<feed->nb_streams;i++) {
1027
        st = feed->streams[i];
1028
        av1 = &st->codec;
1029
        if (av1->codec == av->codec &&
1030
            av1->bit_rate == av->bit_rate) {
1031

    
1032
            switch(av->codec_type) {
1033
            case CODEC_TYPE_AUDIO:
1034
                if (av1->channels == av->channels &&
1035
                    av1->sample_rate == av->sample_rate)
1036
                    goto found;
1037
                break;
1038
            case CODEC_TYPE_VIDEO:
1039
                if (av1->width == av->width &&
1040
                    av1->height == av->height &&
1041
                    av1->frame_rate == av->frame_rate &&
1042
                    av1->gop_size == av->gop_size)
1043
                    goto found;
1044
                break;
1045
            }
1046
        }
1047
    }
1048
    
1049
    fst = av_mallocz(sizeof(AVStream));
1050
    if (!fst)
1051
        return -1;
1052
    fst->priv_data = av_mallocz(sizeof(FeedData));
1053
    memcpy(&fst->codec, av, sizeof(AVCodecContext));
1054
    feed->streams[feed->nb_streams++] = fst;
1055
    return feed->nb_streams - 1;
1056
 found:
1057
    return i;
1058
}
1059

    
1060
/* compute the needed AVStream for each feed */
1061
void build_feed_streams(void)
1062
{
1063
    FFStream *stream, *feed;
1064
    int i;
1065

    
1066
    /* gather all streams */
1067
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1068
        feed = stream->feed;
1069
        if (feed) {
1070
            if (!stream->is_feed) {
1071
                for(i=0;i<stream->nb_streams;i++) {
1072
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
1073
                }
1074
            } else {
1075
                for(i=0;i<stream->nb_streams;i++) {
1076
                    stream->feed_streams[i] = i;
1077
                }
1078
            }
1079
        }
1080
    }
1081

    
1082
    /* create feed files if needed */
1083
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
1084
        int fd;
1085

    
1086
        if (!url_exist(feed->feed_filename)) {
1087
            AVFormatContext s1, *s = &s1;
1088

    
1089
            /* only write the header of the ffm file */
1090
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
1091
                fprintf(stderr, "Could not open output feed file '%s'\n",
1092
                        feed->feed_filename);
1093
                exit(1);
1094
            }
1095
            s->format = feed->fmt;
1096
            s->nb_streams = feed->nb_streams;
1097
            for(i=0;i<s->nb_streams;i++) {
1098
                AVStream *st;
1099
                st = feed->streams[i];
1100
                s->streams[i] = st;
1101
            }
1102
            s->format->write_header(s);
1103

    
1104
            url_fclose(&s->pb);
1105
        }
1106
        /* get feed size and write index */
1107
        fd = open(feed->feed_filename, O_RDONLY);
1108
        if (fd < 0) {
1109
            fprintf(stderr, "Could not open output feed file '%s'\n",
1110
                    feed->feed_filename);
1111
            exit(1);
1112
        }
1113

    
1114
        feed->feed_write_index = ffm_read_write_index(fd);
1115
        feed->feed_size = lseek(fd, 0, SEEK_END);
1116
        /* ensure that we do not wrap before the end of file */
1117
        if (feed->feed_max_size < feed->feed_size)
1118
            feed->feed_max_size = feed->feed_size;
1119

    
1120
        close(fd);
1121
    }
1122
}
1123

    
1124
static void get_arg(char *buf, int buf_size, const char **pp)
1125
{
1126
    const char *p;
1127
    char *q;
1128
    int quote;
1129

    
1130
    p = *pp;
1131
    while (isspace(*p)) p++;
1132
    q = buf;
1133
    quote = 0;
1134
    if (*p == '\"' || *p == '\'')
1135
        quote = *p++;
1136
    for(;;) {
1137
        if (quote) {
1138
            if (*p == quote)
1139
                break;
1140
        } else {
1141
            if (isspace(*p))
1142
                break;
1143
        }
1144
        if (*p == '\0')
1145
            break;
1146
        if ((q - buf) < buf_size - 1)
1147
            *q++ = *p;
1148
        p++;
1149
    }
1150
    *q = '\0';
1151
    if (quote && *p == quote)
1152
        p++;
1153
    *pp = p;
1154
}
1155

    
1156
/* add a codec and set the default parameters */
1157
void add_codec(FFStream *stream, AVCodecContext *av)
1158
{
1159
    AVStream *st;
1160

    
1161
    /* compute default parameters */
1162
    switch(av->codec_type) {
1163
    case CODEC_TYPE_AUDIO:
1164
        if (av->bit_rate == 0)
1165
            av->bit_rate = 64000;
1166
        if (av->sample_rate == 0)
1167
            av->sample_rate = 22050;
1168
        if (av->channels == 0)
1169
            av->channels = 1;
1170
        break;
1171
    case CODEC_TYPE_VIDEO:
1172
        if (av->bit_rate == 0)
1173
            av->bit_rate = 64000;
1174
        if (av->frame_rate == 0)
1175
            av->frame_rate = 5 * FRAME_RATE_BASE;
1176
        if (av->width == 0 || av->height == 0) {
1177
            av->width = 160;
1178
            av->height = 128;
1179
        }
1180
        break;
1181
    }
1182

    
1183
    st = av_mallocz(sizeof(AVStream));
1184
    if (!st)
1185
        return;
1186
    stream->streams[stream->nb_streams++] = st;
1187
    memcpy(&st->codec, av, sizeof(AVCodecContext));
1188
}
1189

    
1190
int parse_ffconfig(const char *filename)
1191
{
1192
    FILE *f;
1193
    char line[1024];
1194
    char cmd[64];
1195
    char arg[1024];
1196
    const char *p;
1197
    int val, errors, line_num;
1198
    FFStream **last_stream, *stream;
1199
    FFStream **last_feed, *feed;
1200
    AVCodecContext audio_enc, video_enc;
1201
    int audio_id, video_id;
1202

    
1203
    f = fopen(filename, "r");
1204
    if (!f) {
1205
        perror(filename);
1206
        return -1;
1207
    }
1208
    
1209
    errors = 0;
1210
    line_num = 0;
1211
    first_stream = NULL;
1212
    last_stream = &first_stream;
1213
    first_feed = NULL;
1214
    last_feed = &first_feed;
1215
    stream = NULL;
1216
    feed = NULL;
1217
    audio_id = CODEC_ID_NONE;
1218
    video_id = CODEC_ID_NONE;
1219
    for(;;) {
1220
        if (fgets(line, sizeof(line), f) == NULL)
1221
            break;
1222
        line_num++;
1223
        p = line;
1224
        while (isspace(*p)) 
1225
            p++;
1226
        if (*p == '\0' || *p == '#')
1227
            continue;
1228

    
1229
        get_arg(cmd, sizeof(cmd), &p);
1230
        
1231
        if (!strcasecmp(cmd, "Port")) {
1232
            get_arg(arg, sizeof(arg), &p);
1233
            my_addr.sin_port = htons (atoi(arg));
1234
        } else if (!strcasecmp(cmd, "BindAddress")) {
1235
            get_arg(arg, sizeof(arg), &p);
1236
            if (!inet_aton(arg, &my_addr.sin_addr)) {
1237
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
1238
                        filename, line_num, arg);
1239
                errors++;
1240
            }
1241
        } else if (!strcasecmp(cmd, "MaxClients")) {
1242
            get_arg(arg, sizeof(arg), &p);
1243
            val = atoi(arg);
1244
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
1245
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
1246
                        filename, line_num, arg);
1247
                errors++;
1248
            } else {
1249
                nb_max_connections = val;
1250
            }
1251
        } else if (!strcasecmp(cmd, "CustomLog")) {
1252
            get_arg(logfilename, sizeof(logfilename), &p);
1253
        } else if (!strcasecmp(cmd, "<Feed")) {
1254
            /*********************************************/
1255
            /* Feed related options */
1256
            char *q;
1257
            if (stream || feed) {
1258
                fprintf(stderr, "%s:%d: Already in a tag\n",
1259
                        filename, line_num);
1260
            } else {
1261
                feed = av_mallocz(sizeof(FFStream));
1262
                /* add in stream list */
1263
                *last_stream = feed;
1264
                last_stream = &feed->next;
1265
                /* add in feed list */
1266
                *last_feed = feed;
1267
                last_feed = &feed->next_feed;
1268
                
1269
                get_arg(feed->filename, sizeof(feed->filename), &p);
1270
                q = strrchr(feed->filename, '>');
1271
                if (*q)
1272
                    *q = '\0';
1273
                feed->fmt = guess_format("ffm", NULL, NULL);
1274
                /* defaut feed file */
1275
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
1276
                         "/tmp/%s.ffm", feed->filename);
1277
                feed->feed_max_size = 5 * 1024 * 1024;
1278
                feed->is_feed = 1;
1279
                feed->feed = feed; /* self feeding :-) */
1280
            }
1281
        } else if (!strcasecmp(cmd, "File")) {
1282
            if (feed) {
1283
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
1284
            } else if (stream) {
1285
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
1286
            }
1287
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
1288
            if (feed) {
1289
                const char *p1;
1290
                double fsize;
1291

    
1292
                get_arg(arg, sizeof(arg), &p);
1293
                p1 = arg;
1294
                fsize = strtod(p1, (char **)&p1);
1295
                switch(toupper(*p1)) {
1296
                case 'K':
1297
                    fsize *= 1024;
1298
                    break;
1299
                case 'M':
1300
                    fsize *= 1024 * 1024;
1301
                    break;
1302
                case 'G':
1303
                    fsize *= 1024 * 1024 * 1024;
1304
                    break;
1305
                }
1306
                feed->feed_max_size = (INT64)fsize;
1307
            }
1308
        } else if (!strcasecmp(cmd, "</Feed>")) {
1309
            if (!feed) {
1310
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
1311
                        filename, line_num);
1312
                errors++;
1313
            }
1314
            feed = NULL;
1315
        } else if (!strcasecmp(cmd, "<Stream")) {
1316
            /*********************************************/
1317
            /* Stream related options */
1318
            char *q;
1319
            if (stream || feed) {
1320
                fprintf(stderr, "%s:%d: Already in a tag\n",
1321
                        filename, line_num);
1322
            } else {
1323
                stream = av_mallocz(sizeof(FFStream));
1324
                *last_stream = stream;
1325
                last_stream = &stream->next;
1326

    
1327
                get_arg(stream->filename, sizeof(stream->filename), &p);
1328
                q = strrchr(stream->filename, '>');
1329
                if (*q)
1330
                    *q = '\0';
1331
                stream->fmt = guess_format(NULL, stream->filename, NULL);
1332
                memset(&audio_enc, 0, sizeof(AVCodecContext));
1333
                memset(&video_enc, 0, sizeof(AVCodecContext));
1334
                audio_id = CODEC_ID_NONE;
1335
                video_id = CODEC_ID_NONE;
1336
                if (stream->fmt) {
1337
                    audio_id = stream->fmt->audio_codec;
1338
                    video_id = stream->fmt->video_codec;
1339
                }
1340
            }
1341
        } else if (!strcasecmp(cmd, "Feed")) {
1342
            get_arg(arg, sizeof(arg), &p);
1343
            if (stream) {
1344
                FFStream *sfeed;
1345
                
1346
                sfeed = first_feed;
1347
                while (sfeed != NULL) {
1348
                    if (!strcmp(sfeed->filename, arg))
1349
                        break;
1350
                    sfeed = sfeed->next_feed;
1351
                }
1352
                if (!sfeed) {
1353
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
1354
                            filename, line_num, arg);
1355
                } else {
1356
                    stream->feed = sfeed;
1357
                }
1358
            }
1359
        } else if (!strcasecmp(cmd, "Format")) {
1360
            get_arg(arg, sizeof(arg), &p);
1361
            if (!strcmp(arg, "status")) {
1362
                stream->stream_type = STREAM_TYPE_STATUS;
1363
                stream->fmt = NULL;
1364
            } else {
1365
                stream->stream_type = STREAM_TYPE_LIVE;
1366
                /* jpeg cannot be used here, so use single frame jpeg */
1367
                if (!strcmp(arg, "jpeg"))
1368
                    strcpy(arg, "singlejpeg");
1369
                stream->fmt = guess_format(arg, NULL, NULL);
1370
                if (!stream->fmt) {
1371
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
1372
                            filename, line_num, arg);
1373
                    errors++;
1374
                }
1375
            }
1376
            if (stream->fmt) {
1377
                audio_id = stream->fmt->audio_codec;
1378
                video_id = stream->fmt->video_codec;
1379
            }
1380
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
1381
            get_arg(arg, sizeof(arg), &p);
1382
            if (stream) {
1383
                audio_enc.bit_rate = atoi(arg) * 1000;
1384
            }
1385
        } else if (!strcasecmp(cmd, "AudioChannels")) {
1386
            get_arg(arg, sizeof(arg), &p);
1387
            if (stream) {
1388
                audio_enc.channels = atoi(arg);
1389
            }
1390
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
1391
            get_arg(arg, sizeof(arg), &p);
1392
            if (stream) {
1393
                audio_enc.sample_rate = atoi(arg);
1394
            }
1395
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
1396
            get_arg(arg, sizeof(arg), &p);
1397
            if (stream) {
1398
                video_enc.bit_rate = atoi(arg) * 1000;
1399
            }
1400
        } else if (!strcasecmp(cmd, "VideoSize")) {
1401
            get_arg(arg, sizeof(arg), &p);
1402
            if (stream) {
1403
                parse_image_size(&video_enc.width, &video_enc.height, arg);
1404
                if ((video_enc.width % 16) != 0 ||
1405
                    (video_enc.height % 16) != 0) {
1406
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
1407
                            filename, line_num);
1408
                    errors++;
1409
                }
1410
            }
1411
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
1412
            get_arg(arg, sizeof(arg), &p);
1413
            if (stream) {
1414
                video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
1415
            }
1416
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
1417
            get_arg(arg, sizeof(arg), &p);
1418
            if (stream) {
1419
                video_enc.gop_size = atoi(arg);
1420
            }
1421
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
1422
            if (stream) {
1423
                video_enc.gop_size = 1;
1424
            }
1425
        } else if (!strcasecmp(cmd, "NoVideo")) {
1426
            video_id = CODEC_ID_NONE;
1427
        } else if (!strcasecmp(cmd, "NoAudio")) {
1428
            audio_id = CODEC_ID_NONE;
1429
        } else if (!strcasecmp(cmd, "</Stream>")) {
1430
            if (!stream) {
1431
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
1432
                        filename, line_num);
1433
                errors++;
1434
            }
1435
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
1436
                if (audio_id != CODEC_ID_NONE) {
1437
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
1438
                    audio_enc.codec_id = audio_id;
1439
                    add_codec(stream, &audio_enc);
1440
                }
1441
                if (video_id != CODEC_ID_NONE) {
1442
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
1443
                    video_enc.codec_id = video_id;
1444
                    add_codec(stream, &video_enc);
1445
                }
1446
            }
1447
            stream = NULL;
1448
        } else {
1449
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
1450
                    filename, line_num, cmd);
1451
            errors++;
1452
        }
1453
    }
1454

    
1455
    fclose(f);
1456
    if (errors)
1457
        return -1;
1458
    else
1459
        return 0;
1460
}
1461

    
1462

    
1463
void *http_server_thread(void *arg)
1464
{
1465
    http_server(my_addr);
1466
    return NULL;
1467
}
1468

    
1469
#if 0
1470
static void write_packet(FFCodec *ffenc,
1471
                         UINT8 *buf, int size)
1472
{
1473
    PacketHeader hdr;
1474
    AVCodecContext *enc = &ffenc->enc;
1475
    UINT8 *wptr;
1476
    mk_header(&hdr, enc, size);
1477
    wptr = http_fifo.wptr;
1478
    fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
1479
    fifo_write(&http_fifo, buf, size, &wptr);
1480
    /* atomic modification of wptr */
1481
    http_fifo.wptr = wptr;
1482
    ffenc->data_count += size;
1483
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
1484
}
1485
#endif
1486

    
1487
void help(void)
1488
{
1489
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000,2001 Gerard Lantau\n"
1490
           "usage: ffserver [-L] [-h] [-f configfile]\n"
1491
           "Hyper fast multi format Audio/Video streaming server\n"
1492
           "\n"
1493
           "-L            : print the LICENCE\n"
1494
           "-h            : this help\n"
1495
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
1496
           );
1497
}
1498

    
1499
void licence(void)
1500
{
1501
    printf(
1502
    "ffserver version " FFMPEG_VERSION "\n"
1503
    "Copyright (c) 2000,2001 Gerard Lantau\n"
1504
    "This program is free software; you can redistribute it and/or modify\n"
1505
    "it under the terms of the GNU General Public License as published by\n"
1506
    "the Free Software Foundation; either version 2 of the License, or\n"
1507
    "(at your option) any later version.\n"
1508
    "\n"
1509
    "This program is distributed in the hope that it will be useful,\n"
1510
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1511
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1512
    "GNU General Public License for more details.\n"
1513
    "\n"
1514
    "You should have received a copy of the GNU General Public License\n"
1515
    "along with this program; if not, write to the Free Software\n"
1516
    "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
1517
    );
1518
}
1519

    
1520
int main(int argc, char **argv)
1521
{
1522
    const char *config_filename;
1523
    int c;
1524

    
1525
    register_all();
1526

    
1527
    config_filename = "/etc/ffserver.conf";
1528

    
1529
    for(;;) {
1530
        c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL);
1531
        if (c == -1)
1532
            break;
1533
        switch(c) {
1534
        case 'L':
1535
            licence();
1536
            exit(1);
1537
        case '?':
1538
        case 'h':
1539
            help();
1540
            exit(1);
1541
        case 'f':
1542
            config_filename = optarg;
1543
            break;
1544
        default:
1545
            exit(2);
1546
        }
1547
    }
1548

    
1549
    /* address on which the server will handle connections */
1550
    my_addr.sin_family = AF_INET;
1551
    my_addr.sin_port = htons (8080);
1552
    my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
1553
    nb_max_connections = 5;
1554
    first_stream = NULL;
1555
    logfilename[0] = '\0';
1556

    
1557
    if (parse_ffconfig(config_filename) < 0) {
1558
        fprintf(stderr, "Incorrect config file - exiting.\n");
1559
        exit(1);
1560
    }
1561

    
1562
    build_feed_streams();
1563

    
1564
    /* signal init */
1565
    signal(SIGPIPE, SIG_IGN);
1566

    
1567
    /* open log file if needed */
1568
    if (logfilename[0] != '\0') {
1569
        if (!strcmp(logfilename, "-"))
1570
            logfile = stdout;
1571
        else
1572
            logfile = fopen(logfilename, "w");
1573
    }
1574

    
1575
    if (http_server(my_addr) < 0) {
1576
        fprintf(stderr, "Could start http server\n");
1577
        exit(1);
1578
    }
1579

    
1580
    return 0;
1581
}