Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 1b52b6bd

History | View | Annotate | Download (145 KB)

1
/*
2
 * Multiple format streaming server
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library 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 GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
#define HAVE_AV_CONFIG_H
20
#include "common.h"
21
#include "avformat.h"
22

    
23
#include <stdarg.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 <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/wait.h>
34
#include <netinet/in.h>
35
#include <arpa/inet.h>
36
#include <netdb.h>
37
#include <ctype.h>
38
#include <signal.h>
39
#ifdef CONFIG_HAVE_DLFCN
40
#include <dlfcn.h>
41
#endif
42

    
43
#include "ffserver.h"
44

    
45
/* maximum number of simultaneous HTTP connections */
46
#define HTTP_MAX_CONNECTIONS 2000
47

    
48
enum HTTPState {
49
    HTTPSTATE_WAIT_REQUEST,
50
    HTTPSTATE_SEND_HEADER,
51
    HTTPSTATE_SEND_DATA_HEADER,
52
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
53
    HTTPSTATE_SEND_DATA_TRAILER,
54
    HTTPSTATE_RECEIVE_DATA,       
55
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
56
    HTTPSTATE_WAIT,               /* wait before sending next packets */
57
    HTTPSTATE_WAIT_SHORT,         /* short wait for short term 
58
                                     bandwidth limitation */
59
    HTTPSTATE_READY,
60

    
61
    RTSPSTATE_WAIT_REQUEST,
62
    RTSPSTATE_SEND_REPLY,
63
};
64

    
65
const char *http_state[] = {
66
    "HTTP_WAIT_REQUEST",
67
    "HTTP_SEND_HEADER",
68

    
69
    "SEND_DATA_HEADER",
70
    "SEND_DATA",
71
    "SEND_DATA_TRAILER",
72
    "RECEIVE_DATA",
73
    "WAIT_FEED",
74
    "WAIT",
75
    "WAIT_SHORT",
76
    "READY",
77

    
78
    "RTSP_WAIT_REQUEST",
79
    "RTSP_SEND_REPLY",
80
};
81

    
82
#define IOBUFFER_INIT_SIZE 8192
83

    
84
/* coef for exponential mean for bitrate estimation in statistics */
85
#define AVG_COEF 0.9
86

    
87
/* timeouts are in ms */
88
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
89
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
90

    
91
#define SYNC_TIMEOUT (10 * 1000)
92

    
93
typedef struct {
94
    int64_t count1, count2;
95
    long time1, time2;
96
} DataRateData;
97

    
98
/* context associated with one connection */
99
typedef struct HTTPContext {
100
    enum HTTPState state;
101
    int fd; /* socket file descriptor */
102
    struct sockaddr_in from_addr; /* origin */
103
    struct pollfd *poll_entry; /* used when polling */
104
    long timeout;
105
    uint8_t *buffer_ptr, *buffer_end;
106
    int http_error;
107
    struct HTTPContext *next;
108
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
109
    int64_t data_count;
110
    /* feed input */
111
    int feed_fd;
112
    /* input format handling */
113
    AVFormatContext *fmt_in;
114
    long start_time;            /* In milliseconds - this wraps fairly often */
115
    int64_t first_pts;            /* initial pts value */
116
    int pts_stream_index;       /* stream we choose as clock reference */
117
    /* output format handling */
118
    struct FFStream *stream;
119
    /* -1 is invalid stream */
120
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
121
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
122
    int switch_pending;
123
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
124
    int last_packet_sent; /* true if last data packet was sent */
125
    int suppress_log;
126
    DataRateData datarate;
127
    int wmp_client_id;
128
    char protocol[16];
129
    char method[16];
130
    char url[128];
131
    int buffer_size;
132
    uint8_t *buffer;
133
    int is_packetized; /* if true, the stream is packetized */
134
    int packet_stream_index; /* current stream for output in state machine */
135
    
136
    /* RTSP state specific */
137
    uint8_t *pb_buffer; /* XXX: use that in all the code */
138
    ByteIOContext *pb;
139
    int seq; /* RTSP sequence number */
140

    
141
    /* RTP state specific */
142
    enum RTSPProtocol rtp_protocol;
143
    char session_id[32]; /* session id */
144
    AVFormatContext *rtp_ctx[MAX_STREAMS];
145
    URLContext *rtp_handles[MAX_STREAMS];
146
    /* RTP short term bandwidth limitation */
147
    int packet_byte_count;
148
    int packet_start_time_us; /* used for short durations (a few
149
                                 seconds max) */
150
} HTTPContext;
151

    
152
static AVFrame dummy_frame;
153

    
154
/* each generated stream is described here */
155
enum StreamType {
156
    STREAM_TYPE_LIVE,
157
    STREAM_TYPE_STATUS,
158
    STREAM_TYPE_REDIRECT,
159
};
160

    
161
enum IPAddressAction {
162
    IP_ALLOW = 1,
163
    IP_DENY,
164
};
165

    
166
typedef struct IPAddressACL {
167
    struct IPAddressACL *next;
168
    enum IPAddressAction action;
169
    /* These are in host order */
170
    struct in_addr first;
171
    struct in_addr last;
172
} IPAddressACL;
173

    
174
/* description of each stream of the ffserver.conf file */
175
typedef struct FFStream {
176
    enum StreamType stream_type;
177
    char filename[1024];     /* stream filename */
178
    struct FFStream *feed;   /* feed we are using (can be null if
179
                                coming from file) */
180
    AVOutputFormat *fmt;
181
    IPAddressACL *acl;
182
    int nb_streams;
183
    int prebuffer;      /* Number of millseconds early to start */
184
    long max_time;      /* Number of milliseconds to run */
185
    int send_on_key;
186
    AVStream *streams[MAX_STREAMS];
187
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
188
    char feed_filename[1024]; /* file name of the feed storage, or
189
                                 input file name for a stream */
190
    char author[512];
191
    char title[512];
192
    char copyright[512];
193
    char comment[512];
194
    pid_t pid;  /* Of ffmpeg process */
195
    time_t pid_start;  /* Of ffmpeg process */
196
    char **child_argv;
197
    struct FFStream *next;
198
    int bandwidth; /* bandwidth, in kbits/s */
199
    /* RTSP options */
200
    char *rtsp_option;
201
    /* multicast specific */
202
    int is_multicast;
203
    struct in_addr multicast_ip;
204
    int multicast_port; /* first port used for multicast */
205
    int multicast_ttl;
206
    int loop; /* if true, send the stream in loops (only meaningful if file) */
207

    
208
    /* feed specific */
209
    int feed_opened;     /* true if someone is writing to the feed */
210
    int is_feed;         /* true if it is a feed */
211
    int readonly;        /* True if writing is prohibited to the file */
212
    int conns_served;
213
    int64_t bytes_served;
214
    int64_t feed_max_size;      /* maximum storage size */
215
    int64_t feed_write_index;   /* current write position in feed (it wraps round) */
216
    int64_t feed_size;          /* current size of feed */
217
    struct FFStream *next_feed;
218
} FFStream;
219

    
220
typedef struct FeedData {
221
    long long data_count;
222
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
223
} FeedData;
224

    
225
struct sockaddr_in my_http_addr;
226
struct sockaddr_in my_rtsp_addr;
227

    
228
char logfilename[1024];
229
HTTPContext *first_http_ctx;
230
FFStream *first_feed;   /* contains only feeds */
231
FFStream *first_stream; /* contains all streams, including feeds */
232

    
233
static void new_connection(int server_fd, int is_rtsp);
234
static void close_connection(HTTPContext *c);
235

    
236
/* HTTP handling */
237
static int handle_connection(HTTPContext *c);
238
static int http_parse_request(HTTPContext *c);
239
static int http_send_data(HTTPContext *c);
240
static void compute_stats(HTTPContext *c);
241
static int open_input_stream(HTTPContext *c, const char *info);
242
static int http_start_receive_data(HTTPContext *c);
243
static int http_receive_data(HTTPContext *c);
244
static int compute_send_delay(HTTPContext *c);
245

    
246
/* RTSP handling */
247
static int rtsp_parse_request(HTTPContext *c);
248
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
249
static void rtsp_cmd_options(HTTPContext *c, const char *url);
250
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
251
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
252
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
253
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
254

    
255
/* SDP handling */
256
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
257
                                   struct in_addr my_ip);
258

    
259
/* RTP handling */
260
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
261
                                       FFStream *stream, const char *session_id);
262
static int rtp_new_av_stream(HTTPContext *c, 
263
                             int stream_index, struct sockaddr_in *dest_addr);
264

    
265
static const char *my_program_name;
266
static const char *my_program_dir;
267

    
268
static int ffserver_debug;
269
static int ffserver_daemon;
270
static int no_launch;
271
static int need_to_start_children;
272

    
273
int nb_max_connections;
274
int nb_connections;
275

    
276
int max_bandwidth;
277
int current_bandwidth;
278

    
279
static long cur_time;           // Making this global saves on passing it around everywhere
280

    
281
static long gettime_ms(void)
282
{
283
    struct timeval tv;
284

    
285
    gettimeofday(&tv,NULL);
286
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
287
}
288

    
289
static FILE *logfile = NULL;
290

    
291
static void http_log(const char *fmt, ...)
292
{
293
    va_list ap;
294
    va_start(ap, fmt);
295
    
296
    if (logfile) {
297
        vfprintf(logfile, fmt, ap);
298
        fflush(logfile);
299
    }
300
    va_end(ap);
301
}
302

    
303
static char *ctime1(char *buf2)
304
{
305
    time_t ti;
306
    char *p;
307

    
308
    ti = time(NULL);
309
    p = ctime(&ti);
310
    strcpy(buf2, p);
311
    p = buf2 + strlen(p) - 1;
312
    if (*p == '\n')
313
        *p = '\0';
314
    return buf2;
315
}
316

    
317
static void log_connection(HTTPContext *c)
318
{
319
    char buf2[32];
320

    
321
    if (c->suppress_log) 
322
        return;
323

    
324
    http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
325
             inet_ntoa(c->from_addr.sin_addr), 
326
             ctime1(buf2), c->method, c->url, 
327
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
328
}
329

    
330
static void update_datarate(DataRateData *drd, int64_t count)
331
{
332
    if (!drd->time1 && !drd->count1) {
333
        drd->time1 = drd->time2 = cur_time;
334
        drd->count1 = drd->count2 = count;
335
    } else {
336
        if (cur_time - drd->time2 > 5000) {
337
            drd->time1 = drd->time2;
338
            drd->count1 = drd->count2;
339
            drd->time2 = cur_time;
340
            drd->count2 = count;
341
        }
342
    }
343
}
344

    
345
/* In bytes per second */
346
static int compute_datarate(DataRateData *drd, int64_t count)
347
{
348
    if (cur_time == drd->time1)
349
        return 0;
350
    
351
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
352
}
353

    
354
static int get_longterm_datarate(DataRateData *drd, int64_t count)
355
{
356
    /* You get the first 3 seconds flat out */
357
    if (cur_time - drd->time1 < 3000)
358
        return 0;
359
    return compute_datarate(drd, count);
360
}
361

    
362

    
363
static void start_children(FFStream *feed)
364
{
365
    if (no_launch)
366
        return;
367

    
368
    for (; feed; feed = feed->next) {
369
        if (feed->child_argv && !feed->pid) {
370
            feed->pid_start = time(0);
371

    
372
            feed->pid = fork();
373

    
374
            if (feed->pid < 0) {
375
                fprintf(stderr, "Unable to create children\n");
376
                exit(1);
377
            }
378
            if (!feed->pid) {
379
                /* In child */
380
                char pathname[1024];
381
                char *slash;
382
                int i;
383

    
384
                for (i = 3; i < 256; i++) {
385
                    close(i);
386
                }
387

    
388
                if (!ffserver_debug) {
389
                    i = open("/dev/null", O_RDWR);
390
                    if (i)
391
                        dup2(i, 0);
392
                    dup2(i, 1);
393
                    dup2(i, 2);
394
                    if (i)
395
                        close(i);
396
                }
397

    
398
                pstrcpy(pathname, sizeof(pathname), my_program_name);
399

    
400
                slash = strrchr(pathname, '/');
401
                if (!slash) {
402
                    slash = pathname;
403
                } else {
404
                    slash++;
405
                }
406
                strcpy(slash, "ffmpeg");
407

    
408
                /* This is needed to make relative pathnames work */
409
                chdir(my_program_dir);
410

    
411
                signal(SIGPIPE, SIG_DFL);
412

    
413
                execvp(pathname, feed->child_argv);
414

    
415
                _exit(1);
416
            }
417
        }
418
    }
419
}
420

    
421
/* open a listening socket */
422
static int socket_open_listen(struct sockaddr_in *my_addr)
423
{
424
    int server_fd, tmp;
425

    
426
    server_fd = socket(AF_INET,SOCK_STREAM,0);
427
    if (server_fd < 0) {
428
        perror ("socket");
429
        return -1;
430
    }
431
        
432
    tmp = 1;
433
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
434

    
435
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
436
        char bindmsg[32];
437
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
438
        perror (bindmsg);
439
        close(server_fd);
440
        return -1;
441
    }
442
  
443
    if (listen (server_fd, 5) < 0) {
444
        perror ("listen");
445
        close(server_fd);
446
        return -1;
447
    }
448
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
449

    
450
    return server_fd;
451
}
452

    
453
/* start all multicast streams */
454
static void start_multicast(void)
455
{
456
    FFStream *stream;
457
    char session_id[32];
458
    HTTPContext *rtp_c;
459
    struct sockaddr_in dest_addr;
460
    int default_port, stream_index;
461

    
462
    default_port = 6000;
463
    for(stream = first_stream; stream != NULL; stream = stream->next) {
464
        if (stream->is_multicast) {
465
            /* open the RTP connection */
466
            snprintf(session_id, sizeof(session_id), 
467
                     "%08x%08x", (int)random(), (int)random());
468

    
469
            /* choose a port if none given */
470
            if (stream->multicast_port == 0) {
471
                stream->multicast_port = default_port;
472
                default_port += 100;
473
            }
474

    
475
            dest_addr.sin_family = AF_INET;
476
            dest_addr.sin_addr = stream->multicast_ip;
477
            dest_addr.sin_port = htons(stream->multicast_port);
478

    
479
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id);
480
            if (!rtp_c) {
481
                continue;
482
            }
483
            if (open_input_stream(rtp_c, "") < 0) {
484
                fprintf(stderr, "Could not open input stream for stream '%s'\n", 
485
                        stream->filename);
486
                continue;
487
            }
488

    
489
            rtp_c->rtp_protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
490

    
491
            /* open each RTP stream */
492
            for(stream_index = 0; stream_index < stream->nb_streams; 
493
                stream_index++) {
494
                dest_addr.sin_port = htons(stream->multicast_port + 
495
                                           2 * stream_index);
496
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
497
                    fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n", 
498
                            stream->filename, stream_index);
499
                    exit(1);
500
                }
501
            }
502

    
503
            /* change state to send data */
504
            rtp_c->state = HTTPSTATE_SEND_DATA;
505
        }
506
    }
