~medibuntu-maintainers/mplayer/medibuntu.precise

« back to all changes in this revision

Viewing changes to ffmpeg/ffserver.c

  • Committer: Gauvain Pocentek
  • Date: 2012-03-06 11:59:12 UTC
  • mfrom: (66.1.15 precise)
  • Revision ID: gauvain@pocentek.net-20120306115912-h9d6kt9j0l532oo5
* Merge from Ubuntu:
  - put back faac support
  - recommends apport-hooks-medibuntu
  - change Maintainer, Uploaders & Vcs-* fields.
* New upstream snapshot
* upload to unstable
* Build against external libmpeg2
* drop 51_FTBFS_arm.patch again
* no longer build depend on libcdparanoia-dev on the Hurd
* Fix FTBFS on the hurd.
  Thanks to Samuel Thibault <sthibault@debian.org> (Closes: #654974)
* Fix FTBFS on arm
* New upstream snapshot, Closes: #650339, #643621, #481807
* Imported Upstream version 1.0~rc4+svn34492
* Bump standards version
* Bump dependency on libav >= 4:0.8~, Closes: #653887
* Fix build-indep
* Build mplayer-gui again, Closes: #568514
* Drop debian/all-lang-config-mak.sh, no longer needed
* include .dfsg1 in version number
* remove get-orig-source target
* no longer prune compiler flags from the environment
* No longer advertise nor build 3fdx, mga and dxr3 backends,
  Closes: #496106, #442181, #533546
* beautify mplayer version identification string
* Brown paperbag upload.
* Next try to fix build failure on sparce after recent binutils change.
* Brown paperbag upload.
* Really fix build failure on sparc after recent binutils change.
* Properly set Replaces/Conflicts on mplayer2{,-dbg} to avoid
  file overwrite errors.
* Adjust versioning of mplayer listed in the mplayer-dbg's Depends field.
* Fix build failure on sparc after recent binutils change.
* Urgency medium bumped because of RC-level bugfix
  and speeding up x264 transition.
* Update to my @debian.org email.
* Upload to unstable
* Enable joystick support on Linux only, Closes: #638408
* Rebuild fixes toolchain issue on arm, Closes: #637077
* New upstream snapshot
* following the discussion started by Diego Biurrun <diego@biurrun.de>
  in debian-devel, I have prepared a new packaging of 'mplayer'
  (with code that comes from CVS)
* the upstream tar.bz cannot be distributed by Debian, since it contains
   CSS code; so I am repackaging it 
* I have tried my best to address all known issues:
  - the package contains the detailed Copyright made by Diego Biurrun 
  - the package does not contain CSS code, or  AFAIK other code on which 
     there is active patent enforcement
  - there is a script  debian/cvs-changelog.sh  that shows all changes
     done to files included in this source.
    This should comply with GPLv2 sec 2.a  (in spirit if not in letter)
    For this reason, the source code contains CVS directories.
* needs   make (>= 3.80) for 'html-chunked-$(1)' in DOCS/xml/Makefile

* some corrections, as suggested Diego Biurrun
  - binary codecs should go into /usr/lib/codecs (upstream default)
  - better template 'mplayer/install_codecs'
  - an empty 'font=' in mplayer.conf breaks mplayer: postinst corrected
* correction in 'mplayer/cfgnote'
* better mplayer.postinst and mplayer.config

* New upstream release
* better debian/copyright file
* do not ship a skin
* New upstream release
* changed DEB_BUILD_OPTIONS to DEB_BUILD_CONFIGURE ,
  DEB_BUILD_OPTIONS is used as in debian policy
* use gcc-3.4
* changed xlibs-dev to a long list of dependencies, for Debian/etch
* try to adhere to  http://www.mplayerhq.hu/DOCS/tech/binary-packaging.txt
  (see README.Debian for details)
* removed dependency on xlibmesa-dev, disabled opengl
* New upstream release
* Simon McVittie <hacks@pseudorandom.co.uk> wonderful work:
- Work around Debian bug #267442 (glibc's sys/uio.h and gcc's altivec.h have
  conflicting uses for __vector) by re-ordering #includes
- Fix potential symlink attack in ./configure
- Disable support for binary codecs on platforms for which those codecs
  aren't available; also disable the corresponding Debconf note when it's
  inappropriate
- Changed Build-Depends: so it works in pbuilder
- Explicitly build-depend on libjpeg62-dev, libfontconfig1-dev,
  libungif4-dev 
- Tweak debian/rules to avoid certain errors being ignored
- Use --language=all
* provide a target  'debian/rules get-orig-source' 
  that recreates the orig.tar.gz ; then use the above orig.tar.gz
* rewrote some parts of debian/rules
* don't clean and recompile docs if upstream ships them
* mplayer-doc was shipping too much stuff
* translated man pages where not installed properly
* compile with libdv4-dev
* correct README.Debian
* Forgot build-dep on libtheora
* Must not depend on libxvidcore
* New upstream release
* new release.
* rc1 to become 0.90
* new pre-release
* new pre-release
* gtk bug fixed.
* new release.
* version bumped
* 0.60 pre2 release
* 0.60 pre-release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Multiple format streaming server
3
 
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 
 *
5
 
 * This file is part of Libav.
6
 
 *
7
 
 * Libav is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU Lesser General Public
9
 
 * License as published by the Free Software Foundation; either
10
 
 * version 2.1 of the License, or (at your option) any later version.
11
 
 *
12
 
 * Libav is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
 * Lesser General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU Lesser General Public
18
 
 * License along with Libav; if not, write to the Free Software
19
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 
 */
21
 
 
22
 
#include "config.h"
23
 
#if !HAVE_CLOSESOCKET
24
 
#define closesocket close
25
 
#endif
26
 
#include <string.h>
27
 
#include <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/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[] = "ffserver";
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 ffserver.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/ffserver.conf";
302
 
 
303
 
static int ffserver_debug;
304
 
static int ffserver_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 ffserver 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 (!ffserver_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("FFserver 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 ffserver 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 (ffserver_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 ffserver -->\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 ffserver\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_open(st->codec, codec) < 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 buf_size, 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
 
        buf_size = FFM_PACKET_SIZE;
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
 
        buf_size = 0;
2149
 
        /* compute position (relative time) */
2150
 
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2151
 
            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2152
 
                return ret;
2153
 
        } else
2154
 
            stream_pos = 0;
2155
 
    }
2156
 
    if (input_filename[0] == '\0')
2157
 
        return -1;
2158
 
 
2159
 
    /* open stream */
2160
 
    if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2161
 
        http_log("could not open %s: %d\n", input_filename, ret);
2162
 
        return -1;
2163
 
    }
2164
 
    s->flags |= AVFMT_FLAG_GENPTS;
2165
 
    c->fmt_in = s;
2166
 
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2167
 
        http_log("Could not find stream info '%s'\n", input_filename);
2168
 
        av_close_input_file(s);
2169
 
        return -1;
2170
 
    }
2171
 
 
2172
 
    /* open each parser */
2173
 
    for(i=0;i<s->nb_streams;i++)
2174
 
        open_parser(s, i);
2175
 
 
2176
 
    /* choose stream as clock source (we favorize video stream if
2177
 
       present) for packet sending */
2178
 
    c->pts_stream_index = 0;
2179
 
    for(i=0;i<c->stream->nb_streams;i++) {
2180
 
        if (c->pts_stream_index == 0 &&
2181
 
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2182
 
            c->pts_stream_index = i;
2183
 
        }
2184
 
    }
2185
 
 
2186
 
    if (c->fmt_in->iformat->read_seek)
2187
 
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2188
 
    /* set the start time (needed for maxtime and RTP packet timing) */
2189
 
    c->start_time = cur_time;
2190
 
    c->first_pts = AV_NOPTS_VALUE;
2191
 
    return 0;
2192
 
}
2193
 
 
2194
 
/* return the server clock (in us) */
2195
 
static int64_t get_server_clock(HTTPContext *c)
2196
 
{
2197
 
    /* compute current pts value from system time */
2198
 
    return (cur_time - c->start_time) * 1000;
2199
 
}
2200
 
 
2201
 
/* return the estimated time at which the current packet must be sent
2202
 
   (in us) */
2203
 
static int64_t get_packet_send_clock(HTTPContext *c)
2204
 
{
2205
 
    int bytes_left, bytes_sent, frame_bytes;
2206
 
 
2207
 
    frame_bytes = c->cur_frame_bytes;
2208
 
    if (frame_bytes <= 0)
2209
 
        return c->cur_pts;
2210
 
    else {
2211
 
        bytes_left = c->buffer_end - c->buffer_ptr;
2212
 
        bytes_sent = frame_bytes - bytes_left;
2213
 
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2214
 
    }
2215
 
}
2216
 
 
2217
 
 
2218
 
static int http_prepare_data(HTTPContext *c)
2219
 
{
2220
 
    int i, len, ret;
2221
 
    AVFormatContext *ctx;
2222
 
 
2223
 
    av_freep(&c->pb_buffer);
2224
 
    switch(c->state) {
2225
 
    case HTTPSTATE_SEND_DATA_HEADER:
2226
 
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2227
 
        av_dict_set(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2228
 
        av_dict_set(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2229
 
        av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2230
 
        av_dict_set(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
2231
 
 
2232
 
        c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2233
 
 
2234
 
        for(i=0;i<c->stream->nb_streams;i++) {
2235
 
            AVStream *src;
2236
 
            c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2237
 
            /* if file or feed, then just take streams from FFStream struct */
2238
 
            if (!c->stream->feed ||
2239
 
                c->stream->feed == c->stream)
2240
 
                src = c->stream->streams[i];
2241
 
            else
2242
 
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2243
 
 
2244
 
            *(c->fmt_ctx.streams[i]) = *src;
2245
 
            c->fmt_ctx.streams[i]->priv_data = 0;
2246
 
            c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2247
 
                                           AVStream, not in codec */
2248
 
        }
2249
 
        /* set output format parameters */
2250
 
        c->fmt_ctx.oformat = c->stream->fmt;
2251
 
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2252
 
 
2253
 
        c->got_key_frame = 0;
2254
 
 
2255
 
        /* prepare header and save header data in a stream */
2256
 
        if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2257
 
            /* XXX: potential leak */
2258
 
            return -1;
2259
 
        }
2260
 
        c->fmt_ctx.pb->seekable = 0;
2261
 
 
2262
 
        /*
2263
 
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2264
 
         * Default value from Libav
2265
 
         * Try to set it use configuration option
2266
 
         */
2267
 
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2268
 
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2269
 
 
2270
 
        if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2271
 
            http_log("Error writing output header\n");
2272
 
            return -1;
2273
 
        }
2274
 
        av_dict_free(&c->fmt_ctx.metadata);
2275
 
 
2276
 
        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2277
 
        c->buffer_ptr = c->pb_buffer;
2278
 
        c->buffer_end = c->pb_buffer + len;
2279
 
 
2280
 
        c->state = HTTPSTATE_SEND_DATA;
2281
 
        c->last_packet_sent = 0;
2282
 
        break;
2283
 
    case HTTPSTATE_SEND_DATA:
2284
 
        /* find a new packet */
2285
 
        /* read a packet from the input stream */
2286
 
        if (c->stream->feed)
2287
 
            ffm_set_write_index(c->fmt_in,
2288
 
                                c->stream->feed->feed_write_index,
2289
 
                                c->stream->feed->feed_size);
2290
 
 
2291
 
        if (c->stream->max_time &&
2292
 
            c->stream->max_time + c->start_time - cur_time < 0)
2293
 
            /* We have timed out */
2294
 
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2295
 
        else {
2296
 
            AVPacket pkt;
2297
 
        redo:
2298
 
            ret = av_read_frame(c->fmt_in, &pkt);
2299
 
            if (ret < 0) {
2300
 
                if (c->stream->feed) {
2301
 
                    /* if coming from feed, it means we reached the end of the
2302
 
                       ffm file, so must wait for more data */
2303
 
                    c->state = HTTPSTATE_WAIT_FEED;
2304
 
                    return 1; /* state changed */
2305
 
                } else if (ret == AVERROR(EAGAIN)) {
2306
 
                    /* input not ready, come back later */
2307
 
                    return 0;
2308
 
                } else {
2309
 
                    if (c->stream->loop) {
2310
 
                        av_close_input_file(c->fmt_in);
2311
 
                        c->fmt_in = NULL;
2312
 
                        if (open_input_stream(c, "") < 0)
2313
 
                            goto no_loop;
2314
 
                        goto redo;
2315
 
                    } else {
2316
 
                    no_loop:
2317
 
                        /* must send trailer now because eof or error */
2318
 
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2319
 
                    }
2320
 
                }
2321
 
            } else {
2322
 
                int source_index = pkt.stream_index;
2323
 
                /* update first pts if needed */
2324
 
                if (c->first_pts == AV_NOPTS_VALUE) {
2325
 
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2326
 
                    c->start_time = cur_time;
2327
 
                }
2328
 
                /* send it to the appropriate stream */
2329
 
                if (c->stream->feed) {
2330
 
                    /* if coming from a feed, select the right stream */
2331
 
                    if (c->switch_pending) {
2332
 
                        c->switch_pending = 0;
2333
 
                        for(i=0;i<c->stream->nb_streams;i++) {
2334
 
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2335
 
                                if (pkt.flags & AV_PKT_FLAG_KEY)
2336
 
                                    c->switch_feed_streams[i] = -1;
2337
 
                            if (c->switch_feed_streams[i] >= 0)
2338
 
                                c->switch_pending = 1;
2339
 
                        }
2340
 
                    }
2341
 
                    for(i=0;i<c->stream->nb_streams;i++) {
2342
 
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2343
 
                            AVStream *st = c->fmt_in->streams[source_index];
2344
 
                            pkt.stream_index = i;
2345
 
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2346
 
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2347
 
                                 c->stream->nb_streams == 1))
2348
 
                                c->got_key_frame = 1;
2349
 
                            if (!c->stream->send_on_key || c->got_key_frame)
2350
 
                                goto send_it;
2351
 
                        }
2352
 
                    }
2353
 
                } else {
2354
 
                    AVCodecContext *codec;
2355
 
                    AVStream *ist, *ost;
2356
 
                send_it:
2357
 
                    ist = c->fmt_in->streams[source_index];
2358
 
                    /* specific handling for RTP: we use several
2359
 
                       output stream (one for each RTP
2360
 
                       connection). XXX: need more abstract handling */
2361
 
                    if (c->is_packetized) {
2362
 
                        /* compute send time and duration */
2363
 
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2364
 
                        c->cur_pts -= c->first_pts;
2365
 
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2366
 
                        /* find RTP context */
2367
 
                        c->packet_stream_index = pkt.stream_index;
2368
 
                        ctx = c->rtp_ctx[c->packet_stream_index];
2369
 
                        if(!ctx) {
2370
 
                            av_free_packet(&pkt);
2371
 
                            break;
2372
 
                        }
2373
 
                        codec = ctx->streams[0]->codec;
2374
 
                        /* only one stream per RTP connection */
2375
 
                        pkt.stream_index = 0;
2376
 
                    } else {
2377
 
                        ctx = &c->fmt_ctx;
2378
 
                        /* Fudge here */
2379
 
                        codec = ctx->streams[pkt.stream_index]->codec;
2380
 
                    }
2381
 
 
2382
 
                    if (c->is_packetized) {
2383
 
                        int max_packet_size;
2384
 
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2385
 
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2386
 
                        else
2387
 
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2388
 
                        ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2389
 
                    } else {
2390
 
                        ret = avio_open_dyn_buf(&ctx->pb);
2391
 
                    }
2392
 
                    if (ret < 0) {
2393
 
                        /* XXX: potential leak */
2394
 
                        return -1;
2395
 
                    }
2396
 
                    ost = ctx->streams[pkt.stream_index];
2397
 
 
2398
 
                    ctx->pb->seekable = 0;
2399
 
                    if (pkt.dts != AV_NOPTS_VALUE)
2400
 
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2401
 
                    if (pkt.pts != AV_NOPTS_VALUE)
2402
 
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2403
 
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2404
 
                    if (av_write_frame(ctx, &pkt) < 0) {
2405
 
                        http_log("Error writing frame to output\n");
2406
 
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2407
 
                    }
2408
 
 
2409
 
                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2410
 
                    c->cur_frame_bytes = len;
2411
 
                    c->buffer_ptr = c->pb_buffer;
2412
 
                    c->buffer_end = c->pb_buffer + len;
2413
 
 
2414
 
                    codec->frame_number++;
2415
 
                    if (len == 0) {
2416
 
                        av_free_packet(&pkt);
2417
 
                        goto redo;
2418
 
                    }
2419
 
                }
2420
 
                av_free_packet(&pkt);
2421
 
            }
2422
 
        }
