~noskcaj/ubuntu/saucy/libav/merge0.8.7-1

« back to all changes in this revision

Viewing changes to avserver.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2012-01-12 22:30:00 UTC
  • mfrom: (1.2.8) (1.1.13 experimental)
  • Revision ID: package-import@ubuntu.com-20120112223000-cmfo7w78q13i2fd9
Tags: 4:0.8~beta2-1ubuntu1
* Merge from debian, remaining changes:
  - don't build against libdirac, lame, libopenjpeg, librtmp, 
    x264, and xvid  (all in universe)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Multiple format streaming server
 
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
 
4
 *
 
5
 * This file is part of Libav.
 
6
 *
 
7
 * Libav is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU Lesser General Public
 
9
 * License as published by the Free Software Foundation; either
 
10
 * version 2.1 of the License, or (at your option) any later version.
 
11
 *
 
12
 * Libav is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Lesser General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU Lesser General Public
 
18
 * License along with Libav; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
#if !HAVE_CLOSESOCKET
 
24
#define closesocket close
 
25
#endif
 
26
#include <string.h>
 
27
#include <stdlib.h>
 
28
#include "libavformat/avformat.h"
 
29
#include "libavformat/ffm.h"
 
30
#include "libavformat/network.h"
 
31
#include "libavformat/os_support.h"
 
32
#include "libavformat/rtpdec.h"
 
33
#include "libavformat/rtsp.h"
 
34
// XXX for ffio_open_dyn_packet_buffer, to be removed
 
35
#include "libavformat/avio_internal.h"
 
36
#include "libavutil/avstring.h"
 
37
#include "libavutil/lfg.h"
 
38
#include "libavutil/dict.h"
 
39
#include "libavutil/mathematics.h"
 
40
#include "libavutil/random_seed.h"
 
41
#include "libavutil/parseutils.h"
 
42
#include "libavutil/opt.h"
 
43
#include <stdarg.h>
 
44
#include <unistd.h>
 
45
#include <fcntl.h>
 
46
#include <sys/ioctl.h>
 
47
#if HAVE_POLL_H
 
48
#include <poll.h>
 
49
#endif
 
50
#include <errno.h>
 
51
#include <sys/time.h>
 
52
#include <time.h>
 
53
#include <sys/wait.h>
 
54
#include <signal.h>
 
55
#if HAVE_DLFCN_H
 
56
#include <dlfcn.h>
 
57
#endif
 
58
 
 
59
#include "cmdutils.h"
 
60
 
 
61
const char program_name[] = "avserver";
 
62
const int program_birth_year = 2000;
 
63
 
 
64
static const OptionDef options[];
 
65
 
 
66
enum HTTPState {
 
67
    HTTPSTATE_WAIT_REQUEST,
 
68
    HTTPSTATE_SEND_HEADER,
 
69
    HTTPSTATE_SEND_DATA_HEADER,
 
70
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
 
71
    HTTPSTATE_SEND_DATA_TRAILER,
 
72
    HTTPSTATE_RECEIVE_DATA,
 
73
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
 
74
    HTTPSTATE_READY,
 
75
 
 
76
    RTSPSTATE_WAIT_REQUEST,
 
77
    RTSPSTATE_SEND_REPLY,
 
78
    RTSPSTATE_SEND_PACKET,
 
79
};
 
80
 
 
81
static const char *http_state[] = {
 
82
    "HTTP_WAIT_REQUEST",
 
83
    "HTTP_SEND_HEADER",
 
84
 
 
85
    "SEND_DATA_HEADER",
 
86
    "SEND_DATA",
 
87
    "SEND_DATA_TRAILER",
 
88
    "RECEIVE_DATA",
 
89
    "WAIT_FEED",
 
90
    "READY",
 
91
 
 
92
    "RTSP_WAIT_REQUEST",
 
93
    "RTSP_SEND_REPLY",
 
94
    "RTSP_SEND_PACKET",
 
95
};
 
96
 
 
97
#define MAX_STREAMS 20
 
98
 
 
99
#define IOBUFFER_INIT_SIZE 8192
 
100
 
 
101
/* timeouts are in ms */
 
102
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
 
103
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
 
104
 
 
105
#define SYNC_TIMEOUT (10 * 1000)
 
106
 
 
107
typedef struct RTSPActionServerSetup {
 
108
    uint32_t ipaddr;
 
109
    char transport_option[512];
 
110
} RTSPActionServerSetup;
 
111
 
 
112
typedef struct {
 
113
    int64_t count1, count2;
 
114
    int64_t time1, time2;
 
115
} DataRateData;
 
116
 
 
117
/* context associated with one connection */
 
118
typedef struct HTTPContext {
 
119
    enum HTTPState state;
 
120
    int fd; /* socket file descriptor */
 
121
    struct sockaddr_in from_addr; /* origin */
 
122
    struct pollfd *poll_entry; /* used when polling */
 
123
    int64_t timeout;
 
124
    uint8_t *buffer_ptr, *buffer_end;
 
125
    int http_error;
 
126
    int post;
 
127
    int chunked_encoding;
 
128
    int chunk_size;               /* 0 if it needs to be read */
 
129
    struct HTTPContext *next;
 
130
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
 
131
    int64_t data_count;
 
132
    /* feed input */
 
133
    int feed_fd;
 
134
    /* input format handling */
 
135
    AVFormatContext *fmt_in;
 
136
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
 
137
    int64_t first_pts;            /* initial pts value */
 
138
    int64_t cur_pts;             /* current pts value from the stream in us */
 
139
    int64_t cur_frame_duration;  /* duration of the current frame in us */
 
140
    int cur_frame_bytes;       /* output frame size, needed to compute
 
141
                                  the time at which we send each
 
142
                                  packet */
 
143
    int pts_stream_index;        /* stream we choose as clock reference */
 
144
    int64_t cur_clock;           /* current clock reference value in us */
 
145
    /* output format handling */
 
146
    struct FFStream *stream;
 
147
    /* -1 is invalid stream */
 
148
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
 
149
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
 
150
    int switch_pending;
 
151
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
 
152
    int last_packet_sent; /* true if last data packet was sent */
 
153
    int suppress_log;
 
154
    DataRateData datarate;
 
155
    int wmp_client_id;
 
156
    char protocol[16];
 
157
    char method[16];
 
158
    char url[128];
 
159
    int buffer_size;
 
160
    uint8_t *buffer;
 
161
    int is_packetized; /* if true, the stream is packetized */
 
162
    int packet_stream_index; /* current stream for output in state machine */
 
163
 
 
164
    /* RTSP state specific */
 
165
    uint8_t *pb_buffer; /* XXX: use that in all the code */
 
166
    AVIOContext *pb;
 
167
    int seq; /* RTSP sequence number */
 
168
 
 
169
    /* RTP state specific */
 
170
    enum RTSPLowerTransport rtp_protocol;
 
171
    char session_id[32]; /* session id */
 
172
    AVFormatContext *rtp_ctx[MAX_STREAMS];
 
173
 
 
174
    /* RTP/UDP specific */
 
175
    URLContext *rtp_handles[MAX_STREAMS];
 
176
 
 
177
    /* RTP/TCP specific */
 
178
    struct HTTPContext *rtsp_c;
 
179
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
 
180
} HTTPContext;
 
181
 
 
182
/* each generated stream is described here */
 
183
enum StreamType {
 
184
    STREAM_TYPE_LIVE,
 
185
    STREAM_TYPE_STATUS,
 
186
    STREAM_TYPE_REDIRECT,
 
187
};
 
188
 
 
189
enum IPAddressAction {
 
190
    IP_ALLOW = 1,
 
191
    IP_DENY,
 
192
};
 
193
 
 
194
typedef struct IPAddressACL {
 
195
    struct IPAddressACL *next;
 
196
    enum IPAddressAction action;
 
197
    /* These are in host order */
 
198
    struct in_addr first;
 
199
    struct in_addr last;
 
200
} IPAddressACL;
 
201
 
 
202
/* description of each stream of the avserver.conf file */
 
203
typedef struct FFStream {
 
204
    enum StreamType stream_type;
 
205
    char filename[1024];     /* stream filename */
 
206
    struct FFStream *feed;   /* feed we are using (can be null if
 
207
                                coming from file) */
 
208
    AVDictionary *in_opts;   /* input parameters */
 
209
    AVInputFormat *ifmt;       /* if non NULL, force input format */
 
210
    AVOutputFormat *fmt;
 
211
    IPAddressACL *acl;
 
212
    char dynamic_acl[1024];
 
213
    int nb_streams;
 
214
    int prebuffer;      /* Number of millseconds early to start */
 
215
    int64_t max_time;      /* Number of milliseconds to run */
 
216
    int send_on_key;
 
217
    AVStream *streams[MAX_STREAMS];
 
218
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
 
219
    char feed_filename[1024]; /* file name of the feed storage, or
 
220
                                 input file name for a stream */
 
221
    char author[512];
 
222
    char title[512];
 
223
    char copyright[512];
 
224
    char comment[512];
 
225
    pid_t pid;  /* of avconv process */
 
226
    time_t pid_start;  /* of avconv process */
 
227
    char **child_argv;
 
228
    struct FFStream *next;
 
229
    unsigned bandwidth; /* bandwidth, in kbits/s */
 
230
    /* RTSP options */
 
231
    char *rtsp_option;
 
232
    /* multicast specific */
 
233
    int is_multicast;
 
234
    struct in_addr multicast_ip;
 
235
    int multicast_port; /* first port used for multicast */
 
236
    int multicast_ttl;
 
237
    int loop; /* if true, send the stream in loops (only meaningful if file) */
 
238
 
 
239
    /* feed specific */
 
240
    int feed_opened;     /* true if someone is writing to the feed */
 
241
    int is_feed;         /* true if it is a feed */
 
242
    int readonly;        /* True if writing is prohibited to the file */
 
243
    int truncate;        /* True if feeder connection truncate the feed file */
 
244
    int conns_served;
 
245
    int64_t bytes_served;
 
246
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
 
247
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
 
248
    int64_t feed_size;          /* current size of feed */
 
249
    struct FFStream *next_feed;
 
250
} FFStream;
 
251
 
 
252
typedef struct FeedData {
 
253
    long long data_count;
 
254
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
 
255
} FeedData;
 
256
 
 
257
static struct sockaddr_in my_http_addr;
 
258
static struct sockaddr_in my_rtsp_addr;
 
259
 
 
260
static char logfilename[1024];
 
261
static HTTPContext *first_http_ctx;
 
262
static FFStream *first_feed;   /* contains only feeds */
 
263
static FFStream *first_stream; /* contains all streams, including feeds */
 
264
 
 
265
static void new_connection(int server_fd, int is_rtsp);
 
266
static void close_connection(HTTPContext *c);
 
267
 
 
268
/* HTTP handling */
 
269
static int handle_connection(HTTPContext *c);
 
270
static int http_parse_request(HTTPContext *c);
 
271
static int http_send_data(HTTPContext *c);
 
272
static void compute_status(HTTPContext *c);
 
273
static int open_input_stream(HTTPContext *c, const char *info);
 
274
static int http_start_receive_data(HTTPContext *c);
 
275
static int http_receive_data(HTTPContext *c);
 
276
 
 
277
/* RTSP handling */
 
278
static int rtsp_parse_request(HTTPContext *c);
 
279
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
 
280
static void rtsp_cmd_options(HTTPContext *c, const char *url);
 
281
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
 
282
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
 
283
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
 
284
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
 
285
 
 
286
/* SDP handling */
 
287
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
 
288
                                   struct in_addr my_ip);
 
289
 
 
290
/* RTP handling */
 
291
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
 
292
                                       FFStream *stream, const char *session_id,
 
293
                                       enum RTSPLowerTransport rtp_protocol);
 
294
static int rtp_new_av_stream(HTTPContext *c,
 
295
                             int stream_index, struct sockaddr_in *dest_addr,
 
296
                             HTTPContext *rtsp_c);
 
297
 
 
298
static const char *my_program_name;
 
299
static const char *my_program_dir;
 
300
 
 
301
static const char *config_filename = "/etc/avserver.conf";
 
302
 
 
303
static int avserver_debug;
 
304
static int avserver_daemon;
 
305
static int no_launch;
 
306
static int need_to_start_children;
 
307
 
 
308
/* maximum number of simultaneous HTTP connections */
 
309
static unsigned int nb_max_http_connections = 2000;
 
310
static unsigned int nb_max_connections = 5;
 
311
static unsigned int nb_connections;
 
312
 
 
313
static uint64_t max_bandwidth = 1000;
 
314
static uint64_t current_bandwidth;
 
315
 
 
316
static int64_t cur_time;           // Making this global saves on passing it around everywhere
 
317
 
 
318
static AVLFG random_state;
 
319
 
 
320
static FILE *logfile = NULL;
 
321
 
 
322
void exit_program(int ret)
 
323
{
 
324
    exit(ret);
 
325
}
 
326
 
 
327
/* FIXME: make avserver work with IPv6 */
 
328
/* resolve host with also IP address parsing */
 
329
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
 
330
{
 
331
 
 
332
    if (!ff_inet_aton(hostname, sin_addr)) {
 
333
#if HAVE_GETADDRINFO
 
334
        struct addrinfo *ai, *cur;
 
335
        struct addrinfo hints;
 
336
        memset(&hints, 0, sizeof(hints));
 
337
        hints.ai_family = AF_INET;
 
338
        if (getaddrinfo(hostname, NULL, &hints, &ai))
 
339
            return -1;
 
340
        /* getaddrinfo returns a linked list of addrinfo structs.
 
341
         * Even if we set ai_family = AF_INET above, make sure
 
342
         * that the returned one actually is of the correct type. */
 
343
        for (cur = ai; cur; cur = cur->ai_next) {
 
344
            if (cur->ai_family == AF_INET) {
 
345
                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
 
346
                freeaddrinfo(ai);
 
347
                return 0;
 
348
            }
 
349
        }
 
350
        freeaddrinfo(ai);
 
351
        return -1;
 
352
#else
 
353
        struct hostent *hp;
 
354
        hp = gethostbyname(hostname);
 
355
        if (!hp)
 
356
            return -1;
 
357
        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
 
358
#endif
 
359
    }
 
360
    return 0;
 
361
}
 
362
 
 
363
static char *ctime1(char *buf2)
 
364
{
 
365
    time_t ti;
 
366
    char *p;
 
367
 
 
368
    ti = time(NULL);
 
369
    p = ctime(&ti);
 
370
    strcpy(buf2, p);
 
371
    p = buf2 + strlen(p) - 1;
 
372
    if (*p == '\n')
 
373
        *p = '\0';
 
374
    return buf2;
 
375
}
 
376
 
 
377
static void http_vlog(const char *fmt, va_list vargs)
 
378
{
 
379
    static int print_prefix = 1;
 
380
    if (logfile) {
 
381
        if (print_prefix) {
 
382
            char buf[32];
 
383
            ctime1(buf);
 
384
            fprintf(logfile, "%s ", buf);
 
385
        }
 
386
        print_prefix = strstr(fmt, "\n") != NULL;
 
387
        vfprintf(logfile, fmt, vargs);
 
388
        fflush(logfile);
 
389
    }
 
390
}
 
391
 
 
392
#ifdef __GNUC__
 
393
__attribute__ ((format (printf, 1, 2)))
 
394
#endif
 
395
static void http_log(const char *fmt, ...)
 
396
{
 
397
    va_list vargs;
 
398
    va_start(vargs, fmt);
 
399
    http_vlog(fmt, vargs);
 
400
    va_end(vargs);
 
401
}
 
402
 
 
403
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
 
404
{
 
405
    static int print_prefix = 1;
 
406
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
 
407
    if (level > av_log_get_level())
 
408
        return;
 
409
    if (print_prefix && avc)
 
410
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
 
411
    print_prefix = strstr(fmt, "\n") != NULL;
 
412
    http_vlog(fmt, vargs);
 
413
}
 
414
 
 
415
static void log_connection(HTTPContext *c)
 
416
{
 
417
    if (c->suppress_log)
 
418
        return;
 
419
 
 
420
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
 
421
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
 
422
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
 
423
}
 
424
 
 
425
static void update_datarate(DataRateData *drd, int64_t count)
 
426
{
 
427
    if (!drd->time1 && !drd->count1) {
 
428
        drd->time1 = drd->time2 = cur_time;
 
429
        drd->count1 = drd->count2 = count;
 
430
    } else if (cur_time - drd->time2 > 5000) {
 
431
        drd->time1 = drd->time2;
 
432
        drd->count1 = drd->count2;
 
433
        drd->time2 = cur_time;
 
434
        drd->count2 = count;
 
435
    }
 
436
}
 
437
 
 
438
/* In bytes per second */
 
439
static int compute_datarate(DataRateData *drd, int64_t count)
 
440
{
 
441
    if (cur_time == drd->time1)
 
442
        return 0;
 
443
 
 
444
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
 
445
}
 
446
 
 
447
 
 
448
static void start_children(FFStream *feed)
 
449
{
 
450
    if (no_launch)
 
451
        return;
 
452
 
 
453
    for (; feed; feed = feed->next) {
 
454
        if (feed->child_argv && !feed->pid) {
 
455
            feed->pid_start = time(0);
 
456
 
 
457
            feed->pid = fork();
 
458
 
 
459
            if (feed->pid < 0) {
 
460
                http_log("Unable to create children\n");
 
461
                exit(1);
 
462
            }
 
463
            if (!feed->pid) {
 
464
                /* In child */
 
465
                char pathname[1024];
 
466
                char *slash;
 
467
                int i;
 
468
 
 
469
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
 
470
 
 
471
                slash = strrchr(pathname, '/');
 
472
                if (!slash)
 
473
                    slash = pathname;
 
474
                else
 
475
                    slash++;
 
476
                strcpy(slash, "avconv");
 
477
 
 
478
                http_log("Launch command line: ");
 
479
                http_log("%s ", pathname);
 
480
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
 
481
                    http_log("%s ", feed->child_argv[i]);
 
482
                http_log("\n");
 
483
 
 
484
                for (i = 3; i < 256; i++)
 
485
                    close(i);
 
486
 
 
487
                if (!avserver_debug) {
 
488
                    i = open("/dev/null", O_RDWR);
 
489
                    if (i != -1) {
 
490
                        dup2(i, 0);
 
491
                        dup2(i, 1);
 
492
                        dup2(i, 2);
 
493
                        close(i);
 
494
                    }
 
495
                }
 
496
 
 
497
                /* This is needed to make relative pathnames work */
 
498
                chdir(my_program_dir);
 
499
 
 
500
                signal(SIGPIPE, SIG_DFL);
 
501
 
 
502
                execvp(pathname, feed->child_argv);
 
503
 
 
504
                _exit(1);
 
505
            }
 
506
        }
 
507
    }
 
508
}
 
509
 
 
510
/* open a listening socket */
 
511
static int socket_open_listen(struct sockaddr_in *my_addr)
 
512
{
 
513
    int server_fd, tmp;
 
514
 
 
515
    server_fd = socket(AF_INET,SOCK_STREAM,0);
 
516
    if (server_fd < 0) {
 
517
        perror ("socket");
 
518
        return -1;
 
519
    }
 
520
 
 
521
    tmp = 1;
 
522
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
 
523
 
 
524
    my_addr->sin_family = AF_INET;
 
525
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
 
526
        char bindmsg[32];
 
527
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
 
528
        perror (bindmsg);
 
529
        closesocket(server_fd);
 
530
        return -1;
 
531
    }
 
532
 
 
533
    if (listen (server_fd, 5) < 0) {
 
534
        perror ("listen");
 
535
        closesocket(server_fd);
 
536
        return -1;
 
537
    }
 
538
    ff_socket_nonblock(server_fd, 1);
 
539
 
 
540
    return server_fd;
 
541
}
 
542
 
 
543
/* start all multicast streams */
 
544
static void start_multicast(void)
 
545
{
 
546
    FFStream *stream;
 
547
    char session_id[32];
 
548
    HTTPContext *rtp_c;
 
549
    struct sockaddr_in dest_addr;
 
550
    int default_port, stream_index;
 
551
 
 
552
    default_port = 6000;
 
553
    for(stream = first_stream; stream != NULL; stream = stream->next) {
 
554
        if (stream->is_multicast) {
 
555
            /* open the RTP connection */
 
556
            snprintf(session_id, sizeof(session_id), "%08x%08x",
 
557
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
 
558
 
 
559
            /* choose a port if none given */
 
560
            if (stream->multicast_port == 0) {
 
561
                stream->multicast_port = default_port;
 
562
                default_port += 100;
 
563
            }
 
564
 
 
565
            dest_addr.sin_family = AF_INET;
 
566
            dest_addr.sin_addr = stream->multicast_ip;
 
567
            dest_addr.sin_port = htons(stream->multicast_port);
 
568
 
 
569
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
 
570
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
 
571
            if (!rtp_c)
 
572
                continue;
 
573
 
 
574
            if (open_input_stream(rtp_c, "") < 0) {
 
575
                http_log("Could not open input stream for stream '%s'\n",
 
576
                         stream->filename);
 
577
                continue;
 
578
            }
 
579
 
 
580
            /* open each RTP stream */
 
581
            for(stream_index = 0; stream_index < stream->nb_streams;
 
582
                stream_index++) {
 
583
                dest_addr.sin_port = htons(stream->multicast_port +
 
584
                                           2 * stream_index);
 
585
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
 
586
                    http_log("Could not open output stream '%s/streamid=%d'\n",
 
587
                             stream->filename, stream_index);
 
588
                    exit(1);
 
589
                }
 
590
            }
 
591
 
 
592
            /* change state to send data */
 
593
            rtp_c->state = HTTPSTATE_SEND_DATA;
 
594
        }
 
595
    }
 
596
}
 
597
 
 
598
/* main loop of the http server */
 
599
static int http_server(void)
 
600
{
 
601
    int server_fd = 0, rtsp_server_fd = 0;
 
602
    int ret, delay, delay1;
 
603
    struct pollfd *poll_table, *poll_entry;
 
604
    HTTPContext *c, *c_next;
 
605
 
 
606
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
 
607
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
 
608
        return -1;
 
609
    }
 
610
 
 
611
    if (my_http_addr.sin_port) {
 
612
        server_fd = socket_open_listen(&my_http_addr);
 
613
        if (server_fd < 0)
 
614
            return -1;
 
615
    }
 
616
 
 
617
    if (my_rtsp_addr.sin_port) {
 
618
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
 
619
        if (rtsp_server_fd < 0)
 
620
            return -1;
 
621
    }
 