507
}
508

    
509
/* main loop of the http server */
510
static int http_server(void)
511
{
512
    int server_fd, ret, rtsp_server_fd, delay, delay1;
513
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
514
    HTTPContext *c, *c_next;
515

    
516
    server_fd = socket_open_listen(&my_http_addr);
517
    if (server_fd < 0)
518
        return -1;
519

    
520
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
521
    if (rtsp_server_fd < 0)
522
        return -1;
523
    
524
    http_log("ffserver started.\n");
525

    
526
    start_children(first_feed);
527

    
528
    first_http_ctx = NULL;
529
    nb_connections = 0;
530
    first_http_ctx = NULL;
531

    
532
    start_multicast();
533

    
534
    for(;;) {
535
        poll_entry = poll_table;
536
        poll_entry->fd = server_fd;
537
        poll_entry->events = POLLIN;
538
        poll_entry++;
539

    
540
        poll_entry->fd = rtsp_server_fd;
541
        poll_entry->events = POLLIN;
542
        poll_entry++;
543

    
544
        /* wait for events on each HTTP handle */
545
        c = first_http_ctx;
546
        delay = 1000;
547
        while (c != NULL) {
548
            int fd;
549
            fd = c->fd;
550
            switch(c->state) {
551
            case HTTPSTATE_SEND_HEADER:
552
            case RTSPSTATE_SEND_REPLY:
553
                c->poll_entry = poll_entry;
554
                poll_entry->fd = fd;
555
                poll_entry->events = POLLOUT;
556
                poll_entry++;
557
                break;
558
            case HTTPSTATE_SEND_DATA_HEADER:
559
            case HTTPSTATE_SEND_DATA:
560
            case HTTPSTATE_SEND_DATA_TRAILER:
561
                if (!c->is_packetized) {
562
                    /* for TCP, we output as much as we can (may need to put a limit) */
563
                    c->poll_entry = poll_entry;
564
                    poll_entry->fd = fd;
565
                    poll_entry->events = POLLOUT;
566
                    poll_entry++;
567
                } else {
568
                    /* not strictly correct, but currently cannot add
569
                       more than one fd in poll entry */
570
                    delay = 0;
571
                }
572
                break;
573
            case HTTPSTATE_WAIT_REQUEST:
574
            case HTTPSTATE_RECEIVE_DATA:
575
            case HTTPSTATE_WAIT_FEED:
576
            case RTSPSTATE_WAIT_REQUEST:
577
                /* need to catch errors */
578
                c->poll_entry = poll_entry;
579
                poll_entry->fd = fd;
580
                poll_entry->events = POLLIN;/* Maybe this will work */
581
                poll_entry++;
582
                break;
583
            case HTTPSTATE_WAIT:
584
                c->poll_entry = NULL;
585
                delay1 = compute_send_delay(c);
586
                if (delay1 < delay)
587
                    delay = delay1;
588
                break;
589
            case HTTPSTATE_WAIT_SHORT:
590
                c->poll_entry = NULL;
591
                delay1 = 10; /* one tick wait XXX: 10 ms assumed */
592
                if (delay1 < delay)
593
                    delay = delay1;
594
                break;
595
            default:
596
                c->poll_entry = NULL;
597
                break;
598
            }
599
            c = c->next;
600
        }
601

    
602
        /* wait for an event on one connection. We poll at least every
603
           second to handle timeouts */
604
        do {
605
            ret = poll(poll_table, poll_entry - poll_table, delay);
606
        } while (ret == -1);
607
        
608
        cur_time = gettime_ms();
609

    
610
        if (need_to_start_children) {
611
            need_to_start_children = 0;
612
            start_children(first_feed);
613
        }
614

    
615
        /* now handle the events */
616
        for(c = first_http_ctx; c != NULL; c = c_next) {
617
            c_next = c->next;
618
            if (handle_connection(c) < 0) {
619
                /* close and free the connection */
620
                log_connection(c);
621
                close_connection(c);
622
            }
623
        }
624

    
625
        poll_entry = poll_table;
626
        /* new HTTP connection request ? */
627
        if (poll_entry->revents & POLLIN) {
628
            new_connection(server_fd, 0);
629
        }
630
        poll_entry++;
631
        /* new RTSP connection request ? */
632
        if (poll_entry->revents & POLLIN) {
633
            new_connection(rtsp_server_fd, 1);
634
        }
635
    }
636
}
637

    
638
/* start waiting for a new HTTP/RTSP request */
639
static void start_wait_request(HTTPContext *c, int is_rtsp)
640
{
641
    c->buffer_ptr = c->buffer;
642
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
643

    
644
    if (is_rtsp) {
645
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
646
        c->state = RTSPSTATE_WAIT_REQUEST;
647
    } else {
648
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
649
        c->state = HTTPSTATE_WAIT_REQUEST;
650
    }
651
}
652

    
653
static void new_connection(int server_fd, int is_rtsp)
654
{
655
    struct sockaddr_in from_addr;
656
    int fd, len;
657
    HTTPContext *c = NULL;
658

    
659
    len = sizeof(from_addr);
660
    fd = accept(server_fd, (struct sockaddr *)&from_addr, 
661
                &len);
662
    if (fd < 0)
663
        return;
664
    fcntl(fd, F_SETFL, O_NONBLOCK);
665

    
666
    /* XXX: should output a warning page when coming
667
       close to the connection limit */
668
    if (nb_connections >= nb_max_connections)
669
        goto fail;
670
    
671
    /* add a new connection */
672
    c = av_mallocz(sizeof(HTTPContext));
673
    if (!c)
674
        goto fail;
675
    
676
    c->next = first_http_ctx;
677
    first_http_ctx = c;
678
    c->fd = fd;
679
    c->poll_entry = NULL;
680
    c->from_addr = from_addr;
681
    c->buffer_size = IOBUFFER_INIT_SIZE;
682
    c->buffer = av_malloc(c->buffer_size);
683
    if (!c->buffer)
684
        goto fail;
685
    nb_connections++;
686
    
687
    start_wait_request(c, is_rtsp);
688

    
689
    return;
690

    
691
 fail:
692
    if (c) {
693
        av_free(c->buffer);
694
        av_free(c);
695
    }
696
    close(fd);
697
}
698

    
699
static void close_connection(HTTPContext *c)
700
{
701
    HTTPContext **cp, *c1;
702
    int i, nb_streams;
703
    AVFormatContext *ctx;
704
    URLContext *h;
705
    AVStream *st;
706

    
707
    /* remove connection from list */
708
    cp = &first_http_ctx;
709
    while ((*cp) != NULL) {
710
        c1 = *cp;
711
        if (c1 == c) {
712
            *cp = c->next;
713
        } else {
714
            cp = &c1->next;
715
        }
716
    }
717

    
718
    /* remove connection associated resources */
719
    if (c->fd >= 0)
720
        close(c->fd);
721
    if (c->fmt_in) {
722
        /* close each frame parser */
723
        for(i=0;i<c->fmt_in->nb_streams;i++) {
724
            st = c->fmt_in->streams[i];
725
            if (st->codec.codec) {
726
                avcodec_close(&st->codec);
727
            }
728
        }
729
        av_close_input_file(c->fmt_in);
730
    }
731

    
732
    /* free RTP output streams if any */
733
    nb_streams = 0;
734
    if (c->stream) 
735
        nb_streams = c->stream->nb_streams;
736
    
737
    for(i=0;i<nb_streams;i++) {
738
        ctx = c->rtp_ctx[i];
739
        if (ctx) {
740
            av_write_trailer(ctx);
741
            av_free(ctx);
742
        }
743
        h = c->rtp_handles[i];
744
        if (h) {
745
            url_close(h);
746
        }
747
    }
748

    
749
    ctx = &c->fmt_ctx;
750

    
751
    if (!c->last_packet_sent) {
752
        if (ctx->oformat) {
753
            /* prepare header */
754
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
755
                av_write_trailer(ctx);
756
                (void) url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
757
            }
758
        }
759
    }
760

    
761
    for(i=0; i<ctx->nb_streams; i++) 
762
        av_free(ctx->streams[i]) ; 
763

    
764
    if (c->stream)
765
        current_bandwidth -= c->stream->bandwidth;
766
    av_freep(&c->pb_buffer);
767
    av_free(c->buffer);
768
    av_free(c);
769
    nb_connections--;
770
}
771

    
772
static int handle_connection(HTTPContext *c)
773
{
774
    int len, ret;
775
    
776
    switch(c->state) {
777
    case HTTPSTATE_WAIT_REQUEST:
778
    case RTSPSTATE_WAIT_REQUEST:
779
        /* timeout ? */
780
        if ((c->timeout - cur_time) < 0)
781
            return -1;
782
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
783
            return -1;
784

    
785
        /* no need to read if no events */
786
        if (!(c->poll_entry->revents & POLLIN))
787
            return 0;
788
        /* read the data */
789
        len = read(c->fd, c->buffer_ptr, 1);
790
        if (len < 0) {
791
            if (errno != EAGAIN && errno != EINTR)
792
                return -1;
793
        } else if (len == 0) {
794
            return -1;
795
        } else {
796
            /* search for end of request. */
797
            uint8_t *ptr;
798
            c->buffer_ptr += len;
799
            ptr = c->buffer_ptr;
800
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
801
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
802
                /* request found : parse it and reply */
803
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
804
                    ret = http_parse_request(c);
805
                } else {
806
                    ret = rtsp_parse_request(c);
807
                }
808
                if (ret < 0)
809
                    return -1;
810
            } else if (ptr >= c->buffer_end) {
811
                /* request too long: cannot do anything */
812
                return -1;
813
            }
814
        }
815
        break;
816

    
817
    case HTTPSTATE_SEND_HEADER:
818
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
819
            return -1;
820

    
821
        /* no need to write if no events */
822
        if (!(c->poll_entry->revents & POLLOUT))
823
            return 0;
824
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
825
        if (len < 0) {
826
            if (errno != EAGAIN && errno != EINTR) {
827
                /* error : close connection */
828
                av_freep(&c->pb_buffer);
829
                return -1;
830
            }
831
        } else {
832
            c->buffer_ptr += len;
833
            if (c->stream)
834
                c->stream->bytes_served += len;
835
            c->data_count += len;
836
            if (c->buffer_ptr >= c->buffer_end) {
837
                av_freep(&c->pb_buffer);
838
                /* if error, exit */
839
                if (c->http_error) {
840
                    return -1;
841
                }
842
                /* all the buffer was sent : synchronize to the incoming stream */
843
                c->state = HTTPSTATE_SEND_DATA_HEADER;
844
                c->buffer_ptr = c->buffer_end = c->buffer;
845
            }
846
        }
847
        break;
848

    
849
    case HTTPSTATE_SEND_DATA:
850
    case HTTPSTATE_SEND_DATA_HEADER:
851
    case HTTPSTATE_SEND_DATA_TRAILER:
852
        /* for packetized output, we consider we can always write (the
853
           input streams sets the speed). It may be better to verify
854
           that we do not rely too much on the kernel queues */
855
        if (!c->is_packetized) {
856
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
857
                return -1;
858
            
859
            /* no need to read if no events */
860
            if (!(c->poll_entry->revents & POLLOUT))
861
                return 0;
862
        }
863
        if (http_send_data(c) < 0)
864
            return -1;
865
        break;
866
    case HTTPSTATE_RECEIVE_DATA:
867
        /* no need to read if no events */
868
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
869
            return -1;
870
        if (!(c->poll_entry->revents & POLLIN))
871
            return 0;
872
        if (http_receive_data(c) < 0)
873
            return -1;
874
        break;
875
    case HTTPSTATE_WAIT_FEED:
876
        /* no need to read if no events */
877
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
878
            return -1;
879

    
880
        /* nothing to do, we'll be waken up by incoming feed packets */
881
        break;
882

    
883
    case HTTPSTATE_WAIT:
884
        /* if the delay expired, we can send new packets */
885
        if (compute_send_delay(c) <= 0)
886
            c->state = HTTPSTATE_SEND_DATA;
887
        break;
888
    case HTTPSTATE_WAIT_SHORT:
889
        /* just return back to send data */
890
        c->state = HTTPSTATE_SEND_DATA;
891
        break;
892

    
893
    case RTSPSTATE_SEND_REPLY:
894
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
895
            av_freep(&c->pb_buffer);
896
            return -1;
897
        }
898
        /* no need to write if no events */
899
        if (!(c->poll_entry->revents & POLLOUT))
900
            return 0;
901
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
902
        if (len < 0) {
903
            if (errno != EAGAIN && errno != EINTR) {
904
                /* error : close connection */
905
                av_freep(&c->pb_buffer);
906
                return -1;
907
            }
908
        } else {
909
            c->buffer_ptr += len;
910
            c->data_count += len;
911
            if (c->buffer_ptr >= c->buffer_end) {
912
                /* all the buffer was sent : wait for a new request */
913
                av_freep(&c->pb_buffer);
914
                start_wait_request(c, 1);
915
            }
916
        }
917
        break;
918
    case HTTPSTATE_READY:
919
        /* nothing to do */
920
        break;
921
    default:
922
        return -1;
923
    }
924
    return 0;
925
}
926

    
927
static int extract_rates(char *rates, int ratelen, const char *request)
928
{
929
    const char *p;
930

    
931
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
932
        if (strncasecmp(p, "Pragma:", 7) == 0) {
933
            const char *q = p + 7;
934

    
935
            while (*q && *q != '\n' && isspace(*q))
936
                q++;
937

    
938
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
939
                int stream_no;
940
                int rate_no;
941

    
942
                q += 20;
943

    
944
                memset(rates, 0xff, ratelen);
945

    
946
                while (1) {
947
                    while (*q && *q != '\n' && *q != ':')
948
                        q++;
949

    
950
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
951
                        break;
952
                    }
953
                    stream_no--;
954
                    if (stream_no < ratelen && stream_no >= 0) {
955
                        rates[stream_no] = rate_no;
956
                    }
957

    
958
                    while (*q && *q != '\n' && !isspace(*q))
959
                        q++;
960
                }
961

    
962
                return 1;
963
            }
964
        }
965
        p = strchr(p, '\n');
966
        if (!p)
967
            break;
968

    
969
        p++;
970
    }
971

    
972
    return 0;
973
}
974

    
975
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
976
{
977
    int i;
978
    int best_bitrate = 100000000;
979
    int best = -1;
980

    
981
    for (i = 0; i < feed->nb_streams; i++) {
982
        AVCodecContext *feed_codec = &feed->streams[i]->codec;
983

    
984
        if (feed_codec->codec_id != codec->codec_id ||
985
            feed_codec->sample_rate != codec->sample_rate ||
986
            feed_codec->width != codec->width ||
987
            feed_codec->height != codec->height) {
988
            continue;
989
        }
990

    
991
        /* Potential stream */
992

    
993
        /* We want the fastest stream less than bit_rate, or the slowest 
994
         * faster than bit_rate
995
         */
996

    
997
        if (feed_codec->bit_rate <= bit_rate) {
998
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
999
                best_bitrate = feed_codec->bit_rate;
1000
                best = i;
1001
            }
1002
        } else {
1003
            if (feed_codec->bit_rate < best_bitrate) {
1004
                best_bitrate = feed_codec->bit_rate;
1005
                best = i;
1006
            }
1007
        }
1008
    }
1009

    
1010
    return best;
1011
}
1012

    
1013
static int modify_current_stream(HTTPContext *c, char *rates)
1014
{
1015
    int i;
1016
    FFStream *req = c->stream;
1017
    int action_required = 0;
1018

    
1019
    /* Not much we can do for a feed */
1020
    if (!req->feed)
1021
        return 0;
1022

    
1023
    for (i = 0; i < req->nb_streams; i++) {
1024
        AVCodecContext *codec = &req->streams[i]->codec;
1025

    
1026
        switch(rates[i]) {
1027
            case 0:
1028
                c->switch_feed_streams[i] = req->feed_streams[i];
1029
                break;
1030
            case 1:
1031
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1032
                break;
1033
            case 2:
1034
                /* Wants off or slow */
1035
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1036
#ifdef WANTS_OFF
1037
                /* This doesn't work well when it turns off the only stream! */
1038
                c->switch_feed_streams[i] = -2;
1039
                c->feed_streams[i] = -2;
1040
#endif
1041
                break;
1042
        }
1043

    
1044
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1045
            action_required = 1;
1046
    }
1047

    
1048
    return action_required;
1049
}
1050

    
1051

    
1052
static void do_switch_stream(HTTPContext *c, int i)
1053
{
1054
    if (c->switch_feed_streams[i] >= 0) {
1055
#ifdef PHILIP        
1056
        c->feed_streams[i] = c->switch_feed_streams[i];
1057
#endif
1058

    
1059
        /* Now update the stream */
1060
    }
1061
    c->switch_feed_streams[i] = -1;
1062
}
1063

    
1064
/* XXX: factorize in utils.c ? */
1065
/* XXX: take care with different space meaning */
1066
static void skip_spaces(const char **pp)
1067
{
1068
    const char *p;
1069
    p = *pp;
1070
    while (*p == ' ' || *p == '\t')
1071
        p++;
1072
    *pp = p;
1073
}
1074

    
1075
static void get_word(char *buf, int buf_size, const char **pp)
1076
{
1077
    const char *p;
1078
    char *q;
1079

    
1080
    p = *pp;
1081
    skip_spaces(&p);
1082
    q = buf;
1083
    while (!isspace(*p) && *p != '\0') {
1084
        if ((q - buf) < buf_size - 1)
1085
            *q++ = *p;
1086
        p++;
1087
    }
1088
    if (buf_size > 0)
1089
        *q = '\0';
1090
    *pp = p;
1091
}
1092

    
1093
static int validate_acl(FFStream *stream, HTTPContext *c)
1094
{
1095
    enum IPAddressAction last_action = IP_DENY;
1096
    IPAddressACL *acl;
1097
    struct in_addr *src = &c->from_addr.sin_addr;
1098
    unsigned long src_addr = ntohl(src->s_addr);
1099

    
1100
    for (acl = stream->acl; acl; acl = acl->next) {
1101
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
1102
            return (acl->action == IP_ALLOW) ? 1 : 0;
1103
        }
1104
        last_action = acl->action;
1105
    }
1106

    
1107
    /* Nothing matched, so return not the last action */
1108
    return (last_action == IP_DENY) ? 1 : 0;
1109
}
1110

    
1111
/* compute the real filename of a file by matching it without its
1112
   extensions to all the stream filenames */
1113
static void compute_real_filename(char *filename, int max_size)
1114
{
1115
    char file1[1024];
1116
    char file2[1024];
1117
    char *p;
1118
    FFStream *stream;
1119

    
1120
    /* compute filename by matching without the file extensions */
1121
    pstrcpy(file1, sizeof(file1), filename);
1122
    p = strrchr(file1, '.');
1123
    if (p)
1124
        *p = '\0';
1125
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1126
        pstrcpy(file2, sizeof(file2), stream->filename);
1127
        p = strrchr(file2, '.');
1128
        if (p)
1129
            *p = '\0';
1130
        if (!strcmp(file1, file2)) {
1131
            pstrcpy(filename, max_size, stream->filename);
1132
            break;
1133
        }
1134
    }
1135
}
1136

    
1137
enum RedirType {
1138
    REDIR_NONE,
1139
    REDIR_ASX,
1140
    REDIR_RAM,
1141
    REDIR_ASF,
1142
    REDIR_RTSP,
1143
    REDIR_SDP,
1144
};
1145

    
1146
/* parse http request and prepare header */
1147
static int http_parse_request(HTTPContext *c)
1148
{
1149
    char *p;
1150
    int post;
1151
    enum RedirType redir_type;
1152
    char cmd[32];
1153
    char info[1024], *filename;
1154
    char url[1024], *q;
1155
    char protocol[32];
1156
    char msg[1024];
1157
    const char *mime_type;
1158
    FFStream *stream;
1159
    int i;
1160
    char ratebuf[32];
1161
    char *useragent = 0;
1162

    
1163
    p = c->buffer;
1164
    get_word(cmd, sizeof(cmd), (const char **)&p);
1165
    pstrcpy(c->method, sizeof(c->method), cmd);
1166

    
1167
    if (!strcmp(cmd, "GET"))
1168
        post = 0;
1169
    else if (!strcmp(cmd, "POST"))
1170
        post = 1;
1171
    else
1172
        return -1;
1173

    
1174
    get_word(url, sizeof(url), (const char **)&p);
1175
    pstrcpy(c->url, sizeof(c->url), url);
1176

    
1177
    get_word(protocol, sizeof(protocol), (const char **)&p);
1178
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1179
        return -1;
1180

    
1181
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1182
    
1183
    /* find the filename and the optional info string in the request */
1184
    p = url;
1185
    if (*p == '/')
1186
        p++;
1187
    filename = p;
1188
    p = strchr(p, '?');
1189
    if (p) {
1190
        pstrcpy(info, sizeof(info), p);
1191
        *p = '\0';
1192
    } else {
1193
        info[0] = '\0';
1194
    }
1195

    
1196
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1197
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1198
            useragent = p + 11;
1199
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1200
                useragent++;
1201
            break;
1202
        }