2423
 
        break;
2424
 
    default:
2425
 
    case HTTPSTATE_SEND_DATA_TRAILER:
2426
 
        /* last packet test ? */
2427
 
        if (c->last_packet_sent || c->is_packetized)
2428
 
            return -1;
2429
 
        ctx = &c->fmt_ctx;
2430
 
        /* prepare header */
2431
 
        if (avio_open_dyn_buf(&ctx->pb) < 0) {
2432
 
            /* XXX: potential leak */
2433
 
            return -1;
2434
 
        }
2435
 
        c->fmt_ctx.pb->seekable = 0;
2436
 
        av_write_trailer(ctx);
2437
 
        len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2438
 
        c->buffer_ptr = c->pb_buffer;
2439
 
        c->buffer_end = c->pb_buffer + len;
2440
 
 
2441
 
        c->last_packet_sent = 1;
2442
 
        break;
2443
 
    }
2444
 
    return 0;
2445
 
}
2446
 
 
2447
 
/* should convert the format at the same time */
2448
 
/* send data starting at c->buffer_ptr to the output connection
2449
 
   (either UDP or TCP connection) */
2450
 
static int http_send_data(HTTPContext *c)
2451
 
{
2452
 
    int len, ret;
2453
 
 
2454
 
    for(;;) {
2455
 
        if (c->buffer_ptr >= c->buffer_end) {
2456
 
            ret = http_prepare_data(c);
2457
 
            if (ret < 0)
2458
 
                return -1;
2459
 
            else if (ret != 0)
2460
 
                /* state change requested */
2461
 
                break;
2462
 
        } else {
2463
 
            if (c->is_packetized) {
2464
 
                /* RTP data output */
2465
 
                len = c->buffer_end - c->buffer_ptr;
2466
 
                if (len < 4) {
2467
 
                    /* fail safe - should never happen */
2468
 
                fail1:
2469
 
                    c->buffer_ptr = c->buffer_end;
2470
 
                    return 0;
2471
 
                }
2472
 
                len = (c->buffer_ptr[0] << 24) |
2473
 
                    (c->buffer_ptr[1] << 16) |
2474
 
                    (c->buffer_ptr[2] << 8) |
2475
 
                    (c->buffer_ptr[3]);
2476
 
                if (len > (c->buffer_end - c->buffer_ptr))
2477
 
                    goto fail1;
2478
 
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2479
 
                    /* nothing to send yet: we can wait */
2480
 
                    return 0;
2481
 
                }
2482
 
 
2483
 
                c->data_count += len;
2484
 
                update_datarate(&c->datarate, c->data_count);
2485
 
                if (c->stream)
2486
 
                    c->stream->bytes_served += len;
2487
 
 
2488
 
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2489
 
                    /* RTP packets are sent inside the RTSP TCP connection */
2490
 
                    AVIOContext *pb;
2491
 
                    int interleaved_index, size;
2492
 
                    uint8_t header[4];
2493
 
                    HTTPContext *rtsp_c;
2494
 
 
2495
 
                    rtsp_c = c->rtsp_c;
2496
 
                    /* if no RTSP connection left, error */
2497
 
                    if (!rtsp_c)
2498
 
                        return -1;
2499
 
                    /* if already sending something, then wait. */
2500
 
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2501
 
                        break;
2502
 
                    if (avio_open_dyn_buf(&pb) < 0)
2503
 
                        goto fail1;
2504
 
                    interleaved_index = c->packet_stream_index * 2;
2505
 
                    /* RTCP packets are sent at odd indexes */
2506
 
                    if (c->buffer_ptr[1] == 200)
2507
 
                        interleaved_index++;
2508
 
                    /* write RTSP TCP header */
2509
 
                    header[0] = '$';
2510
 
                    header[1] = interleaved_index;
2511
 
                    header[2] = len >> 8;
2512
 
                    header[3] = len;
2513
 
                    avio_write(pb, header, 4);
2514
 
                    /* write RTP packet data */
2515
 
                    c->buffer_ptr += 4;
2516
 
                    avio_write(pb, c->buffer_ptr, len);
2517
 
                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
2518
 
                    /* prepare asynchronous TCP sending */
2519
 
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2520
 
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2521
 
                    c->buffer_ptr += len;
2522
 
 
2523
 
                    /* send everything we can NOW */
2524
 
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2525
 
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2526
 
                    if (len > 0)
2527
 
                        rtsp_c->packet_buffer_ptr += len;
2528
 
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2529
 
                        /* if we could not send all the data, we will
2530
 
                           send it later, so a new state is needed to
2531
 
                           "lock" the RTSP TCP connection */
2532
 
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2533
 
                        break;
2534
 
                    } else
2535
 
                        /* all data has been sent */
2536
 
                        av_freep(&c->packet_buffer);
2537
 
                } else {
2538
 
                    /* send RTP packet directly in UDP */
2539
 
                    c->buffer_ptr += 4;
2540
 
                    url_write(c->rtp_handles[c->packet_stream_index],
2541
 
                              c->buffer_ptr, len);
2542
 
                    c->buffer_ptr += len;
2543
 
                    /* here we continue as we can send several packets per 10 ms slot */
2544
 
                }
2545
 
            } else {
2546
 
                /* TCP data output */
2547
 
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2548
 
                if (len < 0) {
2549
 
                    if (ff_neterrno() != AVERROR(EAGAIN) &&
2550
 
                        ff_neterrno() != AVERROR(EINTR))
2551
 
                        /* error : close connection */
2552
 
                        return -1;
2553
 
                    else
2554
 
                        return 0;
2555
 
                } else
2556
 
                    c->buffer_ptr += len;
2557
 
 
2558
 
                c->data_count += len;
2559
 
                update_datarate(&c->datarate, c->data_count);
2560
 
                if (c->stream)
2561
 
                    c->stream->bytes_served += len;
2562
 
                break;
2563
 
            }
2564
 
        }
2565
 
    } /* for(;;) */
2566
 
    return 0;
2567
 
}
2568
 
 
2569
 
static int http_start_receive_data(HTTPContext *c)
2570
 
{
2571
 
    int fd;
2572
 
 
2573
 
    if (c->stream->feed_opened)
2574
 
        return -1;
2575
 
 
2576
 
    /* Don't permit writing to this one */
2577
 
    if (c->stream->readonly)
2578
 
        return -1;
2579
 
 
2580
 
    /* open feed */
2581
 
    fd = open(c->stream->feed_filename, O_RDWR);
2582
 
    if (fd < 0) {
2583
 
        http_log("Error opening feeder file: %s\n", strerror(errno));
2584
 
        return -1;
2585
 
    }
2586
 
    c->feed_fd = fd;
2587
 
 
2588
 
    if (c->stream->truncate) {
2589
 
        /* truncate feed file */
2590
 
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2591
 
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2592
 
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2593
 
    } else {
2594
 
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2595
 
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2596
 
            return -1;
2597
 
        }
2598
 
    }
2599
 
 
2600
 
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2601
 
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2602
 
    lseek(fd, 0, SEEK_SET);
2603
 
 
2604
 
    /* init buffer input */
2605
 
    c->buffer_ptr = c->buffer;
2606
 
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2607
 
    c->stream->feed_opened = 1;
2608
 
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2609
 
    return 0;
2610
 
}
2611
 
 
2612
 
static int http_receive_data(HTTPContext *c)
2613
 
{
2614
 
    HTTPContext *c1;
2615
 
    int len, loop_run = 0;
2616
 
 
2617
 
    while (c->chunked_encoding && !c->chunk_size &&
2618
 
           c->buffer_end > c->buffer_ptr) {
2619
 
        /* read chunk header, if present */
2620
 
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2621
 
 
2622
 
        if (len < 0) {
2623
 
            if (ff_neterrno() != AVERROR(EAGAIN) &&
2624
 
                ff_neterrno() != AVERROR(EINTR))
2625
 
                /* error : close connection */
2626
 
                goto fail;
2627
 
            return 0;
2628
 
        } else if (len == 0) {
2629
 
            /* end of connection : close it */
2630
 
            goto fail;
2631
 
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2632
 
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2633
 
            c->chunk_size = strtol(c->buffer, 0, 16);
2634
 
            if (c->chunk_size == 0) // end of stream
2635
 
                goto fail;
2636
 
            c->buffer_ptr = c->buffer;
2637
 
            break;
2638
 
        } else if (++loop_run > 10) {
2639
 
            /* no chunk header, abort */
2640
 
            goto fail;
2641
 
        } else {
2642
 
            c->buffer_ptr++;
2643
 
        }
2644
 
    }
2645
 
 
2646
 
    if (c->buffer_end > c->buffer_ptr) {
2647
 
        len = recv(c->fd, c->buffer_ptr,
2648
 
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2649
 
        if (len < 0) {
2650
 
            if (ff_neterrno() != AVERROR(EAGAIN) &&
2651
 
                ff_neterrno() != AVERROR(EINTR))
2652
 
                /* error : close connection */
2653
 
                goto fail;
2654
 
        } else if (len == 0)
2655
 
            /* end of connection : close it */
2656
 
            goto fail;
2657
 
        else {
2658
 
            c->chunk_size -= len;
2659
 
            c->buffer_ptr += len;
2660
 
            c->data_count += len;
2661
 
            update_datarate(&c->datarate, c->data_count);
2662
 
        }
2663
 
    }
2664
 
 
2665
 
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2666
 
        if (c->buffer[0] != 'f' ||
2667
 
            c->buffer[1] != 'm') {
2668
 
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2669
 
            goto fail;
2670
 
        }
2671
 
    }
2672
 
 
2673
 
    if (c->buffer_ptr >= c->buffer_end) {
2674
 
        FFStream *feed = c->stream;
2675
 
        /* a packet has been received : write it in the store, except
2676
 
           if header */
2677
 
        if (c->data_count > FFM_PACKET_SIZE) {
2678
 
 
2679
 
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2680
 
            /* XXX: use llseek or url_seek */
2681
 
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2682
 
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2683
 
                http_log("Error writing to feed file: %s\n", strerror(errno));
2684
 
                goto fail;
2685
 
            }
2686
 
 
2687
 
            feed->feed_write_index += FFM_PACKET_SIZE;
2688
 
            /* update file size */
2689
 
            if (feed->feed_write_index > c->stream->feed_size)
2690
 
                feed->feed_size = feed->feed_write_index;
2691
 
 
2692
 
            /* handle wrap around if max file size reached */
2693
 
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2694
 
                feed->feed_write_index = FFM_PACKET_SIZE;
2695
 
 
2696
 
            /* write index */
2697
 
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2698
 
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2699
 
                goto fail;
2700
 
            }
2701
 
 
2702
 
            /* wake up any waiting connections */
2703
 
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2704
 
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2705
 
                    c1->stream->feed == c->stream->feed)