622
 
 
623
    if (!rtsp_server_fd && !server_fd) {
 
624
        http_log("HTTP and RTSP disabled.\n");
 
625
        return -1;
 
626
    }
 
627
 
 
628
    http_log("AVserver started.\n");
 
629
 
 
630
    start_children(first_feed);
 
631
 
 
632
    start_multicast();
 
633
 
 
634
    for(;;) {
 
635
        poll_entry = poll_table;
 
636
        if (server_fd) {
 
637
            poll_entry->fd = server_fd;
 
638
            poll_entry->events = POLLIN;
 
639
            poll_entry++;
 
640
        }
 
641
        if (rtsp_server_fd) {
 
642
            poll_entry->fd = rtsp_server_fd;
 
643
            poll_entry->events = POLLIN;
 
644
            poll_entry++;
 
645
        }
 
646
 
 
647
        /* wait for events on each HTTP handle */
 
648
        c = first_http_ctx;
 
649
        delay = 1000;
 
650
        while (c != NULL) {
 
651
            int fd;
 
652
            fd = c->fd;
 
653
            switch(c->state) {
 
654
            case HTTPSTATE_SEND_HEADER:
 
655
            case RTSPSTATE_SEND_REPLY:
 
656
            case RTSPSTATE_SEND_PACKET:
 
657
                c->poll_entry = poll_entry;
 
658
                poll_entry->fd = fd;
 
659
                poll_entry->events = POLLOUT;
 
660
                poll_entry++;
 
661
                break;
 
662
            case HTTPSTATE_SEND_DATA_HEADER:
 
663
            case HTTPSTATE_SEND_DATA:
 
664
            case HTTPSTATE_SEND_DATA_TRAILER:
 
665
                if (!c->is_packetized) {
 
666
                    /* for TCP, we output as much as we can (may need to put a limit) */
 
667
                    c->poll_entry = poll_entry;
 
668
                    poll_entry->fd = fd;
 
669
                    poll_entry->events = POLLOUT;
 
670
                    poll_entry++;
 
671
                } else {
 
672
                    /* when avserver is doing the timing, we work by
 
673
                       looking at which packet need to be sent every
 
674
                       10 ms */
 
675
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
 
676
                    if (delay1 < delay)
 
677
                        delay = delay1;
 
678
                }
 
679
                break;
 
680
            case HTTPSTATE_WAIT_REQUEST:
 
681
            case HTTPSTATE_RECEIVE_DATA:
 
682
            case HTTPSTATE_WAIT_FEED:
 
683
            case RTSPSTATE_WAIT_REQUEST:
 
684
                /* need to catch errors */
 
685
                c->poll_entry = poll_entry;
 
686
                poll_entry->fd = fd;
 
687
                poll_entry->events = POLLIN;/* Maybe this will work */
 
688
                poll_entry++;
 
689
                break;
 
690
            default:
 
691
                c->poll_entry = NULL;
 
692
                break;
 
693
            }
 
694
            c = c->next;
 
695
        }
 
696
 
 
697
        /* wait for an event on one connection. We poll at least every
 
698
           second to handle timeouts */
 
699
        do {
 
700
            ret = poll(poll_table, poll_entry - poll_table, delay);
 
701
            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
 
702
                ff_neterrno() != AVERROR(EINTR))
 
703
                return -1;
 
704
        } while (ret < 0);
 
705
 
 
706
        cur_time = av_gettime() / 1000;
 
707
 
 
708
        if (need_to_start_children) {
 
709
            need_to_start_children = 0;
 
710
            start_children(first_feed);
 
711
        }
 
712
 
 
713
        /* now handle the events */
 
714
        for(c = first_http_ctx; c != NULL; c = c_next) {
 
715
            c_next = c->next;
 
716
            if (handle_connection(c) < 0) {
 
717
                /* close and free the connection */
 
718
                log_connection(c);
 
719
                close_connection(c);
 
720
            }
 
721
        }
 
722
 
 
723
        poll_entry = poll_table;
 
724
        if (server_fd) {
 
725
            /* new HTTP connection request ? */
 
726
            if (poll_entry->revents & POLLIN)
 
727
                new_connection(server_fd, 0);
 
728
            poll_entry++;
 
729
        }
 
730
        if (rtsp_server_fd) {
 
731
            /* new RTSP connection request ? */
 
732
            if (poll_entry->revents & POLLIN)
 
733
                new_connection(rtsp_server_fd, 1);
 
734
        }
 
735
    }
 
736
}
 
737
 
 
738
/* start waiting for a new HTTP/RTSP request */
 
739
static void start_wait_request(HTTPContext *c, int is_rtsp)
 
740
{
 
741
    c->buffer_ptr = c->buffer;
 
742
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
 
743
 
 
744
    if (is_rtsp) {
 
745
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
 
746
        c->state = RTSPSTATE_WAIT_REQUEST;
 
747
    } else {
 
748
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
 
749
        c->state = HTTPSTATE_WAIT_REQUEST;
 
750
    }
 
751
}
 
752
 
 
753
static void http_send_too_busy_reply(int fd)
 
754
{
 
755
    char buffer[300];
 
756
    int len = snprintf(buffer, sizeof(buffer),
 
757
                       "HTTP/1.0 503 Server too busy\r\n"
 
758
                       "Content-type: text/html\r\n"
 
759
                       "\r\n"
 
760
                       "<html><head><title>Too busy</title></head><body>\r\n"
 
761
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
 
762
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
 
763
                       "</body></html>\r\n",
 
764
                       nb_connections, nb_max_connections);
 
765
    send(fd, buffer, len, 0);
 
766
}
 
767
 
 
768
 
 
769
static void new_connection(int server_fd, int is_rtsp)
 
770
{
 
771
    struct sockaddr_in from_addr;
 
772
    int fd, len;
 
773
    HTTPContext *c = NULL;
 
774
 
 
775
    len = sizeof(from_addr);
 
776
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
 
777
                &len);
 
778
    if (fd < 0) {
 
779
        http_log("error during accept %s\n", strerror(errno));
 
780
        return;
 
781
    }
 
782
    ff_socket_nonblock(fd, 1);
 
783
 
 
784
    if (nb_connections >= nb_max_connections) {
 
785
        http_send_too_busy_reply(fd);
 
786
        goto fail;
 
787
    }
 
788
 
 
789
    /* add a new connection */
 
790
    c = av_mallocz(sizeof(HTTPContext));
 
791
    if (!c)
 
792
        goto fail;
 
793
 
 
794
    c->fd = fd;
 
795
    c->poll_entry = NULL;
 
796
    c->from_addr = from_addr;
 
797
    c->buffer_size = IOBUFFER_INIT_SIZE;
 
798
    c->buffer = av_malloc(c->buffer_size);
 
799
    if (!c->buffer)
 
800
        goto fail;
 
801
 
 
802
    c->next = first_http_ctx;
 
803
    first_http_ctx = c;
 
804
    nb_connections++;
 
805
 
 
806
    start_wait_request(c, is_rtsp);
 
807
 
 
808
    return;
 
809
 
 
810
 fail:
 
811
    if (c) {
 
812
        av_free(c->buffer);
 
813
        av_free(c);
 
814
    }
 
815
    closesocket(fd);
 
816
}
 
817
 
 
818
static void close_connection(HTTPContext *c)
 
819
{
 
820
    HTTPContext **cp, *c1;
 
821
    int i, nb_streams;
 
822
    AVFormatContext *ctx;
 
823
    URLContext *h;
 
824
    AVStream *st;
 
825
 
 
826
    /* remove connection from list */
 
827
    cp = &first_http_ctx;
 
828
    while ((*cp) != NULL) {
 
829
        c1 = *cp;
 
830
        if (c1 == c)
 
831
            *cp = c->next;
 
832
        else
 
833
            cp = &c1->next;
 
834
    }
 
835
 
 
836
    /* remove references, if any (XXX: do it faster) */
 
837
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
 
838
        if (c1->rtsp_c == c)
 
839
            c1->rtsp_c = NULL;
 
840
    }
 
841
 
 
842
    /* remove connection associated resources */
 
843
    if (c->fd >= 0)
 
844
        closesocket(c->fd);
 
845
    if (c->fmt_in) {
 
846
        /* close each frame parser */
 
847
        for(i=0;i<c->fmt_in->nb_streams;i++) {
 
848
            st = c->fmt_in->streams[i];
 
849
            if (st->codec->codec)
 
850
                avcodec_close(st->codec);
 
851
        }
 
852
        avformat_close_input(&c->fmt_in);
 
853
    }
 
854
 
 
855
    /* free RTP output streams if any */
 
856
    nb_streams = 0;
 
857
    if (c->stream)
 
858
        nb_streams = c->stream->nb_streams;
 
859
 
 
860
    for(i=0;i<nb_streams;i++) {
 
861
        ctx = c->rtp_ctx[i];
 
862
        if (ctx) {
 
863
            av_write_trailer(ctx);
 
864
            av_dict_free(&ctx->metadata);
 
865
            av_free(ctx->streams[0]);
 
866
            av_free(ctx);
 
867
        }
 
868
        h = c->rtp_handles[i];
 
869
        if (h)
 
870
            url_close(h);
 
871
    }
 
872
 
 
873
    ctx = &c->fmt_ctx;
 
874
 
 
875
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
 
876
        if (ctx->oformat) {
 
877
            /* prepare header */
 
878
            if (avio_open_dyn_buf(&ctx->pb) >= 0) {
 
879
                av_write_trailer(ctx);
 
880
                av_freep(&c->pb_buffer);
 
881
                avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
 
882
            }
 
883
        }
 
884
    }
 
885
 
 
886
    for(i=0; i<ctx->nb_streams; i++)
 
887
        av_free(ctx->streams[i]);
 
888
 
 
889
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
 
890
        current_bandwidth -= c->stream->bandwidth;
 
891
 
 
892
    /* signal that there is no feed if we are the feeder socket */
 
893
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
 
894
        c->stream->feed_opened = 0;
 
895
        close(c->feed_fd);
 
896
    }
 
897
 
 
898
    av_freep(&c->pb_buffer);
 
899
    av_freep(&c->packet_buffer);
 
900
    av_free(c->buffer);
 
901
    av_free(c);
 
902
    nb_connections--;
 
903
}
 
904
 
 
905
static int handle_connection(HTTPContext *c)
 
906
{
 
907
    int len, ret;
 
908
 
 
909
    switch(c->state) {
 
910
    case HTTPSTATE_WAIT_REQUEST:
 
911
    case RTSPSTATE_WAIT_REQUEST:
 
912
        /* timeout ? */
 
913
        if ((c->timeout - cur_time) < 0)
 
914
            return -1;
 
915
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
 
916
            return -1;
 
917
 
 
918
        /* no need to read if no events */
 
919
        if (!(c->poll_entry->revents & POLLIN))
 
920
            return 0;
 
921
        /* read the data */
 
922
    read_loop:
 
923
        len = recv(c->fd, c->buffer_ptr, 1, 0);
 
924
        if (len < 0) {
 
925
            if (ff_neterrno() != AVERROR(EAGAIN) &&
 
926
                ff_neterrno() != AVERROR(EINTR))
 
927
                return -1;
 
928
        } else if (len == 0) {
 
929
            return -1;
 
930
        } else {
 
931
            /* search for end of request. */
 
932
            uint8_t *ptr;
 
933
            c->buffer_ptr += len;
 
934
            ptr = c->buffer_ptr;
 
935
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
 
936
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
 
937
                /* request found : parse it and reply */
 
938
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
 
939
                    ret = http_parse_request(c);
 
940
                } else {
 
941
                    ret = rtsp_parse_request(c);
 
942
                }
 
943
                if (ret < 0)
 
944
                    return -1;
 
945
            } else if (ptr >= c->buffer_end) {
 
946
                /* request too long: cannot do anything */
 
947
                return -1;
 
948
            } else goto read_loop;
 
949
        }
 
950
        break;
 
951
 
 
952
    case HTTPSTATE_SEND_HEADER:
 
953
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
 
954
            return -1;
 
955
 
 
956
        /* no need to write if no events */
 
957
        if (!(c->poll_entry->revents & POLLOUT))
 
958
            return 0;
 
959
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
 
960
        if (len < 0) {
 
961
            if (ff_neterrno() != AVERROR(EAGAIN) &&
 
962
                ff_neterrno() != AVERROR(EINTR)) {
 
963
                /* error : close connection */
 
964
                av_freep(&c->pb_buffer);
 
965
                return -1;
 
966
            }
 
967
        } else {
 
968
            c->buffer_ptr += len;
 
969
            if (c->stream)
 
970
                c->stream->bytes_served += len;
 
971
            c->data_count += len;
 
972
            if (c->buffer_ptr >= c->buffer_end) {
 
973
                av_freep(&c->pb_buffer);
 
974
                /* if error, exit */
 
975
                if (c->http_error)
 
976
                    return -1;
 
977
                /* all the buffer was sent : synchronize to the incoming stream */
 
978
                c->state = HTTPSTATE_SEND_DATA_HEADER;
 
979
                c->buffer_ptr = c->buffer_end = c->buffer;
 
980
            }
 
981
        }
 
982
        break;
 
983
 
 
984
    case HTTPSTATE_SEND_DATA:
 
985
    case HTTPSTATE_SEND_DATA_HEADER:
 
986
    case HTTPSTATE_SEND_DATA_TRAILER:
 
987
        /* for packetized output, we consider we can always write (the
 
988
           input streams sets the speed). It may be better to verify
 
989
           that we do not rely too much on the kernel queues */
 
990
        if (!c->is_packetized) {
 
991
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
 
992
                return -1;
 
993
 
 
994
            /* no need to read if no events */
 
995
            if (!(c->poll_entry->revents & POLLOUT))
 
996
                return 0;
 
997
        }
 
998
        if (http_send_data(c) < 0)
 
999
            return -1;
 
1000
        /* close connection if trailer sent */
 
1001
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
 
1002
            return -1;
 
1003
        break;
 
1004
    case HTTPSTATE_RECEIVE_DATA:
 
1005
        /* no need to read if no events */
 
1006
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
 
1007
            return -1;
 
1008
        if (!(c->poll_entry->revents & POLLIN))
 
1009
            return 0;
 
1010
        if (http_receive_data(c) < 0)
 
1011
            return -1;
 
1012
        break;
 
1013
    case HTTPSTATE_WAIT_FEED:
 
1014
        /* no need to read if no events */
 
1015
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
 
1016
            return -1;
 
1017
 
 
1018
        /* nothing to do, we'll be waken up by incoming feed packets */
 
1019
        break;
 
1020
 
 
1021
    case RTSPSTATE_SEND_REPLY:
 
1022
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
 
1023
            av_freep(&c->pb_buffer);
 
1024
            return -1;
 
1025
        }
 
1026
        /* no need to write if no events */
 
1027
        if (!(c->poll_entry->revents & POLLOUT))
 
1028
            return 0;
 
1029
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
 
1030
        if (len < 0) {
 
1031
            if (ff_neterrno() != AVERROR(EAGAIN) &&
 
1032
                ff_neterrno() != AVERROR(EINTR)) {
 
1033
                /* error : close connection */
 
1034
                av_freep(&c->pb_buffer);
 
1035
                return -1;
 
1036
            }
 
1037
        } else {
 
1038
            c->buffer_ptr += len;
 
1039
            c->data_count += len;
 
1040
            if (c->buffer_ptr >= c->buffer_end) {
 
1041
                /* all the buffer was sent : wait for a new request */
 
1042
                av_freep(&c->pb_buffer);
 
1043
                start_wait_request(c, 1);
 
1044
            }
 
1045
        }
 
1046
        break;
 
1047
    case RTSPSTATE_SEND_PACKET:
 
1048
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
 
1049
            av_freep(&c->packet_buffer);
 
1050
            return -1;
 
1051
        }
 
1052
        /* no need to write if no events */
 
1053
        if (!(c->poll_entry->revents & POLLOUT))
 
1054
            return 0;
 
1055
        len = send(c->fd, c->packet_buffer_ptr,
 
1056
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
 
1057
        if (len < 0) {
 
1058
            if (ff_neterrno() != AVERROR(EAGAIN) &&
 
1059
                ff_neterrno() != AVERROR(EINTR)) {
 
1060
                /* error : close connection */
 
1061
                av_freep(&c->packet_buffer);
 
1062
                return -1;
 
1063
            }
 
1064
        } else {
 
1065
            c->packet_buffer_ptr += len;
 
1066
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
 
1067
                /* all the buffer was sent : wait for a new request */
 
1068
                av_freep(&c->packet_buffer);
 
1069
                c->state = RTSPSTATE_WAIT_REQUEST;
 
1070
            }
 
1071
        }
 
1072
        break;
 
1073
    case HTTPSTATE_READY:
 
1074
        /* nothing to do */
 
1075
        break;
 
1076
    default:
 
1077
        return -1;
 
1078
    }
 
1079
    return 0;
 
1080
}
 
1081
 
 
1082
static int extract_rates(char *rates, int ratelen, const char *request)
 
1083
{
 
1084
    const char *p;
 
1085
 
 
1086
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
 
1087
        if (av_strncasecmp(p, "Pragma:", 7) == 0) {
 
1088
            const char *q = p + 7;
 
1089
 
 
1090
            while (*q && *q != '\n' && isspace(*q))
 
1091
                q++;
 
1092
 
 
1093
            if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
 
1094
                int stream_no;
 
1095
                int rate_no;
 
1096
 
 
1097
                q += 20;
 
1098
 
 
1099
                memset(rates, 0xff, ratelen);
 
1100
 
 
1101
                while (1) {
 
1102
                    while (*q && *q != '\n' && *q != ':')
 
1103
                        q++;
 
1104
 
 
1105
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
 
1106
                        break;
 
1107
 
 
1108
                    stream_no--;
 
1109
                    if (stream_no < ratelen && stream_no >= 0)
 
1110
                        rates[stream_no] = rate_no;
 
1111
 
 
1112
                    while (*q && *q != '\n' && !isspace(*q))
 
1113
                        q++;
 
1114
                }
 
1115
 
 
1116
                return 1;
 
1117
            }
 
1118
        }
 
1119
        p = strchr(p, '\n');
 
1120
        if (!p)
 
1121
            break;
 
1122
 
 
1123
        p++;
 
1124
    }
 
1125
 
 
1126
    return 0;
 
1127
}
 
1128
 
 
1129
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
 
1130
{
 
1131
    int i;
 
1132
    int best_bitrate = 100000000;
 
1133
    int best = -1;
 
1134
 
 
1135
    for (i = 0; i < feed->nb_streams; i++) {
 
1136
        AVCodecContext *feed_codec = feed->streams[i]->codec;
 
1137
 
 
1138
        if (feed_codec->codec_id != codec->codec_id ||
 
1139
            feed_codec->sample_rate != codec->sample_rate ||
 
1140
            feed_codec->width != codec->width ||
 
1141
            feed_codec->height != codec->height)
 
1142
            continue;
 
1143
 
 
1144
        /* Potential stream */
 
1145
 
 
1146
        /* We want the fastest stream less than bit_rate, or the slowest
 
1147
         * faster than bit_rate
 
1148
         */
 
1149
 
 
1150
        if (feed_codec->bit_rate <= bit_rate) {
 
1151
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
 
1152
                best_bitrate = feed_codec->bit_rate;
 
1153
                best = i;
 
1154
            }
 
1155
        } else {
 
1156
            if (feed_codec->bit_rate < best_bitrate) {
 
1157
                best_bitrate = feed_codec->bit_rate;
 
1158
                best = i;
 
1159
            }
 
1160
        }
 
1161
    }
 
1162
 
 
1163
    return best;
 
1164
}
 
1165
 
 
1166
static int modify_current_stream(HTTPContext *c, char *rates)
 
1167
{
 
1168
    int i;
 
1169
    FFStream *req = c->stream;
 
1170
    int action_required = 0;
 
1171
 
 
1172
    /* Not much we can do for a feed */
 
1173
    if (!req->feed)
 
1174
        return 0;
 
1175
 
 
1176
    for (i = 0; i < req->nb_streams; i++) {
 
1177
        AVCodecContext *codec = req->streams[i]->codec;
 
1178
 
 
1179
        switch(rates[i]) {
 
1180
            case 0:
 
1181
                c->switch_feed_streams[i] = req->feed_streams[i];
 
1182
                break;
 
1183
            case 1:
 
1184
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
 
1185
                break;
 
1186
            case 2:
 
1187
                /* Wants off or slow */
 
1188
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
 
1189
#ifdef WANTS_OFF
 
1190
                /* This doesn't work well when it turns off the only stream! */
 
1191
                c->switch_feed_streams[i] = -2;
 
1192
                c->feed_streams[i] = -2;
 
1193
#endif
 
1194
                break;
 
1195
        }
 
1196
 
 
1197
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
 
1198
            action_required = 1;
 
1199
    }
 
1200
 
 
1201
    return action_required;
 
1202
}
 
1203
 
 
1204
/* XXX: factorize in utils.c ? */
 
1205
/* XXX: take care with different space meaning */
 
1206
static void skip_spaces(const char **pp)
 
1207
{
 
1208
    const char *p;
 
1209
    p = *pp;
 
1210
    while (*p == ' ' || *p == '\t')
 
1211
        p++;
 
1212
    *pp = p;
 
1213
}
 
1214
 
 
1215
static void get_word(char *buf, int buf_size, const char **pp)
 
1216
{
 
1217
    const char *p;
 
1218
    char *q;
 
1219
 
 
1220
    p = *pp;
 
1221
    skip_spaces(&p);
 
1222
    q = buf;
 
1223
    while (!isspace(*p) && *p != '\0') {
 
1224
        if ((q - buf) < buf_size - 1)
 
1225
            *q++ = *p;
 
1226
        p++;
 
1227
    }
 
1228
    if (buf_size > 0)
 
1229
        *q = '\0';
 
1230
    *pp = p;
 
1231
}
 
1232
 
 
1233
static void get_arg(char *buf, int buf_size, const char **pp)
 
1234
{
 
1235
    const char *p;
 
1236
    char *q;
 
1237
    int quote;
 
1238
 
 
1239
    p = *pp;
 
1240
    while (isspace(*p)) p++;
 
1241
    q = buf;
 
1242
    quote = 0;
 
1243
    if (*p == '\"' || *p == '\'')
 
1244
        quote = *p++;
 
1245
    for(;;) {
 
1246
        if (quote) {
 
1247
            if (*p == quote)
 
1248
                break;
 
1249
        } else {
 
1250
            if (isspace(*p))
 
1251
                break;
 
1252
        }
 
1253
        if (*p == '\0')
 
1254
            break;
 
1255
        if ((q - buf) < buf_size - 1)
 
1256
            *q++ = *p;
 
1257
        p++;
 
1258
    }
 
1259
    *q = '\0';
 
1260
    if (quote && *p == quote)
 
1261
        p++;
 
1262
    *pp = p;
 
1263
}
 