1203
        p = strchr(p, '\n');
1204
        if (!p)
1205
            break;
1206

    
1207
        p++;
1208
    }
1209

    
1210
    redir_type = REDIR_NONE;
1211
    if (match_ext(filename, "asx")) {
1212
        redir_type = REDIR_ASX;
1213
        filename[strlen(filename)-1] = 'f';
1214
    } else if (match_ext(filename, "asf") &&
1215
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1216
        /* if this isn't WMP or lookalike, return the redirector file */
1217
        redir_type = REDIR_ASF;
1218
    } else if (match_ext(filename, "rpm,ram")) {
1219
        redir_type = REDIR_RAM;
1220
        strcpy(filename + strlen(filename)-2, "m");
1221
    } else if (match_ext(filename, "rtsp")) {
1222
        redir_type = REDIR_RTSP;
1223
        compute_real_filename(filename, sizeof(url) - 1);
1224
    } else if (match_ext(filename, "sdp")) {
1225
        redir_type = REDIR_SDP;
1226
        compute_real_filename(filename, sizeof(url) - 1);
1227
    }
1228
    
1229
    stream = first_stream;
1230
    while (stream != NULL) {
1231
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1232
            break;
1233
        stream = stream->next;
1234
    }
1235
    if (stream == NULL) {
1236
        sprintf(msg, "File '%s' not found", url);
1237
        goto send_error;
1238
    }
1239

    
1240
    c->stream = stream;
1241
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1242
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1243

    
1244
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1245
        c->http_error = 301;
1246
        q = c->buffer;
1247
        q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
1248
        q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
1249
        q += sprintf(q, "Content-type: text/html\r\n");
1250
        q += sprintf(q, "\r\n");
1251
        q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
1252
        q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1253
        q += sprintf(q, "</body></html>\r\n");
1254

    
1255
        /* prepare output buffer */
1256
        c->buffer_ptr = c->buffer;
1257
        c->buffer_end = q;
1258
        c->state = HTTPSTATE_SEND_HEADER;
1259
        return 0;
1260
    }
1261

    
1262
    /* If this is WMP, get the rate information */
1263
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1264
        if (modify_current_stream(c, ratebuf)) {
1265
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1266
                if (c->switch_feed_streams[i] >= 0)
1267
                    do_switch_stream(c, i);
1268
            }
1269
        }
1270
    }
1271

    
1272
    if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1273
        current_bandwidth += stream->bandwidth;
1274
    }
1275
    
1276
    if (post == 0 && max_bandwidth < current_bandwidth) {
1277
        c->http_error = 200;
1278
        q = c->buffer;
1279
        q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
1280
        q += sprintf(q, "Content-type: text/html\r\n");
1281
        q += sprintf(q, "\r\n");
1282
        q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
1283
        q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
1284
        q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
1285
            current_bandwidth, max_bandwidth);
1286
        q += sprintf(q, "</body></html>\r\n");
1287

    
1288
        /* prepare output buffer */
1289
        c->buffer_ptr = c->buffer;
1290
        c->buffer_end = q;
1291
        c->state = HTTPSTATE_SEND_HEADER;
1292
        return 0;
1293
    }
1294
    
1295
    if (redir_type != REDIR_NONE) {
1296
        char *hostinfo = 0;
1297
        
1298
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1299
            if (strncasecmp(p, "Host:", 5) == 0) {
1300
                hostinfo = p + 5;
1301
                break;
1302
            }
1303
            p = strchr(p, '\n');
1304
            if (!p)
1305
                break;
1306

    
1307
            p++;
1308
        }
1309

    
1310
        if (hostinfo) {
1311
            char *eoh;
1312
            char hostbuf[260];
1313

    
1314
            while (isspace(*hostinfo))
1315
                hostinfo++;
1316

    
1317
            eoh = strchr(hostinfo, '\n');
1318
            if (eoh) {
1319
                if (eoh[-1] == '\r')
1320
                    eoh--;
1321

    
1322
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1323
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1324
                    hostbuf[eoh - hostinfo] = 0;
1325

    
1326
                    c->http_error = 200;
1327
                    q = c->buffer;
1328
                    switch(redir_type) {
1329
                    case REDIR_ASX:
1330
                        q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
1331
                        q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1332
                        q += sprintf(q, "\r\n");
1333
                        q += sprintf(q, "<ASX Version=\"3\">\r\n");
1334
                        q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
1335
                        q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", 
1336
                                hostbuf, filename, info);
1337
                        q += sprintf(q, "</ASX>\r\n");
1338
                        break;
1339
                    case REDIR_RAM:
1340
                        q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
1341
                        q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
1342
                        q += sprintf(q, "\r\n");
1343
                        q += sprintf(q, "# Autogenerated by ffserver\r\n");
1344
                        q += sprintf(q, "http://%s/%s%s\r\n", 
1345
                                hostbuf, filename, info);
1346
                        break;
1347
                    case REDIR_ASF:
1348
                        q += sprintf(q, "HTTP/1.0 200 ASF Redirect follows\r\n");
1349
                        q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1350
                        q += sprintf(q, "\r\n");
1351
                        q += sprintf(q, "[Reference]\r\n");
1352
                        q += sprintf(q, "Ref1=http://%s/%s%s\r\n", 
1353
                                hostbuf, filename, info);
1354
                        break;
1355
                    case REDIR_RTSP:
1356
                        {
1357
                            char hostname[256], *p;
1358
                            /* extract only hostname */
1359
                            pstrcpy(hostname, sizeof(hostname), hostbuf);
1360
                            p = strrchr(hostname, ':');
1361
                            if (p)
1362
                                *p = '\0';
1363
                            q += sprintf(q, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1364
                            /* XXX: incorrect mime type ? */
1365
                            q += sprintf(q, "Content-type: application/x-rtsp\r\n");
1366
                            q += sprintf(q, "\r\n");
1367
                            q += sprintf(q, "rtsp://%s:%d/%s\r\n", 
1368
                                         hostname, ntohs(my_rtsp_addr.sin_port), 
1369
                                         filename);
1370
                        }
1371
                        break;
1372
                    case REDIR_SDP:
1373
                        {
1374
                            uint8_t *sdp_data;
1375
                            int sdp_data_size, len;
1376
                            struct sockaddr_in my_addr;
1377

    
1378
                            q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1379
                            q += sprintf(q, "Content-type: application/sdp\r\n");
1380
                            q += sprintf(q, "\r\n");
1381

    
1382
                            len = sizeof(my_addr);
1383
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1384
                            
1385
                            /* XXX: should use a dynamic buffer */
1386
                            sdp_data_size = prepare_sdp_description(stream, 
1387
                                                                    &sdp_data, 
1388
                                                                    my_addr.sin_addr);
1389
                            if (sdp_data_size > 0) {
1390
                                memcpy(q, sdp_data, sdp_data_size);
1391
                                q += sdp_data_size;
1392
                                *q = '\0';
1393
                                av_free(sdp_data);
1394
                            }
1395
                        }
1396
                        break;
1397
                    default:
1398
                        av_abort();
1399
                        break;
1400
                    }
1401

    
1402
                    /* prepare output buffer */
1403
                    c->buffer_ptr = c->buffer;
1404
                    c->buffer_end = q;
1405
                    c->state = HTTPSTATE_SEND_HEADER;
1406
                    return 0;
1407
                }
1408
            }
1409
        }
1410

    
1411
        sprintf(msg, "ASX/RAM file not handled");
1412
        goto send_error;
1413
    }
1414

    
1415
    stream->conns_served++;
1416

    
1417
    /* XXX: add there authenticate and IP match */
1418

    
1419
    if (post) {
1420
        /* if post, it means a feed is being sent */
1421
        if (!stream->is_feed) {
1422
            /* However it might be a status report from WMP! Lets log the data
1423
             * as it might come in handy one day
1424
             */
1425
            char *logline = 0;
1426
            int client_id = 0;
1427
            
1428
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1429
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1430
                    logline = p;
1431
                    break;
1432
                }
1433
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1434
                    client_id = strtol(p + 18, 0, 10);
1435
                }
1436
                p = strchr(p, '\n');
1437
                if (!p)
1438
                    break;
1439

    
1440
                p++;
1441
            }
1442

    
1443
            if (logline) {
1444
                char *eol = strchr(logline, '\n');
1445

    
1446
                logline += 17;
1447

    
1448
                if (eol) {
1449
                    if (eol[-1] == '\r')
1450
                        eol--;
1451
                    http_log("%.*s\n", eol - logline, logline);
1452
                    c->suppress_log = 1;
1453
                }
1454
            }
1455

    
1456
#ifdef DEBUG_WMP
1457
            http_log("\nGot request:\n%s\n", c->buffer);
1458
#endif
1459

    
1460
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1461
                HTTPContext *wmpc;
1462

    
1463
                /* Now we have to find the client_id */
1464
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1465
                    if (wmpc->wmp_client_id == client_id)
1466
                        break;
1467
                }
1468

    
1469
                if (wmpc) {
1470
                    if (modify_current_stream(wmpc, ratebuf)) {
1471
                        wmpc->switch_pending = 1;
1472
                    }
1473
                }
1474
            }
1475
            
1476
            sprintf(msg, "POST command not handled");
1477
            c->stream = 0;
1478
            goto send_error;
1479
        }
1480
        if (http_start_receive_data(c) < 0) {
1481
            sprintf(msg, "could not open feed");
1482
            goto send_error;
1483
        }
1484
        c->http_error = 0;
1485
        c->state = HTTPSTATE_RECEIVE_DATA;
1486
        return 0;
1487
    }
1488

    
1489
#ifdef DEBUG_WMP
1490
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1491
        http_log("\nGot request:\n%s\n", c->buffer);
1492
    }
1493
#endif
1494

    
1495
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1496
        goto send_stats;
1497

    
1498
    /* open input stream */
1499
    if (open_input_stream(c, info) < 0) {
1500
        sprintf(msg, "Input stream corresponding to '%s' not found", url);
1501
        goto send_error;
1502
    }
1503

    
1504
    /* prepare http header */
1505
    q = c->buffer;
1506
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1507
    mime_type = c->stream->fmt->mime_type;
1508
    if (!mime_type)
1509
        mime_type = "application/x-octet_stream";
1510
    q += sprintf(q, "Pragma: no-cache\r\n");
1511

    
1512
    /* for asf, we need extra headers */
1513
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1514
        /* Need to allocate a client id */
1515

    
1516
        c->wmp_client_id = random() & 0x7fffffff;
1517

    
1518
        q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1519
    }
1520
    q += sprintf(q, "Content-Type: %s\r\n", mime_type);
1521
    q += sprintf(q, "\r\n");
1522
    
1523
    /* prepare output buffer */
1524
    c->http_error = 0;
1525
    c->buffer_ptr = c->buffer;
1526
    c->buffer_end = q;
1527
    c->state = HTTPSTATE_SEND_HEADER;
1528
    return 0;
1529
 send_error:
1530
    c->http_error = 404;
1531
    q = c->buffer;
1532
    q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
1533
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
1534
    q += sprintf(q, "\r\n");
1535
    q += sprintf(q, "<HTML>\n");
1536
    q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1537
    q += sprintf(q, "<BODY>%s</BODY>\n", msg);
1538
    q += sprintf(q, "</HTML>\n");
1539

    
1540
    /* prepare output buffer */
1541
    c->buffer_ptr = c->buffer;
1542
    c->buffer_end = q;
1543
    c->state = HTTPSTATE_SEND_HEADER;
1544
    return 0;
1545
 send_stats:
1546
    compute_stats(c);
1547
    c->http_error = 200; /* horrible : we use this value to avoid
1548
                            going to the send data state */
1549
    c->state = HTTPSTATE_SEND_HEADER;
1550
    return 0;
1551
}
1552

    
1553
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1554
{
1555
    static const char *suffix = " kMGTP";
1556
    const char *s;
1557

    
1558
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1559
    }
1560

    
1561
    url_fprintf(pb, "%lld%c", count, *s);
1562
}
1563

    
1564
static void compute_stats(HTTPContext *c)
1565
{
1566
    HTTPContext *c1;
1567
    FFStream *stream;
1568
    char *p;
1569
    time_t ti;
1570
    int i, len;
1571
    ByteIOContext pb1, *pb = &pb1;
1572

    
1573
    if (url_open_dyn_buf(pb) < 0) {
1574
        /* XXX: return an error ? */
1575
        c->buffer_ptr = c->buffer;
1576
        c->buffer_end = c->buffer;
1577
        return;
1578
    }
1579

    
1580
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1581
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1582
    url_fprintf(pb, "Pragma: no-cache\r\n");
1583
    url_fprintf(pb, "\r\n");
1584
    
1585
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1586
    if (c->stream->feed_filename) {
1587
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1588
    }
1589
    url_fprintf(pb, "</HEAD>\n<BODY>");
1590
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1591
    /* format status */
1592
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1593
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1594
    url_fprintf(pb, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>bytes<Th valign=top>Format<Th>Bit rate<br>kbits/s<Th align=left>Video<br>kbits/s<th><br>Codec<Th align=left>Audio<br>kbits/s<th><br>Codec<Th align=left valign=top>Feed\n");
1595
    stream = first_stream;
1596
    while (stream != NULL) {
1597
        char sfilename[1024];
1598
        char *eosf;
1599

    
1600
        if (stream->feed != stream) {
1601
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1602
            eosf = sfilename + strlen(sfilename);
1603
            if (eosf - sfilename >= 4) {
1604
                if (strcmp(eosf - 4, ".asf") == 0) {
1605
                    strcpy(eosf - 4, ".asx");
1606
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1607
                    strcpy(eosf - 3, ".ram");
1608
                } else if (stream->fmt == &rtp_mux) {
1609
                    /* generate a sample RTSP director if
1610
                       unicast. Generate an SDP redirector if
1611
                       multicast */
1612
                    eosf = strrchr(sfilename, '.');
1613
                    if (!eosf)
1614
                        eosf = sfilename + strlen(sfilename);
1615
                    if (stream->is_multicast)
1616
                        strcpy(eosf, ".sdp");
1617
                    else
1618
                        strcpy(eosf, ".rtsp");
1619
                }
1620
            }
1621
            
1622
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
1623
                         sfilename, stream->filename);
1624
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1625
                        stream->conns_served);
1626
            fmt_bytecount(pb, stream->bytes_served);
1627
            switch(stream->stream_type) {
1628
            case STREAM_TYPE_LIVE:
1629
                {
1630
                    int audio_bit_rate = 0;
1631
                    int video_bit_rate = 0;
1632
                    const char *audio_codec_name = "";
1633
                    const char *video_codec_name = "";
1634
                    const char *audio_codec_name_extra = "";
1635
                    const char *video_codec_name_extra = "";
1636

    
1637
                    for(i=0;i<stream->nb_streams;i++) {
1638
                        AVStream *st = stream->streams[i];
1639
                        AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1640
                        switch(st->codec.codec_type) {
1641
                        case CODEC_TYPE_AUDIO:
1642
                            audio_bit_rate += st->codec.bit_rate;
1643
                            if (codec) {
1644
                                if (*audio_codec_name)
1645
                                    audio_codec_name_extra = "...";
1646
                                audio_codec_name = codec->name;
1647
                            }
1648
                            break;
1649
                        case CODEC_TYPE_VIDEO:
1650
                            video_bit_rate += st->codec.bit_rate;
1651
                            if (codec) {
1652
                                if (*video_codec_name)
1653
                                    video_codec_name_extra = "...";
1654
                                video_codec_name = codec->name;
1655
                            }
1656
                            break;
1657
                        default:
1658
                            av_abort();
1659
                        }
1660
                    }
1661
                    url_fprintf(pb, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s", 
1662
                                 stream->fmt->name,
1663
                                 stream->bandwidth,
1664
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1665
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1666
                    if (stream->feed) {
1667
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1668
                    } else {
1669
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1670
                    }
1671
                    url_fprintf(pb, "\n");
1672
                }
1673
                break;
1674
            default:
1675
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1676
                break;
1677
            }
1678
        }
1679
        stream = stream->next;
1680
    }
1681
    url_fprintf(pb, "</TABLE>\n");
1682

    
1683
    stream = first_stream;
1684
    while (stream != NULL) {
1685
        if (stream->feed == stream) {
1686
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1687
            if (stream->pid) {
1688
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1689

    
1690
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1691
                {
1692
                    FILE *pid_stat;
1693
                    char ps_cmd[64];
1694

    
1695
                    /* This is somewhat linux specific I guess */
1696
                    snprintf(ps_cmd, sizeof(ps_cmd), 
1697
                             "ps -o \"%%cpu,cputime\" --no-headers %d", 
1698
                             stream->pid);
1699
                    
1700
                    pid_stat = popen(ps_cmd, "r");
1701
                    if (pid_stat) {
1702
                        char cpuperc[10];
1703
                        char cpuused[64];
1704
                        
1705
                        if (fscanf(pid_stat, "%10s %64s", cpuperc, 
1706
                                   cpuused) == 2) {
1707
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1708
                                         cpuperc, cpuused);
1709
                        }
1710
                        fclose(pid_stat);
1711
                    }
1712
                }
1713
#endif
1714

    
1715
                url_fprintf(pb, "<p>");
1716
            }
1717
            url_fprintf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1718

    
1719
            for (i = 0; i < stream->nb_streams; i++) {
1720
                AVStream *st = stream->streams[i];
1721
                AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1722
                const char *type = "unknown";
1723
                char parameters[64];
1724

    
1725
                parameters[0] = 0;
1726

    
1727
                switch(st->codec.codec_type) {
1728
                case CODEC_TYPE_AUDIO:
1729
                    type = "audio";
1730
                    break;
1731
                case CODEC_TYPE_VIDEO:
1732
                    type = "video";
1733
                    sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
1734
                                st->codec.qmin, st->codec.qmax, st->codec.frame_rate / st->codec.frame_rate_base);
1735
                    break;
1736
                default:
1737
                    av_abort();
1738
                }
1739
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1740
                        i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
1741
            }
1742
            url_fprintf(pb, "</table>\n");
1743

    
1744
        }       
1745
        stream = stream->next;
1746
    }
1747
    