2706
 
                    c1->state = HTTPSTATE_SEND_DATA;
2707
 
            }
2708
 
        } else {
2709
 
            /* We have a header in our hands that contains useful data */
2710
 
            AVFormatContext *s = avformat_alloc_context();
2711
 
            AVIOContext *pb;
2712
 
            AVInputFormat *fmt_in;
2713
 
            int i;
2714
 
 
2715
 
            if (!s)
2716
 
                goto fail;
2717
 
 
2718
 
            /* use feed output format name to find corresponding input format */
2719
 
            fmt_in = av_find_input_format(feed->fmt->name);
2720
 
            if (!fmt_in)
2721
 
                goto fail;
2722
 
 
2723
 
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2724
 
                                    0, NULL, NULL, NULL, NULL);
2725
 
            pb->seekable = 0;
2726
 
 
2727
 
            s->pb = pb;
2728
 
            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2729
 
                av_free(pb);
2730
 
                goto fail;
2731
 
            }
2732
 
 
2733
 
            /* Now we have the actual streams */
2734
 
            if (s->nb_streams != feed->nb_streams) {
2735
 
                av_close_input_stream(s);
2736
 
                av_free(pb);
2737
 
                http_log("Feed '%s' stream number does not match registered feed\n",
2738
 
                         c->stream->feed_filename);
2739
 
                goto fail;
2740
 
            }
2741
 
 
2742
 
            for (i = 0; i < s->nb_streams; i++) {
2743
 
                AVStream *fst = feed->streams[i];
2744
 
                AVStream *st = s->streams[i];
2745
 
                avcodec_copy_context(fst->codec, st->codec);
2746
 
            }
2747
 
 
2748
 
            av_close_input_stream(s);
2749
 
            av_free(pb);
2750
 
        }
2751
 
        c->buffer_ptr = c->buffer;
2752
 
    }
2753
 
 
2754
 
    return 0;
2755
 
 fail:
2756
 
    c->stream->feed_opened = 0;
2757
 
    close(c->feed_fd);
2758
 
    /* wake up any waiting connections to stop waiting for feed */
2759
 
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2760
 
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2761
 
            c1->stream->feed == c->stream->feed)
2762
 
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2763
 
    }
2764
 
    return -1;
2765
 
}
2766
 
 
2767
 
/********************************************************************/
2768
 
/* RTSP handling */
2769
 
 
2770
 
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2771
 
{
2772
 
    const char *str;
2773
 
    time_t ti;
2774
 
    struct tm *tm;
2775
 
    char buf2[32];
2776
 
 
2777
 
    switch(error_number) {
2778
 
    case RTSP_STATUS_OK:
2779
 
        str = "OK";
2780
 
        break;
2781
 
    case RTSP_STATUS_METHOD:
2782
 
        str = "Method Not Allowed";
2783
 
        break;
2784
 
    case RTSP_STATUS_BANDWIDTH:
2785
 
        str = "Not Enough Bandwidth";
2786
 
        break;
2787
 
    case RTSP_STATUS_SESSION:
2788
 
        str = "Session Not Found";
2789
 
        break;
2790
 
    case RTSP_STATUS_STATE:
2791
 
        str = "Method Not Valid in This State";
2792
 
        break;
2793
 
    case RTSP_STATUS_AGGREGATE:
2794
 
        str = "Aggregate operation not allowed";
2795
 
        break;
2796
 
    case RTSP_STATUS_ONLY_AGGREGATE:
2797
 
        str = "Only aggregate operation allowed";
2798
 
        break;
2799
 
    case RTSP_STATUS_TRANSPORT:
2800
 
        str = "Unsupported transport";
2801
 
        break;
2802
 
    case RTSP_STATUS_INTERNAL:
2803
 
        str = "Internal Server Error";
2804
 
        break;
2805
 
    case RTSP_STATUS_SERVICE:
2806
 
        str = "Service Unavailable";
2807
 
        break;
2808
 
    case RTSP_STATUS_VERSION:
2809
 
        str = "RTSP Version not supported";
2810
 
        break;
2811
 
    default:
2812
 
        str = "Unknown Error";
2813
 
        break;
2814
 
    }
2815
 
 
2816
 
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2817
 
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2818
 
 
2819
 
    /* output GMT time */
2820
 
    ti = time(NULL);
2821
 
    tm = gmtime(&ti);
2822
 
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2823
 
    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2824
 
}
2825
 
 
2826
 
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2827
 
{
2828
 
    rtsp_reply_header(c, error_number);
2829
 
    avio_printf(c->pb, "\r\n");
2830
 
}
2831
 
 
2832
 
static int rtsp_parse_request(HTTPContext *c)
2833
 
{
2834
 
    const char *p, *p1, *p2;
2835
 
    char cmd[32];
2836
 
    char url[1024];
2837
 
    char protocol[32];
2838
 
    char line[1024];
2839
 
    int len;
2840
 
    RTSPMessageHeader header1, *header = &header1;
2841
 
 
2842
 
    c->buffer_ptr[0] = '\0';
2843
 
    p = c->buffer;
2844
 
 
2845
 
    get_word(cmd, sizeof(cmd), &p);
2846
 
    get_word(url, sizeof(url), &p);
2847
 
    get_word(protocol, sizeof(protocol), &p);
2848
 
 
2849
 
    av_strlcpy(c->method, cmd, sizeof(c->method));
2850
 
    av_strlcpy(c->url, url, sizeof(c->url));
2851
 
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2852
 
 
2853
 
    if (avio_open_dyn_buf(&c->pb) < 0) {
2854
 
        /* XXX: cannot do more */
2855
 
        c->pb = NULL; /* safety */
2856
 
        return -1;
2857
 
    }
2858
 
 
2859
 
    /* check version name */
2860
 
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2861
 
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2862
 
        goto the_end;
2863
 
    }
2864
 
 
2865
 
    /* parse each header line */
2866
 
    memset(header, 0, sizeof(*header));
2867
 
    /* skip to next line */
2868
 
    while (*p != '\n' && *p != '\0')
2869
 
        p++;
2870
 
    if (*p == '\n')
2871
 
        p++;
2872
 
    while (*p != '\0') {
2873
 
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2874
 
        if (!p1)
2875
 
            break;
2876
 
        p2 = p1;
2877
 
        if (p2 > p && p2[-1] == '\r')
2878
 
            p2--;
2879
 
        /* skip empty line */
2880
 
        if (p2 == p)
2881
 
            break;
2882
 
        len = p2 - p;
2883
 
        if (len > sizeof(line) - 1)
2884
 
            len = sizeof(line) - 1;
2885
 
        memcpy(line, p, len);
2886
 
        line[len] = '\0';
2887
 
        ff_rtsp_parse_line(header, line, NULL, NULL);
2888
 
        p = p1 + 1;
2889
 
    }
2890
 
 
2891
 
    /* handle sequence number */
2892
 
    c->seq = header->seq;
2893
 
 
2894
 
    if (!strcmp(cmd, "DESCRIBE"))
2895
 
        rtsp_cmd_describe(c, url);
2896
 
    else if (!strcmp(cmd, "OPTIONS"))
2897
 
        rtsp_cmd_options(c, url);
2898
 
    else if (!strcmp(cmd, "SETUP"))
2899
 
        rtsp_cmd_setup(c, url, header);
2900
 
    else if (!strcmp(cmd, "PLAY"))
2901
 
        rtsp_cmd_play(c, url, header);
2902
 
    else if (!strcmp(cmd, "PAUSE"))
2903
 
        rtsp_cmd_pause(c, url, header);
2904
 
    else if (!strcmp(cmd, "TEARDOWN"))
2905
 
        rtsp_cmd_teardown(c, url, header);
2906
 
    else
2907
 
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2908
 
 
2909
 
 the_end:
2910
 
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2911
 
    c->pb = NULL; /* safety */
2912
 
    if (len < 0) {
2913
 
        /* XXX: cannot do more */
2914
 
        return -1;
2915
 
    }
2916
 
    c->buffer_ptr = c->pb_buffer;
2917
 
    c->buffer_end = c->pb_buffer + len;
2918
 
    c->state = RTSPSTATE_SEND_REPLY;
2919
 
    return 0;
2920
 
}
2921
 
 
2922
 
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2923
 
                                   struct in_addr my_ip)
2924
 
{
2925
 
    AVFormatContext *avc;
2926
 
    AVStream *avs = NULL;
2927
 
    int i;
2928
 
 
2929
 
    avc =  avformat_alloc_context();
2930
 
    if (avc == NULL) {
2931
 
        return -1;
2932
 
    }
2933
 
    av_dict_set(&avc->metadata, "title",
2934
 
               stream->title[0] ? stream->title : "No Title", 0);
2935
 
    avc->nb_streams = stream->nb_streams;
2936
 
    if (stream->is_multicast) {
2937
 
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2938
 
                 inet_ntoa(stream->multicast_ip),
2939
 
                 stream->multicast_port, stream->multicast_ttl);
2940
 
    } else {
2941
 
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2942
 
    }
2943
 
 
2944
 
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2945
 
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2946
 
        goto sdp_done;
2947
 
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2948
 
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2949
 
        goto sdp_done;
2950
 
 
2951
 
    for(i = 0; i < stream->nb_streams; i++) {
2952
 
        avc->streams[i] = &avs[i];
2953
 
        avc->streams[i]->codec = stream->streams[i]->codec;
2954
 
    }
2955
 
    *pbuffer = av_mallocz(2048);
2956
 
    av_sdp_create(&avc, 1, *pbuffer, 2048);
2957
 
 
2958
 
 sdp_done:
2959
 
    av_free(avc->streams);
2960
 
    av_dict_free(&avc->metadata);
2961
 
    av_free(avc);
2962
 
    av_free(avs);
2963
 
 
2964
 
    return strlen(*pbuffer);
2965
 
}
2966
 
 
2967
 
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2968
 
{
2969
 
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2970
 
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2971
 
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2972
 
    avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2973
 
    avio_printf(c->pb, "\r\n");
2974
 
}
2975
 
 
2976
 
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2977
 
{
2978
 
    FFStream *stream;
2979
 
    char path1[1024];
2980
 
    const char *path;
2981
 
    uint8_t *content;
2982
 
    int content_length, len;
2983
 
    struct sockaddr_in my_addr;
2984
 
 
2985
 
    /* find which url is asked */
2986
 
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2987
 
    path = path1;
2988
 
    if (*path == '/')
2989
 
        path++;
2990
 
 
2991
 
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2992
 
        if (!stream->is_feed &&
2993
 
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2994
 
            !strcmp(path, stream->filename)) {
2995
 
            goto found;
2996
 
        }
2997
 
    }
2998
 
    /* no stream found */
2999
 
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3000
 
    return;
3001
 
 
3002
 
 found:
3003
 
    /* prepare the media description in sdp format */
3004
 
 
3005
 
    /* get the host IP */
3006
 
    len = sizeof(my_addr);
3007
 
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3008
 
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3009
 
    if (content_length < 0) {
3010
 
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3011
 
        return;
3012
 
    }
3013
 
    rtsp_reply_header(c, RTSP_STATUS_OK);
3014
 
    avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3015
 
    avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3016
 
    avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3017
 
    avio_printf(c->pb, "\r\n");
3018
 
    avio_write(c->pb, content, content_length);
3019
 
    av_free(content);
3020
 
}
3021
 
 
3022
 