1264
 
 
1265
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
 
1266
                         const char *p, const char *filename, int line_num)
 
1267
{
 
1268
    char arg[1024];
 
1269
    IPAddressACL acl;
 
1270
    int errors = 0;
 
1271
 
 
1272
    get_arg(arg, sizeof(arg), &p);
 
1273
    if (av_strcasecmp(arg, "allow") == 0)
 
1274
        acl.action = IP_ALLOW;
 
1275
    else if (av_strcasecmp(arg, "deny") == 0)
 
1276
        acl.action = IP_DENY;
 
1277
    else {
 
1278
        fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
 
1279
                filename, line_num, arg);
 
1280
        errors++;
 
1281
    }
 
1282
 
 
1283
    get_arg(arg, sizeof(arg), &p);
 
1284
 
 
1285
    if (resolve_host(&acl.first, arg) != 0) {
 
1286
        fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
 
1287
                filename, line_num, arg);
 
1288
        errors++;
 
1289
    } else
 
1290
        acl.last = acl.first;
 
1291
 
 
1292
    get_arg(arg, sizeof(arg), &p);
 
1293
 
 
1294
    if (arg[0]) {
 
1295
        if (resolve_host(&acl.last, arg) != 0) {
 
1296
            fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
 
1297
                    filename, line_num, arg);
 
1298
            errors++;
 
1299
        }
 
1300
    }
 
1301
 
 
1302
    if (!errors) {
 
1303
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
 
1304
        IPAddressACL **naclp = 0;
 
1305
 
 
1306
        acl.next = 0;
 
1307
        *nacl = acl;
 
1308
 
 
1309
        if (stream)
 
1310
            naclp = &stream->acl;
 
1311
        else if (feed)
 
1312
            naclp = &feed->acl;
 
1313
        else if (ext_acl)
 
1314
            naclp = &ext_acl;
 
1315
        else {
 
1316
            fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
 
1317
                    filename, line_num);
 
1318
            errors++;
 
1319
        }
 
1320
 
 
1321
        if (naclp) {
 
1322
            while (*naclp)
 
1323
                naclp = &(*naclp)->next;
 
1324
 
 
1325
            *naclp = nacl;
 
1326
        }
 
1327
    }
 
1328
}
 
1329
 
 
1330
 
 
1331
static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
 
1332
{
 
1333
    FILE* f;
 
1334
    char line[1024];
 
1335
    char  cmd[1024];
 
1336
    IPAddressACL *acl = NULL;
 
1337
    int line_num = 0;
 
1338
    const char *p;
 
1339
 
 
1340
    f = fopen(stream->dynamic_acl, "r");
 
1341
    if (!f) {
 
1342
        perror(stream->dynamic_acl);
 
1343
        return NULL;
 
1344
    }
 
1345
 
 
1346
    acl = av_mallocz(sizeof(IPAddressACL));
 
1347
 
 
1348
    /* Build ACL */
 
1349
    for(;;) {
 
1350
        if (fgets(line, sizeof(line), f) == NULL)
 
1351
            break;
 
1352
        line_num++;
 
1353
        p = line;
 
1354
        while (isspace(*p))
 
1355
            p++;
 
1356
        if (*p == '\0' || *p == '#')
 
1357
            continue;
 
1358
        get_arg(cmd, sizeof(cmd), &p);
 
1359
 
 
1360
        if (!av_strcasecmp(cmd, "ACL"))
 
1361
            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
 
1362
    }
 
1363
    fclose(f);
 
1364
    return acl;
 
1365
}
 
1366
 
 
1367
 
 
1368
static void free_acl_list(IPAddressACL *in_acl)
 
1369
{
 
1370
    IPAddressACL *pacl,*pacl2;
 
1371
 
 
1372
    pacl = in_acl;
 
1373
    while(pacl) {
 
1374
        pacl2 = pacl;
 
1375
        pacl = pacl->next;
 
1376
        av_freep(pacl2);
 
1377
    }
 
1378
}
 
1379
 
 
1380
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
 
1381
{
 
1382
    enum IPAddressAction last_action = IP_DENY;
 
1383
    IPAddressACL *acl;
 
1384
    struct in_addr *src = &c->from_addr.sin_addr;
 
1385
    unsigned long src_addr = src->s_addr;
 
1386
 
 
1387
    for (acl = in_acl; acl; acl = acl->next) {
 
1388
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
 
1389
            return (acl->action == IP_ALLOW) ? 1 : 0;
 
1390
        last_action = acl->action;
 
1391
    }
 
1392
 
 
1393
    /* Nothing matched, so return not the last action */
 
1394
    return (last_action == IP_DENY) ? 1 : 0;
 
1395
}
 
1396
 
 
1397
static int validate_acl(FFStream *stream, HTTPContext *c)
 
1398
{
 
1399
    int ret = 0;
 
1400
    IPAddressACL *acl;
 
1401
 
 
1402
 
 
1403
    /* if stream->acl is null validate_acl_list will return 1 */
 
1404
    ret = validate_acl_list(stream->acl, c);
 
1405
 
 
1406
    if (stream->dynamic_acl[0]) {
 
1407
        acl = parse_dynamic_acl(stream, c);
 
1408
 
 
1409
        ret = validate_acl_list(acl, c);
 
1410
 
 
1411
        free_acl_list(acl);
 
1412
    }
 
1413
 
 
1414
    return ret;
 
1415
}
 
1416
 
 
1417
/* compute the real filename of a file by matching it without its
 
1418
   extensions to all the stream filenames */
 
1419
static void compute_real_filename(char *filename, int max_size)
 
1420
{
 
1421
    char file1[1024];
 
1422
    char file2[1024];
 
1423
    char *p;
 
1424
    FFStream *stream;
 
1425
 
 
1426
    /* compute filename by matching without the file extensions */
 
1427
    av_strlcpy(file1, filename, sizeof(file1));
 
1428
    p = strrchr(file1, '.');
 
1429
    if (p)
 
1430
        *p = '\0';
 
1431
    for(stream = first_stream; stream != NULL; stream = stream->next) {
 
1432
        av_strlcpy(file2, stream->filename, sizeof(file2));
 
1433
        p = strrchr(file2, '.');
 
1434
        if (p)
 
1435
            *p = '\0';
 
1436
        if (!strcmp(file1, file2)) {
 
1437
            av_strlcpy(filename, stream->filename, max_size);
 
1438
            break;
 
1439
        }
 
1440
    }
 
1441
}
 
1442
 
 
1443
enum RedirType {
 
1444
    REDIR_NONE,
 
1445
    REDIR_ASX,
 
1446
    REDIR_RAM,
 
1447
    REDIR_ASF,
 
1448
    REDIR_RTSP,
 
1449
    REDIR_SDP,
 
1450
};
 
1451
 
 
1452
/* parse http request and prepare header */
 
1453
static int http_parse_request(HTTPContext *c)
 
1454
{
 
1455
    char *p;
 
1456
    enum RedirType redir_type;
 
1457
    char cmd[32];
 
1458
    char info[1024], filename[1024];
 
1459
    char url[1024], *q;
 
1460
    char protocol[32];
 
1461
    char msg[1024];
 
1462
    const char *mime_type;
 
1463
    FFStream *stream;
 
1464
    int i;
 
1465
    char ratebuf[32];
 
1466
    char *useragent = 0;
 
1467
 
 
1468
    p = c->buffer;
 
1469
    get_word(cmd, sizeof(cmd), (const char **)&p);
 
1470
    av_strlcpy(c->method, cmd, sizeof(c->method));
 
1471
 
 
1472
    if (!strcmp(cmd, "GET"))
 
1473
        c->post = 0;
 
1474
    else if (!strcmp(cmd, "POST"))
 
1475
        c->post = 1;
 
1476
    else
 
1477
        return -1;
 
1478
 
 
1479
    get_word(url, sizeof(url), (const char **)&p);
 
1480
    av_strlcpy(c->url, url, sizeof(c->url));
 
1481
 
 
1482
    get_word(protocol, sizeof(protocol), (const char **)&p);
 
1483
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
 
1484
        return -1;
 
1485
 
 
1486
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
 
1487
 
 
1488
    if (avserver_debug)
 
1489
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
 
1490
 
 
1491
    /* find the filename and the optional info string in the request */
 
1492
    p = strchr(url, '?');
 
1493
    if (p) {
 
1494
        av_strlcpy(info, p, sizeof(info));
 
1495
        *p = '\0';
 
1496
    } else
 
1497
        info[0] = '\0';
 
1498
 
 
1499
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
 
1500
 
 
1501
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
 
1502
        if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
 
1503
            useragent = p + 11;
 
1504
            if (*useragent && *useragent != '\n' && isspace(*useragent))
 
1505
                useragent++;
 
1506
            break;
 
1507
        }
 
1508
        p = strchr(p, '\n');
 
1509
        if (!p)
 
1510
            break;
 
1511
 
 
1512
        p++;
 
1513
    }
 
1514
 
 
1515
    redir_type = REDIR_NONE;
 
1516
    if (av_match_ext(filename, "asx")) {
 
1517
        redir_type = REDIR_ASX;
 
1518
        filename[strlen(filename)-1] = 'f';
 
1519
    } else if (av_match_ext(filename, "asf") &&
 
1520
        (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
 
1521
        /* if this isn't WMP or lookalike, return the redirector file */
 
1522
        redir_type = REDIR_ASF;
 
1523
    } else if (av_match_ext(filename, "rpm,ram")) {
 
1524
        redir_type = REDIR_RAM;
 
1525
        strcpy(filename + strlen(filename)-2, "m");
 
1526
    } else if (av_match_ext(filename, "rtsp")) {
 
1527
        redir_type = REDIR_RTSP;
 
1528
        compute_real_filename(filename, sizeof(filename) - 1);
 
1529
    } else if (av_match_ext(filename, "sdp")) {
 
1530
        redir_type = REDIR_SDP;
 
1531
        compute_real_filename(filename, sizeof(filename) - 1);
 
1532
    }
 
1533
 
 
1534
    // "redirect" / request to index.html
 
1535
    if (!strlen(filename))
 
1536
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
 
1537
 
 
1538
    stream = first_stream;
 
1539
    while (stream != NULL) {
 
1540
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
 
1541
            break;
 
1542
        stream = stream->next;
 
1543
    }
 
1544
    if (stream == NULL) {
 
1545
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
 
1546
        http_log("File '%s' not found\n", url);
 
1547
        goto send_error;
 
1548
    }
 
1549
 
 
1550
    c->stream = stream;
 
1551
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
 
1552
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
 
1553
 
 
1554
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
 
1555
        c->http_error = 301;
 
1556
        q = c->buffer;
 
1557
        q += snprintf(q, c->buffer_size,
 
1558
                      "HTTP/1.0 301 Moved\r\n"
 
1559
                      "Location: %s\r\n"
 
1560
                      "Content-type: text/html\r\n"
 
1561
                      "\r\n"
 
1562
                      "<html><head><title>Moved</title></head><body>\r\n"
 
1563
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
 
1564
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
 
1565
        /* prepare output buffer */
 
1566
        c->buffer_ptr = c->buffer;
 
1567
        c->buffer_end = q;
 
1568
        c->state = HTTPSTATE_SEND_HEADER;
 
1569
        return 0;
 
1570
    }
 
1571
 
 
1572
    /* If this is WMP, get the rate information */
 
1573
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
 
1574
        if (modify_current_stream(c, ratebuf)) {
 
1575
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
 
1576
                if (c->switch_feed_streams[i] >= 0)
 
1577
                    c->switch_feed_streams[i] = -1;
 
1578
            }
 
1579
        }
 
1580
    }
 
1581
 
 
1582
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
 
1583
        current_bandwidth += stream->bandwidth;
 
1584
 
 
1585
    /* If already streaming this feed, do not let start another feeder. */
 
1586
    if (stream->feed_opened) {
 
1587
        snprintf(msg, sizeof(msg), "This feed is already being received.");
 
1588
        http_log("Feed '%s' already being received\n", stream->feed_filename);
 
1589
        goto send_error;
 
1590
    }
 
1591
 
 
1592
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
 
1593
        c->http_error = 503;
 
1594
        q = c->buffer;
 
1595
        q += snprintf(q, c->buffer_size,
 
1596
                      "HTTP/1.0 503 Server too busy\r\n"
 
1597
                      "Content-type: text/html\r\n"
 
1598
                      "\r\n"
 
1599
                      "<html><head><title>Too busy</title></head><body>\r\n"
 
1600
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
 
1601
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
 
1602
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
 
1603
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
 
1604
        /* prepare output buffer */
 
1605
        c->buffer_ptr = c->buffer;
 
1606
        c->buffer_end = q;
 
1607
        c->state = HTTPSTATE_SEND_HEADER;
 
1608
        return 0;
 
1609
    }
 
1610
 
 
1611
    if (redir_type != REDIR_NONE) {
 
1612
        char *hostinfo = 0;
 
1613
 
 
1614
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
 
1615
            if (av_strncasecmp(p, "Host:", 5) == 0) {
 
1616
                hostinfo = p + 5;
 
1617
                break;
 
1618
            }
 
1619
            p = strchr(p, '\n');
 
1620
            if (!p)
 
1621
                break;
 
1622
 
 
1623
            p++;
 
1624
        }
 
1625
 
 
1626
        if (hostinfo) {
 
1627
            char *eoh;
 
1628
            char hostbuf[260];
 
1629
 
 
1630
            while (isspace(*hostinfo))
 
1631
                hostinfo++;
 
1632
 
 
1633
            eoh = strchr(hostinfo, '\n');
 
1634
            if (eoh) {
 
1635
                if (eoh[-1] == '\r')
 
1636
                    eoh--;
 
1637
 
 
1638
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
 
1639
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
 
1640
                    hostbuf[eoh - hostinfo] = 0;
 
1641
 
 
1642
                    c->http_error = 200;
 
1643
                    q = c->buffer;
 
1644
                    switch(redir_type) {
 
1645
                    case REDIR_ASX:
 
1646
                        q += snprintf(q, c->buffer_size,
 
1647
                                      "HTTP/1.0 200 ASX Follows\r\n"
 
1648
                                      "Content-type: video/x-ms-asf\r\n"
 
1649
                                      "\r\n"
 
1650
                                      "<ASX Version=\"3\">\r\n"
 
1651
                                      //"<!-- Autogenerated by avserver -->\r\n"
 
1652
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
 
1653
                                      "</ASX>\r\n", hostbuf, filename, info);
 
1654
                        break;
 
1655
                    case REDIR_RAM:
 
1656
                        q += snprintf(q, c->buffer_size,
 
1657
                                      "HTTP/1.0 200 RAM Follows\r\n"
 
1658
                                      "Content-type: audio/x-pn-realaudio\r\n"
 
1659
                                      "\r\n"
 
1660
                                      "# Autogenerated by avserver\r\n"
 
1661
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
 
1662
                        break;
 
1663
                    case REDIR_ASF:
 
1664
                        q += snprintf(q, c->buffer_size,
 
1665
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
 
1666
                                      "Content-type: video/x-ms-asf\r\n"
 
1667
                                      "\r\n"
 
1668
                                      "[Reference]\r\n"
 
1669
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
 
1670
                        break;
 
1671
                    case REDIR_RTSP:
 
1672
                        {
 
1673
                            char hostname[256], *p;
 
1674
                            /* extract only hostname */
 
1675
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
 
1676
                            p = strrchr(hostname, ':');
 
1677
                            if (p)
 
1678
                                *p = '\0';
 
1679
                            q += snprintf(q, c->buffer_size,
 
1680
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
 
1681
                                          /* XXX: incorrect mime type ? */
 
1682
                                          "Content-type: application/x-rtsp\r\n"
 
1683
                                          "\r\n"
 
1684
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
 
1685
                        }
 
1686
                        break;
 
1687
                    case REDIR_SDP:
 
1688
                        {
 
1689
                            uint8_t *sdp_data;
 
1690
                            int sdp_data_size, len;
 
1691
                            struct sockaddr_in my_addr;
 
1692
 
 
1693
                            q += snprintf(q, c->buffer_size,
 
1694
                                          "HTTP/1.0 200 OK\r\n"
 
1695
                                          "Content-type: application/sdp\r\n"
 
1696
                                          "\r\n");
 
1697
 
 
1698
                            len = sizeof(my_addr);
 
1699
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
 
1700
 
 
1701
                            /* XXX: should use a dynamic buffer */
 
1702
                            sdp_data_size = prepare_sdp_description(stream,
 
1703
                                                                    &sdp_data,
 
1704
                                                                    my_addr.sin_addr);
 
1705
                            if (sdp_data_size > 0) {
 
1706
                                memcpy(q, sdp_data, sdp_data_size);
 
1707
                                q += sdp_data_size;
 
1708
                                *q = '\0';
 
1709
                                av_free(sdp_data);
 
1710
                            }
 
1711
                        }
 
1712
                        break;
 
1713
                    default:
 
1714
                        abort();
 
1715
                        break;
 
1716
                    }
 
1717
 
 
1718
                    /* prepare output buffer */
 
1719
                    c->buffer_ptr = c->buffer;
 
1720
                    c->buffer_end = q;
 
1721
                    c->state = HTTPSTATE_SEND_HEADER;
 
1722
                    return 0;
 
1723
                }
 
1724
            }
 
1725
        }
 
1726
 
 
1727
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
 
1728
        goto send_error;
 
1729
    }
 
1730
 
 
1731
    stream->conns_served++;
 
1732
 
 
1733
    /* XXX: add there authenticate and IP match */
 
1734
 
 
1735
    if (c->post) {
 
1736
        /* if post, it means a feed is being sent */
 
1737
        if (!stream->is_feed) {
 
1738
            /* However it might be a status report from WMP! Let us log the
 
1739
             * data as it might come in handy one day. */
 
1740
            char *logline = 0;
 
1741
            int client_id = 0;
 
1742
 
 
1743
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
 
1744
                if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
 
1745
                    logline = p;
 
1746
                    break;
 
1747
                }
 
1748
                if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
 
1749
                    client_id = strtol(p + 18, 0, 10);
 
1750
                p = strchr(p, '\n');
 
1751
                if (!p)
 
1752
                    break;
 
1753
 
 
1754
                p++;
 
1755
            }
 
1756
 
 
1757
            if (logline) {
 
1758
                char *eol = strchr(logline, '\n');
 
1759
 
 
1760
                logline += 17;
 
1761
 
 
1762
                if (eol) {
 
1763
                    if (eol[-1] == '\r')
 
1764
                        eol--;
 
1765
                    http_log("%.*s\n", (int) (eol - logline), logline);
 
1766
                    c->suppress_log = 1;
 
1767
                }
 
1768
            }
 
1769
 
 
1770
#ifdef DEBUG
 
1771
            http_log("\nGot request:\n%s\n", c->buffer);
 
1772
#endif
 
1773
 
 
1774
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
 
1775
                HTTPContext *wmpc;
 
1776
 
 
1777
                /* Now we have to find the client_id */
 
1778
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
 
1779
                    if (wmpc->wmp_client_id == client_id)
 
1780
                        break;
 
1781
                }
 
1782
 
 
1783
                if (wmpc && modify_current_stream(wmpc, ratebuf))
 
1784
                    wmpc->switch_pending = 1;
 
1785
            }
 
1786
 
 
1787
            snprintf(msg, sizeof(msg), "POST command not handled");
 
1788
            c->stream = 0;
 
1789
            goto send_error;
 
1790
        }
 
1791
        if (http_start_receive_data(c) < 0) {
 
1792
            snprintf(msg, sizeof(msg), "could not open feed");
 
1793
            goto send_error;
 
1794
        }
 
1795
        c->http_error = 0;
 
1796
        c->state = HTTPSTATE_RECEIVE_DATA;
 
1797
        return 0;
 
1798
    }
 
1799
 
 
1800
#ifdef DEBUG
 
1801
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
 
1802
        http_log("\nGot request:\n%s\n", c->buffer);
 
1803
#endif
 
1804
 
 
1805
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
 
1806
        goto send_status;
 
1807
 
 
1808
    /* open input stream */
 
1809
    if (open_input_stream(c, info) < 0) {
 
1810
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
 
1811
        goto send_error;
 
1812
    }
 
1813
 
 
1814
    /* prepare http header */
 
1815
    q = c->buffer;
 
1816
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
 
1817
    mime_type = c->stream->fmt->mime_type;
 
1818
    if (!mime_type)
 
1819
        mime_type = "application/x-octet-stream";
 
1820
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
 
1821
 
 
1822
    /* for asf, we need extra headers */
 
1823
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
 
1824
        /* Need to allocate a client id */
 
1825
 
 
1826
        c->wmp_client_id = av_lfg_get(&random_state);
 
1827
 
 
1828
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "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);
 
1829
    }
 
1830
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
 
1831
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
 
1832
 
 
1833
    /* prepare output buffer */
 
1834
    c->http_error = 0;
 
1835
    c->buffer_ptr = c->buffer;
 
1836
    c->buffer_end = q;
 
1837
    c->state = HTTPSTATE_SEND_HEADER;
 
1838
    return 0;
 
1839
 send_error:
 
1840
    c->http_error = 404;
 
1841
    q = c->buffer;
 
1842
    q += snprintf(q, c->buffer_size,
 
1843
                  "HTTP/1.0 404 Not Found\r\n"
 
1844
                  "Content-type: text/html\r\n"
 
1845
                  "\r\n"
 
1846
                  "<html>\n"
 
1847
                  "<head><title>404 Not Found</title></head>\n"
 
1848
                  "<body>%s</body>\n"
 
1849
                  "</html>\n", msg);
 
1850
    /* prepare output buffer */
 
1851
    c->buffer_ptr = c->buffer;
 
1852
    c->buffer_end = q;
 
1853
    c->state = HTTPSTATE_SEND_HEADER;
 
1854
    return 0;
 
1855
 send_status:
 
1856
    compute_status(c);
 
1857
    c->http_error = 200; /* horrible : we use this value to avoid
 
1858
                            going to the send data state */
 
1859
    c->state = HTTPSTATE_SEND_HEADER;
 
1860
    return 0;
 
1861
}
 