1748
#if 0
1749
    {
1750
        float avg;
1751
        AVCodecContext *enc;
1752
        char buf[1024];
1753
        
1754
        /* feed status */
1755
        stream = first_feed;
1756
        while (stream != NULL) {
1757
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1758
            url_fprintf(pb, "<TABLE>\n");
1759
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1760
            for(i=0;i<stream->nb_streams;i++) {
1761
                AVStream *st = stream->streams[i];
1762
                FeedData *fdata = st->priv_data;
1763
                enc = &st->codec;
1764
            
1765
                avcodec_string(buf, sizeof(buf), enc);
1766
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1767
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1768
                    avg /= enc->frame_size;
1769
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
1770
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1771
            }
1772
            url_fprintf(pb, "</TABLE>\n");
1773
            stream = stream->next_feed;
1774
        }
1775
    }
1776
#endif
1777

    
1778
    /* connection status */
1779
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1780

    
1781
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1782
                 nb_connections, nb_max_connections);
1783

    
1784
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1785
                 current_bandwidth, max_bandwidth);
1786

    
1787
    url_fprintf(pb, "<TABLE>\n");
1788
    url_fprintf(pb, "<TR><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1789
    c1 = first_http_ctx;
1790
    i = 0;
1791
    while (c1 != NULL) {
1792
        int bitrate;
1793
        int j;
1794

    
1795
        bitrate = 0;
1796
        if (c1->stream) {
1797
            for (j = 0; j < c1->stream->nb_streams; j++) {
1798
                if (!c1->stream->feed) {
1799
                    bitrate += c1->stream->streams[j]->codec.bit_rate;
1800
                } else {
1801
                    if (c1->feed_streams[j] >= 0) {
1802
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec.bit_rate;
1803
                    }
1804
                }
1805
            }
1806
        }
1807

    
1808
        i++;
1809
        p = inet_ntoa(c1->from_addr.sin_addr);
1810
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>", 
1811
                    i, 
1812
                    c1->stream ? c1->stream->filename : "", 
1813
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1814
                    p, 
1815
                    c1->protocol,
1816
                    http_state[c1->state]);
1817
        fmt_bytecount(pb, bitrate);
1818
        url_fprintf(pb, "<td align=right>");
1819
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1820
        url_fprintf(pb, "<td align=right>");
1821
        fmt_bytecount(pb, c1->data_count);
1822
        url_fprintf(pb, "\n");
1823
        c1 = c1->next;
1824
    }
1825
    url_fprintf(pb, "</TABLE>\n");
1826
    
1827
    /* date */
1828
    ti = time(NULL);
1829
    p = ctime(&ti);
1830
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1831
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1832

    
1833
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1834
    c->buffer_ptr = c->pb_buffer;
1835
    c->buffer_end = c->pb_buffer + len;
1836
}
1837

    
1838
/* check if the parser needs to be opened for stream i */
1839
static void open_parser(AVFormatContext *s, int i)
1840
{
1841
    AVStream *st = s->streams[i];
1842
    AVCodec *codec;
1843

    
1844
    if (!st->codec.codec) {
1845
        codec = avcodec_find_decoder(st->codec.codec_id);
1846
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1847
            st->codec.parse_only = 1;
1848
            if (avcodec_open(&st->codec, codec) < 0) {
1849
                st->codec.parse_only = 0;
1850
            }
1851
        }
1852
    }
1853
}
1854

    
1855
static int open_input_stream(HTTPContext *c, const char *info)
1856
{
1857
    char buf[128];
1858
    char input_filename[1024];
1859
    AVFormatContext *s;
1860
    int buf_size, i;
1861
    int64_t stream_pos;
1862

    
1863
    /* find file name */
1864
    if (c->stream->feed) {
1865
        strcpy(input_filename, c->stream->feed->feed_filename);
1866
        buf_size = FFM_PACKET_SIZE;
1867
        /* compute position (absolute time) */
1868
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1869
            stream_pos = parse_date(buf, 0);
1870
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1871
            int prebuffer = strtol(buf, 0, 10);
1872
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1873
        } else {
1874
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1875
        }
1876
    } else {
1877
        strcpy(input_filename, c->stream->feed_filename);
1878
        buf_size = 0;
1879
        /* compute position (relative time) */
1880
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1881
            stream_pos = parse_date(buf, 1);
1882
        } else {
1883
            stream_pos = 0;
1884
        }
1885
    }
1886
    if (input_filename[0] == '\0')
1887
        return -1;
1888

    
1889
#if 0
1890
    { time_t when = stream_pos / 1000000;
1891
    http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1892
    }
1893
#endif
1894

    
1895
    /* open stream */
1896
    if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
1897
        http_log("%s not found", input_filename);
1898
        return -1;
1899
    }
1900
    c->fmt_in = s;
1901
    
1902
    /* open each parser */
1903
    for(i=0;i<s->nb_streams;i++)
1904
        open_parser(s, i);
1905

    
1906
    /* choose stream as clock source (we favorize video stream if
1907
       present) for packet sending */
1908
    c->pts_stream_index = 0;
1909
    for(i=0;i<c->stream->nb_streams;i++) {
1910
        if (c->pts_stream_index == 0 && 
1911
            c->stream->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) {
1912
            c->pts_stream_index = i;
1913
        }
1914
    }
1915

    
1916
    if (c->fmt_in->iformat->read_seek) {
1917
        c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
1918
    }
1919
    /* set the start time (needed for maxtime and RTP packet timing) */
1920
    c->start_time = cur_time;
1921
    c->first_pts = AV_NOPTS_VALUE;
1922
    return 0;
1923
}
1924

    
1925
/* currently desactivated because the new PTS handling is not
1926
   satisfactory yet */
1927
//#define AV_READ_FRAME
1928
#ifdef AV_READ_FRAME
1929

    
1930
/* XXX: generalize that in ffmpeg for picture/audio/data. Currently
1931
   the return packet MUST NOT be freed */
1932
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1933
{
1934
    AVStream *st;
1935
    int len, ret, old_nb_streams, i;
1936

    
1937
    /* see if remaining frames must be parsed */
1938
    for(;;) {
1939
        if (s->cur_len > 0) {
1940
            st = s->streams[s->cur_pkt.stream_index];
1941
            len = avcodec_parse_frame(&st->codec, &pkt->data, &pkt->size, 
1942
                                      s->cur_ptr, s->cur_len);
1943
            if (len < 0) {
1944
                /* error: get next packet */
1945
                s->cur_len = 0;
1946
            } else {
1947
                s->cur_ptr += len;
1948
                s->cur_len -= len;
1949
                if (pkt->size) {
1950
                    /* init pts counter if not done */
1951
                    if (st->pts.den == 0) {
1952
                        switch(st->codec.codec_type) {
1953
                        case CODEC_TYPE_AUDIO:
1954
                            st->pts_incr = (int64_t)s->pts_den;
1955
                            av_frac_init(&st->pts, st->pts.val, 0, 
1956
                                         (int64_t)s->pts_num * st->codec.sample_rate);
1957
                            break;
1958
                        case CODEC_TYPE_VIDEO:
1959
                            st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base;
1960
                            av_frac_init(&st->pts, st->pts.val, 0,
1961
                                         (int64_t)s->pts_num * st->codec.frame_rate);
1962
                            break;
1963
                        default:
1964
                            av_abort();
1965
                        }
1966
                    }
1967
                    
1968
                    /* a frame was read: return it */
1969
                    pkt->pts = st->pts.val;
1970
#if 0
1971
                    printf("add pts=%Lx num=%Lx den=%Lx incr=%Lx\n",
1972
                           st->pts.val, st->pts.num, st->pts.den, st->pts_incr);
1973
#endif
1974
                    switch(st->codec.codec_type) {
1975
                    case CODEC_TYPE_AUDIO:
1976
                        av_frac_add(&st->pts, st->pts_incr * st->codec.frame_size);
1977
                        break;
1978
                    case CODEC_TYPE_VIDEO:
1979
                        av_frac_add(&st->pts, st->pts_incr);
1980
                        break;
1981
                    default:
1982
                        av_abort();
1983
                    }
1984
                    pkt->stream_index = s->cur_pkt.stream_index;
1985
                    /* we use the codec indication because it is
1986
                       more accurate than the demux flags */
1987
                    pkt->flags = 0;
1988
                    if (st->codec.coded_frame->key_frame) 
1989
                        pkt->flags |= PKT_FLAG_KEY;
1990
                    return 0;
1991
                }
1992
            }
1993
        } else {
1994
            /* free previous packet */
1995
            av_free_packet(&s->cur_pkt); 
1996

    
1997
            old_nb_streams = s->nb_streams;
1998
            ret = av_read_packet(s, &s->cur_pkt);
1999
            if (ret)
2000
                return ret;
2001
            /* open parsers for each new streams */
2002
            for(i = old_nb_streams; i < s->nb_streams; i++)
2003
                open_parser(s, i);
2004
            st = s->streams[s->cur_pkt.stream_index];
2005

    
2006
            /* update current pts (XXX: dts handling) from packet, or
2007
               use current pts if none given */
2008
            if (s->cur_pkt.pts != AV_NOPTS_VALUE) {
2009
                av_frac_set(&st->pts, s->cur_pkt.pts);
2010
            } else {
2011
                s->cur_pkt.pts = st->pts.val;
2012
            }
2013
            if (!st->codec.codec) {
2014
                /* no codec opened: just return the raw packet */
2015
                *pkt = s->cur_pkt;
2016

    
2017
                /* no codec opened: just update the pts by considering we
2018
                   have one frame and free the packet */
2019
                if (st->pts.den == 0) {
2020
                    switch(st->codec.codec_type) {
2021
                    case CODEC_TYPE_AUDIO:
2022
                        st->pts_incr = (int64_t)s->pts_den * st->codec.frame_size;
2023
                        av_frac_init(&st->pts, st->pts.val, 0, 
2024
                                     (int64_t)s->pts_num * st->codec.sample_rate);
2025
                        break;
2026
                    case CODEC_TYPE_VIDEO:
2027
                        st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base;
2028
                        av_frac_init(&st->pts, st->pts.val, 0,
2029
                                     (int64_t)s->pts_num * st->codec.frame_rate);
2030
                        break;
2031
                    default:
2032
                        av_abort();
2033
                    }
2034
                }
2035
                av_frac_add(&st->pts, st->pts_incr);
2036
                return 0;
2037
            } else {
2038
                s->cur_ptr = s->cur_pkt.data;
2039
                s->cur_len = s->cur_pkt.size;
2040
            }
2041
        }
2042
    }
2043
}
2044

    
2045
static int compute_send_delay(HTTPContext *c)
2046
{
2047
    int64_t cur_pts, delta_pts, next_pts;
2048
    int delay1;
2049
    
2050
    /* compute current pts value from system time */
2051
    cur_pts = ((int64_t)(cur_time - c->start_time) * c->fmt_in->pts_den) / 
2052
        (c->fmt_in->pts_num * 1000LL);
2053
    /* compute the delta from the stream we choose as
2054
       main clock (we do that to avoid using explicit
2055
       buffers to do exact packet reordering for each
2056
       stream */
2057
    /* XXX: really need to fix the number of streams */
2058
    if (c->pts_stream_index >= c->fmt_in->nb_streams)
2059
        next_pts = cur_pts;
2060
    else
2061
        next_pts = c->fmt_in->streams[c->pts_stream_index]->pts.val;
2062
    delta_pts = next_pts - cur_pts;
2063
    if (delta_pts <= 0) {
2064
        delay1 = 0;
2065
    } else {
2066
        delay1 = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
2067
    }
2068
    return delay1;
2069
}
2070
#else
2071

    
2072
/* just fall backs */
2073
static int av_read_frame(AVFormatContext *s, AVPacket *pkt)
2074
{
2075
    return av_read_packet(s, pkt);
2076
}
2077

    
2078
static int compute_send_delay(HTTPContext *c)
2079
{
2080
    int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count); 
2081

    
2082
    if (datarate > c->stream->bandwidth * 2000) {
2083
        return 1000;
2084
    }
2085
    return 0;
2086
}
2087

    
2088
#endif
2089
    
2090
static int http_prepare_data(HTTPContext *c)
2091
{
2092
    int i, len, ret;
2093
    AVFormatContext *ctx;
2094

    
2095
    switch(c->state) {
2096
    case HTTPSTATE_SEND_DATA_HEADER:
2097
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2098
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), 
2099
                c->stream->author);
2100
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), 
2101
                c->stream->comment);
2102
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), 
2103
                c->stream->copyright);
2104
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), 
2105
                c->stream->title);
2106

    
2107
        /* open output stream by using specified codecs */
2108
        c->fmt_ctx.oformat = c->stream->fmt;
2109
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2110
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2111
            AVStream *st;
2112
            st = av_mallocz(sizeof(AVStream));
2113
            c->fmt_ctx.streams[i] = st;
2114
            /* if file or feed, then just take streams from FFStream struct */
2115
            if (!c->stream->feed || 
2116
                c->stream->feed == c->stream)
2117
                memcpy(st, c->stream->streams[i], sizeof(AVStream));
2118
            else
2119
                memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]],
2120
                           sizeof(AVStream));
2121
            st->codec.frame_number = 0; /* XXX: should be done in
2122
                                           AVStream, not in codec */
2123
            /* I'm pretty sure that this is not correct...
2124
             * However, without it, we crash
2125
             */
2126
            st->codec.coded_frame = &dummy_frame;
2127
        }
2128
        c->got_key_frame = 0;
2129

    
2130
        /* prepare header and save header data in a stream */
2131
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2132
            /* XXX: potential leak */
2133
            return -1;
2134
        }
2135
        c->fmt_ctx.pb.is_streamed = 1;
2136

    
2137
        av_set_parameters(&c->fmt_ctx, NULL);
2138
        av_write_header(&c->fmt_ctx);
2139

    
2140
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2141
        c->buffer_ptr = c->pb_buffer;
2142
        c->buffer_end = c->pb_buffer + len;
2143

    
2144
        c->state = HTTPSTATE_SEND_DATA;
2145
        c->last_packet_sent = 0;
2146
        break;
2147
    case HTTPSTATE_SEND_DATA:
2148
        /* find a new packet */
2149
        {
2150
            AVPacket pkt;
2151
            
2152
            /* read a packet from the input stream */
2153
            if (c->stream->feed) {
2154
                ffm_set_write_index(c->fmt_in, 
2155
                                    c->stream->feed->feed_write_index,
2156
                                    c->stream->feed->feed_size);
2157
            }
2158

    
2159
            if (c->stream->max_time && 
2160
                c->stream->max_time + c->start_time - cur_time < 0) {
2161
                /* We have timed out */
2162
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
2163
            } else {
2164
                if (1 || c->is_packetized) {
2165
                    if (compute_send_delay(c) > 0) {
2166
                        c->state = HTTPSTATE_WAIT;
2167
                        return 1; /* state changed */
2168
                    }
2169
                }
2170
            redo:
2171
                if (av_read_frame(c->fmt_in, &pkt) < 0) {
2172
                    if (c->stream->feed && c->stream->feed->feed_opened) {
2173
                        /* if coming from feed, it means we reached the end of the
2174
                           ffm file, so must wait for more data */
2175
                        c->state = HTTPSTATE_WAIT_FEED;
2176
                        return 1; /* state changed */
2177
                    } else {
2178
                        if (c->stream->loop) {
2179
                            av_close_input_file(c->fmt_in);
2180
                            c->fmt_in = NULL;
2181
                            if (open_input_stream(c, "") < 0)
2182
                                goto no_loop;
2183
                            goto redo;
2184
                        } else {
2185
                        no_loop:
2186
                            /* must send trailer now because eof or error */
2187
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2188
                        }
2189
                    }
2190
                } else {
2191
                    /* update first pts if needed */
2192
                    if (c->first_pts == AV_NOPTS_VALUE)
2193
                        c->first_pts = pkt.pts;
2194
                    
2195
                    /* send it to the appropriate stream */
2196
                    if (c->stream->feed) {
2197
                        /* if coming from a feed, select the right stream */
2198
                        if (c->switch_pending) {
2199
                            c->switch_pending = 0;
2200
                            for(i=0;i<c->stream->nb_streams;i++) {
2201
                                if (c->switch_feed_streams[i] == pkt.stream_index) {
2202
                                    if (pkt.flags & PKT_FLAG_KEY) {
2203
                                        do_switch_stream(c, i);
2204
                                    }
2205
                                }
2206
                                if (c->switch_feed_streams[i] >= 0) {
2207
                                    c->switch_pending = 1;
2208
                                }
2209
                            }
2210
                        }
2211
                        for(i=0;i<c->stream->nb_streams;i++) {
2212
                            if (c->feed_streams[i] == pkt.stream_index) {
2213
                                pkt.stream_index = i;
2214
                                if (pkt.flags & PKT_FLAG_KEY) {
2215
                                    c->got_key_frame |= 1 << i;
2216
                                }
2217
                                /* See if we have all the key frames, then 
2218
                                 * we start to send. This logic is not quite
2219
                                 * right, but it works for the case of a 
2220
                                 * single video stream with one or more
2221
                                 * audio streams (for which every frame is 
2222
                                 * typically a key frame). 
2223
                                 */
2224
                                if (!c->stream->send_on_key || 
2225
                                    ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2226
                                    goto send_it;
2227
                                }
2228
                            }
2229
                        }
2230
                    } else {
2231
                        AVCodecContext *codec;
2232
                        
2233
                    send_it:
2234
                        /* specific handling for RTP: we use several
2235
                           output stream (one for each RTP
2236
                           connection). XXX: need more abstract handling */
2237
                        if (c->is_packetized) {
2238
                            c->packet_stream_index = pkt.stream_index;
2239
                            ctx = c->rtp_ctx[c->packet_stream_index];
2240
                            if(!ctx) {
2241
                              av_free_packet(&pkt);
2242
                              return -1;
2243
                            }
2244
                            codec = &ctx->streams[0]->codec;
2245
                            /* only one stream per RTP connection */
2246
                            pkt.stream_index = 0;
2247
                        } else {
2248
                            ctx = &c->fmt_ctx;
2249
                            /* Fudge here */
2250
                            codec = &ctx->streams[pkt.stream_index]->codec;
2251
                        }
2252
                        
2253
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2254
                        
2255
#ifdef PJSG
2256
                        if (codec->codec_type == CODEC_TYPE_AUDIO) {
2257
                            codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
2258
                            /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
2259
                        }
2260
#endif
2261
                        
2262
                        if (c->is_packetized) {
2263
                            ret = url_open_dyn_packet_buf(&ctx->pb, 
2264
                                                          url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]));
2265
                            c->packet_byte_count = 0;
2266
                            c->packet_start_time_us = av_gettime();
2267
                        } else {
2268
                            ret = url_open_dyn_buf(&ctx->pb);
2269
                        }
2270
                        if (ret < 0) {
2271
                            /* XXX: potential leak */
2272
                            return -1;
2273
                        }
2274
                        if (av_write_frame(ctx, pkt.stream_index, pkt.data, pkt.size)) {
2275
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2276
                        }
2277
                        
2278
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2279
                        c->buffer_ptr = c->pb_buffer;
2280
                        c->buffer_end = c->pb_buffer + len;
2281
                        
2282
                        codec->frame_number++;
2283
                    }
2284
#ifndef AV_READ_FRAME
2285
                    av_free_packet(&pkt);
2286
#endif
2287
                }