static HTTPContext *find_rtp_session(const char *session_id)
3023
 
{
3024
 
    HTTPContext *c;
3025
 
 
3026
 
    if (session_id[0] == '\0')
3027
 
        return NULL;
3028
 
 
3029
 
    for(c = first_http_ctx; c != NULL; c = c->next) {
3030
 
        if (!strcmp(c->session_id, session_id))
3031
 
            return c;
3032
 
    }
3033
 
    return NULL;
3034
 
}
3035
 
 
3036
 
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3037
 
{
3038
 
    RTSPTransportField *th;
3039
 
    int i;
3040
 
 
3041
 
    for(i=0;i<h->nb_transports;i++) {
3042
 
        th = &h->transports[i];
3043
 
        if (th->lower_transport == lower_transport)
3044
 
            return th;
3045
 
    }
3046
 
    return NULL;
3047
 
}
3048
 
 
3049
 
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3050
 
                           RTSPMessageHeader *h)
3051
 
{
3052
 
    FFStream *stream;
3053
 
    int stream_index, rtp_port, rtcp_port;
3054
 
    char buf[1024];
3055
 
    char path1[1024];
3056
 
    const char *path;
3057
 
    HTTPContext *rtp_c;
3058
 
    RTSPTransportField *th;
3059
 
    struct sockaddr_in dest_addr;
3060
 
    RTSPActionServerSetup setup;
3061
 
 
3062
 
    /* find which url is asked */
3063
 
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3064
 
    path = path1;
3065
 
    if (*path == '/')
3066
 
        path++;
3067
 
 
3068
 
    /* now check each stream */
3069
 
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3070
 
        if (!stream->is_feed &&
3071
 
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3072
 
            /* accept aggregate filenames only if single stream */
3073
 
            if (!strcmp(path, stream->filename)) {
3074
 
                if (stream->nb_streams != 1) {
3075
 
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3076
 
                    return;
3077
 
                }
3078
 
                stream_index = 0;
3079
 
                goto found;
3080
 
            }
3081
 
 
3082
 
            for(stream_index = 0; stream_index < stream->nb_streams;
3083
 
                stream_index++) {
3084
 
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
3085
 
                         stream->filename, stream_index);
3086
 
                if (!strcmp(path, buf))
3087
 
                    goto found;
3088
 
            }
3089
 
        }
3090
 
    }
3091
 
    /* no stream found */
3092
 
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3093
 
    return;
3094
 
 found:
3095
 
 
3096
 
    /* generate session id if needed */
3097
 
    if (h->session_id[0] == '\0')
3098
 
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3099
 
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3100
 
 
3101
 
    /* find rtp session, and create it if none found */
3102
 
    rtp_c = find_rtp_session(h->session_id);
3103
 
    if (!rtp_c) {
3104
 
        /* always prefer UDP */
3105
 
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3106
 
        if (!th) {
3107
 
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3108
 
            if (!th) {
3109
 
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3110
 
                return;
3111
 
            }
3112
 
        }
3113
 
 
3114
 
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3115
 
                                   th->lower_transport);
3116
 
        if (!rtp_c) {
3117
 
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3118
 
            return;
3119
 
        }
3120
 
 
3121
 
        /* open input stream */
3122
 
        if (open_input_stream(rtp_c, "") < 0) {
3123
 
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3124
 
            return;
3125
 
        }
3126
 
    }
3127
 
 
3128
 
    /* test if stream is OK (test needed because several SETUP needs
3129
 
       to be done for a given file) */
3130
 
    if (rtp_c->stream != stream) {
3131
 
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3132
 
        return;
3133
 
    }
3134
 
 
3135
 
    /* test if stream is already set up */
3136
 
    if (rtp_c->rtp_ctx[stream_index]) {
3137
 
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3138
 
        return;
3139
 
    }
3140
 
 
3141
 
    /* check transport */
3142
 
    th = find_transport(h, rtp_c->rtp_protocol);
3143
 
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3144
 
                th->client_port_min <= 0)) {
3145
 
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3146
 
        return;
3147
 
    }
3148
 
 
3149
 
    /* setup default options */
3150
 
    setup.transport_option[0] = '\0';
3151
 
    dest_addr = rtp_c->from_addr;
3152
 
    dest_addr.sin_port = htons(th->client_port_min);
3153
 
 
3154
 
    /* setup stream */
3155
 
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3156
 
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3157
 
        return;
3158
 
    }
3159
 
 
3160
 
    /* now everything is OK, so we can send the connection parameters */
3161
 
    rtsp_reply_header(c, RTSP_STATUS_OK);
3162
 
    /* session ID */
3163
 
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3164
 
 
3165
 
    switch(rtp_c->rtp_protocol) {
3166
 
    case RTSP_LOWER_TRANSPORT_UDP:
3167
 
        rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3168
 
        rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3169
 
        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3170
 
                    "client_port=%d-%d;server_port=%d-%d",
3171
 
                    th->client_port_min, th->client_port_max,
3172
 
                    rtp_port, rtcp_port);
3173
 
        break;
3174
 
    case RTSP_LOWER_TRANSPORT_TCP:
3175
 
        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3176
 
                    stream_index * 2, stream_index * 2 + 1);
3177
 
        break;
3178
 
    default:
3179
 
        break;
3180
 
    }
3181
 
    if (setup.transport_option[0] != '\0')
3182
 
        avio_printf(c->pb, ";%s", setup.transport_option);
3183
 
    avio_printf(c->pb, "\r\n");
3184
 
 
3185
 
 
3186
 
    avio_printf(c->pb, "\r\n");
3187
 
}
3188
 
 
3189
 
 
3190
 
/* find an rtp connection by using the session ID. Check consistency
3191
 
   with filename */
3192
 
static HTTPContext *find_rtp_session_with_url(const char *url,
3193
 
                                              const char *session_id)
3194
 
{
3195
 
    HTTPContext *rtp_c;
3196
 
    char path1[1024];
3197
 
    const char *path;
3198
 
    char buf[1024];
3199
 
    int s, len;
3200
 
 
3201
 
    rtp_c = find_rtp_session(session_id);
3202
 
    if (!rtp_c)
3203
 
        return NULL;
3204
 
 
3205
 
    /* find which url is asked */
3206
 
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3207
 
    path = path1;
3208
 
    if (*path == '/')
3209
 
        path++;
3210
 
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3211
 
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3212
 
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3213
 
        rtp_c->stream->filename, s);
3214
 
      if(!strncmp(path, buf, sizeof(buf))) {
3215
 
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3216
 
        return rtp_c;
3217
 
      }
3218
 
    }
3219
 
    len = strlen(path);
3220
 
    if (len > 0 && path[len - 1] == '/' &&
3221
 
        !strncmp(path, rtp_c->stream->filename, len - 1))
3222
 
        return rtp_c;
3223
 
    return NULL;
3224
 
}
3225
 
 
3226
 
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3227
 
{
3228
 
    HTTPContext *rtp_c;
3229
 
 
3230
 
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3231
 
    if (!rtp_c) {
3232
 
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3233
 
        return;
3234
 
    }
3235
 
 
3236
 
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3237
 
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3238
 
        rtp_c->state != HTTPSTATE_READY) {
3239
 
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3240
 
        return;
3241
 
    }
3242
 
 
3243
 
    rtp_c->state = HTTPSTATE_SEND_DATA;
3244
 
 
3245
 
    /* now everything is OK, so we can send the connection parameters */
3246
 
    rtsp_reply_header(c, RTSP_STATUS_OK);
3247
 
    /* session ID */
3248
 
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3249
 
    avio_printf(c->pb, "\r\n");
3250
 
}
3251
 
 
3252
 
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3253
 
{
3254
 
    HTTPContext *rtp_c;
3255
 
 
3256
 
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3257
 
    if (!rtp_c) {
3258
 
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3259
 
        return;
3260
 
    }
3261
 
 
3262
 
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3263
 
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3264
 
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3265
 
        return;
3266
 
    }
3267
 
 
3268
 
    rtp_c->state = HTTPSTATE_READY;
3269
 
    rtp_c->first_pts = AV_NOPTS_VALUE;
3270
 
    /* now everything is OK, so we can send the connection parameters */
3271
 
    rtsp_reply_header(c, RTSP_STATUS_OK);
3272
 
    /* session ID */
3273
 
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3274
 
    avio_printf(c->pb, "\r\n");
3275
 
}
3276
 
 
3277
 
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3278
 
{
3279
 
    HTTPContext *rtp_c;
3280
 
 
3281
 
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3282
 
    if (!rtp_c) {
3283
 
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3284
 
        return;
3285
 
    }
3286
 
 
3287
 
    /* now everything is OK, so we can send the connection parameters */
3288
 
    rtsp_reply_header(c, RTSP_STATUS_OK);
3289
 
    /* session ID */
3290
 
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3291
 
    avio_printf(c->pb, "\r\n");
3292
 
 
3293
 
    /* abort the session */
3294
 
    close_connection(rtp_c);
3295
 
}
3296
 
 
3297
 
 
3298
 
/********************************************************************/
3299
 
/* RTP handling */
3300
 
 
3301
 
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3302
 
                                       FFStream *stream, const char *session_id,
3303
 
                                       enum RTSPLowerTransport rtp_protocol)
3304
 
{
3305
 
    HTTPContext *c = NULL;
3306
 
    const char *proto_str;
3307
 
 
3308
 
    /* XXX: should output a warning page when coming
3309
 
       close to the connection limit */
3310
 
    if (nb_connections >= nb_max_connections)
3311
 
        goto fail;
3312
 
 
3313
 
    /* add a new connection */
3314
 
    c = av_mallocz(sizeof(HTTPContext));
3315
 
    if (!c)
3316
 
        goto fail;
3317
 
 
3318
 
    c->fd = -1;
3319
 
    c->poll_entry = NULL;
3320
 
    c->from_addr = *from_addr;
3321
 
    c->buffer_size = IOBUFFER_INIT_SIZE;
3322
 
    c->buffer = av_malloc(c->buffer_size);
3323
 
    if (!c->buffer)
3324
 
        goto fail;
3325
 
    nb_connections++;
3326
 
    c->stream = stream;
3327
 
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3328
 
    c->state = HTTPSTATE_READY;
3329
 
    c->is_packetized = 1;
3330
 
    c->rtp_protocol = rtp_protocol;
3331
 
 
3332
 
    /* protocol is shown in statistics */
3333
 
    switch(c->rtp_protocol) {
3334
 
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3335
 
        proto_str = "MCAST";
3336
 
        break;
3337
 
    case RTSP_LOWER_TRANSPORT_UDP:
3338
 
        proto_str = "UDP";
3339
 
        break;
3340
 
    case RTSP_LOWER_TRANSPORT_TCP:
3341
 
        proto_str = "TCP";
3342
 
        break;
3343
 
    default:
3344
 
        proto_str = "???";
3345
 
        break;
3346
 
    }
3347
 
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3348
 
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3349
 
 
3350
 
    current_bandwidth += stream->bandwidth;
3351
 
 
3352
 
    c->next = first_http_ctx;
3353
 
    first_http_ctx = c;
3354
 
    return c;
3355
 
 
3356
 
 fail:
3357
 
    if (c) {
3358
 
        av_free(c->buffer);
3359
 
        av_free(c);
3360
 
    }
3361
 
    return NULL;
3362
 
}
3363
 
 
3364
 
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3365
 
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3366
 
   used. */
3367
 
static int rtp_new_av_stream(HTTPContext *c,
3368
 
                             int stream_index, struct sockaddr_in *dest_addr,
3369
 
                             HTTPContext *rtsp_c)
3370
 