1862
 
 
1863
static void fmt_bytecount(AVIOContext *pb, int64_t count)
 
1864
{
 
1865
    static const char *suffix = " kMGTP";
 
1866
    const char *s;
 
1867
 
 
1868
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
 
1869
 
 
1870
    avio_printf(pb, "%"PRId64"%c", count, *s);
 
1871
}
 
1872
 
 
1873
static void compute_status(HTTPContext *c)
 
1874
{
 
1875
    HTTPContext *c1;
 
1876
    FFStream *stream;
 
1877
    char *p;
 
1878
    time_t ti;
 
1879
    int i, len;
 
1880
    AVIOContext *pb;
 
1881
 
 
1882
    if (avio_open_dyn_buf(&pb) < 0) {
 
1883
        /* XXX: return an error ? */
 
1884
        c->buffer_ptr = c->buffer;
 
1885
        c->buffer_end = c->buffer;
 
1886
        return;
 
1887
    }
 
1888
 
 
1889
    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
 
1890
    avio_printf(pb, "Content-type: %s\r\n", "text/html");
 
1891
    avio_printf(pb, "Pragma: no-cache\r\n");
 
1892
    avio_printf(pb, "\r\n");
 
1893
 
 
1894
    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
 
1895
    if (c->stream->feed_filename[0])
 
1896
        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
 
1897
    avio_printf(pb, "</head>\n<body>");
 
1898
    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
 
1899
    /* format status */
 
1900
    avio_printf(pb, "<h2>Available Streams</h2>\n");
 
1901
    avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
 
1902
    avio_printf(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");
 
1903
    stream = first_stream;
 
1904
    while (stream != NULL) {
 
1905
        char sfilename[1024];
 
1906
        char *eosf;
 
1907
 
 
1908
        if (stream->feed != stream) {
 
1909
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
 
1910
            eosf = sfilename + strlen(sfilename);
 
1911
            if (eosf - sfilename >= 4) {
 
1912
                if (strcmp(eosf - 4, ".asf") == 0)
 
1913
                    strcpy(eosf - 4, ".asx");
 
1914
                else if (strcmp(eosf - 3, ".rm") == 0)
 
1915
                    strcpy(eosf - 3, ".ram");
 
1916
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
 
1917
                    /* generate a sample RTSP director if
 
1918
                       unicast. Generate an SDP redirector if
 
1919
                       multicast */
 
1920
                    eosf = strrchr(sfilename, '.');
 
1921
                    if (!eosf)
 
1922
                        eosf = sfilename + strlen(sfilename);
 
1923
                    if (stream->is_multicast)
 
1924
                        strcpy(eosf, ".sdp");
 
1925
                    else
 
1926
                        strcpy(eosf, ".rtsp");
 
1927
                }
 
1928
            }
 
1929
 
 
1930
            avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
 
1931
                         sfilename, stream->filename);
 
1932
            avio_printf(pb, "<td align=right> %d <td align=right> ",
 
1933
                        stream->conns_served);
 
1934
            fmt_bytecount(pb, stream->bytes_served);
 
1935
            switch(stream->stream_type) {
 
1936
            case STREAM_TYPE_LIVE: {
 
1937
                    int audio_bit_rate = 0;
 
1938
                    int video_bit_rate = 0;
 
1939
                    const char *audio_codec_name = "";
 
1940
                    const char *video_codec_name = "";
 
1941
                    const char *audio_codec_name_extra = "";
 
1942
                    const char *video_codec_name_extra = "";
 
1943
 
 
1944
                    for(i=0;i<stream->nb_streams;i++) {
 
1945
                        AVStream *st = stream->streams[i];
 
1946
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
 
1947
                        switch(st->codec->codec_type) {
 
1948
                        case AVMEDIA_TYPE_AUDIO:
 
1949
                            audio_bit_rate += st->codec->bit_rate;
 
1950
                            if (codec) {
 
1951
                                if (*audio_codec_name)
 
1952
                                    audio_codec_name_extra = "...";
 
1953
                                audio_codec_name = codec->name;
 
1954
                            }
 
1955
                            break;
 
1956
                        case AVMEDIA_TYPE_VIDEO:
 
1957
                            video_bit_rate += st->codec->bit_rate;
 
1958
                            if (codec) {
 
1959
                                if (*video_codec_name)
 
1960
                                    video_codec_name_extra = "...";
 
1961
                                video_codec_name = codec->name;
 
1962
                            }
 
1963
                            break;
 
1964
                        case AVMEDIA_TYPE_DATA:
 
1965
                            video_bit_rate += st->codec->bit_rate;
 
1966
                            break;
 
1967
                        default:
 
1968
                            abort();
 
1969
                        }
 
1970
                    }
 
1971
                    avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
 
1972
                                 stream->fmt->name,
 
1973
                                 stream->bandwidth,
 
1974
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
 
1975
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
 
1976
                    if (stream->feed)
 
1977
                        avio_printf(pb, "<td>%s", stream->feed->filename);
 
1978
                    else
 
1979
                        avio_printf(pb, "<td>%s", stream->feed_filename);
 
1980
                    avio_printf(pb, "\n");
 
1981
                }
 
1982
                break;
 
1983
            default:
 
1984
                avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
 
1985
                break;
 
1986
            }
 
1987
        }
 
1988
        stream = stream->next;
 
1989
    }
 
1990
    avio_printf(pb, "</table>\n");
 
1991
 
 
1992
    stream = first_stream;
 
1993
    while (stream != NULL) {
 
1994
        if (stream->feed == stream) {
 
1995
            avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
 
1996
            if (stream->pid) {
 
1997
                avio_printf(pb, "Running as pid %d.\n", stream->pid);
 
1998
 
 
1999
#if defined(linux) && !defined(CONFIG_NOCUTILS)
 
2000
                {
 
2001
                    FILE *pid_stat;
 
2002
                    char ps_cmd[64];
 
2003
 
 
2004
                    /* This is somewhat linux specific I guess */
 
2005
                    snprintf(ps_cmd, sizeof(ps_cmd),
 
2006
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
 
2007
                             stream->pid);
 
2008
 
 
2009
                    pid_stat = popen(ps_cmd, "r");
 
2010
                    if (pid_stat) {
 
2011
                        char cpuperc[10];
 
2012
                        char cpuused[64];
 
2013
 
 
2014
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
 
2015
                                   cpuused) == 2) {
 
2016
                            avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
 
2017
                                         cpuperc, cpuused);
 
2018
                        }
 
2019
                        fclose(pid_stat);
 
2020
                    }
 
2021
                }
 
2022
#endif
 
2023
 
 
2024
                avio_printf(pb, "<p>");
 
2025
            }
 
2026
            avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
 
2027
 
 
2028
            for (i = 0; i < stream->nb_streams; i++) {
 
2029
                AVStream *st = stream->streams[i];
 
2030
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
 
2031
                const char *type = "unknown";
 
2032
                char parameters[64];
 
2033
 
 
2034
                parameters[0] = 0;
 
2035
 
 
2036
                switch(st->codec->codec_type) {
 
2037
                case AVMEDIA_TYPE_AUDIO:
 
2038
                    type = "audio";
 
2039
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
 
2040
                    break;
 
2041
                case AVMEDIA_TYPE_VIDEO:
 
2042
                    type = "video";
 
2043
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
 
2044
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
 
2045
                    break;
 
2046
                default:
 
2047
                    abort();
 
2048
                }
 
2049
                avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
 
2050
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
 
2051
            }
 
2052
            avio_printf(pb, "</table>\n");
 
2053
 
 
2054
        }
 
2055
        stream = stream->next;
 
2056
    }
 
2057
 
 
2058
    /* connection status */
 
2059
    avio_printf(pb, "<h2>Connection Status</h2>\n");
 
2060
 
 
2061
    avio_printf(pb, "Number of connections: %d / %d<br>\n",
 
2062
                 nb_connections, nb_max_connections);
 
2063
 
 
2064
    avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
 
2065
                 current_bandwidth, max_bandwidth);
 
2066
 
 
2067
    avio_printf(pb, "<table>\n");
 
2068
    avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
 
2069
    c1 = first_http_ctx;
 
2070
    i = 0;
 
2071
    while (c1 != NULL) {
 
2072
        int bitrate;
 
2073
        int j;
 
2074
 
 
2075
        bitrate = 0;
 
2076
        if (c1->stream) {
 
2077
            for (j = 0; j < c1->stream->nb_streams; j++) {
 
2078
                if (!c1->stream->feed)
 
2079
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
 
2080
                else if (c1->feed_streams[j] >= 0)
 
2081
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
 
2082
            }
 
2083
        }
 
2084
 
 
2085
        i++;
 
2086
        p = inet_ntoa(c1->from_addr.sin_addr);
 
2087
        avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
 
2088
                    i,
 
2089
                    c1->stream ? c1->stream->filename : "",
 
2090
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
 
2091
                    p,
 
2092
                    c1->protocol,
 
2093
                    http_state[c1->state]);
 
2094
        fmt_bytecount(pb, bitrate);
 
2095
        avio_printf(pb, "<td align=right>");
 
2096
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
 
2097
        avio_printf(pb, "<td align=right>");
 
2098
        fmt_bytecount(pb, c1->data_count);
 
2099
        avio_printf(pb, "\n");
 
2100
        c1 = c1->next;
 
2101
    }
 
2102
    avio_printf(pb, "</table>\n");
 
2103
 
 
2104
    /* date */
 
2105
    ti = time(NULL);
 
2106
    p = ctime(&ti);
 
2107
    avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
 
2108
    avio_printf(pb, "</body>\n</html>\n");
 
2109
 
 
2110
    len = avio_close_dyn_buf(pb, &c->pb_buffer);
 
2111
    c->buffer_ptr = c->pb_buffer;
 
2112
    c->buffer_end = c->pb_buffer + len;
 
2113
}
 
2114
 
 
2115
/* check if the parser needs to be opened for stream i */
 
2116
static void open_parser(AVFormatContext *s, int i)
 
2117
{
 
2118
    AVStream *st = s->streams[i];
 
2119
    AVCodec *codec;
 
2120
 
 
2121
    if (!st->codec->codec) {
 
2122
        codec = avcodec_find_decoder(st->codec->codec_id);
 
2123
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
 
2124
            st->codec->parse_only = 1;
 
2125
            if (avcodec_open2(st->codec, codec, NULL) < 0)
 
2126
                st->codec->parse_only = 0;
 
2127
        }
 
2128
    }
 
2129
}
 
2130
 
 
2131
static int open_input_stream(HTTPContext *c, const char *info)
 
2132
{
 
2133
    char buf[128];
 
2134
    char input_filename[1024];
 
2135
    AVFormatContext *s = NULL;
 
2136
    int i, ret;
 
2137
    int64_t stream_pos;
 
2138
 
 
2139
    /* find file name */
 
2140
    if (c->stream->feed) {
 
2141
        strcpy(input_filename, c->stream->feed->feed_filename);
 
2142
        /* compute position (absolute time) */
 
2143
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
 
2144
            if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
 
2145
                return ret;
 
2146
        } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
 
2147
            int prebuffer = strtol(buf, 0, 10);
 
2148
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
 
2149
        } else
 
2150
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
 
2151
    } else {
 
2152
        strcpy(input_filename, c->stream->feed_filename);
 
2153
        /* compute position (relative time) */
 
2154
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
 
2155
            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
 
2156
                return ret;
 
2157
        } else
 
2158
            stream_pos = 0;
 
2159
    }
 
2160
    if (input_filename[0] == '\0')
 
2161
        return -1;
 
2162
 
 
2163
    /* open stream */
 
2164
    if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
 
2165
        http_log("could not open %s: %d\n", input_filename, ret);
 
2166
        return -1;
 
2167
    }
 
2168
    s->flags |= AVFMT_FLAG_GENPTS;
 
2169
    c->fmt_in = s;
 
2170
    if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
 
2171
        http_log("Could not find stream info '%s'\n", input_filename);
 
2172
        avformat_close_input(&s);
 
2173
        return -1;
 
2174
    }
 
2175
 
 
2176
    /* open each parser */
 
2177
    for(i=0;i<s->nb_streams;i++)
 
2178
        open_parser(s, i);
 
2179
 
 
2180
    /* choose stream as clock source (we favorize video stream if
 
2181
       present) for packet sending */
 
2182
    c->pts_stream_index = 0;
 
2183
    for(i=0;i<c->stream->nb_streams;i++) {
 
2184
        if (c->pts_stream_index == 0 &&
 
2185
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
 
2186
            c->pts_stream_index = i;
 
2187
        }
 
2188
    }
 
2189
 
 
2190
    if (c->fmt_in->iformat->read_seek)
 
2191
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
 
2192
    /* set the start time (needed for maxtime and RTP packet timing) */
 
2193
    c->start_time = cur_time;
 
2194
    c->first_pts = AV_NOPTS_VALUE;
 
2195
    return 0;
 
2196
}
 
2197
 
 
2198
/* return the server clock (in us) */
 
2199
static int64_t get_server_clock(HTTPContext *c)
 
2200
{
 
2201
    /* compute current pts value from system time */
 
2202
    return (cur_time - c->start_time) * 1000;
 
2203
}
 
2204
 
 
2205
/* return the estimated time at which the current packet must be sent
 
2206
   (in us) */
 
2207
static int64_t get_packet_send_clock(HTTPContext *c)
 
2208
{
 
2209
    int bytes_left, bytes_sent, frame_bytes;
 
2210
 
 
2211
    frame_bytes = c->cur_frame_bytes;
 
2212
    if (frame_bytes <= 0)
 
2213
        return c->cur_pts;
 
2214
    else {
 
2215
        bytes_left = c->buffer_end - c->buffer_ptr;
 
2216
        bytes_sent = frame_bytes - bytes_left;
 
2217
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
 
2218
    }
 
2219
}
 
2220
 
 
2221
 
 
2222
static int http_prepare_data(HTTPContext *c)
 
2223
{
 
2224
    int i, len, ret;
 
2225
    AVFormatContext *ctx;
 
2226
 
 
2227
    av_freep(&c->pb_buffer);
 
2228
    switch(c->state) {
 
2229
    case HTTPSTATE_SEND_DATA_HEADER:
 
2230
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
 
2231
        av_dict_set(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
 
2232
        av_dict_set(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
 
2233
        av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
 
2234
        av_dict_set(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
 
2235
 
 
2236
        c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
 
2237
 
 
2238
        for(i=0;i<c->stream->nb_streams;i++) {
 
2239
            AVStream *src;
 
2240
            c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
 
2241
            /* if file or feed, then just take streams from FFStream struct */
 
2242
            if (!c->stream->feed ||
 
2243
                c->stream->feed == c->stream)
 
2244
                src = c->stream->streams[i];
 
2245
            else
 
2246
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
 
2247
 
 
2248
            *(c->fmt_ctx.streams[i]) = *src;
 
2249
            c->fmt_ctx.streams[i]->priv_data = 0;
 
2250
            c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
 
2251
                                           AVStream, not in codec */
 
2252
        }
 
2253
        /* set output format parameters */
 
2254
        c->fmt_ctx.oformat = c->stream->fmt;
 
2255
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
 
2256
 
 
2257
        c->got_key_frame = 0;
 
2258
 
 
2259
        /* prepare header and save header data in a stream */
 
2260
        if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
 
2261
            /* XXX: potential leak */
 
2262
            return -1;
 
2263
        }
 
2264
        c->fmt_ctx.pb->seekable = 0;
 
2265
 
 
2266
        /*
 
2267
         * HACK to avoid mpeg ps muxer to spit many underflow errors
 
2268
         * Default value from Libav
 
2269
         * Try to set it use configuration option
 
2270
         */
 
2271
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
 
2272
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
 
2273
 
 
2274
        if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
 
2275
            http_log("Error writing output header\n");
 
2276
            return -1;
 
2277
        }
 
2278
        av_dict_free(&c->fmt_ctx.metadata);
 
2279
 
 
2280
        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
 
2281
        c->buffer_ptr = c->pb_buffer;
 
2282
        c->buffer_end = c->pb_buffer + len;
 
2283
 
 
2284
        c->state = HTTPSTATE_SEND_DATA;
 
2285
        c->last_packet_sent = 0;
 
2286
        break;
 
2287
    case HTTPSTATE_SEND_DATA:
 
2288
        /* find a new packet */
 
2289
        /* read a packet from the input stream */
 
2290
        if (c->stream->feed)
 
2291
            ffm_set_write_index(c->fmt_in,
 
2292
                                c->stream->feed->feed_write_index,
 
2293
                                c->stream->feed->feed_size);
 
2294
 
 
2295
        if (c->stream->max_time &&
 
2296
            c->stream->max_time + c->start_time - cur_time < 0)
 
2297
            /* We have timed out */
 
2298
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
 
2299
        else {
 
2300
            AVPacket pkt;
 
2301
        redo:
 
2302
            ret = av_read_frame(c->fmt_in, &pkt);
 
2303
            if (ret < 0) {
 
2304
                if (c->stream->feed) {
 
2305
                    /* if coming from feed, it means we reached the end of the
 
2306
                       ffm file, so must wait for more data */
 
2307
                    c->state = HTTPSTATE_WAIT_FEED;
 
2308
                    return 1; /* state changed */
 
2309
                } else if (ret == AVERROR(EAGAIN)) {
 
2310
                    /* input not ready, come back later */
 
2311
                    return 0;
 
2312
                } else {
 
2313
                    if (c->stream->loop) {
 
2314
                        avformat_close_input(&c->fmt_in);
 
2315
                        if (open_input_stream(c, "") < 0)
 
2316
                            goto no_loop;
 
2317
                        goto redo;
 
2318
                    } else {
 
2319
                    no_loop:
 
2320
                        /* must send trailer now because eof or error */
 
2321
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
 
2322
                    }
 
2323
                }
 
2324
            } else {
 
2325
                int source_index = pkt.stream_index;
 
2326
                /* update first pts if needed */
 
2327
                if (c->first_pts == AV_NOPTS_VALUE) {
 
2328
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
 
2329
                    c->start_time = cur_time;
 
2330
                }
 
2331
                /* send it to the appropriate stream */
 
2332
                if (c->stream->feed) {
 
2333
                    /* if coming from a feed, select the right stream */
 
2334
                    if (c->switch_pending) {
 
2335
                        c->switch_pending = 0;
 
2336
                        for(i=0;i<c->stream->nb_streams;i++) {
 
2337
                            if (c->switch_feed_streams[i] == pkt.stream_index)
 
2338
                                if (pkt.flags & AV_PKT_FLAG_KEY)
 
2339
                                    c->switch_feed_streams[i] = -1;
 
2340
                            if (c->switch_feed_streams[i] >= 0)
 
2341
                                c->switch_pending = 1;
 
2342
                        }
 
2343
                    }
 
2344
                    for(i=0;i<c->stream->nb_streams;i++) {
 
2345
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
 
2346
                            AVStream *st = c->fmt_in->streams[source_index];
 
2347
                            pkt.stream_index = i;
 
2348
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
 
2349
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
 
2350
                                 c->stream->nb_streams == 1))
 
2351
                                c->got_key_frame = 1;
 
2352
                            if (!c->stream->send_on_key || c->got_key_frame)
 
2353
                                goto send_it;
 
2354
                        }
 
2355
                    }
 
2356
                } else {
 
2357
                    AVCodecContext *codec;
 
2358
                    AVStream *ist, *ost;
 
2359
                send_it:
 
2360
                    ist = c->fmt_in->streams[source_index];
 
2361
                    /* specific handling for RTP: we use several
 
2362
                       output stream (one for each RTP
 
2363
                       connection). XXX: need more abstract handling */
 
2364
                    if (c->is_packetized) {
 
2365
                        /* compute send time and duration */
 
2366
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
 
2367
                        c->cur_pts -= c->first_pts;
 
2368
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
 
2369
                        /* find RTP context */
 
2370
                        c->packet_stream_index = pkt.stream_index;
 
2371
                        ctx = c->rtp_ctx[c->packet_stream_index];
 
2372
                        if(!ctx) {
 
2373
                            av_free_packet(&pkt);
 
2374
                            break;
 
2375
                        }
 
2376
                        codec = ctx->streams[0]->codec;
 
2377
                        /* only one stream per RTP connection */
 
2378
                        pkt.stream_index = 0;
 
2379
                    } else {
 
2380
                        ctx = &c->fmt_ctx;
 
2381
                        /* Fudge here */
 
2382
                        codec = ctx->streams[pkt.stream_index]->codec;
 
2383
                    }
 
2384
 
 
2385
                    if (c->is_packetized) {
 
2386
                        int max_packet_size;
 
2387
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
 
2388
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
 
2389
                        else
 
2390
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
 
2391
                        ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
 
2392
                    } else {
 
2393
                        ret = avio_open_dyn_buf(&ctx->pb);
 
2394
                    }
 
2395
                    if (ret < 0) {
 
2396
                        /* XXX: potential leak */
 
2397
                        return -1;
 
2398
                    }
 
2399
                    ost = ctx->streams[pkt.stream_index];
 
2400
 
 
2401
                    ctx->pb->seekable = 0;
 
2402
                    if (pkt.dts != AV_NOPTS_VALUE)
 
2403
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
 
2404
                    if (pkt.pts != AV_NOPTS_VALUE)
 
2405
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
 
2406
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
 
2407
                    if (av_write_frame(ctx, &pkt) < 0) {
 
2408
                        http_log("Error writing frame to output\n");
 
2409
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
 
2410
                    }
 
2411
 
 
2412
                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
 
2413
                    c->cur_frame_bytes = len;
 
2414
                    c->buffer_ptr = c->pb_buffer;
 
2415
                    c->buffer_end = c->pb_buffer + len;
 
2416
 
 
2417
                    codec->frame_number++;
 
2418
                    if (len == 0) {
 
2419
                        av_free_packet(&pkt);
 
2420
                        goto redo;
 
2421
                    }
 
2422
                }
 
2423
                av_free_packet(&pkt);
 
2424
            }
 
2425
        }
 
2426
        break;
 
2427
    default:
 
2428
    case HTTPSTATE_SEND_DATA_TRAILER:
 
2429
        /* last packet test ? */
 
2430
        if (c->last_packet_sent || c->is_packetized)
 
2431
            return -1;
 
2432
        ctx = &c->fmt_ctx;
 
2433
        /* prepare header */
 
2434
        if (avio_open_dyn_buf(&ctx->pb) < 0) {
 
2435
            /* XXX: potential leak */
 
2436
            return -1;
 
2437
        }
 