2288
            }
2289
        }
2290
        break;
2291
    default:
2292
    case HTTPSTATE_SEND_DATA_TRAILER:
2293
        /* last packet test ? */
2294
        if (c->last_packet_sent || c->is_packetized)
2295
            return -1;
2296
        ctx = &c->fmt_ctx;
2297
        /* prepare header */
2298
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2299
            /* XXX: potential leak */
2300
            return -1;
2301
        }
2302
        av_write_trailer(ctx);
2303
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2304
        c->buffer_ptr = c->pb_buffer;
2305
        c->buffer_end = c->pb_buffer + len;
2306

    
2307
        c->last_packet_sent = 1;
2308
        break;
2309
    }
2310
    return 0;
2311
}
2312

    
2313
/* in bit/s */
2314
#define SHORT_TERM_BANDWIDTH 8000000
2315

    
2316
/* should convert the format at the same time */
2317
static int http_send_data(HTTPContext *c)
2318
{
2319
    int len, ret, dt;
2320
    
2321
    while (c->buffer_ptr >= c->buffer_end) {
2322
        av_freep(&c->pb_buffer);
2323
        ret = http_prepare_data(c);
2324
        if (ret < 0)
2325
            return -1;
2326
        else if (ret == 0) {
2327
            continue;
2328
        } else {
2329
            /* state change requested */
2330
            return 0;
2331
        }
2332
    }
2333

    
2334
    if (c->buffer_ptr < c->buffer_end) {
2335
        if (c->is_packetized) {
2336
            /* RTP/UDP data output */
2337
            len = c->buffer_end - c->buffer_ptr;
2338
            if (len < 4) {
2339
                /* fail safe - should never happen */
2340
            fail1:
2341
                c->buffer_ptr = c->buffer_end;
2342
                return 0;
2343
            }
2344
            len = (c->buffer_ptr[0] << 24) |
2345
                (c->buffer_ptr[1] << 16) |
2346
                (c->buffer_ptr[2] << 8) |
2347
                (c->buffer_ptr[3]);
2348
            if (len > (c->buffer_end - c->buffer_ptr))
2349
                goto fail1;
2350
            
2351
            /* short term bandwidth limitation */
2352
            dt = av_gettime() - c->packet_start_time_us;
2353
            if (dt < 1)
2354
                dt = 1;
2355

    
2356
            if ((c->packet_byte_count + len) * (int64_t)1000000 >= 
2357
                (SHORT_TERM_BANDWIDTH / 8) * (int64_t)dt) {
2358
                /* bandwidth overflow : wait at most one tick and retry */
2359
                c->state = HTTPSTATE_WAIT_SHORT;
2360
                return 0;
2361
            }
2362

    
2363
            c->buffer_ptr += 4;
2364
            url_write(c->rtp_handles[c->packet_stream_index], 
2365
                      c->buffer_ptr, len);
2366
            c->buffer_ptr += len;
2367
            c->packet_byte_count += len;
2368
        } else {
2369
            /* TCP data output */
2370
            len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2371
            if (len < 0) {
2372
                if (errno != EAGAIN && errno != EINTR) {
2373
                    /* error : close connection */
2374
                    return -1;
2375
                } else {
2376
                    return 0;
2377
                }
2378
            } else {
2379
                c->buffer_ptr += len;
2380
            }
2381
        }
2382
        c->data_count += len;
2383
        update_datarate(&c->datarate, c->data_count);
2384
        if (c->stream)
2385
            c->stream->bytes_served += len;
2386
    }
2387
    return 0;
2388
}
2389

    
2390
static int http_start_receive_data(HTTPContext *c)
2391
{
2392
    int fd;
2393

    
2394
    if (c->stream->feed_opened)
2395
        return -1;
2396

    
2397
    /* Don't permit writing to this one */
2398
    if (c->stream->readonly)
2399
        return -1;
2400

    
2401
    /* open feed */
2402
    fd = open(c->stream->feed_filename, O_RDWR);
2403
    if (fd < 0)
2404
        return -1;
2405
    c->feed_fd = fd;
2406
    
2407
    c->stream->feed_write_index = ffm_read_write_index(fd);
2408
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2409
    lseek(fd, 0, SEEK_SET);
2410

    
2411
    /* init buffer input */
2412
    c->buffer_ptr = c->buffer;
2413
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2414
    c->stream->feed_opened = 1;
2415
    return 0;
2416
}
2417
    
2418
static int http_receive_data(HTTPContext *c)
2419
{
2420
    HTTPContext *c1;
2421

    
2422
    if (c->buffer_end > c->buffer_ptr) {
2423
        int len;
2424

    
2425
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2426
        if (len < 0) {
2427
            if (errno != EAGAIN && errno != EINTR) {
2428
                /* error : close connection */
2429
                goto fail;
2430
            }
2431
        } else if (len == 0) {
2432
            /* end of connection : close it */
2433
            goto fail;
2434
        } else {
2435
            c->buffer_ptr += len;
2436
            c->data_count += len;
2437
            update_datarate(&c->datarate, c->data_count);
2438
        }
2439
    }
2440

    
2441
    if (c->buffer_ptr >= c->buffer_end) {
2442
        FFStream *feed = c->stream;
2443
        /* a packet has been received : write it in the store, except
2444
           if header */
2445
        if (c->data_count > FFM_PACKET_SIZE) {
2446
            
2447
            //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2448
            /* XXX: use llseek or url_seek */
2449
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2450
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2451
            
2452
            feed->feed_write_index += FFM_PACKET_SIZE;
2453
            /* update file size */
2454
            if (feed->feed_write_index > c->stream->feed_size)
2455
                feed->feed_size = feed->feed_write_index;
2456

    
2457
            /* handle wrap around if max file size reached */
2458
            if (feed->feed_write_index >= c->stream->feed_max_size)
2459
                feed->feed_write_index = FFM_PACKET_SIZE;
2460

    
2461
            /* write index */
2462
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2463

    
2464
            /* wake up any waiting connections */
2465
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2466
                if (c1->state == HTTPSTATE_WAIT_FEED && 
2467
                    c1->stream->feed == c->stream->feed) {
2468
                    c1->state = HTTPSTATE_SEND_DATA;
2469
                }
2470
            }
2471
        } else {
2472
            /* We have a header in our hands that contains useful data */
2473
            AVFormatContext s;
2474
            AVInputFormat *fmt_in;
2475
            ByteIOContext *pb = &s.pb;
2476
            int i;
2477

    
2478
            memset(&s, 0, sizeof(s));
2479

    
2480
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2481
            pb->buf_end = c->buffer_end;        /* ?? */
2482
            pb->is_streamed = 1;
2483

    
2484
            /* use feed output format name to find corresponding input format */
2485
            fmt_in = av_find_input_format(feed->fmt->name);
2486
            if (!fmt_in)
2487
                goto fail;
2488

    
2489
            if (fmt_in->priv_data_size > 0) {
2490
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2491
                if (!s.priv_data)
2492
                    goto fail;
2493
            } else
2494
                s.priv_data = NULL;
2495

    
2496
            if (fmt_in->read_header(&s, 0) < 0) {
2497
                av_freep(&s.priv_data);
2498
                goto fail;
2499
            }
2500

    
2501
            /* Now we have the actual streams */
2502
            if (s.nb_streams != feed->nb_streams) {
2503
                av_freep(&s.priv_data);
2504
                goto fail;
2505
            }
2506
            for (i = 0; i < s.nb_streams; i++) {
2507
                memcpy(&feed->streams[i]->codec, 
2508
                       &s.streams[i]->codec, sizeof(AVCodecContext));
2509
            } 
2510
            av_freep(&s.priv_data);
2511
        }
2512
        c->buffer_ptr = c->buffer;
2513
    }
2514

    
2515
    return 0;
2516
 fail:
2517
    c->stream->feed_opened = 0;
2518
    close(c->feed_fd);
2519
    return -1;
2520
}
2521

    
2522
/********************************************************************/
2523
/* RTSP handling */
2524

    
2525
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2526
{
2527
    const char *str;
2528
    time_t ti;
2529
    char *p;
2530
    char buf2[32];
2531

    
2532
    switch(error_number) {
2533
#define DEF(n, c, s) case c: str = s; break; 
2534
#include "rtspcodes.h"
2535
#undef DEF
2536
    default:
2537
        str = "Unknown Error";
2538
        break;
2539
    }
2540
     
2541
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2542
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2543

    
2544
    /* output GMT time */
2545
    ti = time(NULL);
2546
    p = ctime(&ti);
2547
    strcpy(buf2, p);
2548
    p = buf2 + strlen(p) - 1;
2549
    if (*p == '\n')
2550
        *p = '\0';
2551
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2552
}
2553

    
2554
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2555
{
2556
    rtsp_reply_header(c, error_number);
2557
    url_fprintf(c->pb, "\r\n");
2558
}
2559

    
2560
static int rtsp_parse_request(HTTPContext *c)
2561
{
2562
    const char *p, *p1, *p2;
2563
    char cmd[32];
2564
    char url[1024];
2565
    char protocol[32];
2566
    char line[1024];
2567
    ByteIOContext pb1;
2568
    int len;
2569
    RTSPHeader header1, *header = &header1;
2570
    
2571
    c->buffer_ptr[0] = '\0';
2572
    p = c->buffer;
2573
    
2574
    get_word(cmd, sizeof(cmd), &p);
2575
    get_word(url, sizeof(url), &p);
2576
    get_word(protocol, sizeof(protocol), &p);
2577

    
2578
    pstrcpy(c->method, sizeof(c->method), cmd);
2579
    pstrcpy(c->url, sizeof(c->url), url);
2580
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2581

    
2582
    c->pb = &pb1;
2583
    if (url_open_dyn_buf(c->pb) < 0) {
2584
        /* XXX: cannot do more */
2585
        c->pb = NULL; /* safety */
2586
        return -1;
2587
    }
2588

    
2589
    /* check version name */
2590
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2591
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2592
        goto the_end;
2593
    }
2594

    
2595
    /* parse each header line */
2596
    memset(header, 0, sizeof(RTSPHeader));
2597
    /* skip to next line */
2598
    while (*p != '\n' && *p != '\0')
2599
        p++;
2600
    if (*p == '\n')
2601
        p++;
2602
    while (*p != '\0') {
2603
        p1 = strchr(p, '\n');
2604
        if (!p1)
2605
            break;
2606
        p2 = p1;
2607
        if (p2 > p && p2[-1] == '\r')
2608
            p2--;
2609
        /* skip empty line */
2610
        if (p2 == p)
2611
            break;
2612
        len = p2 - p;
2613
        if (len > sizeof(line) - 1)
2614
            len = sizeof(line) - 1;
2615
        memcpy(line, p, len);
2616
        line[len] = '\0';
2617
        rtsp_parse_line(header, line);
2618
        p = p1 + 1;
2619
    }
2620

    
2621
    /* handle sequence number */
2622
    c->seq = header->seq;
2623

    
2624
    if (!strcmp(cmd, "DESCRIBE")) {
2625
        rtsp_cmd_describe(c, url);
2626
    } else if (!strcmp(cmd, "OPTIONS")) {
2627
        rtsp_cmd_options(c, url);
2628
    } else if (!strcmp(cmd, "SETUP")) {
2629
        rtsp_cmd_setup(c, url, header);
2630
    } else if (!strcmp(cmd, "PLAY")) {
2631
        rtsp_cmd_play(c, url, header);
2632
    } else if (!strcmp(cmd, "PAUSE")) {
2633
        rtsp_cmd_pause(c, url, header);
2634
    } else if (!strcmp(cmd, "TEARDOWN")) {
2635
        rtsp_cmd_teardown(c, url, header);
2636
    } else {
2637
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2638
    }
2639
 the_end:
2640
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2641
    c->pb = NULL; /* safety */
2642
    if (len < 0) {
2643
        /* XXX: cannot do more */
2644
        return -1;
2645
    }
2646
    c->buffer_ptr = c->pb_buffer;
2647
    c->buffer_end = c->pb_buffer + len;
2648
    c->state = RTSPSTATE_SEND_REPLY;
2649
    return 0;
2650
}
2651

    
2652
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2653
   AVFormatContext */
2654
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
2655
                                   struct in_addr my_ip)
2656
{
2657
    ByteIOContext pb1, *pb = &pb1;
2658
    int i, payload_type, port, private_payload_type, j;
2659
    const char *ipstr, *title, *mediatype;
2660
    AVStream *st;
2661
    
2662
    if (url_open_dyn_buf(pb) < 0)
2663
        return -1;
2664
    
2665
    /* general media info */
2666

    
2667
    url_fprintf(pb, "v=0\n");
2668
    ipstr = inet_ntoa(my_ip);
2669
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2670
    title = stream->title;
2671
    if (title[0] == '\0')
2672
        title = "No Title";
2673
    url_fprintf(pb, "s=%s\n", title);
2674
    if (stream->comment[0] != '\0')
2675
        url_fprintf(pb, "i=%s\n", stream->comment);
2676
    if (stream->is_multicast) {
2677
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2678
    }
2679
    /* for each stream, we output the necessary info */
2680
    private_payload_type = 96;
2681
    for(i = 0; i < stream->nb_streams; i++) {
2682
        st = stream->streams[i];
2683
        switch(st->codec.codec_type) {
2684
        case CODEC_TYPE_AUDIO:
2685
            mediatype = "audio";
2686
            break;
2687
        case CODEC_TYPE_VIDEO:
2688
            mediatype = "video";
2689
            break;
2690
        default:
2691
            mediatype = "application";
2692
            break;
2693
        }
2694
        /* NOTE: the port indication is not correct in case of
2695
           unicast. It is not an issue because RTSP gives it */
2696
        payload_type = rtp_get_payload_type(&st->codec);
2697
        if (payload_type < 0)
2698
            payload_type = private_payload_type++;
2699
        if (stream->is_multicast) {
2700
            port = stream->multicast_port + 2 * i;
2701
        } else {
2702
            port = 0;
2703
        }
2704
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n", 
2705
                    mediatype, port, payload_type);
2706
        if (payload_type >= 96) {
2707
            /* for private payload type, we need to give more info */
2708
            switch(st->codec.codec_id) {
2709
            case CODEC_ID_MPEG4:
2710
                {
2711
                    uint8_t *data;
2712
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n", 
2713
                                payload_type, 90000);
2714
                    /* we must also add the mpeg4 header */
2715
                    data = st->codec.extradata;
2716
                    if (data) {
2717
                        url_fprintf(pb, "a=fmtp:%d config=");
2718
                        for(j=0;j<st->codec.extradata_size;j++) {
2719
                            url_fprintf(pb, "%02x", data[j]);
2720
                        }
2721
                        url_fprintf(pb, "\n");
2722
                    }
2723
                }
2724
                break;
2725
            default:
2726
                /* XXX: add other codecs ? */
2727
                goto fail;
2728
            }
2729
        }
2730
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2731
    }
2732
    return url_close_dyn_buf(pb, pbuffer);
2733
 fail:
2734
    url_close_dyn_buf(pb, pbuffer);
2735
    av_free(*pbuffer);
2736
    return -1;
2737
}
2738

    
2739
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2740
{
2741
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2742
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2743
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2744
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2745
    url_fprintf(c->pb, "\r\n");
2746
}
2747

    
2748
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2749
{
2750
    FFStream *stream;
2751
    char path1[1024];
2752
    const char *path;
2753
    uint8_t *content;
2754
    int content_length, len;
2755
    struct sockaddr_in my_addr;
2756
    
2757
    /* find which url is asked */
2758
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2759
    path = path1;
2760
    if (*path == '/')
2761
        path++;
2762

    
2763
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2764
        if (!stream->is_feed && stream->fmt == &rtp_mux &&
2765
            !strcmp(path, stream->filename)) {
2766
            goto found;
2767
        }
2768
    }
2769
    /* no stream found */
2770
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2771
    return;
2772

    
2773
 found:
2774
    /* prepare the media description in sdp format */
2775

    
2776
    /* get the host IP */
2777
    len = sizeof(my_addr);
2778
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2779
    
2780
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2781
    if (content_length < 0) {
2782
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2783
        return;
2784
    }
2785
    rtsp_reply_header(c, RTSP_STATUS_OK);
2786
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2787
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2788
    url_fprintf(c->pb, "\r\n");
2789
    put_buffer(c->pb, content, content_length);
2790
}
2791

    
2792
static HTTPContext *find_rtp_session(const char *session_id)
2793
{
2794
    HTTPContext *c;
2795

    
2796
    if (session_id[0] == '\0')
2797
        return NULL;
2798

    
2799
    for(c = first_http_ctx; c != NULL; c = c->next) {
2800
        if (!strcmp(c->session_id, session_id))
2801
            return c;
2802
    }
2803
    return NULL;
2804
}
2805

    
2806
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2807
{
2808
    RTSPTransportField *th;
2809
    int i;
2810

    
2811
    for(i=0;i<h->nb_transports;i++) {
2812
        th = &h->transports[i];
2813
        if (th->protocol == protocol)
2814
            return th;
2815
    }
2816
    return NULL;
2817
}
2818

    
2819
static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2820
                           RTSPHeader *h)