{
3371
 
    AVFormatContext *ctx;
3372
 
    AVStream *st;
3373
 
    char *ipaddr;
3374
 
    URLContext *h = NULL;
3375
 
    uint8_t *dummy_buf;
3376
 
    int max_packet_size;
3377
 
 
3378
 
    /* now we can open the relevant output stream */
3379
 
    ctx = avformat_alloc_context();
3380
 
    if (!ctx)
3381
 
        return -1;
3382
 
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3383
 
 
3384
 
    st = av_mallocz(sizeof(AVStream));
3385
 
    if (!st)
3386
 
        goto fail;
3387
 
    ctx->nb_streams = 1;
3388
 
    ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3389
 
    if (!ctx->streams)
3390
 
      goto fail;
3391
 
    ctx->streams[0] = st;
3392
 
 
3393
 
    if (!c->stream->feed ||
3394
 
        c->stream->feed == c->stream)
3395
 
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3396
 
    else
3397
 
        memcpy(st,
3398
 
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3399
 
               sizeof(AVStream));
3400
 
    st->priv_data = NULL;
3401
 
 
3402
 
    /* build destination RTP address */
3403
 
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3404
 
 
3405
 
    switch(c->rtp_protocol) {
3406
 
    case RTSP_LOWER_TRANSPORT_UDP:
3407
 
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3408
 
        /* RTP/UDP case */
3409
 
 
3410
 
        /* XXX: also pass as parameter to function ? */
3411
 
        if (c->stream->is_multicast) {
3412
 
            int ttl;
3413
 
            ttl = c->stream->multicast_ttl;
3414
 
            if (!ttl)
3415
 
                ttl = 16;
3416
 
            snprintf(ctx->filename, sizeof(ctx->filename),
3417
 
                     "rtp://%s:%d?multicast=1&ttl=%d",
3418
 
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3419
 
        } else {
3420
 
            snprintf(ctx->filename, sizeof(ctx->filename),
3421
 
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3422
 
        }
3423
 
 
3424
 
        if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3425
 
            goto fail;
3426
 
        c->rtp_handles[stream_index] = h;
3427
 
        max_packet_size = url_get_max_packet_size(h);
3428
 
        break;
3429
 
    case RTSP_LOWER_TRANSPORT_TCP:
3430
 
        /* RTP/TCP case */
3431
 
        c->rtsp_c = rtsp_c;
3432
 
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3433
 
        break;
3434
 
    default:
3435
 
        goto fail;
3436
 
    }
3437
 
 
3438
 
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3439
 
             ipaddr, ntohs(dest_addr->sin_port),
3440
 
             c->stream->filename, stream_index, c->protocol);
3441
 
 
3442
 
    /* normally, no packets should be output here, but the packet size may be checked */
3443
 
    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3444
 
        /* XXX: close stream */
3445
 
        goto fail;
3446
 
    }
3447
 
    if (avformat_write_header(ctx, NULL) < 0) {
3448
 
    fail:
3449
 
        if (h)
3450
 
            url_close(h);
3451
 
        av_free(ctx);
3452
 
        return -1;
3453
 
    }
3454
 
    avio_close_dyn_buf(ctx->pb, &dummy_buf);
3455
 
    av_free(dummy_buf);
3456
 
 
3457
 
    c->rtp_ctx[stream_index] = ctx;
3458
 
    return 0;
3459
 
}
3460
 
 
3461
 
/********************************************************************/
3462
 
/* ffserver initialization */
3463
 
 
3464
 
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3465
 
{
3466
 
    AVStream *fst;
3467
 
 
3468
 
    fst = av_mallocz(sizeof(AVStream));
3469
 
    if (!fst)
3470
 
        return NULL;
3471
 
    if (copy) {
3472
 
        fst->codec= avcodec_alloc_context();
3473
 
        memcpy(fst->codec, codec, sizeof(AVCodecContext));
3474
 
        if (codec->extradata_size) {
3475
 
            fst->codec->extradata = av_malloc(codec->extradata_size);
3476
 
            memcpy(fst->codec->extradata, codec->extradata,
3477
 
                codec->extradata_size);
3478
 
        }
3479
 
    } else {
3480
 
        /* live streams must use the actual feed's codec since it may be
3481
 
         * updated later to carry extradata needed by the streams.
3482
 
         */
3483
 
        fst->codec = codec;
3484
 
    }
3485
 
    fst->priv_data = av_mallocz(sizeof(FeedData));
3486
 
    fst->index = stream->nb_streams;
3487
 
    av_set_pts_info(fst, 33, 1, 90000);
3488
 
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3489
 
    stream->streams[stream->nb_streams++] = fst;
3490
 
    return fst;
3491
 
}
3492
 
 
3493
 
/* return the stream number in the feed */
3494
 
static int add_av_stream(FFStream *feed, AVStream *st)
3495
 
{
3496
 
    AVStream *fst;
3497
 
    AVCodecContext *av, *av1;
3498
 
    int i;
3499
 
 
3500
 
    av = st->codec;
3501
 
    for(i=0;i<feed->nb_streams;i++) {
3502
 
        st = feed->streams[i];
3503
 
        av1 = st->codec;
3504
 
        if (av1->codec_id == av->codec_id &&
3505
 
            av1->codec_type == av->codec_type &&
3506
 
            av1->bit_rate == av->bit_rate) {
3507
 
 
3508
 
            switch(av->codec_type) {
3509
 
            case AVMEDIA_TYPE_AUDIO:
3510
 
                if (av1->channels == av->channels &&
3511
 
                    av1->sample_rate == av->sample_rate)
3512
 
                    goto found;
3513
 
                break;
3514
 
            case AVMEDIA_TYPE_VIDEO:
3515
 
                if (av1->width == av->width &&
3516
 
                    av1->height == av->height &&
3517
 
                    av1->time_base.den == av->time_base.den &&
3518
 
                    av1->time_base.num == av->time_base.num &&
3519
 
                    av1->gop_size == av->gop_size)
3520
 
                    goto found;
3521
 
                break;
3522
 
            default:
3523
 
                abort();
3524
 
            }
3525
 
        }
3526
 
    }
3527
 
 
3528
 
    fst = add_av_stream1(feed, av, 0);
3529
 
    if (!fst)
3530
 
        return -1;
3531
 
    return feed->nb_streams - 1;
3532
 
 found:
3533
 
    return i;
3534
 
}
3535
 
 
3536
 
static void remove_stream(FFStream *stream)
3537
 
{
3538
 
    FFStream **ps;
3539
 
    ps = &first_stream;
3540
 
    while (*ps != NULL) {
3541
 
        if (*ps == stream)
3542
 
            *ps = (*ps)->next;
3543
 
        else
3544
 
            ps = &(*ps)->next;
3545
 
    }
3546
 
}
3547
 
 
3548
 
/* specific mpeg4 handling : we extract the raw parameters */
3549
 
static void extract_mpeg4_header(AVFormatContext *infile)
3550
 
{
3551
 
    int mpeg4_count, i, size;
3552
 
    AVPacket pkt;
3553
 
    AVStream *st;
3554
 
    const uint8_t *p;
3555
 
 
3556
 
    mpeg4_count = 0;
3557
 
    for(i=0;i<infile->nb_streams;i++) {
3558
 
        st = infile->streams[i];
3559
 
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3560
 
            st->codec->extradata_size == 0) {
3561
 
            mpeg4_count++;
3562
 
        }
3563
 
    }
3564
 
    if (!mpeg4_count)
3565
 
        return;
3566
 
 
3567
 
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3568
 
    while (mpeg4_count > 0) {
3569
 
        if (av_read_packet(infile, &pkt) < 0)
3570
 
            break;
3571
 
        st = infile->streams[pkt.stream_index];
3572
 
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3573
 
            st->codec->extradata_size == 0) {
3574
 
            av_freep(&st->codec->extradata);
3575
 
            /* fill extradata with the header */
3576
 
            /* XXX: we make hard suppositions here ! */
3577
 
            p = pkt.data;
3578
 
            while (p < pkt.data + pkt.size - 4) {
3579
 
                /* stop when vop header is found */
3580
 
                if (p[0] == 0x00 && p[1] == 0x00 &&
3581
 
                    p[2] == 0x01 && p[3] == 0xb6) {
3582
 
                    size = p - pkt.data;
3583
 
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3584
 
                    st->codec->extradata = av_malloc(size);
3585
 
                    st->codec->extradata_size = size;
3586
 
                    memcpy(st->codec->extradata, pkt.data, size);
3587
 
                    break;
3588
 
                }
3589
 
                p++;
3590
 
            }
3591
 
            mpeg4_count--;
3592
 
        }
3593
 
        av_free_packet(&pkt);
3594
 
    }
3595
 
}
3596
 
 
3597
 
/* compute the needed AVStream for each file */
3598
 
static void build_file_streams(void)
3599
 
{
3600
 
    FFStream *stream, *stream_next;
3601
 
    int i, ret;
3602
 
 
3603
 
    /* gather all streams */
3604
 
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3605
 
        AVFormatContext *infile = NULL;
3606
 
        stream_next = stream->next;
3607
 
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3608
 
            !stream->feed) {
3609
 
            /* the stream comes from a file */
3610
 
            /* try to open the file */
3611
 
            /* open stream */
3612
 
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3613
 
                /* specific case : if transport stream output to RTP,
3614
 
                   we use a raw transport stream reader */
3615
 
                av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3616
 
            }
3617
 
 
3618
 
            http_log("Opening file '%s'\n", stream->feed_filename);
3619
 
            if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3620
 
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3621
 
                /* remove stream (no need to spend more time on it) */
3622
 
            fail:
3623
 
                remove_stream(stream);
3624
 
            } else {
3625
 
                /* find all the AVStreams inside and reference them in
3626
 
                   'stream' */
3627
 
                if (av_find_stream_info(infile) < 0) {
3628
 
                    http_log("Could not find codec parameters from '%s'\n",
3629
 
                             stream->feed_filename);
3630
 
                    av_close_input_file(infile);
3631
 
                    goto fail;
3632
 
                }
3633
 
                extract_mpeg4_header(infile);
3634
 
 
3635
 
                for(i=0;i<infile->nb_streams;i++)
3636
 
                    add_av_stream1(stream, infile->streams[i]->codec, 1);
3637
 
 
3638
 
                av_close_input_file(infile);
3639
 
            }
3640
 
        }
3641
 
    }
3642
 
}
3643
 
 
3644
 
/* compute the needed AVStream for each feed */
3645
 
static void build_feed_streams(void)
3646
 
{
3647
 
    FFStream *stream, *feed;
3648
 
    int i;
3649
 
 
3650
 
    /* gather all streams */
3651
 
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3652
 
        feed = stream->feed;
3653
 
        if (feed) {
3654
 
            if (!stream->is_feed) {
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
 
    /* gather all streams */
3663
 
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3664
 
        feed = stream->feed;
3665
 
        if (feed) {
3666
 
            if (stream->is_feed) {
3667
 
                for(i=0;i<stream->nb_streams;i++)
3668
 
                    stream->feed_streams[i] = i;
3669
 
            }
3670
 
        }
3671
 
    }
3672
 
 
3673
 
    /* create feed files if needed */
3674
 
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3675
 
        int fd;
3676
 
 
3677
 
        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3678
 
            /* See if it matches */
3679
 
            AVFormatContext *s = NULL;
3680
 
            int matches = 0;
3681
 
 
3682
 
            if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3683
 
                /* Now see if it matches */
3684
 
                if (s->nb_streams == feed->nb_streams) {
3685
 
                    matches = 1;
3686
 
                    for(i=0;i<s->nb_streams;i++) {
3687
 
                        AVStream *sf, *ss;
3688
 
                        sf = feed->streams[i];
3689
 
                        ss = s->streams[i];
3690
 
 
3691
 
                        if (sf->index != ss->index ||
3692
 
                            sf->id != ss->id) {
3693
 
                            http_log("Index & Id do not match for stream %d (%s)\n",
3694
 
                                   i, feed->feed_filename);
3695
 
                            matches = 0;
3696
 
                        } else {
3697
 
                            AVCodecContext *ccf, *ccs;
3698
 
 
3699
 
                            ccf = sf->codec;
3700
 
                            ccs = ss->codec;
3701
 
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3702
 
 
3703
 
                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3704
 
                                http_log("Codecs do not match for stream %d\n", i);
3705
 
                                matches = 0;
3706
 
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3707
 
                                http_log("Codec bitrates do not match for stream %d\n", i);
3708
 
                                matches = 0;
3709
 
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3710
 
                                if (CHECK_CODEC(time_base.den) ||
3711
 
                                    CHECK_CODEC(time_base.num) ||
3712
 
                                    CHECK_CODEC(width) ||
3713
 
                                    CHECK_CODEC(height)) {
3714
 
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3715
 
                                    matches = 0;
3716
 
                                }
3717
 
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3718
 
                                if (CHECK_CODEC(sample_rate) ||
3719
 
                                    CHECK_CODEC(channels) ||
3720
 
                                    CHECK_CODEC(frame_size)) {
3721
 
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3722
 
                                    matches = 0;
3723
 
                                }
3724
 
                            } else {
3725
 
                                http_log("Unknown codec type\n");
3726
 
                                matches = 0;
3727
 
                            }
3728
 
                        }
3729
 
                        if (!matches)
3730
 
                            break;
3731
 
                    }
3732
 
                } else
3733
 
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3734
 
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3735
 
 
3736
 
                av_close_input_file(s);
3737
 
            } else
3738
 
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3739
 
                        feed->feed_filename);
3740
 
 
3741
 
            if (!matches) {
3742
 
                if (feed->readonly) {
3743
 
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3744
 
                        feed->feed_filename);
3745
 
                    exit(1);
3746
 
                }
3747
 
                unlink(feed->feed_filename);
3748
 
            }
3749
 
        }
3750
 
        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3751
 
            AVFormatContext s1 = {0}, *s = &s1;
3752
 
 
3753
 
            if (feed->readonly) {
3754
 
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3755
 
                    feed->feed_filename);
3756
 
                exit(1);
3757
 
            }
3758
 
 
3759
 
            /* only write the header of the ffm file */
3760
 
            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3761
 
                http_log("Could not open output feed file '%s'\n",
3762
 
                         feed->feed_filename);
3763
 
                exit(1);
3764
 
            }