2438
        c->fmt_ctx.pb->seekable = 0;
 
2439
        av_write_trailer(ctx);
 
2440
        len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
 
2441
        c->buffer_ptr = c->pb_buffer;
 
2442
        c->buffer_end = c->pb_buffer + len;
 
2443
 
 
2444
        c->last_packet_sent = 1;
 
2445
        break;
 
2446
    }
 
2447
    return 0;
 
2448
}
 
2449
 
 
2450
/* should convert the format at the same time */
 
2451
/* send data starting at c->buffer_ptr to the output connection
 
2452
   (either UDP or TCP connection) */
 
2453
static int http_send_data(HTTPContext *c)
 
2454
{
 
2455
    int len, ret;
 
2456
 
 
2457
    for(;;) {
 
2458
        if (c->buffer_ptr >= c->buffer_end) {
 
2459
            ret = http_prepare_data(c);
 
2460
            if (ret < 0)
 
2461
                return -1;
 
2462
            else if (ret != 0)
 
2463
                /* state change requested */
 
2464
                break;
 
2465
        } else {
 
2466
            if (c->is_packetized) {
 
2467
                /* RTP data output */
 
2468
                len = c->buffer_end - c->buffer_ptr;
 
2469
                if (len < 4) {
 
2470
                    /* fail safe - should never happen */
 
2471
                fail1:
 
2472
                    c->buffer_ptr = c->buffer_end;
 
2473
                    return 0;
 
2474
                }
 
2475
                len = (c->buffer_ptr[0] << 24) |
 
2476
                    (c->buffer_ptr[1] << 16) |
 
2477
                    (c->buffer_ptr[2] << 8) |
 
2478
                    (c->buffer_ptr[3]);
 
2479
                if (len > (c->buffer_end - c->buffer_ptr))
 
2480
                    goto fail1;
 
2481
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
 
2482
                    /* nothing to send yet: we can wait */
 
2483
                    return 0;
 
2484
                }
 
2485
 
 
2486
                c->data_count += len;
 
2487
                update_datarate(&c->datarate, c->data_count);
 
2488
                if (c->stream)
 
2489
                    c->stream->bytes_served += len;
 
2490
 
 
2491
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
 
2492
                    /* RTP packets are sent inside the RTSP TCP connection */
 
2493
                    AVIOContext *pb;
 
2494
                    int interleaved_index, size;
 
2495
                    uint8_t header[4];
 
2496
                    HTTPContext *rtsp_c;
 
2497
 
 
2498
                    rtsp_c = c->rtsp_c;
 
2499
                    /* if no RTSP connection left, error */
 
2500
                    if (!rtsp_c)
 
2501
                        return -1;
 
2502
                    /* if already sending something, then wait. */
 
2503
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
 
2504
                        break;
 
2505
                    if (avio_open_dyn_buf(&pb) < 0)
 
2506
                        goto fail1;
 
2507
                    interleaved_index = c->packet_stream_index * 2;
 
2508
                    /* RTCP packets are sent at odd indexes */
 
2509
                    if (c->buffer_ptr[1] == 200)
 
2510
                        interleaved_index++;
 
2511
                    /* write RTSP TCP header */
 
2512
                    header[0] = '$';
 
2513
                    header[1] = interleaved_index;
 
2514
                    header[2] = len >> 8;
 
2515
                    header[3] = len;
 
2516
                    avio_write(pb, header, 4);
 
2517
                    /* write RTP packet data */
 
2518
                    c->buffer_ptr += 4;
 
2519
                    avio_write(pb, c->buffer_ptr, len);
 
2520
                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
 
2521
                    /* prepare asynchronous TCP sending */
 
2522
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
 
2523
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
 
2524
                    c->buffer_ptr += len;
 
2525
 
 
2526
                    /* send everything we can NOW */
 
2527
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
 
2528
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
 
2529
                    if (len > 0)
 
2530
                        rtsp_c->packet_buffer_ptr += len;
 
2531
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
 
2532
                        /* if we could not send all the data, we will
 
2533
                           send it later, so a new state is needed to
 
2534
                           "lock" the RTSP TCP connection */
 
2535
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
 
2536
                        break;
 
2537
                    } else
 
2538
                        /* all data has been sent */
 
2539
                        av_freep(&c->packet_buffer);
 
2540
                } else {
 
2541
                    /* send RTP packet directly in UDP */
 
2542
                    c->buffer_ptr += 4;
 
2543
                    url_write(c->rtp_handles[c->packet_stream_index],
 
2544
                              c->buffer_ptr, len);
 
2545
                    c->buffer_ptr += len;
 
2546
                    /* here we continue as we can send several packets per 10 ms slot */
 
2547
                }
 
2548
            } else {
 
2549
                /* TCP data output */
 
2550
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
 
2551
                if (len < 0) {
 
2552
                    if (ff_neterrno() != AVERROR(EAGAIN) &&
 
2553
                        ff_neterrno() != AVERROR(EINTR))
 
2554
                        /* error : close connection */
 
2555
                        return -1;
 
2556
                    else
 
2557
                        return 0;
 
2558
                } else
 
2559
                    c->buffer_ptr += len;
 
2560
 
 
2561
                c->data_count += len;
 
2562
                update_datarate(&c->datarate, c->data_count);
 
2563
                if (c->stream)
 
2564
                    c->stream->bytes_served += len;
 
2565
                break;
 
2566
            }
 
2567
        }
 
2568
    } /* for(;;) */
 
2569
    return 0;
 
2570
}
 
2571
 
 
2572
static int http_start_receive_data(HTTPContext *c)
 
2573
{
 
2574
    int fd;
 
2575
 
 
2576
    if (c->stream->feed_opened)
 
2577
        return -1;
 
2578
 
 
2579
    /* Don't permit writing to this one */
 
2580
    if (c->stream->readonly)
 
2581
        return -1;
 
2582
 
 
2583
    /* open feed */
 
2584
    fd = open(c->stream->feed_filename, O_RDWR);
 
2585
    if (fd < 0) {
 
2586
        http_log("Error opening feeder file: %s\n", strerror(errno));
 
2587
        return -1;
 
2588
    }
 
2589
    c->feed_fd = fd;
 
2590
 
 
2591
    if (c->stream->truncate) {
 
2592
        /* truncate feed file */
 
2593
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
 
2594
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
 
2595
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
 
2596
    } else {
 
2597
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
 
2598
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
 
2599
            return -1;
 
2600
        }
 
2601
    }
 
2602
 
 
2603
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
 
2604
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
 
2605
    lseek(fd, 0, SEEK_SET);
 
2606
 
 
2607
    /* init buffer input */
 
2608
    c->buffer_ptr = c->buffer;
 
2609
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
 
2610
    c->stream->feed_opened = 1;
 
2611
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
 
2612
    return 0;
 
2613
}
 
2614
 
 
2615
static int http_receive_data(HTTPContext *c)
 
2616
{
 
2617
    HTTPContext *c1;
 
2618
    int len, loop_run = 0;
 
2619
 
 
2620
    while (c->chunked_encoding && !c->chunk_size &&
 
2621
           c->buffer_end > c->buffer_ptr) {
 
2622
        /* read chunk header, if present */
 
2623
        len = recv(c->fd, c->buffer_ptr, 1, 0);
 
2624
 
 
2625
        if (len < 0) {
 
2626
            if (ff_neterrno() != AVERROR(EAGAIN) &&
 
2627
                ff_neterrno() != AVERROR(EINTR))
 
2628
                /* error : close connection */
 
2629
                goto fail;
 
2630
            return 0;
 
2631
        } else if (len == 0) {
 
2632
            /* end of connection : close it */
 
2633
            goto fail;
 
2634
        } else if (c->buffer_ptr - c->buffer >= 2 &&
 
2635
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
 
2636
            c->chunk_size = strtol(c->buffer, 0, 16);
 
2637
            if (c->chunk_size == 0) // end of stream
 
2638
                goto fail;
 
2639
            c->buffer_ptr = c->buffer;
 
2640
            break;
 
2641
        } else if (++loop_run > 10) {
 
2642
            /* no chunk header, abort */
 
2643
            goto fail;
 
2644
        } else {
 
2645
            c->buffer_ptr++;
 
2646
        }
 
2647
    }
 
2648
 
 
2649
    if (c->buffer_end > c->buffer_ptr) {
 
2650
        len = recv(c->fd, c->buffer_ptr,
 
2651
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
 
2652
        if (len < 0) {
 
2653
            if (ff_neterrno() != AVERROR(EAGAIN) &&
 
2654
                ff_neterrno() != AVERROR(EINTR))
 
2655
                /* error : close connection */
 
2656
                goto fail;
 
2657
        } else if (len == 0)
 
2658
            /* end of connection : close it */
 
2659
            goto fail;
 
2660
        else {
 
2661
            c->chunk_size -= len;
 
2662
            c->buffer_ptr += len;
 
2663
            c->data_count += len;
 
2664
            update_datarate(&c->datarate, c->data_count);
 
2665
        }
 
2666
    }
 
2667
 
 
2668
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
 
2669
        if (c->buffer[0] != 'f' ||
 
2670
            c->buffer[1] != 'm') {
 
2671
            http_log("Feed stream has become desynchronized -- disconnecting\n");
 
2672
            goto fail;
 
2673
        }
 
2674
    }
 
2675
 
 
2676
    if (c->buffer_ptr >= c->buffer_end) {
 
2677
        FFStream *feed = c->stream;
 
2678
        /* a packet has been received : write it in the store, except
 
2679
           if header */
 
2680
        if (c->data_count > FFM_PACKET_SIZE) {
 
2681
 
 
2682
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
 
2683
            /* XXX: use llseek or url_seek */
 
2684
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
 
2685
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
 
2686
                http_log("Error writing to feed file: %s\n", strerror(errno));
 
2687
                goto fail;
 
2688
            }
 
2689
 
 
2690
            feed->feed_write_index += FFM_PACKET_SIZE;
 
2691
            /* update file size */
 
2692
            if (feed->feed_write_index > c->stream->feed_size)
 
2693
                feed->feed_size = feed->feed_write_index;
 
2694
 
 
2695
            /* handle wrap around if max file size reached */
 
2696
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
 
2697
                feed->feed_write_index = FFM_PACKET_SIZE;
 
2698
 
 
2699
            /* write index */
 
2700
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
 
2701
                http_log("Error writing index to feed file: %s\n", strerror(errno));
 
2702
                goto fail;
 
2703
            }
 
2704
 
 
2705
            /* wake up any waiting connections */
 
2706
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
 
2707
                if (c1->state == HTTPSTATE_WAIT_FEED &&
 
2708
                    c1->stream->feed == c->stream->feed)
 
2709
                    c1->state = HTTPSTATE_SEND_DATA;
 
2710
            }
 
2711
        } else {
 
2712
            /* We have a header in our hands that contains useful data */
 
2713
            AVFormatContext *s = avformat_alloc_context();
 
2714
            AVIOContext *pb;
 
2715
            AVInputFormat *fmt_in;
 
2716
            int i;
 
2717
 
 
2718
            if (!s)
 
2719
                goto fail;
 
2720
 
 
2721
            /* use feed output format name to find corresponding input format */
 
2722
            fmt_in = av_find_input_format(feed->fmt->name);
 
2723
            if (!fmt_in)
 
2724
                goto fail;
 
2725
 
 
2726
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
 
2727
                                    0, NULL, NULL, NULL, NULL);
 
2728
            pb->seekable = 0;
 
2729
 
 
2730
            s->pb = pb;
 
2731
            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
 
2732
                av_free(pb);
 
2733
                goto fail;
 
2734
            }
 
2735
 
 
2736
            /* Now we have the actual streams */
 
2737
            if (s->nb_streams != feed->nb_streams) {
 
2738
                avformat_close_input(&s);
 
2739
                av_free(pb);
 
2740
                http_log("Feed '%s' stream number does not match registered feed\n",
 
2741
                         c->stream->feed_filename);
 
2742
                goto fail;
 
2743
            }
 
2744
 
 
2745
            for (i = 0; i < s->nb_streams; i++) {
 
2746
                AVStream *fst = feed->streams[i];
 
2747
                AVStream *st = s->streams[i];
 
2748
                avcodec_copy_context(fst->codec, st->codec);
 
2749
            }
 
2750
 
 
2751
            avformat_close_input(&s);
 
2752
            av_free(pb);
 
2753
        }
 
2754
        c->buffer_ptr = c->buffer;
 
2755
    }
 
2756
 
 
2757
    return 0;
 
2758
 fail:
 
2759
    c->stream->feed_opened = 0;
 
2760
    close(c->feed_fd);
 
2761
    /* wake up any waiting connections to stop waiting for feed */
 
2762
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
 
2763
        if (c1->state == HTTPSTATE_WAIT_FEED &&
 
2764
            c1->stream->feed == c->stream->feed)
 
2765
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
 
2766
    }
 
2767
    return -1;
 
2768
}
 
2769
 
 
2770
/********************************************************************/
 
2771
/* RTSP handling */
 
2772
 
 
2773
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
 
2774
{
 
2775
    const char *str;
 
2776
    time_t ti;
 
2777
    struct tm *tm;
 
2778
    char buf2[32];
 
2779
 
 
2780
    switch(error_number) {
 
2781
    case RTSP_STATUS_OK:
 
2782
        str = "OK";
 
2783
        break;
 
2784
    case RTSP_STATUS_METHOD:
 
2785
        str = "Method Not Allowed";
 
2786
        break;
 
2787
    case RTSP_STATUS_BANDWIDTH:
 
2788
        str = "Not Enough Bandwidth";
 
2789
        break;
 
2790
    case RTSP_STATUS_SESSION:
 
2791
        str = "Session Not Found";
 
2792
        break;
 
2793
    case RTSP_STATUS_STATE:
 
2794
        str = "Method Not Valid in This State";
 
2795
        break;
 
2796
    case RTSP_STATUS_AGGREGATE:
 
2797
        str = "Aggregate operation not allowed";
 
2798
        break;
 
2799
    case RTSP_STATUS_ONLY_AGGREGATE:
 
2800
        str = "Only aggregate operation allowed";
 
2801
        break;
 
2802
    case RTSP_STATUS_TRANSPORT:
 
2803
        str = "Unsupported transport";
 
2804
        break;
 
2805
    case RTSP_STATUS_INTERNAL:
 
2806
        str = "Internal Server Error";
 
2807
        break;
 
2808
    case RTSP_STATUS_SERVICE:
 
2809
        str = "Service Unavailable";
 
2810
        break;
 
2811
    case RTSP_STATUS_VERSION:
 
2812
        str = "RTSP Version not supported";
 
2813
        break;
 
2814
    default:
 
2815
        str = "Unknown Error";
 
2816
        break;
 
2817
    }
 
2818
 
 
2819
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
 
2820
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
 
2821
 
 
2822
    /* output GMT time */
 
2823
    ti = time(NULL);
 
2824
    tm = gmtime(&ti);
 
2825
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
 
2826
    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
 
2827
}
 
2828
 
 
2829
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
 
2830
{
 
2831
    rtsp_reply_header(c, error_number);
 
2832
    avio_printf(c->pb, "\r\n");
 
2833
}
 
2834
 
 
2835
static int rtsp_parse_request(HTTPContext *c)
 
2836
{
 
2837
    const char *p, *p1, *p2;
 
2838
    char cmd[32];
 
2839
    char url[1024];
 
2840
    char protocol[32];
 
2841
    char line[1024];
 
2842
    int len;
 
2843
    RTSPMessageHeader header1, *header = &header1;
 
2844
 
 
2845
    c->buffer_ptr[0] = '\0';
 
2846
    p = c->buffer;
 
2847
 
 
2848
    get_word(cmd, sizeof(cmd), &p);
 
2849
    get_word(url, sizeof(url), &p);
 
2850
    get_word(protocol, sizeof(protocol), &p);
 
2851
 
 
2852
    av_strlcpy(c->method, cmd, sizeof(c->method));
 
2853
    av_strlcpy(c->url, url, sizeof(c->url));
 
2854
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
 
2855
 
 
2856
    if (avio_open_dyn_buf(&c->pb) < 0) {
 
2857
        /* XXX: cannot do more */
 
2858
        c->pb = NULL; /* safety */
 
2859
        return -1;
 
2860
    }
 
2861
 
 
2862
    /* check version name */
 
2863
    if (strcmp(protocol, "RTSP/1.0") != 0) {
 
2864
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
 
2865
        goto the_end;
 
2866
    }
 
2867
 
 
2868
    /* parse each header line */
 
2869
    memset(header, 0, sizeof(*header));
 
2870
    /* skip to next line */
 
2871
    while (*p != '\n' && *p != '\0')
 
2872
        p++;
 
2873
    if (*p == '\n')
 
2874
        p++;
 
2875
    while (*p != '\0') {
 
2876
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
 
2877
        if (!p1)
 
2878
            break;
 
2879
        p2 = p1;
 
2880
        if (p2 > p && p2[-1] == '\r')
 
2881
            p2--;
 
2882
        /* skip empty line */
 
2883
        if (p2 == p)
 
2884
            break;
 
2885
        len = p2 - p;
 
2886
        if (len > sizeof(line) - 1)
 
2887
            len = sizeof(line) - 1;
 
2888
        memcpy(line, p, len);
 
2889
        line[len] = '\0';
 
2890
        ff_rtsp_parse_line(header, line, NULL, NULL);
 
2891
        p = p1 + 1;
 
2892
    }
 
2893
 
 
2894
    /* handle sequence number */
 
2895
    c->seq = header->seq;
 
2896
 
 
2897
    if (!strcmp(cmd, "DESCRIBE"))
 
2898
        rtsp_cmd_describe(c, url);
 
2899
    else if (!strcmp(cmd, "OPTIONS"))
 
2900
        rtsp_cmd_options(c, url);
 
2901
    else if (!strcmp(cmd, "SETUP"))
 
2902
        rtsp_cmd_setup(c, url, header);
 
2903
    else if (!strcmp(cmd, "PLAY"))
 
2904
        rtsp_cmd_play(c, url, header);
 
2905
    else if (!strcmp(cmd, "PAUSE"))
 
2906
        rtsp_cmd_pause(c, url, header);
 
2907
    else if (!strcmp(cmd, "TEARDOWN"))
 
2908
        rtsp_cmd_teardown(c, url, header);
 
2909
    else
 
2910
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
 
2911
 
 
2912
 the_end:
 
2913
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
 
2914
    c->pb = NULL; /* safety */
 
2915
    if (len < 0) {
 
2916
        /* XXX: cannot do more */
 
2917
        return -1;
 
2918
    }
 
2919
    c->buffer_ptr = c->pb_buffer;
 
2920
    c->buffer_end = c->pb_buffer + len;
 
2921
    c->state = RTSPSTATE_SEND_REPLY;
 
2922
    return 0;
 
2923
}
 
2924
 
 
2925
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
 
2926
                                   struct in_addr my_ip)
 
2927
{
 
2928
    AVFormatContext *avc;
 
2929
    AVStream *avs = NULL;
 
2930
    int i;
 
2931
 
 
2932
    avc =  avformat_alloc_context();
 
2933
    if (avc == NULL) {
 
2934
        return -1;
 
2935
    }
 
2936
    av_dict_set(&avc->metadata, "title",
 
2937
               stream->title[0] ? stream->title : "No Title", 0);
 
2938
    avc->nb_streams = stream->nb_streams;
 
2939
    if (stream->is_multicast) {
 
2940
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
 
2941
                 inet_ntoa(stream->multicast_ip),
 
2942
                 stream->multicast_port, stream->multicast_ttl);
 
2943
    } else {
 
2944
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
 
2945
    }
 
2946
 
 
2947
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
 
2948
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
 
2949
        goto sdp_done;
 
2950
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
 
2951
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
 
2952
        goto sdp_done;
 
2953
 
 
2954
    for(i = 0; i < stream->nb_streams; i++) {
 
2955
        avc->streams[i] = &avs[i];
 
2956
        avc->streams[i]->codec = stream->streams[i]->codec;
 
2957
    }
 
2958
    *pbuffer = av_mallocz(2048);
 
2959
    av_sdp_create(&avc, 1, *pbuffer, 2048);
 
2960
 
 
2961
 sdp_done:
 
2962
    av_free(avc->streams);
 
2963
    av_dict_free(&avc->metadata);
 
2964
    av_free(avc);
 
2965
    av_free(avs);
 
2966
 
 
2967
    return strlen(*pbuffer);
 
2968
}
 
2969
 
 
2970
static void rtsp_cmd_options(HTTPContext *c, const char *url)
 
2971
{
 
2972
//    rtsp_reply_header(c, RTSP_STATUS_OK);
 
2973
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
 
2974
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
 
2975
    avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
 
2976
    avio_printf(c->pb, "\r\n");
 
2977
}
 
2978
 
 
2979
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
 
2980
{
 
2981
    FFStream *stream;
 
2982
    char path1[1024];
 
2983
    const char *path;
 
2984
    uint8_t *content;
 
2985
    int content_length, len;
 
2986
    struct sockaddr_in my_addr;
 
2987
 
 
2988
    /* find which url is asked */
 
2989
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
 
2990
    path = path1;
 
2991
    if (*path == '/')
 
2992
        path++;
 
2993
 
 
2994
    for(stream = first_stream; stream != NULL; stream = stream->next) {
 
2995
        if (!stream->is_feed &&
 
2996
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
 
2997
            !strcmp(path, stream->filename)) {
 
2998
            goto found;
 
2999
        }
 
3000
    }
 
3001
    /* no stream found */
 
3002
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
 
3003
    return;
 
3004
 
 
3005
 found:
 
3006
    /* prepare the media description in sdp format */
 
3007
 
 
3008
    /* get the host IP */
 
3009
    len = sizeof(my_addr);
 
3010
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
 
3011
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
 
3012
    if (content_length < 0) {
 
3013
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
 
3014
        return;
 
3015
    }
 
3016
    rtsp_reply_header(c, RTSP_STATUS_OK);
 
3017
    avio_printf(c->pb, "Content-Base: %s/\r\n", url);
 
3018
    avio_printf(c->pb, "Content-Type: application/sdp\r\n");
 
3019
    avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
 
3020
    avio_printf(c->pb, "\r\n");
 
3021
    avio_write(c->pb, content, content_length);
 
3022
    av_free(content);
 
3023
}
 
3024
 
 
3025
static HTTPContext *find_rtp_session(const char *session_id)
 