2821
{
2822
    FFStream *stream;
2823
    int stream_index, port;
2824
    char buf[1024];
2825
    char path1[1024];
2826
    const char *path;
2827
    HTTPContext *rtp_c;
2828
    RTSPTransportField *th;
2829
    struct sockaddr_in dest_addr;
2830
    RTSPActionServerSetup setup;
2831
    
2832
    /* find which url is asked */
2833
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2834
    path = path1;
2835
    if (*path == '/')
2836
        path++;
2837

    
2838
    /* now check each stream */
2839
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2840
        if (!stream->is_feed && stream->fmt == &rtp_mux) {
2841
            /* accept aggregate filenames only if single stream */
2842
            if (!strcmp(path, stream->filename)) {
2843
                if (stream->nb_streams != 1) {
2844
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2845
                    return;
2846
                }
2847
                stream_index = 0;
2848
                goto found;
2849
            }
2850
                
2851
            for(stream_index = 0; stream_index < stream->nb_streams;
2852
                stream_index++) {
2853
                snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2854
                         stream->filename, stream_index);
2855
                if (!strcmp(path, buf))
2856
                    goto found;
2857
            }
2858
        }
2859
    }
2860
    /* no stream found */
2861
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2862
    return;
2863
 found:
2864

    
2865
    /* generate session id if needed */
2866
    if (h->session_id[0] == '\0') {
2867
        snprintf(h->session_id, sizeof(h->session_id), 
2868
                 "%08x%08x", (int)random(), (int)random());
2869
    }
2870

    
2871
    /* find rtp session, and create it if none found */
2872
    rtp_c = find_rtp_session(h->session_id);
2873
    if (!rtp_c) {
2874
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id);
2875
        if (!rtp_c) {
2876
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2877
            return;
2878
        }
2879

    
2880
        /* open input stream */
2881
        if (open_input_stream(rtp_c, "") < 0) {
2882
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2883
            return;
2884
        }
2885

    
2886
        /* always prefer UDP */
2887
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2888
        if (!th) {
2889
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2890
            if (!th) {
2891
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2892
                return;
2893
            }
2894
        }
2895
        rtp_c->rtp_protocol = th->protocol;
2896
    }
2897
    
2898
    /* test if stream is OK (test needed because several SETUP needs
2899
       to be done for a given file) */
2900
    if (rtp_c->stream != stream) {
2901
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2902
        return;
2903
    }
2904
    
2905
    /* test if stream is already set up */
2906
    if (rtp_c->rtp_ctx[stream_index]) {
2907
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2908
        return;
2909
    }
2910

    
2911
    /* check transport */
2912
    th = find_transport(h, rtp_c->rtp_protocol);
2913
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP && 
2914
                th->client_port_min <= 0)) {
2915
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2916
        return;
2917
    }
2918

    
2919
    /* setup default options */
2920
    setup.transport_option[0] = '\0';
2921
    dest_addr = rtp_c->from_addr;
2922
    dest_addr.sin_port = htons(th->client_port_min);
2923
    
2924
    /* add transport option if needed */
2925
    if (ff_rtsp_callback) {
2926
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2927
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
2928
                             (char *)&setup, sizeof(setup),
2929
                             stream->rtsp_option) < 0) {
2930
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2931
            return;
2932
        }
2933
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2934
    }
2935
    
2936
    /* setup stream */
2937
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
2938
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2939
        return;
2940
    }
2941

    
2942
    /* now everything is OK, so we can send the connection parameters */
2943
    rtsp_reply_header(c, RTSP_STATUS_OK);
2944
    /* session ID */
2945
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2946

    
2947
    switch(rtp_c->rtp_protocol) {
2948
    case RTSP_PROTOCOL_RTP_UDP:
2949
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2950
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2951
                    "client_port=%d-%d;server_port=%d-%d",
2952
                    th->client_port_min, th->client_port_min + 1,
2953
                    port, port + 1);
2954
        break;
2955
    case RTSP_PROTOCOL_RTP_TCP:
2956
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2957
                    stream_index * 2, stream_index * 2 + 1);
2958
        break;
2959
    default:
2960
        break;
2961
    }
2962
    if (setup.transport_option[0] != '\0') {
2963
        url_fprintf(c->pb, ";%s", setup.transport_option);
2964
    }
2965
    url_fprintf(c->pb, "\r\n");
2966
    
2967

    
2968
    url_fprintf(c->pb, "\r\n");
2969
}
2970

    
2971

    
2972
/* find an rtp connection by using the session ID. Check consistency
2973
   with filename */
2974
static HTTPContext *find_rtp_session_with_url(const char *url, 
2975
                                              const char *session_id)
2976
{
2977
    HTTPContext *rtp_c;
2978
    char path1[1024];
2979
    const char *path;
2980
    char buf[1024];
2981
    int s;
2982

    
2983
    rtp_c = find_rtp_session(session_id);
2984
    if (!rtp_c)
2985
        return NULL;
2986

    
2987
    /* find which url is asked */
2988
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2989
    path = path1;
2990
    if (*path == '/')
2991
        path++;
2992
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2993
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2994
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2995
        rtp_c->stream->filename, s);
2996
      if(!strncmp(path, buf, sizeof(buf))) {
2997
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2998
        return rtp_c;
2999
      }
3000
    }
3001
    return NULL;
3002
}
3003

    
3004
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3005
{
3006
    HTTPContext *rtp_c;
3007

    
3008
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3009
    if (!rtp_c) {
3010
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3011
        return;
3012
    }
3013
    
3014
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3015
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3016
        rtp_c->state != HTTPSTATE_READY) {
3017
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3018
        return;
3019
    }
3020

    
3021
    rtp_c->state = HTTPSTATE_SEND_DATA;
3022
    
3023
    /* now everything is OK, so we can send the connection parameters */
3024
    rtsp_reply_header(c, RTSP_STATUS_OK);
3025
    /* session ID */
3026
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3027
    url_fprintf(c->pb, "\r\n");
3028
}
3029

    
3030
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3031
{
3032
    HTTPContext *rtp_c;
3033

    
3034
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3035
    if (!rtp_c) {
3036
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3037
        return;
3038
    }
3039
    
3040
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3041
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3042
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3043
        return;
3044
    }
3045
    
3046
    rtp_c->state = HTTPSTATE_READY;
3047
    
3048
    /* now everything is OK, so we can send the connection parameters */
3049
    rtsp_reply_header(c, RTSP_STATUS_OK);
3050
    /* session ID */
3051
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3052
    url_fprintf(c->pb, "\r\n");
3053
}
3054

    
3055
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3056
{
3057
    HTTPContext *rtp_c;
3058

    
3059
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3060
    if (!rtp_c) {
3061
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3062
        return;
3063
    }
3064
    
3065
    /* abort the session */
3066
    close_connection(rtp_c);
3067

    
3068
    if (ff_rtsp_callback) {
3069
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, 
3070
                         NULL, 0,
3071
                         rtp_c->stream->rtsp_option);
3072
    }
3073

    
3074
    /* now everything is OK, so we can send the connection parameters */
3075
    rtsp_reply_header(c, RTSP_STATUS_OK);
3076
    /* session ID */
3077
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3078
    url_fprintf(c->pb, "\r\n");
3079
}
3080

    
3081

    
3082
/********************************************************************/
3083
/* RTP handling */
3084

    
3085
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
3086
                                       FFStream *stream, const char *session_id)
3087
{
3088
    HTTPContext *c = NULL;
3089

    
3090
    /* XXX: should output a warning page when coming
3091
       close to the connection limit */
3092
    if (nb_connections >= nb_max_connections)
3093
        goto fail;
3094
    
3095
    /* add a new connection */
3096
    c = av_mallocz(sizeof(HTTPContext));
3097
    if (!c)
3098
        goto fail;
3099
    
3100
    c->fd = -1;
3101
    c->poll_entry = NULL;
3102
    c->from_addr = *from_addr;
3103
    c->buffer_size = IOBUFFER_INIT_SIZE;
3104
    c->buffer = av_malloc(c->buffer_size);
3105
    if (!c->buffer)
3106
        goto fail;
3107
    nb_connections++;
3108
    c->stream = stream;
3109
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3110
    c->state = HTTPSTATE_READY;
3111
    c->is_packetized = 1;
3112
    /* protocol is shown in statistics */
3113
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP");
3114

    
3115
    current_bandwidth += stream->bandwidth;
3116

    
3117
    c->next = first_http_ctx;
3118
    first_http_ctx = c;
3119
    return c;
3120
        
3121
 fail:
3122
    if (c) {
3123
        av_free(c->buffer);
3124
        av_free(c);
3125
    }
3126
    return NULL;
3127
}
3128

    
3129
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3130
   command). if dest_addr is NULL, then TCP tunneling in RTSP is
3131
   used. */
3132
static int rtp_new_av_stream(HTTPContext *c, 
3133
                             int stream_index, struct sockaddr_in *dest_addr)
3134
{
3135
    AVFormatContext *ctx;
3136
    AVStream *st;
3137
    char *ipaddr;
3138
    URLContext *h;
3139
    uint8_t *dummy_buf;
3140
    char buf2[32];
3141
    
3142
    /* now we can open the relevant output stream */
3143
    ctx = av_mallocz(sizeof(AVFormatContext));
3144
    if (!ctx)
3145
        return -1;
3146
    ctx->oformat = &rtp_mux;
3147

    
3148
    st = av_mallocz(sizeof(AVStream));
3149
    if (!st)
3150
        goto fail;
3151
    ctx->nb_streams = 1;
3152
    ctx->streams[0] = st;
3153

    
3154
    if (!c->stream->feed || 
3155
        c->stream->feed == c->stream) {
3156
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3157
    } else {
3158
        memcpy(st, 
3159
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3160
               sizeof(AVStream));
3161
    }
3162
    
3163
    if (dest_addr) {
3164
        /* build destination RTP address */
3165
        ipaddr = inet_ntoa(dest_addr->sin_addr);
3166
        
3167
        /* XXX: also pass as parameter to function ? */
3168
        if (c->stream->is_multicast) {
3169
            int ttl;
3170
            ttl = c->stream->multicast_ttl;
3171
            if (!ttl)
3172
                ttl = 16;
3173
            snprintf(ctx->filename, sizeof(ctx->filename),
3174
                     "rtp://%s:%d?multicast=1&ttl=%d", 
3175
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3176
        } else {
3177
            snprintf(ctx->filename, sizeof(ctx->filename),
3178
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3179
        }
3180

    
3181
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3182
            goto fail;
3183
        c->rtp_handles[stream_index] = h;
3184
    } else {
3185
        goto fail;
3186
    }
3187

    
3188
    http_log("%s:%d - - [%s] \"RTPSTART %s/streamid=%d\"\n",
3189
             ipaddr, ntohs(dest_addr->sin_port), 
3190
             ctime1(buf2), 
3191
             c->stream->filename, stream_index);
3192

    
3193
    /* normally, no packets should be output here, but the packet size may be checked */
3194
    if (url_open_dyn_packet_buf(&ctx->pb, 
3195
                                url_get_max_packet_size(h)) < 0) {
3196
        /* XXX: close stream */
3197
        goto fail;
3198
    }
3199
    av_set_parameters(ctx, NULL);
3200
    if (av_write_header(ctx) < 0) {
3201
    fail:
3202
        if (h)
3203
            url_close(h);
3204
        av_free(ctx);
3205
        return -1;
3206
    }
3207
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3208
    av_free(dummy_buf);
3209
    
3210
    c->rtp_ctx[stream_index] = ctx;
3211
    return 0;
3212
}
3213

    
3214
/********************************************************************/
3215
/* ffserver initialization */
3216

    
3217
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3218
{
3219
    AVStream *fst;
3220

    
3221
    fst = av_mallocz(sizeof(AVStream));
3222
    if (!fst)
3223
        return NULL;
3224
    fst->priv_data = av_mallocz(sizeof(FeedData));
3225
    memcpy(&fst->codec, codec, sizeof(AVCodecContext));
3226
    fst->codec.coded_frame = &dummy_frame;
3227
    stream->streams[stream->nb_streams++] = fst;
3228
    return fst;
3229
}
3230

    
3231
/* return the stream number in the feed */
3232
static int add_av_stream(FFStream *feed, AVStream *st)
3233
{
3234
    AVStream *fst;
3235
    AVCodecContext *av, *av1;
3236
    int i;
3237

    
3238
    av = &st->codec;
3239
    for(i=0;i<feed->nb_streams;i++) {
3240
        st = feed->streams[i];
3241
        av1 = &st->codec;
3242
        if (av1->codec_id == av->codec_id &&
3243
            av1->codec_type == av->codec_type &&
3244
            av1->bit_rate == av->bit_rate) {
3245

    
3246
            switch(av->codec_type) {
3247
            case CODEC_TYPE_AUDIO:
3248
                if (av1->channels == av->channels &&
3249
                    av1->sample_rate == av->sample_rate)
3250
                    goto found;
3251
                break;
3252
            case CODEC_TYPE_VIDEO:
3253
                if (av1->width == av->width &&
3254
                    av1->height == av->height &&
3255
                    av1->frame_rate == av->frame_rate &&
3256
                    av1->frame_rate_base == av->frame_rate_base &&
3257
                    av1->gop_size == av->gop_size)
3258
                    goto found;
3259
                break;
3260
            default:
3261
                av_abort();
3262
            }
3263
        }
3264
    }
3265
    
3266
    fst = add_av_stream1(feed, av);
3267
    if (!fst)
3268
        return -1;
3269
    return feed->nb_streams - 1;
3270
 found:
3271
    return i;
3272
}
3273

    
3274
static void remove_stream(FFStream *stream)
3275
{
3276
    FFStream **ps;
3277
    ps = &first_stream;
3278
    while (*ps != NULL) {
3279
        if (*ps == stream) {
3280
            *ps = (*ps)->next;
3281
        } else {
3282
            ps = &(*ps)->next;
3283
        }
3284
    }
3285
}
3286

    
3287
/* specific mpeg4 handling : we extract the raw parameters */
3288
static void extract_mpeg4_header(AVFormatContext *infile)
3289
{
3290
    int mpeg4_count, i, size;
3291
    AVPacket pkt;
3292
    AVStream *st;
3293
    const uint8_t *p;
3294

    
3295
    mpeg4_count = 0;
3296
    for(i=0;i<infile->nb_streams;i++) {
3297
        st = infile->streams[i];
3298
        if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3299
            st->codec.extradata == NULL) {
3300
            mpeg4_count++;
3301
        }
3302
    }
3303
    if (!mpeg4_count)
3304
        return;
3305

    
3306
    printf("MPEG4 without extra data: trying to find header\n");
3307
    while (mpeg4_count > 0) {
3308
        if (av_read_packet(infile, &pkt) < 0)
3309
            break;
3310
        st = infile->streams[pkt.stream_index];
3311
        if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3312
            st->codec.extradata == NULL) {
3313
            /* fill extradata with the header */
3314
            /* XXX: we make hard suppositions here ! */
3315
            p = pkt.data;
3316
            while (p < pkt.data + pkt.size - 4) {
3317
                /* stop when vop header is found */
3318
                if (p[0] == 0x00 && p[1] == 0x00 && 
3319
                    p[2] == 0x01 && p[3] == 0xb6) {
3320
                    size = p - pkt.data;
3321
                    //                    av_hex_dump(pkt.data, size);
3322
                    st->codec.extradata = av_malloc(size);
3323
                    st->codec.extradata_size = size;
3324
                    memcpy(st->codec.extradata, pkt.data, size);
3325
                    break;
3326
                }
3327
                p++;
3328
            }
3329
            mpeg4_count--;
3330
        }
3331
        av_free_packet(&pkt);
3332
    }
3333
}
3334

    
3335
/* compute the needed AVStream for each file */
3336
static void build_file_streams(void)
3337
{
3338
    FFStream *stream, *stream_next;
3339
    AVFormatContext *infile;
3340
    int i;
3341

    
3342
    /* gather all streams */
3343
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3344
        stream_next = stream->next;
3345
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3346
            !stream->feed) {
3347
            /* the stream comes from a file */
3348
            /* try to open the file */
3349
            /* open stream */
3350
            if (av_open_input_file(&infile, stream->feed_filename, 
3351
                                   NULL, 0, NULL) < 0) {
3352
                http_log("%s not found", stream->feed_filename);
3353
                /* remove stream (no need to spend more time on it) */
3354
            fail:
3355
                remove_stream(stream);
3356
            } else {
3357
                /* find all the AVStreams inside and reference them in
3358
                   'stream' */
3359
                if (av_find_stream_info(infile) < 0) {
3360
                    http_log("Could not find codec parameters from '%s'", 
3361
                             stream->feed_filename);
3362
                    av_close_input_file(infile);
3363
                    goto fail;
3364
                }
3365
                extract_mpeg4_header(infile);
3366

    
3367
                for(i=0;i<infile->nb_streams;i++) {
3368
                    add_av_stream1(stream, &infile->streams[i]->codec);
3369
                }
3370
                av_close_input_file(infile);
3371
            }
3372
        }
3373
    }
3374
}
3375

    
3376
/* compute the needed AVStream for each feed */
3377
static void build_feed_streams(void)
3378
{
3379
    FFStream *stream, *feed;
3380
    int i;
3381

    
3382
    /* gather all streams */
3383
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3384
        feed = stream->feed;
3385
        if (feed) {
3386
            if (!stream->is_feed) {
3387
                /* we handle a stream coming from a feed */
3388
                for(i=0;i<stream->nb_streams;i++) {
3389
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3390
                }
3391
            }
3392
        }
3393
    }
3394

    
3395
    /* gather all streams */
3396
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3397
        feed = stream->feed;
3398
        if (feed) {
3399
            if (stream->is_feed) {
3400
                for(i=0;i<stream->nb_streams;i++) {
3401
                    stream->feed_streams[i] = i;
3402
                }
3403
            }
3404
        }