3765
 
            s->oformat = feed->fmt;
3766
 
            s->nb_streams = feed->nb_streams;
3767
 
            s->streams = feed->streams;
3768
 
            if (avformat_write_header(s, NULL) < 0) {
3769
 
                http_log("Container doesn't supports the required parameters\n");
3770
 
                exit(1);
3771
 
            }
3772
 
            /* XXX: need better api */
3773
 
            av_freep(&s->priv_data);
3774
 
            avio_close(s->pb);
3775
 
        }
3776
 
        /* get feed size and write index */
3777
 
        fd = open(feed->feed_filename, O_RDONLY);
3778
 
        if (fd < 0) {
3779
 
            http_log("Could not open output feed file '%s'\n",
3780
 
                    feed->feed_filename);
3781
 
            exit(1);
3782
 
        }
3783
 
 
3784
 
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3785
 
        feed->feed_size = lseek(fd, 0, SEEK_END);
3786
 
        /* ensure that we do not wrap before the end of file */
3787
 
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3788
 
            feed->feed_max_size = feed->feed_size;
3789
 
 
3790
 
        close(fd);
3791
 
    }
3792
 
}
3793
 
 
3794
 
/* compute the bandwidth used by each stream */
3795
 
static void compute_bandwidth(void)
3796
 
{
3797
 
    unsigned bandwidth;
3798
 
    int i;
3799
 
    FFStream *stream;
3800
 
 
3801
 
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3802
 
        bandwidth = 0;
3803
 
        for(i=0;i<stream->nb_streams;i++) {
3804
 
            AVStream *st = stream->streams[i];
3805
 
            switch(st->codec->codec_type) {
3806
 
            case AVMEDIA_TYPE_AUDIO:
3807
 
            case AVMEDIA_TYPE_VIDEO:
3808
 
                bandwidth += st->codec->bit_rate;
3809
 
                break;
3810
 
            default:
3811
 
                break;
3812
 
            }
3813
 
        }
3814
 
        stream->bandwidth = (bandwidth + 999) / 1000;
3815
 
    }
3816
 
}
3817
 
 
3818
 
/* add a codec and set the default parameters */
3819
 
static void add_codec(FFStream *stream, AVCodecContext *av)
3820
 
{
3821
 
    AVStream *st;
3822
 
 
3823
 
    /* compute default parameters */
3824
 
    switch(av->codec_type) {
3825
 
    case AVMEDIA_TYPE_AUDIO:
3826
 
        if (av->bit_rate == 0)
3827
 
            av->bit_rate = 64000;
3828
 
        if (av->sample_rate == 0)
3829
 
            av->sample_rate = 22050;
3830
 
        if (av->channels == 0)
3831
 
            av->channels = 1;
3832
 
        break;
3833
 
    case AVMEDIA_TYPE_VIDEO:
3834
 
        if (av->bit_rate == 0)
3835
 
            av->bit_rate = 64000;
3836
 
        if (av->time_base.num == 0){
3837
 
            av->time_base.den = 5;
3838
 
            av->time_base.num = 1;
3839
 
        }
3840
 
        if (av->width == 0 || av->height == 0) {
3841
 
            av->width = 160;
3842
 
            av->height = 128;
3843
 
        }
3844
 
        /* Bitrate tolerance is less for streaming */
3845
 
        if (av->bit_rate_tolerance == 0)
3846
 
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3847
 
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3848
 
        if (av->qmin == 0)
3849
 
            av->qmin = 3;
3850
 
        if (av->qmax == 0)
3851
 
            av->qmax = 31;
3852
 
        if (av->max_qdiff == 0)
3853
 
            av->max_qdiff = 3;
3854
 
        av->qcompress = 0.5;
3855
 
        av->qblur = 0.5;
3856
 
 
3857
 
        if (!av->nsse_weight)
3858
 
            av->nsse_weight = 8;
3859
 
 
3860
 
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3861
 
        if (!av->me_method)
3862
 
            av->me_method = ME_EPZS;
3863
 
        av->rc_buffer_aggressivity = 1.0;
3864
 
 
3865
 
        if (!av->rc_eq)
3866
 
            av->rc_eq = "tex^qComp";
3867
 
        if (!av->i_quant_factor)
3868
 
            av->i_quant_factor = -0.8;
3869
 
        if (!av->b_quant_factor)
3870
 
            av->b_quant_factor = 1.25;
3871
 
        if (!av->b_quant_offset)
3872
 
            av->b_quant_offset = 1.25;
3873
 
        if (!av->rc_max_rate)
3874
 
            av->rc_max_rate = av->bit_rate * 2;
3875
 
 
3876
 
        if (av->rc_max_rate && !av->rc_buffer_size) {
3877
 
            av->rc_buffer_size = av->rc_max_rate;
3878
 
        }
3879
 
 
3880
 
 
3881
 
        break;
3882
 
    default:
3883
 
        abort();
3884
 
    }
3885
 
 
3886
 
    st = av_mallocz(sizeof(AVStream));
3887
 
    if (!st)
3888
 
        return;
3889
 
    st->codec = avcodec_alloc_context();
3890
 
    stream->streams[stream->nb_streams++] = st;
3891
 
    memcpy(st->codec, av, sizeof(AVCodecContext));
3892
 
}
3893
 
 
3894
 
static enum CodecID opt_audio_codec(const char *arg)
3895
 
{
3896
 
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3897
 
 
3898
 
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3899
 
        return CODEC_ID_NONE;
3900
 
 
3901
 
    return p->id;
3902
 
}
3903
 
 
3904
 
static enum CodecID opt_video_codec(const char *arg)
3905
 
{
3906
 
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3907
 
 
3908
 
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3909
 
        return CODEC_ID_NONE;
3910
 
 
3911
 
    return p->id;
3912
 
}
3913
 
 
3914
 
/* simplistic plugin support */
3915
 
 
3916
 
#if HAVE_DLOPEN
3917
 
static void load_module(const char *filename)
3918
 
{
3919
 
    void *dll;
3920
 
    void (*init_func)(void);
3921
 
    dll = dlopen(filename, RTLD_NOW);
3922
 
    if (!dll) {
3923
 
        fprintf(stderr, "Could not load module '%s' - %s\n",
3924
 
                filename, dlerror());
3925
 
        return;
3926
 
    }
3927
 
 
3928
 
    init_func = dlsym(dll, "ffserver_module_init");
3929
 
    if (!init_func) {
3930
 
        fprintf(stderr,
3931
 
                "%s: init function 'ffserver_module_init()' not found\n",
3932
 
                filename);
3933
 
        dlclose(dll);
3934
 
    }
3935
 
 
3936
 
    init_func();
3937
 
}
3938
 
#endif
3939
 
 
3940
 
static int ffserver_opt_default(const char *opt, const char *arg,
3941
 
                       AVCodecContext *avctx, int type)
3942
 
{
3943
 
    int ret = 0;
3944
 
    const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3945
 
    if(o)
3946
 
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3947
 
    return ret;
3948
 
}
3949
 
 
3950
 
static int ffserver_opt_preset(const char *arg,
3951
 
                       AVCodecContext *avctx, int type,
3952
 
                       enum CodecID *audio_id, enum CodecID *video_id)
3953
 
{
3954
 
    FILE *f=NULL;
3955
 
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3956
 
    int ret = 0;
3957
 
    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3958
 
 
3959
 
    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3960
 
                              codec ? codec->name : NULL))) {
3961
 
        fprintf(stderr, "File for preset '%s' not found\n", arg);
3962
 
        return 1;
3963
 
    }
3964
 
 
3965
 
    while(!feof(f)){
3966
 
        int e= fscanf(f, "%999[^\n]\n", line) - 1;
3967
 
        if(line[0] == '#' && !e)
3968
 
            continue;
3969
 
        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3970
 
        if(e){
3971
 
            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3972
 
            ret = 1;
3973
 
            break;
3974
 
        }
3975
 
        if(!strcmp(tmp, "acodec")){
3976
 
            *audio_id = opt_audio_codec(tmp2);
3977
 
        }else if(!strcmp(tmp, "vcodec")){
3978
 
            *video_id = opt_video_codec(tmp2);
3979
 
        }else if(!strcmp(tmp, "scodec")){
3980
 
            /* opt_subtitle_codec(tmp2); */
3981
 
        }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3982
 
            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3983
 
            ret = 1;
3984
 
            break;
3985
 
        }
3986
 
    }
3987
 
 
3988
 
    fclose(f);
3989
 
 
3990
 
    return ret;
3991
 
}
3992
 
 
3993
 
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3994
 
                                             const char *mime_type)
3995
 
{
3996
 
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3997
 
 
3998
 
    if (fmt) {
3999
 
        AVOutputFormat *stream_fmt;
4000
 
        char stream_format_name[64];
4001
 
 
4002
 
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4003
 
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4004
 
 
4005
 
        if (stream_fmt)
4006
 
            fmt = stream_fmt;
4007
 
    }
4008
 
 
4009
 
    return fmt;
4010
 
}
4011
 
 
4012
 
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4013
 
{
4014
 
    va_list vl;
4015
 
    va_start(vl, fmt);
4016
 
    fprintf(stderr, "%s:%d: ", filename, line_num);
4017
 
    vfprintf(stderr, fmt, vl);
4018
 
    va_end(vl);
4019
 
 
4020
 
    (*errors)++;
4021
 
}
4022
 
 
4023
 
static int parse_ffconfig(const char *filename)
4024
 
{
4025
 
    FILE *f;
4026
 
    char line[1024];
4027
 
    char cmd[64];
4028
 
    char arg[1024];
4029
 
    const char *p;
4030
 
    int val, errors, line_num;
4031
 
    FFStream **last_stream, *stream, *redirect;
4032
 
    FFStream **last_feed, *feed, *s;
4033
 
    AVCodecContext audio_enc, video_enc;
4034
 
    enum CodecID audio_id, video_id;
4035
 
 
4036
 
    f = fopen(filename, "r");
4037
 
    if (!f) {
4038
 
        perror(filename);
4039
 
        return -1;
4040
 
    }
4041
 
 
4042
 
    errors = 0;
4043
 
    line_num = 0;
4044
 
    first_stream = NULL;
4045
 
    last_stream = &first_stream;
4046
 
    first_feed = NULL;
4047
 
    last_feed = &first_feed;
4048
 
    stream = NULL;
4049
 
    feed = NULL;
4050
 
    redirect = NULL;
4051
 
    audio_id = CODEC_ID_NONE;
4052
 
    video_id = CODEC_ID_NONE;
4053
 
 
4054
 
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4055
 
    for(;;) {
4056
 
        if (fgets(line, sizeof(line), f) == NULL)
4057
 
            break;
4058
 
        line_num++;
4059
 
        p = line;
4060
 
        while (isspace(*p))
4061
 
            p++;
4062
 
        if (*p == '\0' || *p == '#')
4063
 
            continue;
4064
 
 
4065
 
        get_arg(cmd, sizeof(cmd), &p);
4066
 
 
4067
 
        if (!strcasecmp(cmd, "Port")) {
4068
 
            get_arg(arg, sizeof(arg), &p);
4069
 
            val = atoi(arg);
4070
 
            if (val < 1 || val > 65536) {
4071
 
                ERROR("Invalid_port: %s\n", arg);
4072
 
            }
4073
 
            my_http_addr.sin_port = htons(val);
4074
 
        } else if (!strcasecmp(cmd, "BindAddress")) {
4075
 
            get_arg(arg, sizeof(arg), &p);
4076
 
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4077
 
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4078
 
            }
4079
 
        } else if (!strcasecmp(cmd, "NoDaemon")) {
4080
 
            ffserver_daemon = 0;
4081
 
        } else if (!strcasecmp(cmd, "RTSPPort")) {
4082
 
            get_arg(arg, sizeof(arg), &p);
4083
 
            val = atoi(arg);
4084
 
            if (val < 1 || val > 65536) {
4085
 
                ERROR("%s:%d: Invalid port: %s\n", arg);
4086
 
            }
4087
 
            my_rtsp_addr.sin_port = htons(atoi(arg));
4088
 
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4089
 
            get_arg(arg, sizeof(arg), &p);
4090
 
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4091
 
                ERROR("Invalid host/IP address: %s\n", arg);
4092
 
            }
4093
 
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4094
 
            get_arg(arg, sizeof(arg), &p);
4095
 
            val = atoi(arg);
4096
 
            if (val < 1 || val > 65536) {
4097
 
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4098
 
            }
4099
 
            nb_max_http_connections = val;
4100
 
        } else if (!strcasecmp(cmd, "MaxClients")) {
4101
 
            get_arg(arg, sizeof(arg), &p);
4102
 
            val = atoi(arg);
4103
 
            if (val < 1 || val > nb_max_http_connections) {
4104
 
                ERROR("Invalid MaxClients: %s\n", arg);
4105
 
            } else {
4106
 
                nb_max_connections = val;
4107
 
            }
4108
 
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4109
 
            int64_t llval;
4110
 
            get_arg(arg, sizeof(arg), &p);
4111
 
            llval = atoll(arg);
4112
 
            if (llval < 10 || llval > 10000000) {
4113
 
                ERROR("Invalid MaxBandwidth: %s\n", arg);
4114
 
            } else
4115
 
                max_bandwidth = llval;
4116
 
        } else if (!strcasecmp(cmd, "CustomLog")) {
4117
 
            if (!ffserver_debug)
4118
 
                get_arg(logfilename, sizeof(logfilename), &p);
4119
 
        } else if (!strcasecmp(cmd, "<Feed")) {
4120
 
            /*********************************************/
4121
 
            /* Feed related options */
4122
 
            char *q;
4123
 
            if (stream || feed) {
4124
 
                ERROR("Already in a tag\n");
4125
 
            } else {
4126
 
                feed = av_mallocz(sizeof(FFStream));
4127
 
                get_arg(feed->filename, sizeof(feed->filename), &p);
4128
 
                q = strrchr(feed->filename, '>');
4129
 
                if (*q)
4130
 
                    *q = '\0';
4131
 
 
4132
 
                for (s = first_feed; s; s = s->next) {
4133
 
                    if (!strcmp(feed->filename, s->filename)) {
4134
 
                        ERROR("Feed '%s' already registered\n", s->filename);
4135
 
                    }
4136
 
                }
4137
 
 
4138
 
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4139
 
                /* defaut feed file */
4140
 
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4141
 
                         "/tmp/%s.ffm", feed->filename);
4142
 
                feed->feed_max_size = 5 * 1024 * 1024;
4143
 
                feed->is_feed = 1;
4144
 
                feed->feed = feed; /* self feeding :-) */
4145
 
 
4146
 
                /* add in stream list */
4147
 
                *last_stream = feed;
4148
 
                last_stream = &feed->next;
4149
 
                /* add in feed list */
4150
 
                *last_feed = feed;
4151
 
                last_feed = &feed->next_feed;
4152
 
            }
