Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ dd2af5aa

History | View | Annotate | Download (48.6 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 "avformat.h"
40

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

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

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

    
64
#define IOBUFFER_MAX_SIZE 16384
65

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

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

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

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

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

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

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

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

    
142
int nb_max_connections;
143
int nb_connections;
144

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

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

    
153
static FILE *logfile = NULL;
154

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

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

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

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

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

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

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

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

    
256
        /* now handle the events */
257

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
692

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1119
        close(fd);
1120
    }
1121
}
1122

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

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

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

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

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

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

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

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

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

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

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

    
1461

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

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

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

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

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

    
1524
    register_all();
1525

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

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

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

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

    
1561
    build_feed_streams();
1562

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

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

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

    
1579
    return 0;
1580
}