3405
    }
3406

    
3407
    /* create feed files if needed */
3408
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3409
        int fd;
3410

    
3411
        if (url_exist(feed->feed_filename)) {
3412
            /* See if it matches */
3413
            AVFormatContext *s;
3414
            int matches = 0;
3415

    
3416
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3417
                /* Now see if it matches */
3418
                if (s->nb_streams == feed->nb_streams) {
3419
                    matches = 1;
3420
                    for(i=0;i<s->nb_streams;i++) {
3421
                        AVStream *sf, *ss;
3422
                        sf = feed->streams[i];
3423
                        ss = s->streams[i];
3424

    
3425
                        if (sf->index != ss->index ||
3426
                            sf->id != ss->id) {
3427
                            printf("Index & Id do not match for stream %d\n", i);
3428
                            matches = 0;
3429
                        } else {
3430
                            AVCodecContext *ccf, *ccs;
3431

    
3432
                            ccf = &sf->codec;
3433
                            ccs = &ss->codec;
3434
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3435

    
3436
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3437
                                printf("Codecs do not match for stream %d\n", i);
3438
                                matches = 0;
3439
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3440
                                printf("Codec bitrates do not match for stream %d\n", i);
3441
                                matches = 0;
3442
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3443
                                if (CHECK_CODEC(frame_rate) ||
3444
                                    CHECK_CODEC(frame_rate_base) ||
3445
                                    CHECK_CODEC(width) ||
3446
                                    CHECK_CODEC(height)) {
3447
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3448
                                    matches = 0;
3449
                                }
3450
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3451
                                if (CHECK_CODEC(sample_rate) ||
3452
                                    CHECK_CODEC(channels) ||
3453
                                    CHECK_CODEC(frame_size)) {
3454
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3455
                                    matches = 0;
3456
                                }
3457
                            } else {
3458
                                printf("Unknown codec type\n");
3459
                                matches = 0;
3460
                            }
3461
                        }
3462
                        if (!matches) {
3463
                            break;
3464
                        }
3465
                    }
3466
                } else {
3467
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3468
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3469
                }
3470

    
3471
                av_close_input_file(s);
3472
            } else {
3473
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3474
                        feed->feed_filename);
3475
            }
3476
            if (!matches) {
3477
                if (feed->readonly) {
3478
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3479
                        feed->feed_filename);
3480
                    exit(1);
3481
                }
3482
                unlink(feed->feed_filename);
3483
            }
3484
        }
3485
        if (!url_exist(feed->feed_filename)) {
3486
            AVFormatContext s1, *s = &s1;
3487

    
3488
            if (feed->readonly) {
3489
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3490
                    feed->feed_filename);
3491
                exit(1);
3492
            }
3493

    
3494
            /* only write the header of the ffm file */
3495
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3496
                fprintf(stderr, "Could not open output feed file '%s'\n",
3497
                        feed->feed_filename);
3498
                exit(1);
3499
            }
3500
            s->oformat = feed->fmt;
3501
            s->nb_streams = feed->nb_streams;
3502
            for(i=0;i<s->nb_streams;i++) {
3503
                AVStream *st;
3504
                st = feed->streams[i];
3505
                s->streams[i] = st;
3506
            }
3507
            av_set_parameters(s, NULL);
3508
            av_write_header(s);
3509
            /* XXX: need better api */
3510
            av_freep(&s->priv_data);
3511
            url_fclose(&s->pb);
3512
        }
3513
        /* get feed size and write index */
3514
        fd = open(feed->feed_filename, O_RDONLY);
3515
        if (fd < 0) {
3516
            fprintf(stderr, "Could not open output feed file '%s'\n",
3517
                    feed->feed_filename);
3518
            exit(1);
3519
        }
3520

    
3521
        feed->feed_write_index = ffm_read_write_index(fd);
3522
        feed->feed_size = lseek(fd, 0, SEEK_END);
3523
        /* ensure that we do not wrap before the end of file */
3524
        if (feed->feed_max_size < feed->feed_size)
3525
            feed->feed_max_size = feed->feed_size;
3526

    
3527
        close(fd);
3528
    }
3529
}
3530

    
3531
/* compute the bandwidth used by each stream */
3532
static void compute_bandwidth(void)
3533
{
3534
    int bandwidth, i;
3535
    FFStream *stream;
3536
    
3537
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3538
        bandwidth = 0;
3539
        for(i=0;i<stream->nb_streams;i++) {
3540
            AVStream *st = stream->streams[i];
3541
            switch(st->codec.codec_type) {
3542
            case CODEC_TYPE_AUDIO:
3543
            case CODEC_TYPE_VIDEO:
3544
                bandwidth += st->codec.bit_rate;
3545
                break;
3546
            default:
3547
                break;
3548
            }
3549
        }
3550
        stream->bandwidth = (bandwidth + 999) / 1000;
3551
    }
3552
}
3553

    
3554
static void get_arg(char *buf, int buf_size, const char **pp)
3555
{
3556
    const char *p;
3557
    char *q;
3558
    int quote;
3559

    
3560
    p = *pp;
3561
    while (isspace(*p)) p++;
3562
    q = buf;
3563
    quote = 0;
3564
    if (*p == '\"' || *p == '\'')
3565
        quote = *p++;
3566
    for(;;) {
3567
        if (quote) {
3568
            if (*p == quote)
3569
                break;
3570
        } else {
3571
            if (isspace(*p))
3572
                break;
3573
        }
3574
        if (*p == '\0')
3575
            break;
3576
        if ((q - buf) < buf_size - 1)
3577
            *q++ = *p;
3578
        p++;
3579
    }
3580
    *q = '\0';
3581
    if (quote && *p == quote)
3582
        p++;
3583
    *pp = p;
3584
}
3585

    
3586
/* add a codec and set the default parameters */
3587
static void add_codec(FFStream *stream, AVCodecContext *av)
3588
{
3589
    AVStream *st;
3590

    
3591
    /* compute default parameters */
3592
    switch(av->codec_type) {
3593
    case CODEC_TYPE_AUDIO:
3594
        if (av->bit_rate == 0)
3595
            av->bit_rate = 64000;
3596
        if (av->sample_rate == 0)
3597
            av->sample_rate = 22050;
3598
        if (av->channels == 0)
3599
            av->channels = 1;
3600
        break;
3601
    case CODEC_TYPE_VIDEO:
3602
        if (av->bit_rate == 0)
3603
            av->bit_rate = 64000;
3604
        if (av->frame_rate == 0){
3605
            av->frame_rate = 5;
3606
            av->frame_rate_base = 1;
3607
        }
3608
        if (av->width == 0 || av->height == 0) {
3609
            av->width = 160;
3610
            av->height = 128;
3611
        }
3612
        /* Bitrate tolerance is less for streaming */
3613
        if (av->bit_rate_tolerance == 0)
3614
            av->bit_rate_tolerance = av->bit_rate / 4;
3615
        if (av->qmin == 0)
3616
            av->qmin = 3;
3617
        if (av->qmax == 0)
3618
            av->qmax = 31;
3619
        if (av->max_qdiff == 0)
3620
            av->max_qdiff = 3;
3621
        av->qcompress = 0.5;
3622
        av->qblur = 0.5;
3623

    
3624
        if (!av->rc_eq)
3625
            av->rc_eq = "tex^qComp";
3626
        if (!av->i_quant_factor)
3627
            av->i_quant_factor = -0.8;
3628
        if (!av->b_quant_factor)
3629
            av->b_quant_factor = 1.25;
3630
        if (!av->b_quant_offset)
3631
            av->b_quant_offset = 1.25;
3632
        if (!av->rc_min_rate)
3633
            av->rc_min_rate = av->bit_rate / 2;
3634
        if (!av->rc_max_rate)
3635
            av->rc_max_rate = av->bit_rate * 2;
3636

    
3637
        break;
3638
    default:
3639
        av_abort();
3640
    }
3641

    
3642
    st = av_mallocz(sizeof(AVStream));
3643
    if (!st)
3644
        return;
3645
    stream->streams[stream->nb_streams++] = st;
3646
    memcpy(&st->codec, av, sizeof(AVCodecContext));
3647
}
3648

    
3649
static int opt_audio_codec(const char *arg)
3650
{
3651
    AVCodec *p;
3652

    
3653
    p = first_avcodec;
3654
    while (p) {
3655
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3656
            break;
3657
        p = p->next;
3658
    }
3659
    if (p == NULL) {
3660
        return CODEC_ID_NONE;
3661
    }
3662

    
3663
    return p->id;
3664
}
3665

    
3666
static int opt_video_codec(const char *arg)
3667
{
3668
    AVCodec *p;
3669

    
3670
    p = first_avcodec;
3671
    while (p) {
3672
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3673
            break;
3674
        p = p->next;
3675
    }
3676
    if (p == NULL) {
3677
        return CODEC_ID_NONE;
3678
    }
3679

    
3680
    return p->id;
3681
}
3682

    
3683
/* simplistic plugin support */
3684

    
3685
#ifdef CONFIG_HAVE_DLOPEN
3686
void load_module(const char *filename)
3687
{
3688
    void *dll;
3689
    void (*init_func)(void);
3690
    dll = dlopen(filename, RTLD_NOW);
3691
    if (!dll) {
3692
        fprintf(stderr, "Could not load module '%s' - %s\n",
3693
                filename, dlerror());
3694
        return;
3695
    }
3696
    
3697
    init_func = dlsym(dll, "ffserver_module_init");
3698
    if (!init_func) {
3699
        fprintf(stderr, 
3700
                "%s: init function 'ffserver_module_init()' not found\n",
3701
                filename);
3702
        dlclose(dll);
3703
    }
3704

    
3705
    init_func();
3706
}
3707
#endif
3708

    
3709
static int parse_ffconfig(const char *filename)
3710
{
3711
    FILE *f;
3712
    char line[1024];
3713
    char cmd[64];
3714
    char arg[1024];
3715
    const char *p;
3716
    int val, errors, line_num;
3717
    FFStream **last_stream, *stream, *redirect;
3718
    FFStream **last_feed, *feed;
3719
    AVCodecContext audio_enc, video_enc;
3720
    int audio_id, video_id;
3721

    
3722
    f = fopen(filename, "r");
3723
    if (!f) {
3724
        perror(filename);
3725
        return -1;
3726
    }
3727
    
3728
    errors = 0;
3729
    line_num = 0;
3730
    first_stream = NULL;
3731
    last_stream = &first_stream;
3732
    first_feed = NULL;
3733
    last_feed = &first_feed;
3734
    stream = NULL;
3735
    feed = NULL;
3736
    redirect = NULL;
3737
    audio_id = CODEC_ID_NONE;
3738
    video_id = CODEC_ID_NONE;
3739
    for(;;) {
3740
        if (fgets(line, sizeof(line), f) == NULL)
3741
            break;
3742
        line_num++;
3743
        p = line;
3744
        while (isspace(*p)) 
3745
            p++;
3746
        if (*p == '\0' || *p == '#')
3747
            continue;
3748

    
3749
        get_arg(cmd, sizeof(cmd), &p);
3750
        
3751
        if (!strcasecmp(cmd, "Port")) {
3752
            get_arg(arg, sizeof(arg), &p);
3753
            my_http_addr.sin_port = htons (atoi(arg));
3754
        } else if (!strcasecmp(cmd, "BindAddress")) {
3755
            get_arg(arg, sizeof(arg), &p);
3756
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3757
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3758
                        filename, line_num, arg);
3759
                errors++;
3760
            }
3761
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3762
            ffserver_daemon = 0;
3763
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3764
            get_arg(arg, sizeof(arg), &p);
3765
            my_rtsp_addr.sin_port = htons (atoi(arg));
3766
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3767
            get_arg(arg, sizeof(arg), &p);
3768
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3769
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3770
                        filename, line_num, arg);
3771
                errors++;
3772
            }
3773
        } else if (!strcasecmp(cmd, "MaxClients")) {
3774
            get_arg(arg, sizeof(arg), &p);
3775
            val = atoi(arg);
3776
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3777
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
3778
                        filename, line_num, arg);
3779
                errors++;
3780
            } else {
3781
                nb_max_connections = val;
3782
            }
3783
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3784
            get_arg(arg, sizeof(arg), &p);
3785
            val = atoi(arg);
3786
            if (val < 10 || val > 100000) {
3787
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
3788
                        filename, line_num, arg);
3789
                errors++;
3790
            } else {
3791
                max_bandwidth = val;
3792
            }
3793
        } else if (!strcasecmp(cmd, "CustomLog")) {
3794
            get_arg(logfilename, sizeof(logfilename), &p);
3795
        } else if (!strcasecmp(cmd, "<Feed")) {
3796
            /*********************************************/
3797
            /* Feed related options */
3798
            char *q;
3799
            if (stream || feed) {
3800
                fprintf(stderr, "%s:%d: Already in a tag\n",
3801
                        filename, line_num);
3802
            } else {
3803
                feed = av_mallocz(sizeof(FFStream));
3804
                /* add in stream list */
3805
                *last_stream = feed;
3806
                last_stream = &feed->next;
3807
                /* add in feed list */
3808
                *last_feed = feed;
3809
                last_feed = &feed->next_feed;
3810
                
3811
                get_arg(feed->filename, sizeof(feed->filename), &p);
3812
                q = strrchr(feed->filename, '>');
3813
                if (*q)
3814
                    *q = '\0';
3815
                feed->fmt = guess_format("ffm", NULL, NULL);
3816
                /* defaut feed file */
3817
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3818
                         "/tmp/%s.ffm", feed->filename);
3819
                feed->feed_max_size = 5 * 1024 * 1024;
3820
                feed->is_feed = 1;
3821
                feed->feed = feed; /* self feeding :-) */
3822
            }
3823
        } else if (!strcasecmp(cmd, "Launch")) {
3824
            if (feed) {
3825
                int i;
3826

    
3827
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3828

    
3829
                feed->child_argv[0] = av_malloc(7);
3830
                strcpy(feed->child_argv[0], "ffmpeg");
3831

    
3832
                for (i = 1; i < 62; i++) {
3833
                    char argbuf[256];
3834

    
3835
                    get_arg(argbuf, sizeof(argbuf), &p);
3836
                    if (!argbuf[0])
3837
                        break;
3838

    
3839
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3840
                    strcpy(feed->child_argv[i], argbuf);
3841
                }
3842

    
3843
                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3844

    
3845
                snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
3846
                    ntohs(my_http_addr.sin_port), feed->filename);
3847
            }
3848
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3849
            if (feed) {
3850
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3851
                feed->readonly = 1;
3852
            } else if (stream) {
3853
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3854
            }
3855
        } else if (!strcasecmp(cmd, "File")) {
3856
            if (feed) {
3857
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3858
            } else if (stream) {
3859
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3860
            }
3861
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3862
            if (feed) {
3863
                const char *p1;
3864
                double fsize;
3865

    
3866
                get_arg(arg, sizeof(arg), &p);
3867
                p1 = arg;
3868
                fsize = strtod(p1, (char **)&p1);
3869
                switch(toupper(*p1)) {
3870
                case 'K':
3871
                    fsize *= 1024;
3872
                    break;
3873
                case 'M':
3874
                    fsize *= 1024 * 1024;
3875
                    break;
3876
                case 'G':
3877
                    fsize *= 1024 * 1024 * 1024;
3878
                    break;
3879
                }
3880
                feed->feed_max_size = (int64_t)fsize;
3881
            }
3882
        } else if (!strcasecmp(cmd, "</Feed>")) {
3883
            if (!feed) {
3884
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3885
                        filename, line_num);
3886
                errors++;
3887
#if 0
3888
            } else {
3889
                /* Make sure that we start out clean */
3890
                if (unlink(feed->feed_filename) < 0 
3891
                    && errno != ENOENT) {
3892
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3893
                        filename, line_num, feed->feed_filename, strerror(errno));
3894
                    errors++;
3895
                }
3896
#endif
3897
            }
3898
            feed = NULL;
3899
        } else if (!strcasecmp(cmd, "<Stream")) {
3900
            /*********************************************/
3901
            /* Stream related options */
3902
            char *q;
3903
            if (stream || feed) {
3904
                fprintf(stderr, "%s:%d: Already in a tag\n",
3905
                        filename, line_num);
3906
            } else {
3907
                stream = av_mallocz(sizeof(FFStream));
3908
                *last_stream = stream;
3909
                last_stream = &stream->next;
3910

    
3911
                get_arg(stream->filename, sizeof(stream->filename), &p);
3912
                q = strrchr(stream->filename, '>');
3913
                if (*q)
3914
                    *q = '\0';
3915
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3916
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3917
                memset(&video_enc, 0, sizeof(AVCodecContext));
3918
                audio_id = CODEC_ID_NONE;
3919
                video_id = CODEC_ID_NONE;
3920
                if (stream->fmt) {
3921
                    audio_id = stream->fmt->audio_codec;
3922
                    video_id = stream->fmt->video_codec;
3923
                }
3924
            }
3925
        } else if (!strcasecmp(cmd, "Feed")) {
3926
            get_arg(arg, sizeof(arg), &p);
3927
            if (stream) {
3928
                FFStream *sfeed;
3929
                
3930
                sfeed = first_feed;
3931
                while (sfeed != NULL) {
3932
                    if (!strcmp(sfeed->filename, arg))
3933
                        break;
3934
                    sfeed = sfeed->next_feed;
3935
                }
3936
                if (!sfeed) {
3937
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3938
                            filename, line_num, arg);
3939
                } else {
3940
                    stream->feed = sfeed;
3941
                }
3942
            }
3943
        } else if (!strcasecmp(cmd, "Format")) {
3944
            get_arg(arg, sizeof(arg), &p);
3945
            if (!strcmp(arg, "status")) {
3946
                stream->stream_type = STREAM_TYPE_STATUS;
3947
                stream->fmt = NULL;
3948
            } else {
3949
                stream->stream_type = STREAM_TYPE_LIVE;
3950
                /* jpeg cannot be used here, so use single frame jpeg */
3951
                if (!strcmp(arg, "jpeg"))
3952
                    strcpy(arg, "singlejpeg");
3953
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3954
                if (!stream->fmt) {
3955
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
3956
                            filename, line_num, arg);
3957
                    errors++;
3958
                }
3959
            }