4153
 
        } else if (!strcasecmp(cmd, "Launch")) {
4154
 
            if (feed) {
4155
 
                int i;
4156
 
 
4157
 
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4158
 
 
4159
 
                for (i = 0; i < 62; i++) {
4160
 
                    get_arg(arg, sizeof(arg), &p);
4161
 
                    if (!arg[0])
4162
 
                        break;
4163
 
 
4164
 
                    feed->child_argv[i] = av_strdup(arg);
4165
 
                }
4166
 
 
4167
 
                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4168
 
 
4169
 
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4170
 
                    "http://%s:%d/%s",
4171
 
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4172
 
                    inet_ntoa(my_http_addr.sin_addr),
4173
 
                    ntohs(my_http_addr.sin_port), feed->filename);
4174
 
            }
4175
 
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4176
 
            if (feed) {
4177
 
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4178
 
                feed->readonly = 1;
4179
 
            } else if (stream) {
4180
 
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4181
 
            }
4182
 
        } else if (!strcasecmp(cmd, "File")) {
4183
 
            if (feed) {
4184
 
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4185
 
            } else if (stream)
4186
 
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4187
 
        } else if (!strcasecmp(cmd, "Truncate")) {
4188
 
            if (feed) {
4189
 
                get_arg(arg, sizeof(arg), &p);
4190
 
                feed->truncate = strtod(arg, NULL);
4191
 
            }
4192
 
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4193
 
            if (feed) {
4194
 
                char *p1;
4195
 
                double fsize;
4196
 
 
4197
 
                get_arg(arg, sizeof(arg), &p);
4198
 
                p1 = arg;
4199
 
                fsize = strtod(p1, &p1);
4200
 
                switch(toupper(*p1)) {
4201
 
                case 'K':
4202
 
                    fsize *= 1024;
4203
 
                    break;
4204
 
                case 'M':
4205
 
                    fsize *= 1024 * 1024;
4206
 
                    break;
4207
 
                case 'G':
4208
 
                    fsize *= 1024 * 1024 * 1024;
4209
 
                    break;
4210
 
                }
4211
 
                feed->feed_max_size = (int64_t)fsize;
4212
 
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4213
 
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4214
 
                }
4215
 
            }
4216
 
        } else if (!strcasecmp(cmd, "</Feed>")) {
4217
 
            if (!feed) {
4218
 
                ERROR("No corresponding <Feed> for </Feed>\n");
4219
 
            }
4220
 
            feed = NULL;
4221
 
        } else if (!strcasecmp(cmd, "<Stream")) {
4222
 
            /*********************************************/
4223
 
            /* Stream related options */
4224
 
            char *q;
4225
 
            if (stream || feed) {
4226
 
                ERROR("Already in a tag\n");
4227
 
            } else {
4228
 
                FFStream *s;
4229
 
                stream = av_mallocz(sizeof(FFStream));
4230
 
                get_arg(stream->filename, sizeof(stream->filename), &p);
4231
 
                q = strrchr(stream->filename, '>');
4232
 
                if (*q)
4233
 
                    *q = '\0';
4234
 
 
4235
 
                for (s = first_stream; s; s = s->next) {
4236
 
                    if (!strcmp(stream->filename, s->filename)) {
4237
 
                        ERROR("Stream '%s' already registered\n", s->filename);
4238
 
                    }
4239
 
                }
4240
 
 
4241
 
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4242
 
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4243
 
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4244
 
                audio_id = CODEC_ID_NONE;
4245
 
                video_id = CODEC_ID_NONE;
4246
 
                if (stream->fmt) {
4247
 
                    audio_id = stream->fmt->audio_codec;
4248
 
                    video_id = stream->fmt->video_codec;
4249
 
                }
4250
 
 
4251
 
                *last_stream = stream;
4252
 
                last_stream = &stream->next;
4253
 
            }
4254
 
        } else if (!strcasecmp(cmd, "Feed")) {
4255
 
            get_arg(arg, sizeof(arg), &p);
4256
 
            if (stream) {
4257
 
                FFStream *sfeed;
4258
 
 
4259
 
                sfeed = first_feed;
4260
 
                while (sfeed != NULL) {
4261
 
                    if (!strcmp(sfeed->filename, arg))
4262
 
                        break;
4263
 
                    sfeed = sfeed->next_feed;
4264
 
                }
4265
 
                if (!sfeed)
4266
 
                    ERROR("feed '%s' not defined\n", arg);
4267
 
                else
4268
 
                    stream->feed = sfeed;
4269
 
            }
4270
 
        } else if (!strcasecmp(cmd, "Format")) {
4271
 
            get_arg(arg, sizeof(arg), &p);
4272
 
            if (stream) {
4273
 
                if (!strcmp(arg, "status")) {
4274
 
                    stream->stream_type = STREAM_TYPE_STATUS;
4275
 
                    stream->fmt = NULL;
4276
 
                } else {
4277
 
                    stream->stream_type = STREAM_TYPE_LIVE;
4278
 
                    /* jpeg cannot be used here, so use single frame jpeg */
4279
 
                    if (!strcmp(arg, "jpeg"))
4280
 
                        strcpy(arg, "mjpeg");
4281
 
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4282
 
                    if (!stream->fmt) {
4283
 
                        ERROR("Unknown Format: %s\n", arg);
4284
 
                    }
4285
 
                }
4286
 
                if (stream->fmt) {
4287
 
                    audio_id = stream->fmt->audio_codec;
4288
 
                    video_id = stream->fmt->video_codec;
4289
 
                }
4290
 
            }
4291
 
        } else if (!strcasecmp(cmd, "InputFormat")) {
4292
 
            get_arg(arg, sizeof(arg), &p);
4293
 
            if (stream) {
4294
 
                stream->ifmt = av_find_input_format(arg);
4295
 
                if (!stream->ifmt) {
4296
 
                    ERROR("Unknown input format: %s\n", arg);
4297
 
                }
4298
 
            }
4299
 
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4300
 
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4301
 
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4302
 
            } else {
4303
 
                ERROR("FaviconURL only permitted for status streams\n");
4304
 
            }
4305
 
        } else if (!strcasecmp(cmd, "Author")) {
4306
 
            if (stream)
4307
 
                get_arg(stream->author, sizeof(stream->author), &p);
4308
 
        } else if (!strcasecmp(cmd, "Comment")) {
4309
 
            if (stream)
4310
 
                get_arg(stream->comment, sizeof(stream->comment), &p);
4311
 
        } else if (!strcasecmp(cmd, "Copyright")) {
4312
 
            if (stream)
4313
 
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4314
 
        } else if (!strcasecmp(cmd, "Title")) {
4315
 
            if (stream)
4316
 
                get_arg(stream->title, sizeof(stream->title), &p);
4317
 
        } else if (!strcasecmp(cmd, "Preroll")) {
4318
 
            get_arg(arg, sizeof(arg), &p);
4319
 
            if (stream)
4320
 
                stream->prebuffer = atof(arg) * 1000;
4321
 
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4322
 
            if (stream)
4323
 
                stream->send_on_key = 1;
4324
 
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4325
 
            get_arg(arg, sizeof(arg), &p);
4326
 
            audio_id = opt_audio_codec(arg);
4327
 
            if (audio_id == CODEC_ID_NONE) {
4328
 
                ERROR("Unknown AudioCodec: %s\n", arg);
4329
 
            }
4330
 
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4331
 
            get_arg(arg, sizeof(arg), &p);
4332
 
            video_id = opt_video_codec(arg);
4333
 
            if (video_id == CODEC_ID_NONE) {
4334
 
                ERROR("Unknown VideoCodec: %s\n", arg);
4335
 
            }
4336
 
        } else if (!strcasecmp(cmd, "MaxTime")) {
4337
 
            get_arg(arg, sizeof(arg), &p);
4338
 
            if (stream)
4339
 
                stream->max_time = atof(arg) * 1000;
4340
 
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4341
 
            get_arg(arg, sizeof(arg), &p);
4342
 
            if (stream)
4343
 
                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4344
 
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4345
 
            get_arg(arg, sizeof(arg), &p);
4346
 
            if (stream)
4347
 
                audio_enc.channels = atoi(arg);
4348
 
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4349
 
            get_arg(arg, sizeof(arg), &p);
4350
 
            if (stream)
4351
 
                audio_enc.sample_rate = atoi(arg);
4352
 
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4353
 
            get_arg(arg, sizeof(arg), &p);
4354
 
            if (stream) {
4355
 
//                audio_enc.quality = atof(arg) * 1000;
4356
 
            }
4357
 
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4358
 
            if (stream) {
4359
 
                int minrate, maxrate;
4360
 
 
4361
 
                get_arg(arg, sizeof(arg), &p);
4362
 
 
4363
 
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4364
 
                    video_enc.rc_min_rate = minrate * 1000;
4365
 
                    video_enc.rc_max_rate = maxrate * 1000;
4366
 
                } else {
4367
 
                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4368
 
                }
4369
 
            }
4370
 
        } else if (!strcasecmp(cmd, "Debug")) {
4371
 
            if (stream) {
4372
 
                get_arg(arg, sizeof(arg), &p);
4373
 
                video_enc.debug = strtol(arg,0,0);
4374
 
            }
4375
 
        } else if (!strcasecmp(cmd, "Strict")) {
4376
 
            if (stream) {
4377
 
                get_arg(arg, sizeof(arg), &p);
4378
 
                video_enc.strict_std_compliance = atoi(arg);
4379
 
            }
4380
 
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4381
 
            if (stream) {
4382
 
                get_arg(arg, sizeof(arg), &p);
4383
 
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4384
 
            }
4385
 
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4386
 
            if (stream) {
4387
 
                get_arg(arg, sizeof(arg), &p);
4388
 
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4389
 
            }
4390
 
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4391
 
            get_arg(arg, sizeof(arg), &p);
4392
 
            if (stream) {
4393
 
                video_enc.bit_rate = atoi(arg) * 1000;
4394
 
            }
4395
 
        } else if (!strcasecmp(cmd, "VideoSize")) {
4396
 
            get_arg(arg, sizeof(arg), &p);
4397
 
            if (stream) {
4398
 
                av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4399
 
                if ((video_enc.width % 16) != 0 ||
4400
 
                    (video_enc.height % 16) != 0) {
4401
 
                    ERROR("Image size must be a multiple of 16\n");
4402
 
                }
4403
 
            }
4404
 
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4405
 
            get_arg(arg, sizeof(arg), &p);
4406
 
            if (stream) {
4407
 
                AVRational frame_rate;
4408
 
                if (av_parse_video_rate(&frame_rate, arg) < 0) {
4409
 
                    ERROR("Incorrect frame rate: %s\n", arg);
4410
 
                } else {
4411
 
                    video_enc.time_base.num = frame_rate.den;
4412
 
                    video_enc.time_base.den = frame_rate.num;
4413
 
                }
4414
 
            }
4415
 
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4416
 
            get_arg(arg, sizeof(arg), &p);
4417
 
            if (stream)
4418
 
                video_enc.gop_size = atoi(arg);
4419
 
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4420
 
            if (stream)
4421
 
                video_enc.gop_size = 1;
4422
 
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4423
 
            if (stream)
4424
 
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4425
 
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4426
 
            if (stream) {
4427
 
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4428
 
                video_enc.flags |= CODEC_FLAG_4MV;
4429
 
            }
4430
 
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4431
 
                   !strcasecmp(cmd, "AVOptionAudio")) {
4432
 
            char arg2[1024];
4433
 
            AVCodecContext *avctx;
4434
 
            int type;
4435
 
            get_arg(arg, sizeof(arg), &p);
4436
 
            get_arg(arg2, sizeof(arg2), &p);
4437
 
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4438
 
                avctx = &video_enc;
4439
 
                type = AV_OPT_FLAG_VIDEO_PARAM;
4440
 
            } else {
4441
 
                avctx = &audio_enc;
4442
 
                type = AV_OPT_FLAG_AUDIO_PARAM;
4443
 
            }