3026
{
 
3027
    HTTPContext *c;
 
3028
 
 
3029
    if (session_id[0] == '\0')
 
3030
        return NULL;
 
3031
 
 
3032
    for(c = first_http_ctx; c != NULL; c = c->next) {
 
3033
        if (!strcmp(c->session_id, session_id))
 
3034
            return c;
 
3035
    }
 
3036
    return NULL;
 
3037
}
 
3038
 
 
3039
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
 
3040
{
 
3041
    RTSPTransportField *th;
 
3042
    int i;
 
3043
 
 
3044
    for(i=0;i<h->nb_transports;i++) {
 
3045
        th = &h->transports[i];
 
3046
        if (th->lower_transport == lower_transport)
 
3047
            return th;
 
3048
    }
 
3049
    return NULL;
 
3050
}
 
3051
 
 
3052
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
 
3053
                           RTSPMessageHeader *h)
 
3054
{
 
3055
    FFStream *stream;
 
3056
    int stream_index, rtp_port, rtcp_port;
 
3057
    char buf[1024];
 
3058
    char path1[1024];
 
3059
    const char *path;
 
3060
    HTTPContext *rtp_c;
 
3061
    RTSPTransportField *th;
 
3062
    struct sockaddr_in dest_addr;
 
3063
    RTSPActionServerSetup setup;
 
3064
 
 
3065
    /* find which url is asked */
 
3066
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
 
3067
    path = path1;
 
3068
    if (*path == '/')
 
3069
        path++;
 
3070
 
 
3071
    /* now check each stream */
 
3072
    for(stream = first_stream; stream != NULL; stream = stream->next) {
 
3073
        if (!stream->is_feed &&
 
3074
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
 
3075
            /* accept aggregate filenames only if single stream */
 
3076
            if (!strcmp(path, stream->filename)) {
 
3077
                if (stream->nb_streams != 1) {
 
3078
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
 
3079
                    return;
 
3080
                }
 
3081
                stream_index = 0;
 
3082
                goto found;
 
3083
            }
 
3084
 
 
3085
            for(stream_index = 0; stream_index < stream->nb_streams;
 
3086
                stream_index++) {
 
3087
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
 
3088
                         stream->filename, stream_index);
 
3089
                if (!strcmp(path, buf))
 
3090
                    goto found;
 
3091
            }
 
3092
        }
 
3093
    }
 
3094
    /* no stream found */
 
3095
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
 
3096
    return;
 
3097
 found:
 
3098
 
 
3099
    /* generate session id if needed */
 
3100
    if (h->session_id[0] == '\0')
 
3101
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
 
3102
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
 
3103
 
 
3104
    /* find rtp session, and create it if none found */
 
3105
    rtp_c = find_rtp_session(h->session_id);
 
3106
    if (!rtp_c) {
 
3107
        /* always prefer UDP */
 
3108
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
 
3109
        if (!th) {
 
3110
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
 
3111
            if (!th) {
 
3112
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
 
3113
                return;
 
3114
            }
 
3115
        }
 
3116
 
 
3117
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
 
3118
                                   th->lower_transport);
 
3119
        if (!rtp_c) {
 
3120
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
 
3121
            return;
 
3122
        }
 
3123
 
 
3124
        /* open input stream */
 
3125
        if (open_input_stream(rtp_c, "") < 0) {
 
3126
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
 
3127
            return;
 
3128
        }
 
3129
    }
 
3130
 
 
3131
    /* test if stream is OK (test needed because several SETUP needs
 
3132
       to be done for a given file) */
 
3133
    if (rtp_c->stream != stream) {
 
3134
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
 
3135
        return;
 
3136
    }
 
3137
 
 
3138
    /* test if stream is already set up */
 
3139
    if (rtp_c->rtp_ctx[stream_index]) {
 
3140
        rtsp_reply_error(c, RTSP_STATUS_STATE);
 
3141
        return;
 
3142
    }
 
3143
 
 
3144
    /* check transport */
 
3145
    th = find_transport(h, rtp_c->rtp_protocol);
 
3146
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
 
3147
                th->client_port_min <= 0)) {
 
3148
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
 
3149
        return;
 
3150
    }
 
3151
 
 
3152
    /* setup default options */
 
3153
    setup.transport_option[0] = '\0';
 
3154
    dest_addr = rtp_c->from_addr;
 
3155
    dest_addr.sin_port = htons(th->client_port_min);
 
3156
 
 
3157
    /* setup stream */
 
3158
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
 
3159
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
 
3160
        return;
 
3161
    }
 
3162
 
 
3163
    /* now everything is OK, so we can send the connection parameters */
 
3164
    rtsp_reply_header(c, RTSP_STATUS_OK);
 
3165
    /* session ID */
 
3166
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
 
3167
 
 
3168
    switch(rtp_c->rtp_protocol) {
 
3169
    case RTSP_LOWER_TRANSPORT_UDP:
 
3170
        rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
 
3171
        rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
 
3172
        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
 
3173
                    "client_port=%d-%d;server_port=%d-%d",
 
3174
                    th->client_port_min, th->client_port_max,
 
3175
                    rtp_port, rtcp_port);
 
3176
        break;
 
3177
    case RTSP_LOWER_TRANSPORT_TCP:
 
3178
        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
 
3179
                    stream_index * 2, stream_index * 2 + 1);
 
3180
        break;
 
3181
    default:
 
3182
        break;
 
3183
    }
 
3184
    if (setup.transport_option[0] != '\0')
 
3185
        avio_printf(c->pb, ";%s", setup.transport_option);
 
3186
    avio_printf(c->pb, "\r\n");
 
3187
 
 
3188
 
 
3189
    avio_printf(c->pb, "\r\n");
 
3190
}
 
3191
 
 
3192
 
 
3193
/* find an rtp connection by using the session ID. Check consistency
 
3194
   with filename */
 
3195
static HTTPContext *find_rtp_session_with_url(const char *url,
 
3196
                                              const char *session_id)
 
3197
{
 
3198
    HTTPContext *rtp_c;
 
3199
    char path1[1024];
 
3200
    const char *path;
 
3201
    char buf[1024];
 
3202
    int s, len;
 
3203
 
 
3204
    rtp_c = find_rtp_session(session_id);
 
3205
    if (!rtp_c)
 
3206
        return NULL;
 
3207
 
 
3208
    /* find which url is asked */
 
3209
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
 
3210
    path = path1;
 
3211
    if (*path == '/')
 
3212
        path++;
 
3213
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
 
3214
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
 
3215
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
 
3216
        rtp_c->stream->filename, s);
 
3217
      if(!strncmp(path, buf, sizeof(buf))) {
 
3218
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
 
3219
        return rtp_c;
 
3220
      }
 
3221
    }
 
3222
    len = strlen(path);
 
3223
    if (len > 0 && path[len - 1] == '/' &&
 
3224
        !strncmp(path, rtp_c->stream->filename, len - 1))
 
3225
        return rtp_c;
 
3226
    return NULL;
 
3227
}
 
3228
 
 
3229
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
 
3230
{
 
3231
    HTTPContext *rtp_c;
 
3232
 
 
3233
    rtp_c = find_rtp_session_with_url(url, h->session_id);
 
3234
    if (!rtp_c) {
 
3235
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
 
3236
        return;
 
3237
    }
 
3238
 
 
3239
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
 
3240
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
 
3241
        rtp_c->state != HTTPSTATE_READY) {
 
3242
        rtsp_reply_error(c, RTSP_STATUS_STATE);
 
3243
        return;
 
3244
    }
 
3245
 
 
3246
    rtp_c->state = HTTPSTATE_SEND_DATA;
 
3247
 
 
3248
    /* now everything is OK, so we can send the connection parameters */
 
3249
    rtsp_reply_header(c, RTSP_STATUS_OK);
 
3250
    /* session ID */
 
3251
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
 
3252
    avio_printf(c->pb, "\r\n");
 
3253
}
 
3254
 
 
3255
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
 
3256
{
 
3257
    HTTPContext *rtp_c;
 
3258
 
 
3259
    rtp_c = find_rtp_session_with_url(url, h->session_id);
 
3260
    if (!rtp_c) {
 
3261
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
 
3262
        return;
 
3263
    }
 
3264
 
 
3265
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
 
3266
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
 
3267
        rtsp_reply_error(c, RTSP_STATUS_STATE);
 
3268
        return;
 
3269
    }
 
3270
 
 
3271
    rtp_c->state = HTTPSTATE_READY;
 
3272
    rtp_c->first_pts = AV_NOPTS_VALUE;
 
3273
    /* now everything is OK, so we can send the connection parameters */
 
3274
    rtsp_reply_header(c, RTSP_STATUS_OK);
 
3275
    /* session ID */
 
3276
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
 
3277
    avio_printf(c->pb, "\r\n");
 
3278
}
 
3279
 
 
3280
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
 
3281
{
 
3282
    HTTPContext *rtp_c;
 
3283
 
 
3284
    rtp_c = find_rtp_session_with_url(url, h->session_id);
 
3285
    if (!rtp_c) {
 
3286
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
 
3287
        return;
 
3288
    }
 
3289
 
 
3290
    /* now everything is OK, so we can send the connection parameters */
 
3291
    rtsp_reply_header(c, RTSP_STATUS_OK);
 
3292
    /* session ID */
 
3293
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
 
3294
    avio_printf(c->pb, "\r\n");
 
3295
 
 
3296
    /* abort the session */
 
3297
    close_connection(rtp_c);
 
3298
}
 
3299
 
 
3300
 
 
3301
/********************************************************************/
 
3302
/* RTP handling */
 
3303
 
 
3304
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
 
3305
                                       FFStream *stream, const char *session_id,
 
3306
                                       enum RTSPLowerTransport rtp_protocol)
 
3307
{
 
3308
    HTTPContext *c = NULL;
 
3309
    const char *proto_str;
 
3310
 
 
3311
    /* XXX: should output a warning page when coming
 
3312
       close to the connection limit */
 
3313
    if (nb_connections >= nb_max_connections)
 
3314
        goto fail;
 
3315
 
 
3316
    /* add a new connection */
 
3317
    c = av_mallocz(sizeof(HTTPContext));
 
3318
    if (!c)
 
3319
        goto fail;
 
3320
 
 
3321
    c->fd = -1;
 
3322
    c->poll_entry = NULL;
 
3323
    c->from_addr = *from_addr;
 
3324
    c->buffer_size = IOBUFFER_INIT_SIZE;
 
3325
    c->buffer = av_malloc(c->buffer_size);
 
3326
    if (!c->buffer)
 
3327
        goto fail;
 
3328
    nb_connections++;
 
3329
    c->stream = stream;
 
3330
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
 
3331
    c->state = HTTPSTATE_READY;
 
3332
    c->is_packetized = 1;
 
3333
    c->rtp_protocol = rtp_protocol;
 
3334
 
 
3335
    /* protocol is shown in statistics */
 
3336
    switch(c->rtp_protocol) {
 
3337
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
 
3338
        proto_str = "MCAST";
 
3339
        break;
 
3340
    case RTSP_LOWER_TRANSPORT_UDP:
 
3341
        proto_str = "UDP";
 
3342
        break;
 
3343
    case RTSP_LOWER_TRANSPORT_TCP:
 
3344
        proto_str = "TCP";
 
3345
        break;
 
3346
    default:
 
3347
        proto_str = "???";
 
3348
        break;
 
3349
    }
 
3350
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
 
3351
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
 
3352
 
 
3353
    current_bandwidth += stream->bandwidth;
 
3354
 
 
3355
    c->next = first_http_ctx;
 
3356
    first_http_ctx = c;
 
3357
    return c;
 
3358
 
 
3359
 fail:
 
3360
    if (c) {
 
3361
        av_free(c->buffer);
 
3362
        av_free(c);
 
3363
    }
 
3364
    return NULL;
 
3365
}
 
3366
 
 
3367
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
 
3368
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
 
3369
   used. */
 
3370
static int rtp_new_av_stream(HTTPContext *c,
 
3371
                             int stream_index, struct sockaddr_in *dest_addr,
 
3372
                             HTTPContext *rtsp_c)
 
3373
{
 
3374
    AVFormatContext *ctx;
 
3375
    AVStream *st;
 
3376
    char *ipaddr;
 
3377
    URLContext *h = NULL;
 
3378
    uint8_t *dummy_buf;
 
3379
    int max_packet_size;
 
3380
 
 
3381
    /* now we can open the relevant output stream */
 
3382
    ctx = avformat_alloc_context();
 
3383
    if (!ctx)
 
3384
        return -1;
 
3385
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
 
3386
 
 
3387
    st = av_mallocz(sizeof(AVStream));
 
3388
    if (!st)
 
3389
        goto fail;
 
3390
    ctx->nb_streams = 1;
 
3391
    ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
 
3392
    if (!ctx->streams)
 
3393
      goto fail;
 
3394
    ctx->streams[0] = st;
 
3395
 
 
3396
    if (!c->stream->feed ||
 
3397
        c->stream->feed == c->stream)
 
3398
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
 
3399
    else
 
3400
        memcpy(st,
 
3401
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
 
3402
               sizeof(AVStream));
 
3403
    st->priv_data = NULL;
 
3404
 
 
3405
    /* build destination RTP address */
 
3406
    ipaddr = inet_ntoa(dest_addr->sin_addr);
 
3407
 
 
3408
    switch(c->rtp_protocol) {
 
3409
    case RTSP_LOWER_TRANSPORT_UDP:
 
3410
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
 
3411
        /* RTP/UDP case */
 
3412
 
 
3413
        /* XXX: also pass as parameter to function ? */
 
3414
        if (c->stream->is_multicast) {
 
3415
            int ttl;
 
3416
            ttl = c->stream->multicast_ttl;
 
3417
            if (!ttl)
 
3418
                ttl = 16;
 
3419
            snprintf(ctx->filename, sizeof(ctx->filename),
 
3420
                     "rtp://%s:%d?multicast=1&ttl=%d",
 
3421
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
 
3422
        } else {
 
3423
            snprintf(ctx->filename, sizeof(ctx->filename),
 
3424
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
 
3425
        }
 
3426
 
 
3427
        if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
 
3428
            goto fail;
 
3429
        c->rtp_handles[stream_index] = h;
 
3430
        max_packet_size = url_get_max_packet_size(h);
 
3431
        break;
 
3432
    case RTSP_LOWER_TRANSPORT_TCP:
 
3433
        /* RTP/TCP case */
 
3434
        c->rtsp_c = rtsp_c;
 
3435
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
 
3436
        break;
 
3437
    default:
 
3438
        goto fail;
 
3439
    }
 
3440
 
 
3441
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
 
3442
             ipaddr, ntohs(dest_addr->sin_port),
 
3443
             c->stream->filename, stream_index, c->protocol);
 
3444
 
 
3445
    /* normally, no packets should be output here, but the packet size may be checked */
 
3446
    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
 
3447
        /* XXX: close stream */
 
3448
        goto fail;
 
3449
    }
 
3450
    if (avformat_write_header(ctx, NULL) < 0) {
 
3451
    fail:
 
3452
        if (h)
 
3453
            url_close(h);
 
3454
        av_free(ctx);
 
3455
        return -1;
 
3456
    }
 
3457
    avio_close_dyn_buf(ctx->pb, &dummy_buf);
 
3458
    av_free(dummy_buf);
 
3459
 
 
3460
    c->rtp_ctx[stream_index] = ctx;
 
3461
    return 0;
 
3462
}
 
3463
 
 
3464
/********************************************************************/
 
3465
/* avserver initialization */
 
3466
 
 
3467
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
 
3468
{
 
3469
    AVStream *fst;
 
3470
 
 
3471
    fst = av_mallocz(sizeof(AVStream));
 
3472
    if (!fst)
 
3473
        return NULL;
 
3474
    if (copy) {
 
3475
        fst->codec = avcodec_alloc_context3(NULL);
 
3476
        memcpy(fst->codec, codec, sizeof(AVCodecContext));
 
3477
        if (codec->extradata_size) {
 
3478
            fst->codec->extradata = av_malloc(codec->extradata_size);
 
3479
            memcpy(fst->codec->extradata, codec->extradata,
 
3480
                codec->extradata_size);
 
3481
        }
 
3482
    } else {
 
3483
        /* live streams must use the actual feed's codec since it may be
 
3484
         * updated later to carry extradata needed by the streams.
 
3485
         */
 
3486
        fst->codec = codec;
 
3487
    }
 
3488
    fst->priv_data = av_mallocz(sizeof(FeedData));
 
3489
    fst->index = stream->nb_streams;
 
3490
    av_set_pts_info(fst, 33, 1, 90000);
 
3491
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
 
3492
    stream->streams[stream->nb_streams++] = fst;
 
3493
    return fst;
 
3494
}
 
3495
 
 
3496
/* return the stream number in the feed */
 
3497
static int add_av_stream(FFStream *feed, AVStream *st)
 
3498
{
 
3499
    AVStream *fst;
 
3500
    AVCodecContext *av, *av1;
 
3501
    int i;
 
3502
 
 
3503
    av = st->codec;
 
3504
    for(i=0;i<feed->nb_streams;i++) {
 
3505
        st = feed->streams[i];
 
3506
        av1 = st->codec;
 
3507
        if (av1->codec_id == av->codec_id &&
 
3508
            av1->codec_type == av->codec_type &&
 
3509
            av1->bit_rate == av->bit_rate) {
 
3510
 
 
3511
            switch(av->codec_type) {
 
3512
            case AVMEDIA_TYPE_AUDIO:
 
3513
                if (av1->channels == av->channels &&
 
3514
                    av1->sample_rate == av->sample_rate)
 
3515
                    return i;
 
3516
                break;
 
3517
            case AVMEDIA_TYPE_VIDEO:
 
3518
                if (av1->width == av->width &&
 
3519
                    av1->height == av->height &&
 
3520
                    av1->time_base.den == av->time_base.den &&
 
3521
                    av1->time_base.num == av->time_base.num &&
 
3522
                    av1->gop_size == av->gop_size)
 
3523
                    return i;
 
3524
                break;
 
3525
            default:
 
3526
                abort();
 
3527
            }
 
3528
        }
 
3529
    }
 
3530
 
 
3531
    fst = add_av_stream1(feed, av, 0);
 
3532
    if (!fst)
 
3533
        return -1;
 
3534
    return feed->nb_streams - 1;
 
3535
}
 
3536
 
 
3537
static void remove_stream(FFStream *stream)
 
3538
{
 
3539
    FFStream **ps;
 
3540
    ps = &first_stream;
 
3541
    while (*ps != NULL) {
 
3542
        if (*ps == stream)
 
3543
            *ps = (*ps)->next;
 
3544
        else
 
3545
            ps = &(*ps)->next;
 
3546
    }
 
3547
}
 
3548
 
 
3549
/* specific mpeg4 handling : we extract the raw parameters */
 
3550
static void extract_mpeg4_header(AVFormatContext *infile)
 
3551
{
 
3552
    int mpeg4_count, i, size;
 
3553
    AVPacket pkt;
 
3554
    AVStream *st;
 
3555
    const uint8_t *p;
 
3556
 
 
3557
    mpeg4_count = 0;
 
3558
    for(i=0;i<infile->nb_streams;i++) {
 
3559
        st = infile->streams[i];
 
3560
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
 
3561
            st->codec->extradata_size == 0) {
 
3562
            mpeg4_count++;
 
3563
        }
 
3564
    }
 
3565
    if (!mpeg4_count)
 
3566
        return;
 
3567
 
 
3568
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
 
3569
    while (mpeg4_count > 0) {
 
3570
        if (av_read_packet(infile, &pkt) < 0)
 
3571
            break;
 
3572
        st = infile->streams[pkt.stream_index];
 
3573
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
 
3574
            st->codec->extradata_size == 0) {
 
3575
            av_freep(&st->codec->extradata);
 
3576
            /* fill extradata with the header */
 
3577
            /* XXX: we make hard suppositions here ! */
 
3578
            p = pkt.data;
 
3579
            while (p < pkt.data + pkt.size - 4) {
 
3580
                /* stop when vop header is found */
 
3581
                if (p[0] == 0x00 && p[1] == 0x00 &&
 
3582
                    p[2] == 0x01 && p[3] == 0xb6) {
 
3583
                    size = p - pkt.data;
 
3584
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
 
3585
                    st->codec->extradata = av_malloc(size);
 
3586
                    st->codec->extradata_size = size;
 
3587
                    memcpy(st->codec->extradata, pkt.data, size);
 
3588
                    break;
 
3589
                }
 
3590
                p++;
 
3591
            }
 
3592
            mpeg4_count--;
 
3593
        }
 
3594
        av_free_packet(&pkt);
 
3595
    }
 
3596
}
 
3597
 
 
3598
/* compute the needed AVStream for each file */
 
3599
static void build_file_streams(void)
 
3600
{
 
3601
    FFStream *stream, *stream_next;
 
3602
    int i, ret;
 
3603
 
 
3604
    /* gather all streams */
 
3605
    for(stream = first_stream; stream != NULL; stream = stream_next) {
 
3606
        AVFormatContext *infile = NULL;
 
3607
        stream_next = stream->next;
 
3608
        if (stream->stream_type == STREAM_TYPE_LIVE &&
 
3609
            !stream->feed) {
 
3610
            /* the stream comes from a file */
 
3611
            /* try to open the file */
 
3612
            /* open stream */
 
3613
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
 
3614
                /* specific case : if transport stream output to RTP,
 
3615
                   we use a raw transport stream reader */
 
3616
                av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
 
3617
            }
 
3618
 
 
3619
            http_log("Opening file '%s'\n", stream->feed_filename);
 
3620
            if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
 
3621
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
 
3622
                /* remove stream (no need to spend more time on it) */
 
3623
            fail:
 
3624
                remove_stream(stream);
 
3625
            } else {
 
3626
                /* find all the AVStreams inside and reference them in
 
3627
                   'stream' */
 
3628
                if (avformat_find_stream_info(infile, NULL) < 0) {
 
3629
                    http_log("Could not find codec parameters from '%s'\n",
 
3630
                             stream->feed_filename);
 
3631
                    avformat_close_input(&infile);
 
3632
                    goto fail;
 
3633
                }
 
3634
                extract_mpeg4_header(infile);
 
3635
 
 
3636
                for(i=0;i<infile->nb_streams;i++)
 
3637
                    add_av_stream1(stream, infile->streams[i]->codec, 1);
 
3638
 
 
3639
                avformat_close_input(&infile);
 
3640
            }
 
3641
        }
 
3642
    }
 
3643
}
 
3644
 
 
3645
/* compute the needed AVStream for each feed */
 
3646
static void build_feed_streams(void)
 