3960
            if (stream->fmt) {
3961
                audio_id = stream->fmt->audio_codec;
3962
                video_id = stream->fmt->video_codec;
3963
            }
3964
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3965
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3966
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3967
            } else {
3968
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
3969
                            filename, line_num);
3970
                errors++;
3971
            }
3972
        } else if (!strcasecmp(cmd, "Author")) {
3973
            if (stream) {
3974
                get_arg(stream->author, sizeof(stream->author), &p);
3975
            }
3976
        } else if (!strcasecmp(cmd, "Comment")) {
3977
            if (stream) {
3978
                get_arg(stream->comment, sizeof(stream->comment), &p);
3979
            }
3980
        } else if (!strcasecmp(cmd, "Copyright")) {
3981
            if (stream) {
3982
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
3983
            }
3984
        } else if (!strcasecmp(cmd, "Title")) {
3985
            if (stream) {
3986
                get_arg(stream->title, sizeof(stream->title), &p);
3987
            }
3988
        } else if (!strcasecmp(cmd, "Preroll")) {
3989
            get_arg(arg, sizeof(arg), &p);
3990
            if (stream) {
3991
                stream->prebuffer = atof(arg) * 1000;
3992
            }
3993
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
3994
            if (stream) {
3995
                stream->send_on_key = 1;
3996
            }
3997
        } else if (!strcasecmp(cmd, "AudioCodec")) {
3998
            get_arg(arg, sizeof(arg), &p);
3999
            audio_id = opt_audio_codec(arg);
4000
            if (audio_id == CODEC_ID_NONE) {
4001
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
4002
                        filename, line_num, arg);
4003
                errors++;
4004
            }
4005
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4006
            get_arg(arg, sizeof(arg), &p);
4007
            video_id = opt_video_codec(arg);
4008
            if (video_id == CODEC_ID_NONE) {
4009
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
4010
                        filename, line_num, arg);
4011
                errors++;
4012
            }
4013
        } else if (!strcasecmp(cmd, "MaxTime")) {
4014
            get_arg(arg, sizeof(arg), &p);
4015
            if (stream) {
4016
                stream->max_time = atof(arg) * 1000;
4017
            }
4018
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4019
            get_arg(arg, sizeof(arg), &p);
4020
            if (stream) {
4021
                audio_enc.bit_rate = atoi(arg) * 1000;
4022
            }
4023
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4024
            get_arg(arg, sizeof(arg), &p);
4025
            if (stream) {
4026
                audio_enc.channels = atoi(arg);
4027
            }
4028
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4029
            get_arg(arg, sizeof(arg), &p);
4030
            if (stream) {
4031
                audio_enc.sample_rate = atoi(arg);
4032
            }
4033
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4034
            get_arg(arg, sizeof(arg), &p);
4035
            if (stream) {
4036
//                audio_enc.quality = atof(arg) * 1000;
4037
            }
4038
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4039
            if (stream) {
4040
                int minrate, maxrate;
4041

    
4042
                get_arg(arg, sizeof(arg), &p);
4043

    
4044
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4045
                    video_enc.rc_min_rate = minrate * 1000;
4046
                    video_enc.rc_max_rate = maxrate * 1000;
4047
                } else {
4048
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", 
4049
                            filename, line_num, arg);
4050
                    errors++;
4051
                }
4052
            }
4053
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4054
            if (stream) {
4055
                get_arg(arg, sizeof(arg), &p);
4056
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4057
            }
4058
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4059
            get_arg(arg, sizeof(arg), &p);
4060
            if (stream) {
4061
                video_enc.bit_rate = atoi(arg) * 1000;
4062
            }
4063
        } else if (!strcasecmp(cmd, "VideoSize")) {
4064
            get_arg(arg, sizeof(arg), &p);
4065
            if (stream) {
4066
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4067
                if ((video_enc.width % 16) != 0 ||
4068
                    (video_enc.height % 16) != 0) {
4069
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4070
                            filename, line_num);
4071
                    errors++;
4072
                }
4073
            }
4074
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4075
            get_arg(arg, sizeof(arg), &p);
4076
            if (stream) {
4077
                video_enc.frame_rate_base= DEFAULT_FRAME_RATE_BASE;
4078
                video_enc.frame_rate = (int)(strtod(arg, NULL) * video_enc.frame_rate_base);
4079
            }
4080
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4081
            get_arg(arg, sizeof(arg), &p);
4082
            if (stream) {
4083
                video_enc.gop_size = atoi(arg);
4084
            }
4085
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4086
            if (stream) {
4087
                video_enc.gop_size = 1;
4088
            }
4089
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4090
            if (stream) {
4091
                video_enc.flags |= CODEC_FLAG_HQ;
4092
            }
4093
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4094
            if (stream) {
4095
                video_enc.flags |= CODEC_FLAG_HQ;
4096
                video_enc.flags |= CODEC_FLAG_4MV;
4097
            }
4098
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4099
            get_arg(arg, sizeof(arg), &p);
4100
            if (stream) {
4101
                video_enc.max_qdiff = atoi(arg);
4102
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4103
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4104
                            filename, line_num);
4105
                    errors++;
4106
                }
4107
            }
4108
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4109
            get_arg(arg, sizeof(arg), &p);
4110
            if (stream) {
4111
                video_enc.qmax = atoi(arg);
4112
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4113
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4114
                            filename, line_num);
4115
                    errors++;
4116
                }
4117
            }
4118
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4119
            get_arg(arg, sizeof(arg), &p);
4120
            if (stream) {
4121
                video_enc.qmin = atoi(arg);
4122
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4123
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4124
                            filename, line_num);
4125
                    errors++;
4126
                }
4127
            }
4128
        } else if (!strcasecmp(cmd, "LumaElim")) {
4129
            get_arg(arg, sizeof(arg), &p);
4130
            if (stream) {
4131
                video_enc.luma_elim_threshold = atoi(arg);
4132
            }
4133
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4134
            get_arg(arg, sizeof(arg), &p);
4135
            if (stream) {
4136
                video_enc.chroma_elim_threshold = atoi(arg);
4137
            }
4138
        } else if (!strcasecmp(cmd, "LumiMask")) {
4139
            get_arg(arg, sizeof(arg), &p);
4140
            if (stream) {
4141
                video_enc.lumi_masking = atof(arg);
4142
            }
4143
        } else if (!strcasecmp(cmd, "DarkMask")) {
4144
            get_arg(arg, sizeof(arg), &p);
4145
            if (stream) {
4146
                video_enc.dark_masking = atof(arg);
4147
            }
4148
        } else if (!strcasecmp(cmd, "NoVideo")) {
4149
            video_id = CODEC_ID_NONE;
4150
        } else if (!strcasecmp(cmd, "NoAudio")) {
4151
            audio_id = CODEC_ID_NONE;
4152
        } else if (!strcasecmp(cmd, "ACL")) {
4153
            IPAddressACL acl;
4154
            struct hostent *he;
4155

    
4156
            get_arg(arg, sizeof(arg), &p);
4157
            if (strcasecmp(arg, "allow") == 0) {
4158
                acl.action = IP_ALLOW;
4159
            } else if (strcasecmp(arg, "deny") == 0) {
4160
                acl.action = IP_DENY;
4161
            } else {
4162
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4163
                        filename, line_num, arg);
4164
                errors++;
4165
            }
4166

    
4167
            get_arg(arg, sizeof(arg), &p);
4168

    
4169
            he = gethostbyname(arg);
4170
            if (!he) {
4171
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4172
                        filename, line_num, arg);
4173
                errors++;
4174
            } else {
4175
                /* Only take the first */
4176
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4177
                acl.last = acl.first;
4178
            }
4179

    
4180
            get_arg(arg, sizeof(arg), &p);
4181

    
4182
            if (arg[0]) {
4183
                he = gethostbyname(arg);
4184
                if (!he) {
4185
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4186
                            filename, line_num, arg);
4187
                    errors++;
4188
                } else {
4189
                    /* Only take the first */
4190
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4191
                }
4192
            }
4193

    
4194
            if (!errors) {
4195
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4196
                IPAddressACL **naclp = 0;
4197

    
4198
                *nacl = acl;
4199
                nacl->next = 0;
4200

    
4201
                if (stream) {
4202
                    naclp = &stream->acl;
4203
                } else if (feed) {
4204
                    naclp = &feed->acl;
4205
                } else {
4206
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4207
                            filename, line_num);
4208
                    errors++;
4209
                }
4210

    
4211
                if (naclp) {
4212
                    while (*naclp)
4213
                        naclp = &(*naclp)->next;
4214

    
4215
                    *naclp = nacl;
4216
                }
4217
            }
4218
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4219
            get_arg(arg, sizeof(arg), &p);
4220
            if (stream) {
4221
                av_freep(&stream->rtsp_option);
4222
                /* XXX: av_strdup ? */
4223
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4224
                if (stream->rtsp_option) {
4225
                    strcpy(stream->rtsp_option, arg);
4226
                }
4227
            }
4228
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4229
            get_arg(arg, sizeof(arg), &p);
4230
            if (stream) {
4231
                if (!inet_aton(arg, &stream->multicast_ip)) {
4232
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
4233
                            filename, line_num, arg);
4234
                    errors++;
4235
                }
4236
                stream->is_multicast = 1;
4237
                stream->loop = 1; /* default is looping */
4238
            }
4239
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4240
            get_arg(arg, sizeof(arg), &p);
4241
            if (stream) {
4242
                stream->multicast_port = atoi(arg);
4243
            }
4244
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4245
            get_arg(arg, sizeof(arg), &p);
4246
            if (stream) {
4247
                stream->multicast_ttl = atoi(arg);
4248
            }
4249
        } else if (!strcasecmp(cmd, "NoLoop")) {
4250
            if (stream) {
4251
                stream->loop = 0;
4252
            }
4253
        } else if (!strcasecmp(cmd, "</Stream>")) {
4254
            if (!stream) {
4255
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4256
                        filename, line_num);
4257
                errors++;
4258
            }
4259
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4260
                if (audio_id != CODEC_ID_NONE) {
4261
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4262
                    audio_enc.codec_id = audio_id;
4263
                    add_codec(stream, &audio_enc);
4264
                }
4265
                if (video_id != CODEC_ID_NONE) {
4266
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4267
                    video_enc.codec_id = video_id;
4268
                    add_codec(stream, &video_enc);
4269
                }
4270
            }
4271
            stream = NULL;
4272
        } else if (!strcasecmp(cmd, "<Redirect")) {
4273
            /*********************************************/
4274
            char *q;
4275
            if (stream || feed || redirect) {
4276
                fprintf(stderr, "%s:%d: Already in a tag\n",
4277
                        filename, line_num);
4278
                errors++;
4279
            } else {
4280
                redirect = av_mallocz(sizeof(FFStream));
4281
                *last_stream = redirect;
4282
                last_stream = &redirect->next;
4283

    
4284
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4285
                q = strrchr(redirect->filename, '>');
4286
                if (*q)
4287
                    *q = '\0';
4288
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4289
            }
4290
        } else if (!strcasecmp(cmd, "URL")) {
4291
            if (redirect) {
4292
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4293
            }
4294
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4295
            if (!redirect) {
4296
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4297
                        filename, line_num);
4298
                errors++;
4299
            }
4300
            if (!redirect->feed_filename[0]) {
4301
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4302
                        filename, line_num);
4303
                errors++;
4304
            }
4305
            redirect = NULL;
4306
        } else if (!strcasecmp(cmd, "LoadModule")) {
4307
            get_arg(arg, sizeof(arg), &p);
4308
#ifdef CONFIG_HAVE_DLOPEN
4309
            load_module(arg);
4310
#else
4311
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n", 
4312
                    filename, line_num, arg);
4313
            errors++;
4314
#endif
4315
        } else {
4316
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
4317
                    filename, line_num, cmd);
4318
            errors++;
4319
        }
4320
    }
4321

    
4322
    fclose(f);
4323
    if (errors)
4324
        return -1;
4325
    else
4326
        return 0;
4327
}
4328

    
4329

    
4330
#if 0
4331
static void write_packet(FFCodec *ffenc,
4332
                         uint8_t *buf, int size)
4333
{
4334
    PacketHeader hdr;
4335
    AVCodecContext *enc = &ffenc->enc;
4336
    uint8_t *wptr;
4337
    mk_header(&hdr, enc, size);
4338
    wptr = http_fifo.wptr;
4339
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4340
    fifo_write(&http_fifo, buf, size, &wptr);
4341
    /* atomic modification of wptr */
4342
    http_fifo.wptr = wptr;
4343
    ffenc->data_count += size;
4344
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4345
}
4346
#endif
4347

    
4348
static void help(void)
4349
{
4350
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
4351
           "usage: ffserver [-L] [-h] [-f configfile]\n"
4352
           "Hyper fast multi format Audio/Video streaming server\n"
4353
           "\n"
4354
           "-L            : print the LICENCE\n"
4355
           "-h            : this help\n"
4356
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4357
           );
4358
}
4359

    
4360
static void licence(void)
4361
{
4362
    printf(
4363
    "ffserver version " FFMPEG_VERSION "\n"
4364
    "Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
4365
    "This library is free software; you can redistribute it and/or\n"
4366
    "modify it under the terms of the GNU Lesser General Public\n"
4367
    "License as published by the Free Software Foundation; either\n"
4368
    "version 2 of the License, or (at your option) any later version.\n"
4369
    "\n"
4370
    "This library is distributed in the hope that it will be useful,\n"
4371
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4372
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4373
    "Lesser General Public License for more details.\n"
4374
    "\n"
4375
    "You should have received a copy of the GNU Lesser General Public\n"
4376
    "License along with this library; if not, write to the Free Software\n"
4377
    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4378
    );
4379
}
4380

    
4381
static void handle_child_exit(int sig)
4382
{
4383
    pid_t pid;
4384
    int status;
4385

    
4386
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4387
        FFStream *feed;
4388

    
4389
        for (feed = first_feed; feed; feed = feed->next) {
4390
            if (feed->pid == pid) {
4391
                int uptime = time(0) - feed->pid_start;
4392

    
4393
                feed->pid = 0;
4394
                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4395

    
4396
                if (uptime < 30) {
4397
                    /* Turn off any more restarts */
4398
                    feed->child_argv = 0;
4399
                }    
4400
            }
4401
        }
4402
    }
4403

    
4404
    need_to_start_children = 1;
4405
}
4406

    
4407
int main(int argc, char **argv)
4408
{
4409
    const char *config_filename;
4410
    int c;
4411
    struct sigaction sigact;
4412

    
4413
    av_register_all();
4414

    
4415
    config_filename = "/etc/ffserver.conf";
4416

    
4417
    my_program_name = argv[0];
4418
    my_program_dir = getcwd(0, 0);
4419
    ffserver_daemon = 1;
4420
    
4421
    for(;;) {
4422
        c = getopt(argc, argv, "ndLh?f:");
4423
        if (c == -1)
4424
            break;
4425
        switch(c) {
4426
        case 'L':
4427
            licence();
4428
            exit(1);
4429
        case '?':
4430
        case 'h':
4431
            help();
4432
            exit(1);
4433
        case 'n':
4434
            no_launch = 1;
4435
            break;
4436
        case 'd':
4437
            ffserver_debug = 1;
4438
            ffserver_daemon = 0;
4439
            break;
4440
        case 'f':
4441
            config_filename = optarg;
4442
            break;
4443
        default:
4444
            exit(2);
4445
        }
4446
    }
4447

    
4448
    putenv("http_proxy");               /* Kill the http_proxy */
4449

    
4450
    srandom(gettime_ms() + (getpid() << 16));
4451

    
4452
    /* address on which the server will handle HTTP connections */
4453
    my_http_addr.sin_family = AF_INET;
4454
    my_http_addr.sin_port = htons (8080);
4455
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4456

    
4457
    /* address on which the server will handle RTSP connections */
4458
    my_rtsp_addr.sin_family = AF_INET;
4459
    my_rtsp_addr.sin_port = htons (5454);
4460
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4461
    
4462
    nb_max_connections = 5;
4463
    max_bandwidth = 1000;
4464
    first_stream = NULL;
4465
    logfilename[0] = '\0';
4466

    
4467
    memset(&sigact, 0, sizeof(sigact));
4468
    sigact.sa_handler = handle_child_exit;
4469
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4470
    sigaction(SIGCHLD, &sigact, 0);
4471

    
4472
    if (parse_ffconfig(config_filename) < 0) {
4473
        fprintf(stderr, "Incorrect config file - exiting.\n");
4474
        exit(1);
4475
    }
4476

    
4477
    build_file_streams();
4478

    
4479
    build_feed_streams();
4480

    
4481
    compute_bandwidth();
4482

    
4483
    /* put the process in background and detach it from its TTY */
4484
    if (ffserver_daemon) {
4485
        int pid;
4486

    
4487
        pid = fork();
4488
        if (pid < 0) {
4489
            perror("fork");
4490
            exit(1);
4491
        } else if (pid > 0) {
4492
            /* parent : exit */
4493
            exit(0);
4494
        } else {
4495
            /* child */
4496
            setsid();
4497
            chdir("/");
4498
            close(0);
4499
            open("/dev/null", O_RDWR);
4500
            if (strcmp(logfilename, "-") != 0) {
4501
                close(1);
4502
                dup(0);
4503
            }
4504
            close(2);
4505
            dup(0);
4506
        }
4507
    }
4508

    
4509
    /* signal init */
4510
    signal(SIGPIPE, SIG_IGN);
4511

    
4512
    /* open log file if needed */
4513
    if (logfilename[0] != '\0') {
4514
        if (!strcmp(logfilename, "-"))
4515
            logfile = stdout;
4516
        else
4517
            logfile = fopen(logfilename, "w");
4518
    }
4519

    
4520
    if (http_server() < 0) {
4521
        fprintf(stderr, "Could not start server\n");
4522
        exit(1);
4523
    }
4524

    
4525
    return 0;
4526
}