4444
 
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4445
 
                ERROR("AVOption error: %s %s\n", arg, arg2);
4446
 
            }
4447
 
        } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4448
 
                   !strcasecmp(cmd, "AVPresetAudio")) {
4449
 
            AVCodecContext *avctx;
4450
 
            int type;
4451
 
            get_arg(arg, sizeof(arg), &p);
4452
 
            if (!strcasecmp(cmd, "AVPresetVideo")) {
4453
 
                avctx = &video_enc;
4454
 
                video_enc.codec_id = video_id;
4455
 
                type = AV_OPT_FLAG_VIDEO_PARAM;
4456
 
            } else {
4457
 
                avctx = &audio_enc;
4458
 
                audio_enc.codec_id = audio_id;
4459
 
                type = AV_OPT_FLAG_AUDIO_PARAM;
4460
 
            }
4461
 
            if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4462
 
                ERROR("AVPreset error: %s\n", arg);
4463
 
            }
4464
 
        } else if (!strcasecmp(cmd, "VideoTag")) {
4465
 
            get_arg(arg, sizeof(arg), &p);
4466
 
            if ((strlen(arg) == 4) && stream)
4467
 
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4468
 
        } else if (!strcasecmp(cmd, "BitExact")) {
4469
 
            if (stream)
4470
 
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4471
 
        } else if (!strcasecmp(cmd, "DctFastint")) {
4472
 
            if (stream)
4473
 
                video_enc.dct_algo  = FF_DCT_FASTINT;
4474
 
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4475
 
            if (stream)
4476
 
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4477
 
        } else if (!strcasecmp(cmd, "Qscale")) {
4478
 
            get_arg(arg, sizeof(arg), &p);
4479
 
            if (stream) {
4480
 
                video_enc.flags |= CODEC_FLAG_QSCALE;
4481
 
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4482
 
            }
4483
 
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4484
 
            get_arg(arg, sizeof(arg), &p);
4485
 
            if (stream) {
4486
 
                video_enc.max_qdiff = atoi(arg);
4487
 
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4488
 
                    ERROR("VideoQDiff out of range\n");
4489
 
                }
4490
 
            }
4491
 
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4492
 
            get_arg(arg, sizeof(arg), &p);
4493
 
            if (stream) {
4494
 
                video_enc.qmax = atoi(arg);
4495
 
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4496
 
                    ERROR("VideoQMax out of range\n");
4497
 
                }
4498
 
            }
4499
 
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4500
 
            get_arg(arg, sizeof(arg), &p);
4501
 
            if (stream) {
4502
 
                video_enc.qmin = atoi(arg);
4503
 
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4504
 
                    ERROR("VideoQMin out of range\n");
4505
 
                }
4506
 
            }
4507
 
        } else if (!strcasecmp(cmd, "LumaElim")) {
4508
 
            get_arg(arg, sizeof(arg), &p);
4509
 
            if (stream)
4510
 
                video_enc.luma_elim_threshold = atoi(arg);
4511
 
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4512
 
            get_arg(arg, sizeof(arg), &p);
4513
 
            if (stream)
4514
 
                video_enc.chroma_elim_threshold = atoi(arg);
4515
 
        } else if (!strcasecmp(cmd, "LumiMask")) {
4516
 
            get_arg(arg, sizeof(arg), &p);
4517
 
            if (stream)
4518
 
                video_enc.lumi_masking = atof(arg);
4519
 
        } else if (!strcasecmp(cmd, "DarkMask")) {
4520
 
            get_arg(arg, sizeof(arg), &p);
4521
 
            if (stream)
4522
 
                video_enc.dark_masking = atof(arg);
4523
 
        } else if (!strcasecmp(cmd, "NoVideo")) {
4524
 
            video_id = CODEC_ID_NONE;
4525
 
        } else if (!strcasecmp(cmd, "NoAudio")) {
4526
 
            audio_id = CODEC_ID_NONE;
4527
 
        } else if (!strcasecmp(cmd, "ACL")) {
4528
 
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4529
 
        } else if (!strcasecmp(cmd, "DynamicACL")) {
4530
 
            if (stream) {
4531
 
                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4532
 
            }
4533
 
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4534
 
            get_arg(arg, sizeof(arg), &p);
4535
 
            if (stream) {
4536
 
                av_freep(&stream->rtsp_option);
4537
 
                stream->rtsp_option = av_strdup(arg);
4538
 
            }
4539
 
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4540
 
            get_arg(arg, sizeof(arg), &p);
4541
 
            if (stream) {
4542
 
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4543
 
                    ERROR("Invalid host/IP address: %s\n", arg);
4544
 
                }
4545
 
                stream->is_multicast = 1;
4546
 
                stream->loop = 1; /* default is looping */
4547
 
            }
4548
 
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4549
 
            get_arg(arg, sizeof(arg), &p);
4550
 
            if (stream)
4551
 
                stream->multicast_port = atoi(arg);
4552
 
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4553
 
            get_arg(arg, sizeof(arg), &p);
4554
 
            if (stream)
4555
 
                stream->multicast_ttl = atoi(arg);
4556
 
        } else if (!strcasecmp(cmd, "NoLoop")) {
4557
 
            if (stream)
4558
 
                stream->loop = 0;
4559
 
        } else if (!strcasecmp(cmd, "</Stream>")) {
4560
 
            if (!stream) {
4561
 
                ERROR("No corresponding <Stream> for </Stream>\n");
4562
 
            } else {
4563
 
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4564
 
                    if (audio_id != CODEC_ID_NONE) {
4565
 
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4566
 
                        audio_enc.codec_id = audio_id;
4567
 
                        add_codec(stream, &audio_enc);
4568
 
                    }
4569
 
                    if (video_id != CODEC_ID_NONE) {
4570
 
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4571
 
                        video_enc.codec_id = video_id;
4572
 
                        add_codec(stream, &video_enc);
4573
 
                    }
4574
 
                }
4575
 
                stream = NULL;
4576
 
            }
4577
 
        } else if (!strcasecmp(cmd, "<Redirect")) {
4578
 
            /*********************************************/
4579
 
            char *q;
4580
 
            if (stream || feed || redirect) {
4581
 
                ERROR("Already in a tag\n");
4582
 
            } else {
4583
 
                redirect = av_mallocz(sizeof(FFStream));
4584
 
                *last_stream = redirect;
4585
 
                last_stream = &redirect->next;
4586
 
 
4587
 
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4588
 
                q = strrchr(redirect->filename, '>');
4589
 
                if (*q)
4590
 
                    *q = '\0';
4591
 
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4592
 
            }
4593
 
        } else if (!strcasecmp(cmd, "URL")) {
4594
 
            if (redirect)
4595
 
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4596
 
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4597
 
            if (!redirect) {
4598
 
                ERROR("No corresponding <Redirect> for </Redirect>\n");
4599
 
            } else {
4600
 
                if (!redirect->feed_filename[0]) {
4601
 
                    ERROR("No URL found for <Redirect>\n");
4602
 
                }
4603
 
                redirect = NULL;
4604
 
            }
4605
 
        } else if (!strcasecmp(cmd, "LoadModule")) {
4606
 
            get_arg(arg, sizeof(arg), &p);
4607
 
#if HAVE_DLOPEN
4608
 
            load_module(arg);
4609
 
#else
4610
 
            ERROR("Module support not compiled into this version: '%s'\n", arg);
4611
 
#endif
4612
 
        } else {
4613
 
            ERROR("Incorrect keyword: '%s'\n", cmd);
4614
 
        }
4615
 
    }
4616
 
#undef ERROR
4617
 
 
4618
 
    fclose(f);
4619
 
    if (errors)
4620
 
        return -1;
4621
 
    else
4622
 
        return 0;
4623
 
}
4624
 
 
4625
 
static void handle_child_exit(int sig)
4626
 
{
4627
 
    pid_t pid;
4628
 
    int status;
4629
 
 
4630
 
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4631
 
        FFStream *feed;
4632
 
 
4633
 
        for (feed = first_feed; feed; feed = feed->next) {
4634
 
            if (feed->pid == pid) {
4635
 
                int uptime = time(0) - feed->pid_start;
4636
 
 
4637
 
                feed->pid = 0;
4638
 
                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4639
 
 
4640
 
                if (uptime < 30)
4641
 
                    /* Turn off any more restarts */
4642
 
                    feed->child_argv = 0;
4643
 
            }
4644
 
        }
4645
 
    }
4646
 
 
4647
 
    need_to_start_children = 1;
4648
 
}
4649
 
 
4650
 
static void opt_debug(void)
4651
 
{
4652
 
    ffserver_debug = 1;
4653
 
    ffserver_daemon = 0;
4654
 
    logfilename[0] = '-';
4655
 
}
4656
 
 
4657
 
static void show_help(void)
4658
 
{
4659
 
    printf("usage: ffserver [options]\n"
4660
 
           "Hyper fast multi format Audio/Video streaming server\n");
4661
 
    printf("\n");
4662
 
    show_help_options(options, "Main options:\n", 0, 0);
4663
 
}
4664
 
 
4665
 
static const OptionDef options[] = {
4666
 
#include "cmdutils_common_opts.h"
4667
 
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4668
 
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4669
 
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4670
 
    { NULL },
4671
 
};
4672
 
 
4673
 
int main(int argc, char **argv)
4674
 
{
4675
 
    struct sigaction sigact;
4676
 
 
4677
 
    av_register_all();
4678
 
 
4679
 
    show_banner();
4680
 
 
4681
 
    my_program_name = argv[0];
4682
 
    my_program_dir = getcwd(0, 0);
4683
 
    ffserver_daemon = 1;
4684
 
 
4685
 
    parse_options(argc, argv, options, NULL);
4686
 
 
4687
 
    unsetenv("http_proxy");             /* Kill the http_proxy */
4688
 
 
4689
 
    av_lfg_init(&random_state, av_get_random_seed());
4690
 
 
4691
 
    memset(&sigact, 0, sizeof(sigact));
4692
 
    sigact.sa_handler = handle_child_exit;
4693
 
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4694
 
    sigaction(SIGCHLD, &sigact, 0);
4695
 
 
4696
 
    if (parse_ffconfig(config_filename) < 0) {
4697
 
        fprintf(stderr, "Incorrect config file - exiting.\n");
4698
 
        exit(1);
4699
 
    }
4700
 
 
4701
 
    /* open log file if needed */
4702
 
    if (logfilename[0] != '\0') {
4703
 
        if (!strcmp(logfilename, "-"))
4704
 
            logfile = stdout;
4705
 
        else
4706
 
            logfile = fopen(logfilename, "a");
4707
 
        av_log_set_callback(http_av_log);
4708
 
    }
4709
 
 
4710
 
    build_file_streams();
4711
 
 
4712
 
    build_feed_streams();
4713
 
 
4714
 
    compute_bandwidth();
4715
 
 
4716
 
    /* put the process in background and detach it from its TTY */
4717
 
    if (ffserver_daemon) {
4718
 
        int pid;
4719
 
 
4720
 
        pid = fork();
4721
 
        if (pid < 0) {
4722
 
            perror("fork");
4723
 
            exit(1);
4724
 
        } else if (pid > 0) {
4725
 
            /* parent : exit */
4726
 
            exit(0);
4727
 
        } else {
4728
 
            /* child */
4729
 
            setsid();
4730
 
            close(0);
4731
 
            open("/dev/null", O_RDWR);
4732
 
            if (strcmp(logfilename, "-") != 0) {
4733
 
                close(1);
4734
 
                dup(0);
4735
 
            }
4736
 
            close(2);
4737
 
            dup(0);
4738
 
        }
4739
 
    }
4740
 
 
4741
 
    /* signal init */
4742
 
    signal(SIGPIPE, SIG_IGN);
4743
 
 
4744
 
    if (ffserver_daemon)
4745
 
        chdir("/");
4746
 
 
4747
 
    if (http_server() < 0) {
4748
 
        http_log("Could not start server\n");
4749
 
        exit(1);
4750
 
    }
4751
 
 
4752
 
    return 0;
4753
 
}