3647
{
 
3648
    FFStream *stream, *feed;
 
3649
    int i;
 
3650
 
 
3651
    /* gather all streams */
 
3652
    for(stream = first_stream; stream != NULL; stream = stream->next) {
 
3653
        feed = stream->feed;
 
3654
        if (feed) {
 
3655
            if (stream->is_feed) {
 
3656
                for(i=0;i<stream->nb_streams;i++)
 
3657
                    stream->feed_streams[i] = i;
 
3658
            } else {
 
3659
                /* we handle a stream coming from a feed */
 
3660
                for(i=0;i<stream->nb_streams;i++)
 
3661
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
 
3662
            }
 
3663
        }
 
3664
    }
 
3665
 
 
3666
    /* create feed files if needed */
 
3667
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
 
3668
        int fd;
 
3669
 
 
3670
        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
 
3671
            /* See if it matches */
 
3672
            AVFormatContext *s = NULL;
 
3673
            int matches = 0;
 
3674
 
 
3675
            if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
 
3676
                /* Now see if it matches */
 
3677
                if (s->nb_streams == feed->nb_streams) {
 
3678
                    matches = 1;
 
3679
                    for(i=0;i<s->nb_streams;i++) {
 
3680
                        AVStream *sf, *ss;
 
3681
                        sf = feed->streams[i];
 
3682
                        ss = s->streams[i];
 
3683
 
 
3684
                        if (sf->index != ss->index ||
 
3685
                            sf->id != ss->id) {
 
3686
                            http_log("Index & Id do not match for stream %d (%s)\n",
 
3687
                                   i, feed->feed_filename);
 
3688
                            matches = 0;
 
3689
                        } else {
 
3690
                            AVCodecContext *ccf, *ccs;
 
3691
 
 
3692
                            ccf = sf->codec;
 
3693
                            ccs = ss->codec;
 
3694
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
 
3695
 
 
3696
                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
 
3697
                                http_log("Codecs do not match for stream %d\n", i);
 
3698
                                matches = 0;
 
3699
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
 
3700
                                http_log("Codec bitrates do not match for stream %d\n", i);
 
3701
                                matches = 0;
 
3702
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
 
3703
                                if (CHECK_CODEC(time_base.den) ||
 
3704
                                    CHECK_CODEC(time_base.num) ||
 
3705
                                    CHECK_CODEC(width) ||
 
3706
                                    CHECK_CODEC(height)) {
 
3707
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
 
3708
                                    matches = 0;
 
3709
                                }
 
3710
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
 
3711
                                if (CHECK_CODEC(sample_rate) ||
 
3712
                                    CHECK_CODEC(channels) ||
 
3713
                                    CHECK_CODEC(frame_size)) {
 
3714
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
 
3715
                                    matches = 0;
 
3716
                                }
 
3717
                            } else {
 
3718
                                http_log("Unknown codec type\n");
 
3719
                                matches = 0;
 
3720
                            }
 
3721
                        }
 
3722
                        if (!matches)
 
3723
                            break;
 
3724
                    }
 
3725
                } else
 
3726
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
 
3727
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
 
3728
 
 
3729
                avformat_close_input(&s);
 
3730
            } else
 
3731
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
 
3732
                        feed->feed_filename);
 
3733
 
 
3734
            if (!matches) {
 
3735
                if (feed->readonly) {
 
3736
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
 
3737
                        feed->feed_filename);
 
3738
                    exit(1);
 
3739
                }
 
3740
                unlink(feed->feed_filename);
 
3741
            }
 
3742
        }
 
3743
        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
 
3744
            AVFormatContext s1 = {0}, *s = &s1;
 
3745
 
 
3746
            if (feed->readonly) {
 
3747
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
 
3748
                    feed->feed_filename);
 
3749
                exit(1);
 
3750
            }
 
3751
 
 
3752
            /* only write the header of the ffm file */
 
3753
            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
 
3754
                http_log("Could not open output feed file '%s'\n",
 
3755
                         feed->feed_filename);
 
3756
                exit(1);
 
3757
            }
 
3758
            s->oformat = feed->fmt;
 
3759
            s->nb_streams = feed->nb_streams;
 
3760
            s->streams = feed->streams;
 
3761
            if (avformat_write_header(s, NULL) < 0) {
 
3762
                http_log("Container doesn't supports the required parameters\n");
 
3763
                exit(1);
 
3764
            }
 
3765
            /* XXX: need better api */
 
3766
            av_freep(&s->priv_data);
 
3767
            avio_close(s->pb);
 
3768
        }
 
3769
        /* get feed size and write index */
 
3770
        fd = open(feed->feed_filename, O_RDONLY);
 
3771
        if (fd < 0) {
 
3772
            http_log("Could not open output feed file '%s'\n",
 
3773
                    feed->feed_filename);
 
3774
            exit(1);
 
3775
        }
 
3776
 
 
3777
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
 
3778
        feed->feed_size = lseek(fd, 0, SEEK_END);
 
3779
        /* ensure that we do not wrap before the end of file */
 
3780
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
 
3781
            feed->feed_max_size = feed->feed_size;
 
3782
 
 
3783
        close(fd);
 
3784
    }
 
3785
}
 
3786
 
 
3787
/* compute the bandwidth used by each stream */
 
3788
static void compute_bandwidth(void)
 
3789
{
 
3790
    unsigned bandwidth;
 
3791
    int i;
 
3792
    FFStream *stream;
 
3793
 
 
3794
    for(stream = first_stream; stream != NULL; stream = stream->next) {
 
3795
        bandwidth = 0;
 
3796
        for(i=0;i<stream->nb_streams;i++) {
 
3797
            AVStream *st = stream->streams[i];
 
3798
            switch(st->codec->codec_type) {
 
3799
            case AVMEDIA_TYPE_AUDIO:
 
3800
            case AVMEDIA_TYPE_VIDEO:
 
3801
                bandwidth += st->codec->bit_rate;
 
3802
                break;
 
3803
            default:
 
3804
                break;
 
3805
            }
 
3806
        }
 
3807
        stream->bandwidth = (bandwidth + 999) / 1000;
 
3808
    }
 
3809
}
 
3810
 
 
3811
/* add a codec and set the default parameters */
 
3812
static void add_codec(FFStream *stream, AVCodecContext *av)
 
3813
{
 
3814
    AVStream *st;
 
3815
 
 
3816
    /* compute default parameters */
 
3817
    switch(av->codec_type) {
 
3818
    case AVMEDIA_TYPE_AUDIO:
 
3819
        if (av->bit_rate == 0)
 
3820
            av->bit_rate = 64000;
 
3821
        if (av->sample_rate == 0)
 
3822
            av->sample_rate = 22050;
 
3823
        if (av->channels == 0)
 
3824
            av->channels = 1;
 
3825
        break;
 
3826
    case AVMEDIA_TYPE_VIDEO:
 
3827
        if (av->bit_rate == 0)
 
3828
            av->bit_rate = 64000;
 
3829
        if (av->time_base.num == 0){
 
3830
            av->time_base.den = 5;
 
3831
            av->time_base.num = 1;
 
3832
        }
 
3833
        if (av->width == 0 || av->height == 0) {
 
3834
            av->width = 160;
 
3835
            av->height = 128;
 
3836
        }
 
3837
        /* Bitrate tolerance is less for streaming */
 
3838
        if (av->bit_rate_tolerance == 0)
 
3839
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
 
3840
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
 
3841
        if (av->qmin == 0)
 
3842
            av->qmin = 3;
 
3843
        if (av->qmax == 0)
 
3844
            av->qmax = 31;
 
3845
        if (av->max_qdiff == 0)
 
3846
            av->max_qdiff = 3;
 
3847
        av->qcompress = 0.5;
 
3848
        av->qblur = 0.5;
 
3849
 
 
3850
        if (!av->nsse_weight)
 
3851
            av->nsse_weight = 8;
 
3852
 
 
3853
        av->frame_skip_cmp = FF_CMP_DCTMAX;
 
3854
        if (!av->me_method)
 
3855
            av->me_method = ME_EPZS;
 
3856
        av->rc_buffer_aggressivity = 1.0;
 
3857
 
 
3858
        if (!av->rc_eq)
 
3859
            av->rc_eq = "tex^qComp";
 
3860
        if (!av->i_quant_factor)
 
3861
            av->i_quant_factor = -0.8;
 
3862
        if (!av->b_quant_factor)
 
3863
            av->b_quant_factor = 1.25;
 
3864
        if (!av->b_quant_offset)
 
3865
            av->b_quant_offset = 1.25;
 
3866
        if (!av->rc_max_rate)
 
3867
            av->rc_max_rate = av->bit_rate * 2;
 
3868
 
 
3869
        if (av->rc_max_rate && !av->rc_buffer_size) {
 
3870
            av->rc_buffer_size = av->rc_max_rate;
 
3871
        }
 
3872
 
 
3873
 
 
3874
        break;
 
3875
    default:
 
3876
        abort();
 
3877
    }
 
3878
 
 
3879
    st = av_mallocz(sizeof(AVStream));
 
3880
    if (!st)
 
3881
        return;
 
3882
    st->codec = avcodec_alloc_context3(NULL);
 
3883
    stream->streams[stream->nb_streams++] = st;
 
3884
    memcpy(st->codec, av, sizeof(AVCodecContext));
 
3885
}
 
3886
 
 
3887
static enum CodecID opt_audio_codec(const char *arg)
 
3888
{
 
3889
    AVCodec *p= avcodec_find_encoder_by_name(arg);
 
3890
 
 
3891
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
 
3892
        return CODEC_ID_NONE;
 
3893
 
 
3894
    return p->id;
 
3895
}
 
3896
 
 
3897
static enum CodecID opt_video_codec(const char *arg)
 
3898
{
 
3899
    AVCodec *p= avcodec_find_encoder_by_name(arg);
 
3900
 
 
3901
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
 
3902
        return CODEC_ID_NONE;
 
3903
 
 
3904
    return p->id;
 
3905
}
 
3906
 
 
3907
/* simplistic plugin support */
 
3908
 
 
3909
#if HAVE_DLOPEN
 
3910
static void load_module(const char *filename)
 
3911
{
 
3912
    void *dll;
 
3913
    void (*init_func)(void);
 
3914
    dll = dlopen(filename, RTLD_NOW);
 
3915
    if (!dll) {
 
3916
        fprintf(stderr, "Could not load module '%s' - %s\n",
 
3917
                filename, dlerror());
 
3918
        return;
 
3919
    }
 
3920
 
 
3921
    init_func = dlsym(dll, "avserver_module_init");
 
3922
    if (!init_func) {
 
3923
        fprintf(stderr,
 
3924
                "%s: init function 'avserver_module_init()' not found\n",
 
3925
                filename);
 
3926
        dlclose(dll);
 
3927
    }
 
3928
 
 
3929
    init_func();
 
3930
}
 
3931
#endif
 
3932
 
 
3933
static int avserver_opt_default(const char *opt, const char *arg,
 
3934
                       AVCodecContext *avctx, int type)
 
3935
{
 
3936
    int ret = 0;
 
3937
    const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
 
3938
    if(o)
 
3939
        ret = av_opt_set(avctx, opt, arg, 0);
 
3940
    return ret;
 
3941
}
 
3942
 
 
3943
static int avserver_opt_preset(const char *arg,
 
3944
                       AVCodecContext *avctx, int type,
 
3945
                       enum CodecID *audio_id, enum CodecID *video_id)
 
3946
{
 
3947
    FILE *f=NULL;
 
3948
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
 
3949
    int ret = 0;
 
3950
    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
 
3951
 
 
3952
    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
 
3953
                              codec ? codec->name : NULL))) {
 
3954
        fprintf(stderr, "File for preset '%s' not found\n", arg);
 
3955
        return 1;
 
3956
    }
 
3957
 
 
3958
    while(!feof(f)){
 
3959
        int e= fscanf(f, "%999[^\n]\n", line) - 1;
 
3960
        if(line[0] == '#' && !e)
 
3961
            continue;
 
3962
        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
 
3963
        if(e){
 
3964
            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
 
3965
            ret = 1;
 
3966
            break;
 
3967
        }
 
3968
        if(!strcmp(tmp, "acodec")){
 
3969
            *audio_id = opt_audio_codec(tmp2);
 
3970
        }else if(!strcmp(tmp, "vcodec")){
 
3971
            *video_id = opt_video_codec(tmp2);
 
3972
        }else if(!strcmp(tmp, "scodec")){
 
3973
            /* opt_subtitle_codec(tmp2); */
 
3974
        }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){
 
3975
            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
 
3976
            ret = 1;
 
3977
            break;
 
3978
        }
 
3979
    }
 
3980
 
 
3981
    fclose(f);
 
3982
 
 
3983
    return ret;
 
3984
}
 
3985
 
 
3986
static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename,
 
3987
                                             const char *mime_type)
 
3988
{
 
3989
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
 
3990
 
 
3991
    if (fmt) {
 
3992
        AVOutputFormat *stream_fmt;
 
3993
        char stream_format_name[64];
 
3994
 
 
3995
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
 
3996
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
 
3997
 
 
3998
        if (stream_fmt)
 
3999
            fmt = stream_fmt;
 
4000
    }
 
4001
 
 
4002
    return fmt;
 
4003
}
 
4004
 
 
4005
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
 
4006
{
 
4007
    va_list vl;
 
4008
    va_start(vl, fmt);
 
4009
    fprintf(stderr, "%s:%d: ", filename, line_num);
 
4010
    vfprintf(stderr, fmt, vl);
 
4011
    va_end(vl);
 
4012
 
 
4013
    (*errors)++;
 
4014
}
 
4015
 
 
4016
static int parse_ffconfig(const char *filename)
 
4017
{
 
4018
    FILE *f;
 
4019
    char line[1024];
 
4020
    char cmd[64];
 
4021
    char arg[1024];
 
4022
    const char *p;
 
4023
    int val, errors, line_num;
 
4024
    FFStream **last_stream, *stream, *redirect;
 
4025
    FFStream **last_feed, *feed, *s;
 
4026
    AVCodecContext audio_enc, video_enc;
 
4027
    enum CodecID audio_id, video_id;
 
4028
 
 
4029
    f = fopen(filename, "r");
 
4030
    if (!f) {
 
4031
        perror(filename);
 
4032
        return -1;
 
4033
    }
 
4034
 
 
4035
    errors = 0;
 
4036
    line_num = 0;
 
4037
    first_stream = NULL;
 
4038
    last_stream = &first_stream;
 
4039
    first_feed = NULL;
 
4040
    last_feed = &first_feed;
 
4041
    stream = NULL;
 
4042
    feed = NULL;
 
4043
    redirect = NULL;
 
4044
    audio_id = CODEC_ID_NONE;
 
4045
    video_id = CODEC_ID_NONE;
 
4046
 
 
4047
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
 
4048
    for(;;) {
 
4049
        if (fgets(line, sizeof(line), f) == NULL)
 
4050
            break;
 
4051
        line_num++;
 
4052
        p = line;
 
4053
        while (isspace(*p))
 
4054
            p++;
 
4055
        if (*p == '\0' || *p == '#')
 
4056
            continue;
 
4057
 
 
4058
        get_arg(cmd, sizeof(cmd), &p);
 
4059
 
 
4060
        if (!av_strcasecmp(cmd, "Port")) {
 
4061
            get_arg(arg, sizeof(arg), &p);
 
4062
            val = atoi(arg);
 
4063
            if (val < 1 || val > 65536) {
 
4064
                ERROR("Invalid_port: %s\n", arg);
 
4065
            }
 
4066
            my_http_addr.sin_port = htons(val);
 
4067
        } else if (!av_strcasecmp(cmd, "BindAddress")) {
 
4068
            get_arg(arg, sizeof(arg), &p);
 
4069
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
 
4070
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
 
4071
            }
 
4072
        } else if (!av_strcasecmp(cmd, "NoDaemon")) {
 
4073
            avserver_daemon = 0;
 
4074
        } else if (!av_strcasecmp(cmd, "RTSPPort")) {
 
4075
            get_arg(arg, sizeof(arg), &p);
 
4076
            val = atoi(arg);
 
4077
            if (val < 1 || val > 65536) {
 
4078
                ERROR("%s:%d: Invalid port: %s\n", arg);
 
4079
            }
 
4080
            my_rtsp_addr.sin_port = htons(atoi(arg));
 
4081
        } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
 
4082
            get_arg(arg, sizeof(arg), &p);
 
4083
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
 
4084
                ERROR("Invalid host/IP address: %s\n", arg);
 
4085
            }
 
4086
        } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
 
4087
            get_arg(arg, sizeof(arg), &p);
 
4088
            val = atoi(arg);
 
4089
            if (val < 1 || val > 65536) {
 
4090
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
 
4091
            }
 
4092
            nb_max_http_connections = val;
 
4093
        } else if (!av_strcasecmp(cmd, "MaxClients")) {
 
4094
            get_arg(arg, sizeof(arg), &p);
 
4095
            val = atoi(arg);
 
4096
            if (val < 1 || val > nb_max_http_connections) {
 
4097
                ERROR("Invalid MaxClients: %s\n", arg);
 
4098
            } else {
 
4099
                nb_max_connections = val;
 
4100
            }
 
4101
        } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
 
4102
            int64_t llval;
 
4103
            get_arg(arg, sizeof(arg), &p);
 
4104
            llval = atoll(arg);
 
4105
            if (llval < 10 || llval > 10000000) {
 
4106
                ERROR("Invalid MaxBandwidth: %s\n", arg);
 
4107
            } else
 
4108
                max_bandwidth = llval;
 
4109
        } else if (!av_strcasecmp(cmd, "CustomLog")) {
 
4110
            if (!avserver_debug)
 
4111
                get_arg(logfilename, sizeof(logfilename), &p);
 
4112
        } else if (!av_strcasecmp(cmd, "<Feed")) {
 
4113
            /*********************************************/
 
4114
            /* Feed related options */
 
4115
            char *q;
 
4116
            if (stream || feed) {
 
4117
                ERROR("Already in a tag\n");
 
4118
            } else {
 
4119
                feed = av_mallocz(sizeof(FFStream));
 
4120
                get_arg(feed->filename, sizeof(feed->filename), &p);
 
4121
                q = strrchr(feed->filename, '>');
 
4122
                if (*q)
 
4123
                    *q = '\0';
 
4124
 
 
4125
                for (s = first_feed; s; s = s->next) {
 
4126
                    if (!strcmp(feed->filename, s->filename)) {
 
4127
                        ERROR("Feed '%s' already registered\n", s->filename);
 
4128
                    }
 
4129
                }
 
4130
 
 
4131
                feed->fmt = av_guess_format("ffm", NULL, NULL);
 
4132
                /* defaut feed file */
 
4133
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
 
4134
                         "/tmp/%s.ffm", feed->filename);
 
4135
                feed->feed_max_size = 5 * 1024 * 1024;
 
4136
                feed->is_feed = 1;
 
4137
                feed->feed = feed; /* self feeding :-) */
 
4138
 
 
4139
                /* add in stream list */
 
4140
                *last_stream = feed;
 
4141
                last_stream = &feed->next;
 
4142
                /* add in feed list */
 
4143
                *last_feed = feed;
 
4144
                last_feed = &feed->next_feed;
 
4145
            }
 
4146
        } else if (!av_strcasecmp(cmd, "Launch")) {
 
4147
            if (feed) {
 
4148
                int i;
 
4149
 
 
4150
                feed->child_argv = av_mallocz(64 * sizeof(char *));
 
4151
 
 
4152
                for (i = 0; i < 62; i++) {
 
4153
                    get_arg(arg, sizeof(arg), &p);
 
4154
                    if (!arg[0])
 
4155
                        break;
 
4156
 
 
4157
                    feed->child_argv[i] = av_strdup(arg);
 
4158
                }
 
4159
 
 
4160
                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
 
4161
 
 
4162
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
 
4163
                    "http://%s:%d/%s",
 
4164
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
 
4165
                    inet_ntoa(my_http_addr.sin_addr),
 
4166
                    ntohs(my_http_addr.sin_port), feed->filename);
 
4167
            }
 
4168
        } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
 
4169
            if (feed) {
 
4170
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
 
4171
                feed->readonly = 1;
 
4172
            } else if (stream) {
 
4173
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
 
4174
            }
 
4175
        } else if (!av_strcasecmp(cmd, "File")) {
 
4176
            if (feed) {
 
4177
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
 
4178
            } else if (stream)
 
4179
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
 
4180
        } else if (!av_strcasecmp(cmd, "Truncate")) {
 
4181
            if (feed) {
 
4182
                get_arg(arg, sizeof(arg), &p);
 
4183
                feed->truncate = strtod(arg, NULL);
 
4184
            }
 
4185
        } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
 
4186
            if (feed) {
 
4187
                char *p1;
 
4188
                double fsize;
 
4189
 
 
4190
                get_arg(arg, sizeof(arg), &p);
 
4191
                p1 = arg;
 
4192
                fsize = strtod(p1, &p1);
 
4193
                switch(toupper(*p1)) {
 
4194
                case 'K':
 
4195
                    fsize *= 1024;
 
4196
                    break;
 
4197
                case 'M':
 
4198
                    fsize *= 1024 * 1024;
 
4199
                    break;
 
4200
                case 'G':
 
4201
                    fsize *= 1024 * 1024 * 1024;
 
4202
                    break;
 
4203
                }
 
4204
                feed->feed_max_size = (int64_t)fsize;
 
4205
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
 
4206
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
 
4207
                }
 
4208
            }
 
