Browse code

Rename ffserver to avserver.

Anton Khirnov authored on 2011/07/27 04:56:56
Showing 19 changed files
... ...
@@ -14,7 +14,7 @@ doxy
14 14
 ffmpeg
15 15
 avplay
16 16
 avprobe
17
-ffserver
17
+avserver
18 18
 libavcodec/*_tablegen
19 19
 libavcodec/*_tables.c
20 20
 libavcodec/*_tables.h
... ...
@@ -5,7 +5,7 @@ releases are sorted from youngest to oldest.
5 5
 version <next>:
6 6
 - BWF muxer
7 7
 - Flash Screen Video 2 decoder
8
-- ffplay/ffprobe renamed to avplay/avprobe
8
+- ffplay/ffprobe/ffserver renamed to avplay/avprobe/avserver
9 9
 
10 10
 
11 11
 version 0.7:
... ...
@@ -55,7 +55,7 @@ COMPILE_S = $(call COMPILE,AS)
55 55
 PROGS-$(CONFIG_FFMPEG)   += ffmpeg
56 56
 PROGS-$(CONFIG_AVPLAY)   += avplay
57 57
 PROGS-$(CONFIG_AVPROBE)  += avprobe
58
-PROGS-$(CONFIG_FFSERVER) += ffserver
58
+PROGS-$(CONFIG_AVSERVER) += avserver
59 59
 
60 60
 PROGS      := $(PROGS-yes:%=%$(EXESUF))
61 61
 OBJS        = $(PROGS-yes:%=%.o) cmdutils.o
... ...
@@ -64,7 +64,7 @@ HOSTPROGS  := $(TESTTOOLS:%=tests/%)
64 64
 TOOLS       = qt-faststart trasher
65 65
 TOOLS-$(CONFIG_ZLIB) += cws2fws
66 66
 
67
-BASENAMES   = ffmpeg avplay avprobe ffserver
67
+BASENAMES   = ffmpeg avplay avprobe avserver
68 68
 ALLPROGS    = $(BASENAMES:%=%$(EXESUF))
69 69
 ALLMANPAGES = $(BASENAMES:%=%.1)
70 70
 
... ...
@@ -118,7 +118,7 @@ $(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D))))
118 118
 
119 119
 avplay.o: CFLAGS += $(SDL_CFLAGS)
120 120
 avplay$(EXESUF): FF_EXTRALIBS += $(SDL_LIBS)
121
-ffserver$(EXESUF): LDFLAGS += $(FFSERVERLDFLAGS)
121
+avserver$(EXESUF): LDFLAGS += $(AVSERVERLDFLAGS)
122 122
 
123 123
 $(PROGS): %$(EXESUF): %.o cmdutils.o $(FF_DEP_LIBS)
124 124
 	$(LD) $(LDFLAGS) -o $@ $< cmdutils.o $(FF_EXTRALIBS)
125 125
new file mode 100644
... ...
@@ -0,0 +1,4742 @@
0
+/*
1
+ * Multiple format streaming server
2
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
3
+ *
4
+ * This file is part of Libav.
5
+ *
6
+ * Libav is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * Libav is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with Libav; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "config.h"
22
+#if !HAVE_CLOSESOCKET
23
+#define closesocket close
24
+#endif
25
+#include <string.h>
26
+#include <strings.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 ffmpeg process */
226
+    time_t pid_start;  /* Of ffmpeg 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
+/* FIXME: make avserver work with IPv6 */
323
+/* resolve host with also IP address parsing */
324
+static int resolve_host(struct in_addr *sin_addr, const char *hostname)
325
+{
326
+
327
+    if (!ff_inet_aton(hostname, sin_addr)) {
328
+#if HAVE_GETADDRINFO
329
+        struct addrinfo *ai, *cur;
330
+        struct addrinfo hints;
331
+        memset(&hints, 0, sizeof(hints));
332
+        hints.ai_family = AF_INET;
333
+        if (getaddrinfo(hostname, NULL, &hints, &ai))
334
+            return -1;
335
+        /* getaddrinfo returns a linked list of addrinfo structs.
336
+         * Even if we set ai_family = AF_INET above, make sure
337
+         * that the returned one actually is of the correct type. */
338
+        for (cur = ai; cur; cur = cur->ai_next) {
339
+            if (cur->ai_family == AF_INET) {
340
+                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
341
+                freeaddrinfo(ai);
342
+                return 0;
343
+            }
344
+        }
345
+        freeaddrinfo(ai);
346
+        return -1;
347
+#else
348
+        struct hostent *hp;
349
+        hp = gethostbyname(hostname);
350
+        if (!hp)
351
+            return -1;
352
+        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
353
+#endif
354
+    }
355
+    return 0;
356
+}
357
+
358
+static char *ctime1(char *buf2)
359
+{
360
+    time_t ti;
361
+    char *p;
362
+
363
+    ti = time(NULL);
364
+    p = ctime(&ti);
365
+    strcpy(buf2, p);
366
+    p = buf2 + strlen(p) - 1;
367
+    if (*p == '\n')
368
+        *p = '\0';
369
+    return buf2;
370
+}
371
+
372
+static void http_vlog(const char *fmt, va_list vargs)
373
+{
374
+    static int print_prefix = 1;
375
+    if (logfile) {
376
+        if (print_prefix) {
377
+            char buf[32];
378
+            ctime1(buf);
379
+            fprintf(logfile, "%s ", buf);
380
+        }
381
+        print_prefix = strstr(fmt, "\n") != NULL;
382
+        vfprintf(logfile, fmt, vargs);
383
+        fflush(logfile);
384
+    }
385
+}
386
+
387
+#ifdef __GNUC__
388
+__attribute__ ((format (printf, 1, 2)))
389
+#endif
390
+static void http_log(const char *fmt, ...)
391
+{
392
+    va_list vargs;
393
+    va_start(vargs, fmt);
394
+    http_vlog(fmt, vargs);
395
+    va_end(vargs);
396
+}
397
+
398
+static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
399
+{
400
+    static int print_prefix = 1;
401
+    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
402
+    if (level > av_log_get_level())
403
+        return;
404
+    if (print_prefix && avc)
405
+        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
406
+    print_prefix = strstr(fmt, "\n") != NULL;
407
+    http_vlog(fmt, vargs);
408
+}
409
+
410
+static void log_connection(HTTPContext *c)
411
+{
412
+    if (c->suppress_log)
413
+        return;
414
+
415
+    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
416
+             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
417
+             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
418
+}
419
+
420
+static void update_datarate(DataRateData *drd, int64_t count)
421
+{
422
+    if (!drd->time1 && !drd->count1) {
423
+        drd->time1 = drd->time2 = cur_time;
424
+        drd->count1 = drd->count2 = count;
425
+    } else if (cur_time - drd->time2 > 5000) {
426
+        drd->time1 = drd->time2;
427
+        drd->count1 = drd->count2;
428
+        drd->time2 = cur_time;
429
+        drd->count2 = count;
430
+    }
431
+}
432
+
433
+/* In bytes per second */
434
+static int compute_datarate(DataRateData *drd, int64_t count)
435
+{
436
+    if (cur_time == drd->time1)
437
+        return 0;
438
+
439
+    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
440
+}
441
+
442
+
443
+static void start_children(FFStream *feed)
444
+{
445
+    if (no_launch)
446
+        return;
447
+
448
+    for (; feed; feed = feed->next) {
449
+        if (feed->child_argv && !feed->pid) {
450
+            feed->pid_start = time(0);
451
+
452
+            feed->pid = fork();
453
+
454
+            if (feed->pid < 0) {
455
+                http_log("Unable to create children\n");
456
+                exit(1);
457
+            }
458
+            if (!feed->pid) {
459
+                /* In child */
460
+                char pathname[1024];
461
+                char *slash;
462
+                int i;
463
+
464
+                av_strlcpy(pathname, my_program_name, sizeof(pathname));
465
+
466
+                slash = strrchr(pathname, '/');
467
+                if (!slash)
468
+                    slash = pathname;
469
+                else
470
+                    slash++;
471
+                strcpy(slash, "ffmpeg");
472
+
473
+                http_log("Launch commandline: ");
474
+                http_log("%s ", pathname);
475
+                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
476
+                    http_log("%s ", feed->child_argv[i]);
477
+                http_log("\n");
478
+
479
+                for (i = 3; i < 256; i++)
480
+                    close(i);
481
+
482
+                if (!avserver_debug) {
483
+                    i = open("/dev/null", O_RDWR);
484
+                    if (i != -1) {
485
+                        dup2(i, 0);
486
+                        dup2(i, 1);
487
+                        dup2(i, 2);
488
+                        close(i);
489
+                    }
490
+                }
491
+
492
+                /* This is needed to make relative pathnames work */
493
+                chdir(my_program_dir);
494
+
495
+                signal(SIGPIPE, SIG_DFL);
496
+
497
+                execvp(pathname, feed->child_argv);
498
+
499
+                _exit(1);
500
+            }
501
+        }
502
+    }
503
+}
504
+
505
+/* open a listening socket */
506
+static int socket_open_listen(struct sockaddr_in *my_addr)
507
+{
508
+    int server_fd, tmp;
509
+
510
+    server_fd = socket(AF_INET,SOCK_STREAM,0);
511
+    if (server_fd < 0) {
512
+        perror ("socket");
513
+        return -1;
514
+    }
515
+
516
+    tmp = 1;
517
+    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
518
+
519
+    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
520
+        char bindmsg[32];
521
+        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
522
+        perror (bindmsg);
523
+        closesocket(server_fd);
524
+        return -1;
525
+    }
526
+
527
+    if (listen (server_fd, 5) < 0) {
528
+        perror ("listen");
529
+        closesocket(server_fd);
530
+        return -1;
531
+    }
532
+    ff_socket_nonblock(server_fd, 1);
533
+
534
+    return server_fd;
535
+}
536
+
537
+/* start all multicast streams */
538
+static void start_multicast(void)
539
+{
540
+    FFStream *stream;
541
+    char session_id[32];
542
+    HTTPContext *rtp_c;
543
+    struct sockaddr_in dest_addr;
544
+    int default_port, stream_index;
545
+
546
+    default_port = 6000;
547
+    for(stream = first_stream; stream != NULL; stream = stream->next) {
548
+        if (stream->is_multicast) {
549
+            /* open the RTP connection */
550
+            snprintf(session_id, sizeof(session_id), "%08x%08x",
551
+                     av_lfg_get(&random_state), av_lfg_get(&random_state));
552
+
553
+            /* choose a port if none given */
554
+            if (stream->multicast_port == 0) {
555
+                stream->multicast_port = default_port;
556
+                default_port += 100;
557
+            }
558
+
559
+            dest_addr.sin_family = AF_INET;
560
+            dest_addr.sin_addr = stream->multicast_ip;
561
+            dest_addr.sin_port = htons(stream->multicast_port);
562
+
563
+            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
564
+                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
565
+            if (!rtp_c)
566
+                continue;
567
+
568
+            if (open_input_stream(rtp_c, "") < 0) {
569
+                http_log("Could not open input stream for stream '%s'\n",
570
+                         stream->filename);
571
+                continue;
572
+            }
573
+
574
+            /* open each RTP stream */
575
+            for(stream_index = 0; stream_index < stream->nb_streams;
576
+                stream_index++) {
577
+                dest_addr.sin_port = htons(stream->multicast_port +
578
+                                           2 * stream_index);
579
+                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
580
+                    http_log("Could not open output stream '%s/streamid=%d'\n",
581
+                             stream->filename, stream_index);
582
+                    exit(1);
583
+                }
584
+            }
585
+
586
+            /* change state to send data */
587
+            rtp_c->state = HTTPSTATE_SEND_DATA;
588
+        }
589
+    }
590
+}
591
+
592
+/* main loop of the http server */
593
+static int http_server(void)
594
+{
595
+    int server_fd = 0, rtsp_server_fd = 0;
596
+    int ret, delay, delay1;
597
+    struct pollfd *poll_table, *poll_entry;
598
+    HTTPContext *c, *c_next;
599
+
600
+    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
601
+        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
602
+        return -1;
603
+    }
604
+
605
+    if (my_http_addr.sin_port) {
606
+        server_fd = socket_open_listen(&my_http_addr);
607
+        if (server_fd < 0)
608
+            return -1;
609
+    }
610
+
611
+    if (my_rtsp_addr.sin_port) {
612
+        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
613
+        if (rtsp_server_fd < 0)
614
+            return -1;
615
+    }
616
+
617
+    if (!rtsp_server_fd && !server_fd) {
618
+        http_log("HTTP and RTSP disabled.\n");
619
+        return -1;
620
+    }
621
+
622
+    http_log("AVserver started.\n");
623
+
624
+    start_children(first_feed);
625
+
626
+    start_multicast();
627
+
628
+    for(;;) {
629
+        poll_entry = poll_table;
630
+        if (server_fd) {
631
+            poll_entry->fd = server_fd;
632
+            poll_entry->events = POLLIN;
633
+            poll_entry++;
634
+        }
635
+        if (rtsp_server_fd) {
636
+            poll_entry->fd = rtsp_server_fd;
637
+            poll_entry->events = POLLIN;
638
+            poll_entry++;
639
+        }
640
+
641
+        /* wait for events on each HTTP handle */
642
+        c = first_http_ctx;
643
+        delay = 1000;
644
+        while (c != NULL) {
645
+            int fd;
646
+            fd = c->fd;
647
+            switch(c->state) {
648
+            case HTTPSTATE_SEND_HEADER:
649
+            case RTSPSTATE_SEND_REPLY:
650
+            case RTSPSTATE_SEND_PACKET:
651
+                c->poll_entry = poll_entry;
652
+                poll_entry->fd = fd;
653
+                poll_entry->events = POLLOUT;
654
+                poll_entry++;
655
+                break;
656
+            case HTTPSTATE_SEND_DATA_HEADER:
657
+            case HTTPSTATE_SEND_DATA:
658
+            case HTTPSTATE_SEND_DATA_TRAILER:
659
+                if (!c->is_packetized) {
660
+                    /* for TCP, we output as much as we can (may need to put a limit) */
661
+                    c->poll_entry = poll_entry;
662
+                    poll_entry->fd = fd;
663
+                    poll_entry->events = POLLOUT;
664
+                    poll_entry++;
665
+                } else {
666
+                    /* when avserver is doing the timing, we work by
667
+                       looking at which packet need to be sent every
668
+                       10 ms */
669
+                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
670
+                    if (delay1 < delay)
671
+                        delay = delay1;
672
+                }
673
+                break;
674
+            case HTTPSTATE_WAIT_REQUEST:
675
+            case HTTPSTATE_RECEIVE_DATA:
676
+            case HTTPSTATE_WAIT_FEED:
677
+            case RTSPSTATE_WAIT_REQUEST:
678
+                /* need to catch errors */
679
+                c->poll_entry = poll_entry;
680
+                poll_entry->fd = fd;
681
+                poll_entry->events = POLLIN;/* Maybe this will work */
682
+                poll_entry++;
683
+                break;
684
+            default:
685
+                c->poll_entry = NULL;
686
+                break;
687
+            }
688
+            c = c->next;
689
+        }
690
+
691
+        /* wait for an event on one connection. We poll at least every
692
+           second to handle timeouts */
693
+        do {
694
+            ret = poll(poll_table, poll_entry - poll_table, delay);
695
+            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
696
+                ff_neterrno() != AVERROR(EINTR))
697
+                return -1;
698
+        } while (ret < 0);
699
+
700
+        cur_time = av_gettime() / 1000;
701
+
702
+        if (need_to_start_children) {
703
+            need_to_start_children = 0;
704
+            start_children(first_feed);
705
+        }
706
+
707
+        /* now handle the events */
708
+        for(c = first_http_ctx; c != NULL; c = c_next) {
709
+            c_next = c->next;
710
+            if (handle_connection(c) < 0) {
711
+                /* close and free the connection */
712
+                log_connection(c);
713
+                close_connection(c);
714
+            }
715
+        }
716
+
717
+        poll_entry = poll_table;
718
+        if (server_fd) {
719
+            /* new HTTP connection request ? */
720
+            if (poll_entry->revents & POLLIN)
721
+                new_connection(server_fd, 0);
722
+            poll_entry++;
723
+        }
724
+        if (rtsp_server_fd) {
725
+            /* new RTSP connection request ? */
726
+            if (poll_entry->revents & POLLIN)
727
+                new_connection(rtsp_server_fd, 1);
728
+        }
729
+    }
730
+}
731
+
732
+/* start waiting for a new HTTP/RTSP request */
733
+static void start_wait_request(HTTPContext *c, int is_rtsp)
734
+{
735
+    c->buffer_ptr = c->buffer;
736
+    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
737
+
738
+    if (is_rtsp) {
739
+        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
740
+        c->state = RTSPSTATE_WAIT_REQUEST;
741
+    } else {
742
+        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
743
+        c->state = HTTPSTATE_WAIT_REQUEST;
744
+    }
745
+}
746
+
747
+static void http_send_too_busy_reply(int fd)
748
+{
749
+    char buffer[300];
750
+    int len = snprintf(buffer, sizeof(buffer),
751
+                       "HTTP/1.0 503 Server too busy\r\n"
752
+                       "Content-type: text/html\r\n"
753
+                       "\r\n"
754
+                       "<html><head><title>Too busy</title></head><body>\r\n"
755
+                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
756
+                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
757
+                       "</body></html>\r\n",
758
+                       nb_connections, nb_max_connections);
759
+    send(fd, buffer, len, 0);
760
+}
761
+
762
+
763
+static void new_connection(int server_fd, int is_rtsp)
764
+{
765
+    struct sockaddr_in from_addr;
766
+    int fd, len;
767
+    HTTPContext *c = NULL;
768
+
769
+    len = sizeof(from_addr);
770
+    fd = accept(server_fd, (struct sockaddr *)&from_addr,
771
+                &len);
772
+    if (fd < 0) {
773
+        http_log("error during accept %s\n", strerror(errno));
774
+        return;
775
+    }
776
+    ff_socket_nonblock(fd, 1);
777
+
778
+    if (nb_connections >= nb_max_connections) {
779
+        http_send_too_busy_reply(fd);
780
+        goto fail;
781
+    }
782
+
783
+    /* add a new connection */
784
+    c = av_mallocz(sizeof(HTTPContext));
785
+    if (!c)
786
+        goto fail;
787
+
788
+    c->fd = fd;
789
+    c->poll_entry = NULL;
790
+    c->from_addr = from_addr;
791
+    c->buffer_size = IOBUFFER_INIT_SIZE;
792
+    c->buffer = av_malloc(c->buffer_size);
793
+    if (!c->buffer)
794
+        goto fail;
795
+
796
+    c->next = first_http_ctx;
797
+    first_http_ctx = c;
798
+    nb_connections++;
799
+
800
+    start_wait_request(c, is_rtsp);
801
+
802
+    return;
803
+
804
+ fail:
805
+    if (c) {
806
+        av_free(c->buffer);
807
+        av_free(c);
808
+    }
809
+    closesocket(fd);
810
+}
811
+
812
+static void close_connection(HTTPContext *c)
813
+{
814
+    HTTPContext **cp, *c1;
815
+    int i, nb_streams;
816
+    AVFormatContext *ctx;
817
+    URLContext *h;
818
+    AVStream *st;
819
+
820
+    /* remove connection from list */
821
+    cp = &first_http_ctx;
822
+    while ((*cp) != NULL) {
823
+        c1 = *cp;
824
+        if (c1 == c)
825
+            *cp = c->next;
826
+        else
827
+            cp = &c1->next;
828
+    }
829
+
830
+    /* remove references, if any (XXX: do it faster) */
831
+    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
832
+        if (c1->rtsp_c == c)
833
+            c1->rtsp_c = NULL;
834
+    }
835
+
836
+    /* remove connection associated resources */
837
+    if (c->fd >= 0)
838
+        closesocket(c->fd);
839
+    if (c->fmt_in) {
840
+        /* close each frame parser */
841
+        for(i=0;i<c->fmt_in->nb_streams;i++) {
842
+            st = c->fmt_in->streams[i];
843
+            if (st->codec->codec)
844
+                avcodec_close(st->codec);
845
+        }
846
+        av_close_input_file(c->fmt_in);
847
+    }
848
+
849
+    /* free RTP output streams if any */
850
+    nb_streams = 0;
851
+    if (c->stream)
852
+        nb_streams = c->stream->nb_streams;
853
+
854
+    for(i=0;i<nb_streams;i++) {
855
+        ctx = c->rtp_ctx[i];
856
+        if (ctx) {
857
+            av_write_trailer(ctx);
858
+            av_dict_free(&ctx->metadata);
859
+            av_free(ctx->streams[0]);
860
+            av_free(ctx);
861
+        }
862
+        h = c->rtp_handles[i];
863
+        if (h)
864
+            url_close(h);
865
+    }
866
+
867
+    ctx = &c->fmt_ctx;
868
+
869
+    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
870
+        if (ctx->oformat) {
871
+            /* prepare header */
872
+            if (avio_open_dyn_buf(&ctx->pb) >= 0) {
873
+                av_write_trailer(ctx);
874
+                av_freep(&c->pb_buffer);
875
+                avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
876
+            }
877
+        }
878
+    }
879
+
880
+    for(i=0; i<ctx->nb_streams; i++)
881
+        av_free(ctx->streams[i]);
882
+
883
+    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
884
+        current_bandwidth -= c->stream->bandwidth;
885
+
886
+    /* signal that there is no feed if we are the feeder socket */
887
+    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
888
+        c->stream->feed_opened = 0;
889
+        close(c->feed_fd);
890
+    }
891
+
892
+    av_freep(&c->pb_buffer);
893
+    av_freep(&c->packet_buffer);
894
+    av_free(c->buffer);
895
+    av_free(c);
896
+    nb_connections--;
897
+}
898
+
899
+static int handle_connection(HTTPContext *c)
900
+{
901
+    int len, ret;
902
+
903
+    switch(c->state) {
904
+    case HTTPSTATE_WAIT_REQUEST:
905
+    case RTSPSTATE_WAIT_REQUEST:
906
+        /* timeout ? */
907
+        if ((c->timeout - cur_time) < 0)
908
+            return -1;
909
+        if (c->poll_entry->revents & (POLLERR | POLLHUP))
910
+            return -1;
911
+
912
+        /* no need to read if no events */
913
+        if (!(c->poll_entry->revents & POLLIN))
914
+            return 0;
915
+        /* read the data */
916
+    read_loop:
917
+        len = recv(c->fd, c->buffer_ptr, 1, 0);
918
+        if (len < 0) {
919
+            if (ff_neterrno() != AVERROR(EAGAIN) &&
920
+                ff_neterrno() != AVERROR(EINTR))
921
+                return -1;
922
+        } else if (len == 0) {
923
+            return -1;
924
+        } else {
925
+            /* search for end of request. */
926
+            uint8_t *ptr;
927
+            c->buffer_ptr += len;
928
+            ptr = c->buffer_ptr;
929
+            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
930
+                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
931
+                /* request found : parse it and reply */
932
+                if (c->state == HTTPSTATE_WAIT_REQUEST) {
933
+                    ret = http_parse_request(c);
934
+                } else {
935
+                    ret = rtsp_parse_request(c);
936
+                }
937
+                if (ret < 0)
938
+                    return -1;
939
+            } else if (ptr >= c->buffer_end) {
940
+                /* request too long: cannot do anything */
941
+                return -1;
942
+            } else goto read_loop;
943
+        }
944
+        break;
945
+
946
+    case HTTPSTATE_SEND_HEADER:
947
+        if (c->poll_entry->revents & (POLLERR | POLLHUP))
948
+            return -1;
949
+
950
+        /* no need to write if no events */
951
+        if (!(c->poll_entry->revents & POLLOUT))
952
+            return 0;
953
+        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
954
+        if (len < 0) {
955
+            if (ff_neterrno() != AVERROR(EAGAIN) &&
956
+                ff_neterrno() != AVERROR(EINTR)) {
957
+                /* error : close connection */
958
+                av_freep(&c->pb_buffer);
959
+                return -1;
960
+            }
961
+        } else {
962
+            c->buffer_ptr += len;
963
+            if (c->stream)
964
+                c->stream->bytes_served += len;
965
+            c->data_count += len;
966
+            if (c->buffer_ptr >= c->buffer_end) {
967
+                av_freep(&c->pb_buffer);
968
+                /* if error, exit */
969
+                if (c->http_error)
970
+                    return -1;
971
+                /* all the buffer was sent : synchronize to the incoming stream */
972
+                c->state = HTTPSTATE_SEND_DATA_HEADER;
973
+                c->buffer_ptr = c->buffer_end = c->buffer;
974
+            }
975
+        }
976
+        break;
977
+
978
+    case HTTPSTATE_SEND_DATA:
979
+    case HTTPSTATE_SEND_DATA_HEADER:
980
+    case HTTPSTATE_SEND_DATA_TRAILER:
981
+        /* for packetized output, we consider we can always write (the
982
+           input streams sets the speed). It may be better to verify
983
+           that we do not rely too much on the kernel queues */
984
+        if (!c->is_packetized) {
985
+            if (c->poll_entry->revents & (POLLERR | POLLHUP))
986
+                return -1;
987
+
988
+            /* no need to read if no events */
989
+            if (!(c->poll_entry->revents & POLLOUT))
990
+                return 0;
991
+        }
992
+        if (http_send_data(c) < 0)
993
+            return -1;
994
+        /* close connection if trailer sent */
995
+        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
996
+            return -1;
997
+        break;
998
+    case HTTPSTATE_RECEIVE_DATA:
999
+        /* no need to read if no events */
1000
+        if (c->poll_entry->revents & (POLLERR | POLLHUP))
1001
+            return -1;
1002
+        if (!(c->poll_entry->revents & POLLIN))
1003
+            return 0;
1004
+        if (http_receive_data(c) < 0)
1005
+            return -1;
1006
+        break;
1007
+    case HTTPSTATE_WAIT_FEED:
1008
+        /* no need to read if no events */
1009
+        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1010
+            return -1;
1011
+
1012
+        /* nothing to do, we'll be waken up by incoming feed packets */
1013
+        break;
1014
+
1015
+    case RTSPSTATE_SEND_REPLY:
1016
+        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1017
+            av_freep(&c->pb_buffer);
1018
+            return -1;
1019
+        }
1020
+        /* no need to write if no events */
1021
+        if (!(c->poll_entry->revents & POLLOUT))
1022
+            return 0;
1023
+        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1024
+        if (len < 0) {
1025
+            if (ff_neterrno() != AVERROR(EAGAIN) &&
1026
+                ff_neterrno() != AVERROR(EINTR)) {
1027
+                /* error : close connection */
1028
+                av_freep(&c->pb_buffer);
1029
+                return -1;
1030
+            }
1031
+        } else {
1032
+            c->buffer_ptr += len;
1033
+            c->data_count += len;
1034
+            if (c->buffer_ptr >= c->buffer_end) {
1035
+                /* all the buffer was sent : wait for a new request */
1036
+                av_freep(&c->pb_buffer);
1037
+                start_wait_request(c, 1);
1038
+            }
1039
+        }
1040
+        break;
1041
+    case RTSPSTATE_SEND_PACKET:
1042
+        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1043
+            av_freep(&c->packet_buffer);
1044
+            return -1;
1045
+        }
1046
+        /* no need to write if no events */
1047
+        if (!(c->poll_entry->revents & POLLOUT))
1048
+            return 0;
1049
+        len = send(c->fd, c->packet_buffer_ptr,
1050
+                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1051
+        if (len < 0) {
1052
+            if (ff_neterrno() != AVERROR(EAGAIN) &&
1053
+                ff_neterrno() != AVERROR(EINTR)) {
1054
+                /* error : close connection */
1055
+                av_freep(&c->packet_buffer);
1056
+                return -1;
1057
+            }
1058
+        } else {
1059
+            c->packet_buffer_ptr += len;
1060
+            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1061
+                /* all the buffer was sent : wait for a new request */
1062
+                av_freep(&c->packet_buffer);
1063
+                c->state = RTSPSTATE_WAIT_REQUEST;
1064
+            }
1065
+        }
1066
+        break;
1067
+    case HTTPSTATE_READY:
1068
+        /* nothing to do */
1069
+        break;
1070
+    default:
1071
+        return -1;
1072
+    }
1073
+    return 0;
1074
+}
1075
+
1076
+static int extract_rates(char *rates, int ratelen, const char *request)
1077
+{
1078
+    const char *p;
1079
+
1080
+    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1081
+        if (strncasecmp(p, "Pragma:", 7) == 0) {
1082
+            const char *q = p + 7;
1083
+
1084
+            while (*q && *q != '\n' && isspace(*q))
1085
+                q++;
1086
+
1087
+            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1088
+                int stream_no;
1089
+                int rate_no;
1090
+
1091
+                q += 20;
1092
+
1093
+                memset(rates, 0xff, ratelen);
1094
+
1095
+                while (1) {
1096
+                    while (*q && *q != '\n' && *q != ':')
1097
+                        q++;
1098
+
1099
+                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1100
+                        break;
1101
+
1102
+                    stream_no--;
1103
+                    if (stream_no < ratelen && stream_no >= 0)
1104
+                        rates[stream_no] = rate_no;
1105
+
1106
+                    while (*q && *q != '\n' && !isspace(*q))
1107
+                        q++;
1108
+                }
1109
+
1110
+                return 1;
1111
+            }
1112
+        }
1113
+        p = strchr(p, '\n');
1114
+        if (!p)
1115
+            break;
1116
+
1117
+        p++;
1118
+    }
1119
+
1120
+    return 0;
1121
+}
1122
+
1123
+static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1124
+{
1125
+    int i;
1126
+    int best_bitrate = 100000000;
1127
+    int best = -1;
1128
+
1129
+    for (i = 0; i < feed->nb_streams; i++) {
1130
+        AVCodecContext *feed_codec = feed->streams[i]->codec;
1131
+
1132
+        if (feed_codec->codec_id != codec->codec_id ||
1133
+            feed_codec->sample_rate != codec->sample_rate ||
1134
+            feed_codec->width != codec->width ||
1135
+            feed_codec->height != codec->height)
1136
+            continue;
1137
+
1138
+        /* Potential stream */
1139
+
1140
+        /* We want the fastest stream less than bit_rate, or the slowest
1141
+         * faster than bit_rate
1142
+         */
1143
+
1144
+        if (feed_codec->bit_rate <= bit_rate) {
1145
+            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1146
+                best_bitrate = feed_codec->bit_rate;
1147
+                best = i;
1148
+            }
1149
+        } else {
1150
+            if (feed_codec->bit_rate < best_bitrate) {
1151
+                best_bitrate = feed_codec->bit_rate;
1152
+                best = i;
1153
+            }
1154
+        }
1155
+    }
1156
+
1157
+    return best;
1158
+}
1159
+
1160
+static int modify_current_stream(HTTPContext *c, char *rates)
1161
+{
1162
+    int i;
1163
+    FFStream *req = c->stream;
1164
+    int action_required = 0;
1165
+
1166
+    /* Not much we can do for a feed */
1167
+    if (!req->feed)
1168
+        return 0;
1169
+
1170
+    for (i = 0; i < req->nb_streams; i++) {
1171
+        AVCodecContext *codec = req->streams[i]->codec;
1172
+
1173
+        switch(rates[i]) {
1174
+            case 0:
1175
+                c->switch_feed_streams[i] = req->feed_streams[i];
1176
+                break;
1177
+            case 1:
1178
+                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1179
+                break;
1180
+            case 2:
1181
+                /* Wants off or slow */
1182
+                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1183
+#ifdef WANTS_OFF
1184
+                /* This doesn't work well when it turns off the only stream! */
1185
+                c->switch_feed_streams[i] = -2;
1186
+                c->feed_streams[i] = -2;
1187
+#endif
1188
+                break;
1189
+        }
1190
+
1191
+        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1192
+            action_required = 1;
1193
+    }
1194
+
1195
+    return action_required;
1196
+}
1197
+
1198
+/* XXX: factorize in utils.c ? */
1199
+/* XXX: take care with different space meaning */
1200
+static void skip_spaces(const char **pp)
1201
+{
1202
+    const char *p;
1203
+    p = *pp;
1204
+    while (*p == ' ' || *p == '\t')
1205
+        p++;
1206
+    *pp = p;
1207
+}
1208
+
1209
+static void get_word(char *buf, int buf_size, const char **pp)
1210
+{
1211
+    const char *p;
1212
+    char *q;
1213
+
1214
+    p = *pp;
1215
+    skip_spaces(&p);
1216
+    q = buf;
1217
+    while (!isspace(*p) && *p != '\0') {
1218
+        if ((q - buf) < buf_size - 1)
1219
+            *q++ = *p;
1220
+        p++;
1221
+    }
1222
+    if (buf_size > 0)
1223
+        *q = '\0';
1224
+    *pp = p;
1225
+}
1226
+
1227
+static void get_arg(char *buf, int buf_size, const char **pp)
1228
+{
1229
+    const char *p;
1230
+    char *q;
1231
+    int quote;
1232
+
1233
+    p = *pp;
1234
+    while (isspace(*p)) p++;
1235
+    q = buf;
1236
+    quote = 0;
1237
+    if (*p == '\"' || *p == '\'')
1238
+        quote = *p++;
1239
+    for(;;) {
1240
+        if (quote) {
1241
+            if (*p == quote)
1242
+                break;
1243
+        } else {
1244
+            if (isspace(*p))
1245
+                break;
1246
+        }
1247
+        if (*p == '\0')
1248
+            break;
1249
+        if ((q - buf) < buf_size - 1)
1250
+            *q++ = *p;
1251
+        p++;
1252
+    }
1253
+    *q = '\0';
1254
+    if (quote && *p == quote)
1255
+        p++;
1256
+    *pp = p;
1257
+}
1258
+
1259
+static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1260
+                         const char *p, const char *filename, int line_num)
1261
+{
1262
+    char arg[1024];
1263
+    IPAddressACL acl;
1264
+    int errors = 0;
1265
+
1266
+    get_arg(arg, sizeof(arg), &p);
1267
+    if (strcasecmp(arg, "allow") == 0)
1268
+        acl.action = IP_ALLOW;
1269
+    else if (strcasecmp(arg, "deny") == 0)
1270
+        acl.action = IP_DENY;
1271
+    else {
1272
+        fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1273
+                filename, line_num, arg);
1274
+        errors++;
1275
+    }
1276
+
1277
+    get_arg(arg, sizeof(arg), &p);
1278
+
1279
+    if (resolve_host(&acl.first, arg) != 0) {
1280
+        fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1281
+                filename, line_num, arg);
1282
+        errors++;
1283
+    } else
1284
+        acl.last = acl.first;
1285
+
1286
+    get_arg(arg, sizeof(arg), &p);
1287
+
1288
+    if (arg[0]) {
1289
+        if (resolve_host(&acl.last, arg) != 0) {
1290
+            fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1291
+                    filename, line_num, arg);
1292
+            errors++;
1293
+        }
1294
+    }
1295
+
1296
+    if (!errors) {
1297
+        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1298
+        IPAddressACL **naclp = 0;
1299
+
1300
+        acl.next = 0;
1301
+        *nacl = acl;
1302
+
1303
+        if (stream)
1304
+            naclp = &stream->acl;
1305
+        else if (feed)
1306
+            naclp = &feed->acl;
1307
+        else if (ext_acl)
1308
+            naclp = &ext_acl;
1309
+        else {
1310
+            fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1311
+                    filename, line_num);
1312
+            errors++;
1313
+        }
1314
+
1315
+        if (naclp) {
1316
+            while (*naclp)
1317
+                naclp = &(*naclp)->next;
1318
+
1319
+            *naclp = nacl;
1320
+        }
1321
+    }
1322
+}
1323
+
1324
+
1325
+static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1326
+{
1327
+    FILE* f;
1328
+    char line[1024];
1329
+    char  cmd[1024];
1330
+    IPAddressACL *acl = NULL;
1331
+    int line_num = 0;
1332
+    const char *p;
1333
+
1334
+    f = fopen(stream->dynamic_acl, "r");
1335
+    if (!f) {
1336
+        perror(stream->dynamic_acl);
1337
+        return NULL;
1338
+    }
1339
+
1340
+    acl = av_mallocz(sizeof(IPAddressACL));
1341
+
1342
+    /* Build ACL */
1343
+    for(;;) {
1344
+        if (fgets(line, sizeof(line), f) == NULL)
1345
+            break;
1346
+        line_num++;
1347
+        p = line;
1348
+        while (isspace(*p))
1349
+            p++;
1350
+        if (*p == '\0' || *p == '#')
1351
+            continue;
1352
+        get_arg(cmd, sizeof(cmd), &p);
1353
+
1354
+        if (!strcasecmp(cmd, "ACL"))
1355
+            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1356
+    }
1357
+    fclose(f);
1358
+    return acl;
1359
+}
1360
+
1361
+
1362
+static void free_acl_list(IPAddressACL *in_acl)
1363
+{
1364
+    IPAddressACL *pacl,*pacl2;
1365
+
1366
+    pacl = in_acl;
1367
+    while(pacl) {
1368
+        pacl2 = pacl;
1369
+        pacl = pacl->next;
1370
+        av_freep(pacl2);
1371
+    }
1372
+}
1373
+
1374
+static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1375
+{
1376
+    enum IPAddressAction last_action = IP_DENY;
1377
+    IPAddressACL *acl;
1378
+    struct in_addr *src = &c->from_addr.sin_addr;
1379
+    unsigned long src_addr = src->s_addr;
1380
+
1381
+    for (acl = in_acl; acl; acl = acl->next) {
1382
+        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1383
+            return (acl->action == IP_ALLOW) ? 1 : 0;
1384
+        last_action = acl->action;
1385
+    }
1386
+
1387
+    /* Nothing matched, so return not the last action */
1388
+    return (last_action == IP_DENY) ? 1 : 0;
1389
+}
1390
+
1391
+static int validate_acl(FFStream *stream, HTTPContext *c)
1392
+{
1393
+    int ret = 0;
1394
+    IPAddressACL *acl;
1395
+
1396
+
1397
+    /* if stream->acl is null validate_acl_list will return 1 */
1398
+    ret = validate_acl_list(stream->acl, c);
1399
+
1400
+    if (stream->dynamic_acl[0]) {
1401
+        acl = parse_dynamic_acl(stream, c);
1402
+
1403
+        ret = validate_acl_list(acl, c);
1404
+
1405
+        free_acl_list(acl);
1406
+    }
1407
+
1408
+    return ret;
1409
+}
1410
+
1411
+/* compute the real filename of a file by matching it without its
1412
+   extensions to all the stream filenames */
1413
+static void compute_real_filename(char *filename, int max_size)
1414
+{
1415
+    char file1[1024];
1416
+    char file2[1024];
1417
+    char *p;
1418
+    FFStream *stream;
1419
+
1420
+    /* compute filename by matching without the file extensions */
1421
+    av_strlcpy(file1, filename, sizeof(file1));
1422
+    p = strrchr(file1, '.');
1423
+    if (p)
1424
+        *p = '\0';
1425
+    for(stream = first_stream; stream != NULL; stream = stream->next) {
1426
+        av_strlcpy(file2, stream->filename, sizeof(file2));
1427
+        p = strrchr(file2, '.');
1428
+        if (p)
1429
+            *p = '\0';
1430
+        if (!strcmp(file1, file2)) {
1431
+            av_strlcpy(filename, stream->filename, max_size);
1432
+            break;
1433
+        }
1434
+    }
1435
+}
1436
+
1437
+enum RedirType {
1438
+    REDIR_NONE,
1439
+    REDIR_ASX,
1440
+    REDIR_RAM,
1441
+    REDIR_ASF,
1442
+    REDIR_RTSP,
1443
+    REDIR_SDP,
1444
+};
1445
+
1446
+/* parse http request and prepare header */
1447
+static int http_parse_request(HTTPContext *c)
1448
+{
1449
+    char *p;
1450
+    enum RedirType redir_type;
1451
+    char cmd[32];
1452
+    char info[1024], filename[1024];
1453
+    char url[1024], *q;
1454
+    char protocol[32];
1455
+    char msg[1024];
1456
+    const char *mime_type;
1457
+    FFStream *stream;
1458
+    int i;
1459
+    char ratebuf[32];
1460
+    char *useragent = 0;
1461
+
1462
+    p = c->buffer;
1463
+    get_word(cmd, sizeof(cmd), (const char **)&p);
1464
+    av_strlcpy(c->method, cmd, sizeof(c->method));
1465
+
1466
+    if (!strcmp(cmd, "GET"))
1467
+        c->post = 0;
1468
+    else if (!strcmp(cmd, "POST"))
1469
+        c->post = 1;
1470
+    else
1471
+        return -1;
1472
+
1473
+    get_word(url, sizeof(url), (const char **)&p);
1474
+    av_strlcpy(c->url, url, sizeof(c->url));
1475
+
1476
+    get_word(protocol, sizeof(protocol), (const char **)&p);
1477
+    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1478
+        return -1;
1479
+
1480
+    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1481
+
1482
+    if (avserver_debug)
1483
+        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1484
+
1485
+    /* find the filename and the optional info string in the request */
1486
+    p = strchr(url, '?');
1487
+    if (p) {
1488
+        av_strlcpy(info, p, sizeof(info));
1489
+        *p = '\0';
1490
+    } else
1491
+        info[0] = '\0';
1492
+
1493
+    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1494
+
1495
+    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1496
+        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1497
+            useragent = p + 11;
1498
+            if (*useragent && *useragent != '\n' && isspace(*useragent))
1499
+                useragent++;
1500
+            break;
1501
+        }
1502
+        p = strchr(p, '\n');
1503
+        if (!p)
1504
+            break;
1505
+
1506
+        p++;
1507
+    }
1508
+
1509
+    redir_type = REDIR_NONE;
1510
+    if (av_match_ext(filename, "asx")) {
1511
+        redir_type = REDIR_ASX;
1512
+        filename[strlen(filename)-1] = 'f';
1513
+    } else if (av_match_ext(filename, "asf") &&
1514
+        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1515
+        /* if this isn't WMP or lookalike, return the redirector file */
1516
+        redir_type = REDIR_ASF;
1517
+    } else if (av_match_ext(filename, "rpm,ram")) {
1518
+        redir_type = REDIR_RAM;
1519
+        strcpy(filename + strlen(filename)-2, "m");
1520
+    } else if (av_match_ext(filename, "rtsp")) {
1521
+        redir_type = REDIR_RTSP;
1522
+        compute_real_filename(filename, sizeof(filename) - 1);
1523
+    } else if (av_match_ext(filename, "sdp")) {
1524
+        redir_type = REDIR_SDP;
1525
+        compute_real_filename(filename, sizeof(filename) - 1);
1526
+    }
1527
+
1528
+    // "redirect" / request to index.html
1529
+    if (!strlen(filename))
1530
+        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1531
+
1532
+    stream = first_stream;
1533
+    while (stream != NULL) {
1534
+        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1535
+            break;
1536
+        stream = stream->next;
1537
+    }
1538
+    if (stream == NULL) {
1539
+        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1540
+        http_log("File '%s' not found\n", url);
1541
+        goto send_error;
1542
+    }
1543
+
1544
+    c->stream = stream;
1545
+    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1546
+    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1547
+
1548
+    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1549
+        c->http_error = 301;
1550
+        q = c->buffer;
1551
+        q += snprintf(q, c->buffer_size,
1552
+                      "HTTP/1.0 301 Moved\r\n"
1553
+                      "Location: %s\r\n"
1554
+                      "Content-type: text/html\r\n"
1555
+                      "\r\n"
1556
+                      "<html><head><title>Moved</title></head><body>\r\n"
1557
+                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1558
+                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1559
+        /* prepare output buffer */
1560
+        c->buffer_ptr = c->buffer;
1561
+        c->buffer_end = q;
1562
+        c->state = HTTPSTATE_SEND_HEADER;
1563
+        return 0;
1564
+    }
1565
+
1566
+    /* If this is WMP, get the rate information */
1567
+    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1568
+        if (modify_current_stream(c, ratebuf)) {
1569
+            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1570
+                if (c->switch_feed_streams[i] >= 0)
1571
+                    c->switch_feed_streams[i] = -1;
1572
+            }
1573
+        }
1574
+    }
1575
+
1576
+    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1577
+        current_bandwidth += stream->bandwidth;
1578
+
1579
+    /* If already streaming this feed, do not let start another feeder. */
1580
+    if (stream->feed_opened) {
1581
+        snprintf(msg, sizeof(msg), "This feed is already being received.");
1582
+        http_log("Feed '%s' already being received\n", stream->feed_filename);
1583
+        goto send_error;
1584
+    }
1585
+
1586
+    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1587
+        c->http_error = 503;
1588
+        q = c->buffer;
1589
+        q += snprintf(q, c->buffer_size,
1590
+                      "HTTP/1.0 503 Server too busy\r\n"
1591
+                      "Content-type: text/html\r\n"
1592
+                      "\r\n"
1593
+                      "<html><head><title>Too busy</title></head><body>\r\n"
1594
+                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1595
+                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1596
+                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1597
+                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1598
+        /* prepare output buffer */
1599
+        c->buffer_ptr = c->buffer;
1600
+        c->buffer_end = q;
1601
+        c->state = HTTPSTATE_SEND_HEADER;
1602
+        return 0;
1603
+    }
1604
+
1605
+    if (redir_type != REDIR_NONE) {
1606
+        char *hostinfo = 0;
1607
+
1608
+        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1609
+            if (strncasecmp(p, "Host:", 5) == 0) {
1610
+                hostinfo = p + 5;
1611
+                break;
1612
+            }
1613
+            p = strchr(p, '\n');
1614
+            if (!p)
1615
+                break;
1616
+
1617
+            p++;
1618
+        }
1619
+
1620
+        if (hostinfo) {
1621
+            char *eoh;
1622
+            char hostbuf[260];
1623
+
1624
+            while (isspace(*hostinfo))
1625
+                hostinfo++;
1626
+
1627
+            eoh = strchr(hostinfo, '\n');
1628
+            if (eoh) {
1629
+                if (eoh[-1] == '\r')
1630
+                    eoh--;
1631
+
1632
+                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1633
+                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1634
+                    hostbuf[eoh - hostinfo] = 0;
1635
+
1636
+                    c->http_error = 200;
1637
+                    q = c->buffer;
1638
+                    switch(redir_type) {
1639
+                    case REDIR_ASX:
1640
+                        q += snprintf(q, c->buffer_size,
1641
+                                      "HTTP/1.0 200 ASX Follows\r\n"
1642
+                                      "Content-type: video/x-ms-asf\r\n"
1643
+                                      "\r\n"
1644
+                                      "<ASX Version=\"3\">\r\n"
1645
+                                      //"<!-- Autogenerated by avserver -->\r\n"
1646
+                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1647
+                                      "</ASX>\r\n", hostbuf, filename, info);
1648
+                        break;
1649
+                    case REDIR_RAM:
1650
+                        q += snprintf(q, c->buffer_size,
1651
+                                      "HTTP/1.0 200 RAM Follows\r\n"
1652
+                                      "Content-type: audio/x-pn-realaudio\r\n"
1653
+                                      "\r\n"
1654
+                                      "# Autogenerated by avserver\r\n"
1655
+                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1656
+                        break;
1657
+                    case REDIR_ASF:
1658
+                        q += snprintf(q, c->buffer_size,
1659
+                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1660
+                                      "Content-type: video/x-ms-asf\r\n"
1661
+                                      "\r\n"
1662
+                                      "[Reference]\r\n"
1663
+                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1664
+                        break;
1665
+                    case REDIR_RTSP:
1666
+                        {
1667
+                            char hostname[256], *p;
1668
+                            /* extract only hostname */
1669
+                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1670
+                            p = strrchr(hostname, ':');
1671
+                            if (p)
1672
+                                *p = '\0';
1673
+                            q += snprintf(q, c->buffer_size,
1674
+                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1675
+                                          /* XXX: incorrect mime type ? */
1676
+                                          "Content-type: application/x-rtsp\r\n"
1677
+                                          "\r\n"
1678
+                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1679
+                        }
1680
+                        break;
1681
+                    case REDIR_SDP:
1682
+                        {
1683
+                            uint8_t *sdp_data;
1684
+                            int sdp_data_size, len;
1685
+                            struct sockaddr_in my_addr;
1686
+
1687
+                            q += snprintf(q, c->buffer_size,
1688
+                                          "HTTP/1.0 200 OK\r\n"
1689
+                                          "Content-type: application/sdp\r\n"
1690
+                                          "\r\n");
1691
+
1692
+                            len = sizeof(my_addr);
1693
+                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1694
+
1695
+                            /* XXX: should use a dynamic buffer */
1696
+                            sdp_data_size = prepare_sdp_description(stream,
1697
+                                                                    &sdp_data,
1698
+                                                                    my_addr.sin_addr);
1699
+                            if (sdp_data_size > 0) {
1700
+                                memcpy(q, sdp_data, sdp_data_size);
1701
+                                q += sdp_data_size;
1702
+                                *q = '\0';
1703
+                                av_free(sdp_data);
1704
+                            }
1705
+                        }
1706
+                        break;
1707
+                    default:
1708
+                        abort();
1709
+                        break;
1710
+                    }
1711
+
1712
+                    /* prepare output buffer */
1713
+                    c->buffer_ptr = c->buffer;
1714
+                    c->buffer_end = q;
1715
+                    c->state = HTTPSTATE_SEND_HEADER;
1716
+                    return 0;
1717
+                }
1718
+            }
1719
+        }
1720
+
1721
+        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1722
+        goto send_error;
1723
+    }
1724
+
1725
+    stream->conns_served++;
1726
+
1727
+    /* XXX: add there authenticate and IP match */
1728
+
1729
+    if (c->post) {
1730
+        /* if post, it means a feed is being sent */
1731
+        if (!stream->is_feed) {
1732
+            /* However it might be a status report from WMP! Let us log the
1733
+             * data as it might come in handy one day. */
1734
+            char *logline = 0;
1735
+            int client_id = 0;
1736
+
1737
+            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1738
+                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1739
+                    logline = p;
1740
+                    break;
1741
+                }
1742
+                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1743
+                    client_id = strtol(p + 18, 0, 10);
1744
+                p = strchr(p, '\n');
1745
+                if (!p)
1746
+                    break;
1747
+
1748
+                p++;
1749
+            }
1750
+
1751
+            if (logline) {
1752
+                char *eol = strchr(logline, '\n');
1753
+
1754
+                logline += 17;
1755
+
1756
+                if (eol) {
1757
+                    if (eol[-1] == '\r')
1758
+                        eol--;
1759
+                    http_log("%.*s\n", (int) (eol - logline), logline);
1760
+                    c->suppress_log = 1;
1761
+                }
1762
+            }
1763
+
1764
+#ifdef DEBUG
1765
+            http_log("\nGot request:\n%s\n", c->buffer);
1766
+#endif
1767
+
1768
+            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1769
+                HTTPContext *wmpc;
1770
+
1771
+                /* Now we have to find the client_id */
1772
+                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1773
+                    if (wmpc->wmp_client_id == client_id)
1774
+                        break;
1775
+                }
1776
+
1777
+                if (wmpc && modify_current_stream(wmpc, ratebuf))
1778
+                    wmpc->switch_pending = 1;
1779
+            }
1780
+
1781
+            snprintf(msg, sizeof(msg), "POST command not handled");
1782
+            c->stream = 0;
1783
+            goto send_error;
1784
+        }
1785
+        if (http_start_receive_data(c) < 0) {
1786
+            snprintf(msg, sizeof(msg), "could not open feed");
1787
+            goto send_error;
1788
+        }
1789
+        c->http_error = 0;
1790
+        c->state = HTTPSTATE_RECEIVE_DATA;
1791
+        return 0;
1792
+    }
1793
+
1794
+#ifdef DEBUG
1795
+    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1796
+        http_log("\nGot request:\n%s\n", c->buffer);
1797
+#endif
1798
+
1799
+    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1800
+        goto send_status;
1801
+
1802
+    /* open input stream */
1803
+    if (open_input_stream(c, info) < 0) {
1804
+        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1805
+        goto send_error;
1806
+    }
1807
+
1808
+    /* prepare http header */
1809
+    q = c->buffer;
1810
+    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1811
+    mime_type = c->stream->fmt->mime_type;
1812
+    if (!mime_type)
1813
+        mime_type = "application/x-octet-stream";
1814
+    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1815
+
1816
+    /* for asf, we need extra headers */
1817
+    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1818
+        /* Need to allocate a client id */
1819
+
1820
+        c->wmp_client_id = av_lfg_get(&random_state);
1821
+
1822
+        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);
1823
+    }
1824
+    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1825
+    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1826
+
1827
+    /* prepare output buffer */
1828
+    c->http_error = 0;
1829
+    c->buffer_ptr = c->buffer;
1830
+    c->buffer_end = q;
1831
+    c->state = HTTPSTATE_SEND_HEADER;
1832
+    return 0;
1833
+ send_error:
1834
+    c->http_error = 404;
1835
+    q = c->buffer;
1836
+    q += snprintf(q, c->buffer_size,
1837
+                  "HTTP/1.0 404 Not Found\r\n"
1838
+                  "Content-type: text/html\r\n"
1839
+                  "\r\n"
1840
+                  "<html>\n"
1841
+                  "<head><title>404 Not Found</title></head>\n"
1842
+                  "<body>%s</body>\n"
1843
+                  "</html>\n", msg);
1844
+    /* prepare output buffer */
1845
+    c->buffer_ptr = c->buffer;
1846
+    c->buffer_end = q;
1847
+    c->state = HTTPSTATE_SEND_HEADER;
1848
+    return 0;
1849
+ send_status:
1850
+    compute_status(c);
1851
+    c->http_error = 200; /* horrible : we use this value to avoid
1852
+                            going to the send data state */
1853
+    c->state = HTTPSTATE_SEND_HEADER;
1854
+    return 0;
1855
+}
1856
+
1857
+static void fmt_bytecount(AVIOContext *pb, int64_t count)
1858
+{
1859
+    static const char *suffix = " kMGTP";
1860
+    const char *s;
1861
+
1862
+    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1863
+
1864
+    avio_printf(pb, "%"PRId64"%c", count, *s);
1865
+}
1866
+
1867
+static void compute_status(HTTPContext *c)
1868
+{
1869
+    HTTPContext *c1;
1870
+    FFStream *stream;
1871
+    char *p;
1872
+    time_t ti;
1873
+    int i, len;
1874
+    AVIOContext *pb;
1875
+
1876
+    if (avio_open_dyn_buf(&pb) < 0) {
1877
+        /* XXX: return an error ? */
1878
+        c->buffer_ptr = c->buffer;
1879
+        c->buffer_end = c->buffer;
1880
+        return;
1881
+    }
1882
+
1883
+    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1884
+    avio_printf(pb, "Content-type: %s\r\n", "text/html");
1885
+    avio_printf(pb, "Pragma: no-cache\r\n");
1886
+    avio_printf(pb, "\r\n");
1887
+
1888
+    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1889
+    if (c->stream->feed_filename[0])
1890
+        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1891
+    avio_printf(pb, "</head>\n<body>");
1892
+    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1893
+    /* format status */
1894
+    avio_printf(pb, "<h2>Available Streams</h2>\n");
1895
+    avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1896
+    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");
1897
+    stream = first_stream;
1898
+    while (stream != NULL) {
1899
+        char sfilename[1024];
1900
+        char *eosf;
1901
+
1902
+        if (stream->feed != stream) {
1903
+            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1904
+            eosf = sfilename + strlen(sfilename);
1905
+            if (eosf - sfilename >= 4) {
1906
+                if (strcmp(eosf - 4, ".asf") == 0)
1907
+                    strcpy(eosf - 4, ".asx");
1908
+                else if (strcmp(eosf - 3, ".rm") == 0)
1909
+                    strcpy(eosf - 3, ".ram");
1910
+                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1911
+                    /* generate a sample RTSP director if
1912
+                       unicast. Generate an SDP redirector if
1913
+                       multicast */
1914
+                    eosf = strrchr(sfilename, '.');
1915
+                    if (!eosf)
1916
+                        eosf = sfilename + strlen(sfilename);
1917
+                    if (stream->is_multicast)
1918
+                        strcpy(eosf, ".sdp");
1919
+                    else
1920
+                        strcpy(eosf, ".rtsp");
1921
+                }
1922
+            }
1923
+
1924
+            avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1925
+                         sfilename, stream->filename);
1926
+            avio_printf(pb, "<td align=right> %d <td align=right> ",
1927
+                        stream->conns_served);
1928
+            fmt_bytecount(pb, stream->bytes_served);
1929
+            switch(stream->stream_type) {
1930
+            case STREAM_TYPE_LIVE: {
1931
+                    int audio_bit_rate = 0;
1932
+                    int video_bit_rate = 0;
1933
+                    const char *audio_codec_name = "";
1934
+                    const char *video_codec_name = "";
1935
+                    const char *audio_codec_name_extra = "";
1936
+                    const char *video_codec_name_extra = "";
1937
+
1938
+                    for(i=0;i<stream->nb_streams;i++) {
1939
+                        AVStream *st = stream->streams[i];
1940
+                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1941
+                        switch(st->codec->codec_type) {
1942
+                        case AVMEDIA_TYPE_AUDIO:
1943
+                            audio_bit_rate += st->codec->bit_rate;
1944
+                            if (codec) {
1945
+                                if (*audio_codec_name)
1946
+                                    audio_codec_name_extra = "...";
1947
+                                audio_codec_name = codec->name;
1948
+                            }
1949
+                            break;
1950
+                        case AVMEDIA_TYPE_VIDEO:
1951
+                            video_bit_rate += st->codec->bit_rate;
1952
+                            if (codec) {
1953
+                                if (*video_codec_name)
1954
+                                    video_codec_name_extra = "...";
1955
+                                video_codec_name = codec->name;
1956
+                            }
1957
+                            break;
1958
+                        case AVMEDIA_TYPE_DATA:
1959
+                            video_bit_rate += st->codec->bit_rate;
1960
+                            break;
1961
+                        default:
1962
+                            abort();
1963
+                        }
1964
+                    }
1965
+                    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",
1966
+                                 stream->fmt->name,
1967
+                                 stream->bandwidth,
1968
+                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1969
+                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1970
+                    if (stream->feed)
1971
+                        avio_printf(pb, "<td>%s", stream->feed->filename);
1972
+                    else
1973
+                        avio_printf(pb, "<td>%s", stream->feed_filename);
1974
+                    avio_printf(pb, "\n");
1975
+                }
1976
+                break;
1977
+            default:
1978
+                avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1979
+                break;
1980
+            }
1981
+        }
1982
+        stream = stream->next;
1983
+    }
1984
+    avio_printf(pb, "</table>\n");
1985
+
1986
+    stream = first_stream;
1987
+    while (stream != NULL) {
1988
+        if (stream->feed == stream) {
1989
+            avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1990
+            if (stream->pid) {
1991
+                avio_printf(pb, "Running as pid %d.\n", stream->pid);
1992
+
1993
+#if defined(linux) && !defined(CONFIG_NOCUTILS)
1994
+                {
1995
+                    FILE *pid_stat;
1996
+                    char ps_cmd[64];
1997
+
1998
+                    /* This is somewhat linux specific I guess */
1999
+                    snprintf(ps_cmd, sizeof(ps_cmd),
2000
+                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2001
+                             stream->pid);
2002
+
2003
+                    pid_stat = popen(ps_cmd, "r");
2004
+                    if (pid_stat) {
2005
+                        char cpuperc[10];
2006
+                        char cpuused[64];
2007
+
2008
+                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
2009
+                                   cpuused) == 2) {
2010
+                            avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2011
+                                         cpuperc, cpuused);
2012
+                        }
2013
+                        fclose(pid_stat);
2014
+                    }
2015
+                }
2016
+#endif
2017
+
2018
+                avio_printf(pb, "<p>");
2019
+            }
2020
+            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");
2021
+
2022
+            for (i = 0; i < stream->nb_streams; i++) {
2023
+                AVStream *st = stream->streams[i];
2024
+                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2025
+                const char *type = "unknown";
2026
+                char parameters[64];
2027
+
2028
+                parameters[0] = 0;
2029
+
2030
+                switch(st->codec->codec_type) {
2031
+                case AVMEDIA_TYPE_AUDIO:
2032
+                    type = "audio";
2033
+                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2034
+                    break;
2035
+                case AVMEDIA_TYPE_VIDEO:
2036
+                    type = "video";
2037
+                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2038
+                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2039
+                    break;
2040
+                default:
2041
+                    abort();
2042
+                }
2043
+                avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2044
+                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2045
+            }
2046
+            avio_printf(pb, "</table>\n");
2047
+
2048
+        }
2049
+        stream = stream->next;
2050
+    }
2051
+
2052
+    /* connection status */
2053
+    avio_printf(pb, "<h2>Connection Status</h2>\n");
2054
+
2055
+    avio_printf(pb, "Number of connections: %d / %d<br>\n",
2056
+                 nb_connections, nb_max_connections);
2057
+
2058
+    avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2059
+                 current_bandwidth, max_bandwidth);
2060
+
2061
+    avio_printf(pb, "<table>\n");
2062
+    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");
2063
+    c1 = first_http_ctx;
2064
+    i = 0;
2065
+    while (c1 != NULL) {
2066
+        int bitrate;
2067
+        int j;
2068
+
2069
+        bitrate = 0;
2070
+        if (c1->stream) {
2071
+            for (j = 0; j < c1->stream->nb_streams; j++) {
2072
+                if (!c1->stream->feed)
2073
+                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2074
+                else if (c1->feed_streams[j] >= 0)
2075
+                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2076
+            }
2077
+        }
2078
+
2079
+        i++;
2080
+        p = inet_ntoa(c1->from_addr.sin_addr);
2081
+        avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2082
+                    i,
2083
+                    c1->stream ? c1->stream->filename : "",
2084
+                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2085
+                    p,
2086
+                    c1->protocol,
2087
+                    http_state[c1->state]);
2088
+        fmt_bytecount(pb, bitrate);
2089
+        avio_printf(pb, "<td align=right>");
2090
+        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2091
+        avio_printf(pb, "<td align=right>");
2092
+        fmt_bytecount(pb, c1->data_count);
2093
+        avio_printf(pb, "\n");
2094
+        c1 = c1->next;
2095
+    }
2096
+    avio_printf(pb, "</table>\n");
2097
+
2098
+    /* date */
2099
+    ti = time(NULL);
2100
+    p = ctime(&ti);
2101
+    avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2102
+    avio_printf(pb, "</body>\n</html>\n");
2103
+
2104
+    len = avio_close_dyn_buf(pb, &c->pb_buffer);
2105
+    c->buffer_ptr = c->pb_buffer;
2106
+    c->buffer_end = c->pb_buffer + len;
2107
+}
2108
+
2109
+/* check if the parser needs to be opened for stream i */
2110
+static void open_parser(AVFormatContext *s, int i)
2111
+{
2112
+    AVStream *st = s->streams[i];
2113
+    AVCodec *codec;
2114
+
2115
+    if (!st->codec->codec) {
2116
+        codec = avcodec_find_decoder(st->codec->codec_id);
2117
+        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2118
+            st->codec->parse_only = 1;
2119
+            if (avcodec_open2(st->codec, codec, NULL) < 0)
2120
+                st->codec->parse_only = 0;
2121
+        }
2122
+    }
2123
+}
2124
+
2125
+static int open_input_stream(HTTPContext *c, const char *info)
2126
+{
2127
+    char buf[128];
2128
+    char input_filename[1024];
2129
+    AVFormatContext *s = NULL;
2130
+    int i, ret;
2131
+    int64_t stream_pos;
2132
+
2133
+    /* find file name */
2134
+    if (c->stream->feed) {
2135
+        strcpy(input_filename, c->stream->feed->feed_filename);
2136
+        /* compute position (absolute time) */
2137
+        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2138
+            if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2139
+                return ret;
2140
+        } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2141
+            int prebuffer = strtol(buf, 0, 10);
2142
+            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2143
+        } else
2144
+            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2145
+    } else {
2146
+        strcpy(input_filename, c->stream->feed_filename);
2147
+        /* compute position (relative time) */
2148
+        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2149
+            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2150
+                return ret;
2151
+        } else
2152
+            stream_pos = 0;
2153
+    }
2154
+    if (input_filename[0] == '\0')
2155
+        return -1;
2156
+
2157
+    /* open stream */
2158
+    if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2159
+        http_log("could not open %s: %d\n", input_filename, ret);
2160
+        return -1;
2161
+    }
2162
+    s->flags |= AVFMT_FLAG_GENPTS;
2163
+    c->fmt_in = s;
2164
+    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2165
+        http_log("Could not find stream info '%s'\n", input_filename);
2166
+        av_close_input_file(s);
2167
+        return -1;
2168
+    }
2169
+
2170
+    /* open each parser */
2171
+    for(i=0;i<s->nb_streams;i++)
2172
+        open_parser(s, i);
2173
+
2174
+    /* choose stream as clock source (we favorize video stream if
2175
+       present) for packet sending */
2176
+    c->pts_stream_index = 0;
2177
+    for(i=0;i<c->stream->nb_streams;i++) {
2178
+        if (c->pts_stream_index == 0 &&
2179
+            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2180
+            c->pts_stream_index = i;
2181
+        }
2182
+    }
2183
+
2184
+    if (c->fmt_in->iformat->read_seek)
2185
+        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2186
+    /* set the start time (needed for maxtime and RTP packet timing) */
2187
+    c->start_time = cur_time;
2188
+    c->first_pts = AV_NOPTS_VALUE;
2189
+    return 0;
2190
+}
2191
+
2192
+/* return the server clock (in us) */
2193
+static int64_t get_server_clock(HTTPContext *c)
2194
+{
2195
+    /* compute current pts value from system time */
2196
+    return (cur_time - c->start_time) * 1000;
2197
+}
2198
+
2199
+/* return the estimated time at which the current packet must be sent
2200
+   (in us) */
2201
+static int64_t get_packet_send_clock(HTTPContext *c)
2202
+{
2203
+    int bytes_left, bytes_sent, frame_bytes;
2204
+
2205
+    frame_bytes = c->cur_frame_bytes;
2206
+    if (frame_bytes <= 0)
2207
+        return c->cur_pts;
2208
+    else {
2209
+        bytes_left = c->buffer_end - c->buffer_ptr;
2210
+        bytes_sent = frame_bytes - bytes_left;
2211
+        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2212
+    }
2213
+}
2214
+
2215
+
2216
+static int http_prepare_data(HTTPContext *c)
2217
+{
2218
+    int i, len, ret;
2219
+    AVFormatContext *ctx;
2220
+
2221
+    av_freep(&c->pb_buffer);
2222
+    switch(c->state) {
2223
+    case HTTPSTATE_SEND_DATA_HEADER:
2224
+        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2225
+        av_dict_set(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2226
+        av_dict_set(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2227
+        av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2228
+        av_dict_set(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
2229
+
2230
+        c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2231
+
2232
+        for(i=0;i<c->stream->nb_streams;i++) {
2233
+            AVStream *src;
2234
+            c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2235
+            /* if file or feed, then just take streams from FFStream struct */
2236
+            if (!c->stream->feed ||
2237
+                c->stream->feed == c->stream)
2238
+                src = c->stream->streams[i];
2239
+            else
2240
+                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2241
+
2242
+            *(c->fmt_ctx.streams[i]) = *src;
2243
+            c->fmt_ctx.streams[i]->priv_data = 0;
2244
+            c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2245
+                                           AVStream, not in codec */
2246
+        }
2247
+        /* set output format parameters */
2248
+        c->fmt_ctx.oformat = c->stream->fmt;
2249
+        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2250
+
2251
+        c->got_key_frame = 0;
2252
+
2253
+        /* prepare header and save header data in a stream */
2254
+        if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2255
+            /* XXX: potential leak */
2256
+            return -1;
2257
+        }
2258
+        c->fmt_ctx.pb->seekable = 0;
2259
+
2260
+        /*
2261
+         * HACK to avoid mpeg ps muxer to spit many underflow errors
2262
+         * Default value from Libav
2263
+         * Try to set it use configuration option
2264
+         */
2265
+        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2266
+        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2267
+
2268
+        if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2269
+            http_log("Error writing output header\n");
2270
+            return -1;
2271
+        }
2272
+        av_dict_free(&c->fmt_ctx.metadata);
2273
+
2274
+        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2275
+        c->buffer_ptr = c->pb_buffer;
2276
+        c->buffer_end = c->pb_buffer + len;
2277
+
2278
+        c->state = HTTPSTATE_SEND_DATA;
2279
+        c->last_packet_sent = 0;
2280
+        break;
2281
+    case HTTPSTATE_SEND_DATA:
2282
+        /* find a new packet */
2283
+        /* read a packet from the input stream */
2284
+        if (c->stream->feed)
2285
+            ffm_set_write_index(c->fmt_in,
2286
+                                c->stream->feed->feed_write_index,
2287
+                                c->stream->feed->feed_size);
2288
+
2289
+        if (c->stream->max_time &&
2290
+            c->stream->max_time + c->start_time - cur_time < 0)
2291
+            /* We have timed out */
2292
+            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2293
+        else {
2294
+            AVPacket pkt;
2295
+        redo:
2296
+            ret = av_read_frame(c->fmt_in, &pkt);
2297
+            if (ret < 0) {
2298
+                if (c->stream->feed) {
2299
+                    /* if coming from feed, it means we reached the end of the
2300
+                       ffm file, so must wait for more data */
2301
+                    c->state = HTTPSTATE_WAIT_FEED;
2302
+                    return 1; /* state changed */
2303
+                } else if (ret == AVERROR(EAGAIN)) {
2304
+                    /* input not ready, come back later */
2305
+                    return 0;
2306
+                } else {
2307
+                    if (c->stream->loop) {
2308
+                        av_close_input_file(c->fmt_in);
2309
+                        c->fmt_in = NULL;
2310
+                        if (open_input_stream(c, "") < 0)
2311
+                            goto no_loop;
2312
+                        goto redo;
2313
+                    } else {
2314
+                    no_loop:
2315
+                        /* must send trailer now because eof or error */
2316
+                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2317
+                    }
2318
+                }
2319
+            } else {
2320
+                int source_index = pkt.stream_index;
2321
+                /* update first pts if needed */
2322
+                if (c->first_pts == AV_NOPTS_VALUE) {
2323
+                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2324
+                    c->start_time = cur_time;
2325
+                }
2326
+                /* send it to the appropriate stream */
2327
+                if (c->stream->feed) {
2328
+                    /* if coming from a feed, select the right stream */
2329
+                    if (c->switch_pending) {
2330
+                        c->switch_pending = 0;
2331
+                        for(i=0;i<c->stream->nb_streams;i++) {
2332
+                            if (c->switch_feed_streams[i] == pkt.stream_index)
2333
+                                if (pkt.flags & AV_PKT_FLAG_KEY)
2334
+                                    c->switch_feed_streams[i] = -1;
2335
+                            if (c->switch_feed_streams[i] >= 0)
2336
+                                c->switch_pending = 1;
2337
+                        }
2338
+                    }
2339
+                    for(i=0;i<c->stream->nb_streams;i++) {
2340
+                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2341
+                            AVStream *st = c->fmt_in->streams[source_index];
2342
+                            pkt.stream_index = i;
2343
+                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2344
+                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2345
+                                 c->stream->nb_streams == 1))
2346
+                                c->got_key_frame = 1;
2347
+                            if (!c->stream->send_on_key || c->got_key_frame)
2348
+                                goto send_it;
2349
+                        }
2350
+                    }
2351
+                } else {
2352
+                    AVCodecContext *codec;
2353
+                    AVStream *ist, *ost;
2354
+                send_it:
2355
+                    ist = c->fmt_in->streams[source_index];
2356
+                    /* specific handling for RTP: we use several
2357
+                       output stream (one for each RTP
2358
+                       connection). XXX: need more abstract handling */
2359
+                    if (c->is_packetized) {
2360
+                        /* compute send time and duration */
2361
+                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2362
+                        c->cur_pts -= c->first_pts;
2363
+                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2364
+                        /* find RTP context */
2365
+                        c->packet_stream_index = pkt.stream_index;
2366
+                        ctx = c->rtp_ctx[c->packet_stream_index];
2367
+                        if(!ctx) {
2368
+                            av_free_packet(&pkt);
2369
+                            break;
2370
+                        }
2371
+                        codec = ctx->streams[0]->codec;
2372
+                        /* only one stream per RTP connection */
2373
+                        pkt.stream_index = 0;
2374
+                    } else {
2375
+                        ctx = &c->fmt_ctx;
2376
+                        /* Fudge here */
2377
+                        codec = ctx->streams[pkt.stream_index]->codec;
2378
+                    }
2379
+
2380
+                    if (c->is_packetized) {
2381
+                        int max_packet_size;
2382
+                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2383
+                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2384
+                        else
2385
+                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2386
+                        ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2387
+                    } else {
2388
+                        ret = avio_open_dyn_buf(&ctx->pb);
2389
+                    }
2390
+                    if (ret < 0) {
2391
+                        /* XXX: potential leak */
2392
+                        return -1;
2393
+                    }
2394
+                    ost = ctx->streams[pkt.stream_index];
2395
+
2396
+                    ctx->pb->seekable = 0;
2397
+                    if (pkt.dts != AV_NOPTS_VALUE)
2398
+                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2399
+                    if (pkt.pts != AV_NOPTS_VALUE)
2400
+                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2401
+                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2402
+                    if (av_write_frame(ctx, &pkt) < 0) {
2403
+                        http_log("Error writing frame to output\n");
2404
+                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2405
+                    }
2406
+
2407
+                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2408
+                    c->cur_frame_bytes = len;
2409
+                    c->buffer_ptr = c->pb_buffer;
2410
+                    c->buffer_end = c->pb_buffer + len;
2411
+
2412
+                    codec->frame_number++;
2413
+                    if (len == 0) {
2414
+                        av_free_packet(&pkt);
2415
+                        goto redo;
2416
+                    }
2417
+                }
2418
+                av_free_packet(&pkt);
2419
+            }
2420
+        }
2421
+        break;
2422
+    default:
2423
+    case HTTPSTATE_SEND_DATA_TRAILER:
2424
+        /* last packet test ? */
2425
+        if (c->last_packet_sent || c->is_packetized)
2426
+            return -1;
2427
+        ctx = &c->fmt_ctx;
2428
+        /* prepare header */
2429
+        if (avio_open_dyn_buf(&ctx->pb) < 0) {
2430
+            /* XXX: potential leak */
2431
+            return -1;
2432
+        }
2433
+        c->fmt_ctx.pb->seekable = 0;
2434
+        av_write_trailer(ctx);
2435
+        len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2436
+        c->buffer_ptr = c->pb_buffer;
2437
+        c->buffer_end = c->pb_buffer + len;
2438
+
2439
+        c->last_packet_sent = 1;
2440
+        break;
2441
+    }
2442
+    return 0;
2443
+}
2444
+
2445
+/* should convert the format at the same time */
2446
+/* send data starting at c->buffer_ptr to the output connection
2447
+   (either UDP or TCP connection) */
2448
+static int http_send_data(HTTPContext *c)
2449
+{
2450
+    int len, ret;
2451
+
2452
+    for(;;) {
2453
+        if (c->buffer_ptr >= c->buffer_end) {
2454
+            ret = http_prepare_data(c);
2455
+            if (ret < 0)
2456
+                return -1;
2457
+            else if (ret != 0)
2458
+                /* state change requested */
2459
+                break;
2460
+        } else {
2461
+            if (c->is_packetized) {
2462
+                /* RTP data output */
2463
+                len = c->buffer_end - c->buffer_ptr;
2464
+                if (len < 4) {
2465
+                    /* fail safe - should never happen */
2466
+                fail1:
2467
+                    c->buffer_ptr = c->buffer_end;
2468
+                    return 0;
2469
+                }
2470
+                len = (c->buffer_ptr[0] << 24) |
2471
+                    (c->buffer_ptr[1] << 16) |
2472
+                    (c->buffer_ptr[2] << 8) |
2473
+                    (c->buffer_ptr[3]);
2474
+                if (len > (c->buffer_end - c->buffer_ptr))
2475
+                    goto fail1;
2476
+                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2477
+                    /* nothing to send yet: we can wait */
2478
+                    return 0;
2479
+                }
2480
+
2481
+                c->data_count += len;
2482
+                update_datarate(&c->datarate, c->data_count);
2483
+                if (c->stream)
2484
+                    c->stream->bytes_served += len;
2485
+
2486
+                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2487
+                    /* RTP packets are sent inside the RTSP TCP connection */
2488
+                    AVIOContext *pb;
2489
+                    int interleaved_index, size;
2490
+                    uint8_t header[4];
2491
+                    HTTPContext *rtsp_c;
2492
+
2493
+                    rtsp_c = c->rtsp_c;
2494
+                    /* if no RTSP connection left, error */
2495
+                    if (!rtsp_c)
2496
+                        return -1;
2497
+                    /* if already sending something, then wait. */
2498
+                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2499
+                        break;
2500
+                    if (avio_open_dyn_buf(&pb) < 0)
2501
+                        goto fail1;
2502
+                    interleaved_index = c->packet_stream_index * 2;
2503
+                    /* RTCP packets are sent at odd indexes */
2504
+                    if (c->buffer_ptr[1] == 200)
2505
+                        interleaved_index++;
2506
+                    /* write RTSP TCP header */
2507
+                    header[0] = '$';
2508
+                    header[1] = interleaved_index;
2509
+                    header[2] = len >> 8;
2510
+                    header[3] = len;
2511
+                    avio_write(pb, header, 4);
2512
+                    /* write RTP packet data */
2513
+                    c->buffer_ptr += 4;
2514
+                    avio_write(pb, c->buffer_ptr, len);
2515
+                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
2516
+                    /* prepare asynchronous TCP sending */
2517
+                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2518
+                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2519
+                    c->buffer_ptr += len;
2520
+
2521
+                    /* send everything we can NOW */
2522
+                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2523
+                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2524
+                    if (len > 0)
2525
+                        rtsp_c->packet_buffer_ptr += len;
2526
+                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2527
+                        /* if we could not send all the data, we will
2528
+                           send it later, so a new state is needed to
2529
+                           "lock" the RTSP TCP connection */
2530
+                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2531
+                        break;
2532
+                    } else
2533
+                        /* all data has been sent */
2534
+                        av_freep(&c->packet_buffer);
2535
+                } else {
2536
+                    /* send RTP packet directly in UDP */
2537
+                    c->buffer_ptr += 4;
2538
+                    url_write(c->rtp_handles[c->packet_stream_index],
2539
+                              c->buffer_ptr, len);
2540
+                    c->buffer_ptr += len;
2541
+                    /* here we continue as we can send several packets per 10 ms slot */
2542
+                }
2543
+            } else {
2544
+                /* TCP data output */
2545
+                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2546
+                if (len < 0) {
2547
+                    if (ff_neterrno() != AVERROR(EAGAIN) &&
2548
+                        ff_neterrno() != AVERROR(EINTR))
2549
+                        /* error : close connection */
2550
+                        return -1;
2551
+                    else
2552
+                        return 0;
2553
+                } else
2554
+                    c->buffer_ptr += len;
2555
+
2556
+                c->data_count += len;
2557
+                update_datarate(&c->datarate, c->data_count);
2558
+                if (c->stream)
2559
+                    c->stream->bytes_served += len;
2560
+                break;
2561
+            }
2562
+        }
2563
+    } /* for(;;) */
2564
+    return 0;
2565
+}
2566
+
2567
+static int http_start_receive_data(HTTPContext *c)
2568
+{
2569
+    int fd;
2570
+
2571
+    if (c->stream->feed_opened)
2572
+        return -1;
2573
+
2574
+    /* Don't permit writing to this one */
2575
+    if (c->stream->readonly)
2576
+        return -1;
2577
+
2578
+    /* open feed */
2579
+    fd = open(c->stream->feed_filename, O_RDWR);
2580
+    if (fd < 0) {
2581
+        http_log("Error opening feeder file: %s\n", strerror(errno));
2582
+        return -1;
2583
+    }
2584
+    c->feed_fd = fd;
2585
+
2586
+    if (c->stream->truncate) {
2587
+        /* truncate feed file */
2588
+        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2589
+        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2590
+        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2591
+    } else {
2592
+        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2593
+            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2594
+            return -1;
2595
+        }
2596
+    }
2597
+
2598
+    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2599
+    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2600
+    lseek(fd, 0, SEEK_SET);
2601
+
2602
+    /* init buffer input */
2603
+    c->buffer_ptr = c->buffer;
2604
+    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2605
+    c->stream->feed_opened = 1;
2606
+    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2607
+    return 0;
2608
+}
2609
+
2610
+static int http_receive_data(HTTPContext *c)
2611
+{
2612
+    HTTPContext *c1;
2613
+    int len, loop_run = 0;
2614
+
2615
+    while (c->chunked_encoding && !c->chunk_size &&
2616
+           c->buffer_end > c->buffer_ptr) {
2617
+        /* read chunk header, if present */
2618
+        len = recv(c->fd, c->buffer_ptr, 1, 0);
2619
+
2620
+        if (len < 0) {
2621
+            if (ff_neterrno() != AVERROR(EAGAIN) &&
2622
+                ff_neterrno() != AVERROR(EINTR))
2623
+                /* error : close connection */
2624
+                goto fail;
2625
+            return 0;
2626
+        } else if (len == 0) {
2627
+            /* end of connection : close it */
2628
+            goto fail;
2629
+        } else if (c->buffer_ptr - c->buffer >= 2 &&
2630
+                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2631
+            c->chunk_size = strtol(c->buffer, 0, 16);
2632
+            if (c->chunk_size == 0) // end of stream
2633
+                goto fail;
2634
+            c->buffer_ptr = c->buffer;
2635
+            break;
2636
+        } else if (++loop_run > 10) {
2637
+            /* no chunk header, abort */
2638
+            goto fail;
2639
+        } else {
2640
+            c->buffer_ptr++;
2641
+        }
2642
+    }
2643
+
2644
+    if (c->buffer_end > c->buffer_ptr) {
2645
+        len = recv(c->fd, c->buffer_ptr,
2646
+                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2647
+        if (len < 0) {
2648
+            if (ff_neterrno() != AVERROR(EAGAIN) &&
2649
+                ff_neterrno() != AVERROR(EINTR))
2650
+                /* error : close connection */
2651
+                goto fail;
2652
+        } else if (len == 0)
2653
+            /* end of connection : close it */
2654
+            goto fail;
2655
+        else {
2656
+            c->chunk_size -= len;
2657
+            c->buffer_ptr += len;
2658
+            c->data_count += len;
2659
+            update_datarate(&c->datarate, c->data_count);
2660
+        }
2661
+    }
2662
+
2663
+    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2664
+        if (c->buffer[0] != 'f' ||
2665
+            c->buffer[1] != 'm') {
2666
+            http_log("Feed stream has become desynchronized -- disconnecting\n");
2667
+            goto fail;
2668
+        }
2669
+    }
2670
+
2671
+    if (c->buffer_ptr >= c->buffer_end) {
2672
+        FFStream *feed = c->stream;
2673
+        /* a packet has been received : write it in the store, except
2674
+           if header */
2675
+        if (c->data_count > FFM_PACKET_SIZE) {
2676
+
2677
+            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2678
+            /* XXX: use llseek or url_seek */
2679
+            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2680
+            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2681
+                http_log("Error writing to feed file: %s\n", strerror(errno));
2682
+                goto fail;
2683
+            }
2684
+
2685
+            feed->feed_write_index += FFM_PACKET_SIZE;
2686
+            /* update file size */
2687
+            if (feed->feed_write_index > c->stream->feed_size)
2688
+                feed->feed_size = feed->feed_write_index;
2689
+
2690
+            /* handle wrap around if max file size reached */
2691
+            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2692
+                feed->feed_write_index = FFM_PACKET_SIZE;
2693
+
2694
+            /* write index */
2695
+            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2696
+                http_log("Error writing index to feed file: %s\n", strerror(errno));
2697
+                goto fail;
2698
+            }
2699
+
2700
+            /* wake up any waiting connections */
2701
+            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2702
+                if (c1->state == HTTPSTATE_WAIT_FEED &&
2703
+                    c1->stream->feed == c->stream->feed)
2704
+                    c1->state = HTTPSTATE_SEND_DATA;
2705
+            }
2706
+        } else {
2707
+            /* We have a header in our hands that contains useful data */
2708
+            AVFormatContext *s = avformat_alloc_context();
2709
+            AVIOContext *pb;
2710
+            AVInputFormat *fmt_in;
2711
+            int i;
2712
+
2713
+            if (!s)
2714
+                goto fail;
2715
+
2716
+            /* use feed output format name to find corresponding input format */
2717
+            fmt_in = av_find_input_format(feed->fmt->name);
2718
+            if (!fmt_in)
2719
+                goto fail;
2720
+
2721
+            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2722
+                                    0, NULL, NULL, NULL, NULL);
2723
+            pb->seekable = 0;
2724
+
2725
+            s->pb = pb;
2726
+            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2727
+                av_free(pb);
2728
+                goto fail;
2729
+            }
2730
+
2731
+            /* Now we have the actual streams */
2732
+            if (s->nb_streams != feed->nb_streams) {
2733
+                av_close_input_stream(s);
2734
+                av_free(pb);
2735
+                http_log("Feed '%s' stream number does not match registered feed\n",
2736
+                         c->stream->feed_filename);
2737
+                goto fail;
2738
+            }
2739
+
2740
+            for (i = 0; i < s->nb_streams; i++) {
2741
+                AVStream *fst = feed->streams[i];
2742
+                AVStream *st = s->streams[i];
2743
+                avcodec_copy_context(fst->codec, st->codec);
2744
+            }
2745
+
2746
+            av_close_input_stream(s);
2747
+            av_free(pb);
2748
+        }
2749
+        c->buffer_ptr = c->buffer;
2750
+    }
2751
+
2752
+    return 0;
2753
+ fail:
2754
+    c->stream->feed_opened = 0;
2755
+    close(c->feed_fd);
2756
+    /* wake up any waiting connections to stop waiting for feed */
2757
+    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2758
+        if (c1->state == HTTPSTATE_WAIT_FEED &&
2759
+            c1->stream->feed == c->stream->feed)
2760
+            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2761
+    }
2762
+    return -1;
2763
+}
2764
+
2765
+/********************************************************************/
2766
+/* RTSP handling */
2767
+
2768
+static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2769
+{
2770
+    const char *str;
2771
+    time_t ti;
2772
+    struct tm *tm;
2773
+    char buf2[32];
2774
+
2775
+    switch(error_number) {
2776
+    case RTSP_STATUS_OK:
2777
+        str = "OK";
2778
+        break;
2779
+    case RTSP_STATUS_METHOD:
2780
+        str = "Method Not Allowed";
2781
+        break;
2782
+    case RTSP_STATUS_BANDWIDTH:
2783
+        str = "Not Enough Bandwidth";
2784
+        break;
2785
+    case RTSP_STATUS_SESSION:
2786
+        str = "Session Not Found";
2787
+        break;
2788
+    case RTSP_STATUS_STATE:
2789
+        str = "Method Not Valid in This State";
2790
+        break;
2791
+    case RTSP_STATUS_AGGREGATE:
2792
+        str = "Aggregate operation not allowed";
2793
+        break;
2794
+    case RTSP_STATUS_ONLY_AGGREGATE:
2795
+        str = "Only aggregate operation allowed";
2796
+        break;
2797
+    case RTSP_STATUS_TRANSPORT:
2798
+        str = "Unsupported transport";
2799
+        break;
2800
+    case RTSP_STATUS_INTERNAL:
2801
+        str = "Internal Server Error";
2802
+        break;
2803
+    case RTSP_STATUS_SERVICE:
2804
+        str = "Service Unavailable";
2805
+        break;
2806
+    case RTSP_STATUS_VERSION:
2807
+        str = "RTSP Version not supported";
2808
+        break;
2809
+    default:
2810
+        str = "Unknown Error";
2811
+        break;
2812
+    }
2813
+
2814
+    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2815
+    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2816
+
2817
+    /* output GMT time */
2818
+    ti = time(NULL);
2819
+    tm = gmtime(&ti);
2820
+    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2821
+    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2822
+}
2823
+
2824
+static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2825
+{
2826
+    rtsp_reply_header(c, error_number);
2827
+    avio_printf(c->pb, "\r\n");
2828
+}
2829
+
2830
+static int rtsp_parse_request(HTTPContext *c)
2831
+{
2832
+    const char *p, *p1, *p2;
2833
+    char cmd[32];
2834
+    char url[1024];
2835
+    char protocol[32];
2836
+    char line[1024];
2837
+    int len;
2838
+    RTSPMessageHeader header1, *header = &header1;
2839
+
2840
+    c->buffer_ptr[0] = '\0';
2841
+    p = c->buffer;
2842
+
2843
+    get_word(cmd, sizeof(cmd), &p);
2844
+    get_word(url, sizeof(url), &p);
2845
+    get_word(protocol, sizeof(protocol), &p);
2846
+
2847
+    av_strlcpy(c->method, cmd, sizeof(c->method));
2848
+    av_strlcpy(c->url, url, sizeof(c->url));
2849
+    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2850
+
2851
+    if (avio_open_dyn_buf(&c->pb) < 0) {
2852
+        /* XXX: cannot do more */
2853
+        c->pb = NULL; /* safety */
2854
+        return -1;
2855
+    }
2856
+
2857
+    /* check version name */
2858
+    if (strcmp(protocol, "RTSP/1.0") != 0) {
2859
+        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2860
+        goto the_end;
2861
+    }
2862
+
2863
+    /* parse each header line */
2864
+    memset(header, 0, sizeof(*header));
2865
+    /* skip to next line */
2866
+    while (*p != '\n' && *p != '\0')
2867
+        p++;
2868
+    if (*p == '\n')
2869
+        p++;
2870
+    while (*p != '\0') {
2871
+        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2872
+        if (!p1)
2873
+            break;
2874
+        p2 = p1;
2875
+        if (p2 > p && p2[-1] == '\r')
2876
+            p2--;
2877
+        /* skip empty line */
2878
+        if (p2 == p)
2879
+            break;
2880
+        len = p2 - p;
2881
+        if (len > sizeof(line) - 1)
2882
+            len = sizeof(line) - 1;
2883
+        memcpy(line, p, len);
2884
+        line[len] = '\0';
2885
+        ff_rtsp_parse_line(header, line, NULL, NULL);
2886
+        p = p1 + 1;
2887
+    }
2888
+
2889
+    /* handle sequence number */
2890
+    c->seq = header->seq;
2891
+
2892
+    if (!strcmp(cmd, "DESCRIBE"))
2893
+        rtsp_cmd_describe(c, url);
2894
+    else if (!strcmp(cmd, "OPTIONS"))
2895
+        rtsp_cmd_options(c, url);
2896
+    else if (!strcmp(cmd, "SETUP"))
2897
+        rtsp_cmd_setup(c, url, header);
2898
+    else if (!strcmp(cmd, "PLAY"))
2899
+        rtsp_cmd_play(c, url, header);
2900
+    else if (!strcmp(cmd, "PAUSE"))
2901
+        rtsp_cmd_pause(c, url, header);
2902
+    else if (!strcmp(cmd, "TEARDOWN"))
2903
+        rtsp_cmd_teardown(c, url, header);
2904
+    else
2905
+        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2906
+
2907
+ the_end:
2908
+    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2909
+    c->pb = NULL; /* safety */
2910
+    if (len < 0) {
2911
+        /* XXX: cannot do more */
2912
+        return -1;
2913
+    }
2914
+    c->buffer_ptr = c->pb_buffer;
2915
+    c->buffer_end = c->pb_buffer + len;
2916
+    c->state = RTSPSTATE_SEND_REPLY;
2917
+    return 0;
2918
+}
2919
+
2920
+static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2921
+                                   struct in_addr my_ip)
2922
+{
2923
+    AVFormatContext *avc;
2924
+    AVStream *avs = NULL;
2925
+    int i;
2926
+
2927
+    avc =  avformat_alloc_context();
2928
+    if (avc == NULL) {
2929
+        return -1;
2930
+    }
2931
+    av_dict_set(&avc->metadata, "title",
2932
+               stream->title[0] ? stream->title : "No Title", 0);
2933
+    avc->nb_streams = stream->nb_streams;
2934
+    if (stream->is_multicast) {
2935
+        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2936
+                 inet_ntoa(stream->multicast_ip),
2937
+                 stream->multicast_port, stream->multicast_ttl);
2938
+    } else {
2939
+        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2940
+    }
2941
+
2942
+    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2943
+        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2944
+        goto sdp_done;
2945
+    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2946
+        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2947
+        goto sdp_done;
2948
+
2949
+    for(i = 0; i < stream->nb_streams; i++) {
2950
+        avc->streams[i] = &avs[i];
2951
+        avc->streams[i]->codec = stream->streams[i]->codec;
2952
+    }
2953
+    *pbuffer = av_mallocz(2048);
2954
+    av_sdp_create(&avc, 1, *pbuffer, 2048);
2955
+
2956
+ sdp_done:
2957
+    av_free(avc->streams);
2958
+    av_dict_free(&avc->metadata);
2959
+    av_free(avc);
2960
+    av_free(avs);
2961
+
2962
+    return strlen(*pbuffer);
2963
+}
2964
+
2965
+static void rtsp_cmd_options(HTTPContext *c, const char *url)
2966
+{
2967
+//    rtsp_reply_header(c, RTSP_STATUS_OK);
2968
+    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2969
+    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2970
+    avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2971
+    avio_printf(c->pb, "\r\n");
2972
+}
2973
+
2974
+static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2975
+{
2976
+    FFStream *stream;
2977
+    char path1[1024];
2978
+    const char *path;
2979
+    uint8_t *content;
2980
+    int content_length, len;
2981
+    struct sockaddr_in my_addr;
2982
+
2983
+    /* find which url is asked */
2984
+    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2985
+    path = path1;
2986
+    if (*path == '/')
2987
+        path++;
2988
+
2989
+    for(stream = first_stream; stream != NULL; stream = stream->next) {
2990
+        if (!stream->is_feed &&
2991
+            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2992
+            !strcmp(path, stream->filename)) {
2993
+            goto found;
2994
+        }
2995
+    }
2996
+    /* no stream found */
2997
+    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2998
+    return;
2999
+
3000
+ found:
3001
+    /* prepare the media description in sdp format */
3002
+
3003
+    /* get the host IP */
3004
+    len = sizeof(my_addr);
3005
+    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3006
+    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3007
+    if (content_length < 0) {
3008
+        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3009
+        return;
3010
+    }
3011
+    rtsp_reply_header(c, RTSP_STATUS_OK);
3012
+    avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3013
+    avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3014
+    avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3015
+    avio_printf(c->pb, "\r\n");
3016
+    avio_write(c->pb, content, content_length);
3017
+    av_free(content);
3018
+}
3019
+
3020
+static HTTPContext *find_rtp_session(const char *session_id)
3021
+{
3022
+    HTTPContext *c;
3023
+
3024
+    if (session_id[0] == '\0')
3025
+        return NULL;
3026
+
3027
+    for(c = first_http_ctx; c != NULL; c = c->next) {
3028
+        if (!strcmp(c->session_id, session_id))
3029
+            return c;
3030
+    }
3031
+    return NULL;
3032
+}
3033
+
3034
+static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3035
+{
3036
+    RTSPTransportField *th;
3037
+    int i;
3038
+
3039
+    for(i=0;i<h->nb_transports;i++) {
3040
+        th = &h->transports[i];
3041
+        if (th->lower_transport == lower_transport)
3042
+            return th;
3043
+    }
3044
+    return NULL;
3045
+}
3046
+
3047
+static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3048
+                           RTSPMessageHeader *h)
3049
+{
3050
+    FFStream *stream;
3051
+    int stream_index, rtp_port, rtcp_port;
3052
+    char buf[1024];
3053
+    char path1[1024];
3054
+    const char *path;
3055
+    HTTPContext *rtp_c;
3056
+    RTSPTransportField *th;
3057
+    struct sockaddr_in dest_addr;
3058
+    RTSPActionServerSetup setup;
3059
+
3060
+    /* find which url is asked */
3061
+    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3062
+    path = path1;
3063
+    if (*path == '/')
3064
+        path++;
3065
+
3066
+    /* now check each stream */
3067
+    for(stream = first_stream; stream != NULL; stream = stream->next) {
3068
+        if (!stream->is_feed &&
3069
+            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3070
+            /* accept aggregate filenames only if single stream */
3071
+            if (!strcmp(path, stream->filename)) {
3072
+                if (stream->nb_streams != 1) {
3073
+                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3074
+                    return;
3075
+                }
3076
+                stream_index = 0;
3077
+                goto found;
3078
+            }
3079
+
3080
+            for(stream_index = 0; stream_index < stream->nb_streams;
3081
+                stream_index++) {
3082
+                snprintf(buf, sizeof(buf), "%s/streamid=%d",
3083
+                         stream->filename, stream_index);
3084
+                if (!strcmp(path, buf))
3085
+                    goto found;
3086
+            }
3087
+        }
3088
+    }
3089
+    /* no stream found */
3090
+    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3091
+    return;
3092
+ found:
3093
+
3094
+    /* generate session id if needed */
3095
+    if (h->session_id[0] == '\0')
3096
+        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3097
+                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3098
+
3099
+    /* find rtp session, and create it if none found */
3100
+    rtp_c = find_rtp_session(h->session_id);
3101
+    if (!rtp_c) {
3102
+        /* always prefer UDP */
3103
+        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3104
+        if (!th) {
3105
+            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3106
+            if (!th) {
3107
+                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3108
+                return;
3109
+            }
3110
+        }
3111
+
3112
+        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3113
+                                   th->lower_transport);
3114
+        if (!rtp_c) {
3115
+            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3116
+            return;
3117
+        }
3118
+
3119
+        /* open input stream */
3120
+        if (open_input_stream(rtp_c, "") < 0) {
3121
+            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3122
+            return;
3123
+        }
3124
+    }
3125
+
3126
+    /* test if stream is OK (test needed because several SETUP needs
3127
+       to be done for a given file) */
3128
+    if (rtp_c->stream != stream) {
3129
+        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3130
+        return;
3131
+    }
3132
+
3133
+    /* test if stream is already set up */
3134
+    if (rtp_c->rtp_ctx[stream_index]) {
3135
+        rtsp_reply_error(c, RTSP_STATUS_STATE);
3136
+        return;
3137
+    }
3138
+
3139
+    /* check transport */
3140
+    th = find_transport(h, rtp_c->rtp_protocol);
3141
+    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3142
+                th->client_port_min <= 0)) {
3143
+        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3144
+        return;
3145
+    }
3146
+
3147
+    /* setup default options */
3148
+    setup.transport_option[0] = '\0';
3149
+    dest_addr = rtp_c->from_addr;
3150
+    dest_addr.sin_port = htons(th->client_port_min);
3151
+
3152
+    /* setup stream */
3153
+    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3154
+        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3155
+        return;
3156
+    }
3157
+
3158
+    /* now everything is OK, so we can send the connection parameters */
3159
+    rtsp_reply_header(c, RTSP_STATUS_OK);
3160
+    /* session ID */
3161
+    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3162
+
3163
+    switch(rtp_c->rtp_protocol) {
3164
+    case RTSP_LOWER_TRANSPORT_UDP:
3165
+        rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3166
+        rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3167
+        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3168
+                    "client_port=%d-%d;server_port=%d-%d",
3169
+                    th->client_port_min, th->client_port_max,
3170
+                    rtp_port, rtcp_port);
3171
+        break;
3172
+    case RTSP_LOWER_TRANSPORT_TCP:
3173
+        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3174
+                    stream_index * 2, stream_index * 2 + 1);
3175
+        break;
3176
+    default:
3177
+        break;
3178
+    }
3179
+    if (setup.transport_option[0] != '\0')
3180
+        avio_printf(c->pb, ";%s", setup.transport_option);
3181
+    avio_printf(c->pb, "\r\n");
3182
+
3183
+
3184
+    avio_printf(c->pb, "\r\n");
3185
+}
3186
+
3187
+
3188
+/* find an rtp connection by using the session ID. Check consistency
3189
+   with filename */
3190
+static HTTPContext *find_rtp_session_with_url(const char *url,
3191
+                                              const char *session_id)
3192
+{
3193
+    HTTPContext *rtp_c;
3194
+    char path1[1024];
3195
+    const char *path;
3196
+    char buf[1024];
3197
+    int s, len;
3198
+
3199
+    rtp_c = find_rtp_session(session_id);
3200
+    if (!rtp_c)
3201
+        return NULL;
3202
+
3203
+    /* find which url is asked */
3204
+    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3205
+    path = path1;
3206
+    if (*path == '/')
3207
+        path++;
3208
+    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3209
+    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3210
+      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3211
+        rtp_c->stream->filename, s);
3212
+      if(!strncmp(path, buf, sizeof(buf))) {
3213
+    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3214
+        return rtp_c;
3215
+      }
3216
+    }
3217
+    len = strlen(path);
3218
+    if (len > 0 && path[len - 1] == '/' &&
3219
+        !strncmp(path, rtp_c->stream->filename, len - 1))
3220
+        return rtp_c;
3221
+    return NULL;
3222
+}
3223
+
3224
+static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3225
+{
3226
+    HTTPContext *rtp_c;
3227
+
3228
+    rtp_c = find_rtp_session_with_url(url, h->session_id);
3229
+    if (!rtp_c) {
3230
+        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3231
+        return;
3232
+    }
3233
+
3234
+    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3235
+        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3236
+        rtp_c->state != HTTPSTATE_READY) {
3237
+        rtsp_reply_error(c, RTSP_STATUS_STATE);
3238
+        return;
3239
+    }
3240
+
3241
+    rtp_c->state = HTTPSTATE_SEND_DATA;
3242
+
3243
+    /* now everything is OK, so we can send the connection parameters */
3244
+    rtsp_reply_header(c, RTSP_STATUS_OK);
3245
+    /* session ID */
3246
+    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3247
+    avio_printf(c->pb, "\r\n");
3248
+}
3249
+
3250
+static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3251
+{
3252
+    HTTPContext *rtp_c;
3253
+
3254
+    rtp_c = find_rtp_session_with_url(url, h->session_id);
3255
+    if (!rtp_c) {
3256
+        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3257
+        return;
3258
+    }
3259
+
3260
+    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3261
+        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3262
+        rtsp_reply_error(c, RTSP_STATUS_STATE);
3263
+        return;
3264
+    }
3265
+
3266
+    rtp_c->state = HTTPSTATE_READY;
3267
+    rtp_c->first_pts = AV_NOPTS_VALUE;
3268
+    /* now everything is OK, so we can send the connection parameters */
3269
+    rtsp_reply_header(c, RTSP_STATUS_OK);
3270
+    /* session ID */
3271
+    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3272
+    avio_printf(c->pb, "\r\n");
3273
+}
3274
+
3275
+static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3276
+{
3277
+    HTTPContext *rtp_c;
3278
+
3279
+    rtp_c = find_rtp_session_with_url(url, h->session_id);
3280
+    if (!rtp_c) {
3281
+        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3282
+        return;
3283
+    }
3284
+
3285
+    /* now everything is OK, so we can send the connection parameters */
3286
+    rtsp_reply_header(c, RTSP_STATUS_OK);
3287
+    /* session ID */
3288
+    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3289
+    avio_printf(c->pb, "\r\n");
3290
+
3291
+    /* abort the session */
3292
+    close_connection(rtp_c);
3293
+}
3294
+
3295
+
3296
+/********************************************************************/
3297
+/* RTP handling */
3298
+
3299
+static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3300
+                                       FFStream *stream, const char *session_id,
3301
+                                       enum RTSPLowerTransport rtp_protocol)
3302
+{
3303
+    HTTPContext *c = NULL;
3304
+    const char *proto_str;
3305
+
3306
+    /* XXX: should output a warning page when coming
3307
+       close to the connection limit */
3308
+    if (nb_connections >= nb_max_connections)
3309
+        goto fail;
3310
+
3311
+    /* add a new connection */
3312
+    c = av_mallocz(sizeof(HTTPContext));
3313
+    if (!c)
3314
+        goto fail;
3315
+
3316
+    c->fd = -1;
3317
+    c->poll_entry = NULL;
3318
+    c->from_addr = *from_addr;
3319
+    c->buffer_size = IOBUFFER_INIT_SIZE;
3320
+    c->buffer = av_malloc(c->buffer_size);
3321
+    if (!c->buffer)
3322
+        goto fail;
3323
+    nb_connections++;
3324
+    c->stream = stream;
3325
+    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3326
+    c->state = HTTPSTATE_READY;
3327
+    c->is_packetized = 1;
3328
+    c->rtp_protocol = rtp_protocol;
3329
+
3330
+    /* protocol is shown in statistics */
3331
+    switch(c->rtp_protocol) {
3332
+    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3333
+        proto_str = "MCAST";
3334
+        break;
3335
+    case RTSP_LOWER_TRANSPORT_UDP:
3336
+        proto_str = "UDP";
3337
+        break;
3338
+    case RTSP_LOWER_TRANSPORT_TCP:
3339
+        proto_str = "TCP";
3340
+        break;
3341
+    default:
3342
+        proto_str = "???";
3343
+        break;
3344
+    }
3345
+    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3346
+    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3347
+
3348
+    current_bandwidth += stream->bandwidth;
3349
+
3350
+    c->next = first_http_ctx;
3351
+    first_http_ctx = c;
3352
+    return c;
3353
+
3354
+ fail:
3355
+    if (c) {
3356
+        av_free(c->buffer);
3357
+        av_free(c);
3358
+    }
3359
+    return NULL;
3360
+}
3361
+
3362
+/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3363
+   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3364
+   used. */
3365
+static int rtp_new_av_stream(HTTPContext *c,
3366
+                             int stream_index, struct sockaddr_in *dest_addr,
3367
+                             HTTPContext *rtsp_c)
3368
+{
3369
+    AVFormatContext *ctx;
3370
+    AVStream *st;
3371
+    char *ipaddr;
3372
+    URLContext *h = NULL;
3373
+    uint8_t *dummy_buf;
3374
+    int max_packet_size;
3375
+
3376
+    /* now we can open the relevant output stream */
3377
+    ctx = avformat_alloc_context();
3378
+    if (!ctx)
3379
+        return -1;
3380
+    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3381
+
3382
+    st = av_mallocz(sizeof(AVStream));
3383
+    if (!st)
3384
+        goto fail;
3385
+    ctx->nb_streams = 1;
3386
+    ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3387
+    if (!ctx->streams)
3388
+      goto fail;
3389
+    ctx->streams[0] = st;
3390
+
3391
+    if (!c->stream->feed ||
3392
+        c->stream->feed == c->stream)
3393
+        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3394
+    else
3395
+        memcpy(st,
3396
+               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3397
+               sizeof(AVStream));
3398
+    st->priv_data = NULL;
3399
+
3400
+    /* build destination RTP address */
3401
+    ipaddr = inet_ntoa(dest_addr->sin_addr);
3402
+
3403
+    switch(c->rtp_protocol) {
3404
+    case RTSP_LOWER_TRANSPORT_UDP:
3405
+    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3406
+        /* RTP/UDP case */
3407
+
3408
+        /* XXX: also pass as parameter to function ? */
3409
+        if (c->stream->is_multicast) {
3410
+            int ttl;
3411
+            ttl = c->stream->multicast_ttl;
3412
+            if (!ttl)
3413
+                ttl = 16;
3414
+            snprintf(ctx->filename, sizeof(ctx->filename),
3415
+                     "rtp://%s:%d?multicast=1&ttl=%d",
3416
+                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3417
+        } else {
3418
+            snprintf(ctx->filename, sizeof(ctx->filename),
3419
+                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3420
+        }
3421
+
3422
+        if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3423
+            goto fail;
3424
+        c->rtp_handles[stream_index] = h;
3425
+        max_packet_size = url_get_max_packet_size(h);
3426
+        break;
3427
+    case RTSP_LOWER_TRANSPORT_TCP:
3428
+        /* RTP/TCP case */
3429
+        c->rtsp_c = rtsp_c;
3430
+        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3431
+        break;
3432
+    default:
3433
+        goto fail;
3434
+    }
3435
+
3436
+    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3437
+             ipaddr, ntohs(dest_addr->sin_port),
3438
+             c->stream->filename, stream_index, c->protocol);
3439
+
3440
+    /* normally, no packets should be output here, but the packet size may be checked */
3441
+    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3442
+        /* XXX: close stream */
3443
+        goto fail;
3444
+    }
3445
+    if (avformat_write_header(ctx, NULL) < 0) {
3446
+    fail:
3447
+        if (h)
3448
+            url_close(h);
3449
+        av_free(ctx);
3450
+        return -1;
3451
+    }
3452
+    avio_close_dyn_buf(ctx->pb, &dummy_buf);
3453
+    av_free(dummy_buf);
3454
+
3455
+    c->rtp_ctx[stream_index] = ctx;
3456
+    return 0;
3457
+}
3458
+
3459
+/********************************************************************/
3460
+/* avserver initialization */
3461
+
3462
+static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3463
+{
3464
+    AVStream *fst;
3465
+
3466
+    fst = av_mallocz(sizeof(AVStream));
3467
+    if (!fst)
3468
+        return NULL;
3469
+    if (copy) {
3470
+        fst->codec = avcodec_alloc_context3(NULL);
3471
+        memcpy(fst->codec, codec, sizeof(AVCodecContext));
3472
+        if (codec->extradata_size) {
3473
+            fst->codec->extradata = av_malloc(codec->extradata_size);
3474
+            memcpy(fst->codec->extradata, codec->extradata,
3475
+                codec->extradata_size);
3476
+        }
3477
+    } else {
3478
+        /* live streams must use the actual feed's codec since it may be
3479
+         * updated later to carry extradata needed by the streams.
3480
+         */
3481
+        fst->codec = codec;
3482
+    }
3483
+    fst->priv_data = av_mallocz(sizeof(FeedData));
3484
+    fst->index = stream->nb_streams;
3485
+    av_set_pts_info(fst, 33, 1, 90000);
3486
+    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3487
+    stream->streams[stream->nb_streams++] = fst;
3488
+    return fst;
3489
+}
3490
+
3491
+/* return the stream number in the feed */
3492
+static int add_av_stream(FFStream *feed, AVStream *st)
3493
+{
3494
+    AVStream *fst;
3495
+    AVCodecContext *av, *av1;
3496
+    int i;
3497
+
3498
+    av = st->codec;
3499
+    for(i=0;i<feed->nb_streams;i++) {
3500
+        st = feed->streams[i];
3501
+        av1 = st->codec;
3502
+        if (av1->codec_id == av->codec_id &&
3503
+            av1->codec_type == av->codec_type &&
3504
+            av1->bit_rate == av->bit_rate) {
3505
+
3506
+            switch(av->codec_type) {
3507
+            case AVMEDIA_TYPE_AUDIO:
3508
+                if (av1->channels == av->channels &&
3509
+                    av1->sample_rate == av->sample_rate)
3510
+                    return i;
3511
+                break;
3512
+            case AVMEDIA_TYPE_VIDEO:
3513
+                if (av1->width == av->width &&
3514
+                    av1->height == av->height &&
3515
+                    av1->time_base.den == av->time_base.den &&
3516
+                    av1->time_base.num == av->time_base.num &&
3517
+                    av1->gop_size == av->gop_size)
3518
+                    return i;
3519
+                break;
3520
+            default:
3521
+                abort();
3522
+            }
3523
+        }
3524
+    }
3525
+
3526
+    fst = add_av_stream1(feed, av, 0);
3527
+    if (!fst)
3528
+        return -1;
3529
+    return feed->nb_streams - 1;
3530
+}
3531
+
3532
+static void remove_stream(FFStream *stream)
3533
+{
3534
+    FFStream **ps;
3535
+    ps = &first_stream;
3536
+    while (*ps != NULL) {
3537
+        if (*ps == stream)
3538
+            *ps = (*ps)->next;
3539
+        else
3540
+            ps = &(*ps)->next;
3541
+    }
3542
+}
3543
+
3544
+/* specific mpeg4 handling : we extract the raw parameters */
3545
+static void extract_mpeg4_header(AVFormatContext *infile)
3546
+{
3547
+    int mpeg4_count, i, size;
3548
+    AVPacket pkt;
3549
+    AVStream *st;
3550
+    const uint8_t *p;
3551
+
3552
+    mpeg4_count = 0;
3553
+    for(i=0;i<infile->nb_streams;i++) {
3554
+        st = infile->streams[i];
3555
+        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3556
+            st->codec->extradata_size == 0) {
3557
+            mpeg4_count++;
3558
+        }
3559
+    }
3560
+    if (!mpeg4_count)
3561
+        return;
3562
+
3563
+    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3564
+    while (mpeg4_count > 0) {
3565
+        if (av_read_packet(infile, &pkt) < 0)
3566
+            break;
3567
+        st = infile->streams[pkt.stream_index];
3568
+        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3569
+            st->codec->extradata_size == 0) {
3570
+            av_freep(&st->codec->extradata);
3571
+            /* fill extradata with the header */
3572
+            /* XXX: we make hard suppositions here ! */
3573
+            p = pkt.data;
3574
+            while (p < pkt.data + pkt.size - 4) {
3575
+                /* stop when vop header is found */
3576
+                if (p[0] == 0x00 && p[1] == 0x00 &&
3577
+                    p[2] == 0x01 && p[3] == 0xb6) {
3578
+                    size = p - pkt.data;
3579
+                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3580
+                    st->codec->extradata = av_malloc(size);
3581
+                    st->codec->extradata_size = size;
3582
+                    memcpy(st->codec->extradata, pkt.data, size);
3583
+                    break;
3584
+                }
3585
+                p++;
3586
+            }
3587
+            mpeg4_count--;
3588
+        }
3589
+        av_free_packet(&pkt);
3590
+    }
3591
+}
3592
+
3593
+/* compute the needed AVStream for each file */
3594
+static void build_file_streams(void)
3595
+{
3596
+    FFStream *stream, *stream_next;
3597
+    int i, ret;
3598
+
3599
+    /* gather all streams */
3600
+    for(stream = first_stream; stream != NULL; stream = stream_next) {
3601
+        AVFormatContext *infile = NULL;
3602
+        stream_next = stream->next;
3603
+        if (stream->stream_type == STREAM_TYPE_LIVE &&
3604
+            !stream->feed) {
3605
+            /* the stream comes from a file */
3606
+            /* try to open the file */
3607
+            /* open stream */
3608
+            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3609
+                /* specific case : if transport stream output to RTP,
3610
+                   we use a raw transport stream reader */
3611
+                av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3612
+            }
3613
+
3614
+            http_log("Opening file '%s'\n", stream->feed_filename);
3615
+            if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3616
+                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3617
+                /* remove stream (no need to spend more time on it) */
3618
+            fail:
3619
+                remove_stream(stream);
3620
+            } else {
3621
+                /* find all the AVStreams inside and reference them in
3622
+                   'stream' */
3623
+                if (av_find_stream_info(infile) < 0) {
3624
+                    http_log("Could not find codec parameters from '%s'\n",
3625
+                             stream->feed_filename);
3626
+                    av_close_input_file(infile);
3627
+                    goto fail;
3628
+                }
3629
+                extract_mpeg4_header(infile);
3630
+
3631
+                for(i=0;i<infile->nb_streams;i++)
3632
+                    add_av_stream1(stream, infile->streams[i]->codec, 1);
3633
+
3634
+                av_close_input_file(infile);
3635
+            }
3636
+        }
3637
+    }
3638
+}
3639
+
3640
+/* compute the needed AVStream for each feed */
3641
+static void build_feed_streams(void)
3642
+{
3643
+    FFStream *stream, *feed;
3644
+    int i;
3645
+
3646
+    /* gather all streams */
3647
+    for(stream = first_stream; stream != NULL; stream = stream->next) {
3648
+        feed = stream->feed;
3649
+        if (feed) {
3650
+            if (stream->is_feed) {
3651
+                for(i=0;i<stream->nb_streams;i++)
3652
+                    stream->feed_streams[i] = i;
3653
+            } else {
3654
+                /* we handle a stream coming from a feed */
3655
+                for(i=0;i<stream->nb_streams;i++)
3656
+                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3657
+            }
3658
+        }
3659
+    }
3660
+
3661
+    /* create feed files if needed */
3662
+    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3663
+        int fd;
3664
+
3665
+        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3666
+            /* See if it matches */
3667
+            AVFormatContext *s = NULL;
3668
+            int matches = 0;
3669
+
3670
+            if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3671
+                /* Now see if it matches */
3672
+                if (s->nb_streams == feed->nb_streams) {
3673
+                    matches = 1;
3674
+                    for(i=0;i<s->nb_streams;i++) {
3675
+                        AVStream *sf, *ss;
3676
+                        sf = feed->streams[i];
3677
+                        ss = s->streams[i];
3678
+
3679
+                        if (sf->index != ss->index ||
3680
+                            sf->id != ss->id) {
3681
+                            http_log("Index & Id do not match for stream %d (%s)\n",
3682
+                                   i, feed->feed_filename);
3683
+                            matches = 0;
3684
+                        } else {
3685
+                            AVCodecContext *ccf, *ccs;
3686
+
3687
+                            ccf = sf->codec;
3688
+                            ccs = ss->codec;
3689
+#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3690
+
3691
+                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3692
+                                http_log("Codecs do not match for stream %d\n", i);
3693
+                                matches = 0;
3694
+                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3695
+                                http_log("Codec bitrates do not match for stream %d\n", i);
3696
+                                matches = 0;
3697
+                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3698
+                                if (CHECK_CODEC(time_base.den) ||
3699
+                                    CHECK_CODEC(time_base.num) ||
3700
+                                    CHECK_CODEC(width) ||
3701
+                                    CHECK_CODEC(height)) {
3702
+                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3703
+                                    matches = 0;
3704
+                                }
3705
+                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3706
+                                if (CHECK_CODEC(sample_rate) ||
3707
+                                    CHECK_CODEC(channels) ||
3708
+                                    CHECK_CODEC(frame_size)) {
3709
+                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3710
+                                    matches = 0;
3711
+                                }
3712
+                            } else {
3713
+                                http_log("Unknown codec type\n");
3714
+                                matches = 0;
3715
+                            }
3716
+                        }
3717
+                        if (!matches)
3718
+                            break;
3719
+                    }
3720
+                } else
3721
+                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3722
+                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3723
+
3724
+                av_close_input_file(s);
3725
+            } else
3726
+                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3727
+                        feed->feed_filename);
3728
+
3729
+            if (!matches) {
3730
+                if (feed->readonly) {
3731
+                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3732
+                        feed->feed_filename);
3733
+                    exit(1);
3734
+                }
3735
+                unlink(feed->feed_filename);
3736
+            }
3737
+        }
3738
+        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3739
+            AVFormatContext s1 = {0}, *s = &s1;
3740
+
3741
+            if (feed->readonly) {
3742
+                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3743
+                    feed->feed_filename);
3744
+                exit(1);
3745
+            }
3746
+
3747
+            /* only write the header of the ffm file */
3748
+            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3749
+                http_log("Could not open output feed file '%s'\n",
3750
+                         feed->feed_filename);
3751
+                exit(1);
3752
+            }
3753
+            s->oformat = feed->fmt;
3754
+            s->nb_streams = feed->nb_streams;
3755
+            s->streams = feed->streams;
3756
+            if (avformat_write_header(s, NULL) < 0) {
3757
+                http_log("Container doesn't supports the required parameters\n");
3758
+                exit(1);
3759
+            }
3760
+            /* XXX: need better api */
3761
+            av_freep(&s->priv_data);
3762
+            avio_close(s->pb);
3763
+        }
3764
+        /* get feed size and write index */
3765
+        fd = open(feed->feed_filename, O_RDONLY);
3766
+        if (fd < 0) {
3767
+            http_log("Could not open output feed file '%s'\n",
3768
+                    feed->feed_filename);
3769
+            exit(1);
3770
+        }
3771
+
3772
+        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3773
+        feed->feed_size = lseek(fd, 0, SEEK_END);
3774
+        /* ensure that we do not wrap before the end of file */
3775
+        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3776
+            feed->feed_max_size = feed->feed_size;
3777
+
3778
+        close(fd);
3779
+    }
3780
+}
3781
+
3782
+/* compute the bandwidth used by each stream */
3783
+static void compute_bandwidth(void)
3784
+{
3785
+    unsigned bandwidth;
3786
+    int i;
3787
+    FFStream *stream;
3788
+
3789
+    for(stream = first_stream; stream != NULL; stream = stream->next) {
3790
+        bandwidth = 0;
3791
+        for(i=0;i<stream->nb_streams;i++) {
3792
+            AVStream *st = stream->streams[i];
3793
+            switch(st->codec->codec_type) {
3794
+            case AVMEDIA_TYPE_AUDIO:
3795
+            case AVMEDIA_TYPE_VIDEO:
3796
+                bandwidth += st->codec->bit_rate;
3797
+                break;
3798
+            default:
3799
+                break;
3800
+            }
3801
+        }
3802
+        stream->bandwidth = (bandwidth + 999) / 1000;
3803
+    }
3804
+}
3805
+
3806
+/* add a codec and set the default parameters */
3807
+static void add_codec(FFStream *stream, AVCodecContext *av)
3808
+{
3809
+    AVStream *st;
3810
+
3811
+    /* compute default parameters */
3812
+    switch(av->codec_type) {
3813
+    case AVMEDIA_TYPE_AUDIO:
3814
+        if (av->bit_rate == 0)
3815
+            av->bit_rate = 64000;
3816
+        if (av->sample_rate == 0)
3817
+            av->sample_rate = 22050;
3818
+        if (av->channels == 0)
3819
+            av->channels = 1;
3820
+        break;
3821
+    case AVMEDIA_TYPE_VIDEO:
3822
+        if (av->bit_rate == 0)
3823
+            av->bit_rate = 64000;
3824
+        if (av->time_base.num == 0){
3825
+            av->time_base.den = 5;
3826
+            av->time_base.num = 1;
3827
+        }
3828
+        if (av->width == 0 || av->height == 0) {
3829
+            av->width = 160;
3830
+            av->height = 128;
3831
+        }
3832
+        /* Bitrate tolerance is less for streaming */
3833
+        if (av->bit_rate_tolerance == 0)
3834
+            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3835
+                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3836
+        if (av->qmin == 0)
3837
+            av->qmin = 3;
3838
+        if (av->qmax == 0)
3839
+            av->qmax = 31;
3840
+        if (av->max_qdiff == 0)
3841
+            av->max_qdiff = 3;
3842
+        av->qcompress = 0.5;
3843
+        av->qblur = 0.5;
3844
+
3845
+        if (!av->nsse_weight)
3846
+            av->nsse_weight = 8;
3847
+
3848
+        av->frame_skip_cmp = FF_CMP_DCTMAX;
3849
+        if (!av->me_method)
3850
+            av->me_method = ME_EPZS;
3851
+        av->rc_buffer_aggressivity = 1.0;
3852
+
3853
+        if (!av->rc_eq)
3854
+            av->rc_eq = "tex^qComp";
3855
+        if (!av->i_quant_factor)
3856
+            av->i_quant_factor = -0.8;
3857
+        if (!av->b_quant_factor)
3858
+            av->b_quant_factor = 1.25;
3859
+        if (!av->b_quant_offset)
3860
+            av->b_quant_offset = 1.25;
3861
+        if (!av->rc_max_rate)
3862
+            av->rc_max_rate = av->bit_rate * 2;
3863
+
3864
+        if (av->rc_max_rate && !av->rc_buffer_size) {
3865
+            av->rc_buffer_size = av->rc_max_rate;
3866
+        }
3867
+
3868
+
3869
+        break;
3870
+    default:
3871
+        abort();
3872
+    }
3873
+
3874
+    st = av_mallocz(sizeof(AVStream));
3875
+    if (!st)
3876
+        return;
3877
+    st->codec = avcodec_alloc_context3(NULL);
3878
+    stream->streams[stream->nb_streams++] = st;
3879
+    memcpy(st->codec, av, sizeof(AVCodecContext));
3880
+}
3881
+
3882
+static enum CodecID opt_audio_codec(const char *arg)
3883
+{
3884
+    AVCodec *p= avcodec_find_encoder_by_name(arg);
3885
+
3886
+    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3887
+        return CODEC_ID_NONE;
3888
+
3889
+    return p->id;
3890
+}
3891
+
3892
+static enum CodecID opt_video_codec(const char *arg)
3893
+{
3894
+    AVCodec *p= avcodec_find_encoder_by_name(arg);
3895
+
3896
+    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3897
+        return CODEC_ID_NONE;
3898
+
3899
+    return p->id;
3900
+}
3901
+
3902
+/* simplistic plugin support */
3903
+
3904
+#if HAVE_DLOPEN
3905
+static void load_module(const char *filename)
3906
+{
3907
+    void *dll;
3908
+    void (*init_func)(void);
3909
+    dll = dlopen(filename, RTLD_NOW);
3910
+    if (!dll) {
3911
+        fprintf(stderr, "Could not load module '%s' - %s\n",
3912
+                filename, dlerror());
3913
+        return;
3914
+    }
3915
+
3916
+    init_func = dlsym(dll, "avserver_module_init");
3917
+    if (!init_func) {
3918
+        fprintf(stderr,
3919
+                "%s: init function 'avserver_module_init()' not found\n",
3920
+                filename);
3921
+        dlclose(dll);
3922
+    }
3923
+
3924
+    init_func();
3925
+}
3926
+#endif
3927
+
3928
+static int avserver_opt_default(const char *opt, const char *arg,
3929
+                       AVCodecContext *avctx, int type)
3930
+{
3931
+    int ret = 0;
3932
+    const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3933
+    if(o)
3934
+        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3935
+    return ret;
3936
+}
3937
+
3938
+static int avserver_opt_preset(const char *arg,
3939
+                       AVCodecContext *avctx, int type,
3940
+                       enum CodecID *audio_id, enum CodecID *video_id)
3941
+{
3942
+    FILE *f=NULL;
3943
+    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3944
+    int ret = 0;
3945
+    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3946
+
3947
+    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3948
+                              codec ? codec->name : NULL))) {
3949
+        fprintf(stderr, "File for preset '%s' not found\n", arg);
3950
+        return 1;
3951
+    }
3952
+
3953
+    while(!feof(f)){
3954
+        int e= fscanf(f, "%999[^\n]\n", line) - 1;
3955
+        if(line[0] == '#' && !e)
3956
+            continue;
3957
+        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3958
+        if(e){
3959
+            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3960
+            ret = 1;
3961
+            break;
3962
+        }
3963
+        if(!strcmp(tmp, "acodec")){
3964
+            *audio_id = opt_audio_codec(tmp2);
3965
+        }else if(!strcmp(tmp, "vcodec")){
3966
+            *video_id = opt_video_codec(tmp2);
3967
+        }else if(!strcmp(tmp, "scodec")){
3968
+            /* opt_subtitle_codec(tmp2); */
3969
+        }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){
3970
+            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3971
+            ret = 1;
3972
+            break;
3973
+        }
3974
+    }
3975
+
3976
+    fclose(f);
3977
+
3978
+    return ret;
3979
+}
3980
+
3981
+static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename,
3982
+                                             const char *mime_type)
3983
+{
3984
+    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3985
+
3986
+    if (fmt) {
3987
+        AVOutputFormat *stream_fmt;
3988
+        char stream_format_name[64];
3989
+
3990
+        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3991
+        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3992
+
3993
+        if (stream_fmt)
3994
+            fmt = stream_fmt;
3995
+    }
3996
+
3997
+    return fmt;
3998
+}
3999
+
4000
+static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4001
+{
4002
+    va_list vl;
4003
+    va_start(vl, fmt);
4004
+    fprintf(stderr, "%s:%d: ", filename, line_num);
4005
+    vfprintf(stderr, fmt, vl);
4006
+    va_end(vl);
4007
+
4008
+    (*errors)++;
4009
+}
4010
+
4011
+static int parse_ffconfig(const char *filename)
4012
+{
4013
+    FILE *f;
4014
+    char line[1024];
4015
+    char cmd[64];
4016
+    char arg[1024];
4017
+    const char *p;
4018
+    int val, errors, line_num;
4019
+    FFStream **last_stream, *stream, *redirect;
4020
+    FFStream **last_feed, *feed, *s;
4021
+    AVCodecContext audio_enc, video_enc;
4022
+    enum CodecID audio_id, video_id;
4023
+
4024
+    f = fopen(filename, "r");
4025
+    if (!f) {
4026
+        perror(filename);
4027
+        return -1;
4028
+    }
4029
+
4030
+    errors = 0;
4031
+    line_num = 0;
4032
+    first_stream = NULL;
4033
+    last_stream = &first_stream;
4034
+    first_feed = NULL;
4035
+    last_feed = &first_feed;
4036
+    stream = NULL;
4037
+    feed = NULL;
4038
+    redirect = NULL;
4039
+    audio_id = CODEC_ID_NONE;
4040
+    video_id = CODEC_ID_NONE;
4041
+
4042
+#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4043
+    for(;;) {
4044
+        if (fgets(line, sizeof(line), f) == NULL)
4045
+            break;
4046
+        line_num++;
4047
+        p = line;
4048
+        while (isspace(*p))
4049
+            p++;
4050
+        if (*p == '\0' || *p == '#')
4051
+            continue;
4052
+
4053
+        get_arg(cmd, sizeof(cmd), &p);
4054
+
4055
+        if (!strcasecmp(cmd, "Port")) {
4056
+            get_arg(arg, sizeof(arg), &p);
4057
+            val = atoi(arg);
4058
+            if (val < 1 || val > 65536) {
4059
+                ERROR("Invalid_port: %s\n", arg);
4060
+            }
4061
+            my_http_addr.sin_port = htons(val);
4062
+        } else if (!strcasecmp(cmd, "BindAddress")) {
4063
+            get_arg(arg, sizeof(arg), &p);
4064
+            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4065
+                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4066
+            }
4067
+        } else if (!strcasecmp(cmd, "NoDaemon")) {
4068
+            avserver_daemon = 0;
4069
+        } else if (!strcasecmp(cmd, "RTSPPort")) {
4070
+            get_arg(arg, sizeof(arg), &p);
4071
+            val = atoi(arg);
4072
+            if (val < 1 || val > 65536) {
4073
+                ERROR("%s:%d: Invalid port: %s\n", arg);
4074
+            }
4075
+            my_rtsp_addr.sin_port = htons(atoi(arg));
4076
+        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4077
+            get_arg(arg, sizeof(arg), &p);
4078
+            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4079
+                ERROR("Invalid host/IP address: %s\n", arg);
4080
+            }
4081
+        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4082
+            get_arg(arg, sizeof(arg), &p);
4083
+            val = atoi(arg);
4084
+            if (val < 1 || val > 65536) {
4085
+                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4086
+            }
4087
+            nb_max_http_connections = val;
4088
+        } else if (!strcasecmp(cmd, "MaxClients")) {
4089
+            get_arg(arg, sizeof(arg), &p);
4090
+            val = atoi(arg);
4091
+            if (val < 1 || val > nb_max_http_connections) {
4092
+                ERROR("Invalid MaxClients: %s\n", arg);
4093
+            } else {
4094
+                nb_max_connections = val;
4095
+            }
4096
+        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4097
+            int64_t llval;
4098
+            get_arg(arg, sizeof(arg), &p);
4099
+            llval = atoll(arg);
4100
+            if (llval < 10 || llval > 10000000) {
4101
+                ERROR("Invalid MaxBandwidth: %s\n", arg);
4102
+            } else
4103
+                max_bandwidth = llval;
4104
+        } else if (!strcasecmp(cmd, "CustomLog")) {
4105
+            if (!avserver_debug)
4106
+                get_arg(logfilename, sizeof(logfilename), &p);
4107
+        } else if (!strcasecmp(cmd, "<Feed")) {
4108
+            /*********************************************/
4109
+            /* Feed related options */
4110
+            char *q;
4111
+            if (stream || feed) {
4112
+                ERROR("Already in a tag\n");
4113
+            } else {
4114
+                feed = av_mallocz(sizeof(FFStream));
4115
+                get_arg(feed->filename, sizeof(feed->filename), &p);
4116
+                q = strrchr(feed->filename, '>');
4117
+                if (*q)
4118
+                    *q = '\0';
4119
+
4120
+                for (s = first_feed; s; s = s->next) {
4121
+                    if (!strcmp(feed->filename, s->filename)) {
4122
+                        ERROR("Feed '%s' already registered\n", s->filename);
4123
+                    }
4124
+                }
4125
+
4126
+                feed->fmt = av_guess_format("ffm", NULL, NULL);
4127
+                /* defaut feed file */
4128
+                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4129
+                         "/tmp/%s.ffm", feed->filename);
4130
+                feed->feed_max_size = 5 * 1024 * 1024;
4131
+                feed->is_feed = 1;
4132
+                feed->feed = feed; /* self feeding :-) */
4133
+
4134
+                /* add in stream list */
4135
+                *last_stream = feed;
4136
+                last_stream = &feed->next;
4137
+                /* add in feed list */
4138
+                *last_feed = feed;
4139
+                last_feed = &feed->next_feed;
4140
+            }
4141
+        } else if (!strcasecmp(cmd, "Launch")) {
4142
+            if (feed) {
4143
+                int i;
4144
+
4145
+                feed->child_argv = av_mallocz(64 * sizeof(char *));
4146
+
4147
+                for (i = 0; i < 62; i++) {
4148
+                    get_arg(arg, sizeof(arg), &p);
4149
+                    if (!arg[0])
4150
+                        break;
4151
+
4152
+                    feed->child_argv[i] = av_strdup(arg);
4153
+                }
4154
+
4155
+                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4156
+
4157
+                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4158
+                    "http://%s:%d/%s",
4159
+                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4160
+                    inet_ntoa(my_http_addr.sin_addr),
4161
+                    ntohs(my_http_addr.sin_port), feed->filename);
4162
+            }
4163
+        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4164
+            if (feed) {
4165
+                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4166
+                feed->readonly = 1;
4167
+            } else if (stream) {
4168
+                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4169
+            }
4170
+        } else if (!strcasecmp(cmd, "File")) {
4171
+            if (feed) {
4172
+                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4173
+            } else if (stream)
4174
+                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4175
+        } else if (!strcasecmp(cmd, "Truncate")) {
4176
+            if (feed) {
4177
+                get_arg(arg, sizeof(arg), &p);
4178
+                feed->truncate = strtod(arg, NULL);
4179
+            }
4180
+        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4181
+            if (feed) {
4182
+                char *p1;
4183
+                double fsize;
4184
+
4185
+                get_arg(arg, sizeof(arg), &p);
4186
+                p1 = arg;
4187
+                fsize = strtod(p1, &p1);
4188
+                switch(toupper(*p1)) {
4189
+                case 'K':
4190
+                    fsize *= 1024;
4191
+                    break;
4192
+                case 'M':
4193
+                    fsize *= 1024 * 1024;
4194
+                    break;
4195
+                case 'G':
4196
+                    fsize *= 1024 * 1024 * 1024;
4197
+                    break;
4198
+                }
4199
+                feed->feed_max_size = (int64_t)fsize;
4200
+                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4201
+                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4202
+                }
4203
+            }
4204
+        } else if (!strcasecmp(cmd, "</Feed>")) {
4205
+            if (!feed) {
4206
+                ERROR("No corresponding <Feed> for </Feed>\n");
4207
+            }
4208
+            feed = NULL;
4209
+        } else if (!strcasecmp(cmd, "<Stream")) {
4210
+            /*********************************************/
4211
+            /* Stream related options */
4212
+            char *q;
4213
+            if (stream || feed) {
4214
+                ERROR("Already in a tag\n");
4215
+            } else {
4216
+                FFStream *s;
4217
+                stream = av_mallocz(sizeof(FFStream));
4218
+                get_arg(stream->filename, sizeof(stream->filename), &p);
4219
+                q = strrchr(stream->filename, '>');
4220
+                if (*q)
4221
+                    *q = '\0';
4222
+
4223
+                for (s = first_stream; s; s = s->next) {
4224
+                    if (!strcmp(stream->filename, s->filename)) {
4225
+                        ERROR("Stream '%s' already registered\n", s->filename);
4226
+                    }
4227
+                }
4228
+
4229
+                stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
4230
+                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4231
+                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4232
+                audio_id = CODEC_ID_NONE;
4233
+                video_id = CODEC_ID_NONE;
4234
+                if (stream->fmt) {
4235
+                    audio_id = stream->fmt->audio_codec;
4236
+                    video_id = stream->fmt->video_codec;
4237
+                }
4238
+
4239
+                *last_stream = stream;
4240
+                last_stream = &stream->next;
4241
+            }
4242
+        } else if (!strcasecmp(cmd, "Feed")) {
4243
+            get_arg(arg, sizeof(arg), &p);
4244
+            if (stream) {
4245
+                FFStream *sfeed;
4246
+
4247
+                sfeed = first_feed;
4248
+                while (sfeed != NULL) {
4249
+                    if (!strcmp(sfeed->filename, arg))
4250
+                        break;
4251
+                    sfeed = sfeed->next_feed;
4252
+                }
4253
+                if (!sfeed)
4254
+                    ERROR("feed '%s' not defined\n", arg);
4255
+                else
4256
+                    stream->feed = sfeed;
4257
+            }
4258
+        } else if (!strcasecmp(cmd, "Format")) {
4259
+            get_arg(arg, sizeof(arg), &p);
4260
+            if (stream) {
4261
+                if (!strcmp(arg, "status")) {
4262
+                    stream->stream_type = STREAM_TYPE_STATUS;
4263
+                    stream->fmt = NULL;
4264
+                } else {
4265
+                    stream->stream_type = STREAM_TYPE_LIVE;
4266
+                    /* jpeg cannot be used here, so use single frame jpeg */
4267
+                    if (!strcmp(arg, "jpeg"))
4268
+                        strcpy(arg, "mjpeg");
4269
+                    stream->fmt = avserver_guess_format(arg, NULL, NULL);
4270
+                    if (!stream->fmt) {
4271
+                        ERROR("Unknown Format: %s\n", arg);
4272
+                    }
4273
+                }
4274
+                if (stream->fmt) {
4275
+                    audio_id = stream->fmt->audio_codec;
4276
+                    video_id = stream->fmt->video_codec;
4277
+                }
4278
+            }
4279
+        } else if (!strcasecmp(cmd, "InputFormat")) {
4280
+            get_arg(arg, sizeof(arg), &p);
4281
+            if (stream) {
4282
+                stream->ifmt = av_find_input_format(arg);
4283
+                if (!stream->ifmt) {
4284
+                    ERROR("Unknown input format: %s\n", arg);
4285
+                }
4286
+            }
4287
+        } else if (!strcasecmp(cmd, "FaviconURL")) {
4288
+            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4289
+                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4290
+            } else {
4291
+                ERROR("FaviconURL only permitted for status streams\n");
4292
+            }
4293
+        } else if (!strcasecmp(cmd, "Author")) {
4294
+            if (stream)
4295
+                get_arg(stream->author, sizeof(stream->author), &p);
4296
+        } else if (!strcasecmp(cmd, "Comment")) {
4297
+            if (stream)
4298
+                get_arg(stream->comment, sizeof(stream->comment), &p);
4299
+        } else if (!strcasecmp(cmd, "Copyright")) {
4300
+            if (stream)
4301
+                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4302
+        } else if (!strcasecmp(cmd, "Title")) {
4303
+            if (stream)
4304
+                get_arg(stream->title, sizeof(stream->title), &p);
4305
+        } else if (!strcasecmp(cmd, "Preroll")) {
4306
+            get_arg(arg, sizeof(arg), &p);
4307
+            if (stream)
4308
+                stream->prebuffer = atof(arg) * 1000;
4309
+        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4310
+            if (stream)
4311
+                stream->send_on_key = 1;
4312
+        } else if (!strcasecmp(cmd, "AudioCodec")) {
4313
+            get_arg(arg, sizeof(arg), &p);
4314
+            audio_id = opt_audio_codec(arg);
4315
+            if (audio_id == CODEC_ID_NONE) {
4316
+                ERROR("Unknown AudioCodec: %s\n", arg);
4317
+            }
4318
+        } else if (!strcasecmp(cmd, "VideoCodec")) {
4319
+            get_arg(arg, sizeof(arg), &p);
4320
+            video_id = opt_video_codec(arg);
4321
+            if (video_id == CODEC_ID_NONE) {
4322
+                ERROR("Unknown VideoCodec: %s\n", arg);
4323
+            }
4324
+        } else if (!strcasecmp(cmd, "MaxTime")) {
4325
+            get_arg(arg, sizeof(arg), &p);
4326
+            if (stream)
4327
+                stream->max_time = atof(arg) * 1000;
4328
+        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4329
+            get_arg(arg, sizeof(arg), &p);
4330
+            if (stream)
4331
+                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4332
+        } else if (!strcasecmp(cmd, "AudioChannels")) {
4333
+            get_arg(arg, sizeof(arg), &p);
4334
+            if (stream)
4335
+                audio_enc.channels = atoi(arg);
4336
+        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4337
+            get_arg(arg, sizeof(arg), &p);
4338
+            if (stream)
4339
+                audio_enc.sample_rate = atoi(arg);
4340
+        } else if (!strcasecmp(cmd, "AudioQuality")) {
4341
+            get_arg(arg, sizeof(arg), &p);
4342
+            if (stream) {
4343
+//                audio_enc.quality = atof(arg) * 1000;
4344
+            }
4345
+        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4346
+            if (stream) {
4347
+                int minrate, maxrate;
4348
+
4349
+                get_arg(arg, sizeof(arg), &p);
4350
+
4351
+                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4352
+                    video_enc.rc_min_rate = minrate * 1000;
4353
+                    video_enc.rc_max_rate = maxrate * 1000;
4354
+                } else {
4355
+                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4356
+                }
4357
+            }
4358
+        } else if (!strcasecmp(cmd, "Debug")) {
4359
+            if (stream) {
4360
+                get_arg(arg, sizeof(arg), &p);
4361
+                video_enc.debug = strtol(arg,0,0);
4362
+            }
4363
+        } else if (!strcasecmp(cmd, "Strict")) {
4364
+            if (stream) {
4365
+                get_arg(arg, sizeof(arg), &p);
4366
+                video_enc.strict_std_compliance = atoi(arg);
4367
+            }
4368
+        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4369
+            if (stream) {
4370
+                get_arg(arg, sizeof(arg), &p);
4371
+                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4372
+            }
4373
+        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4374
+            if (stream) {
4375
+                get_arg(arg, sizeof(arg), &p);
4376
+                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4377
+            }
4378
+        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4379
+            get_arg(arg, sizeof(arg), &p);
4380
+            if (stream) {
4381
+                video_enc.bit_rate = atoi(arg) * 1000;
4382
+            }
4383
+        } else if (!strcasecmp(cmd, "VideoSize")) {
4384
+            get_arg(arg, sizeof(arg), &p);
4385
+            if (stream) {
4386
+                av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4387
+                if ((video_enc.width % 16) != 0 ||
4388
+                    (video_enc.height % 16) != 0) {
4389
+                    ERROR("Image size must be a multiple of 16\n");
4390
+                }
4391
+            }
4392
+        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4393
+            get_arg(arg, sizeof(arg), &p);
4394
+            if (stream) {
4395
+                AVRational frame_rate;
4396
+                if (av_parse_video_rate(&frame_rate, arg) < 0) {
4397
+                    ERROR("Incorrect frame rate: %s\n", arg);
4398
+                } else {
4399
+                    video_enc.time_base.num = frame_rate.den;
4400
+                    video_enc.time_base.den = frame_rate.num;
4401
+                }
4402
+            }
4403
+        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4404
+            get_arg(arg, sizeof(arg), &p);
4405
+            if (stream)
4406
+                video_enc.gop_size = atoi(arg);
4407
+        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4408
+            if (stream)
4409
+                video_enc.gop_size = 1;
4410
+        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4411
+            if (stream)
4412
+                video_enc.mb_decision = FF_MB_DECISION_BITS;
4413
+        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4414
+            if (stream) {
4415
+                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4416
+                video_enc.flags |= CODEC_FLAG_4MV;
4417
+            }
4418
+        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4419
+                   !strcasecmp(cmd, "AVOptionAudio")) {
4420
+            char arg2[1024];
4421
+            AVCodecContext *avctx;
4422
+            int type;
4423
+            get_arg(arg, sizeof(arg), &p);
4424
+            get_arg(arg2, sizeof(arg2), &p);
4425
+            if (!strcasecmp(cmd, "AVOptionVideo")) {
4426
+                avctx = &video_enc;
4427
+                type = AV_OPT_FLAG_VIDEO_PARAM;
4428
+            } else {
4429
+                avctx = &audio_enc;
4430
+                type = AV_OPT_FLAG_AUDIO_PARAM;
4431
+            }
4432
+            if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4433
+                ERROR("AVOption error: %s %s\n", arg, arg2);
4434
+            }
4435
+        } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4436
+                   !strcasecmp(cmd, "AVPresetAudio")) {
4437
+            AVCodecContext *avctx;
4438
+            int type;
4439
+            get_arg(arg, sizeof(arg), &p);
4440
+            if (!strcasecmp(cmd, "AVPresetVideo")) {
4441
+                avctx = &video_enc;
4442
+                video_enc.codec_id = video_id;
4443
+                type = AV_OPT_FLAG_VIDEO_PARAM;
4444
+            } else {
4445
+                avctx = &audio_enc;
4446
+                audio_enc.codec_id = audio_id;
4447
+                type = AV_OPT_FLAG_AUDIO_PARAM;
4448
+            }
4449
+            if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4450
+                ERROR("AVPreset error: %s\n", arg);
4451
+            }
4452
+        } else if (!strcasecmp(cmd, "VideoTag")) {
4453
+            get_arg(arg, sizeof(arg), &p);
4454
+            if ((strlen(arg) == 4) && stream)
4455
+                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4456
+        } else if (!strcasecmp(cmd, "BitExact")) {
4457
+            if (stream)
4458
+                video_enc.flags |= CODEC_FLAG_BITEXACT;
4459
+        } else if (!strcasecmp(cmd, "DctFastint")) {
4460
+            if (stream)
4461
+                video_enc.dct_algo  = FF_DCT_FASTINT;
4462
+        } else if (!strcasecmp(cmd, "IdctSimple")) {
4463
+            if (stream)
4464
+                video_enc.idct_algo = FF_IDCT_SIMPLE;
4465
+        } else if (!strcasecmp(cmd, "Qscale")) {
4466
+            get_arg(arg, sizeof(arg), &p);
4467
+            if (stream) {
4468
+                video_enc.flags |= CODEC_FLAG_QSCALE;
4469
+                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4470
+            }
4471
+        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4472
+            get_arg(arg, sizeof(arg), &p);
4473
+            if (stream) {
4474
+                video_enc.max_qdiff = atoi(arg);
4475
+                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4476
+                    ERROR("VideoQDiff out of range\n");
4477
+                }
4478
+            }
4479
+        } else if (!strcasecmp(cmd, "VideoQMax")) {
4480
+            get_arg(arg, sizeof(arg), &p);
4481
+            if (stream) {
4482
+                video_enc.qmax = atoi(arg);
4483
+                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4484
+                    ERROR("VideoQMax out of range\n");
4485
+                }
4486
+            }
4487
+        } else if (!strcasecmp(cmd, "VideoQMin")) {
4488
+            get_arg(arg, sizeof(arg), &p);
4489
+            if (stream) {
4490
+                video_enc.qmin = atoi(arg);
4491
+                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4492
+                    ERROR("VideoQMin out of range\n");
4493
+                }
4494
+            }
4495
+        } else if (!strcasecmp(cmd, "LumaElim")) {
4496
+            get_arg(arg, sizeof(arg), &p);
4497
+            if (stream)
4498
+                video_enc.luma_elim_threshold = atoi(arg);
4499
+        } else if (!strcasecmp(cmd, "ChromaElim")) {
4500
+            get_arg(arg, sizeof(arg), &p);
4501
+            if (stream)
4502
+                video_enc.chroma_elim_threshold = atoi(arg);
4503
+        } else if (!strcasecmp(cmd, "LumiMask")) {
4504
+            get_arg(arg, sizeof(arg), &p);
4505
+            if (stream)
4506
+                video_enc.lumi_masking = atof(arg);
4507
+        } else if (!strcasecmp(cmd, "DarkMask")) {
4508
+            get_arg(arg, sizeof(arg), &p);
4509
+            if (stream)
4510
+                video_enc.dark_masking = atof(arg);
4511
+        } else if (!strcasecmp(cmd, "NoVideo")) {
4512
+            video_id = CODEC_ID_NONE;
4513
+        } else if (!strcasecmp(cmd, "NoAudio")) {
4514
+            audio_id = CODEC_ID_NONE;
4515
+        } else if (!strcasecmp(cmd, "ACL")) {
4516
+            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4517
+        } else if (!strcasecmp(cmd, "DynamicACL")) {
4518
+            if (stream) {
4519
+                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4520
+            }
4521
+        } else if (!strcasecmp(cmd, "RTSPOption")) {
4522
+            get_arg(arg, sizeof(arg), &p);
4523
+            if (stream) {
4524
+                av_freep(&stream->rtsp_option);
4525
+                stream->rtsp_option = av_strdup(arg);
4526
+            }
4527
+        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4528
+            get_arg(arg, sizeof(arg), &p);
4529
+            if (stream) {
4530
+                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4531
+                    ERROR("Invalid host/IP address: %s\n", arg);
4532
+                }
4533
+                stream->is_multicast = 1;
4534
+                stream->loop = 1; /* default is looping */
4535
+            }
4536
+        } else if (!strcasecmp(cmd, "MulticastPort")) {
4537
+            get_arg(arg, sizeof(arg), &p);
4538
+            if (stream)
4539
+                stream->multicast_port = atoi(arg);
4540
+        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4541
+            get_arg(arg, sizeof(arg), &p);
4542
+            if (stream)
4543
+                stream->multicast_ttl = atoi(arg);
4544
+        } else if (!strcasecmp(cmd, "NoLoop")) {
4545
+            if (stream)
4546
+                stream->loop = 0;
4547
+        } else if (!strcasecmp(cmd, "</Stream>")) {
4548
+            if (!stream) {
4549
+                ERROR("No corresponding <Stream> for </Stream>\n");
4550
+            } else {
4551
+                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4552
+                    if (audio_id != CODEC_ID_NONE) {
4553
+                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4554
+                        audio_enc.codec_id = audio_id;
4555
+                        add_codec(stream, &audio_enc);
4556
+                    }
4557
+                    if (video_id != CODEC_ID_NONE) {
4558
+                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4559
+                        video_enc.codec_id = video_id;
4560
+                        add_codec(stream, &video_enc);
4561
+                    }
4562
+                }
4563
+                stream = NULL;
4564
+            }
4565
+        } else if (!strcasecmp(cmd, "<Redirect")) {
4566
+            /*********************************************/
4567
+            char *q;
4568
+            if (stream || feed || redirect) {
4569
+                ERROR("Already in a tag\n");
4570
+            } else {
4571
+                redirect = av_mallocz(sizeof(FFStream));
4572
+                *last_stream = redirect;
4573
+                last_stream = &redirect->next;
4574
+
4575
+                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4576
+                q = strrchr(redirect->filename, '>');
4577
+                if (*q)
4578
+                    *q = '\0';
4579
+                redirect->stream_type = STREAM_TYPE_REDIRECT;
4580
+            }
4581
+        } else if (!strcasecmp(cmd, "URL")) {
4582
+            if (redirect)
4583
+                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4584
+        } else if (!strcasecmp(cmd, "</Redirect>")) {
4585
+            if (!redirect) {
4586
+                ERROR("No corresponding <Redirect> for </Redirect>\n");
4587
+            } else {
4588
+                if (!redirect->feed_filename[0]) {
4589
+                    ERROR("No URL found for <Redirect>\n");
4590
+                }
4591
+                redirect = NULL;
4592
+            }
4593
+        } else if (!strcasecmp(cmd, "LoadModule")) {
4594
+            get_arg(arg, sizeof(arg), &p);
4595
+#if HAVE_DLOPEN
4596
+            load_module(arg);
4597
+#else
4598
+            ERROR("Module support not compiled into this version: '%s'\n", arg);
4599
+#endif
4600
+        } else {
4601
+            ERROR("Incorrect keyword: '%s'\n", cmd);
4602
+        }
4603
+    }
4604
+#undef ERROR
4605
+
4606
+    fclose(f);
4607
+    if (errors)
4608
+        return -1;
4609
+    else
4610
+        return 0;
4611
+}
4612
+
4613
+static void handle_child_exit(int sig)
4614
+{
4615
+    pid_t pid;
4616
+    int status;
4617
+
4618
+    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4619
+        FFStream *feed;
4620
+
4621
+        for (feed = first_feed; feed; feed = feed->next) {
4622
+            if (feed->pid == pid) {
4623
+                int uptime = time(0) - feed->pid_start;
4624
+
4625
+                feed->pid = 0;
4626
+                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4627
+
4628
+                if (uptime < 30)
4629
+                    /* Turn off any more restarts */
4630
+                    feed->child_argv = 0;
4631
+            }
4632
+        }
4633
+    }
4634
+
4635
+    need_to_start_children = 1;
4636
+}
4637
+
4638
+static void opt_debug(void)
4639
+{
4640
+    avserver_debug = 1;
4641
+    avserver_daemon = 0;
4642
+    logfilename[0] = '-';
4643
+}
4644
+
4645
+static void show_help(void)
4646
+{
4647
+    printf("usage: avserver [options]\n"
4648
+           "Hyper fast multi format Audio/Video streaming server\n");
4649
+    printf("\n");
4650
+    show_help_options(options, "Main options:\n", 0, 0);
4651
+}
4652
+
4653
+static const OptionDef options[] = {
4654
+#include "cmdutils_common_opts.h"
4655
+    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4656
+    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4657
+    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/avserver.conf", "configfile" },
4658
+    { NULL },
4659
+};
4660
+
4661
+int main(int argc, char **argv)
4662
+{
4663
+    struct sigaction sigact;
4664
+
4665
+    av_register_all();
4666
+
4667
+    show_banner();
4668
+
4669
+    my_program_name = argv[0];
4670
+    my_program_dir = getcwd(0, 0);
4671
+    avserver_daemon = 1;
4672
+
4673
+    parse_options(argc, argv, options, NULL);
4674
+
4675
+    unsetenv("http_proxy");             /* Kill the http_proxy */
4676
+
4677
+    av_lfg_init(&random_state, av_get_random_seed());
4678
+
4679
+    memset(&sigact, 0, sizeof(sigact));
4680
+    sigact.sa_handler = handle_child_exit;
4681
+    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4682
+    sigaction(SIGCHLD, &sigact, 0);
4683
+
4684
+    if (parse_ffconfig(config_filename) < 0) {
4685
+        fprintf(stderr, "Incorrect config file - exiting.\n");
4686
+        exit(1);
4687
+    }
4688
+
4689
+    /* open log file if needed */
4690
+    if (logfilename[0] != '\0') {
4691
+        if (!strcmp(logfilename, "-"))
4692
+            logfile = stdout;
4693
+        else
4694
+            logfile = fopen(logfilename, "a");
4695
+        av_log_set_callback(http_av_log);
4696
+    }
4697
+
4698
+    build_file_streams();
4699
+
4700
+    build_feed_streams();
4701
+
4702
+    compute_bandwidth();
4703
+
4704
+    /* put the process in background and detach it from its TTY */
4705
+    if (avserver_daemon) {
4706
+        int pid;
4707
+
4708
+        pid = fork();
4709
+        if (pid < 0) {
4710
+            perror("fork");
4711
+            exit(1);
4712
+        } else if (pid > 0) {
4713
+            /* parent : exit */
4714
+            exit(0);
4715
+        } else {
4716
+            /* child */
4717
+            setsid();
4718
+            close(0);
4719
+            open("/dev/null", O_RDWR);
4720
+            if (strcmp(logfilename, "-") != 0) {
4721
+                close(1);
4722
+                dup(0);
4723
+            }
4724
+            close(2);
4725
+            dup(0);
4726
+        }
4727
+    }
4728
+
4729
+    /* signal init */
4730
+    signal(SIGPIPE, SIG_IGN);
4731
+
4732
+    if (avserver_daemon)
4733
+        chdir("/");
4734
+
4735
+    if (http_server() < 0) {
4736
+        http_log("Could not start server\n");
4737
+        exit(1);
4738
+    }
4739
+
4740
+    return 0;
4741
+}
... ...
@@ -83,7 +83,7 @@ Configuration options:
83 83
   --disable-ffmpeg         disable ffmpeg build
84 84
   --disable-avplay         disable avplay build
85 85
   --disable-avprobe        disable avprobe build
86
-  --disable-ffserver       disable ffserver build
86
+  --disable-avserver       disable avserver build
87 87
   --disable-avdevice       disable libavdevice build
88 88
   --disable-avcodec        disable libavcodec build
89 89
   --disable-avformat       disable libavformat build
... ...
@@ -915,7 +915,7 @@ CONFIG_LIST="
915 915
     ffmpeg
916 916
     avplay
917 917
     avprobe
918
-    ffserver
918
+    avserver
919 919
     fft
920 920
     frei0r
921 921
     golomb
... ...
@@ -1492,8 +1492,8 @@ ffmpeg_select="buffer_filter"
1492 1492
 avplay_deps="avcodec avformat swscale sdl"
1493 1493
 avplay_select="rdft"
1494 1494
 avprobe_deps="avcodec avformat"
1495
-ffserver_deps="avformat ffm_muxer fork rtp_protocol rtsp_demuxer"
1496
-ffserver_extralibs='$ldl'
1495
+avserver_deps="avformat ffm_muxer fork rtp_protocol rtsp_demuxer"
1496
+avserver_extralibs='$ldl'
1497 1497
 
1498 1498
 doc_deps="texi2html"
1499 1499
 
... ...
@@ -1637,7 +1637,7 @@ enable fastdiv
1637 1637
 enable ffmpeg
1638 1638
 enable avplay
1639 1639
 enable avprobe
1640
-enable ffserver
1640
+enable avserver
1641 1641
 enable network
1642 1642
 enable optimizations
1643 1643
 enable postproc
... ...
@@ -1648,7 +1648,7 @@ enable swscale_alpha
1648 1648
 
1649 1649
 # build settings
1650 1650
 SHFLAGS='-shared -Wl,-soname,$$(@F)'
1651
-FFSERVERLDFLAGS=-Wl,-E
1651
+AVSERVERLDFLAGS=-Wl,-E
1652 1652
 LIBPREF="lib"
1653 1653
 LIBSUF=".a"
1654 1654
 FULLNAME='$(NAME)$(BUILDSUF)'
... ...
@@ -2355,7 +2355,7 @@ case $target_os in
2355 2355
         host_libs=
2356 2356
         ;;
2357 2357
     sunos)
2358
-        FFSERVERLDFLAGS=""
2358
+        AVSERVERLDFLAGS=""
2359 2359
         SHFLAGS='-shared -Wl,-h,$$(@F)'
2360 2360
         enabled x86 && SHFLAGS="-mimpure-text $SHFLAGS"
2361 2361
         network_extralibs="-lsocket -lnsl"
... ...
@@ -2400,7 +2400,7 @@ case $target_os in
2400 2400
         SLIBSUF=".dylib"
2401 2401
         SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME).$(LIBVERSION)$(SLIBSUF)'
2402 2402
         SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME).$(LIBMAJOR)$(SLIBSUF)'
2403
-        FFSERVERLDFLAGS=-Wl,-bind_at_load
2403
+        AVSERVERLDFLAGS=-Wl,-bind_at_load
2404 2404
         objformat="macho"
2405 2405
         enabled x86_64 && objformat="macho64"
2406 2406
         enabled_any pic shared ||
... ...
@@ -2472,7 +2472,7 @@ case $target_os in
2472 2472
         add_cppflags -D_GNU_SOURCE
2473 2473
         add_ldflags -Zomf -Zbin-files -Zargs-wild -Zmap
2474 2474
         SHFLAGS='$(SUBDIR)$(NAME).def -Zdll -Zomf'
2475
-        FFSERVERLDFLAGS=""
2475
+        AVSERVERLDFLAGS=""
2476 2476
         LIBSUF="_s.a"
2477 2477
         SLIBPREF=""
2478 2478
         SLIBSUF=".dll"
... ...
@@ -3218,7 +3218,7 @@ AS_O=$CC_O
3218 3218
 CC_O=$CC_O
3219 3219
 DLLTOOL=$dlltool
3220 3220
 LDFLAGS=$LDFLAGS
3221
-FFSERVERLDFLAGS=$FFSERVERLDFLAGS
3221
+AVSERVERLDFLAGS=$AVSERVERLDFLAGS
3222 3222
 SHFLAGS=$SHFLAGS
3223 3223
 YASMFLAGS=$YASMFLAGS
3224 3224
 BUILDSUF=$build_suffix
... ...
@@ -170,7 +170,7 @@ Seek to percentage in file corresponding to fraction of width.
170 170
 @settitle AVplay media player
171 171
 
172 172
 @c man begin SEEALSO
173
-ffmpeg(1), avprobe(1), ffserver(1) and the Libav HTML documentation
173
+ffmpeg(1), avprobe(1), avserver(1) and the Libav HTML documentation
174 174
 @c man end
175 175
 
176 176
 @c man begin AUTHORS
... ...
@@ -122,7 +122,7 @@ with name "STREAM".
122 122
 @settitle avprobe media prober
123 123
 
124 124
 @c man begin SEEALSO
125
-ffmpeg(1), avplay(1), ffserver(1) and the Libav HTML documentation
125
+ffmpeg(1), avplay(1), avserver(1) and the Libav HTML documentation
126 126
 @c man end
127 127
 
128 128
 @c man begin AUTHORS
129 129
new file mode 100644
... ...
@@ -0,0 +1,377 @@
0
+# Port on which the server is listening. You must select a different
1
+# port from your standard HTTP web server if it is running on the same
2
+# computer.
3
+Port 8090
4
+
5
+# Address on which the server is bound. Only useful if you have
6
+# several network interfaces.
7
+BindAddress 0.0.0.0
8
+
9
+# Number of simultaneous HTTP connections that can be handled. It has
10
+# to be defined *before* the MaxClients parameter, since it defines the
11
+# MaxClients maximum limit.
12
+MaxHTTPConnections 2000
13
+
14
+# Number of simultaneous requests that can be handled. Since AVServer
15
+# is very fast, it is more likely that you will want to leave this high
16
+# and use MaxBandwidth, below.
17
+MaxClients 1000
18
+
19
+# This the maximum amount of kbit/sec that you are prepared to
20
+# consume when streaming to clients.
21
+MaxBandwidth 1000
22
+
23
+# Access log file (uses standard Apache log file format)
24
+# '-' is the standard output.
25
+CustomLog -
26
+
27
+# Suppress that if you want to launch avserver as a daemon.
28
+NoDaemon
29
+
30
+
31
+##################################################################
32
+# Definition of the live feeds. Each live feed contains one video
33
+# and/or audio sequence coming from an ffmpeg encoder or another
34
+# avserver. This sequence may be encoded simultaneously with several
35
+# codecs at several resolutions.
36
+
37
+<Feed feed1.ffm>
38
+
39
+# You must use 'ffmpeg' to send a live feed to avserver. In this
40
+# example, you can type:
41
+#
42
+# ffmpeg http://localhost:8090/feed1.ffm
43
+
44
+# avserver can also do time shifting. It means that it can stream any
45
+# previously recorded live stream. The request should contain:
46
+# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify
47
+# a path where the feed is stored on disk. You also specify the
48
+# maximum size of the feed, where zero means unlimited. Default:
49
+# File=/tmp/feed_name.ffm FileMaxSize=5M
50
+File /tmp/feed1.ffm
51
+FileMaxSize 200K
52
+
53
+# You could specify
54
+# ReadOnlyFile /saved/specialvideo.ffm
55
+# This marks the file as readonly and it will not be deleted or updated.
56
+
57
+# Specify launch in order to start ffmpeg automatically.
58
+# First ffmpeg must be defined with an appropriate path if needed,
59
+# after that options can follow, but avoid adding the http:// field
60
+#Launch ffmpeg
61
+
62
+# Only allow connections from localhost to the feed.
63
+ACL allow 127.0.0.1
64
+
65
+</Feed>
66
+
67
+
68
+##################################################################
69
+# Now you can define each stream which will be generated from the
70
+# original audio and video stream. Each format has a filename (here
71
+# 'test1.mpg'). AVServer will send this stream when answering a
72
+# request containing this filename.
73
+
74
+<Stream test1.mpg>
75
+
76
+# coming from live feed 'feed1'
77
+Feed feed1.ffm
78
+
79
+# Format of the stream : you can choose among:
80
+# mpeg       : MPEG-1 multiplexed video and audio
81
+# mpegvideo  : only MPEG-1 video
82
+# mp2        : MPEG-2 audio (use AudioCodec to select layer 2 and 3 codec)
83
+# ogg        : Ogg format (Vorbis audio codec)
84
+# rm         : RealNetworks-compatible stream. Multiplexed audio and video.
85
+# ra         : RealNetworks-compatible stream. Audio only.
86
+# mpjpeg     : Multipart JPEG (works with Netscape without any plugin)
87
+# jpeg       : Generate a single JPEG image.
88
+# asf        : ASF compatible streaming (Windows Media Player format).
89
+# swf        : Macromedia Flash compatible stream
90
+# avi        : AVI format (MPEG-4 video, MPEG audio sound)
91
+Format mpeg
92
+
93
+# Bitrate for the audio stream. Codecs usually support only a few
94
+# different bitrates.
95
+AudioBitRate 32
96
+
97
+# Number of audio channels: 1 = mono, 2 = stereo
98
+AudioChannels 1
99
+
100
+# Sampling frequency for audio. When using low bitrates, you should
101
+# lower this frequency to 22050 or 11025. The supported frequencies
102
+# depend on the selected audio codec.
103
+AudioSampleRate 44100
104
+
105
+# Bitrate for the video stream
106
+VideoBitRate 64
107
+
108
+# Ratecontrol buffer size
109
+VideoBufferSize 40
110
+
111
+# Number of frames per second
112
+VideoFrameRate 3
113
+
114
+# Size of the video frame: WxH (default: 160x128)
115
+# The following abbreviations are defined: sqcif, qcif, cif, 4cif, qqvga,
116
+# qvga, vga, svga, xga, uxga, qxga, sxga, qsxga, hsxga, wvga, wxga, wsxga,
117
+# wuxga, woxga, wqsxga, wquxga, whsxga, whuxga, cga, ega, hd480, hd720,
118
+# hd1080
119
+VideoSize 160x128
120
+
121
+# Transmit only intra frames (useful for low bitrates, but kills frame rate).
122
+#VideoIntraOnly
123
+
124
+# If non-intra only, an intra frame is transmitted every VideoGopSize
125
+# frames. Video synchronization can only begin at an intra frame.
126
+VideoGopSize 12
127
+
128
+# More MPEG-4 parameters
129
+# VideoHighQuality
130
+# Video4MotionVector
131
+
132
+# Choose your codecs:
133
+#AudioCodec mp2
134
+#VideoCodec mpeg1video
135
+
136
+# Suppress audio
137
+#NoAudio
138
+
139
+# Suppress video
140
+#NoVideo
141
+
142
+#VideoQMin 3
143
+#VideoQMax 31
144
+
145
+# Set this to the number of seconds backwards in time to start. Note that
146
+# most players will buffer 5-10 seconds of video, and also you need to allow
147
+# for a keyframe to appear in the data stream.
148
+#Preroll 15
149
+
150
+# ACL:
151
+
152
+# You can allow ranges of addresses (or single addresses)
153
+#ACL ALLOW <first address> <last address>
154
+
155
+# You can deny ranges of addresses (or single addresses)
156
+#ACL DENY <first address> <last address>
157
+
158
+# You can repeat the ACL allow/deny as often as you like. It is on a per
159
+# stream basis. The first match defines the action. If there are no matches,
160
+# then the default is the inverse of the last ACL statement.
161
+#
162
+# Thus 'ACL allow localhost' only allows access from localhost.
163
+# 'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and
164
+# allow everybody else.
165
+
166
+</Stream>
167
+
168
+
169
+##################################################################
170
+# Example streams
171
+
172
+
173
+# Multipart JPEG
174
+
175
+#<Stream test.mjpg>
176
+#Feed feed1.ffm
177
+#Format mpjpeg
178
+#VideoFrameRate 2
179
+#VideoIntraOnly
180
+#NoAudio
181
+#Strict -1
182
+#</Stream>
183
+
184
+
185
+# Single JPEG
186
+
187
+#<Stream test.jpg>
188
+#Feed feed1.ffm
189
+#Format jpeg
190
+#VideoFrameRate 2
191
+#VideoIntraOnly
192
+##VideoSize 352x240
193
+#NoAudio
194
+#Strict -1
195
+#</Stream>
196
+
197
+
198
+# Flash
199
+
200
+#<Stream test.swf>
201
+#Feed feed1.ffm
202
+#Format swf
203
+#VideoFrameRate 2
204
+#VideoIntraOnly
205
+#NoAudio
206
+#</Stream>
207
+
208
+
209
+# ASF compatible
210
+
211
+<Stream test.asf>
212
+Feed feed1.ffm
213
+Format asf
214
+VideoFrameRate 15
215
+VideoSize 352x240
216
+VideoBitRate 256
217
+VideoBufferSize 40
218
+VideoGopSize 30
219
+AudioBitRate 64
220
+StartSendOnKey
221
+</Stream>
222
+
223
+
224
+# MP3 audio
225
+
226
+#<Stream test.mp3>
227
+#Feed feed1.ffm
228
+#Format mp2
229
+#AudioCodec mp3
230
+#AudioBitRate 64
231
+#AudioChannels 1
232
+#AudioSampleRate 44100
233
+#NoVideo
234
+#</Stream>
235
+
236
+
237
+# Ogg Vorbis audio
238
+
239
+#<Stream test.ogg>
240
+#Feed feed1.ffm
241
+#Title "Stream title"
242
+#AudioBitRate 64
243
+#AudioChannels 2
244
+#AudioSampleRate 44100
245
+#NoVideo
246
+#</Stream>
247
+
248
+
249
+# Real with audio only at 32 kbits
250
+
251
+#<Stream test.ra>
252
+#Feed feed1.ffm
253
+#Format rm
254
+#AudioBitRate 32
255
+#NoVideo
256
+#NoAudio
257
+#</Stream>
258
+
259
+
260
+# Real with audio and video at 64 kbits
261
+
262
+#<Stream test.rm>
263
+#Feed feed1.ffm
264
+#Format rm
265
+#AudioBitRate 32
266
+#VideoBitRate 128
267
+#VideoFrameRate 25
268
+#VideoGopSize 25
269
+#NoAudio
270
+#</Stream>
271
+
272
+
273
+##################################################################
274
+# A stream coming from a file: you only need to set the input
275
+# filename and optionally a new format. Supported conversions:
276
+#    AVI -> ASF
277
+
278
+#<Stream file.rm>
279
+#File "/usr/local/httpd/htdocs/tlive.rm"
280
+#NoAudio
281
+#</Stream>
282
+
283
+#<Stream file.asf>
284
+#File "/usr/local/httpd/htdocs/test.asf"
285
+#NoAudio
286
+#Author "Me"
287
+#Copyright "Super MegaCorp"
288
+#Title "Test stream from disk"
289
+#Comment "Test comment"
290
+#</Stream>
291
+
292
+
293
+##################################################################
294
+# RTSP examples
295
+#
296
+# You can access this stream with the RTSP URL:
297
+#   rtsp://localhost:5454/test1-rtsp.mpg
298
+#
299
+# A non-standard RTSP redirector is also created. Its URL is:
300
+#   http://localhost:8090/test1-rtsp.rtsp
301
+
302
+#<Stream test1-rtsp.mpg>
303
+#Format rtp
304
+#File "/usr/local/httpd/htdocs/test1.mpg"
305
+#</Stream>
306
+
307
+
308
+# Transcode an incoming live feed to another live feed,
309
+# using libx264 and video presets
310
+
311
+#<Stream live.h264>
312
+#Format rtp
313
+#Feed feed1.ffm
314
+#VideoCodec libx264
315
+#VideoFrameRate 24
316
+#VideoBitRate 100
317
+#VideoSize 480x272
318
+#AVPresetVideo default
319
+#AVPresetVideo baseline
320
+#AVOptionVideo flags +global_header
321
+#
322
+#AudioCodec libfaac
323
+#AudioBitRate 32
324
+#AudioChannels 2
325
+#AudioSampleRate 22050
326
+#AVOptionAudio flags +global_header
327
+#</Stream>
328
+
329
+##################################################################
330
+# SDP/multicast examples
331
+#
332
+# If you want to send your stream in multicast, you must set the
333
+# multicast address with MulticastAddress. The port and the TTL can
334
+# also be set.
335
+#
336
+# An SDP file is automatically generated by avserver by adding the
337
+# 'sdp' extension to the stream name (here
338
+# http://localhost:8090/test1-sdp.sdp). You should usually give this
339
+# file to your player to play the stream.
340
+#
341
+# The 'NoLoop' option can be used to avoid looping when the stream is
342
+# terminated.
343
+
344
+#<Stream test1-sdp.mpg>
345
+#Format rtp
346
+#File "/usr/local/httpd/htdocs/test1.mpg"
347
+#MulticastAddress 224.124.0.1
348
+#MulticastPort 5000
349
+#MulticastTTL 16
350
+#NoLoop
351
+#</Stream>
352
+
353
+
354
+##################################################################
355
+# Special streams
356
+
357
+# Server status
358
+
359
+<Stream stat.html>
360
+Format status
361
+
362
+# Only allow local people to get the status
363
+ACL allow localhost
364
+ACL allow 192.168.0.0 192.168.255.255
365
+
366
+#FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico
367
+</Stream>
368
+
369
+
370
+# Redirect index.html to the appropriate site
371
+
372
+<Redirect index.html>
373
+URL http://www.libav.org/
374
+</Redirect>
375
+
376
+
0 377
new file mode 100644
... ...
@@ -0,0 +1,278 @@
0
+\input texinfo @c -*- texinfo -*-
1
+
2
+@settitle avserver Documentation
3
+@titlepage
4
+@center @titlefont{avserver Documentation}
5
+@end titlepage
6
+
7
+@top
8
+
9
+@contents
10
+
11
+@chapter Synopsys
12
+
13
+The generic syntax is:
14
+
15
+@example
16
+@c man begin SYNOPSIS
17
+avserver [options]
18
+@c man end
19
+@end example
20
+
21
+@chapter Description
22
+@c man begin DESCRIPTION
23
+
24
+avserver is a streaming server for both audio and video. It supports
25
+several live feeds, streaming from files and time shifting on live feeds
26
+(you can seek to positions in the past on each live feed, provided you
27
+specify a big enough feed storage in avserver.conf).
28
+
29
+avserver runs in daemon mode by default; that is, it puts itself in
30
+the background and detaches from its TTY, unless it is launched in
31
+debug mode or a NoDaemon option is specified in the configuration
32
+file.
33
+
34
+This documentation covers only the streaming aspects of avserver /
35
+ffmpeg. All questions about parameters for ffmpeg, codec questions,
36
+etc. are not covered here. Read @file{ffmpeg-doc.html} for more
37
+information.
38
+
39
+@section How does it work?
40
+
41
+avserver receives prerecorded files or FFM streams from some ffmpeg
42
+instance as input, then streams them over RTP/RTSP/HTTP.
43
+
44
+An avserver instance will listen on some port as specified in the
45
+configuration file. You can launch one or more instances of ffmpeg and
46
+send one or more FFM streams to the port where avserver is expecting
47
+to receive them. Alternately, you can make avserver launch such ffmpeg
48
+instances at startup.
49
+
50
+Input streams are called feeds, and each one is specified by a <Feed>
51
+section in the configuration file.
52
+
53
+For each feed you can have different output streams in various
54
+formats, each one specified by a <Stream> section in the configuration
55
+file.
56
+
57
+@section Status stream
58
+
59
+avserver supports an HTTP interface which exposes the current status
60
+of the server.
61
+
62
+Simply point your browser to the address of the special status stream
63
+specified in the configuration file.
64
+
65
+For example if you have:
66
+@example
67
+<Stream status.html>
68
+Format status
69
+
70
+# Only allow local people to get the status
71
+ACL allow localhost
72
+ACL allow 192.168.0.0 192.168.255.255
73
+</Stream>
74
+@end example
75
+
76
+then the server will post a page with the status information when
77
+the special stream @file{status.html} is requested.
78
+
79
+@section What can this do?
80
+
81
+When properly configured and running, you can capture video and audio in real
82
+time from a suitable capture card, and stream it out over the Internet to
83
+either Windows Media Player or RealAudio player (with some restrictions).
84
+
85
+It can also stream from files, though that is currently broken. Very often, a
86
+web server can be used to serve up the files just as well.
87
+
88
+It can stream prerecorded video from .ffm files, though it is somewhat tricky
89
+to make it work correctly.
90
+
91
+@section What do I need?
92
+
93
+I use Linux on a 900 MHz Duron with a cheapo Bt848 based TV capture card. I'm
94
+using stock Linux 2.4.17 with the stock drivers. [Actually that isn't true,
95
+I needed some special drivers for my motherboard-based sound card.]
96
+
97
+I understand that FreeBSD systems work just fine as well.
98
+
99
+@section How do I make it work?
100
+
101
+First, build the kit. It *really* helps to have installed LAME first. Then when
102
+you run the avserver ./configure, make sure that you have the
103
+@code{--enable-libmp3lame} flag turned on.
104
+
105
+LAME is important as it allows for streaming audio to Windows Media Player.
106
+Don't ask why the other audio types do not work.
107
+
108
+As a simple test, just run the following two command lines where INPUTFILE
109
+is some file which you can decode with ffmpeg:
110
+
111
+@example
112
+./avserver -f doc/avserver.conf &
113
+./ffmpeg -i INPUTFILE http://localhost:8090/feed1.ffm
114
+@end example
115
+
116
+At this point you should be able to go to your Windows machine and fire up
117
+Windows Media Player (WMP). Go to Open URL and enter
118
+
119
+@example
120
+    http://<linuxbox>:8090/test.asf
121
+@end example
122
+
123
+You should (after a short delay) see video and hear audio.
124
+
125
+WARNING: trying to stream test1.mpg doesn't work with WMP as it tries to
126
+transfer the entire file before starting to play.
127
+The same is true of AVI files.
128
+
129
+@section What happens next?
130
+
131
+You should edit the avserver.conf file to suit your needs (in terms of
132
+frame rates etc). Then install avserver and ffmpeg, write a script to start
133
+them up, and off you go.
134
+
135
+@section Troubleshooting
136
+
137
+@subsection I don't hear any audio, but video is fine.
138
+
139
+Maybe you didn't install LAME, or got your ./configure statement wrong. Check
140
+the ffmpeg output to see if a line referring to MP3 is present. If not, then
141
+your configuration was incorrect. If it is, then maybe your wiring is not
142
+set up correctly. Maybe the sound card is not getting data from the right
143
+input source. Maybe you have a really awful audio interface (like I do)
144
+that only captures in stereo and also requires that one channel be flipped.
145
+If you are one of these people, then export 'AUDIO_FLIP_LEFT=1' before
146
+starting ffmpeg.
147
+
148
+@subsection The audio and video loose sync after a while.
149
+
150
+Yes, they do.
151
+
152
+@subsection After a long while, the video update rate goes way down in WMP.
153
+
154
+Yes, it does. Who knows why?
155
+
156
+@subsection WMP 6.4 behaves differently to WMP 7.
157
+
158
+Yes, it does. Any thoughts on this would be gratefully received. These
159
+differences extend to embedding WMP into a web page. [There are two
160
+object IDs that you can use: The old one, which does not play well, and
161
+the new one, which does (both tested on the same system). However,
162
+I suspect that the new one is not available unless you have installed WMP 7].
163
+
164
+@section What else can it do?
165
+
166
+You can replay video from .ffm files that was recorded earlier.
167
+However, there are a number of caveats, including the fact that the
168
+avserver parameters must match the original parameters used to record the
169
+file. If they do not, then avserver deletes the file before recording into it.
170
+(Now that I write this, it seems broken).
171
+
172
+You can fiddle with many of the codec choices and encoding parameters, and
173
+there are a bunch more parameters that you cannot control. Post a message
174
+to the mailing list if there are some 'must have' parameters. Look in
175
+avserver.conf for a list of the currently available controls.
176
+
177
+It will automatically generate the ASX or RAM files that are often used
178
+in browsers. These files are actually redirections to the underlying ASF
179
+or RM file. The reason for this is that the browser often fetches the
180
+entire file before starting up the external viewer. The redirection files
181
+are very small and can be transferred quickly. [The stream itself is
182
+often 'infinite' and thus the browser tries to download it and never
183
+finishes.]
184
+
185
+@section Tips
186
+
187
+* When you connect to a live stream, most players (WMP, RA, etc) want to
188
+buffer a certain number of seconds of material so that they can display the
189
+signal continuously. However, avserver (by default) starts sending data
190
+in realtime. This means that there is a pause of a few seconds while the
191
+buffering is being done by the player. The good news is that this can be
192
+cured by adding a '?buffer=5' to the end of the URL. This means that the
193
+stream should start 5 seconds in the past -- and so the first 5 seconds
194
+of the stream are sent as fast as the network will allow. It will then
195
+slow down to real time. This noticeably improves the startup experience.
196
+
197
+You can also add a 'Preroll 15' statement into the avserver.conf that will
198
+add the 15 second prebuffering on all requests that do not otherwise
199
+specify a time. In addition, avserver will skip frames until a key_frame
200
+is found. This further reduces the startup delay by not transferring data
201
+that will be discarded.
202
+
203
+* You may want to adjust the MaxBandwidth in the avserver.conf to limit
204
+the amount of bandwidth consumed by live streams.
205
+
206
+@section Why does the ?buffer / Preroll stop working after a time?
207
+
208
+It turns out that (on my machine at least) the number of frames successfully
209
+grabbed is marginally less than the number that ought to be grabbed. This
210
+means that the timestamp in the encoded data stream gets behind realtime.
211
+This means that if you say 'Preroll 10', then when the stream gets 10
212
+or more seconds behind, there is no Preroll left.
213
+
214
+Fixing this requires a change in the internals of how timestamps are
215
+handled.
216
+
217
+@section Does the @code{?date=} stuff work.
218
+
219
+Yes (subject to the limitation outlined above). Also note that whenever you
220
+start avserver, it deletes the ffm file (if any parameters have changed),
221
+thus wiping out what you had recorded before.
222
+
223
+The format of the @code{?date=xxxxxx} is fairly flexible. You should use one
224
+of the following formats (the 'T' is literal):
225
+
226
+@example
227
+* YYYY-MM-DDTHH:MM:SS     (localtime)
228
+* YYYY-MM-DDTHH:MM:SSZ    (UTC)
229
+@end example
230
+
231
+You can omit the YYYY-MM-DD, and then it refers to the current day. However
232
+note that @samp{?date=16:00:00} refers to 16:00 on the current day -- this
233
+may be in the future and so is unlikely to be useful.
234
+
235
+You use this by adding the ?date= to the end of the URL for the stream.
236
+For example:   @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}.
237
+@c man end
238
+
239
+@chapter Options
240
+@c man begin OPTIONS
241
+
242
+@include fftools-common-opts.texi
243
+
244
+@section Main options
245
+
246
+@table @option
247
+@item -f @var{configfile}
248
+Use @file{configfile} instead of @file{/etc/avserver.conf}.
249
+@item -n
250
+Enable no-launch mode. This option disables all the Launch directives
251
+within the various <Stream> sections. Since avserver will not launch
252
+any ffmpeg instances, you will have to launch them manually.
253
+@item -d
254
+Enable debug mode. This option increases log verbosity, directs log
255
+messages to stdout and causes avserver to run in the foreground
256
+rather than as a daemon.
257
+@end table
258
+@c man end
259
+
260
+@ignore
261
+
262
+@setfilename avserver
263
+@settitle avserver video server
264
+
265
+@c man begin SEEALSO
266
+
267
+ffmpeg(1), avplay(1), avprobe(1), the @file{ffmpeg/doc/avserver.conf}
268
+example and the Libav HTML documentation
269
+@c man end
270
+
271
+@c man begin AUTHORS
272
+The Libav developers
273
+@c man end
274
+
275
+@end ignore
276
+
277
+@bye
... ...
@@ -164,7 +164,7 @@ Set the number of video frames to record.
164 164
 @item -r @var{fps}
165 165
 Set frame rate (Hz value, fraction or abbreviation), (default = 25).
166 166
 @item -s @var{size}
167
-Set frame size. The format is @samp{wxh} (ffserver default = 160x128, ffmpeg default = same as source).
167
+Set frame size. The format is @samp{wxh} (avserver default = 160x128, ffmpeg default = same as source).
168 168
 The following abbreviations are recognized:
169 169
 @table @samp
170 170
 @item sqcif
... ...
@@ -726,7 +726,7 @@ Set RTP payload size in bytes.
726 726
 Read input at native frame rate. Mainly used to simulate a grab device.
727 727
 @item -loop_input
728 728
 Loop over the input stream. Currently it works only for image
729
-streams. This option is used for automatic FFserver testing.
729
+streams. This option is used for automatic AVserver testing.
730 730
 This option is deprecated, use -loop.
731 731
 @item -loop_output @var{number_of_times}
732 732
 Repeatedly loop output for formats that support looping such as animated GIF
... ...
@@ -1079,7 +1079,7 @@ file to which you want to add them.
1079 1079
 @settitle ffmpeg video converter
1080 1080
 
1081 1081
 @c man begin SEEALSO
1082
-avplay(1), avprobe(1), ffserver(1) and the Libav HTML documentation
1082
+avplay(1), avprobe(1), avserver(1) and the Libav HTML documentation
1083 1083
 @c man end
1084 1084
 
1085 1085
 @c man begin AUTHORS
1086 1086
deleted file mode 100644
... ...
@@ -1,377 +0,0 @@
1
-# Port on which the server is listening. You must select a different
2
-# port from your standard HTTP web server if it is running on the same
3
-# computer.
4
-Port 8090
5
-
6
-# Address on which the server is bound. Only useful if you have
7
-# several network interfaces.
8
-BindAddress 0.0.0.0
9
-
10
-# Number of simultaneous HTTP connections that can be handled. It has
11
-# to be defined *before* the MaxClients parameter, since it defines the
12
-# MaxClients maximum limit.
13
-MaxHTTPConnections 2000
14
-
15
-# Number of simultaneous requests that can be handled. Since FFServer
16
-# is very fast, it is more likely that you will want to leave this high
17
-# and use MaxBandwidth, below.
18
-MaxClients 1000
19
-
20
-# This the maximum amount of kbit/sec that you are prepared to
21
-# consume when streaming to clients.
22
-MaxBandwidth 1000
23
-
24
-# Access log file (uses standard Apache log file format)
25
-# '-' is the standard output.
26
-CustomLog -
27
-
28
-# Suppress that if you want to launch ffserver as a daemon.
29
-NoDaemon
30
-
31
-
32
-##################################################################
33
-# Definition of the live feeds. Each live feed contains one video
34
-# and/or audio sequence coming from an ffmpeg encoder or another
35
-# ffserver. This sequence may be encoded simultaneously with several
36
-# codecs at several resolutions.
37
-
38
-<Feed feed1.ffm>
39
-
40
-# You must use 'ffmpeg' to send a live feed to ffserver. In this
41
-# example, you can type:
42
-#
43
-# ffmpeg http://localhost:8090/feed1.ffm
44
-
45
-# ffserver can also do time shifting. It means that it can stream any
46
-# previously recorded live stream. The request should contain:
47
-# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify
48
-# a path where the feed is stored on disk. You also specify the
49
-# maximum size of the feed, where zero means unlimited. Default:
50
-# File=/tmp/feed_name.ffm FileMaxSize=5M
51
-File /tmp/feed1.ffm
52
-FileMaxSize 200K
53
-
54
-# You could specify
55
-# ReadOnlyFile /saved/specialvideo.ffm
56
-# This marks the file as readonly and it will not be deleted or updated.
57
-
58
-# Specify launch in order to start ffmpeg automatically.
59
-# First ffmpeg must be defined with an appropriate path if needed,
60
-# after that options can follow, but avoid adding the http:// field
61
-#Launch ffmpeg
62
-
63
-# Only allow connections from localhost to the feed.
64
-ACL allow 127.0.0.1
65
-
66
-</Feed>
67
-
68
-
69
-##################################################################
70
-# Now you can define each stream which will be generated from the
71
-# original audio and video stream. Each format has a filename (here
72
-# 'test1.mpg'). FFServer will send this stream when answering a
73
-# request containing this filename.
74
-
75
-<Stream test1.mpg>
76
-
77
-# coming from live feed 'feed1'
78
-Feed feed1.ffm
79
-
80
-# Format of the stream : you can choose among:
81
-# mpeg       : MPEG-1 multiplexed video and audio
82
-# mpegvideo  : only MPEG-1 video
83
-# mp2        : MPEG-2 audio (use AudioCodec to select layer 2 and 3 codec)
84
-# ogg        : Ogg format (Vorbis audio codec)
85
-# rm         : RealNetworks-compatible stream. Multiplexed audio and video.
86
-# ra         : RealNetworks-compatible stream. Audio only.
87
-# mpjpeg     : Multipart JPEG (works with Netscape without any plugin)
88
-# jpeg       : Generate a single JPEG image.
89
-# asf        : ASF compatible streaming (Windows Media Player format).
90
-# swf        : Macromedia Flash compatible stream
91
-# avi        : AVI format (MPEG-4 video, MPEG audio sound)
92
-Format mpeg
93
-
94
-# Bitrate for the audio stream. Codecs usually support only a few
95
-# different bitrates.
96
-AudioBitRate 32
97
-
98
-# Number of audio channels: 1 = mono, 2 = stereo
99
-AudioChannels 1
100
-
101
-# Sampling frequency for audio. When using low bitrates, you should
102
-# lower this frequency to 22050 or 11025. The supported frequencies
103
-# depend on the selected audio codec.
104
-AudioSampleRate 44100
105
-
106
-# Bitrate for the video stream
107
-VideoBitRate 64
108
-
109
-# Ratecontrol buffer size
110
-VideoBufferSize 40
111
-
112
-# Number of frames per second
113
-VideoFrameRate 3
114
-
115
-# Size of the video frame: WxH (default: 160x128)
116
-# The following abbreviations are defined: sqcif, qcif, cif, 4cif, qqvga,
117
-# qvga, vga, svga, xga, uxga, qxga, sxga, qsxga, hsxga, wvga, wxga, wsxga,
118
-# wuxga, woxga, wqsxga, wquxga, whsxga, whuxga, cga, ega, hd480, hd720,
119
-# hd1080
120
-VideoSize 160x128
121
-
122
-# Transmit only intra frames (useful for low bitrates, but kills frame rate).
123
-#VideoIntraOnly
124
-
125
-# If non-intra only, an intra frame is transmitted every VideoGopSize
126
-# frames. Video synchronization can only begin at an intra frame.
127
-VideoGopSize 12
128
-
129
-# More MPEG-4 parameters
130
-# VideoHighQuality
131
-# Video4MotionVector
132
-
133
-# Choose your codecs:
134
-#AudioCodec mp2
135
-#VideoCodec mpeg1video
136
-
137
-# Suppress audio
138
-#NoAudio
139
-
140
-# Suppress video
141
-#NoVideo
142
-
143
-#VideoQMin 3
144
-#VideoQMax 31
145
-
146
-# Set this to the number of seconds backwards in time to start. Note that
147
-# most players will buffer 5-10 seconds of video, and also you need to allow
148
-# for a keyframe to appear in the data stream.
149
-#Preroll 15
150
-
151
-# ACL:
152
-
153
-# You can allow ranges of addresses (or single addresses)
154
-#ACL ALLOW <first address> <last address>
155
-
156
-# You can deny ranges of addresses (or single addresses)
157
-#ACL DENY <first address> <last address>
158
-
159
-# You can repeat the ACL allow/deny as often as you like. It is on a per
160
-# stream basis. The first match defines the action. If there are no matches,
161
-# then the default is the inverse of the last ACL statement.
162
-#
163
-# Thus 'ACL allow localhost' only allows access from localhost.
164
-# 'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and
165
-# allow everybody else.
166
-
167
-</Stream>
168
-
169
-
170
-##################################################################
171
-# Example streams
172
-
173
-
174
-# Multipart JPEG
175
-
176
-#<Stream test.mjpg>
177
-#Feed feed1.ffm
178
-#Format mpjpeg
179
-#VideoFrameRate 2
180
-#VideoIntraOnly
181
-#NoAudio
182
-#Strict -1
183
-#</Stream>
184
-
185
-
186
-# Single JPEG
187
-
188
-#<Stream test.jpg>
189
-#Feed feed1.ffm
190
-#Format jpeg
191
-#VideoFrameRate 2
192
-#VideoIntraOnly
193
-##VideoSize 352x240
194
-#NoAudio
195
-#Strict -1
196
-#</Stream>
197
-
198
-
199
-# Flash
200
-
201
-#<Stream test.swf>
202
-#Feed feed1.ffm
203
-#Format swf
204
-#VideoFrameRate 2
205
-#VideoIntraOnly
206
-#NoAudio
207
-#</Stream>
208
-
209
-
210
-# ASF compatible
211
-
212
-<Stream test.asf>
213
-Feed feed1.ffm
214
-Format asf
215
-VideoFrameRate 15
216
-VideoSize 352x240
217
-VideoBitRate 256
218
-VideoBufferSize 40
219
-VideoGopSize 30
220
-AudioBitRate 64
221
-StartSendOnKey
222
-</Stream>
223
-
224
-
225
-# MP3 audio
226
-
227
-#<Stream test.mp3>
228
-#Feed feed1.ffm
229
-#Format mp2
230
-#AudioCodec mp3
231
-#AudioBitRate 64
232
-#AudioChannels 1
233
-#AudioSampleRate 44100
234
-#NoVideo
235
-#</Stream>
236
-
237
-
238
-# Ogg Vorbis audio
239
-
240
-#<Stream test.ogg>
241
-#Feed feed1.ffm
242
-#Title "Stream title"
243
-#AudioBitRate 64
244
-#AudioChannels 2
245
-#AudioSampleRate 44100
246
-#NoVideo
247
-#</Stream>
248
-
249
-
250
-# Real with audio only at 32 kbits
251
-
252
-#<Stream test.ra>
253
-#Feed feed1.ffm
254
-#Format rm
255
-#AudioBitRate 32
256
-#NoVideo
257
-#NoAudio
258
-#</Stream>
259
-
260
-
261
-# Real with audio and video at 64 kbits
262
-
263
-#<Stream test.rm>
264
-#Feed feed1.ffm
265
-#Format rm
266
-#AudioBitRate 32
267
-#VideoBitRate 128
268
-#VideoFrameRate 25
269
-#VideoGopSize 25
270
-#NoAudio
271
-#</Stream>
272
-
273
-
274
-##################################################################
275
-# A stream coming from a file: you only need to set the input
276
-# filename and optionally a new format. Supported conversions:
277
-#    AVI -> ASF
278
-
279
-#<Stream file.rm>
280
-#File "/usr/local/httpd/htdocs/tlive.rm"
281
-#NoAudio
282
-#</Stream>
283
-
284
-#<Stream file.asf>
285
-#File "/usr/local/httpd/htdocs/test.asf"
286
-#NoAudio
287
-#Author "Me"
288
-#Copyright "Super MegaCorp"
289
-#Title "Test stream from disk"
290
-#Comment "Test comment"
291
-#</Stream>
292
-
293
-
294
-##################################################################
295
-# RTSP examples
296
-#
297
-# You can access this stream with the RTSP URL:
298
-#   rtsp://localhost:5454/test1-rtsp.mpg
299
-#
300
-# A non-standard RTSP redirector is also created. Its URL is:
301
-#   http://localhost:8090/test1-rtsp.rtsp
302
-
303
-#<Stream test1-rtsp.mpg>
304
-#Format rtp
305
-#File "/usr/local/httpd/htdocs/test1.mpg"
306
-#</Stream>
307
-
308
-
309
-# Transcode an incoming live feed to another live feed,
310
-# using libx264 and video presets
311
-
312
-#<Stream live.h264>
313
-#Format rtp
314
-#Feed feed1.ffm
315
-#VideoCodec libx264
316
-#VideoFrameRate 24
317
-#VideoBitRate 100
318
-#VideoSize 480x272
319
-#AVPresetVideo default
320
-#AVPresetVideo baseline
321
-#AVOptionVideo flags +global_header
322
-#
323
-#AudioCodec libfaac
324
-#AudioBitRate 32
325
-#AudioChannels 2
326
-#AudioSampleRate 22050
327
-#AVOptionAudio flags +global_header
328
-#</Stream>
329
-
330
-##################################################################
331
-# SDP/multicast examples
332
-#
333
-# If you want to send your stream in multicast, you must set the
334
-# multicast address with MulticastAddress. The port and the TTL can
335
-# also be set.
336
-#
337
-# An SDP file is automatically generated by ffserver by adding the
338
-# 'sdp' extension to the stream name (here
339
-# http://localhost:8090/test1-sdp.sdp). You should usually give this
340
-# file to your player to play the stream.
341
-#
342
-# The 'NoLoop' option can be used to avoid looping when the stream is
343
-# terminated.
344
-
345
-#<Stream test1-sdp.mpg>
346
-#Format rtp
347
-#File "/usr/local/httpd/htdocs/test1.mpg"
348
-#MulticastAddress 224.124.0.1
349
-#MulticastPort 5000
350
-#MulticastTTL 16
351
-#NoLoop
352
-#</Stream>
353
-
354
-
355
-##################################################################
356
-# Special streams
357
-
358
-# Server status
359
-
360
-<Stream stat.html>
361
-Format status
362
-
363
-# Only allow local people to get the status
364
-ACL allow localhost
365
-ACL allow 192.168.0.0 192.168.255.255
366
-
367
-#FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico
368
-</Stream>
369
-
370
-
371
-# Redirect index.html to the appropriate site
372
-
373
-<Redirect index.html>
374
-URL http://www.libav.org/
375
-</Redirect>
376
-
377
-
378 1
deleted file mode 100644
... ...
@@ -1,278 +0,0 @@
1
-\input texinfo @c -*- texinfo -*-
2
-
3
-@settitle ffserver Documentation
4
-@titlepage
5
-@center @titlefont{ffserver Documentation}
6
-@end titlepage
7
-
8
-@top
9
-
10
-@contents
11
-
12
-@chapter Synopsys
13
-
14
-The generic syntax is:
15
-
16
-@example
17
-@c man begin SYNOPSIS
18
-ffserver [options]
19
-@c man end
20
-@end example
21
-
22
-@chapter Description
23
-@c man begin DESCRIPTION
24
-
25
-ffserver is a streaming server for both audio and video. It supports
26
-several live feeds, streaming from files and time shifting on live feeds
27
-(you can seek to positions in the past on each live feed, provided you
28
-specify a big enough feed storage in ffserver.conf).
29
-
30
-ffserver runs in daemon mode by default; that is, it puts itself in
31
-the background and detaches from its TTY, unless it is launched in
32
-debug mode or a NoDaemon option is specified in the configuration
33
-file.
34
-
35
-This documentation covers only the streaming aspects of ffserver /
36
-ffmpeg. All questions about parameters for ffmpeg, codec questions,
37
-etc. are not covered here. Read @file{ffmpeg-doc.html} for more
38
-information.
39
-
40
-@section How does it work?
41
-
42
-ffserver receives prerecorded files or FFM streams from some ffmpeg
43
-instance as input, then streams them over RTP/RTSP/HTTP.
44
-
45
-An ffserver instance will listen on some port as specified in the
46
-configuration file. You can launch one or more instances of ffmpeg and
47
-send one or more FFM streams to the port where ffserver is expecting
48
-to receive them. Alternately, you can make ffserver launch such ffmpeg
49
-instances at startup.
50
-
51
-Input streams are called feeds, and each one is specified by a <Feed>
52
-section in the configuration file.
53
-
54
-For each feed you can have different output streams in various
55
-formats, each one specified by a <Stream> section in the configuration
56
-file.
57
-
58
-@section Status stream
59
-
60
-ffserver supports an HTTP interface which exposes the current status
61
-of the server.
62
-
63
-Simply point your browser to the address of the special status stream
64
-specified in the configuration file.
65
-
66
-For example if you have:
67
-@example
68
-<Stream status.html>
69
-Format status
70
-
71
-# Only allow local people to get the status
72
-ACL allow localhost
73
-ACL allow 192.168.0.0 192.168.255.255
74
-</Stream>
75
-@end example
76
-
77
-then the server will post a page with the status information when
78
-the special stream @file{status.html} is requested.
79
-
80
-@section What can this do?
81
-
82
-When properly configured and running, you can capture video and audio in real
83
-time from a suitable capture card, and stream it out over the Internet to
84
-either Windows Media Player or RealAudio player (with some restrictions).
85
-
86
-It can also stream from files, though that is currently broken. Very often, a
87
-web server can be used to serve up the files just as well.
88
-
89
-It can stream prerecorded video from .ffm files, though it is somewhat tricky
90
-to make it work correctly.
91
-
92
-@section What do I need?
93
-
94
-I use Linux on a 900 MHz Duron with a cheapo Bt848 based TV capture card. I'm
95
-using stock Linux 2.4.17 with the stock drivers. [Actually that isn't true,
96
-I needed some special drivers for my motherboard-based sound card.]
97
-
98
-I understand that FreeBSD systems work just fine as well.
99
-
100
-@section How do I make it work?
101
-
102
-First, build the kit. It *really* helps to have installed LAME first. Then when
103
-you run the ffserver ./configure, make sure that you have the
104
-@code{--enable-libmp3lame} flag turned on.
105
-
106
-LAME is important as it allows for streaming audio to Windows Media Player.
107
-Don't ask why the other audio types do not work.
108
-
109
-As a simple test, just run the following two command lines where INPUTFILE
110
-is some file which you can decode with ffmpeg:
111
-
112
-@example
113
-./ffserver -f doc/ffserver.conf &
114
-./ffmpeg -i INPUTFILE http://localhost:8090/feed1.ffm
115
-@end example
116
-
117
-At this point you should be able to go to your Windows machine and fire up
118
-Windows Media Player (WMP). Go to Open URL and enter
119
-
120
-@example
121
-    http://<linuxbox>:8090/test.asf
122
-@end example
123
-
124
-You should (after a short delay) see video and hear audio.
125
-
126
-WARNING: trying to stream test1.mpg doesn't work with WMP as it tries to
127
-transfer the entire file before starting to play.
128
-The same is true of AVI files.
129
-
130
-@section What happens next?
131
-
132
-You should edit the ffserver.conf file to suit your needs (in terms of
133
-frame rates etc). Then install ffserver and ffmpeg, write a script to start
134
-them up, and off you go.
135
-
136
-@section Troubleshooting
137
-
138
-@subsection I don't hear any audio, but video is fine.
139
-
140
-Maybe you didn't install LAME, or got your ./configure statement wrong. Check
141
-the ffmpeg output to see if a line referring to MP3 is present. If not, then
142
-your configuration was incorrect. If it is, then maybe your wiring is not
143
-set up correctly. Maybe the sound card is not getting data from the right
144
-input source. Maybe you have a really awful audio interface (like I do)
145
-that only captures in stereo and also requires that one channel be flipped.
146
-If you are one of these people, then export 'AUDIO_FLIP_LEFT=1' before
147
-starting ffmpeg.
148
-
149
-@subsection The audio and video loose sync after a while.
150
-
151
-Yes, they do.
152
-
153
-@subsection After a long while, the video update rate goes way down in WMP.
154
-
155
-Yes, it does. Who knows why?
156
-
157
-@subsection WMP 6.4 behaves differently to WMP 7.
158
-
159
-Yes, it does. Any thoughts on this would be gratefully received. These
160
-differences extend to embedding WMP into a web page. [There are two
161
-object IDs that you can use: The old one, which does not play well, and
162
-the new one, which does (both tested on the same system). However,
163
-I suspect that the new one is not available unless you have installed WMP 7].
164
-
165
-@section What else can it do?
166
-
167
-You can replay video from .ffm files that was recorded earlier.
168
-However, there are a number of caveats, including the fact that the
169
-ffserver parameters must match the original parameters used to record the
170
-file. If they do not, then ffserver deletes the file before recording into it.
171
-(Now that I write this, it seems broken).
172
-
173
-You can fiddle with many of the codec choices and encoding parameters, and
174
-there are a bunch more parameters that you cannot control. Post a message
175
-to the mailing list if there are some 'must have' parameters. Look in
176
-ffserver.conf for a list of the currently available controls.
177
-
178
-It will automatically generate the ASX or RAM files that are often used
179
-in browsers. These files are actually redirections to the underlying ASF
180
-or RM file. The reason for this is that the browser often fetches the
181
-entire file before starting up the external viewer. The redirection files
182
-are very small and can be transferred quickly. [The stream itself is
183
-often 'infinite' and thus the browser tries to download it and never
184
-finishes.]
185
-
186
-@section Tips
187
-
188
-* When you connect to a live stream, most players (WMP, RA, etc) want to
189
-buffer a certain number of seconds of material so that they can display the
190
-signal continuously. However, ffserver (by default) starts sending data
191
-in realtime. This means that there is a pause of a few seconds while the
192
-buffering is being done by the player. The good news is that this can be
193
-cured by adding a '?buffer=5' to the end of the URL. This means that the
194
-stream should start 5 seconds in the past -- and so the first 5 seconds
195
-of the stream are sent as fast as the network will allow. It will then
196
-slow down to real time. This noticeably improves the startup experience.
197
-
198
-You can also add a 'Preroll 15' statement into the ffserver.conf that will
199
-add the 15 second prebuffering on all requests that do not otherwise
200
-specify a time. In addition, ffserver will skip frames until a key_frame
201
-is found. This further reduces the startup delay by not transferring data
202
-that will be discarded.
203
-
204
-* You may want to adjust the MaxBandwidth in the ffserver.conf to limit
205
-the amount of bandwidth consumed by live streams.
206
-
207
-@section Why does the ?buffer / Preroll stop working after a time?
208
-
209
-It turns out that (on my machine at least) the number of frames successfully
210
-grabbed is marginally less than the number that ought to be grabbed. This
211
-means that the timestamp in the encoded data stream gets behind realtime.
212
-This means that if you say 'Preroll 10', then when the stream gets 10
213
-or more seconds behind, there is no Preroll left.
214
-
215
-Fixing this requires a change in the internals of how timestamps are
216
-handled.
217
-
218
-@section Does the @code{?date=} stuff work.
219
-
220
-Yes (subject to the limitation outlined above). Also note that whenever you
221
-start ffserver, it deletes the ffm file (if any parameters have changed),
222
-thus wiping out what you had recorded before.
223
-
224
-The format of the @code{?date=xxxxxx} is fairly flexible. You should use one
225
-of the following formats (the 'T' is literal):
226
-
227
-@example
228
-* YYYY-MM-DDTHH:MM:SS     (localtime)
229
-* YYYY-MM-DDTHH:MM:SSZ    (UTC)
230
-@end example
231
-
232
-You can omit the YYYY-MM-DD, and then it refers to the current day. However
233
-note that @samp{?date=16:00:00} refers to 16:00 on the current day -- this
234
-may be in the future and so is unlikely to be useful.
235
-
236
-You use this by adding the ?date= to the end of the URL for the stream.
237
-For example:   @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}.
238
-@c man end
239
-
240
-@chapter Options
241
-@c man begin OPTIONS
242
-
243
-@include fftools-common-opts.texi
244
-
245
-@section Main options
246
-
247
-@table @option
248
-@item -f @var{configfile}
249
-Use @file{configfile} instead of @file{/etc/ffserver.conf}.
250
-@item -n
251
-Enable no-launch mode. This option disables all the Launch directives
252
-within the various <Stream> sections. Since ffserver will not launch
253
-any ffmpeg instances, you will have to launch them manually.
254
-@item -d
255
-Enable debug mode. This option increases log verbosity, directs log
256
-messages to stdout and causes ffserver to run in the foreground
257
-rather than as a daemon.
258
-@end table
259
-@c man end
260
-
261
-@ignore
262
-
263
-@setfilename ffserver
264
-@settitle ffserver video server
265
-
266
-@c man begin SEEALSO
267
-
268
-ffmpeg(1), avplay(1), avprobe(1), the @file{ffmpeg/doc/ffserver.conf}
269
-example and the Libav HTML documentation
270
-@c man end
271
-
272
-@c man begin AUTHORS
273
-The Libav developers
274
-@c man end
275
-
276
-@end ignore
277
-
278
-@bye
... ...
@@ -91,7 +91,7 @@ library:
91 91
 @item Electronic Arts cdata  @tab    @tab X
92 92
 @item Electronic Arts Multimedia  @tab    @tab X
93 93
     @tab Used in various EA games; files have extensions like WVE and UV2.
94
-@item FFM (FFserver live feed)  @tab X @tab X
94
+@item FFM (AVserver live feed)  @tab X @tab X
95 95
 @item Flash (SWF)               @tab X @tab X
96 96
 @item Flash 9 (AVM2)            @tab X @tab X
97 97
     @tab Only embedded audio is decoded.
... ...
@@ -691,7 +691,7 @@ static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, AVCode
691 691
     return ost;
692 692
 }
693 693
 
694
-static int read_ffserver_streams(AVFormatContext *s, const char *filename)
694
+static int read_avserver_streams(AVFormatContext *s, const char *filename)
695 695
 {
696 696
     int i, err;
697 697
     AVFormatContext *ic = NULL;
... ...
@@ -3766,9 +3766,9 @@ static void opt_output_file(const char *filename)
3766 3766
 
3767 3767
     if (!strcmp(file_oformat->name, "ffm") &&
3768 3768
         av_strstart(filename, "http:", NULL)) {
3769
-        /* special case for files sent to ffserver: we get the stream
3770
-           parameters from ffserver */
3771
-        int err = read_ffserver_streams(oc, filename);
3769
+        /* special case for files sent to avserver: we get the stream
3770
+           parameters from avserver */
3771
+        int err = read_avserver_streams(oc, filename);
3772 3772
         if (err < 0) {
3773 3773
             print_error(filename, err);
3774 3774
             ffmpeg_exit(1);
3775 3775
deleted file mode 100644
... ...
@@ -1,4742 +0,0 @@
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 <strings.h>
28
-#include <stdlib.h>
29
-#include "libavformat/avformat.h"
30
-#include "libavformat/ffm.h"
31
-#include "libavformat/network.h"
32
-#include "libavformat/os_support.h"
33
-#include "libavformat/rtpdec.h"
34
-#include "libavformat/rtsp.h"
35
-// XXX for ffio_open_dyn_packet_buffer, to be removed
36
-#include "libavformat/avio_internal.h"
37
-#include "libavutil/avstring.h"
38
-#include "libavutil/lfg.h"
39
-#include "libavutil/dict.h"
40
-#include "libavutil/mathematics.h"
41
-#include "libavutil/random_seed.h"
42
-#include "libavutil/parseutils.h"
43
-#include "libavutil/opt.h"
44
-#include <stdarg.h>
45
-#include <unistd.h>
46
-#include <fcntl.h>
47
-#include <sys/ioctl.h>
48
-#if HAVE_POLL_H
49
-#include <poll.h>
50
-#endif
51
-#include <errno.h>
52
-#include <sys/time.h>
53
-#include <time.h>
54
-#include <sys/wait.h>
55
-#include <signal.h>
56
-#if HAVE_DLFCN_H
57
-#include <dlfcn.h>
58
-#endif
59
-
60
-#include "cmdutils.h"
61
-
62
-const char program_name[] = "ffserver";
63
-const int program_birth_year = 2000;
64
-
65
-static const OptionDef options[];
66
-
67
-enum HTTPState {
68
-    HTTPSTATE_WAIT_REQUEST,
69
-    HTTPSTATE_SEND_HEADER,
70
-    HTTPSTATE_SEND_DATA_HEADER,
71
-    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
72
-    HTTPSTATE_SEND_DATA_TRAILER,
73
-    HTTPSTATE_RECEIVE_DATA,
74
-    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
75
-    HTTPSTATE_READY,
76
-
77
-    RTSPSTATE_WAIT_REQUEST,
78
-    RTSPSTATE_SEND_REPLY,
79
-    RTSPSTATE_SEND_PACKET,
80
-};
81
-
82
-static const char *http_state[] = {
83
-    "HTTP_WAIT_REQUEST",
84
-    "HTTP_SEND_HEADER",
85
-
86
-    "SEND_DATA_HEADER",
87
-    "SEND_DATA",
88
-    "SEND_DATA_TRAILER",
89
-    "RECEIVE_DATA",
90
-    "WAIT_FEED",
91
-    "READY",
92
-
93
-    "RTSP_WAIT_REQUEST",
94
-    "RTSP_SEND_REPLY",
95
-    "RTSP_SEND_PACKET",
96
-};
97
-
98
-#define MAX_STREAMS 20
99
-
100
-#define IOBUFFER_INIT_SIZE 8192
101
-
102
-/* timeouts are in ms */
103
-#define HTTP_REQUEST_TIMEOUT (15 * 1000)
104
-#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
105
-
106
-#define SYNC_TIMEOUT (10 * 1000)
107
-
108
-typedef struct RTSPActionServerSetup {
109
-    uint32_t ipaddr;
110
-    char transport_option[512];
111
-} RTSPActionServerSetup;
112
-
113
-typedef struct {
114
-    int64_t count1, count2;
115
-    int64_t time1, time2;
116
-} DataRateData;
117
-
118
-/* context associated with one connection */
119
-typedef struct HTTPContext {
120
-    enum HTTPState state;
121
-    int fd; /* socket file descriptor */
122
-    struct sockaddr_in from_addr; /* origin */
123
-    struct pollfd *poll_entry; /* used when polling */
124
-    int64_t timeout;
125
-    uint8_t *buffer_ptr, *buffer_end;
126
-    int http_error;
127
-    int post;
128
-    int chunked_encoding;
129
-    int chunk_size;               /* 0 if it needs to be read */
130
-    struct HTTPContext *next;
131
-    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
132
-    int64_t data_count;
133
-    /* feed input */
134
-    int feed_fd;
135
-    /* input format handling */
136
-    AVFormatContext *fmt_in;
137
-    int64_t start_time;            /* In milliseconds - this wraps fairly often */
138
-    int64_t first_pts;            /* initial pts value */
139
-    int64_t cur_pts;             /* current pts value from the stream in us */
140
-    int64_t cur_frame_duration;  /* duration of the current frame in us */
141
-    int cur_frame_bytes;       /* output frame size, needed to compute
142
-                                  the time at which we send each
143
-                                  packet */
144
-    int pts_stream_index;        /* stream we choose as clock reference */
145
-    int64_t cur_clock;           /* current clock reference value in us */
146
-    /* output format handling */
147
-    struct FFStream *stream;
148
-    /* -1 is invalid stream */
149
-    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
150
-    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
151
-    int switch_pending;
152
-    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
153
-    int last_packet_sent; /* true if last data packet was sent */
154
-    int suppress_log;
155
-    DataRateData datarate;
156
-    int wmp_client_id;
157
-    char protocol[16];
158
-    char method[16];
159
-    char url[128];
160
-    int buffer_size;
161
-    uint8_t *buffer;
162
-    int is_packetized; /* if true, the stream is packetized */
163
-    int packet_stream_index; /* current stream for output in state machine */
164
-
165
-    /* RTSP state specific */
166
-    uint8_t *pb_buffer; /* XXX: use that in all the code */
167
-    AVIOContext *pb;
168
-    int seq; /* RTSP sequence number */
169
-
170
-    /* RTP state specific */
171
-    enum RTSPLowerTransport rtp_protocol;
172
-    char session_id[32]; /* session id */
173
-    AVFormatContext *rtp_ctx[MAX_STREAMS];
174
-
175
-    /* RTP/UDP specific */
176
-    URLContext *rtp_handles[MAX_STREAMS];
177
-
178
-    /* RTP/TCP specific */
179
-    struct HTTPContext *rtsp_c;
180
-    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
181
-} HTTPContext;
182
-
183
-/* each generated stream is described here */
184
-enum StreamType {
185
-    STREAM_TYPE_LIVE,
186
-    STREAM_TYPE_STATUS,
187
-    STREAM_TYPE_REDIRECT,
188
-};
189
-
190
-enum IPAddressAction {
191
-    IP_ALLOW = 1,
192
-    IP_DENY,
193
-};
194
-
195
-typedef struct IPAddressACL {
196
-    struct IPAddressACL *next;
197
-    enum IPAddressAction action;
198
-    /* These are in host order */
199
-    struct in_addr first;
200
-    struct in_addr last;
201
-} IPAddressACL;
202
-
203
-/* description of each stream of the ffserver.conf file */
204
-typedef struct FFStream {
205
-    enum StreamType stream_type;
206
-    char filename[1024];     /* stream filename */
207
-    struct FFStream *feed;   /* feed we are using (can be null if
208
-                                coming from file) */
209
-    AVDictionary *in_opts;   /* input parameters */
210
-    AVInputFormat *ifmt;       /* if non NULL, force input format */
211
-    AVOutputFormat *fmt;
212
-    IPAddressACL *acl;
213
-    char dynamic_acl[1024];
214
-    int nb_streams;
215
-    int prebuffer;      /* Number of millseconds early to start */
216
-    int64_t max_time;      /* Number of milliseconds to run */
217
-    int send_on_key;
218
-    AVStream *streams[MAX_STREAMS];
219
-    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
220
-    char feed_filename[1024]; /* file name of the feed storage, or
221
-                                 input file name for a stream */
222
-    char author[512];
223
-    char title[512];
224
-    char copyright[512];
225
-    char comment[512];
226
-    pid_t pid;  /* Of ffmpeg process */
227
-    time_t pid_start;  /* Of ffmpeg process */
228
-    char **child_argv;
229
-    struct FFStream *next;
230
-    unsigned bandwidth; /* bandwidth, in kbits/s */
231
-    /* RTSP options */
232
-    char *rtsp_option;
233
-    /* multicast specific */
234
-    int is_multicast;
235
-    struct in_addr multicast_ip;
236
-    int multicast_port; /* first port used for multicast */
237
-    int multicast_ttl;
238
-    int loop; /* if true, send the stream in loops (only meaningful if file) */
239
-
240
-    /* feed specific */
241
-    int feed_opened;     /* true if someone is writing to the feed */
242
-    int is_feed;         /* true if it is a feed */
243
-    int readonly;        /* True if writing is prohibited to the file */
244
-    int truncate;        /* True if feeder connection truncate the feed file */
245
-    int conns_served;
246
-    int64_t bytes_served;
247
-    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
248
-    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
249
-    int64_t feed_size;          /* current size of feed */
250
-    struct FFStream *next_feed;
251
-} FFStream;
252
-
253
-typedef struct FeedData {
254
-    long long data_count;
255
-    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
256
-} FeedData;
257
-
258
-static struct sockaddr_in my_http_addr;
259
-static struct sockaddr_in my_rtsp_addr;
260
-
261
-static char logfilename[1024];
262
-static HTTPContext *first_http_ctx;
263
-static FFStream *first_feed;   /* contains only feeds */
264
-static FFStream *first_stream; /* contains all streams, including feeds */
265
-
266
-static void new_connection(int server_fd, int is_rtsp);
267
-static void close_connection(HTTPContext *c);
268
-
269
-/* HTTP handling */
270
-static int handle_connection(HTTPContext *c);
271
-static int http_parse_request(HTTPContext *c);
272
-static int http_send_data(HTTPContext *c);
273
-static void compute_status(HTTPContext *c);
274
-static int open_input_stream(HTTPContext *c, const char *info);
275
-static int http_start_receive_data(HTTPContext *c);
276
-static int http_receive_data(HTTPContext *c);
277
-
278
-/* RTSP handling */
279
-static int rtsp_parse_request(HTTPContext *c);
280
-static void rtsp_cmd_describe(HTTPContext *c, const char *url);
281
-static void rtsp_cmd_options(HTTPContext *c, const char *url);
282
-static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283
-static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284
-static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285
-static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286
-
287
-/* SDP handling */
288
-static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
289
-                                   struct in_addr my_ip);
290
-
291
-/* RTP handling */
292
-static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
293
-                                       FFStream *stream, const char *session_id,
294
-                                       enum RTSPLowerTransport rtp_protocol);
295
-static int rtp_new_av_stream(HTTPContext *c,
296
-                             int stream_index, struct sockaddr_in *dest_addr,
297
-                             HTTPContext *rtsp_c);
298
-
299
-static const char *my_program_name;
300
-static const char *my_program_dir;
301
-
302
-static const char *config_filename = "/etc/ffserver.conf";
303
-
304
-static int ffserver_debug;
305
-static int ffserver_daemon;
306
-static int no_launch;
307
-static int need_to_start_children;
308
-
309
-/* maximum number of simultaneous HTTP connections */
310
-static unsigned int nb_max_http_connections = 2000;
311
-static unsigned int nb_max_connections = 5;
312
-static unsigned int nb_connections;
313
-
314
-static uint64_t max_bandwidth = 1000;
315
-static uint64_t current_bandwidth;
316
-
317
-static int64_t cur_time;           // Making this global saves on passing it around everywhere
318
-
319
-static AVLFG random_state;
320
-
321
-static FILE *logfile = NULL;
322
-
323
-/* FIXME: make ffserver work with IPv6 */
324
-/* resolve host with also IP address parsing */
325
-static int resolve_host(struct in_addr *sin_addr, const char *hostname)
326
-{
327
-
328
-    if (!ff_inet_aton(hostname, sin_addr)) {
329
-#if HAVE_GETADDRINFO
330
-        struct addrinfo *ai, *cur;
331
-        struct addrinfo hints;
332
-        memset(&hints, 0, sizeof(hints));
333
-        hints.ai_family = AF_INET;
334
-        if (getaddrinfo(hostname, NULL, &hints, &ai))
335
-            return -1;
336
-        /* getaddrinfo returns a linked list of addrinfo structs.
337
-         * Even if we set ai_family = AF_INET above, make sure
338
-         * that the returned one actually is of the correct type. */
339
-        for (cur = ai; cur; cur = cur->ai_next) {
340
-            if (cur->ai_family == AF_INET) {
341
-                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
342
-                freeaddrinfo(ai);
343
-                return 0;
344
-            }
345
-        }
346
-        freeaddrinfo(ai);
347
-        return -1;
348
-#else
349
-        struct hostent *hp;
350
-        hp = gethostbyname(hostname);
351
-        if (!hp)
352
-            return -1;
353
-        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
354
-#endif
355
-    }
356
-    return 0;
357
-}
358
-
359
-static char *ctime1(char *buf2)
360
-{
361
-    time_t ti;
362
-    char *p;
363
-
364
-    ti = time(NULL);
365
-    p = ctime(&ti);
366
-    strcpy(buf2, p);
367
-    p = buf2 + strlen(p) - 1;
368
-    if (*p == '\n')
369
-        *p = '\0';
370
-    return buf2;
371
-}
372
-
373
-static void http_vlog(const char *fmt, va_list vargs)
374
-{
375
-    static int print_prefix = 1;
376
-    if (logfile) {
377
-        if (print_prefix) {
378
-            char buf[32];
379
-            ctime1(buf);
380
-            fprintf(logfile, "%s ", buf);
381
-        }
382
-        print_prefix = strstr(fmt, "\n") != NULL;
383
-        vfprintf(logfile, fmt, vargs);
384
-        fflush(logfile);
385
-    }
386
-}
387
-
388
-#ifdef __GNUC__
389
-__attribute__ ((format (printf, 1, 2)))
390
-#endif
391
-static void http_log(const char *fmt, ...)
392
-{
393
-    va_list vargs;
394
-    va_start(vargs, fmt);
395
-    http_vlog(fmt, vargs);
396
-    va_end(vargs);
397
-}
398
-
399
-static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
400
-{
401
-    static int print_prefix = 1;
402
-    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
403
-    if (level > av_log_get_level())
404
-        return;
405
-    if (print_prefix && avc)
406
-        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
407
-    print_prefix = strstr(fmt, "\n") != NULL;
408
-    http_vlog(fmt, vargs);
409
-}
410
-
411
-static void log_connection(HTTPContext *c)
412
-{
413
-    if (c->suppress_log)
414
-        return;
415
-
416
-    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
417
-             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
418
-             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
419
-}
420
-
421
-static void update_datarate(DataRateData *drd, int64_t count)
422
-{
423
-    if (!drd->time1 && !drd->count1) {
424
-        drd->time1 = drd->time2 = cur_time;
425
-        drd->count1 = drd->count2 = count;
426
-    } else if (cur_time - drd->time2 > 5000) {
427
-        drd->time1 = drd->time2;
428
-        drd->count1 = drd->count2;
429
-        drd->time2 = cur_time;
430
-        drd->count2 = count;
431
-    }
432
-}
433
-
434
-/* In bytes per second */
435
-static int compute_datarate(DataRateData *drd, int64_t count)
436
-{
437
-    if (cur_time == drd->time1)
438
-        return 0;
439
-
440
-    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
441
-}
442
-
443
-
444
-static void start_children(FFStream *feed)
445
-{
446
-    if (no_launch)
447
-        return;
448
-
449
-    for (; feed; feed = feed->next) {
450
-        if (feed->child_argv && !feed->pid) {
451
-            feed->pid_start = time(0);
452
-
453
-            feed->pid = fork();
454
-
455
-            if (feed->pid < 0) {
456
-                http_log("Unable to create children\n");
457
-                exit(1);
458
-            }
459
-            if (!feed->pid) {
460
-                /* In child */
461
-                char pathname[1024];
462
-                char *slash;
463
-                int i;
464
-
465
-                av_strlcpy(pathname, my_program_name, sizeof(pathname));
466
-
467
-                slash = strrchr(pathname, '/');
468
-                if (!slash)
469
-                    slash = pathname;
470
-                else
471
-                    slash++;
472
-                strcpy(slash, "ffmpeg");
473
-
474
-                http_log("Launch commandline: ");
475
-                http_log("%s ", pathname);
476
-                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
477
-                    http_log("%s ", feed->child_argv[i]);
478
-                http_log("\n");
479
-
480
-                for (i = 3; i < 256; i++)
481
-                    close(i);
482
-
483
-                if (!ffserver_debug) {
484
-                    i = open("/dev/null", O_RDWR);
485
-                    if (i != -1) {
486
-                        dup2(i, 0);
487
-                        dup2(i, 1);
488
-                        dup2(i, 2);
489
-                        close(i);
490
-                    }
491
-                }
492
-
493
-                /* This is needed to make relative pathnames work */
494
-                chdir(my_program_dir);
495
-
496
-                signal(SIGPIPE, SIG_DFL);
497
-
498
-                execvp(pathname, feed->child_argv);
499
-
500
-                _exit(1);
501
-            }
502
-        }
503
-    }
504
-}
505
-
506
-/* open a listening socket */
507
-static int socket_open_listen(struct sockaddr_in *my_addr)
508
-{
509
-    int server_fd, tmp;
510
-
511
-    server_fd = socket(AF_INET,SOCK_STREAM,0);
512
-    if (server_fd < 0) {
513
-        perror ("socket");
514
-        return -1;
515
-    }
516
-
517
-    tmp = 1;
518
-    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
519
-
520
-    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
521
-        char bindmsg[32];
522
-        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
523
-        perror (bindmsg);
524
-        closesocket(server_fd);
525
-        return -1;
526
-    }
527
-
528
-    if (listen (server_fd, 5) < 0) {
529
-        perror ("listen");
530
-        closesocket(server_fd);
531
-        return -1;
532
-    }
533
-    ff_socket_nonblock(server_fd, 1);
534
-
535
-    return server_fd;
536
-}
537
-
538
-/* start all multicast streams */
539
-static void start_multicast(void)
540
-{
541
-    FFStream *stream;
542
-    char session_id[32];
543
-    HTTPContext *rtp_c;
544
-    struct sockaddr_in dest_addr;
545
-    int default_port, stream_index;
546
-
547
-    default_port = 6000;
548
-    for(stream = first_stream; stream != NULL; stream = stream->next) {
549
-        if (stream->is_multicast) {
550
-            /* open the RTP connection */
551
-            snprintf(session_id, sizeof(session_id), "%08x%08x",
552
-                     av_lfg_get(&random_state), av_lfg_get(&random_state));
553
-
554
-            /* choose a port if none given */
555
-            if (stream->multicast_port == 0) {
556
-                stream->multicast_port = default_port;
557
-                default_port += 100;
558
-            }
559
-
560
-            dest_addr.sin_family = AF_INET;
561
-            dest_addr.sin_addr = stream->multicast_ip;
562
-            dest_addr.sin_port = htons(stream->multicast_port);
563
-
564
-            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
565
-                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
566
-            if (!rtp_c)
567
-                continue;
568
-
569
-            if (open_input_stream(rtp_c, "") < 0) {
570
-                http_log("Could not open input stream for stream '%s'\n",
571
-                         stream->filename);
572
-                continue;
573
-            }
574
-
575
-            /* open each RTP stream */
576
-            for(stream_index = 0; stream_index < stream->nb_streams;
577
-                stream_index++) {
578
-                dest_addr.sin_port = htons(stream->multicast_port +
579
-                                           2 * stream_index);
580
-                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
581
-                    http_log("Could not open output stream '%s/streamid=%d'\n",
582
-                             stream->filename, stream_index);
583
-                    exit(1);
584
-                }
585
-            }
586
-
587
-            /* change state to send data */
588
-            rtp_c->state = HTTPSTATE_SEND_DATA;
589
-        }
590
-    }
591
-}
592
-
593
-/* main loop of the http server */
594
-static int http_server(void)
595
-{
596
-    int server_fd = 0, rtsp_server_fd = 0;
597
-    int ret, delay, delay1;
598
-    struct pollfd *poll_table, *poll_entry;
599
-    HTTPContext *c, *c_next;
600
-
601
-    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
602
-        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
603
-        return -1;
604
-    }
605
-
606
-    if (my_http_addr.sin_port) {
607
-        server_fd = socket_open_listen(&my_http_addr);
608
-        if (server_fd < 0)
609
-            return -1;
610
-    }
611
-
612
-    if (my_rtsp_addr.sin_port) {
613
-        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
614
-        if (rtsp_server_fd < 0)
615
-            return -1;
616
-    }
617
-
618
-    if (!rtsp_server_fd && !server_fd) {
619
-        http_log("HTTP and RTSP disabled.\n");
620
-        return -1;
621
-    }
622
-
623
-    http_log("FFserver started.\n");
624
-
625
-    start_children(first_feed);
626
-
627
-    start_multicast();
628
-
629
-    for(;;) {
630
-        poll_entry = poll_table;
631
-        if (server_fd) {
632
-            poll_entry->fd = server_fd;
633
-            poll_entry->events = POLLIN;
634
-            poll_entry++;
635
-        }
636
-        if (rtsp_server_fd) {
637
-            poll_entry->fd = rtsp_server_fd;
638
-            poll_entry->events = POLLIN;
639
-            poll_entry++;
640
-        }
641
-
642
-        /* wait for events on each HTTP handle */
643
-        c = first_http_ctx;
644
-        delay = 1000;
645
-        while (c != NULL) {
646
-            int fd;
647
-            fd = c->fd;
648
-            switch(c->state) {
649
-            case HTTPSTATE_SEND_HEADER:
650
-            case RTSPSTATE_SEND_REPLY:
651
-            case RTSPSTATE_SEND_PACKET:
652
-                c->poll_entry = poll_entry;
653
-                poll_entry->fd = fd;
654
-                poll_entry->events = POLLOUT;
655
-                poll_entry++;
656
-                break;
657
-            case HTTPSTATE_SEND_DATA_HEADER:
658
-            case HTTPSTATE_SEND_DATA:
659
-            case HTTPSTATE_SEND_DATA_TRAILER:
660
-                if (!c->is_packetized) {
661
-                    /* for TCP, we output as much as we can (may need to put a limit) */
662
-                    c->poll_entry = poll_entry;
663
-                    poll_entry->fd = fd;
664
-                    poll_entry->events = POLLOUT;
665
-                    poll_entry++;
666
-                } else {
667
-                    /* when ffserver is doing the timing, we work by
668
-                       looking at which packet need to be sent every
669
-                       10 ms */
670
-                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
671
-                    if (delay1 < delay)
672
-                        delay = delay1;
673
-                }
674
-                break;
675
-            case HTTPSTATE_WAIT_REQUEST:
676
-            case HTTPSTATE_RECEIVE_DATA:
677
-            case HTTPSTATE_WAIT_FEED:
678
-            case RTSPSTATE_WAIT_REQUEST:
679
-                /* need to catch errors */
680
-                c->poll_entry = poll_entry;
681
-                poll_entry->fd = fd;
682
-                poll_entry->events = POLLIN;/* Maybe this will work */
683
-                poll_entry++;
684
-                break;
685
-            default:
686
-                c->poll_entry = NULL;
687
-                break;
688
-            }
689
-            c = c->next;
690
-        }
691
-
692
-        /* wait for an event on one connection. We poll at least every
693
-           second to handle timeouts */
694
-        do {
695
-            ret = poll(poll_table, poll_entry - poll_table, delay);
696
-            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
697
-                ff_neterrno() != AVERROR(EINTR))
698
-                return -1;
699
-        } while (ret < 0);
700
-
701
-        cur_time = av_gettime() / 1000;
702
-
703
-        if (need_to_start_children) {
704
-            need_to_start_children = 0;
705
-            start_children(first_feed);
706
-        }
707
-
708
-        /* now handle the events */
709
-        for(c = first_http_ctx; c != NULL; c = c_next) {
710
-            c_next = c->next;
711
-            if (handle_connection(c) < 0) {
712
-                /* close and free the connection */
713
-                log_connection(c);
714
-                close_connection(c);
715
-            }
716
-        }
717
-
718
-        poll_entry = poll_table;
719
-        if (server_fd) {
720
-            /* new HTTP connection request ? */
721
-            if (poll_entry->revents & POLLIN)
722
-                new_connection(server_fd, 0);
723
-            poll_entry++;
724
-        }
725
-        if (rtsp_server_fd) {
726
-            /* new RTSP connection request ? */
727
-            if (poll_entry->revents & POLLIN)
728
-                new_connection(rtsp_server_fd, 1);
729
-        }
730
-    }
731
-}
732
-
733
-/* start waiting for a new HTTP/RTSP request */
734
-static void start_wait_request(HTTPContext *c, int is_rtsp)
735
-{
736
-    c->buffer_ptr = c->buffer;
737
-    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
738
-
739
-    if (is_rtsp) {
740
-        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
741
-        c->state = RTSPSTATE_WAIT_REQUEST;
742
-    } else {
743
-        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
744
-        c->state = HTTPSTATE_WAIT_REQUEST;
745
-    }
746
-}
747
-
748
-static void http_send_too_busy_reply(int fd)
749
-{
750
-    char buffer[300];
751
-    int len = snprintf(buffer, sizeof(buffer),
752
-                       "HTTP/1.0 503 Server too busy\r\n"
753
-                       "Content-type: text/html\r\n"
754
-                       "\r\n"
755
-                       "<html><head><title>Too busy</title></head><body>\r\n"
756
-                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
757
-                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
758
-                       "</body></html>\r\n",
759
-                       nb_connections, nb_max_connections);
760
-    send(fd, buffer, len, 0);
761
-}
762
-
763
-
764
-static void new_connection(int server_fd, int is_rtsp)
765
-{
766
-    struct sockaddr_in from_addr;
767
-    int fd, len;
768
-    HTTPContext *c = NULL;
769
-
770
-    len = sizeof(from_addr);
771
-    fd = accept(server_fd, (struct sockaddr *)&from_addr,
772
-                &len);
773
-    if (fd < 0) {
774
-        http_log("error during accept %s\n", strerror(errno));
775
-        return;
776
-    }
777
-    ff_socket_nonblock(fd, 1);
778
-
779
-    if (nb_connections >= nb_max_connections) {
780
-        http_send_too_busy_reply(fd);
781
-        goto fail;
782
-    }
783
-
784
-    /* add a new connection */
785
-    c = av_mallocz(sizeof(HTTPContext));
786
-    if (!c)
787
-        goto fail;
788
-
789
-    c->fd = fd;
790
-    c->poll_entry = NULL;
791
-    c->from_addr = from_addr;
792
-    c->buffer_size = IOBUFFER_INIT_SIZE;
793
-    c->buffer = av_malloc(c->buffer_size);
794
-    if (!c->buffer)
795
-        goto fail;
796
-
797
-    c->next = first_http_ctx;
798
-    first_http_ctx = c;
799
-    nb_connections++;
800
-
801
-    start_wait_request(c, is_rtsp);
802
-
803
-    return;
804
-
805
- fail:
806
-    if (c) {
807
-        av_free(c->buffer);
808
-        av_free(c);
809
-    }
810
-    closesocket(fd);
811
-}
812
-
813
-static void close_connection(HTTPContext *c)
814
-{
815
-    HTTPContext **cp, *c1;
816
-    int i, nb_streams;
817
-    AVFormatContext *ctx;
818
-    URLContext *h;
819
-    AVStream *st;
820
-
821
-    /* remove connection from list */
822
-    cp = &first_http_ctx;
823
-    while ((*cp) != NULL) {
824
-        c1 = *cp;
825
-        if (c1 == c)
826
-            *cp = c->next;
827
-        else
828
-            cp = &c1->next;
829
-    }
830
-
831
-    /* remove references, if any (XXX: do it faster) */
832
-    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
833
-        if (c1->rtsp_c == c)
834
-            c1->rtsp_c = NULL;
835
-    }
836
-
837
-    /* remove connection associated resources */
838
-    if (c->fd >= 0)
839
-        closesocket(c->fd);
840
-    if (c->fmt_in) {
841
-        /* close each frame parser */
842
-        for(i=0;i<c->fmt_in->nb_streams;i++) {
843
-            st = c->fmt_in->streams[i];
844
-            if (st->codec->codec)
845
-                avcodec_close(st->codec);
846
-        }
847
-        av_close_input_file(c->fmt_in);
848
-    }
849
-
850
-    /* free RTP output streams if any */
851
-    nb_streams = 0;
852
-    if (c->stream)
853
-        nb_streams = c->stream->nb_streams;
854
-
855
-    for(i=0;i<nb_streams;i++) {
856
-        ctx = c->rtp_ctx[i];
857
-        if (ctx) {
858
-            av_write_trailer(ctx);
859
-            av_dict_free(&ctx->metadata);
860
-            av_free(ctx->streams[0]);
861
-            av_free(ctx);
862
-        }
863
-        h = c->rtp_handles[i];
864
-        if (h)
865
-            url_close(h);
866
-    }
867
-
868
-    ctx = &c->fmt_ctx;
869
-
870
-    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
871
-        if (ctx->oformat) {
872
-            /* prepare header */
873
-            if (avio_open_dyn_buf(&ctx->pb) >= 0) {
874
-                av_write_trailer(ctx);
875
-                av_freep(&c->pb_buffer);
876
-                avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
877
-            }
878
-        }
879
-    }
880
-
881
-    for(i=0; i<ctx->nb_streams; i++)
882
-        av_free(ctx->streams[i]);
883
-
884
-    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
885
-        current_bandwidth -= c->stream->bandwidth;
886
-
887
-    /* signal that there is no feed if we are the feeder socket */
888
-    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
889
-        c->stream->feed_opened = 0;
890
-        close(c->feed_fd);
891
-    }
892
-
893
-    av_freep(&c->pb_buffer);
894
-    av_freep(&c->packet_buffer);
895
-    av_free(c->buffer);
896
-    av_free(c);
897
-    nb_connections--;
898
-}
899
-
900
-static int handle_connection(HTTPContext *c)
901
-{
902
-    int len, ret;
903
-
904
-    switch(c->state) {
905
-    case HTTPSTATE_WAIT_REQUEST:
906
-    case RTSPSTATE_WAIT_REQUEST:
907
-        /* timeout ? */
908
-        if ((c->timeout - cur_time) < 0)
909
-            return -1;
910
-        if (c->poll_entry->revents & (POLLERR | POLLHUP))
911
-            return -1;
912
-
913
-        /* no need to read if no events */
914
-        if (!(c->poll_entry->revents & POLLIN))
915
-            return 0;
916
-        /* read the data */
917
-    read_loop:
918
-        len = recv(c->fd, c->buffer_ptr, 1, 0);
919
-        if (len < 0) {
920
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
921
-                ff_neterrno() != AVERROR(EINTR))
922
-                return -1;
923
-        } else if (len == 0) {
924
-            return -1;
925
-        } else {
926
-            /* search for end of request. */
927
-            uint8_t *ptr;
928
-            c->buffer_ptr += len;
929
-            ptr = c->buffer_ptr;
930
-            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
931
-                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
932
-                /* request found : parse it and reply */
933
-                if (c->state == HTTPSTATE_WAIT_REQUEST) {
934
-                    ret = http_parse_request(c);
935
-                } else {
936
-                    ret = rtsp_parse_request(c);
937
-                }
938
-                if (ret < 0)
939
-                    return -1;
940
-            } else if (ptr >= c->buffer_end) {
941
-                /* request too long: cannot do anything */
942
-                return -1;
943
-            } else goto read_loop;
944
-        }
945
-        break;
946
-
947
-    case HTTPSTATE_SEND_HEADER:
948
-        if (c->poll_entry->revents & (POLLERR | POLLHUP))
949
-            return -1;
950
-
951
-        /* no need to write if no events */
952
-        if (!(c->poll_entry->revents & POLLOUT))
953
-            return 0;
954
-        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
955
-        if (len < 0) {
956
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
957
-                ff_neterrno() != AVERROR(EINTR)) {
958
-                /* error : close connection */
959
-                av_freep(&c->pb_buffer);
960
-                return -1;
961
-            }
962
-        } else {
963
-            c->buffer_ptr += len;
964
-            if (c->stream)
965
-                c->stream->bytes_served += len;
966
-            c->data_count += len;
967
-            if (c->buffer_ptr >= c->buffer_end) {
968
-                av_freep(&c->pb_buffer);
969
-                /* if error, exit */
970
-                if (c->http_error)
971
-                    return -1;
972
-                /* all the buffer was sent : synchronize to the incoming stream */
973
-                c->state = HTTPSTATE_SEND_DATA_HEADER;
974
-                c->buffer_ptr = c->buffer_end = c->buffer;
975
-            }
976
-        }
977
-        break;
978
-
979
-    case HTTPSTATE_SEND_DATA:
980
-    case HTTPSTATE_SEND_DATA_HEADER:
981
-    case HTTPSTATE_SEND_DATA_TRAILER:
982
-        /* for packetized output, we consider we can always write (the
983
-           input streams sets the speed). It may be better to verify
984
-           that we do not rely too much on the kernel queues */
985
-        if (!c->is_packetized) {
986
-            if (c->poll_entry->revents & (POLLERR | POLLHUP))
987
-                return -1;
988
-
989
-            /* no need to read if no events */
990
-            if (!(c->poll_entry->revents & POLLOUT))
991
-                return 0;
992
-        }
993
-        if (http_send_data(c) < 0)
994
-            return -1;
995
-        /* close connection if trailer sent */
996
-        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
997
-            return -1;
998
-        break;
999
-    case HTTPSTATE_RECEIVE_DATA:
1000
-        /* no need to read if no events */
1001
-        if (c->poll_entry->revents & (POLLERR | POLLHUP))
1002
-            return -1;
1003
-        if (!(c->poll_entry->revents & POLLIN))
1004
-            return 0;
1005
-        if (http_receive_data(c) < 0)
1006
-            return -1;
1007
-        break;
1008
-    case HTTPSTATE_WAIT_FEED:
1009
-        /* no need to read if no events */
1010
-        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1011
-            return -1;
1012
-
1013
-        /* nothing to do, we'll be waken up by incoming feed packets */
1014
-        break;
1015
-
1016
-    case RTSPSTATE_SEND_REPLY:
1017
-        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1018
-            av_freep(&c->pb_buffer);
1019
-            return -1;
1020
-        }
1021
-        /* no need to write if no events */
1022
-        if (!(c->poll_entry->revents & POLLOUT))
1023
-            return 0;
1024
-        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1025
-        if (len < 0) {
1026
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
1027
-                ff_neterrno() != AVERROR(EINTR)) {
1028
-                /* error : close connection */
1029
-                av_freep(&c->pb_buffer);
1030
-                return -1;
1031
-            }
1032
-        } else {
1033
-            c->buffer_ptr += len;
1034
-            c->data_count += len;
1035
-            if (c->buffer_ptr >= c->buffer_end) {
1036
-                /* all the buffer was sent : wait for a new request */
1037
-                av_freep(&c->pb_buffer);
1038
-                start_wait_request(c, 1);
1039
-            }
1040
-        }
1041
-        break;
1042
-    case RTSPSTATE_SEND_PACKET:
1043
-        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1044
-            av_freep(&c->packet_buffer);
1045
-            return -1;
1046
-        }
1047
-        /* no need to write if no events */
1048
-        if (!(c->poll_entry->revents & POLLOUT))
1049
-            return 0;
1050
-        len = send(c->fd, c->packet_buffer_ptr,
1051
-                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1052
-        if (len < 0) {
1053
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
1054
-                ff_neterrno() != AVERROR(EINTR)) {
1055
-                /* error : close connection */
1056
-                av_freep(&c->packet_buffer);
1057
-                return -1;
1058
-            }
1059
-        } else {
1060
-            c->packet_buffer_ptr += len;
1061
-            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1062
-                /* all the buffer was sent : wait for a new request */
1063
-                av_freep(&c->packet_buffer);
1064
-                c->state = RTSPSTATE_WAIT_REQUEST;
1065
-            }
1066
-        }
1067
-        break;
1068
-    case HTTPSTATE_READY:
1069
-        /* nothing to do */
1070
-        break;
1071
-    default:
1072
-        return -1;
1073
-    }
1074
-    return 0;
1075
-}
1076
-
1077
-static int extract_rates(char *rates, int ratelen, const char *request)
1078
-{
1079
-    const char *p;
1080
-
1081
-    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1082
-        if (strncasecmp(p, "Pragma:", 7) == 0) {
1083
-            const char *q = p + 7;
1084
-
1085
-            while (*q && *q != '\n' && isspace(*q))
1086
-                q++;
1087
-
1088
-            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1089
-                int stream_no;
1090
-                int rate_no;
1091
-
1092
-                q += 20;
1093
-
1094
-                memset(rates, 0xff, ratelen);
1095
-
1096
-                while (1) {
1097
-                    while (*q && *q != '\n' && *q != ':')
1098
-                        q++;
1099
-
1100
-                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1101
-                        break;
1102
-
1103
-                    stream_no--;
1104
-                    if (stream_no < ratelen && stream_no >= 0)
1105
-                        rates[stream_no] = rate_no;
1106
-
1107
-                    while (*q && *q != '\n' && !isspace(*q))
1108
-                        q++;
1109
-                }
1110
-
1111
-                return 1;
1112
-            }
1113
-        }
1114
-        p = strchr(p, '\n');
1115
-        if (!p)
1116
-            break;
1117
-
1118
-        p++;
1119
-    }
1120
-
1121
-    return 0;
1122
-}
1123
-
1124
-static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1125
-{
1126
-    int i;
1127
-    int best_bitrate = 100000000;
1128
-    int best = -1;
1129
-
1130
-    for (i = 0; i < feed->nb_streams; i++) {
1131
-        AVCodecContext *feed_codec = feed->streams[i]->codec;
1132
-
1133
-        if (feed_codec->codec_id != codec->codec_id ||
1134
-            feed_codec->sample_rate != codec->sample_rate ||
1135
-            feed_codec->width != codec->width ||
1136
-            feed_codec->height != codec->height)
1137
-            continue;
1138
-
1139
-        /* Potential stream */
1140
-
1141
-        /* We want the fastest stream less than bit_rate, or the slowest
1142
-         * faster than bit_rate
1143
-         */
1144
-
1145
-        if (feed_codec->bit_rate <= bit_rate) {
1146
-            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1147
-                best_bitrate = feed_codec->bit_rate;
1148
-                best = i;
1149
-            }
1150
-        } else {
1151
-            if (feed_codec->bit_rate < best_bitrate) {
1152
-                best_bitrate = feed_codec->bit_rate;
1153
-                best = i;
1154
-            }
1155
-        }
1156
-    }
1157
-
1158
-    return best;
1159
-}
1160
-
1161
-static int modify_current_stream(HTTPContext *c, char *rates)
1162
-{
1163
-    int i;
1164
-    FFStream *req = c->stream;
1165
-    int action_required = 0;
1166
-
1167
-    /* Not much we can do for a feed */
1168
-    if (!req->feed)
1169
-        return 0;
1170
-
1171
-    for (i = 0; i < req->nb_streams; i++) {
1172
-        AVCodecContext *codec = req->streams[i]->codec;
1173
-
1174
-        switch(rates[i]) {
1175
-            case 0:
1176
-                c->switch_feed_streams[i] = req->feed_streams[i];
1177
-                break;
1178
-            case 1:
1179
-                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1180
-                break;
1181
-            case 2:
1182
-                /* Wants off or slow */
1183
-                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1184
-#ifdef WANTS_OFF
1185
-                /* This doesn't work well when it turns off the only stream! */
1186
-                c->switch_feed_streams[i] = -2;
1187
-                c->feed_streams[i] = -2;
1188
-#endif
1189
-                break;
1190
-        }
1191
-
1192
-        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1193
-            action_required = 1;
1194
-    }
1195
-
1196
-    return action_required;
1197
-}
1198
-
1199
-/* XXX: factorize in utils.c ? */
1200
-/* XXX: take care with different space meaning */
1201
-static void skip_spaces(const char **pp)
1202
-{
1203
-    const char *p;
1204
-    p = *pp;
1205
-    while (*p == ' ' || *p == '\t')
1206
-        p++;
1207
-    *pp = p;
1208
-}
1209
-
1210
-static void get_word(char *buf, int buf_size, const char **pp)
1211
-{
1212
-    const char *p;
1213
-    char *q;
1214
-
1215
-    p = *pp;
1216
-    skip_spaces(&p);
1217
-    q = buf;
1218
-    while (!isspace(*p) && *p != '\0') {
1219
-        if ((q - buf) < buf_size - 1)
1220
-            *q++ = *p;
1221
-        p++;
1222
-    }
1223
-    if (buf_size > 0)
1224
-        *q = '\0';
1225
-    *pp = p;
1226
-}
1227
-
1228
-static void get_arg(char *buf, int buf_size, const char **pp)
1229
-{
1230
-    const char *p;
1231
-    char *q;
1232
-    int quote;
1233
-
1234
-    p = *pp;
1235
-    while (isspace(*p)) p++;
1236
-    q = buf;
1237
-    quote = 0;
1238
-    if (*p == '\"' || *p == '\'')
1239
-        quote = *p++;
1240
-    for(;;) {
1241
-        if (quote) {
1242
-            if (*p == quote)
1243
-                break;
1244
-        } else {
1245
-            if (isspace(*p))
1246
-                break;
1247
-        }
1248
-        if (*p == '\0')
1249
-            break;
1250
-        if ((q - buf) < buf_size - 1)
1251
-            *q++ = *p;
1252
-        p++;
1253
-    }
1254
-    *q = '\0';
1255
-    if (quote && *p == quote)
1256
-        p++;
1257
-    *pp = p;
1258
-}
1259
-
1260
-static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1261
-                         const char *p, const char *filename, int line_num)
1262
-{
1263
-    char arg[1024];
1264
-    IPAddressACL acl;
1265
-    int errors = 0;
1266
-
1267
-    get_arg(arg, sizeof(arg), &p);
1268
-    if (strcasecmp(arg, "allow") == 0)
1269
-        acl.action = IP_ALLOW;
1270
-    else if (strcasecmp(arg, "deny") == 0)
1271
-        acl.action = IP_DENY;
1272
-    else {
1273
-        fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1274
-                filename, line_num, arg);
1275
-        errors++;
1276
-    }
1277
-
1278
-    get_arg(arg, sizeof(arg), &p);
1279
-
1280
-    if (resolve_host(&acl.first, arg) != 0) {
1281
-        fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1282
-                filename, line_num, arg);
1283
-        errors++;
1284
-    } else
1285
-        acl.last = acl.first;
1286
-
1287
-    get_arg(arg, sizeof(arg), &p);
1288
-
1289
-    if (arg[0]) {
1290
-        if (resolve_host(&acl.last, arg) != 0) {
1291
-            fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1292
-                    filename, line_num, arg);
1293
-            errors++;
1294
-        }
1295
-    }
1296
-
1297
-    if (!errors) {
1298
-        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1299
-        IPAddressACL **naclp = 0;
1300
-
1301
-        acl.next = 0;
1302
-        *nacl = acl;
1303
-
1304
-        if (stream)
1305
-            naclp = &stream->acl;
1306
-        else if (feed)
1307
-            naclp = &feed->acl;
1308
-        else if (ext_acl)
1309
-            naclp = &ext_acl;
1310
-        else {
1311
-            fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1312
-                    filename, line_num);
1313
-            errors++;
1314
-        }
1315
-
1316
-        if (naclp) {
1317
-            while (*naclp)
1318
-                naclp = &(*naclp)->next;
1319
-
1320
-            *naclp = nacl;
1321
-        }
1322
-    }
1323
-}
1324
-
1325
-
1326
-static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1327
-{
1328
-    FILE* f;
1329
-    char line[1024];
1330
-    char  cmd[1024];
1331
-    IPAddressACL *acl = NULL;
1332
-    int line_num = 0;
1333
-    const char *p;
1334
-
1335
-    f = fopen(stream->dynamic_acl, "r");
1336
-    if (!f) {
1337
-        perror(stream->dynamic_acl);
1338
-        return NULL;
1339
-    }
1340
-
1341
-    acl = av_mallocz(sizeof(IPAddressACL));
1342
-
1343
-    /* Build ACL */
1344
-    for(;;) {
1345
-        if (fgets(line, sizeof(line), f) == NULL)
1346
-            break;
1347
-        line_num++;
1348
-        p = line;
1349
-        while (isspace(*p))
1350
-            p++;
1351
-        if (*p == '\0' || *p == '#')
1352
-            continue;
1353
-        get_arg(cmd, sizeof(cmd), &p);
1354
-
1355
-        if (!strcasecmp(cmd, "ACL"))
1356
-            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1357
-    }
1358
-    fclose(f);
1359
-    return acl;
1360
-}
1361
-
1362
-
1363
-static void free_acl_list(IPAddressACL *in_acl)
1364
-{
1365
-    IPAddressACL *pacl,*pacl2;
1366
-
1367
-    pacl = in_acl;
1368
-    while(pacl) {
1369
-        pacl2 = pacl;
1370
-        pacl = pacl->next;
1371
-        av_freep(pacl2);
1372
-    }
1373
-}
1374
-
1375
-static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1376
-{
1377
-    enum IPAddressAction last_action = IP_DENY;
1378
-    IPAddressACL *acl;
1379
-    struct in_addr *src = &c->from_addr.sin_addr;
1380
-    unsigned long src_addr = src->s_addr;
1381
-
1382
-    for (acl = in_acl; acl; acl = acl->next) {
1383
-        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1384
-            return (acl->action == IP_ALLOW) ? 1 : 0;
1385
-        last_action = acl->action;
1386
-    }
1387
-
1388
-    /* Nothing matched, so return not the last action */
1389
-    return (last_action == IP_DENY) ? 1 : 0;
1390
-}
1391
-
1392
-static int validate_acl(FFStream *stream, HTTPContext *c)
1393
-{
1394
-    int ret = 0;
1395
-    IPAddressACL *acl;
1396
-
1397
-
1398
-    /* if stream->acl is null validate_acl_list will return 1 */
1399
-    ret = validate_acl_list(stream->acl, c);
1400
-
1401
-    if (stream->dynamic_acl[0]) {
1402
-        acl = parse_dynamic_acl(stream, c);
1403
-
1404
-        ret = validate_acl_list(acl, c);
1405
-
1406
-        free_acl_list(acl);
1407
-    }
1408
-
1409
-    return ret;
1410
-}
1411
-
1412
-/* compute the real filename of a file by matching it without its
1413
-   extensions to all the stream filenames */
1414
-static void compute_real_filename(char *filename, int max_size)
1415
-{
1416
-    char file1[1024];
1417
-    char file2[1024];
1418
-    char *p;
1419
-    FFStream *stream;
1420
-
1421
-    /* compute filename by matching without the file extensions */
1422
-    av_strlcpy(file1, filename, sizeof(file1));
1423
-    p = strrchr(file1, '.');
1424
-    if (p)
1425
-        *p = '\0';
1426
-    for(stream = first_stream; stream != NULL; stream = stream->next) {
1427
-        av_strlcpy(file2, stream->filename, sizeof(file2));
1428
-        p = strrchr(file2, '.');
1429
-        if (p)
1430
-            *p = '\0';
1431
-        if (!strcmp(file1, file2)) {
1432
-            av_strlcpy(filename, stream->filename, max_size);
1433
-            break;
1434
-        }
1435
-    }
1436
-}
1437
-
1438
-enum RedirType {
1439
-    REDIR_NONE,
1440
-    REDIR_ASX,
1441
-    REDIR_RAM,
1442
-    REDIR_ASF,
1443
-    REDIR_RTSP,
1444
-    REDIR_SDP,
1445
-};
1446
-
1447
-/* parse http request and prepare header */
1448
-static int http_parse_request(HTTPContext *c)
1449
-{
1450
-    char *p;
1451
-    enum RedirType redir_type;
1452
-    char cmd[32];
1453
-    char info[1024], filename[1024];
1454
-    char url[1024], *q;
1455
-    char protocol[32];
1456
-    char msg[1024];
1457
-    const char *mime_type;
1458
-    FFStream *stream;
1459
-    int i;
1460
-    char ratebuf[32];
1461
-    char *useragent = 0;
1462
-
1463
-    p = c->buffer;
1464
-    get_word(cmd, sizeof(cmd), (const char **)&p);
1465
-    av_strlcpy(c->method, cmd, sizeof(c->method));
1466
-
1467
-    if (!strcmp(cmd, "GET"))
1468
-        c->post = 0;
1469
-    else if (!strcmp(cmd, "POST"))
1470
-        c->post = 1;
1471
-    else
1472
-        return -1;
1473
-
1474
-    get_word(url, sizeof(url), (const char **)&p);
1475
-    av_strlcpy(c->url, url, sizeof(c->url));
1476
-
1477
-    get_word(protocol, sizeof(protocol), (const char **)&p);
1478
-    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1479
-        return -1;
1480
-
1481
-    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1482
-
1483
-    if (ffserver_debug)
1484
-        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1485
-
1486
-    /* find the filename and the optional info string in the request */
1487
-    p = strchr(url, '?');
1488
-    if (p) {
1489
-        av_strlcpy(info, p, sizeof(info));
1490
-        *p = '\0';
1491
-    } else
1492
-        info[0] = '\0';
1493
-
1494
-    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1495
-
1496
-    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1497
-        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1498
-            useragent = p + 11;
1499
-            if (*useragent && *useragent != '\n' && isspace(*useragent))
1500
-                useragent++;
1501
-            break;
1502
-        }
1503
-        p = strchr(p, '\n');
1504
-        if (!p)
1505
-            break;
1506
-
1507
-        p++;
1508
-    }
1509
-
1510
-    redir_type = REDIR_NONE;
1511
-    if (av_match_ext(filename, "asx")) {
1512
-        redir_type = REDIR_ASX;
1513
-        filename[strlen(filename)-1] = 'f';
1514
-    } else if (av_match_ext(filename, "asf") &&
1515
-        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1516
-        /* if this isn't WMP or lookalike, return the redirector file */
1517
-        redir_type = REDIR_ASF;
1518
-    } else if (av_match_ext(filename, "rpm,ram")) {
1519
-        redir_type = REDIR_RAM;
1520
-        strcpy(filename + strlen(filename)-2, "m");
1521
-    } else if (av_match_ext(filename, "rtsp")) {
1522
-        redir_type = REDIR_RTSP;
1523
-        compute_real_filename(filename, sizeof(filename) - 1);
1524
-    } else if (av_match_ext(filename, "sdp")) {
1525
-        redir_type = REDIR_SDP;
1526
-        compute_real_filename(filename, sizeof(filename) - 1);
1527
-    }
1528
-
1529
-    // "redirect" / request to index.html
1530
-    if (!strlen(filename))
1531
-        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1532
-
1533
-    stream = first_stream;
1534
-    while (stream != NULL) {
1535
-        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1536
-            break;
1537
-        stream = stream->next;
1538
-    }
1539
-    if (stream == NULL) {
1540
-        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1541
-        http_log("File '%s' not found\n", url);
1542
-        goto send_error;
1543
-    }
1544
-
1545
-    c->stream = stream;
1546
-    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1547
-    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1548
-
1549
-    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1550
-        c->http_error = 301;
1551
-        q = c->buffer;
1552
-        q += snprintf(q, c->buffer_size,
1553
-                      "HTTP/1.0 301 Moved\r\n"
1554
-                      "Location: %s\r\n"
1555
-                      "Content-type: text/html\r\n"
1556
-                      "\r\n"
1557
-                      "<html><head><title>Moved</title></head><body>\r\n"
1558
-                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1559
-                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1560
-        /* prepare output buffer */
1561
-        c->buffer_ptr = c->buffer;
1562
-        c->buffer_end = q;
1563
-        c->state = HTTPSTATE_SEND_HEADER;
1564
-        return 0;
1565
-    }
1566
-
1567
-    /* If this is WMP, get the rate information */
1568
-    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1569
-        if (modify_current_stream(c, ratebuf)) {
1570
-            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1571
-                if (c->switch_feed_streams[i] >= 0)
1572
-                    c->switch_feed_streams[i] = -1;
1573
-            }
1574
-        }
1575
-    }
1576
-
1577
-    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1578
-        current_bandwidth += stream->bandwidth;
1579
-
1580
-    /* If already streaming this feed, do not let start another feeder. */
1581
-    if (stream->feed_opened) {
1582
-        snprintf(msg, sizeof(msg), "This feed is already being received.");
1583
-        http_log("Feed '%s' already being received\n", stream->feed_filename);
1584
-        goto send_error;
1585
-    }
1586
-
1587
-    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1588
-        c->http_error = 503;
1589
-        q = c->buffer;
1590
-        q += snprintf(q, c->buffer_size,
1591
-                      "HTTP/1.0 503 Server too busy\r\n"
1592
-                      "Content-type: text/html\r\n"
1593
-                      "\r\n"
1594
-                      "<html><head><title>Too busy</title></head><body>\r\n"
1595
-                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1596
-                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1597
-                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1598
-                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1599
-        /* prepare output buffer */
1600
-        c->buffer_ptr = c->buffer;
1601
-        c->buffer_end = q;
1602
-        c->state = HTTPSTATE_SEND_HEADER;
1603
-        return 0;
1604
-    }
1605
-
1606
-    if (redir_type != REDIR_NONE) {
1607
-        char *hostinfo = 0;
1608
-
1609
-        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1610
-            if (strncasecmp(p, "Host:", 5) == 0) {
1611
-                hostinfo = p + 5;
1612
-                break;
1613
-            }
1614
-            p = strchr(p, '\n');
1615
-            if (!p)
1616
-                break;
1617
-
1618
-            p++;
1619
-        }
1620
-
1621
-        if (hostinfo) {
1622
-            char *eoh;
1623
-            char hostbuf[260];
1624
-
1625
-            while (isspace(*hostinfo))
1626
-                hostinfo++;
1627
-
1628
-            eoh = strchr(hostinfo, '\n');
1629
-            if (eoh) {
1630
-                if (eoh[-1] == '\r')
1631
-                    eoh--;
1632
-
1633
-                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1634
-                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1635
-                    hostbuf[eoh - hostinfo] = 0;
1636
-
1637
-                    c->http_error = 200;
1638
-                    q = c->buffer;
1639
-                    switch(redir_type) {
1640
-                    case REDIR_ASX:
1641
-                        q += snprintf(q, c->buffer_size,
1642
-                                      "HTTP/1.0 200 ASX Follows\r\n"
1643
-                                      "Content-type: video/x-ms-asf\r\n"
1644
-                                      "\r\n"
1645
-                                      "<ASX Version=\"3\">\r\n"
1646
-                                      //"<!-- Autogenerated by ffserver -->\r\n"
1647
-                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1648
-                                      "</ASX>\r\n", hostbuf, filename, info);
1649
-                        break;
1650
-                    case REDIR_RAM:
1651
-                        q += snprintf(q, c->buffer_size,
1652
-                                      "HTTP/1.0 200 RAM Follows\r\n"
1653
-                                      "Content-type: audio/x-pn-realaudio\r\n"
1654
-                                      "\r\n"
1655
-                                      "# Autogenerated by ffserver\r\n"
1656
-                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1657
-                        break;
1658
-                    case REDIR_ASF:
1659
-                        q += snprintf(q, c->buffer_size,
1660
-                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1661
-                                      "Content-type: video/x-ms-asf\r\n"
1662
-                                      "\r\n"
1663
-                                      "[Reference]\r\n"
1664
-                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1665
-                        break;
1666
-                    case REDIR_RTSP:
1667
-                        {
1668
-                            char hostname[256], *p;
1669
-                            /* extract only hostname */
1670
-                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1671
-                            p = strrchr(hostname, ':');
1672
-                            if (p)
1673
-                                *p = '\0';
1674
-                            q += snprintf(q, c->buffer_size,
1675
-                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1676
-                                          /* XXX: incorrect mime type ? */
1677
-                                          "Content-type: application/x-rtsp\r\n"
1678
-                                          "\r\n"
1679
-                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1680
-                        }
1681
-                        break;
1682
-                    case REDIR_SDP:
1683
-                        {
1684
-                            uint8_t *sdp_data;
1685
-                            int sdp_data_size, len;
1686
-                            struct sockaddr_in my_addr;
1687
-
1688
-                            q += snprintf(q, c->buffer_size,
1689
-                                          "HTTP/1.0 200 OK\r\n"
1690
-                                          "Content-type: application/sdp\r\n"
1691
-                                          "\r\n");
1692
-
1693
-                            len = sizeof(my_addr);
1694
-                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1695
-
1696
-                            /* XXX: should use a dynamic buffer */
1697
-                            sdp_data_size = prepare_sdp_description(stream,
1698
-                                                                    &sdp_data,
1699
-                                                                    my_addr.sin_addr);
1700
-                            if (sdp_data_size > 0) {
1701
-                                memcpy(q, sdp_data, sdp_data_size);
1702
-                                q += sdp_data_size;
1703
-                                *q = '\0';
1704
-                                av_free(sdp_data);
1705
-                            }
1706
-                        }
1707
-                        break;
1708
-                    default:
1709
-                        abort();
1710
-                        break;
1711
-                    }
1712
-
1713
-                    /* prepare output buffer */
1714
-                    c->buffer_ptr = c->buffer;
1715
-                    c->buffer_end = q;
1716
-                    c->state = HTTPSTATE_SEND_HEADER;
1717
-                    return 0;
1718
-                }
1719
-            }
1720
-        }
1721
-
1722
-        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1723
-        goto send_error;
1724
-    }
1725
-
1726
-    stream->conns_served++;
1727
-
1728
-    /* XXX: add there authenticate and IP match */
1729
-
1730
-    if (c->post) {
1731
-        /* if post, it means a feed is being sent */
1732
-        if (!stream->is_feed) {
1733
-            /* However it might be a status report from WMP! Let us log the
1734
-             * data as it might come in handy one day. */
1735
-            char *logline = 0;
1736
-            int client_id = 0;
1737
-
1738
-            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1739
-                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1740
-                    logline = p;
1741
-                    break;
1742
-                }
1743
-                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1744
-                    client_id = strtol(p + 18, 0, 10);
1745
-                p = strchr(p, '\n');
1746
-                if (!p)
1747
-                    break;
1748
-
1749
-                p++;
1750
-            }
1751
-
1752
-            if (logline) {
1753
-                char *eol = strchr(logline, '\n');
1754
-
1755
-                logline += 17;
1756
-
1757
-                if (eol) {
1758
-                    if (eol[-1] == '\r')
1759
-                        eol--;
1760
-                    http_log("%.*s\n", (int) (eol - logline), logline);
1761
-                    c->suppress_log = 1;
1762
-                }
1763
-            }
1764
-
1765
-#ifdef DEBUG
1766
-            http_log("\nGot request:\n%s\n", c->buffer);
1767
-#endif
1768
-
1769
-            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1770
-                HTTPContext *wmpc;
1771
-
1772
-                /* Now we have to find the client_id */
1773
-                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1774
-                    if (wmpc->wmp_client_id == client_id)
1775
-                        break;
1776
-                }
1777
-
1778
-                if (wmpc && modify_current_stream(wmpc, ratebuf))
1779
-                    wmpc->switch_pending = 1;
1780
-            }
1781
-
1782
-            snprintf(msg, sizeof(msg), "POST command not handled");
1783
-            c->stream = 0;
1784
-            goto send_error;
1785
-        }
1786
-        if (http_start_receive_data(c) < 0) {
1787
-            snprintf(msg, sizeof(msg), "could not open feed");
1788
-            goto send_error;
1789
-        }
1790
-        c->http_error = 0;
1791
-        c->state = HTTPSTATE_RECEIVE_DATA;
1792
-        return 0;
1793
-    }
1794
-
1795
-#ifdef DEBUG
1796
-    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1797
-        http_log("\nGot request:\n%s\n", c->buffer);
1798
-#endif
1799
-
1800
-    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1801
-        goto send_status;
1802
-
1803
-    /* open input stream */
1804
-    if (open_input_stream(c, info) < 0) {
1805
-        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1806
-        goto send_error;
1807
-    }
1808
-
1809
-    /* prepare http header */
1810
-    q = c->buffer;
1811
-    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1812
-    mime_type = c->stream->fmt->mime_type;
1813
-    if (!mime_type)
1814
-        mime_type = "application/x-octet-stream";
1815
-    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1816
-
1817
-    /* for asf, we need extra headers */
1818
-    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1819
-        /* Need to allocate a client id */
1820
-
1821
-        c->wmp_client_id = av_lfg_get(&random_state);
1822
-
1823
-        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);
1824
-    }
1825
-    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1826
-    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1827
-
1828
-    /* prepare output buffer */
1829
-    c->http_error = 0;
1830
-    c->buffer_ptr = c->buffer;
1831
-    c->buffer_end = q;
1832
-    c->state = HTTPSTATE_SEND_HEADER;
1833
-    return 0;
1834
- send_error:
1835
-    c->http_error = 404;
1836
-    q = c->buffer;
1837
-    q += snprintf(q, c->buffer_size,
1838
-                  "HTTP/1.0 404 Not Found\r\n"
1839
-                  "Content-type: text/html\r\n"
1840
-                  "\r\n"
1841
-                  "<html>\n"
1842
-                  "<head><title>404 Not Found</title></head>\n"
1843
-                  "<body>%s</body>\n"
1844
-                  "</html>\n", msg);
1845
-    /* prepare output buffer */
1846
-    c->buffer_ptr = c->buffer;
1847
-    c->buffer_end = q;
1848
-    c->state = HTTPSTATE_SEND_HEADER;
1849
-    return 0;
1850
- send_status:
1851
-    compute_status(c);
1852
-    c->http_error = 200; /* horrible : we use this value to avoid
1853
-                            going to the send data state */
1854
-    c->state = HTTPSTATE_SEND_HEADER;
1855
-    return 0;
1856
-}
1857
-
1858
-static void fmt_bytecount(AVIOContext *pb, int64_t count)
1859
-{
1860
-    static const char *suffix = " kMGTP";
1861
-    const char *s;
1862
-
1863
-    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1864
-
1865
-    avio_printf(pb, "%"PRId64"%c", count, *s);
1866
-}
1867
-
1868
-static void compute_status(HTTPContext *c)
1869
-{
1870
-    HTTPContext *c1;
1871
-    FFStream *stream;
1872
-    char *p;
1873
-    time_t ti;
1874
-    int i, len;
1875
-    AVIOContext *pb;
1876
-
1877
-    if (avio_open_dyn_buf(&pb) < 0) {
1878
-        /* XXX: return an error ? */
1879
-        c->buffer_ptr = c->buffer;
1880
-        c->buffer_end = c->buffer;
1881
-        return;
1882
-    }
1883
-
1884
-    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1885
-    avio_printf(pb, "Content-type: %s\r\n", "text/html");
1886
-    avio_printf(pb, "Pragma: no-cache\r\n");
1887
-    avio_printf(pb, "\r\n");
1888
-
1889
-    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1890
-    if (c->stream->feed_filename[0])
1891
-        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1892
-    avio_printf(pb, "</head>\n<body>");
1893
-    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1894
-    /* format status */
1895
-    avio_printf(pb, "<h2>Available Streams</h2>\n");
1896
-    avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1897
-    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");
1898
-    stream = first_stream;
1899
-    while (stream != NULL) {
1900
-        char sfilename[1024];
1901
-        char *eosf;
1902
-
1903
-        if (stream->feed != stream) {
1904
-            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1905
-            eosf = sfilename + strlen(sfilename);
1906
-            if (eosf - sfilename >= 4) {
1907
-                if (strcmp(eosf - 4, ".asf") == 0)
1908
-                    strcpy(eosf - 4, ".asx");
1909
-                else if (strcmp(eosf - 3, ".rm") == 0)
1910
-                    strcpy(eosf - 3, ".ram");
1911
-                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1912
-                    /* generate a sample RTSP director if
1913
-                       unicast. Generate an SDP redirector if
1914
-                       multicast */
1915
-                    eosf = strrchr(sfilename, '.');
1916
-                    if (!eosf)
1917
-                        eosf = sfilename + strlen(sfilename);
1918
-                    if (stream->is_multicast)
1919
-                        strcpy(eosf, ".sdp");
1920
-                    else
1921
-                        strcpy(eosf, ".rtsp");
1922
-                }
1923
-            }
1924
-
1925
-            avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1926
-                         sfilename, stream->filename);
1927
-            avio_printf(pb, "<td align=right> %d <td align=right> ",
1928
-                        stream->conns_served);
1929
-            fmt_bytecount(pb, stream->bytes_served);
1930
-            switch(stream->stream_type) {
1931
-            case STREAM_TYPE_LIVE: {
1932
-                    int audio_bit_rate = 0;
1933
-                    int video_bit_rate = 0;
1934
-                    const char *audio_codec_name = "";
1935
-                    const char *video_codec_name = "";
1936
-                    const char *audio_codec_name_extra = "";
1937
-                    const char *video_codec_name_extra = "";
1938
-
1939
-                    for(i=0;i<stream->nb_streams;i++) {
1940
-                        AVStream *st = stream->streams[i];
1941
-                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1942
-                        switch(st->codec->codec_type) {
1943
-                        case AVMEDIA_TYPE_AUDIO:
1944
-                            audio_bit_rate += st->codec->bit_rate;
1945
-                            if (codec) {
1946
-                                if (*audio_codec_name)
1947
-                                    audio_codec_name_extra = "...";
1948
-                                audio_codec_name = codec->name;
1949
-                            }
1950
-                            break;
1951
-                        case AVMEDIA_TYPE_VIDEO:
1952
-                            video_bit_rate += st->codec->bit_rate;
1953
-                            if (codec) {
1954
-                                if (*video_codec_name)
1955
-                                    video_codec_name_extra = "...";
1956
-                                video_codec_name = codec->name;
1957
-                            }
1958
-                            break;
1959
-                        case AVMEDIA_TYPE_DATA:
1960
-                            video_bit_rate += st->codec->bit_rate;
1961
-                            break;
1962
-                        default:
1963
-                            abort();
1964
-                        }
1965
-                    }
1966
-                    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",
1967
-                                 stream->fmt->name,
1968
-                                 stream->bandwidth,
1969
-                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1970
-                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1971
-                    if (stream->feed)
1972
-                        avio_printf(pb, "<td>%s", stream->feed->filename);
1973
-                    else
1974
-                        avio_printf(pb, "<td>%s", stream->feed_filename);
1975
-                    avio_printf(pb, "\n");
1976
-                }
1977
-                break;
1978
-            default:
1979
-                avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1980
-                break;
1981
-            }
1982
-        }
1983
-        stream = stream->next;
1984
-    }
1985
-    avio_printf(pb, "</table>\n");
1986
-
1987
-    stream = first_stream;
1988
-    while (stream != NULL) {
1989
-        if (stream->feed == stream) {
1990
-            avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1991
-            if (stream->pid) {
1992
-                avio_printf(pb, "Running as pid %d.\n", stream->pid);
1993
-
1994
-#if defined(linux) && !defined(CONFIG_NOCUTILS)
1995
-                {
1996
-                    FILE *pid_stat;
1997
-                    char ps_cmd[64];
1998
-
1999
-                    /* This is somewhat linux specific I guess */
2000
-                    snprintf(ps_cmd, sizeof(ps_cmd),
2001
-                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2002
-                             stream->pid);
2003
-
2004
-                    pid_stat = popen(ps_cmd, "r");
2005
-                    if (pid_stat) {
2006
-                        char cpuperc[10];
2007
-                        char cpuused[64];
2008
-
2009
-                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
2010
-                                   cpuused) == 2) {
2011
-                            avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2012
-                                         cpuperc, cpuused);
2013
-                        }
2014
-                        fclose(pid_stat);
2015
-                    }
2016
-                }
2017
-#endif
2018
-
2019
-                avio_printf(pb, "<p>");
2020
-            }
2021
-            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");
2022
-
2023
-            for (i = 0; i < stream->nb_streams; i++) {
2024
-                AVStream *st = stream->streams[i];
2025
-                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2026
-                const char *type = "unknown";
2027
-                char parameters[64];
2028
-
2029
-                parameters[0] = 0;
2030
-
2031
-                switch(st->codec->codec_type) {
2032
-                case AVMEDIA_TYPE_AUDIO:
2033
-                    type = "audio";
2034
-                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2035
-                    break;
2036
-                case AVMEDIA_TYPE_VIDEO:
2037
-                    type = "video";
2038
-                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2039
-                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2040
-                    break;
2041
-                default:
2042
-                    abort();
2043
-                }
2044
-                avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2045
-                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2046
-            }
2047
-            avio_printf(pb, "</table>\n");
2048
-
2049
-        }
2050
-        stream = stream->next;
2051
-    }
2052
-
2053
-    /* connection status */
2054
-    avio_printf(pb, "<h2>Connection Status</h2>\n");
2055
-
2056
-    avio_printf(pb, "Number of connections: %d / %d<br>\n",
2057
-                 nb_connections, nb_max_connections);
2058
-
2059
-    avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2060
-                 current_bandwidth, max_bandwidth);
2061
-
2062
-    avio_printf(pb, "<table>\n");
2063
-    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");
2064
-    c1 = first_http_ctx;
2065
-    i = 0;
2066
-    while (c1 != NULL) {
2067
-        int bitrate;
2068
-        int j;
2069
-
2070
-        bitrate = 0;
2071
-        if (c1->stream) {
2072
-            for (j = 0; j < c1->stream->nb_streams; j++) {
2073
-                if (!c1->stream->feed)
2074
-                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2075
-                else if (c1->feed_streams[j] >= 0)
2076
-                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2077
-            }
2078
-        }
2079
-
2080
-        i++;
2081
-        p = inet_ntoa(c1->from_addr.sin_addr);
2082
-        avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2083
-                    i,
2084
-                    c1->stream ? c1->stream->filename : "",
2085
-                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2086
-                    p,
2087
-                    c1->protocol,
2088
-                    http_state[c1->state]);
2089
-        fmt_bytecount(pb, bitrate);
2090
-        avio_printf(pb, "<td align=right>");
2091
-        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2092
-        avio_printf(pb, "<td align=right>");
2093
-        fmt_bytecount(pb, c1->data_count);
2094
-        avio_printf(pb, "\n");
2095
-        c1 = c1->next;
2096
-    }
2097
-    avio_printf(pb, "</table>\n");
2098
-
2099
-    /* date */
2100
-    ti = time(NULL);
2101
-    p = ctime(&ti);
2102
-    avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2103
-    avio_printf(pb, "</body>\n</html>\n");
2104
-
2105
-    len = avio_close_dyn_buf(pb, &c->pb_buffer);
2106
-    c->buffer_ptr = c->pb_buffer;
2107
-    c->buffer_end = c->pb_buffer + len;
2108
-}
2109
-
2110
-/* check if the parser needs to be opened for stream i */
2111
-static void open_parser(AVFormatContext *s, int i)
2112
-{
2113
-    AVStream *st = s->streams[i];
2114
-    AVCodec *codec;
2115
-
2116
-    if (!st->codec->codec) {
2117
-        codec = avcodec_find_decoder(st->codec->codec_id);
2118
-        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2119
-            st->codec->parse_only = 1;
2120
-            if (avcodec_open2(st->codec, codec, NULL) < 0)
2121
-                st->codec->parse_only = 0;
2122
-        }
2123
-    }
2124
-}
2125
-
2126
-static int open_input_stream(HTTPContext *c, const char *info)
2127
-{
2128
-    char buf[128];
2129
-    char input_filename[1024];
2130
-    AVFormatContext *s = NULL;
2131
-    int i, ret;
2132
-    int64_t stream_pos;
2133
-
2134
-    /* find file name */
2135
-    if (c->stream->feed) {
2136
-        strcpy(input_filename, c->stream->feed->feed_filename);
2137
-        /* compute position (absolute time) */
2138
-        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2139
-            if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2140
-                return ret;
2141
-        } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2142
-            int prebuffer = strtol(buf, 0, 10);
2143
-            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2144
-        } else
2145
-            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2146
-    } else {
2147
-        strcpy(input_filename, c->stream->feed_filename);
2148
-        /* compute position (relative time) */
2149
-        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2150
-            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2151
-                return ret;
2152
-        } else
2153
-            stream_pos = 0;
2154
-    }
2155
-    if (input_filename[0] == '\0')
2156
-        return -1;
2157
-
2158
-    /* open stream */
2159
-    if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2160
-        http_log("could not open %s: %d\n", input_filename, ret);
2161
-        return -1;
2162
-    }
2163
-    s->flags |= AVFMT_FLAG_GENPTS;
2164
-    c->fmt_in = s;
2165
-    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2166
-        http_log("Could not find stream info '%s'\n", input_filename);
2167
-        av_close_input_file(s);
2168
-        return -1;
2169
-    }
2170
-
2171
-    /* open each parser */
2172
-    for(i=0;i<s->nb_streams;i++)
2173
-        open_parser(s, i);
2174
-
2175
-    /* choose stream as clock source (we favorize video stream if
2176
-       present) for packet sending */
2177
-    c->pts_stream_index = 0;
2178
-    for(i=0;i<c->stream->nb_streams;i++) {
2179
-        if (c->pts_stream_index == 0 &&
2180
-            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2181
-            c->pts_stream_index = i;
2182
-        }
2183
-    }
2184
-
2185
-    if (c->fmt_in->iformat->read_seek)
2186
-        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2187
-    /* set the start time (needed for maxtime and RTP packet timing) */
2188
-    c->start_time = cur_time;
2189
-    c->first_pts = AV_NOPTS_VALUE;
2190
-    return 0;
2191
-}
2192
-
2193
-/* return the server clock (in us) */
2194
-static int64_t get_server_clock(HTTPContext *c)
2195
-{
2196
-    /* compute current pts value from system time */
2197
-    return (cur_time - c->start_time) * 1000;
2198
-}
2199
-
2200
-/* return the estimated time at which the current packet must be sent
2201
-   (in us) */
2202
-static int64_t get_packet_send_clock(HTTPContext *c)
2203
-{
2204
-    int bytes_left, bytes_sent, frame_bytes;
2205
-
2206
-    frame_bytes = c->cur_frame_bytes;
2207
-    if (frame_bytes <= 0)
2208
-        return c->cur_pts;
2209
-    else {
2210
-        bytes_left = c->buffer_end - c->buffer_ptr;
2211
-        bytes_sent = frame_bytes - bytes_left;
2212
-        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2213
-    }
2214
-}
2215
-
2216
-
2217
-static int http_prepare_data(HTTPContext *c)
2218
-{
2219
-    int i, len, ret;
2220
-    AVFormatContext *ctx;
2221
-
2222
-    av_freep(&c->pb_buffer);
2223
-    switch(c->state) {
2224
-    case HTTPSTATE_SEND_DATA_HEADER:
2225
-        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2226
-        av_dict_set(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2227
-        av_dict_set(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2228
-        av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2229
-        av_dict_set(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
2230
-
2231
-        c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2232
-
2233
-        for(i=0;i<c->stream->nb_streams;i++) {
2234
-            AVStream *src;
2235
-            c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2236
-            /* if file or feed, then just take streams from FFStream struct */
2237
-            if (!c->stream->feed ||
2238
-                c->stream->feed == c->stream)
2239
-                src = c->stream->streams[i];
2240
-            else
2241
-                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2242
-
2243
-            *(c->fmt_ctx.streams[i]) = *src;
2244
-            c->fmt_ctx.streams[i]->priv_data = 0;
2245
-            c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2246
-                                           AVStream, not in codec */
2247
-        }
2248
-        /* set output format parameters */
2249
-        c->fmt_ctx.oformat = c->stream->fmt;
2250
-        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2251
-
2252
-        c->got_key_frame = 0;
2253
-
2254
-        /* prepare header and save header data in a stream */
2255
-        if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2256
-            /* XXX: potential leak */
2257
-            return -1;
2258
-        }
2259
-        c->fmt_ctx.pb->seekable = 0;
2260
-
2261
-        /*
2262
-         * HACK to avoid mpeg ps muxer to spit many underflow errors
2263
-         * Default value from Libav
2264
-         * Try to set it use configuration option
2265
-         */
2266
-        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2267
-        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2268
-
2269
-        if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2270
-            http_log("Error writing output header\n");
2271
-            return -1;
2272
-        }
2273
-        av_dict_free(&c->fmt_ctx.metadata);
2274
-
2275
-        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2276
-        c->buffer_ptr = c->pb_buffer;
2277
-        c->buffer_end = c->pb_buffer + len;
2278
-
2279
-        c->state = HTTPSTATE_SEND_DATA;
2280
-        c->last_packet_sent = 0;
2281
-        break;
2282
-    case HTTPSTATE_SEND_DATA:
2283
-        /* find a new packet */
2284
-        /* read a packet from the input stream */
2285
-        if (c->stream->feed)
2286
-            ffm_set_write_index(c->fmt_in,
2287
-                                c->stream->feed->feed_write_index,
2288
-                                c->stream->feed->feed_size);
2289
-
2290
-        if (c->stream->max_time &&
2291
-            c->stream->max_time + c->start_time - cur_time < 0)
2292
-            /* We have timed out */
2293
-            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2294
-        else {
2295
-            AVPacket pkt;
2296
-        redo:
2297
-            ret = av_read_frame(c->fmt_in, &pkt);
2298
-            if (ret < 0) {
2299
-                if (c->stream->feed) {
2300
-                    /* if coming from feed, it means we reached the end of the
2301
-                       ffm file, so must wait for more data */
2302
-                    c->state = HTTPSTATE_WAIT_FEED;
2303
-                    return 1; /* state changed */
2304
-                } else if (ret == AVERROR(EAGAIN)) {
2305
-                    /* input not ready, come back later */
2306
-                    return 0;
2307
-                } else {
2308
-                    if (c->stream->loop) {
2309
-                        av_close_input_file(c->fmt_in);
2310
-                        c->fmt_in = NULL;
2311
-                        if (open_input_stream(c, "") < 0)
2312
-                            goto no_loop;
2313
-                        goto redo;
2314
-                    } else {
2315
-                    no_loop:
2316
-                        /* must send trailer now because eof or error */
2317
-                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2318
-                    }
2319
-                }
2320
-            } else {
2321
-                int source_index = pkt.stream_index;
2322
-                /* update first pts if needed */
2323
-                if (c->first_pts == AV_NOPTS_VALUE) {
2324
-                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2325
-                    c->start_time = cur_time;
2326
-                }
2327
-                /* send it to the appropriate stream */
2328
-                if (c->stream->feed) {
2329
-                    /* if coming from a feed, select the right stream */
2330
-                    if (c->switch_pending) {
2331
-                        c->switch_pending = 0;
2332
-                        for(i=0;i<c->stream->nb_streams;i++) {
2333
-                            if (c->switch_feed_streams[i] == pkt.stream_index)
2334
-                                if (pkt.flags & AV_PKT_FLAG_KEY)
2335
-                                    c->switch_feed_streams[i] = -1;
2336
-                            if (c->switch_feed_streams[i] >= 0)
2337
-                                c->switch_pending = 1;
2338
-                        }
2339
-                    }
2340
-                    for(i=0;i<c->stream->nb_streams;i++) {
2341
-                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2342
-                            AVStream *st = c->fmt_in->streams[source_index];
2343
-                            pkt.stream_index = i;
2344
-                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2345
-                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2346
-                                 c->stream->nb_streams == 1))
2347
-                                c->got_key_frame = 1;
2348
-                            if (!c->stream->send_on_key || c->got_key_frame)
2349
-                                goto send_it;
2350
-                        }
2351
-                    }
2352
-                } else {
2353
-                    AVCodecContext *codec;
2354
-                    AVStream *ist, *ost;
2355
-                send_it:
2356
-                    ist = c->fmt_in->streams[source_index];
2357
-                    /* specific handling for RTP: we use several
2358
-                       output stream (one for each RTP
2359
-                       connection). XXX: need more abstract handling */
2360
-                    if (c->is_packetized) {
2361
-                        /* compute send time and duration */
2362
-                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2363
-                        c->cur_pts -= c->first_pts;
2364
-                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2365
-                        /* find RTP context */
2366
-                        c->packet_stream_index = pkt.stream_index;
2367
-                        ctx = c->rtp_ctx[c->packet_stream_index];
2368
-                        if(!ctx) {
2369
-                            av_free_packet(&pkt);
2370
-                            break;
2371
-                        }
2372
-                        codec = ctx->streams[0]->codec;
2373
-                        /* only one stream per RTP connection */
2374
-                        pkt.stream_index = 0;
2375
-                    } else {
2376
-                        ctx = &c->fmt_ctx;
2377
-                        /* Fudge here */
2378
-                        codec = ctx->streams[pkt.stream_index]->codec;
2379
-                    }
2380
-
2381
-                    if (c->is_packetized) {
2382
-                        int max_packet_size;
2383
-                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2384
-                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2385
-                        else
2386
-                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2387
-                        ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2388
-                    } else {
2389
-                        ret = avio_open_dyn_buf(&ctx->pb);
2390
-                    }
2391
-                    if (ret < 0) {
2392
-                        /* XXX: potential leak */
2393
-                        return -1;
2394
-                    }
2395
-                    ost = ctx->streams[pkt.stream_index];
2396
-
2397
-                    ctx->pb->seekable = 0;
2398
-                    if (pkt.dts != AV_NOPTS_VALUE)
2399
-                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2400
-                    if (pkt.pts != AV_NOPTS_VALUE)
2401
-                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2402
-                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2403
-                    if (av_write_frame(ctx, &pkt) < 0) {
2404
-                        http_log("Error writing frame to output\n");
2405
-                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2406
-                    }
2407
-
2408
-                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2409
-                    c->cur_frame_bytes = len;
2410
-                    c->buffer_ptr = c->pb_buffer;
2411
-                    c->buffer_end = c->pb_buffer + len;
2412
-
2413
-                    codec->frame_number++;
2414
-                    if (len == 0) {
2415
-                        av_free_packet(&pkt);
2416
-                        goto redo;
2417
-                    }
2418
-                }
2419
-                av_free_packet(&pkt);
2420
-            }
2421
-        }
2422
-        break;
2423
-    default:
2424
-    case HTTPSTATE_SEND_DATA_TRAILER:
2425
-        /* last packet test ? */
2426
-        if (c->last_packet_sent || c->is_packetized)
2427
-            return -1;
2428
-        ctx = &c->fmt_ctx;
2429
-        /* prepare header */
2430
-        if (avio_open_dyn_buf(&ctx->pb) < 0) {
2431
-            /* XXX: potential leak */
2432
-            return -1;
2433
-        }
2434
-        c->fmt_ctx.pb->seekable = 0;
2435
-        av_write_trailer(ctx);
2436
-        len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2437
-        c->buffer_ptr = c->pb_buffer;
2438
-        c->buffer_end = c->pb_buffer + len;
2439
-
2440
-        c->last_packet_sent = 1;
2441
-        break;
2442
-    }
2443
-    return 0;
2444
-}
2445
-
2446
-/* should convert the format at the same time */
2447
-/* send data starting at c->buffer_ptr to the output connection
2448
-   (either UDP or TCP connection) */
2449
-static int http_send_data(HTTPContext *c)
2450
-{
2451
-    int len, ret;
2452
-
2453
-    for(;;) {
2454
-        if (c->buffer_ptr >= c->buffer_end) {
2455
-            ret = http_prepare_data(c);
2456
-            if (ret < 0)
2457
-                return -1;
2458
-            else if (ret != 0)
2459
-                /* state change requested */
2460
-                break;
2461
-        } else {
2462
-            if (c->is_packetized) {
2463
-                /* RTP data output */
2464
-                len = c->buffer_end - c->buffer_ptr;
2465
-                if (len < 4) {
2466
-                    /* fail safe - should never happen */
2467
-                fail1:
2468
-                    c->buffer_ptr = c->buffer_end;
2469
-                    return 0;
2470
-                }
2471
-                len = (c->buffer_ptr[0] << 24) |
2472
-                    (c->buffer_ptr[1] << 16) |
2473
-                    (c->buffer_ptr[2] << 8) |
2474
-                    (c->buffer_ptr[3]);
2475
-                if (len > (c->buffer_end - c->buffer_ptr))
2476
-                    goto fail1;
2477
-                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2478
-                    /* nothing to send yet: we can wait */
2479
-                    return 0;
2480
-                }
2481
-
2482
-                c->data_count += len;
2483
-                update_datarate(&c->datarate, c->data_count);
2484
-                if (c->stream)
2485
-                    c->stream->bytes_served += len;
2486
-
2487
-                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2488
-                    /* RTP packets are sent inside the RTSP TCP connection */
2489
-                    AVIOContext *pb;
2490
-                    int interleaved_index, size;
2491
-                    uint8_t header[4];
2492
-                    HTTPContext *rtsp_c;
2493
-
2494
-                    rtsp_c = c->rtsp_c;
2495
-                    /* if no RTSP connection left, error */
2496
-                    if (!rtsp_c)
2497
-                        return -1;
2498
-                    /* if already sending something, then wait. */
2499
-                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2500
-                        break;
2501
-                    if (avio_open_dyn_buf(&pb) < 0)
2502
-                        goto fail1;
2503
-                    interleaved_index = c->packet_stream_index * 2;
2504
-                    /* RTCP packets are sent at odd indexes */
2505
-                    if (c->buffer_ptr[1] == 200)
2506
-                        interleaved_index++;
2507
-                    /* write RTSP TCP header */
2508
-                    header[0] = '$';
2509
-                    header[1] = interleaved_index;
2510
-                    header[2] = len >> 8;
2511
-                    header[3] = len;
2512
-                    avio_write(pb, header, 4);
2513
-                    /* write RTP packet data */
2514
-                    c->buffer_ptr += 4;
2515
-                    avio_write(pb, c->buffer_ptr, len);
2516
-                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
2517
-                    /* prepare asynchronous TCP sending */
2518
-                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2519
-                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2520
-                    c->buffer_ptr += len;
2521
-
2522
-                    /* send everything we can NOW */
2523
-                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2524
-                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2525
-                    if (len > 0)
2526
-                        rtsp_c->packet_buffer_ptr += len;
2527
-                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2528
-                        /* if we could not send all the data, we will
2529
-                           send it later, so a new state is needed to
2530
-                           "lock" the RTSP TCP connection */
2531
-                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2532
-                        break;
2533
-                    } else
2534
-                        /* all data has been sent */
2535
-                        av_freep(&c->packet_buffer);
2536
-                } else {
2537
-                    /* send RTP packet directly in UDP */
2538
-                    c->buffer_ptr += 4;
2539
-                    url_write(c->rtp_handles[c->packet_stream_index],
2540
-                              c->buffer_ptr, len);
2541
-                    c->buffer_ptr += len;
2542
-                    /* here we continue as we can send several packets per 10 ms slot */
2543
-                }
2544
-            } else {
2545
-                /* TCP data output */
2546
-                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2547
-                if (len < 0) {
2548
-                    if (ff_neterrno() != AVERROR(EAGAIN) &&
2549
-                        ff_neterrno() != AVERROR(EINTR))
2550
-                        /* error : close connection */
2551
-                        return -1;
2552
-                    else
2553
-                        return 0;
2554
-                } else
2555
-                    c->buffer_ptr += len;
2556
-
2557
-                c->data_count += len;
2558
-                update_datarate(&c->datarate, c->data_count);
2559
-                if (c->stream)
2560
-                    c->stream->bytes_served += len;
2561
-                break;
2562
-            }
2563
-        }
2564
-    } /* for(;;) */
2565
-    return 0;
2566
-}
2567
-
2568
-static int http_start_receive_data(HTTPContext *c)
2569
-{
2570
-    int fd;
2571
-
2572
-    if (c->stream->feed_opened)
2573
-        return -1;
2574
-
2575
-    /* Don't permit writing to this one */
2576
-    if (c->stream->readonly)
2577
-        return -1;
2578
-
2579
-    /* open feed */
2580
-    fd = open(c->stream->feed_filename, O_RDWR);
2581
-    if (fd < 0) {
2582
-        http_log("Error opening feeder file: %s\n", strerror(errno));
2583
-        return -1;
2584
-    }
2585
-    c->feed_fd = fd;
2586
-
2587
-    if (c->stream->truncate) {
2588
-        /* truncate feed file */
2589
-        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2590
-        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2591
-        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2592
-    } else {
2593
-        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2594
-            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2595
-            return -1;
2596
-        }
2597
-    }
2598
-
2599
-    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2600
-    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2601
-    lseek(fd, 0, SEEK_SET);
2602
-
2603
-    /* init buffer input */
2604
-    c->buffer_ptr = c->buffer;
2605
-    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2606
-    c->stream->feed_opened = 1;
2607
-    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2608
-    return 0;
2609
-}
2610
-
2611
-static int http_receive_data(HTTPContext *c)
2612
-{
2613
-    HTTPContext *c1;
2614
-    int len, loop_run = 0;
2615
-
2616
-    while (c->chunked_encoding && !c->chunk_size &&
2617
-           c->buffer_end > c->buffer_ptr) {
2618
-        /* read chunk header, if present */
2619
-        len = recv(c->fd, c->buffer_ptr, 1, 0);
2620
-
2621
-        if (len < 0) {
2622
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
2623
-                ff_neterrno() != AVERROR(EINTR))
2624
-                /* error : close connection */
2625
-                goto fail;
2626
-            return 0;
2627
-        } else if (len == 0) {
2628
-            /* end of connection : close it */
2629
-            goto fail;
2630
-        } else if (c->buffer_ptr - c->buffer >= 2 &&
2631
-                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2632
-            c->chunk_size = strtol(c->buffer, 0, 16);
2633
-            if (c->chunk_size == 0) // end of stream
2634
-                goto fail;
2635
-            c->buffer_ptr = c->buffer;
2636
-            break;
2637
-        } else if (++loop_run > 10) {
2638
-            /* no chunk header, abort */
2639
-            goto fail;
2640
-        } else {
2641
-            c->buffer_ptr++;
2642
-        }
2643
-    }
2644
-
2645
-    if (c->buffer_end > c->buffer_ptr) {
2646
-        len = recv(c->fd, c->buffer_ptr,
2647
-                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2648
-        if (len < 0) {
2649
-            if (ff_neterrno() != AVERROR(EAGAIN) &&
2650
-                ff_neterrno() != AVERROR(EINTR))
2651
-                /* error : close connection */
2652
-                goto fail;
2653
-        } else if (len == 0)
2654
-            /* end of connection : close it */
2655
-            goto fail;
2656
-        else {
2657
-            c->chunk_size -= len;
2658
-            c->buffer_ptr += len;
2659
-            c->data_count += len;
2660
-            update_datarate(&c->datarate, c->data_count);
2661
-        }
2662
-    }
2663
-
2664
-    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2665
-        if (c->buffer[0] != 'f' ||
2666
-            c->buffer[1] != 'm') {
2667
-            http_log("Feed stream has become desynchronized -- disconnecting\n");
2668
-            goto fail;
2669
-        }
2670
-    }
2671
-
2672
-    if (c->buffer_ptr >= c->buffer_end) {
2673
-        FFStream *feed = c->stream;
2674
-        /* a packet has been received : write it in the store, except
2675
-           if header */
2676
-        if (c->data_count > FFM_PACKET_SIZE) {
2677
-
2678
-            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2679
-            /* XXX: use llseek or url_seek */
2680
-            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2681
-            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2682
-                http_log("Error writing to feed file: %s\n", strerror(errno));
2683
-                goto fail;
2684
-            }
2685
-
2686
-            feed->feed_write_index += FFM_PACKET_SIZE;
2687
-            /* update file size */
2688
-            if (feed->feed_write_index > c->stream->feed_size)
2689
-                feed->feed_size = feed->feed_write_index;
2690
-
2691
-            /* handle wrap around if max file size reached */
2692
-            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2693
-                feed->feed_write_index = FFM_PACKET_SIZE;
2694
-
2695
-            /* write index */
2696
-            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2697
-                http_log("Error writing index to feed file: %s\n", strerror(errno));
2698
-                goto fail;
2699
-            }
2700
-
2701
-            /* wake up any waiting connections */
2702
-            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2703
-                if (c1->state == HTTPSTATE_WAIT_FEED &&
2704
-                    c1->stream->feed == c->stream->feed)
2705
-                    c1->state = HTTPSTATE_SEND_DATA;
2706
-            }
2707
-        } else {
2708
-            /* We have a header in our hands that contains useful data */
2709
-            AVFormatContext *s = avformat_alloc_context();
2710
-            AVIOContext *pb;
2711
-            AVInputFormat *fmt_in;
2712
-            int i;
2713
-
2714
-            if (!s)
2715
-                goto fail;
2716
-
2717
-            /* use feed output format name to find corresponding input format */
2718
-            fmt_in = av_find_input_format(feed->fmt->name);
2719
-            if (!fmt_in)
2720
-                goto fail;
2721
-
2722
-            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2723
-                                    0, NULL, NULL, NULL, NULL);
2724
-            pb->seekable = 0;
2725
-
2726
-            s->pb = pb;
2727
-            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2728
-                av_free(pb);
2729
-                goto fail;
2730
-            }
2731
-
2732
-            /* Now we have the actual streams */
2733
-            if (s->nb_streams != feed->nb_streams) {
2734
-                av_close_input_stream(s);
2735
-                av_free(pb);
2736
-                http_log("Feed '%s' stream number does not match registered feed\n",
2737
-                         c->stream->feed_filename);
2738
-                goto fail;
2739
-            }
2740
-
2741
-            for (i = 0; i < s->nb_streams; i++) {
2742
-                AVStream *fst = feed->streams[i];
2743
-                AVStream *st = s->streams[i];
2744
-                avcodec_copy_context(fst->codec, st->codec);
2745
-            }
2746
-
2747
-            av_close_input_stream(s);
2748
-            av_free(pb);
2749
-        }
2750
-        c->buffer_ptr = c->buffer;
2751
-    }
2752
-
2753
-    return 0;
2754
- fail:
2755
-    c->stream->feed_opened = 0;
2756
-    close(c->feed_fd);
2757
-    /* wake up any waiting connections to stop waiting for feed */
2758
-    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2759
-        if (c1->state == HTTPSTATE_WAIT_FEED &&
2760
-            c1->stream->feed == c->stream->feed)
2761
-            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2762
-    }
2763
-    return -1;
2764
-}
2765
-
2766
-/********************************************************************/
2767
-/* RTSP handling */
2768
-
2769
-static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2770
-{
2771
-    const char *str;
2772
-    time_t ti;
2773
-    struct tm *tm;
2774
-    char buf2[32];
2775
-
2776
-    switch(error_number) {
2777
-    case RTSP_STATUS_OK:
2778
-        str = "OK";
2779
-        break;
2780
-    case RTSP_STATUS_METHOD:
2781
-        str = "Method Not Allowed";
2782
-        break;
2783
-    case RTSP_STATUS_BANDWIDTH:
2784
-        str = "Not Enough Bandwidth";
2785
-        break;
2786
-    case RTSP_STATUS_SESSION:
2787
-        str = "Session Not Found";
2788
-        break;
2789
-    case RTSP_STATUS_STATE:
2790
-        str = "Method Not Valid in This State";
2791
-        break;
2792
-    case RTSP_STATUS_AGGREGATE:
2793
-        str = "Aggregate operation not allowed";
2794
-        break;
2795
-    case RTSP_STATUS_ONLY_AGGREGATE:
2796
-        str = "Only aggregate operation allowed";
2797
-        break;
2798
-    case RTSP_STATUS_TRANSPORT:
2799
-        str = "Unsupported transport";
2800
-        break;
2801
-    case RTSP_STATUS_INTERNAL:
2802
-        str = "Internal Server Error";
2803
-        break;
2804
-    case RTSP_STATUS_SERVICE:
2805
-        str = "Service Unavailable";
2806
-        break;
2807
-    case RTSP_STATUS_VERSION:
2808
-        str = "RTSP Version not supported";
2809
-        break;
2810
-    default:
2811
-        str = "Unknown Error";
2812
-        break;
2813
-    }
2814
-
2815
-    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2816
-    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2817
-
2818
-    /* output GMT time */
2819
-    ti = time(NULL);
2820
-    tm = gmtime(&ti);
2821
-    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2822
-    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2823
-}
2824
-
2825
-static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2826
-{
2827
-    rtsp_reply_header(c, error_number);
2828
-    avio_printf(c->pb, "\r\n");
2829
-}
2830
-
2831
-static int rtsp_parse_request(HTTPContext *c)
2832
-{
2833
-    const char *p, *p1, *p2;
2834
-    char cmd[32];
2835
-    char url[1024];
2836
-    char protocol[32];
2837
-    char line[1024];
2838
-    int len;
2839
-    RTSPMessageHeader header1, *header = &header1;
2840
-
2841
-    c->buffer_ptr[0] = '\0';
2842
-    p = c->buffer;
2843
-
2844
-    get_word(cmd, sizeof(cmd), &p);
2845
-    get_word(url, sizeof(url), &p);
2846
-    get_word(protocol, sizeof(protocol), &p);
2847
-
2848
-    av_strlcpy(c->method, cmd, sizeof(c->method));
2849
-    av_strlcpy(c->url, url, sizeof(c->url));
2850
-    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2851
-
2852
-    if (avio_open_dyn_buf(&c->pb) < 0) {
2853
-        /* XXX: cannot do more */
2854
-        c->pb = NULL; /* safety */
2855
-        return -1;
2856
-    }
2857
-
2858
-    /* check version name */
2859
-    if (strcmp(protocol, "RTSP/1.0") != 0) {
2860
-        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2861
-        goto the_end;
2862
-    }
2863
-
2864
-    /* parse each header line */
2865
-    memset(header, 0, sizeof(*header));
2866
-    /* skip to next line */
2867
-    while (*p != '\n' && *p != '\0')
2868
-        p++;
2869
-    if (*p == '\n')
2870
-        p++;
2871
-    while (*p != '\0') {
2872
-        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2873
-        if (!p1)
2874
-            break;
2875
-        p2 = p1;
2876
-        if (p2 > p && p2[-1] == '\r')
2877
-            p2--;
2878
-        /* skip empty line */
2879
-        if (p2 == p)
2880
-            break;
2881
-        len = p2 - p;
2882
-        if (len > sizeof(line) - 1)
2883
-            len = sizeof(line) - 1;
2884
-        memcpy(line, p, len);
2885
-        line[len] = '\0';
2886
-        ff_rtsp_parse_line(header, line, NULL, NULL);
2887
-        p = p1 + 1;
2888
-    }
2889
-
2890
-    /* handle sequence number */
2891
-    c->seq = header->seq;
2892
-
2893
-    if (!strcmp(cmd, "DESCRIBE"))
2894
-        rtsp_cmd_describe(c, url);
2895
-    else if (!strcmp(cmd, "OPTIONS"))
2896
-        rtsp_cmd_options(c, url);
2897
-    else if (!strcmp(cmd, "SETUP"))
2898
-        rtsp_cmd_setup(c, url, header);
2899
-    else if (!strcmp(cmd, "PLAY"))
2900
-        rtsp_cmd_play(c, url, header);
2901
-    else if (!strcmp(cmd, "PAUSE"))
2902
-        rtsp_cmd_pause(c, url, header);
2903
-    else if (!strcmp(cmd, "TEARDOWN"))
2904
-        rtsp_cmd_teardown(c, url, header);
2905
-    else
2906
-        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2907
-
2908
- the_end:
2909
-    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2910
-    c->pb = NULL; /* safety */
2911
-    if (len < 0) {
2912
-        /* XXX: cannot do more */
2913
-        return -1;
2914
-    }
2915
-    c->buffer_ptr = c->pb_buffer;
2916
-    c->buffer_end = c->pb_buffer + len;
2917
-    c->state = RTSPSTATE_SEND_REPLY;
2918
-    return 0;
2919
-}
2920
-
2921
-static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2922
-                                   struct in_addr my_ip)
2923
-{
2924
-    AVFormatContext *avc;
2925
-    AVStream *avs = NULL;
2926
-    int i;
2927
-
2928
-    avc =  avformat_alloc_context();
2929
-    if (avc == NULL) {
2930
-        return -1;
2931
-    }
2932
-    av_dict_set(&avc->metadata, "title",
2933
-               stream->title[0] ? stream->title : "No Title", 0);
2934
-    avc->nb_streams = stream->nb_streams;
2935
-    if (stream->is_multicast) {
2936
-        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2937
-                 inet_ntoa(stream->multicast_ip),
2938
-                 stream->multicast_port, stream->multicast_ttl);
2939
-    } else {
2940
-        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2941
-    }
2942
-
2943
-    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2944
-        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2945
-        goto sdp_done;
2946
-    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2947
-        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2948
-        goto sdp_done;
2949
-
2950
-    for(i = 0; i < stream->nb_streams; i++) {
2951
-        avc->streams[i] = &avs[i];
2952
-        avc->streams[i]->codec = stream->streams[i]->codec;
2953
-    }
2954
-    *pbuffer = av_mallocz(2048);
2955
-    av_sdp_create(&avc, 1, *pbuffer, 2048);
2956
-
2957
- sdp_done:
2958
-    av_free(avc->streams);
2959
-    av_dict_free(&avc->metadata);
2960
-    av_free(avc);
2961
-    av_free(avs);
2962
-
2963
-    return strlen(*pbuffer);
2964
-}
2965
-
2966
-static void rtsp_cmd_options(HTTPContext *c, const char *url)
2967
-{
2968
-//    rtsp_reply_header(c, RTSP_STATUS_OK);
2969
-    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2970
-    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2971
-    avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2972
-    avio_printf(c->pb, "\r\n");
2973
-}
2974
-
2975
-static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2976
-{
2977
-    FFStream *stream;
2978
-    char path1[1024];
2979
-    const char *path;
2980
-    uint8_t *content;
2981
-    int content_length, len;
2982
-    struct sockaddr_in my_addr;
2983
-
2984
-    /* find which url is asked */
2985
-    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2986
-    path = path1;
2987
-    if (*path == '/')
2988
-        path++;
2989
-
2990
-    for(stream = first_stream; stream != NULL; stream = stream->next) {
2991
-        if (!stream->is_feed &&
2992
-            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2993
-            !strcmp(path, stream->filename)) {
2994
-            goto found;
2995
-        }
2996
-    }
2997
-    /* no stream found */
2998
-    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2999
-    return;
3000
-
3001
- found:
3002
-    /* prepare the media description in sdp format */
3003
-
3004
-    /* get the host IP */
3005
-    len = sizeof(my_addr);
3006
-    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3007
-    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3008
-    if (content_length < 0) {
3009
-        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3010
-        return;
3011
-    }
3012
-    rtsp_reply_header(c, RTSP_STATUS_OK);
3013
-    avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3014
-    avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3015
-    avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3016
-    avio_printf(c->pb, "\r\n");
3017
-    avio_write(c->pb, content, content_length);
3018
-    av_free(content);
3019
-}
3020
-
3021
-static HTTPContext *find_rtp_session(const char *session_id)
3022
-{
3023
-    HTTPContext *c;
3024
-
3025
-    if (session_id[0] == '\0')
3026
-        return NULL;
3027
-
3028
-    for(c = first_http_ctx; c != NULL; c = c->next) {
3029
-        if (!strcmp(c->session_id, session_id))
3030
-            return c;
3031
-    }
3032
-    return NULL;
3033
-}
3034
-
3035
-static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3036
-{
3037
-    RTSPTransportField *th;
3038
-    int i;
3039
-
3040
-    for(i=0;i<h->nb_transports;i++) {
3041
-        th = &h->transports[i];
3042
-        if (th->lower_transport == lower_transport)
3043
-            return th;
3044
-    }
3045
-    return NULL;
3046
-}
3047
-
3048
-static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3049
-                           RTSPMessageHeader *h)
3050
-{
3051
-    FFStream *stream;
3052
-    int stream_index, rtp_port, rtcp_port;
3053
-    char buf[1024];
3054
-    char path1[1024];
3055
-    const char *path;
3056
-    HTTPContext *rtp_c;
3057
-    RTSPTransportField *th;
3058
-    struct sockaddr_in dest_addr;
3059
-    RTSPActionServerSetup setup;
3060
-
3061
-    /* find which url is asked */
3062
-    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3063
-    path = path1;
3064
-    if (*path == '/')
3065
-        path++;
3066
-
3067
-    /* now check each stream */
3068
-    for(stream = first_stream; stream != NULL; stream = stream->next) {
3069
-        if (!stream->is_feed &&
3070
-            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3071
-            /* accept aggregate filenames only if single stream */
3072
-            if (!strcmp(path, stream->filename)) {
3073
-                if (stream->nb_streams != 1) {
3074
-                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3075
-                    return;
3076
-                }
3077
-                stream_index = 0;
3078
-                goto found;
3079
-            }
3080
-
3081
-            for(stream_index = 0; stream_index < stream->nb_streams;
3082
-                stream_index++) {
3083
-                snprintf(buf, sizeof(buf), "%s/streamid=%d",
3084
-                         stream->filename, stream_index);
3085
-                if (!strcmp(path, buf))
3086
-                    goto found;
3087
-            }
3088
-        }
3089
-    }
3090
-    /* no stream found */
3091
-    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3092
-    return;
3093
- found:
3094
-
3095
-    /* generate session id if needed */
3096
-    if (h->session_id[0] == '\0')
3097
-        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3098
-                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3099
-
3100
-    /* find rtp session, and create it if none found */
3101
-    rtp_c = find_rtp_session(h->session_id);
3102
-    if (!rtp_c) {
3103
-        /* always prefer UDP */
3104
-        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3105
-        if (!th) {
3106
-            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3107
-            if (!th) {
3108
-                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3109
-                return;
3110
-            }
3111
-        }
3112
-
3113
-        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3114
-                                   th->lower_transport);
3115
-        if (!rtp_c) {
3116
-            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3117
-            return;
3118
-        }
3119
-
3120
-        /* open input stream */
3121
-        if (open_input_stream(rtp_c, "") < 0) {
3122
-            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3123
-            return;
3124
-        }
3125
-    }
3126
-
3127
-    /* test if stream is OK (test needed because several SETUP needs
3128
-       to be done for a given file) */
3129
-    if (rtp_c->stream != stream) {
3130
-        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3131
-        return;
3132
-    }
3133
-
3134
-    /* test if stream is already set up */
3135
-    if (rtp_c->rtp_ctx[stream_index]) {
3136
-        rtsp_reply_error(c, RTSP_STATUS_STATE);
3137
-        return;
3138
-    }
3139
-
3140
-    /* check transport */
3141
-    th = find_transport(h, rtp_c->rtp_protocol);
3142
-    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3143
-                th->client_port_min <= 0)) {
3144
-        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3145
-        return;
3146
-    }
3147
-
3148
-    /* setup default options */
3149
-    setup.transport_option[0] = '\0';
3150
-    dest_addr = rtp_c->from_addr;
3151
-    dest_addr.sin_port = htons(th->client_port_min);
3152
-
3153
-    /* setup stream */
3154
-    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3155
-        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3156
-        return;
3157
-    }
3158
-
3159
-    /* now everything is OK, so we can send the connection parameters */
3160
-    rtsp_reply_header(c, RTSP_STATUS_OK);
3161
-    /* session ID */
3162
-    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3163
-
3164
-    switch(rtp_c->rtp_protocol) {
3165
-    case RTSP_LOWER_TRANSPORT_UDP:
3166
-        rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3167
-        rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3168
-        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3169
-                    "client_port=%d-%d;server_port=%d-%d",
3170
-                    th->client_port_min, th->client_port_max,
3171
-                    rtp_port, rtcp_port);
3172
-        break;
3173
-    case RTSP_LOWER_TRANSPORT_TCP:
3174
-        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3175
-                    stream_index * 2, stream_index * 2 + 1);
3176
-        break;
3177
-    default:
3178
-        break;
3179
-    }
3180
-    if (setup.transport_option[0] != '\0')
3181
-        avio_printf(c->pb, ";%s", setup.transport_option);
3182
-    avio_printf(c->pb, "\r\n");
3183
-
3184
-
3185
-    avio_printf(c->pb, "\r\n");
3186
-}
3187
-
3188
-
3189
-/* find an rtp connection by using the session ID. Check consistency
3190
-   with filename */
3191
-static HTTPContext *find_rtp_session_with_url(const char *url,
3192
-                                              const char *session_id)
3193
-{
3194
-    HTTPContext *rtp_c;
3195
-    char path1[1024];
3196
-    const char *path;
3197
-    char buf[1024];
3198
-    int s, len;
3199
-
3200
-    rtp_c = find_rtp_session(session_id);
3201
-    if (!rtp_c)
3202
-        return NULL;
3203
-
3204
-    /* find which url is asked */
3205
-    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3206
-    path = path1;
3207
-    if (*path == '/')
3208
-        path++;
3209
-    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3210
-    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3211
-      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3212
-        rtp_c->stream->filename, s);
3213
-      if(!strncmp(path, buf, sizeof(buf))) {
3214
-    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3215
-        return rtp_c;
3216
-      }
3217
-    }
3218
-    len = strlen(path);
3219
-    if (len > 0 && path[len - 1] == '/' &&
3220
-        !strncmp(path, rtp_c->stream->filename, len - 1))
3221
-        return rtp_c;
3222
-    return NULL;
3223
-}
3224
-
3225
-static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3226
-{
3227
-    HTTPContext *rtp_c;
3228
-
3229
-    rtp_c = find_rtp_session_with_url(url, h->session_id);
3230
-    if (!rtp_c) {
3231
-        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3232
-        return;
3233
-    }
3234
-
3235
-    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3236
-        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3237
-        rtp_c->state != HTTPSTATE_READY) {
3238
-        rtsp_reply_error(c, RTSP_STATUS_STATE);
3239
-        return;
3240
-    }
3241
-
3242
-    rtp_c->state = HTTPSTATE_SEND_DATA;
3243
-
3244
-    /* now everything is OK, so we can send the connection parameters */
3245
-    rtsp_reply_header(c, RTSP_STATUS_OK);
3246
-    /* session ID */
3247
-    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3248
-    avio_printf(c->pb, "\r\n");
3249
-}
3250
-
3251
-static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3252
-{
3253
-    HTTPContext *rtp_c;
3254
-
3255
-    rtp_c = find_rtp_session_with_url(url, h->session_id);
3256
-    if (!rtp_c) {
3257
-        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3258
-        return;
3259
-    }
3260
-
3261
-    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3262
-        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3263
-        rtsp_reply_error(c, RTSP_STATUS_STATE);
3264
-        return;
3265
-    }
3266
-
3267
-    rtp_c->state = HTTPSTATE_READY;
3268
-    rtp_c->first_pts = AV_NOPTS_VALUE;
3269
-    /* now everything is OK, so we can send the connection parameters */
3270
-    rtsp_reply_header(c, RTSP_STATUS_OK);
3271
-    /* session ID */
3272
-    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3273
-    avio_printf(c->pb, "\r\n");
3274
-}
3275
-
3276
-static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3277
-{
3278
-    HTTPContext *rtp_c;
3279
-
3280
-    rtp_c = find_rtp_session_with_url(url, h->session_id);
3281
-    if (!rtp_c) {
3282
-        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3283
-        return;
3284
-    }
3285
-
3286
-    /* now everything is OK, so we can send the connection parameters */
3287
-    rtsp_reply_header(c, RTSP_STATUS_OK);
3288
-    /* session ID */
3289
-    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3290
-    avio_printf(c->pb, "\r\n");
3291
-
3292
-    /* abort the session */
3293
-    close_connection(rtp_c);
3294
-}
3295
-
3296
-
3297
-/********************************************************************/
3298
-/* RTP handling */
3299
-
3300
-static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3301
-                                       FFStream *stream, const char *session_id,
3302
-                                       enum RTSPLowerTransport rtp_protocol)
3303
-{
3304
-    HTTPContext *c = NULL;
3305
-    const char *proto_str;
3306
-
3307
-    /* XXX: should output a warning page when coming
3308
-       close to the connection limit */
3309
-    if (nb_connections >= nb_max_connections)
3310
-        goto fail;
3311
-
3312
-    /* add a new connection */
3313
-    c = av_mallocz(sizeof(HTTPContext));
3314
-    if (!c)
3315
-        goto fail;
3316
-
3317
-    c->fd = -1;
3318
-    c->poll_entry = NULL;
3319
-    c->from_addr = *from_addr;
3320
-    c->buffer_size = IOBUFFER_INIT_SIZE;
3321
-    c->buffer = av_malloc(c->buffer_size);
3322
-    if (!c->buffer)
3323
-        goto fail;
3324
-    nb_connections++;
3325
-    c->stream = stream;
3326
-    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3327
-    c->state = HTTPSTATE_READY;
3328
-    c->is_packetized = 1;
3329
-    c->rtp_protocol = rtp_protocol;
3330
-
3331
-    /* protocol is shown in statistics */
3332
-    switch(c->rtp_protocol) {
3333
-    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3334
-        proto_str = "MCAST";
3335
-        break;
3336
-    case RTSP_LOWER_TRANSPORT_UDP:
3337
-        proto_str = "UDP";
3338
-        break;
3339
-    case RTSP_LOWER_TRANSPORT_TCP:
3340
-        proto_str = "TCP";
3341
-        break;
3342
-    default:
3343
-        proto_str = "???";
3344
-        break;
3345
-    }
3346
-    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3347
-    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3348
-
3349
-    current_bandwidth += stream->bandwidth;
3350
-
3351
-    c->next = first_http_ctx;
3352
-    first_http_ctx = c;
3353
-    return c;
3354
-
3355
- fail:
3356
-    if (c) {
3357
-        av_free(c->buffer);
3358
-        av_free(c);
3359
-    }
3360
-    return NULL;
3361
-}
3362
-
3363
-/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3364
-   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3365
-   used. */
3366
-static int rtp_new_av_stream(HTTPContext *c,
3367
-                             int stream_index, struct sockaddr_in *dest_addr,
3368
-                             HTTPContext *rtsp_c)
3369
-{
3370
-    AVFormatContext *ctx;
3371
-    AVStream *st;
3372
-    char *ipaddr;
3373
-    URLContext *h = NULL;
3374
-    uint8_t *dummy_buf;
3375
-    int max_packet_size;
3376
-
3377
-    /* now we can open the relevant output stream */
3378
-    ctx = avformat_alloc_context();
3379
-    if (!ctx)
3380
-        return -1;
3381
-    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3382
-
3383
-    st = av_mallocz(sizeof(AVStream));
3384
-    if (!st)
3385
-        goto fail;
3386
-    ctx->nb_streams = 1;
3387
-    ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3388
-    if (!ctx->streams)
3389
-      goto fail;
3390
-    ctx->streams[0] = st;
3391
-
3392
-    if (!c->stream->feed ||
3393
-        c->stream->feed == c->stream)
3394
-        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3395
-    else
3396
-        memcpy(st,
3397
-               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3398
-               sizeof(AVStream));
3399
-    st->priv_data = NULL;
3400
-
3401
-    /* build destination RTP address */
3402
-    ipaddr = inet_ntoa(dest_addr->sin_addr);
3403
-
3404
-    switch(c->rtp_protocol) {
3405
-    case RTSP_LOWER_TRANSPORT_UDP:
3406
-    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3407
-        /* RTP/UDP case */
3408
-
3409
-        /* XXX: also pass as parameter to function ? */
3410
-        if (c->stream->is_multicast) {
3411
-            int ttl;
3412
-            ttl = c->stream->multicast_ttl;
3413
-            if (!ttl)
3414
-                ttl = 16;
3415
-            snprintf(ctx->filename, sizeof(ctx->filename),
3416
-                     "rtp://%s:%d?multicast=1&ttl=%d",
3417
-                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3418
-        } else {
3419
-            snprintf(ctx->filename, sizeof(ctx->filename),
3420
-                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3421
-        }
3422
-
3423
-        if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3424
-            goto fail;
3425
-        c->rtp_handles[stream_index] = h;
3426
-        max_packet_size = url_get_max_packet_size(h);
3427
-        break;
3428
-    case RTSP_LOWER_TRANSPORT_TCP:
3429
-        /* RTP/TCP case */
3430
-        c->rtsp_c = rtsp_c;
3431
-        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3432
-        break;
3433
-    default:
3434
-        goto fail;
3435
-    }
3436
-
3437
-    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3438
-             ipaddr, ntohs(dest_addr->sin_port),
3439
-             c->stream->filename, stream_index, c->protocol);
3440
-
3441
-    /* normally, no packets should be output here, but the packet size may be checked */
3442
-    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3443
-        /* XXX: close stream */
3444
-        goto fail;
3445
-    }
3446
-    if (avformat_write_header(ctx, NULL) < 0) {
3447
-    fail:
3448
-        if (h)
3449
-            url_close(h);
3450
-        av_free(ctx);
3451
-        return -1;
3452
-    }
3453
-    avio_close_dyn_buf(ctx->pb, &dummy_buf);
3454
-    av_free(dummy_buf);
3455
-
3456
-    c->rtp_ctx[stream_index] = ctx;
3457
-    return 0;
3458
-}
3459
-
3460
-/********************************************************************/
3461
-/* ffserver initialization */
3462
-
3463
-static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3464
-{
3465
-    AVStream *fst;
3466
-
3467
-    fst = av_mallocz(sizeof(AVStream));
3468
-    if (!fst)
3469
-        return NULL;
3470
-    if (copy) {
3471
-        fst->codec = avcodec_alloc_context3(NULL);
3472
-        memcpy(fst->codec, codec, sizeof(AVCodecContext));
3473
-        if (codec->extradata_size) {
3474
-            fst->codec->extradata = av_malloc(codec->extradata_size);
3475
-            memcpy(fst->codec->extradata, codec->extradata,
3476
-                codec->extradata_size);
3477
-        }
3478
-    } else {
3479
-        /* live streams must use the actual feed's codec since it may be
3480
-         * updated later to carry extradata needed by the streams.
3481
-         */
3482
-        fst->codec = codec;
3483
-    }
3484
-    fst->priv_data = av_mallocz(sizeof(FeedData));
3485
-    fst->index = stream->nb_streams;
3486
-    av_set_pts_info(fst, 33, 1, 90000);
3487
-    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3488
-    stream->streams[stream->nb_streams++] = fst;
3489
-    return fst;
3490
-}
3491
-
3492
-/* return the stream number in the feed */
3493
-static int add_av_stream(FFStream *feed, AVStream *st)
3494
-{
3495
-    AVStream *fst;
3496
-    AVCodecContext *av, *av1;
3497
-    int i;
3498
-
3499
-    av = st->codec;
3500
-    for(i=0;i<feed->nb_streams;i++) {
3501
-        st = feed->streams[i];
3502
-        av1 = st->codec;
3503
-        if (av1->codec_id == av->codec_id &&
3504
-            av1->codec_type == av->codec_type &&
3505
-            av1->bit_rate == av->bit_rate) {
3506
-
3507
-            switch(av->codec_type) {
3508
-            case AVMEDIA_TYPE_AUDIO:
3509
-                if (av1->channels == av->channels &&
3510
-                    av1->sample_rate == av->sample_rate)
3511
-                    return i;
3512
-                break;
3513
-            case AVMEDIA_TYPE_VIDEO:
3514
-                if (av1->width == av->width &&
3515
-                    av1->height == av->height &&
3516
-                    av1->time_base.den == av->time_base.den &&
3517
-                    av1->time_base.num == av->time_base.num &&
3518
-                    av1->gop_size == av->gop_size)
3519
-                    return i;
3520
-                break;
3521
-            default:
3522
-                abort();
3523
-            }
3524
-        }
3525
-    }
3526
-
3527
-    fst = add_av_stream1(feed, av, 0);
3528
-    if (!fst)
3529
-        return -1;
3530
-    return feed->nb_streams - 1;
3531
-}
3532
-
3533
-static void remove_stream(FFStream *stream)
3534
-{
3535
-    FFStream **ps;
3536
-    ps = &first_stream;
3537
-    while (*ps != NULL) {
3538
-        if (*ps == stream)
3539
-            *ps = (*ps)->next;
3540
-        else
3541
-            ps = &(*ps)->next;
3542
-    }
3543
-}
3544
-
3545
-/* specific mpeg4 handling : we extract the raw parameters */
3546
-static void extract_mpeg4_header(AVFormatContext *infile)
3547
-{
3548
-    int mpeg4_count, i, size;
3549
-    AVPacket pkt;
3550
-    AVStream *st;
3551
-    const uint8_t *p;
3552
-
3553
-    mpeg4_count = 0;
3554
-    for(i=0;i<infile->nb_streams;i++) {
3555
-        st = infile->streams[i];
3556
-        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3557
-            st->codec->extradata_size == 0) {
3558
-            mpeg4_count++;
3559
-        }
3560
-    }
3561
-    if (!mpeg4_count)
3562
-        return;
3563
-
3564
-    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3565
-    while (mpeg4_count > 0) {
3566
-        if (av_read_packet(infile, &pkt) < 0)
3567
-            break;
3568
-        st = infile->streams[pkt.stream_index];
3569
-        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3570
-            st->codec->extradata_size == 0) {
3571
-            av_freep(&st->codec->extradata);
3572
-            /* fill extradata with the header */
3573
-            /* XXX: we make hard suppositions here ! */
3574
-            p = pkt.data;
3575
-            while (p < pkt.data + pkt.size - 4) {
3576
-                /* stop when vop header is found */
3577
-                if (p[0] == 0x00 && p[1] == 0x00 &&
3578
-                    p[2] == 0x01 && p[3] == 0xb6) {
3579
-                    size = p - pkt.data;
3580
-                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3581
-                    st->codec->extradata = av_malloc(size);
3582
-                    st->codec->extradata_size = size;
3583
-                    memcpy(st->codec->extradata, pkt.data, size);
3584
-                    break;
3585
-                }
3586
-                p++;
3587
-            }
3588
-            mpeg4_count--;
3589
-        }
3590
-        av_free_packet(&pkt);
3591
-    }
3592
-}
3593
-
3594
-/* compute the needed AVStream for each file */
3595
-static void build_file_streams(void)
3596
-{
3597
-    FFStream *stream, *stream_next;
3598
-    int i, ret;
3599
-
3600
-    /* gather all streams */
3601
-    for(stream = first_stream; stream != NULL; stream = stream_next) {
3602
-        AVFormatContext *infile = NULL;
3603
-        stream_next = stream->next;
3604
-        if (stream->stream_type == STREAM_TYPE_LIVE &&
3605
-            !stream->feed) {
3606
-            /* the stream comes from a file */
3607
-            /* try to open the file */
3608
-            /* open stream */
3609
-            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3610
-                /* specific case : if transport stream output to RTP,
3611
-                   we use a raw transport stream reader */
3612
-                av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3613
-            }
3614
-
3615
-            http_log("Opening file '%s'\n", stream->feed_filename);
3616
-            if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3617
-                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3618
-                /* remove stream (no need to spend more time on it) */
3619
-            fail:
3620
-                remove_stream(stream);
3621
-            } else {
3622
-                /* find all the AVStreams inside and reference them in
3623
-                   'stream' */
3624
-                if (av_find_stream_info(infile) < 0) {
3625
-                    http_log("Could not find codec parameters from '%s'\n",
3626
-                             stream->feed_filename);
3627
-                    av_close_input_file(infile);
3628
-                    goto fail;
3629
-                }
3630
-                extract_mpeg4_header(infile);
3631
-
3632
-                for(i=0;i<infile->nb_streams;i++)
3633
-                    add_av_stream1(stream, infile->streams[i]->codec, 1);
3634
-
3635
-                av_close_input_file(infile);
3636
-            }
3637
-        }
3638
-    }
3639
-}
3640
-
3641
-/* compute the needed AVStream for each feed */
3642
-static void build_feed_streams(void)
3643
-{
3644
-    FFStream *stream, *feed;
3645
-    int i;
3646
-
3647
-    /* gather all streams */
3648
-    for(stream = first_stream; stream != NULL; stream = stream->next) {
3649
-        feed = stream->feed;
3650
-        if (feed) {
3651
-            if (stream->is_feed) {
3652
-                for(i=0;i<stream->nb_streams;i++)
3653
-                    stream->feed_streams[i] = i;
3654
-            } else {
3655
-                /* we handle a stream coming from a feed */
3656
-                for(i=0;i<stream->nb_streams;i++)
3657
-                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3658
-            }
3659
-        }
3660
-    }
3661
-
3662
-    /* create feed files if needed */
3663
-    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3664
-        int fd;
3665
-
3666
-        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3667
-            /* See if it matches */
3668
-            AVFormatContext *s = NULL;
3669
-            int matches = 0;
3670
-
3671
-            if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3672
-                /* Now see if it matches */
3673
-                if (s->nb_streams == feed->nb_streams) {
3674
-                    matches = 1;
3675
-                    for(i=0;i<s->nb_streams;i++) {
3676
-                        AVStream *sf, *ss;
3677
-                        sf = feed->streams[i];
3678
-                        ss = s->streams[i];
3679
-
3680
-                        if (sf->index != ss->index ||
3681
-                            sf->id != ss->id) {
3682
-                            http_log("Index & Id do not match for stream %d (%s)\n",
3683
-                                   i, feed->feed_filename);
3684
-                            matches = 0;
3685
-                        } else {
3686
-                            AVCodecContext *ccf, *ccs;
3687
-
3688
-                            ccf = sf->codec;
3689
-                            ccs = ss->codec;
3690
-#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3691
-
3692
-                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3693
-                                http_log("Codecs do not match for stream %d\n", i);
3694
-                                matches = 0;
3695
-                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3696
-                                http_log("Codec bitrates do not match for stream %d\n", i);
3697
-                                matches = 0;
3698
-                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3699
-                                if (CHECK_CODEC(time_base.den) ||
3700
-                                    CHECK_CODEC(time_base.num) ||
3701
-                                    CHECK_CODEC(width) ||
3702
-                                    CHECK_CODEC(height)) {
3703
-                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3704
-                                    matches = 0;
3705
-                                }
3706
-                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3707
-                                if (CHECK_CODEC(sample_rate) ||
3708
-                                    CHECK_CODEC(channels) ||
3709
-                                    CHECK_CODEC(frame_size)) {
3710
-                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3711
-                                    matches = 0;
3712
-                                }
3713
-                            } else {
3714
-                                http_log("Unknown codec type\n");
3715
-                                matches = 0;
3716
-                            }
3717
-                        }
3718
-                        if (!matches)
3719
-                            break;
3720
-                    }
3721
-                } else
3722
-                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3723
-                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3724
-
3725
-                av_close_input_file(s);
3726
-            } else
3727
-                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3728
-                        feed->feed_filename);
3729
-
3730
-            if (!matches) {
3731
-                if (feed->readonly) {
3732
-                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3733
-                        feed->feed_filename);
3734
-                    exit(1);
3735
-                }
3736
-                unlink(feed->feed_filename);
3737
-            }
3738
-        }
3739
-        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3740
-            AVFormatContext s1 = {0}, *s = &s1;
3741
-
3742
-            if (feed->readonly) {
3743
-                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3744
-                    feed->feed_filename);
3745
-                exit(1);
3746
-            }
3747
-
3748
-            /* only write the header of the ffm file */
3749
-            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3750
-                http_log("Could not open output feed file '%s'\n",
3751
-                         feed->feed_filename);
3752
-                exit(1);
3753
-            }
3754
-            s->oformat = feed->fmt;
3755
-            s->nb_streams = feed->nb_streams;
3756
-            s->streams = feed->streams;
3757
-            if (avformat_write_header(s, NULL) < 0) {
3758
-                http_log("Container doesn't supports the required parameters\n");
3759
-                exit(1);
3760
-            }
3761
-            /* XXX: need better api */
3762
-            av_freep(&s->priv_data);
3763
-            avio_close(s->pb);
3764
-        }
3765
-        /* get feed size and write index */
3766
-        fd = open(feed->feed_filename, O_RDONLY);
3767
-        if (fd < 0) {
3768
-            http_log("Could not open output feed file '%s'\n",
3769
-                    feed->feed_filename);
3770
-            exit(1);
3771
-        }
3772
-
3773
-        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3774
-        feed->feed_size = lseek(fd, 0, SEEK_END);
3775
-        /* ensure that we do not wrap before the end of file */
3776
-        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3777
-            feed->feed_max_size = feed->feed_size;
3778
-
3779
-        close(fd);
3780
-    }
3781
-}
3782
-
3783
-/* compute the bandwidth used by each stream */
3784
-static void compute_bandwidth(void)
3785
-{
3786
-    unsigned bandwidth;
3787
-    int i;
3788
-    FFStream *stream;
3789
-
3790
-    for(stream = first_stream; stream != NULL; stream = stream->next) {
3791
-        bandwidth = 0;
3792
-        for(i=0;i<stream->nb_streams;i++) {
3793
-            AVStream *st = stream->streams[i];
3794
-            switch(st->codec->codec_type) {
3795
-            case AVMEDIA_TYPE_AUDIO:
3796
-            case AVMEDIA_TYPE_VIDEO:
3797
-                bandwidth += st->codec->bit_rate;
3798
-                break;
3799
-            default:
3800
-                break;
3801
-            }
3802
-        }
3803
-        stream->bandwidth = (bandwidth + 999) / 1000;
3804
-    }
3805
-}
3806
-
3807
-/* add a codec and set the default parameters */
3808
-static void add_codec(FFStream *stream, AVCodecContext *av)
3809
-{
3810
-    AVStream *st;
3811
-
3812
-    /* compute default parameters */
3813
-    switch(av->codec_type) {
3814
-    case AVMEDIA_TYPE_AUDIO:
3815
-        if (av->bit_rate == 0)
3816
-            av->bit_rate = 64000;
3817
-        if (av->sample_rate == 0)
3818
-            av->sample_rate = 22050;
3819
-        if (av->channels == 0)
3820
-            av->channels = 1;
3821
-        break;
3822
-    case AVMEDIA_TYPE_VIDEO:
3823
-        if (av->bit_rate == 0)
3824
-            av->bit_rate = 64000;
3825
-        if (av->time_base.num == 0){
3826
-            av->time_base.den = 5;
3827
-            av->time_base.num = 1;
3828
-        }
3829
-        if (av->width == 0 || av->height == 0) {
3830
-            av->width = 160;
3831
-            av->height = 128;
3832
-        }
3833
-        /* Bitrate tolerance is less for streaming */
3834
-        if (av->bit_rate_tolerance == 0)
3835
-            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3836
-                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3837
-        if (av->qmin == 0)
3838
-            av->qmin = 3;
3839
-        if (av->qmax == 0)
3840
-            av->qmax = 31;
3841
-        if (av->max_qdiff == 0)
3842
-            av->max_qdiff = 3;
3843
-        av->qcompress = 0.5;
3844
-        av->qblur = 0.5;
3845
-
3846
-        if (!av->nsse_weight)
3847
-            av->nsse_weight = 8;
3848
-
3849
-        av->frame_skip_cmp = FF_CMP_DCTMAX;
3850
-        if (!av->me_method)
3851
-            av->me_method = ME_EPZS;
3852
-        av->rc_buffer_aggressivity = 1.0;
3853
-
3854
-        if (!av->rc_eq)
3855
-            av->rc_eq = "tex^qComp";
3856
-        if (!av->i_quant_factor)
3857
-            av->i_quant_factor = -0.8;
3858
-        if (!av->b_quant_factor)
3859
-            av->b_quant_factor = 1.25;
3860
-        if (!av->b_quant_offset)
3861
-            av->b_quant_offset = 1.25;
3862
-        if (!av->rc_max_rate)
3863
-            av->rc_max_rate = av->bit_rate * 2;
3864
-
3865
-        if (av->rc_max_rate && !av->rc_buffer_size) {
3866
-            av->rc_buffer_size = av->rc_max_rate;
3867
-        }
3868
-
3869
-
3870
-        break;
3871
-    default:
3872
-        abort();
3873
-    }
3874
-
3875
-    st = av_mallocz(sizeof(AVStream));
3876
-    if (!st)
3877
-        return;
3878
-    st->codec = avcodec_alloc_context3(NULL);
3879
-    stream->streams[stream->nb_streams++] = st;
3880
-    memcpy(st->codec, av, sizeof(AVCodecContext));
3881
-}
3882
-
3883
-static enum CodecID opt_audio_codec(const char *arg)
3884
-{
3885
-    AVCodec *p= avcodec_find_encoder_by_name(arg);
3886
-
3887
-    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3888
-        return CODEC_ID_NONE;
3889
-
3890
-    return p->id;
3891
-}
3892
-
3893
-static enum CodecID opt_video_codec(const char *arg)
3894
-{
3895
-    AVCodec *p= avcodec_find_encoder_by_name(arg);
3896
-
3897
-    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3898
-        return CODEC_ID_NONE;
3899
-
3900
-    return p->id;
3901
-}
3902
-
3903
-/* simplistic plugin support */
3904
-
3905
-#if HAVE_DLOPEN
3906
-static void load_module(const char *filename)
3907
-{
3908
-    void *dll;
3909
-    void (*init_func)(void);
3910
-    dll = dlopen(filename, RTLD_NOW);
3911
-    if (!dll) {
3912
-        fprintf(stderr, "Could not load module '%s' - %s\n",
3913
-                filename, dlerror());
3914
-        return;
3915
-    }
3916
-
3917
-    init_func = dlsym(dll, "ffserver_module_init");
3918
-    if (!init_func) {
3919
-        fprintf(stderr,
3920
-                "%s: init function 'ffserver_module_init()' not found\n",
3921
-                filename);
3922
-        dlclose(dll);
3923
-    }
3924
-
3925
-    init_func();
3926
-}
3927
-#endif
3928
-
3929
-static int ffserver_opt_default(const char *opt, const char *arg,
3930
-                       AVCodecContext *avctx, int type)
3931
-{
3932
-    int ret = 0;
3933
-    const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3934
-    if(o)
3935
-        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3936
-    return ret;
3937
-}
3938
-
3939
-static int ffserver_opt_preset(const char *arg,
3940
-                       AVCodecContext *avctx, int type,
3941
-                       enum CodecID *audio_id, enum CodecID *video_id)
3942
-{
3943
-    FILE *f=NULL;
3944
-    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3945
-    int ret = 0;
3946
-    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3947
-
3948
-    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3949
-                              codec ? codec->name : NULL))) {
3950
-        fprintf(stderr, "File for preset '%s' not found\n", arg);
3951
-        return 1;
3952
-    }
3953
-
3954
-    while(!feof(f)){
3955
-        int e= fscanf(f, "%999[^\n]\n", line) - 1;
3956
-        if(line[0] == '#' && !e)
3957
-            continue;
3958
-        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3959
-        if(e){
3960
-            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3961
-            ret = 1;
3962
-            break;
3963
-        }
3964
-        if(!strcmp(tmp, "acodec")){
3965
-            *audio_id = opt_audio_codec(tmp2);
3966
-        }else if(!strcmp(tmp, "vcodec")){
3967
-            *video_id = opt_video_codec(tmp2);
3968
-        }else if(!strcmp(tmp, "scodec")){
3969
-            /* opt_subtitle_codec(tmp2); */
3970
-        }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3971
-            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3972
-            ret = 1;
3973
-            break;
3974
-        }
3975
-    }
3976
-
3977
-    fclose(f);
3978
-
3979
-    return ret;
3980
-}
3981
-
3982
-static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3983
-                                             const char *mime_type)
3984
-{
3985
-    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3986
-
3987
-    if (fmt) {
3988
-        AVOutputFormat *stream_fmt;
3989
-        char stream_format_name[64];
3990
-
3991
-        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3992
-        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3993
-
3994
-        if (stream_fmt)
3995
-            fmt = stream_fmt;
3996
-    }
3997
-
3998
-    return fmt;
3999
-}
4000
-
4001
-static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4002
-{
4003
-    va_list vl;
4004
-    va_start(vl, fmt);
4005
-    fprintf(stderr, "%s:%d: ", filename, line_num);
4006
-    vfprintf(stderr, fmt, vl);
4007
-    va_end(vl);
4008
-
4009
-    (*errors)++;
4010
-}
4011
-
4012
-static int parse_ffconfig(const char *filename)
4013
-{
4014
-    FILE *f;
4015
-    char line[1024];
4016
-    char cmd[64];
4017
-    char arg[1024];
4018
-    const char *p;
4019
-    int val, errors, line_num;
4020
-    FFStream **last_stream, *stream, *redirect;
4021
-    FFStream **last_feed, *feed, *s;
4022
-    AVCodecContext audio_enc, video_enc;
4023
-    enum CodecID audio_id, video_id;
4024
-
4025
-    f = fopen(filename, "r");
4026
-    if (!f) {
4027
-        perror(filename);
4028
-        return -1;
4029
-    }
4030
-
4031
-    errors = 0;
4032
-    line_num = 0;
4033
-    first_stream = NULL;
4034
-    last_stream = &first_stream;
4035
-    first_feed = NULL;
4036
-    last_feed = &first_feed;
4037
-    stream = NULL;
4038
-    feed = NULL;
4039
-    redirect = NULL;
4040
-    audio_id = CODEC_ID_NONE;
4041
-    video_id = CODEC_ID_NONE;
4042
-
4043
-#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4044
-    for(;;) {
4045
-        if (fgets(line, sizeof(line), f) == NULL)
4046
-            break;
4047
-        line_num++;
4048
-        p = line;
4049
-        while (isspace(*p))
4050
-            p++;
4051
-        if (*p == '\0' || *p == '#')
4052
-            continue;
4053
-
4054
-        get_arg(cmd, sizeof(cmd), &p);
4055
-
4056
-        if (!strcasecmp(cmd, "Port")) {
4057
-            get_arg(arg, sizeof(arg), &p);
4058
-            val = atoi(arg);
4059
-            if (val < 1 || val > 65536) {
4060
-                ERROR("Invalid_port: %s\n", arg);
4061
-            }
4062
-            my_http_addr.sin_port = htons(val);
4063
-        } else if (!strcasecmp(cmd, "BindAddress")) {
4064
-            get_arg(arg, sizeof(arg), &p);
4065
-            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4066
-                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4067
-            }
4068
-        } else if (!strcasecmp(cmd, "NoDaemon")) {
4069
-            ffserver_daemon = 0;
4070
-        } else if (!strcasecmp(cmd, "RTSPPort")) {
4071
-            get_arg(arg, sizeof(arg), &p);
4072
-            val = atoi(arg);
4073
-            if (val < 1 || val > 65536) {
4074
-                ERROR("%s:%d: Invalid port: %s\n", arg);
4075
-            }
4076
-            my_rtsp_addr.sin_port = htons(atoi(arg));
4077
-        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4078
-            get_arg(arg, sizeof(arg), &p);
4079
-            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4080
-                ERROR("Invalid host/IP address: %s\n", arg);
4081
-            }
4082
-        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4083
-            get_arg(arg, sizeof(arg), &p);
4084
-            val = atoi(arg);
4085
-            if (val < 1 || val > 65536) {
4086
-                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4087
-            }
4088
-            nb_max_http_connections = val;
4089
-        } else if (!strcasecmp(cmd, "MaxClients")) {
4090
-            get_arg(arg, sizeof(arg), &p);
4091
-            val = atoi(arg);
4092
-            if (val < 1 || val > nb_max_http_connections) {
4093
-                ERROR("Invalid MaxClients: %s\n", arg);
4094
-            } else {
4095
-                nb_max_connections = val;
4096
-            }
4097
-        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4098
-            int64_t llval;
4099
-            get_arg(arg, sizeof(arg), &p);
4100
-            llval = atoll(arg);
4101
-            if (llval < 10 || llval > 10000000) {
4102
-                ERROR("Invalid MaxBandwidth: %s\n", arg);
4103
-            } else
4104
-                max_bandwidth = llval;
4105
-        } else if (!strcasecmp(cmd, "CustomLog")) {
4106
-            if (!ffserver_debug)
4107
-                get_arg(logfilename, sizeof(logfilename), &p);
4108
-        } else if (!strcasecmp(cmd, "<Feed")) {
4109
-            /*********************************************/
4110
-            /* Feed related options */
4111
-            char *q;
4112
-            if (stream || feed) {
4113
-                ERROR("Already in a tag\n");
4114
-            } else {
4115
-                feed = av_mallocz(sizeof(FFStream));
4116
-                get_arg(feed->filename, sizeof(feed->filename), &p);
4117
-                q = strrchr(feed->filename, '>');
4118
-                if (*q)
4119
-                    *q = '\0';
4120
-
4121
-                for (s = first_feed; s; s = s->next) {
4122
-                    if (!strcmp(feed->filename, s->filename)) {
4123
-                        ERROR("Feed '%s' already registered\n", s->filename);
4124
-                    }
4125
-                }
4126
-
4127
-                feed->fmt = av_guess_format("ffm", NULL, NULL);
4128
-                /* defaut feed file */
4129
-                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4130
-                         "/tmp/%s.ffm", feed->filename);
4131
-                feed->feed_max_size = 5 * 1024 * 1024;
4132
-                feed->is_feed = 1;
4133
-                feed->feed = feed; /* self feeding :-) */
4134
-
4135
-                /* add in stream list */
4136
-                *last_stream = feed;
4137
-                last_stream = &feed->next;
4138
-                /* add in feed list */
4139
-                *last_feed = feed;
4140
-                last_feed = &feed->next_feed;
4141
-            }
4142
-        } else if (!strcasecmp(cmd, "Launch")) {
4143
-            if (feed) {
4144
-                int i;
4145
-
4146
-                feed->child_argv = av_mallocz(64 * sizeof(char *));
4147
-
4148
-                for (i = 0; i < 62; i++) {
4149
-                    get_arg(arg, sizeof(arg), &p);
4150
-                    if (!arg[0])
4151
-                        break;
4152
-
4153
-                    feed->child_argv[i] = av_strdup(arg);
4154
-                }
4155
-
4156
-                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4157
-
4158
-                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4159
-                    "http://%s:%d/%s",
4160
-                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4161
-                    inet_ntoa(my_http_addr.sin_addr),
4162
-                    ntohs(my_http_addr.sin_port), feed->filename);
4163
-            }
4164
-        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4165
-            if (feed) {
4166
-                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4167
-                feed->readonly = 1;
4168
-            } else if (stream) {
4169
-                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4170
-            }
4171
-        } else if (!strcasecmp(cmd, "File")) {
4172
-            if (feed) {
4173
-                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4174
-            } else if (stream)
4175
-                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4176
-        } else if (!strcasecmp(cmd, "Truncate")) {
4177
-            if (feed) {
4178
-                get_arg(arg, sizeof(arg), &p);
4179
-                feed->truncate = strtod(arg, NULL);
4180
-            }
4181
-        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4182
-            if (feed) {
4183
-                char *p1;
4184
-                double fsize;
4185
-
4186
-                get_arg(arg, sizeof(arg), &p);
4187
-                p1 = arg;
4188
-                fsize = strtod(p1, &p1);
4189
-                switch(toupper(*p1)) {
4190
-                case 'K':
4191
-                    fsize *= 1024;
4192
-                    break;
4193
-                case 'M':
4194
-                    fsize *= 1024 * 1024;
4195
-                    break;
4196
-                case 'G':
4197
-                    fsize *= 1024 * 1024 * 1024;
4198
-                    break;
4199
-                }
4200
-                feed->feed_max_size = (int64_t)fsize;
4201
-                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4202
-                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4203
-                }
4204
-            }
4205
-        } else if (!strcasecmp(cmd, "</Feed>")) {
4206
-            if (!feed) {
4207
-                ERROR("No corresponding <Feed> for </Feed>\n");
4208
-            }
4209
-            feed = NULL;
4210
-        } else if (!strcasecmp(cmd, "<Stream")) {
4211
-            /*********************************************/
4212
-            /* Stream related options */
4213
-            char *q;
4214
-            if (stream || feed) {
4215
-                ERROR("Already in a tag\n");
4216
-            } else {
4217
-                FFStream *s;
4218
-                stream = av_mallocz(sizeof(FFStream));
4219
-                get_arg(stream->filename, sizeof(stream->filename), &p);
4220
-                q = strrchr(stream->filename, '>');
4221
-                if (*q)
4222
-                    *q = '\0';
4223
-
4224
-                for (s = first_stream; s; s = s->next) {
4225
-                    if (!strcmp(stream->filename, s->filename)) {
4226
-                        ERROR("Stream '%s' already registered\n", s->filename);
4227
-                    }
4228
-                }
4229
-
4230
-                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4231
-                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4232
-                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4233
-                audio_id = CODEC_ID_NONE;
4234
-                video_id = CODEC_ID_NONE;
4235
-                if (stream->fmt) {
4236
-                    audio_id = stream->fmt->audio_codec;
4237
-                    video_id = stream->fmt->video_codec;
4238
-                }
4239
-
4240
-                *last_stream = stream;
4241
-                last_stream = &stream->next;
4242
-            }
4243
-        } else if (!strcasecmp(cmd, "Feed")) {
4244
-            get_arg(arg, sizeof(arg), &p);
4245
-            if (stream) {
4246
-                FFStream *sfeed;
4247
-
4248
-                sfeed = first_feed;
4249
-                while (sfeed != NULL) {
4250
-                    if (!strcmp(sfeed->filename, arg))
4251
-                        break;
4252
-                    sfeed = sfeed->next_feed;
4253
-                }
4254
-                if (!sfeed)
4255
-                    ERROR("feed '%s' not defined\n", arg);
4256
-                else
4257
-                    stream->feed = sfeed;
4258
-            }
4259
-        } else if (!strcasecmp(cmd, "Format")) {
4260
-            get_arg(arg, sizeof(arg), &p);
4261
-            if (stream) {
4262
-                if (!strcmp(arg, "status")) {
4263
-                    stream->stream_type = STREAM_TYPE_STATUS;
4264
-                    stream->fmt = NULL;
4265
-                } else {
4266
-                    stream->stream_type = STREAM_TYPE_LIVE;
4267
-                    /* jpeg cannot be used here, so use single frame jpeg */
4268
-                    if (!strcmp(arg, "jpeg"))
4269
-                        strcpy(arg, "mjpeg");
4270
-                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4271
-                    if (!stream->fmt) {
4272
-                        ERROR("Unknown Format: %s\n", arg);
4273
-                    }
4274
-                }
4275
-                if (stream->fmt) {
4276
-                    audio_id = stream->fmt->audio_codec;
4277
-                    video_id = stream->fmt->video_codec;
4278
-                }
4279
-            }
4280
-        } else if (!strcasecmp(cmd, "InputFormat")) {
4281
-            get_arg(arg, sizeof(arg), &p);
4282
-            if (stream) {
4283
-                stream->ifmt = av_find_input_format(arg);
4284
-                if (!stream->ifmt) {
4285
-                    ERROR("Unknown input format: %s\n", arg);
4286
-                }
4287
-            }
4288
-        } else if (!strcasecmp(cmd, "FaviconURL")) {
4289
-            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4290
-                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4291
-            } else {
4292
-                ERROR("FaviconURL only permitted for status streams\n");
4293
-            }
4294
-        } else if (!strcasecmp(cmd, "Author")) {
4295
-            if (stream)
4296
-                get_arg(stream->author, sizeof(stream->author), &p);
4297
-        } else if (!strcasecmp(cmd, "Comment")) {
4298
-            if (stream)
4299
-                get_arg(stream->comment, sizeof(stream->comment), &p);
4300
-        } else if (!strcasecmp(cmd, "Copyright")) {
4301
-            if (stream)
4302
-                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4303
-        } else if (!strcasecmp(cmd, "Title")) {
4304
-            if (stream)
4305
-                get_arg(stream->title, sizeof(stream->title), &p);
4306
-        } else if (!strcasecmp(cmd, "Preroll")) {
4307
-            get_arg(arg, sizeof(arg), &p);
4308
-            if (stream)
4309
-                stream->prebuffer = atof(arg) * 1000;
4310
-        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4311
-            if (stream)
4312
-                stream->send_on_key = 1;
4313
-        } else if (!strcasecmp(cmd, "AudioCodec")) {
4314
-            get_arg(arg, sizeof(arg), &p);
4315
-            audio_id = opt_audio_codec(arg);
4316
-            if (audio_id == CODEC_ID_NONE) {
4317
-                ERROR("Unknown AudioCodec: %s\n", arg);
4318
-            }
4319
-        } else if (!strcasecmp(cmd, "VideoCodec")) {
4320
-            get_arg(arg, sizeof(arg), &p);
4321
-            video_id = opt_video_codec(arg);
4322
-            if (video_id == CODEC_ID_NONE) {
4323
-                ERROR("Unknown VideoCodec: %s\n", arg);
4324
-            }
4325
-        } else if (!strcasecmp(cmd, "MaxTime")) {
4326
-            get_arg(arg, sizeof(arg), &p);
4327
-            if (stream)
4328
-                stream->max_time = atof(arg) * 1000;
4329
-        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4330
-            get_arg(arg, sizeof(arg), &p);
4331
-            if (stream)
4332
-                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4333
-        } else if (!strcasecmp(cmd, "AudioChannels")) {
4334
-            get_arg(arg, sizeof(arg), &p);
4335
-            if (stream)
4336
-                audio_enc.channels = atoi(arg);
4337
-        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4338
-            get_arg(arg, sizeof(arg), &p);
4339
-            if (stream)
4340
-                audio_enc.sample_rate = atoi(arg);
4341
-        } else if (!strcasecmp(cmd, "AudioQuality")) {
4342
-            get_arg(arg, sizeof(arg), &p);
4343
-            if (stream) {
4344
-//                audio_enc.quality = atof(arg) * 1000;
4345
-            }
4346
-        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4347
-            if (stream) {
4348
-                int minrate, maxrate;
4349
-
4350
-                get_arg(arg, sizeof(arg), &p);
4351
-
4352
-                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4353
-                    video_enc.rc_min_rate = minrate * 1000;
4354
-                    video_enc.rc_max_rate = maxrate * 1000;
4355
-                } else {
4356
-                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4357
-                }
4358
-            }
4359
-        } else if (!strcasecmp(cmd, "Debug")) {
4360
-            if (stream) {
4361
-                get_arg(arg, sizeof(arg), &p);
4362
-                video_enc.debug = strtol(arg,0,0);
4363
-            }
4364
-        } else if (!strcasecmp(cmd, "Strict")) {
4365
-            if (stream) {
4366
-                get_arg(arg, sizeof(arg), &p);
4367
-                video_enc.strict_std_compliance = atoi(arg);
4368
-            }
4369
-        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4370
-            if (stream) {
4371
-                get_arg(arg, sizeof(arg), &p);
4372
-                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4373
-            }
4374
-        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4375
-            if (stream) {
4376
-                get_arg(arg, sizeof(arg), &p);
4377
-                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4378
-            }
4379
-        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4380
-            get_arg(arg, sizeof(arg), &p);
4381
-            if (stream) {
4382
-                video_enc.bit_rate = atoi(arg) * 1000;
4383
-            }
4384
-        } else if (!strcasecmp(cmd, "VideoSize")) {
4385
-            get_arg(arg, sizeof(arg), &p);
4386
-            if (stream) {
4387
-                av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4388
-                if ((video_enc.width % 16) != 0 ||
4389
-                    (video_enc.height % 16) != 0) {
4390
-                    ERROR("Image size must be a multiple of 16\n");
4391
-                }
4392
-            }
4393
-        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4394
-            get_arg(arg, sizeof(arg), &p);
4395
-            if (stream) {
4396
-                AVRational frame_rate;
4397
-                if (av_parse_video_rate(&frame_rate, arg) < 0) {
4398
-                    ERROR("Incorrect frame rate: %s\n", arg);
4399
-                } else {
4400
-                    video_enc.time_base.num = frame_rate.den;
4401
-                    video_enc.time_base.den = frame_rate.num;
4402
-                }
4403
-            }
4404
-        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4405
-            get_arg(arg, sizeof(arg), &p);
4406
-            if (stream)
4407
-                video_enc.gop_size = atoi(arg);
4408
-        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4409
-            if (stream)
4410
-                video_enc.gop_size = 1;
4411
-        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4412
-            if (stream)
4413
-                video_enc.mb_decision = FF_MB_DECISION_BITS;
4414
-        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4415
-            if (stream) {
4416
-                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4417
-                video_enc.flags |= CODEC_FLAG_4MV;
4418
-            }
4419
-        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4420
-                   !strcasecmp(cmd, "AVOptionAudio")) {
4421
-            char arg2[1024];
4422
-            AVCodecContext *avctx;
4423
-            int type;
4424
-            get_arg(arg, sizeof(arg), &p);
4425
-            get_arg(arg2, sizeof(arg2), &p);
4426
-            if (!strcasecmp(cmd, "AVOptionVideo")) {
4427
-                avctx = &video_enc;
4428
-                type = AV_OPT_FLAG_VIDEO_PARAM;
4429
-            } else {
4430
-                avctx = &audio_enc;
4431
-                type = AV_OPT_FLAG_AUDIO_PARAM;
4432
-            }
4433
-            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4434
-                ERROR("AVOption error: %s %s\n", arg, arg2);
4435
-            }
4436
-        } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4437
-                   !strcasecmp(cmd, "AVPresetAudio")) {
4438
-            AVCodecContext *avctx;
4439
-            int type;
4440
-            get_arg(arg, sizeof(arg), &p);
4441
-            if (!strcasecmp(cmd, "AVPresetVideo")) {
4442
-                avctx = &video_enc;
4443
-                video_enc.codec_id = video_id;
4444
-                type = AV_OPT_FLAG_VIDEO_PARAM;
4445
-            } else {
4446
-                avctx = &audio_enc;
4447
-                audio_enc.codec_id = audio_id;
4448
-                type = AV_OPT_FLAG_AUDIO_PARAM;
4449
-            }
4450
-            if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4451
-                ERROR("AVPreset error: %s\n", arg);
4452
-            }
4453
-        } else if (!strcasecmp(cmd, "VideoTag")) {
4454
-            get_arg(arg, sizeof(arg), &p);
4455
-            if ((strlen(arg) == 4) && stream)
4456
-                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4457
-        } else if (!strcasecmp(cmd, "BitExact")) {
4458
-            if (stream)
4459
-                video_enc.flags |= CODEC_FLAG_BITEXACT;
4460
-        } else if (!strcasecmp(cmd, "DctFastint")) {
4461
-            if (stream)
4462
-                video_enc.dct_algo  = FF_DCT_FASTINT;
4463
-        } else if (!strcasecmp(cmd, "IdctSimple")) {
4464
-            if (stream)
4465
-                video_enc.idct_algo = FF_IDCT_SIMPLE;
4466
-        } else if (!strcasecmp(cmd, "Qscale")) {
4467
-            get_arg(arg, sizeof(arg), &p);
4468
-            if (stream) {
4469
-                video_enc.flags |= CODEC_FLAG_QSCALE;
4470
-                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4471
-            }
4472
-        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4473
-            get_arg(arg, sizeof(arg), &p);
4474
-            if (stream) {
4475
-                video_enc.max_qdiff = atoi(arg);
4476
-                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4477
-                    ERROR("VideoQDiff out of range\n");
4478
-                }
4479
-            }
4480
-        } else if (!strcasecmp(cmd, "VideoQMax")) {
4481
-            get_arg(arg, sizeof(arg), &p);
4482
-            if (stream) {
4483
-                video_enc.qmax = atoi(arg);
4484
-                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4485
-                    ERROR("VideoQMax out of range\n");
4486
-                }
4487
-            }
4488
-        } else if (!strcasecmp(cmd, "VideoQMin")) {
4489
-            get_arg(arg, sizeof(arg), &p);
4490
-            if (stream) {
4491
-                video_enc.qmin = atoi(arg);
4492
-                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4493
-                    ERROR("VideoQMin out of range\n");
4494
-                }
4495
-            }
4496
-        } else if (!strcasecmp(cmd, "LumaElim")) {
4497
-            get_arg(arg, sizeof(arg), &p);
4498
-            if (stream)
4499
-                video_enc.luma_elim_threshold = atoi(arg);
4500
-        } else if (!strcasecmp(cmd, "ChromaElim")) {
4501
-            get_arg(arg, sizeof(arg), &p);
4502
-            if (stream)
4503
-                video_enc.chroma_elim_threshold = atoi(arg);
4504
-        } else if (!strcasecmp(cmd, "LumiMask")) {
4505
-            get_arg(arg, sizeof(arg), &p);
4506
-            if (stream)
4507
-                video_enc.lumi_masking = atof(arg);
4508
-        } else if (!strcasecmp(cmd, "DarkMask")) {
4509
-            get_arg(arg, sizeof(arg), &p);
4510
-            if (stream)
4511
-                video_enc.dark_masking = atof(arg);
4512
-        } else if (!strcasecmp(cmd, "NoVideo")) {
4513
-            video_id = CODEC_ID_NONE;
4514
-        } else if (!strcasecmp(cmd, "NoAudio")) {
4515
-            audio_id = CODEC_ID_NONE;
4516
-        } else if (!strcasecmp(cmd, "ACL")) {
4517
-            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4518
-        } else if (!strcasecmp(cmd, "DynamicACL")) {
4519
-            if (stream) {
4520
-                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4521
-            }
4522
-        } else if (!strcasecmp(cmd, "RTSPOption")) {
4523
-            get_arg(arg, sizeof(arg), &p);
4524
-            if (stream) {
4525
-                av_freep(&stream->rtsp_option);
4526
-                stream->rtsp_option = av_strdup(arg);
4527
-            }
4528
-        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4529
-            get_arg(arg, sizeof(arg), &p);
4530
-            if (stream) {
4531
-                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4532
-                    ERROR("Invalid host/IP address: %s\n", arg);
4533
-                }
4534
-                stream->is_multicast = 1;
4535
-                stream->loop = 1; /* default is looping */
4536
-            }
4537
-        } else if (!strcasecmp(cmd, "MulticastPort")) {
4538
-            get_arg(arg, sizeof(arg), &p);
4539
-            if (stream)
4540
-                stream->multicast_port = atoi(arg);
4541
-        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4542
-            get_arg(arg, sizeof(arg), &p);
4543
-            if (stream)
4544
-                stream->multicast_ttl = atoi(arg);
4545
-        } else if (!strcasecmp(cmd, "NoLoop")) {
4546
-            if (stream)
4547
-                stream->loop = 0;
4548
-        } else if (!strcasecmp(cmd, "</Stream>")) {
4549
-            if (!stream) {
4550
-                ERROR("No corresponding <Stream> for </Stream>\n");
4551
-            } else {
4552
-                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4553
-                    if (audio_id != CODEC_ID_NONE) {
4554
-                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4555
-                        audio_enc.codec_id = audio_id;
4556
-                        add_codec(stream, &audio_enc);
4557
-                    }
4558
-                    if (video_id != CODEC_ID_NONE) {
4559
-                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4560
-                        video_enc.codec_id = video_id;
4561
-                        add_codec(stream, &video_enc);
4562
-                    }
4563
-                }
4564
-                stream = NULL;
4565
-            }
4566
-        } else if (!strcasecmp(cmd, "<Redirect")) {
4567
-            /*********************************************/
4568
-            char *q;
4569
-            if (stream || feed || redirect) {
4570
-                ERROR("Already in a tag\n");
4571
-            } else {
4572
-                redirect = av_mallocz(sizeof(FFStream));
4573
-                *last_stream = redirect;
4574
-                last_stream = &redirect->next;
4575
-
4576
-                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4577
-                q = strrchr(redirect->filename, '>');
4578
-                if (*q)
4579
-                    *q = '\0';
4580
-                redirect->stream_type = STREAM_TYPE_REDIRECT;
4581
-            }
4582
-        } else if (!strcasecmp(cmd, "URL")) {
4583
-            if (redirect)
4584
-                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4585
-        } else if (!strcasecmp(cmd, "</Redirect>")) {
4586
-            if (!redirect) {
4587
-                ERROR("No corresponding <Redirect> for </Redirect>\n");
4588
-            } else {
4589
-                if (!redirect->feed_filename[0]) {
4590
-                    ERROR("No URL found for <Redirect>\n");
4591
-                }
4592
-                redirect = NULL;
4593
-            }
4594
-        } else if (!strcasecmp(cmd, "LoadModule")) {
4595
-            get_arg(arg, sizeof(arg), &p);
4596
-#if HAVE_DLOPEN
4597
-            load_module(arg);
4598
-#else
4599
-            ERROR("Module support not compiled into this version: '%s'\n", arg);
4600
-#endif
4601
-        } else {
4602
-            ERROR("Incorrect keyword: '%s'\n", cmd);
4603
-        }
4604
-    }
4605
-#undef ERROR
4606
-
4607
-    fclose(f);
4608
-    if (errors)
4609
-        return -1;
4610
-    else
4611
-        return 0;
4612
-}
4613
-
4614
-static void handle_child_exit(int sig)
4615
-{
4616
-    pid_t pid;
4617
-    int status;
4618
-
4619
-    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4620
-        FFStream *feed;
4621
-
4622
-        for (feed = first_feed; feed; feed = feed->next) {
4623
-            if (feed->pid == pid) {
4624
-                int uptime = time(0) - feed->pid_start;
4625
-
4626
-                feed->pid = 0;
4627
-                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4628
-
4629
-                if (uptime < 30)
4630
-                    /* Turn off any more restarts */
4631
-                    feed->child_argv = 0;
4632
-            }
4633
-        }
4634
-    }
4635
-
4636
-    need_to_start_children = 1;
4637
-}
4638
-
4639
-static void opt_debug(void)
4640
-{
4641
-    ffserver_debug = 1;
4642
-    ffserver_daemon = 0;
4643
-    logfilename[0] = '-';
4644
-}
4645
-
4646
-static void show_help(void)
4647
-{
4648
-    printf("usage: ffserver [options]\n"
4649
-           "Hyper fast multi format Audio/Video streaming server\n");
4650
-    printf("\n");
4651
-    show_help_options(options, "Main options:\n", 0, 0);
4652
-}
4653
-
4654
-static const OptionDef options[] = {
4655
-#include "cmdutils_common_opts.h"
4656
-    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4657
-    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4658
-    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4659
-    { NULL },
4660
-};
4661
-
4662
-int main(int argc, char **argv)
4663
-{
4664
-    struct sigaction sigact;
4665
-
4666
-    av_register_all();
4667
-
4668
-    show_banner();
4669
-
4670
-    my_program_name = argv[0];
4671
-    my_program_dir = getcwd(0, 0);
4672
-    ffserver_daemon = 1;
4673
-
4674
-    parse_options(argc, argv, options, NULL);
4675
-
4676
-    unsetenv("http_proxy");             /* Kill the http_proxy */
4677
-
4678
-    av_lfg_init(&random_state, av_get_random_seed());
4679
-
4680
-    memset(&sigact, 0, sizeof(sigact));
4681
-    sigact.sa_handler = handle_child_exit;
4682
-    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4683
-    sigaction(SIGCHLD, &sigact, 0);
4684
-
4685
-    if (parse_ffconfig(config_filename) < 0) {
4686
-        fprintf(stderr, "Incorrect config file - exiting.\n");
4687
-        exit(1);
4688
-    }
4689
-
4690
-    /* open log file if needed */
4691
-    if (logfilename[0] != '\0') {
4692
-        if (!strcmp(logfilename, "-"))
4693
-            logfile = stdout;
4694
-        else
4695
-            logfile = fopen(logfilename, "a");
4696
-        av_log_set_callback(http_av_log);
4697
-    }
4698
-
4699
-    build_file_streams();
4700
-
4701
-    build_feed_streams();
4702
-
4703
-    compute_bandwidth();
4704
-
4705
-    /* put the process in background and detach it from its TTY */
4706
-    if (ffserver_daemon) {
4707
-        int pid;
4708
-
4709
-        pid = fork();
4710
-        if (pid < 0) {
4711
-            perror("fork");
4712
-            exit(1);
4713
-        } else if (pid > 0) {
4714
-            /* parent : exit */
4715
-            exit(0);
4716
-        } else {
4717
-            /* child */
4718
-            setsid();
4719
-            close(0);
4720
-            open("/dev/null", O_RDWR);
4721
-            if (strcmp(logfilename, "-") != 0) {
4722
-                close(1);
4723
-                dup(0);
4724
-            }
4725
-            close(2);
4726
-            dup(0);
4727
-        }
4728
-    }
4729
-
4730
-    /* signal init */
4731
-    signal(SIGPIPE, SIG_IGN);
4732
-
4733
-    if (ffserver_daemon)
4734
-        chdir("/");
4735
-
4736
-    if (http_server() < 0) {
4737
-        http_log("Could not start server\n");
4738
-        exit(1);
4739
-    }
4740
-
4741
-    return 0;
4742
-}
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- * FFM (ffserver live feed) common header
2
+ * FFM (avserver live feed) common header
3 3
  * Copyright (c) 2001 Fabrice Bellard
4 4
  *
5 5
  * This file is part of Libav.
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- * FFM (ffserver live feed) demuxer
2
+ * FFM (avserver live feed) demuxer
3 3
  * Copyright (c) 2001 Fabrice Bellard
4 4
  *
5 5
  * This file is part of Libav.
... ...
@@ -23,7 +23,7 @@
23 23
 #include "libavutil/intfloat_readwrite.h"
24 24
 #include "avformat.h"
25 25
 #include "ffm.h"
26
-#if CONFIG_FFSERVER
26
+#if CONFIG_AVSERVER
27 27
 #include <unistd.h>
28 28
 
29 29
 int64_t ffm_read_write_index(int fd)
... ...
@@ -55,7 +55,7 @@ void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size)
55 55
     ffm->write_index = pos;
56 56
     ffm->file_size = file_size;
57 57
 }
58
-#endif // CONFIG_FFSERVER
58
+#endif // CONFIG_AVSERVER
59 59
 
60 60
 static int ffm_is_avail_data(AVFormatContext *s, int size)
61 61
 {
... ...
@@ -510,7 +510,7 @@ static int ffm_probe(AVProbeData *p)
510 510
 
511 511
 AVInputFormat ff_ffm_demuxer = {
512 512
     .name           = "ffm",
513
-    .long_name      = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed) format"),
513
+    .long_name      = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed) format"),
514 514
     .priv_data_size = sizeof(FFMContext),
515 515
     .read_probe     = ffm_probe,
516 516
     .read_header    = ffm_read_header,
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- * FFM (ffserver live feed) muxer
2
+ * FFM (avserver live feed) muxer
3 3
  * Copyright (c) 2001 Fabrice Bellard
4 4
  *
5 5
  * This file is part of Libav.
... ...
@@ -242,7 +242,7 @@ static int ffm_write_trailer(AVFormatContext *s)
242 242
 
243 243
 AVOutputFormat ff_ffm_muxer = {
244 244
     .name              = "ffm",
245
-    .long_name         = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed) format"),
245
+    .long_name         = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed) format"),
246 246
     .mime_type         = "",
247 247
     .extensions        = "ffm",
248 248
     .priv_data_size    = sizeof(FFMContext),
... ...
@@ -22,7 +22,7 @@
22 22
 
23 23
 /* Multipart JPEG */
24 24
 
25
-#define BOUNDARY_TAG "ffserver"
25
+#define BOUNDARY_TAG "avserver"
26 26
 
27 27
 static int mpjpeg_write_header(AVFormatContext *s)
28 28
 {