4209
        } else if (!av_strcasecmp(cmd, "</Feed>")) {
 
4210
            if (!feed) {
 
4211
                ERROR("No corresponding <Feed> for </Feed>\n");
 
4212
            }
 
4213
            feed = NULL;
 
4214
        } else if (!av_strcasecmp(cmd, "<Stream")) {
 
4215
            /*********************************************/
 
4216
            /* Stream related options */
 
4217
            char *q;
 
4218
            if (stream || feed) {
 
4219
                ERROR("Already in a tag\n");
 
4220
            } else {
 
4221
                FFStream *s;
 
4222
                stream = av_mallocz(sizeof(FFStream));
 
4223
                get_arg(stream->filename, sizeof(stream->filename), &p);
 
4224
                q = strrchr(stream->filename, '>');
 
4225
                if (*q)
 
4226
                    *q = '\0';
 
4227
 
 
4228
                for (s = first_stream; s; s = s->next) {
 
4229
                    if (!strcmp(stream->filename, s->filename)) {
 
4230
                        ERROR("Stream '%s' already registered\n", s->filename);
 
4231
                    }
 
4232
                }
 
4233
 
 
4234
                stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
 
4235
                avcodec_get_context_defaults3(&video_enc, NULL);
 
4236
                avcodec_get_context_defaults3(&audio_enc, NULL);
 
4237
                audio_id = CODEC_ID_NONE;
 
4238
                video_id = CODEC_ID_NONE;
 
4239
                if (stream->fmt) {
 
4240
                    audio_id = stream->fmt->audio_codec;
 
4241
                    video_id = stream->fmt->video_codec;
 
4242
                }
 
4243
 
 
4244
                *last_stream = stream;
 
4245
                last_stream = &stream->next;
 
4246
            }
 
4247
        } else if (!av_strcasecmp(cmd, "Feed")) {
 
4248
            get_arg(arg, sizeof(arg), &p);
 
4249
            if (stream) {
 
4250
                FFStream *sfeed;
 
4251
 
 
4252
                sfeed = first_feed;
 
4253
                while (sfeed != NULL) {
 
4254
                    if (!strcmp(sfeed->filename, arg))
 
4255
                        break;
 
4256
                    sfeed = sfeed->next_feed;
 
4257
                }
 
4258
                if (!sfeed)
 
4259
                    ERROR("feed '%s' not defined\n", arg);
 
4260
                else
 
4261
                    stream->feed = sfeed;
 
4262
            }
 
4263
        } else if (!av_strcasecmp(cmd, "Format")) {
 
4264
            get_arg(arg, sizeof(arg), &p);
 
4265
            if (stream) {
 
4266
                if (!strcmp(arg, "status")) {
 
4267
                    stream->stream_type = STREAM_TYPE_STATUS;
 
4268
                    stream->fmt = NULL;
 
4269
                } else {
 
4270
                    stream->stream_type = STREAM_TYPE_LIVE;
 
4271
                    /* jpeg cannot be used here, so use single frame jpeg */
 
4272
                    if (!strcmp(arg, "jpeg"))
 
4273
                        strcpy(arg, "mjpeg");
 
4274
                    stream->fmt = avserver_guess_format(arg, NULL, NULL);
 
4275
                    if (!stream->fmt) {
 
4276
                        ERROR("Unknown Format: %s\n", arg);
 
4277
                    }
 
4278
                }
 
4279
                if (stream->fmt) {
 
4280
                    audio_id = stream->fmt->audio_codec;
 
4281
                    video_id = stream->fmt->video_codec;
 
4282
                }
 
4283
            }
 
4284
        } else if (!av_strcasecmp(cmd, "InputFormat")) {
 
4285
            get_arg(arg, sizeof(arg), &p);
 
4286
            if (stream) {
 
4287
                stream->ifmt = av_find_input_format(arg);
 
4288
                if (!stream->ifmt) {
 
4289
                    ERROR("Unknown input format: %s\n", arg);
 
4290
                }
 
4291
            }
 
4292
        } else if (!av_strcasecmp(cmd, "FaviconURL")) {
 
4293
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
 
4294
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
 
4295
            } else {
 
4296
                ERROR("FaviconURL only permitted for status streams\n");
 
4297
            }
 
4298
        } else if (!av_strcasecmp(cmd, "Author")) {
 
4299
            if (stream)
 
4300
                get_arg(stream->author, sizeof(stream->author), &p);
 
4301
        } else if (!av_strcasecmp(cmd, "Comment")) {
 
4302
            if (stream)
 
4303
                get_arg(stream->comment, sizeof(stream->comment), &p);
 
4304
        } else if (!av_strcasecmp(cmd, "Copyright")) {
 
4305
            if (stream)
 
4306
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
 
4307
        } else if (!av_strcasecmp(cmd, "Title")) {
 
4308
            if (stream)
 
4309
                get_arg(stream->title, sizeof(stream->title), &p);
 
4310
        } else if (!av_strcasecmp(cmd, "Preroll")) {
 
4311
            get_arg(arg, sizeof(arg), &p);
 
4312
            if (stream)
 
4313
                stream->prebuffer = atof(arg) * 1000;
 
4314
        } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
 
4315
            if (stream)
 
4316
                stream->send_on_key = 1;
 
4317
        } else if (!av_strcasecmp(cmd, "AudioCodec")) {
 
4318
            get_arg(arg, sizeof(arg), &p);
 
4319
            audio_id = opt_audio_codec(arg);
 
4320
            if (audio_id == CODEC_ID_NONE) {
 
4321
                ERROR("Unknown AudioCodec: %s\n", arg);
 
4322
            }
 
4323
        } else if (!av_strcasecmp(cmd, "VideoCodec")) {
 
4324
            get_arg(arg, sizeof(arg), &p);
 
4325
            video_id = opt_video_codec(arg);
 
4326
            if (video_id == CODEC_ID_NONE) {
 
4327
                ERROR("Unknown VideoCodec: %s\n", arg);
 
4328
            }
 
4329
        } else if (!av_strcasecmp(cmd, "MaxTime")) {
 
4330
            get_arg(arg, sizeof(arg), &p);
 
4331
            if (stream)
 
4332
                stream->max_time = atof(arg) * 1000;
 
4333
        } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
 
4334
            get_arg(arg, sizeof(arg), &p);
 
4335
            if (stream)
 
4336
                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
 
4337
        } else if (!av_strcasecmp(cmd, "AudioChannels")) {
 
4338
            get_arg(arg, sizeof(arg), &p);
 
4339
            if (stream)
 
4340
                audio_enc.channels = atoi(arg);
 
4341
        } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
 
4342
            get_arg(arg, sizeof(arg), &p);
 
4343
            if (stream)
 
4344
                audio_enc.sample_rate = atoi(arg);
 
4345
        } else if (!av_strcasecmp(cmd, "AudioQuality")) {
 
4346
            get_arg(arg, sizeof(arg), &p);
 
4347
            if (stream) {
 
4348
//                audio_enc.quality = atof(arg) * 1000;
 
4349
            }
 
4350
        } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
 
4351
            if (stream) {
 
4352
                int minrate, maxrate;
 
4353
 
 
4354
                get_arg(arg, sizeof(arg), &p);
 
4355
 
 
4356
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
 
4357
                    video_enc.rc_min_rate = minrate * 1000;
 
4358
                    video_enc.rc_max_rate = maxrate * 1000;
 
4359
                } else {
 
4360
                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
 
4361
                }
 
4362
            }
 
4363
        } else if (!av_strcasecmp(cmd, "Debug")) {
 
4364
            if (stream) {
 
4365
                get_arg(arg, sizeof(arg), &p);
 
4366
                video_enc.debug = strtol(arg,0,0);
 
4367
            }
 
4368
        } else if (!av_strcasecmp(cmd, "Strict")) {
 
4369
            if (stream) {
 
4370
                get_arg(arg, sizeof(arg), &p);
 
4371
                video_enc.strict_std_compliance = atoi(arg);
 
4372
            }
 
4373
        } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
 
4374
            if (stream) {
 
4375
                get_arg(arg, sizeof(arg), &p);
 
4376
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
 
4377
            }
 
4378
        } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
 
4379
            if (stream) {
 
4380
                get_arg(arg, sizeof(arg), &p);
 
4381
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
 
4382
            }
 
4383
        } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
 
4384
            get_arg(arg, sizeof(arg), &p);
 
4385
            if (stream) {
 
4386
                video_enc.bit_rate = atoi(arg) * 1000;
 
4387
            }
 
4388
        } else if (!av_strcasecmp(cmd, "VideoSize")) {
 
4389
            get_arg(arg, sizeof(arg), &p);
 
4390
            if (stream) {
 
4391
                av_parse_video_size(&video_enc.width, &video_enc.height, arg);
 
4392
                if ((video_enc.width % 16) != 0 ||
 
4393
                    (video_enc.height % 16) != 0) {
 
4394
                    ERROR("Image size must be a multiple of 16\n");
 
4395
                }
 
4396
            }
 
4397
        } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
 
4398
            get_arg(arg, sizeof(arg), &p);
 
4399
            if (stream) {
 
4400
                AVRational frame_rate;
 
4401
                if (av_parse_video_rate(&frame_rate, arg) < 0) {
 
4402
                    ERROR("Incorrect frame rate: %s\n", arg);
 
4403
                } else {
 
4404
                    video_enc.time_base.num = frame_rate.den;
 
4405
                    video_enc.time_base.den = frame_rate.num;
 
4406
                }
 
4407
            }
 
4408
        } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
 
4409
            get_arg(arg, sizeof(arg), &p);
 
4410
            if (stream)
 
4411
                video_enc.gop_size = atoi(arg);
 
4412
        } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
 
4413
            if (stream)
 
4414
                video_enc.gop_size = 1;
 
4415
        } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
 
4416
            if (stream)
 
4417
                video_enc.mb_decision = FF_MB_DECISION_BITS;
 
4418
        } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
 
4419
            if (stream) {
 
4420
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
 
4421
                video_enc.flags |= CODEC_FLAG_4MV;
 
4422
            }
 
4423
        } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
 
4424
                   !av_strcasecmp(cmd, "AVOptionAudio")) {
 
4425
            char arg2[1024];
 
4426
            AVCodecContext *avctx;
 
4427
            int type;
 
4428
            get_arg(arg, sizeof(arg), &p);
 
4429
            get_arg(arg2, sizeof(arg2), &p);
 
4430
            if (!av_strcasecmp(cmd, "AVOptionVideo")) {
 
4431
                avctx = &video_enc;
 
4432
                type = AV_OPT_FLAG_VIDEO_PARAM;
 
4433
            } else {
 
4434
                avctx = &audio_enc;
 
4435
                type = AV_OPT_FLAG_AUDIO_PARAM;
 
4436
            }
 
4437
            if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
 
4438
                ERROR("AVOption error: %s %s\n", arg, arg2);
 
4439
            }
 
4440
        } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
 
4441
                   !av_strcasecmp(cmd, "AVPresetAudio")) {
 
4442
            AVCodecContext *avctx;
 
4443
            int type;
 
4444
            get_arg(arg, sizeof(arg), &p);
 
4445
            if (!av_strcasecmp(cmd, "AVPresetVideo")) {
 
4446
                avctx = &video_enc;
 
4447
                video_enc.codec_id = video_id;
 
4448
                type = AV_OPT_FLAG_VIDEO_PARAM;
 
4449
            } else {
 
4450
                avctx = &audio_enc;
 
4451
                audio_enc.codec_id = audio_id;
 
4452
                type = AV_OPT_FLAG_AUDIO_PARAM;
 
4453
            }
 
4454
            if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
 
4455
                ERROR("AVPreset error: %s\n", arg);
 
4456
            }
 
4457
        } else if (!av_strcasecmp(cmd, "VideoTag")) {
 
4458
            get_arg(arg, sizeof(arg), &p);
 
4459
            if ((strlen(arg) == 4) && stream)
 
4460
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
 
4461
        } else if (!av_strcasecmp(cmd, "BitExact")) {
 
4462
            if (stream)
 
4463
                video_enc.flags |= CODEC_FLAG_BITEXACT;
 
4464
        } else if (!av_strcasecmp(cmd, "DctFastint")) {
 
4465
            if (stream)
 
4466
                video_enc.dct_algo  = FF_DCT_FASTINT;
 
4467
        } else if (!av_strcasecmp(cmd, "IdctSimple")) {
 
4468
            if (stream)
 
4469
                video_enc.idct_algo = FF_IDCT_SIMPLE;
 
4470
        } else if (!av_strcasecmp(cmd, "Qscale")) {
 
4471
            get_arg(arg, sizeof(arg), &p);
 
4472
            if (stream) {
 
4473
                video_enc.flags |= CODEC_FLAG_QSCALE;
 
4474
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
 
4475
            }
 
4476
        } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
 
4477
            get_arg(arg, sizeof(arg), &p);
 
4478
            if (stream) {
 
4479
                video_enc.max_qdiff = atoi(arg);
 
4480
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
 
4481
                    ERROR("VideoQDiff out of range\n");
 
4482
                }
 
4483
            }
 
4484
        } else if (!av_strcasecmp(cmd, "VideoQMax")) {
 
4485
            get_arg(arg, sizeof(arg), &p);
 
4486
            if (stream) {
 
4487
                video_enc.qmax = atoi(arg);
 
4488
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
 
4489
                    ERROR("VideoQMax out of range\n");
 
4490
                }
 
4491
            }
 
4492
        } else if (!av_strcasecmp(cmd, "VideoQMin")) {
 
4493
            get_arg(arg, sizeof(arg), &p);
 
4494
            if (stream) {
 
4495
                video_enc.qmin = atoi(arg);
 
4496
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
 
4497
                    ERROR("VideoQMin out of range\n");
 
4498
                }
 
4499
            }
 
4500
        } else if (!av_strcasecmp(cmd, "LumaElim")) {
 
4501
            get_arg(arg, sizeof(arg), &p);
 
4502
            if (stream)
 
4503
                video_enc.luma_elim_threshold = atoi(arg);
 
4504
        } else if (!av_strcasecmp(cmd, "ChromaElim")) {
 
4505
            get_arg(arg, sizeof(arg), &p);
 
4506
            if (stream)
 
4507
                video_enc.chroma_elim_threshold = atoi(arg);
 
4508
        } else if (!av_strcasecmp(cmd, "LumiMask")) {
 
4509
            get_arg(arg, sizeof(arg), &p);
 
4510
            if (stream)
 
4511
                video_enc.lumi_masking = atof(arg);
 
4512
        } else if (!av_strcasecmp(cmd, "DarkMask")) {
 
4513
            get_arg(arg, sizeof(arg), &p);
 
4514
            if (stream)
 
4515
                video_enc.dark_masking = atof(arg);
 
4516
        } else if (!av_strcasecmp(cmd, "NoVideo")) {
 
4517
            video_id = CODEC_ID_NONE;
 
4518
        } else if (!av_strcasecmp(cmd, "NoAudio")) {
 
4519
            audio_id = CODEC_ID_NONE;
 
4520
        } else if (!av_strcasecmp(cmd, "ACL")) {
 
4521
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
 
4522
        } else if (!av_strcasecmp(cmd, "DynamicACL")) {
 
4523
            if (stream) {
 
4524
                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
 
4525
            }
 
4526
        } else if (!av_strcasecmp(cmd, "RTSPOption")) {
 
4527
            get_arg(arg, sizeof(arg), &p);
 
4528
            if (stream) {
 
4529
                av_freep(&stream->rtsp_option);
 
4530
                stream->rtsp_option = av_strdup(arg);
 
4531
            }
 
4532
        } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
 
4533
            get_arg(arg, sizeof(arg), &p);
 
4534
            if (stream) {
 
4535
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
 
4536
                    ERROR("Invalid host/IP address: %s\n", arg);
 
4537
                }
 
4538
                stream->is_multicast = 1;
 
4539
                stream->loop = 1; /* default is looping */
 
4540
            }
 
4541
        } else if (!av_strcasecmp(cmd, "MulticastPort")) {
 
4542
            get_arg(arg, sizeof(arg), &p);
 
4543
            if (stream)
 
4544
                stream->multicast_port = atoi(arg);
 
4545
        } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
 
4546
            get_arg(arg, sizeof(arg), &p);
 
4547
            if (stream)
 
4548
                stream->multicast_ttl = atoi(arg);
 
4549
        } else if (!av_strcasecmp(cmd, "NoLoop")) {
 
4550
            if (stream)
 
4551
                stream->loop = 0;
 
4552
        } else if (!av_strcasecmp(cmd, "</Stream>")) {
 
4553
            if (!stream) {
 
4554
                ERROR("No corresponding <Stream> for </Stream>\n");
 
4555
            } else {
 
4556
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
 
4557
                    if (audio_id != CODEC_ID_NONE) {
 
4558
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
 
4559
                        audio_enc.codec_id = audio_id;
 
4560
                        add_codec(stream, &audio_enc);
 
4561
                    }
 
4562
                    if (video_id != CODEC_ID_NONE) {
 
4563
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
 
4564
                        video_enc.codec_id = video_id;
 
4565
                        add_codec(stream, &video_enc);
 
4566
                    }
 
4567
                }
 
4568
                stream = NULL;
 
4569
            }
 
4570
        } else if (!av_strcasecmp(cmd, "<Redirect")) {
 
4571
            /*********************************************/
 
4572
            char *q;
 
4573
            if (stream || feed || redirect) {
 
4574
                ERROR("Already in a tag\n");
 
4575
            } else {
 
4576
                redirect = av_mallocz(sizeof(FFStream));
 
4577
                *last_stream = redirect;
 
4578
                last_stream = &redirect->next;
 
4579
 
 
4580
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
 
4581
                q = strrchr(redirect->filename, '>');
 
4582
                if (*q)
 
4583
                    *q = '\0';
 
4584
                redirect->stream_type = STREAM_TYPE_REDIRECT;
 
4585
            }
 
4586
        } else if (!av_strcasecmp(cmd, "URL")) {
 
4587
            if (redirect)
 
4588
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
 
4589
        } else if (!av_strcasecmp(cmd, "</Redirect>")) {
 
4590
            if (!redirect) {
 
4591
                ERROR("No corresponding <Redirect> for </Redirect>\n");
 
4592
            } else {
 
4593
                if (!redirect->feed_filename[0]) {
 
4594
                    ERROR("No URL found for <Redirect>\n");
 
4595
                }
 
4596
                redirect = NULL;
 
4597
            }
 
4598
        } else if (!av_strcasecmp(cmd, "LoadModule")) {
 
4599
            get_arg(arg, sizeof(arg), &p);
 
4600
#if HAVE_DLOPEN
 
4601
            load_module(arg);
 
4602
#else
 
4603
            ERROR("Module support not compiled into this version: '%s'\n", arg);
 
4604
#endif
 
4605
        } else {
 
4606
            ERROR("Incorrect keyword: '%s'\n", cmd);
 
4607
        }
 
4608
    }
 
4609
#undef ERROR
 
4610
 
 
4611
    fclose(f);
 
4612
    if (errors)
 
4613
        return -1;
 
4614
    else
 
4615
        return 0;
 
4616
}
 
4617
 
 
4618
static void handle_child_exit(int sig)
 
4619
{
 
4620
    pid_t pid;
 
4621
    int status;
 
4622
 
 
4623
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 
4624
        FFStream *feed;
 
4625
 
 
4626
        for (feed = first_feed; feed; feed = feed->next) {
 
4627
            if (feed->pid == pid) {
 
4628
                int uptime = time(0) - feed->pid_start;
 
4629
 
 
4630
                feed->pid = 0;
 
4631
                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
 
4632
 
 
4633
                if (uptime < 30)
 
4634
                    /* Turn off any more restarts */
 
4635
                    feed->child_argv = 0;
 
4636
            }
 
4637
        }
 
4638
    }
 
4639
 
 
4640
    need_to_start_children = 1;
 
4641
}
 
4642
 
 
4643
static void opt_debug(void)
 
4644
{
 
4645
    avserver_debug = 1;
 
4646
    avserver_daemon = 0;
 
4647
    logfilename[0] = '-';
 
4648
}
 
4649
 
 
4650
static void show_help(void)
 
4651
{
 
4652
    printf("usage: avserver [options]\n"
 
4653
           "Hyper fast multi format Audio/Video streaming server\n");
 
4654
    printf("\n");
 
4655
    show_help_options(options, "Main options:\n", 0, 0);
 
4656
}
 
4657
 
 
4658
static const OptionDef options[] = {
 
4659
#include "cmdutils_common_opts.h"
 
4660
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
 
4661
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
 
4662
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/avserver.conf", "configfile" },
 
4663
    { NULL },
 
4664
};
 
4665
 
 
4666
int main(int argc, char **argv)
 
4667
{
 
4668
    struct sigaction sigact;
 
4669
 
 
4670
    parse_loglevel(argc, argv, options);
 
4671
    av_register_all();
 
4672
    avformat_network_init();
 
4673
 
 
4674
    show_banner();
 
4675
 
 
4676
    my_program_name = argv[0];
 
4677
    my_program_dir = getcwd(0, 0);
 
4678
    avserver_daemon = 1;
 
4679
 
 
4680
    parse_options(NULL, argc, argv, options, NULL);
 
4681
 
 
4682
    unsetenv("http_proxy");             /* Kill the http_proxy */
 
4683
 
 
4684
    av_lfg_init(&random_state, av_get_random_seed());
 
4685
 
 
4686
    memset(&sigact, 0, sizeof(sigact));
 
4687
    sigact.sa_handler = handle_child_exit;
 
4688
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
 
4689
    sigaction(SIGCHLD, &sigact, 0);
 
4690
 
 
4691
    if (parse_ffconfig(config_filename) < 0) {
 
4692
        fprintf(stderr, "Incorrect config file - exiting.\n");
 
4693
        exit(1);
 
4694
    }
 
4695
 
 
4696
    /* open log file if needed */
 
4697
    if (logfilename[0] != '\0') {
 
4698
        if (!strcmp(logfilename, "-"))
 
4699
            logfile = stdout;
 
4700
        else
 
4701
            logfile = fopen(logfilename, "a");
 
4702
        av_log_set_callback(http_av_log);
 
4703
    }
 
4704
 
 
4705
    build_file_streams();
 
4706
 
 
4707
    build_feed_streams();
 
4708
 
 
4709
    compute_bandwidth();
 
4710
 
 
4711
    /* put the process in background and detach it from its TTY */
 
4712
    if (avserver_daemon) {
 
4713
        int pid;
 
4714
 
 
4715
        pid = fork();
 
4716
        if (pid < 0) {
 
4717
            perror("fork");
 
4718
            exit(1);
 
4719
        } else if (pid > 0) {
 
4720
            /* parent : exit */
 
4721
            exit(0);
 
4722
        } else {
 
4723
            /* child */
 
4724
            setsid();
 
4725
            close(0);
 
4726
            open("/dev/null", O_RDWR);
 
4727
            if (strcmp(logfilename, "-") != 0) {
 
4728
                close(1);
 
4729
                dup(0);
 
4730
            }
 
4731
            close(2);
 
4732
            dup(0);
 
4733
        }
 
4734
    }
 
4735
 
 
4736
    /* signal init */
 
4737
    signal(SIGPIPE, SIG_IGN);
 
4738
 
 
4739
    if (avserver_daemon)
 
4740
        chdir("/");
 
4741
 
 
4742
    if (http_server() < 0) {
 
4743
        http_log("Could not start server\n");
 
4744
        exit(1);
 
4745
    }
 
4746
 
 
4747
    return 0;
 
4748
}