Libav 0.7.1
ffserver.c
Go to the documentation of this file.
00001 /*
00002  * Multiple format streaming server
00003  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * Libav is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include "config.h"
00023 #if !HAVE_CLOSESOCKET
00024 #define closesocket close
00025 #endif
00026 #include <string.h>
00027 #include <strings.h>
00028 #include <stdlib.h>
00029 #include "libavformat/avformat.h"
00030 #include "libavformat/ffm.h"
00031 #include "libavformat/network.h"
00032 #include "libavformat/os_support.h"
00033 #include "libavformat/rtpdec.h"
00034 #include "libavformat/rtsp.h"
00035 // XXX for ffio_open_dyn_packet_buffer, to be removed
00036 #include "libavformat/avio_internal.h"
00037 #include "libavutil/avstring.h"
00038 #include "libavutil/lfg.h"
00039 #include "libavutil/dict.h"
00040 #include "libavutil/random_seed.h"
00041 #include "libavutil/parseutils.h"
00042 #include "libavutil/opt.h"
00043 #include <stdarg.h>
00044 #include <unistd.h>
00045 #include <fcntl.h>
00046 #include <sys/ioctl.h>
00047 #if HAVE_POLL_H
00048 #include <poll.h>
00049 #endif
00050 #include <errno.h>
00051 #include <sys/time.h>
00052 #include <time.h>
00053 #include <sys/wait.h>
00054 #include <signal.h>
00055 #if HAVE_DLFCN_H
00056 #include <dlfcn.h>
00057 #endif
00058 
00059 #include "cmdutils.h"
00060 
00061 const char program_name[] = "ffserver";
00062 const int program_birth_year = 2000;
00063 
00064 static const OptionDef options[];
00065 
00066 enum HTTPState {
00067     HTTPSTATE_WAIT_REQUEST,
00068     HTTPSTATE_SEND_HEADER,
00069     HTTPSTATE_SEND_DATA_HEADER,
00070     HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
00071     HTTPSTATE_SEND_DATA_TRAILER,
00072     HTTPSTATE_RECEIVE_DATA,
00073     HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
00074     HTTPSTATE_READY,
00075 
00076     RTSPSTATE_WAIT_REQUEST,
00077     RTSPSTATE_SEND_REPLY,
00078     RTSPSTATE_SEND_PACKET,
00079 };
00080 
00081 static const char *http_state[] = {
00082     "HTTP_WAIT_REQUEST",
00083     "HTTP_SEND_HEADER",
00084 
00085     "SEND_DATA_HEADER",
00086     "SEND_DATA",
00087     "SEND_DATA_TRAILER",
00088     "RECEIVE_DATA",
00089     "WAIT_FEED",
00090     "READY",
00091 
00092     "RTSP_WAIT_REQUEST",
00093     "RTSP_SEND_REPLY",
00094     "RTSP_SEND_PACKET",
00095 };
00096 
00097 #define MAX_STREAMS 20
00098 
00099 #define IOBUFFER_INIT_SIZE 8192
00100 
00101 /* timeouts are in ms */
00102 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
00103 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
00104 
00105 #define SYNC_TIMEOUT (10 * 1000)
00106 
00107 typedef struct RTSPActionServerSetup {
00108     uint32_t ipaddr;
00109     char transport_option[512];
00110 } RTSPActionServerSetup;
00111 
00112 typedef struct {
00113     int64_t count1, count2;
00114     int64_t time1, time2;
00115 } DataRateData;
00116 
00117 /* context associated with one connection */
00118 typedef struct HTTPContext {
00119     enum HTTPState state;
00120     int fd; /* socket file descriptor */
00121     struct sockaddr_in from_addr; /* origin */
00122     struct pollfd *poll_entry; /* used when polling */
00123     int64_t timeout;
00124     uint8_t *buffer_ptr, *buffer_end;
00125     int http_error;
00126     int post;
00127     int chunked_encoding;
00128     int chunk_size;               /* 0 if it needs to be read */
00129     struct HTTPContext *next;
00130     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
00131     int64_t data_count;
00132     /* feed input */
00133     int feed_fd;
00134     /* input format handling */
00135     AVFormatContext *fmt_in;
00136     int64_t start_time;            /* In milliseconds - this wraps fairly often */
00137     int64_t first_pts;            /* initial pts value */
00138     int64_t cur_pts;             /* current pts value from the stream in us */
00139     int64_t cur_frame_duration;  /* duration of the current frame in us */
00140     int cur_frame_bytes;       /* output frame size, needed to compute
00141                                   the time at which we send each
00142                                   packet */
00143     int pts_stream_index;        /* stream we choose as clock reference */
00144     int64_t cur_clock;           /* current clock reference value in us */
00145     /* output format handling */
00146     struct FFStream *stream;
00147     /* -1 is invalid stream */
00148     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
00149     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
00150     int switch_pending;
00151     AVFormatContext fmt_ctx; /* instance of FFStream for one user */
00152     int last_packet_sent; /* true if last data packet was sent */
00153     int suppress_log;
00154     DataRateData datarate;
00155     int wmp_client_id;
00156     char protocol[16];
00157     char method[16];
00158     char url[128];
00159     int buffer_size;
00160     uint8_t *buffer;
00161     int is_packetized; /* if true, the stream is packetized */
00162     int packet_stream_index; /* current stream for output in state machine */
00163 
00164     /* RTSP state specific */
00165     uint8_t *pb_buffer; /* XXX: use that in all the code */
00166     AVIOContext *pb;
00167     int seq; /* RTSP sequence number */
00168 
00169     /* RTP state specific */
00170     enum RTSPLowerTransport rtp_protocol;
00171     char session_id[32]; /* session id */
00172     AVFormatContext *rtp_ctx[MAX_STREAMS];
00173 
00174     /* RTP/UDP specific */
00175     URLContext *rtp_handles[MAX_STREAMS];
00176 
00177     /* RTP/TCP specific */
00178     struct HTTPContext *rtsp_c;
00179     uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
00180 } HTTPContext;
00181 
00182 /* each generated stream is described here */
00183 enum StreamType {
00184     STREAM_TYPE_LIVE,
00185     STREAM_TYPE_STATUS,
00186     STREAM_TYPE_REDIRECT,
00187 };
00188 
00189 enum IPAddressAction {
00190     IP_ALLOW = 1,
00191     IP_DENY,
00192 };
00193 
00194 typedef struct IPAddressACL {
00195     struct IPAddressACL *next;
00196     enum IPAddressAction action;
00197     /* These are in host order */
00198     struct in_addr first;
00199     struct in_addr last;
00200 } IPAddressACL;
00201 
00202 /* description of each stream of the ffserver.conf file */
00203 typedef struct FFStream {
00204     enum StreamType stream_type;
00205     char filename[1024];     /* stream filename */
00206     struct FFStream *feed;   /* feed we are using (can be null if
00207                                 coming from file) */
00208     AVDictionary *in_opts;   /* input parameters */
00209     AVInputFormat *ifmt;       /* if non NULL, force input format */
00210     AVOutputFormat *fmt;
00211     IPAddressACL *acl;
00212     char dynamic_acl[1024];
00213     int nb_streams;
00214     int prebuffer;      /* Number of millseconds early to start */
00215     int64_t max_time;      /* Number of milliseconds to run */
00216     int send_on_key;
00217     AVStream *streams[MAX_STREAMS];
00218     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
00219     char feed_filename[1024]; /* file name of the feed storage, or
00220                                  input file name for a stream */
00221     char author[512];
00222     char title[512];
00223     char copyright[512];
00224     char comment[512];
00225     pid_t pid;  /* Of ffmpeg process */
00226     time_t pid_start;  /* Of ffmpeg process */
00227     char **child_argv;
00228     struct FFStream *next;
00229     unsigned bandwidth; /* bandwidth, in kbits/s */
00230     /* RTSP options */
00231     char *rtsp_option;
00232     /* multicast specific */
00233     int is_multicast;
00234     struct in_addr multicast_ip;
00235     int multicast_port; /* first port used for multicast */
00236     int multicast_ttl;
00237     int loop; /* if true, send the stream in loops (only meaningful if file) */
00238 
00239     /* feed specific */
00240     int feed_opened;     /* true if someone is writing to the feed */
00241     int is_feed;         /* true if it is a feed */
00242     int readonly;        /* True if writing is prohibited to the file */
00243     int truncate;        /* True if feeder connection truncate the feed file */
00244     int conns_served;
00245     int64_t bytes_served;
00246     int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
00247     int64_t feed_write_index;   /* current write position in feed (it wraps around) */
00248     int64_t feed_size;          /* current size of feed */
00249     struct FFStream *next_feed;
00250 } FFStream;
00251 
00252 typedef struct FeedData {
00253     long long data_count;
00254     float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
00255 } FeedData;
00256 
00257 static struct sockaddr_in my_http_addr;
00258 static struct sockaddr_in my_rtsp_addr;
00259 
00260 static char logfilename[1024];
00261 static HTTPContext *first_http_ctx;
00262 static FFStream *first_feed;   /* contains only feeds */
00263 static FFStream *first_stream; /* contains all streams, including feeds */
00264 
00265 static void new_connection(int server_fd, int is_rtsp);
00266 static void close_connection(HTTPContext *c);
00267 
00268 /* HTTP handling */
00269 static int handle_connection(HTTPContext *c);
00270 static int http_parse_request(HTTPContext *c);
00271 static int http_send_data(HTTPContext *c);
00272 static void compute_status(HTTPContext *c);
00273 static int open_input_stream(HTTPContext *c, const char *info);
00274 static int http_start_receive_data(HTTPContext *c);
00275 static int http_receive_data(HTTPContext *c);
00276 
00277 /* RTSP handling */
00278 static int rtsp_parse_request(HTTPContext *c);
00279 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
00280 static void rtsp_cmd_options(HTTPContext *c, const char *url);
00281 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00282 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00283 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00284 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00285 
00286 /* SDP handling */
00287 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
00288                                    struct in_addr my_ip);
00289 
00290 /* RTP handling */
00291 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
00292                                        FFStream *stream, const char *session_id,
00293                                        enum RTSPLowerTransport rtp_protocol);
00294 static int rtp_new_av_stream(HTTPContext *c,
00295                              int stream_index, struct sockaddr_in *dest_addr,
00296                              HTTPContext *rtsp_c);
00297 
00298 static const char *my_program_name;
00299 static const char *my_program_dir;
00300 
00301 static const char *config_filename = "/etc/ffserver.conf";
00302 
00303 static int ffserver_debug;
00304 static int ffserver_daemon;
00305 static int no_launch;
00306 static int need_to_start_children;
00307 
00308 /* maximum number of simultaneous HTTP connections */
00309 static unsigned int nb_max_http_connections = 2000;
00310 static unsigned int nb_max_connections = 5;
00311 static unsigned int nb_connections;
00312 
00313 static uint64_t max_bandwidth = 1000;
00314 static uint64_t current_bandwidth;
00315 
00316 static int64_t cur_time;           // Making this global saves on passing it around everywhere
00317 
00318 static AVLFG random_state;
00319 
00320 static FILE *logfile = NULL;
00321 
00322 /* FIXME: make ffserver work with IPv6 */
00323 /* resolve host with also IP address parsing */
00324 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
00325 {
00326 
00327     if (!ff_inet_aton(hostname, sin_addr)) {
00328 #if HAVE_GETADDRINFO
00329         struct addrinfo *ai, *cur;
00330         struct addrinfo hints;
00331         memset(&hints, 0, sizeof(hints));
00332         hints.ai_family = AF_INET;
00333         if (getaddrinfo(hostname, NULL, &hints, &ai))
00334             return -1;
00335         /* getaddrinfo returns a linked list of addrinfo structs.
00336          * Even if we set ai_family = AF_INET above, make sure
00337          * that the returned one actually is of the correct type. */
00338         for (cur = ai; cur; cur = cur->ai_next) {
00339             if (cur->ai_family == AF_INET) {
00340                 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
00341                 freeaddrinfo(ai);
00342                 return 0;
00343             }
00344         }
00345         freeaddrinfo(ai);
00346         return -1;
00347 #else
00348         struct hostent *hp;
00349         hp = gethostbyname(hostname);
00350         if (!hp)
00351             return -1;
00352         memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
00353 #endif
00354     }
00355     return 0;
00356 }
00357 
00358 static char *ctime1(char *buf2)
00359 {
00360     time_t ti;
00361     char *p;
00362 
00363     ti = time(NULL);
00364     p = ctime(&ti);
00365     strcpy(buf2, p);
00366     p = buf2 + strlen(p) - 1;
00367     if (*p == '\n')
00368         *p = '\0';
00369     return buf2;
00370 }
00371 
00372 static void http_vlog(const char *fmt, va_list vargs)
00373 {
00374     static int print_prefix = 1;
00375     if (logfile) {
00376         if (print_prefix) {
00377             char buf[32];
00378             ctime1(buf);
00379             fprintf(logfile, "%s ", buf);
00380         }
00381         print_prefix = strstr(fmt, "\n") != NULL;
00382         vfprintf(logfile, fmt, vargs);
00383         fflush(logfile);
00384     }
00385 }
00386 
00387 #ifdef __GNUC__
00388 __attribute__ ((format (printf, 1, 2)))
00389 #endif
00390 static void http_log(const char *fmt, ...)
00391 {
00392     va_list vargs;
00393     va_start(vargs, fmt);
00394     http_vlog(fmt, vargs);
00395     va_end(vargs);
00396 }
00397 
00398 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
00399 {
00400     static int print_prefix = 1;
00401     AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
00402     if (level > av_log_get_level())
00403         return;
00404     if (print_prefix && avc)
00405         http_log("[%s @ %p]", avc->item_name(ptr), ptr);
00406     print_prefix = strstr(fmt, "\n") != NULL;
00407     http_vlog(fmt, vargs);
00408 }
00409 
00410 static void log_connection(HTTPContext *c)
00411 {
00412     if (c->suppress_log)
00413         return;
00414 
00415     http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
00416              inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
00417              c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
00418 }
00419 
00420 static void update_datarate(DataRateData *drd, int64_t count)
00421 {
00422     if (!drd->time1 && !drd->count1) {
00423         drd->time1 = drd->time2 = cur_time;
00424         drd->count1 = drd->count2 = count;
00425     } else if (cur_time - drd->time2 > 5000) {
00426         drd->time1 = drd->time2;
00427         drd->count1 = drd->count2;
00428         drd->time2 = cur_time;
00429         drd->count2 = count;
00430     }
00431 }
00432 
00433 /* In bytes per second */
00434 static int compute_datarate(DataRateData *drd, int64_t count)
00435 {
00436     if (cur_time == drd->time1)
00437         return 0;
00438 
00439     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
00440 }
00441 
00442 
00443 static void start_children(FFStream *feed)
00444 {
00445     if (no_launch)
00446         return;
00447 
00448     for (; feed; feed = feed->next) {
00449         if (feed->child_argv && !feed->pid) {
00450             feed->pid_start = time(0);
00451 
00452             feed->pid = fork();
00453 
00454             if (feed->pid < 0) {
00455                 http_log("Unable to create children\n");
00456                 exit(1);
00457             }
00458             if (!feed->pid) {
00459                 /* In child */
00460                 char pathname[1024];
00461                 char *slash;
00462                 int i;
00463 
00464                 av_strlcpy(pathname, my_program_name, sizeof(pathname));
00465 
00466                 slash = strrchr(pathname, '/');
00467                 if (!slash)
00468                     slash = pathname;
00469                 else
00470                     slash++;
00471                 strcpy(slash, "ffmpeg");
00472 
00473                 http_log("Launch commandline: ");
00474                 http_log("%s ", pathname);
00475                 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
00476                     http_log("%s ", feed->child_argv[i]);
00477                 http_log("\n");
00478 
00479                 for (i = 3; i < 256; i++)
00480                     close(i);
00481 
00482                 if (!ffserver_debug) {
00483                     i = open("/dev/null", O_RDWR);
00484                     if (i != -1) {
00485                         dup2(i, 0);
00486                         dup2(i, 1);
00487                         dup2(i, 2);
00488                         close(i);
00489                     }
00490                 }
00491 
00492                 /* This is needed to make relative pathnames work */
00493                 chdir(my_program_dir);
00494 
00495                 signal(SIGPIPE, SIG_DFL);
00496 
00497                 execvp(pathname, feed->child_argv);
00498 
00499                 _exit(1);
00500             }
00501         }
00502     }
00503 }
00504 
00505 /* open a listening socket */
00506 static int socket_open_listen(struct sockaddr_in *my_addr)
00507 {
00508     int server_fd, tmp;
00509 
00510     server_fd = socket(AF_INET,SOCK_STREAM,0);
00511     if (server_fd < 0) {
00512         perror ("socket");
00513         return -1;
00514     }
00515 
00516     tmp = 1;
00517     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
00518 
00519     my_addr->sin_family = AF_INET;
00520     if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
00521         char bindmsg[32];
00522         snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
00523         perror (bindmsg);
00524         closesocket(server_fd);
00525         return -1;
00526     }
00527 
00528     if (listen (server_fd, 5) < 0) {
00529         perror ("listen");
00530         closesocket(server_fd);
00531         return -1;
00532     }
00533     ff_socket_nonblock(server_fd, 1);
00534 
00535     return server_fd;
00536 }
00537 
00538 /* start all multicast streams */
00539 static void start_multicast(void)
00540 {
00541     FFStream *stream;
00542     char session_id[32];
00543     HTTPContext *rtp_c;
00544     struct sockaddr_in dest_addr;
00545     int default_port, stream_index;
00546 
00547     default_port = 6000;
00548     for(stream = first_stream; stream != NULL; stream = stream->next) {
00549         if (stream->is_multicast) {
00550             /* open the RTP connection */
00551             snprintf(session_id, sizeof(session_id), "%08x%08x",
00552                      av_lfg_get(&random_state), av_lfg_get(&random_state));
00553 
00554             /* choose a port if none given */
00555             if (stream->multicast_port == 0) {
00556                 stream->multicast_port = default_port;
00557                 default_port += 100;
00558             }
00559 
00560             dest_addr.sin_family = AF_INET;
00561             dest_addr.sin_addr = stream->multicast_ip;
00562             dest_addr.sin_port = htons(stream->multicast_port);
00563 
00564             rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
00565                                        RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
00566             if (!rtp_c)
00567                 continue;
00568 
00569             if (open_input_stream(rtp_c, "") < 0) {
00570                 http_log("Could not open input stream for stream '%s'\n",
00571                          stream->filename);
00572                 continue;
00573             }
00574 
00575             /* open each RTP stream */
00576             for(stream_index = 0; stream_index < stream->nb_streams;
00577                 stream_index++) {
00578                 dest_addr.sin_port = htons(stream->multicast_port +
00579                                            2 * stream_index);
00580                 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
00581                     http_log("Could not open output stream '%s/streamid=%d'\n",
00582                              stream->filename, stream_index);
00583                     exit(1);
00584                 }
00585             }
00586 
00587             /* change state to send data */
00588             rtp_c->state = HTTPSTATE_SEND_DATA;
00589         }
00590     }
00591 }
00592 
00593 /* main loop of the http server */
00594 static int http_server(void)
00595 {
00596     int server_fd = 0, rtsp_server_fd = 0;
00597     int ret, delay, delay1;
00598     struct pollfd *poll_table, *poll_entry;
00599     HTTPContext *c, *c_next;
00600 
00601     if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
00602         http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
00603         return -1;
00604     }
00605 
00606     if (my_http_addr.sin_port) {
00607         server_fd = socket_open_listen(&my_http_addr);
00608         if (server_fd < 0)
00609             return -1;
00610     }
00611 
00612     if (my_rtsp_addr.sin_port) {
00613         rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
00614         if (rtsp_server_fd < 0)
00615             return -1;
00616     }
00617 
00618     if (!rtsp_server_fd && !server_fd) {
00619         http_log("HTTP and RTSP disabled.\n");
00620         return -1;
00621     }
00622 
00623     http_log("FFserver started.\n");
00624 
00625     start_children(first_feed);
00626 
00627     start_multicast();
00628 
00629     for(;;) {
00630         poll_entry = poll_table;
00631         if (server_fd) {
00632             poll_entry->fd = server_fd;
00633             poll_entry->events = POLLIN;
00634             poll_entry++;
00635         }
00636         if (rtsp_server_fd) {
00637             poll_entry->fd = rtsp_server_fd;
00638             poll_entry->events = POLLIN;
00639             poll_entry++;
00640         }
00641 
00642         /* wait for events on each HTTP handle */
00643         c = first_http_ctx;
00644         delay = 1000;
00645         while (c != NULL) {
00646             int fd;
00647             fd = c->fd;
00648             switch(c->state) {
00649             case HTTPSTATE_SEND_HEADER:
00650             case RTSPSTATE_SEND_REPLY:
00651             case RTSPSTATE_SEND_PACKET:
00652                 c->poll_entry = poll_entry;
00653                 poll_entry->fd = fd;
00654                 poll_entry->events = POLLOUT;
00655                 poll_entry++;
00656                 break;
00657             case HTTPSTATE_SEND_DATA_HEADER:
00658             case HTTPSTATE_SEND_DATA:
00659             case HTTPSTATE_SEND_DATA_TRAILER:
00660                 if (!c->is_packetized) {
00661                     /* for TCP, we output as much as we can (may need to put a limit) */
00662                     c->poll_entry = poll_entry;
00663                     poll_entry->fd = fd;
00664                     poll_entry->events = POLLOUT;
00665                     poll_entry++;
00666                 } else {
00667                     /* when ffserver is doing the timing, we work by
00668                        looking at which packet need to be sent every
00669                        10 ms */
00670                     delay1 = 10; /* one tick wait XXX: 10 ms assumed */
00671                     if (delay1 < delay)
00672                         delay = delay1;
00673                 }
00674                 break;
00675             case HTTPSTATE_WAIT_REQUEST:
00676             case HTTPSTATE_RECEIVE_DATA:
00677             case HTTPSTATE_WAIT_FEED:
00678             case RTSPSTATE_WAIT_REQUEST:
00679                 /* need to catch errors */
00680                 c->poll_entry = poll_entry;
00681                 poll_entry->fd = fd;
00682                 poll_entry->events = POLLIN;/* Maybe this will work */
00683                 poll_entry++;
00684                 break;
00685             default:
00686                 c->poll_entry = NULL;
00687                 break;
00688             }
00689             c = c->next;
00690         }
00691 
00692         /* wait for an event on one connection. We poll at least every
00693            second to handle timeouts */
00694         do {
00695             ret = poll(poll_table, poll_entry - poll_table, delay);
00696             if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
00697                 ff_neterrno() != AVERROR(EINTR))
00698                 return -1;
00699         } while (ret < 0);
00700 
00701         cur_time = av_gettime() / 1000;
00702 
00703         if (need_to_start_children) {
00704             need_to_start_children = 0;
00705             start_children(first_feed);
00706         }
00707 
00708         /* now handle the events */
00709         for(c = first_http_ctx; c != NULL; c = c_next) {
00710             c_next = c->next;
00711             if (handle_connection(c) < 0) {
00712                 /* close and free the connection */
00713                 log_connection(c);
00714                 close_connection(c);
00715             }
00716         }
00717 
00718         poll_entry = poll_table;
00719         if (server_fd) {
00720             /* new HTTP connection request ? */
00721             if (poll_entry->revents & POLLIN)
00722                 new_connection(server_fd, 0);
00723             poll_entry++;
00724         }
00725         if (rtsp_server_fd) {
00726             /* new RTSP connection request ? */
00727             if (poll_entry->revents & POLLIN)
00728                 new_connection(rtsp_server_fd, 1);
00729         }
00730     }
00731 }
00732 
00733 /* start waiting for a new HTTP/RTSP request */
00734 static void start_wait_request(HTTPContext *c, int is_rtsp)
00735 {
00736     c->buffer_ptr = c->buffer;
00737     c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
00738 
00739     if (is_rtsp) {
00740         c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
00741         c->state = RTSPSTATE_WAIT_REQUEST;
00742     } else {
00743         c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
00744         c->state = HTTPSTATE_WAIT_REQUEST;
00745     }
00746 }
00747 
00748 static void http_send_too_busy_reply(int fd)
00749 {
00750     char buffer[300];
00751     int len = snprintf(buffer, sizeof(buffer),
00752                        "HTTP/1.0 503 Server too busy\r\n"
00753                        "Content-type: text/html\r\n"
00754                        "\r\n"
00755                        "<html><head><title>Too busy</title></head><body>\r\n"
00756                        "<p>The server is too busy to serve your request at this time.</p>\r\n"
00757                        "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
00758                        "</body></html>\r\n",
00759                        nb_connections, nb_max_connections);
00760     send(fd, buffer, len, 0);
00761 }
00762 
00763 
00764 static void new_connection(int server_fd, int is_rtsp)
00765 {
00766     struct sockaddr_in from_addr;
00767     int fd, len;
00768     HTTPContext *c = NULL;
00769 
00770     len = sizeof(from_addr);
00771     fd = accept(server_fd, (struct sockaddr *)&from_addr,
00772                 &len);
00773     if (fd < 0) {
00774         http_log("error during accept %s\n", strerror(errno));
00775         return;
00776     }
00777     ff_socket_nonblock(fd, 1);
00778 
00779     if (nb_connections >= nb_max_connections) {
00780         http_send_too_busy_reply(fd);
00781         goto fail;
00782     }
00783 
00784     /* add a new connection */
00785     c = av_mallocz(sizeof(HTTPContext));
00786     if (!c)
00787         goto fail;
00788 
00789     c->fd = fd;
00790     c->poll_entry = NULL;
00791     c->from_addr = from_addr;
00792     c->buffer_size = IOBUFFER_INIT_SIZE;
00793     c->buffer = av_malloc(c->buffer_size);
00794     if (!c->buffer)
00795         goto fail;
00796 
00797     c->next = first_http_ctx;
00798     first_http_ctx = c;
00799     nb_connections++;
00800 
00801     start_wait_request(c, is_rtsp);
00802 
00803     return;
00804 
00805  fail:
00806     if (c) {
00807         av_free(c->buffer);
00808         av_free(c);
00809     }
00810     closesocket(fd);
00811 }
00812 
00813 static void close_connection(HTTPContext *c)
00814 {
00815     HTTPContext **cp, *c1;
00816     int i, nb_streams;
00817     AVFormatContext *ctx;
00818     URLContext *h;
00819     AVStream *st;
00820 
00821     /* remove connection from list */
00822     cp = &first_http_ctx;
00823     while ((*cp) != NULL) {
00824         c1 = *cp;
00825         if (c1 == c)
00826             *cp = c->next;
00827         else
00828             cp = &c1->next;
00829     }
00830 
00831     /* remove references, if any (XXX: do it faster) */
00832     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
00833         if (c1->rtsp_c == c)
00834             c1->rtsp_c = NULL;
00835     }
00836 
00837     /* remove connection associated resources */
00838     if (c->fd >= 0)
00839         closesocket(c->fd);
00840     if (c->fmt_in) {
00841         /* close each frame parser */
00842         for(i=0;i<c->fmt_in->nb_streams;i++) {
00843             st = c->fmt_in->streams[i];
00844             if (st->codec->codec)
00845                 avcodec_close(st->codec);
00846         }
00847         av_close_input_file(c->fmt_in);
00848     }
00849 
00850     /* free RTP output streams if any */
00851     nb_streams = 0;
00852     if (c->stream)
00853         nb_streams = c->stream->nb_streams;
00854 
00855     for(i=0;i<nb_streams;i++) {
00856         ctx = c->rtp_ctx[i];
00857         if (ctx) {
00858             av_write_trailer(ctx);
00859             av_dict_free(&ctx->metadata);
00860             av_free(ctx->streams[0]);
00861             av_free(ctx);
00862         }
00863         h = c->rtp_handles[i];
00864         if (h)
00865             url_close(h);
00866     }
00867 
00868     ctx = &c->fmt_ctx;
00869 
00870     if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
00871         if (ctx->oformat) {
00872             /* prepare header */
00873             if (avio_open_dyn_buf(&ctx->pb) >= 0) {
00874                 av_write_trailer(ctx);
00875                 av_freep(&c->pb_buffer);
00876                 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
00877             }
00878         }
00879     }
00880 
00881     for(i=0; i<ctx->nb_streams; i++)
00882         av_free(ctx->streams[i]);
00883 
00884     if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
00885         current_bandwidth -= c->stream->bandwidth;
00886 
00887     /* signal that there is no feed if we are the feeder socket */
00888     if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
00889         c->stream->feed_opened = 0;
00890         close(c->feed_fd);
00891     }
00892 
00893     av_freep(&c->pb_buffer);
00894     av_freep(&c->packet_buffer);
00895     av_free(c->buffer);
00896     av_free(c);
00897     nb_connections--;
00898 }
00899 
00900 static int handle_connection(HTTPContext *c)
00901 {
00902     int len, ret;
00903 
00904     switch(c->state) {
00905     case HTTPSTATE_WAIT_REQUEST:
00906     case RTSPSTATE_WAIT_REQUEST:
00907         /* timeout ? */
00908         if ((c->timeout - cur_time) < 0)
00909             return -1;
00910         if (c->poll_entry->revents & (POLLERR | POLLHUP))
00911             return -1;
00912 
00913         /* no need to read if no events */
00914         if (!(c->poll_entry->revents & POLLIN))
00915             return 0;
00916         /* read the data */
00917     read_loop:
00918         len = recv(c->fd, c->buffer_ptr, 1, 0);
00919         if (len < 0) {
00920             if (ff_neterrno() != AVERROR(EAGAIN) &&
00921                 ff_neterrno() != AVERROR(EINTR))
00922                 return -1;
00923         } else if (len == 0) {
00924             return -1;
00925         } else {
00926             /* search for end of request. */
00927             uint8_t *ptr;
00928             c->buffer_ptr += len;
00929             ptr = c->buffer_ptr;
00930             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
00931                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
00932                 /* request found : parse it and reply */
00933                 if (c->state == HTTPSTATE_WAIT_REQUEST) {
00934                     ret = http_parse_request(c);
00935                 } else {
00936                     ret = rtsp_parse_request(c);
00937                 }
00938                 if (ret < 0)
00939                     return -1;
00940             } else if (ptr >= c->buffer_end) {
00941                 /* request too long: cannot do anything */
00942                 return -1;
00943             } else goto read_loop;
00944         }
00945         break;
00946 
00947     case HTTPSTATE_SEND_HEADER:
00948         if (c->poll_entry->revents & (POLLERR | POLLHUP))
00949             return -1;
00950 
00951         /* no need to write if no events */
00952         if (!(c->poll_entry->revents & POLLOUT))
00953             return 0;
00954         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
00955         if (len < 0) {
00956             if (ff_neterrno() != AVERROR(EAGAIN) &&
00957                 ff_neterrno() != AVERROR(EINTR)) {
00958                 /* error : close connection */
00959                 av_freep(&c->pb_buffer);
00960                 return -1;
00961             }
00962         } else {
00963             c->buffer_ptr += len;
00964             if (c->stream)
00965                 c->stream->bytes_served += len;
00966             c->data_count += len;
00967             if (c->buffer_ptr >= c->buffer_end) {
00968                 av_freep(&c->pb_buffer);
00969                 /* if error, exit */
00970                 if (c->http_error)
00971                     return -1;
00972                 /* all the buffer was sent : synchronize to the incoming stream */
00973                 c->state = HTTPSTATE_SEND_DATA_HEADER;
00974                 c->buffer_ptr = c->buffer_end = c->buffer;
00975             }
00976         }
00977         break;
00978 
00979     case HTTPSTATE_SEND_DATA:
00980     case HTTPSTATE_SEND_DATA_HEADER:
00981     case HTTPSTATE_SEND_DATA_TRAILER:
00982         /* for packetized output, we consider we can always write (the
00983            input streams sets the speed). It may be better to verify
00984            that we do not rely too much on the kernel queues */
00985         if (!c->is_packetized) {
00986             if (c->poll_entry->revents & (POLLERR | POLLHUP))
00987                 return -1;
00988 
00989             /* no need to read if no events */
00990             if (!(c->poll_entry->revents & POLLOUT))
00991                 return 0;
00992         }
00993         if (http_send_data(c) < 0)
00994             return -1;
00995         /* close connection if trailer sent */
00996         if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
00997             return -1;
00998         break;
00999     case HTTPSTATE_RECEIVE_DATA:
01000         /* no need to read if no events */
01001         if (c->poll_entry->revents & (POLLERR | POLLHUP))
01002             return -1;
01003         if (!(c->poll_entry->revents & POLLIN))
01004             return 0;
01005         if (http_receive_data(c) < 0)
01006             return -1;
01007         break;
01008     case HTTPSTATE_WAIT_FEED:
01009         /* no need to read if no events */
01010         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
01011             return -1;
01012 
01013         /* nothing to do, we'll be waken up by incoming feed packets */
01014         break;
01015 
01016     case RTSPSTATE_SEND_REPLY:
01017         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
01018             av_freep(&c->pb_buffer);
01019             return -1;
01020         }
01021         /* no need to write if no events */
01022         if (!(c->poll_entry->revents & POLLOUT))
01023             return 0;
01024         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
01025         if (len < 0) {
01026             if (ff_neterrno() != AVERROR(EAGAIN) &&
01027                 ff_neterrno() != AVERROR(EINTR)) {
01028                 /* error : close connection */
01029                 av_freep(&c->pb_buffer);
01030                 return -1;
01031             }
01032         } else {
01033             c->buffer_ptr += len;
01034             c->data_count += len;
01035             if (c->buffer_ptr >= c->buffer_end) {
01036                 /* all the buffer was sent : wait for a new request */
01037                 av_freep(&c->pb_buffer);
01038                 start_wait_request(c, 1);
01039             }
01040         }
01041         break;
01042     case RTSPSTATE_SEND_PACKET:
01043         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
01044             av_freep(&c->packet_buffer);
01045             return -1;
01046         }
01047         /* no need to write if no events */
01048         if (!(c->poll_entry->revents & POLLOUT))
01049             return 0;
01050         len = send(c->fd, c->packet_buffer_ptr,
01051                     c->packet_buffer_end - c->packet_buffer_ptr, 0);
01052         if (len < 0) {
01053             if (ff_neterrno() != AVERROR(EAGAIN) &&
01054                 ff_neterrno() != AVERROR(EINTR)) {
01055                 /* error : close connection */
01056                 av_freep(&c->packet_buffer);
01057                 return -1;
01058             }
01059         } else {
01060             c->packet_buffer_ptr += len;
01061             if (c->packet_buffer_ptr >= c->packet_buffer_end) {
01062                 /* all the buffer was sent : wait for a new request */
01063                 av_freep(&c->packet_buffer);
01064                 c->state = RTSPSTATE_WAIT_REQUEST;
01065             }
01066         }
01067         break;
01068     case HTTPSTATE_READY:
01069         /* nothing to do */
01070         break;
01071     default:
01072         return -1;
01073     }
01074     return 0;
01075 }
01076 
01077 static int extract_rates(char *rates, int ratelen, const char *request)
01078 {
01079     const char *p;
01080 
01081     for (p = request; *p && *p != '\r' && *p != '\n'; ) {
01082         if (strncasecmp(p, "Pragma:", 7) == 0) {
01083             const char *q = p + 7;
01084 
01085             while (*q && *q != '\n' && isspace(*q))
01086                 q++;
01087 
01088             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
01089                 int stream_no;
01090                 int rate_no;
01091 
01092                 q += 20;
01093 
01094                 memset(rates, 0xff, ratelen);
01095 
01096                 while (1) {
01097                     while (*q && *q != '\n' && *q != ':')
01098                         q++;
01099 
01100                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
01101                         break;
01102 
01103                     stream_no--;
01104                     if (stream_no < ratelen && stream_no >= 0)
01105                         rates[stream_no] = rate_no;
01106 
01107                     while (*q && *q != '\n' && !isspace(*q))
01108                         q++;
01109                 }
01110 
01111                 return 1;
01112             }
01113         }
01114         p = strchr(p, '\n');
01115         if (!p)
01116             break;
01117 
01118         p++;
01119     }
01120 
01121     return 0;
01122 }
01123 
01124 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
01125 {
01126     int i;
01127     int best_bitrate = 100000000;
01128     int best = -1;
01129 
01130     for (i = 0; i < feed->nb_streams; i++) {
01131         AVCodecContext *feed_codec = feed->streams[i]->codec;
01132 
01133         if (feed_codec->codec_id != codec->codec_id ||
01134             feed_codec->sample_rate != codec->sample_rate ||
01135             feed_codec->width != codec->width ||
01136             feed_codec->height != codec->height)
01137             continue;
01138 
01139         /* Potential stream */
01140 
01141         /* We want the fastest stream less than bit_rate, or the slowest
01142          * faster than bit_rate
01143          */
01144 
01145         if (feed_codec->bit_rate <= bit_rate) {
01146             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
01147                 best_bitrate = feed_codec->bit_rate;
01148                 best = i;
01149             }
01150         } else {
01151             if (feed_codec->bit_rate < best_bitrate) {
01152                 best_bitrate = feed_codec->bit_rate;
01153                 best = i;
01154             }
01155         }
01156     }
01157 
01158     return best;
01159 }
01160 
01161 static int modify_current_stream(HTTPContext *c, char *rates)
01162 {
01163     int i;
01164     FFStream *req = c->stream;
01165     int action_required = 0;
01166 
01167     /* Not much we can do for a feed */
01168     if (!req->feed)
01169         return 0;
01170 
01171     for (i = 0; i < req->nb_streams; i++) {
01172         AVCodecContext *codec = req->streams[i]->codec;
01173 
01174         switch(rates[i]) {
01175             case 0:
01176                 c->switch_feed_streams[i] = req->feed_streams[i];
01177                 break;
01178             case 1:
01179                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
01180                 break;
01181             case 2:
01182                 /* Wants off or slow */
01183                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
01184 #ifdef WANTS_OFF
01185                 /* This doesn't work well when it turns off the only stream! */
01186                 c->switch_feed_streams[i] = -2;
01187                 c->feed_streams[i] = -2;
01188 #endif
01189                 break;
01190         }
01191 
01192         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
01193             action_required = 1;
01194     }
01195 
01196     return action_required;
01197 }
01198 
01199 /* XXX: factorize in utils.c ? */
01200 /* XXX: take care with different space meaning */
01201 static void skip_spaces(const char **pp)
01202 {
01203     const char *p;
01204     p = *pp;
01205     while (*p == ' ' || *p == '\t')
01206         p++;
01207     *pp = p;
01208 }
01209 
01210 static void get_word(char *buf, int buf_size, const char **pp)
01211 {
01212     const char *p;
01213     char *q;
01214 
01215     p = *pp;
01216     skip_spaces(&p);
01217     q = buf;
01218     while (!isspace(*p) && *p != '\0') {
01219         if ((q - buf) < buf_size - 1)
01220             *q++ = *p;
01221         p++;
01222     }
01223     if (buf_size > 0)
01224         *q = '\0';
01225     *pp = p;
01226 }
01227 
01228 static void get_arg(char *buf, int buf_size, const char **pp)
01229 {
01230     const char *p;
01231     char *q;
01232     int quote;
01233 
01234     p = *pp;
01235     while (isspace(*p)) p++;
01236     q = buf;
01237     quote = 0;
01238     if (*p == '\"' || *p == '\'')
01239         quote = *p++;
01240     for(;;) {
01241         if (quote) {
01242             if (*p == quote)
01243                 break;
01244         } else {
01245             if (isspace(*p))
01246                 break;
01247         }
01248         if (*p == '\0')
01249             break;
01250         if ((q - buf) < buf_size - 1)
01251             *q++ = *p;
01252         p++;
01253     }
01254     *q = '\0';
01255     if (quote && *p == quote)
01256         p++;
01257     *pp = p;
01258 }
01259 
01260 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
01261                          const char *p, const char *filename, int line_num)
01262 {
01263     char arg[1024];
01264     IPAddressACL acl;
01265     int errors = 0;
01266 
01267     get_arg(arg, sizeof(arg), &p);
01268     if (strcasecmp(arg, "allow") == 0)
01269         acl.action = IP_ALLOW;
01270     else if (strcasecmp(arg, "deny") == 0)
01271         acl.action = IP_DENY;
01272     else {
01273         fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
01274                 filename, line_num, arg);
01275         errors++;
01276     }
01277 
01278     get_arg(arg, sizeof(arg), &p);
01279 
01280     if (resolve_host(&acl.first, arg) != 0) {
01281         fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
01282                 filename, line_num, arg);
01283         errors++;
01284     } else
01285         acl.last = acl.first;
01286 
01287     get_arg(arg, sizeof(arg), &p);
01288 
01289     if (arg[0]) {
01290         if (resolve_host(&acl.last, arg) != 0) {
01291             fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
01292                     filename, line_num, arg);
01293             errors++;
01294         }
01295     }
01296 
01297     if (!errors) {
01298         IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
01299         IPAddressACL **naclp = 0;
01300 
01301         acl.next = 0;
01302         *nacl = acl;
01303 
01304         if (stream)
01305             naclp = &stream->acl;
01306         else if (feed)
01307             naclp = &feed->acl;
01308         else if (ext_acl)
01309             naclp = &ext_acl;
01310         else {
01311             fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
01312                     filename, line_num);
01313             errors++;
01314         }
01315 
01316         if (naclp) {
01317             while (*naclp)
01318                 naclp = &(*naclp)->next;
01319 
01320             *naclp = nacl;
01321         }
01322     }
01323 }
01324 
01325 
01326 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
01327 {
01328     FILE* f;
01329     char line[1024];
01330     char  cmd[1024];
01331     IPAddressACL *acl = NULL;
01332     int line_num = 0;
01333     const char *p;
01334 
01335     f = fopen(stream->dynamic_acl, "r");
01336     if (!f) {
01337         perror(stream->dynamic_acl);
01338         return NULL;
01339     }
01340 
01341     acl = av_mallocz(sizeof(IPAddressACL));
01342 
01343     /* Build ACL */
01344     for(;;) {
01345         if (fgets(line, sizeof(line), f) == NULL)
01346             break;
01347         line_num++;
01348         p = line;
01349         while (isspace(*p))
01350             p++;
01351         if (*p == '\0' || *p == '#')
01352             continue;
01353         get_arg(cmd, sizeof(cmd), &p);
01354 
01355         if (!strcasecmp(cmd, "ACL"))
01356             parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
01357     }
01358     fclose(f);
01359     return acl;
01360 }
01361 
01362 
01363 static void free_acl_list(IPAddressACL *in_acl)
01364 {
01365     IPAddressACL *pacl,*pacl2;
01366 
01367     pacl = in_acl;
01368     while(pacl) {
01369         pacl2 = pacl;
01370         pacl = pacl->next;
01371         av_freep(pacl2);
01372     }
01373 }
01374 
01375 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
01376 {
01377     enum IPAddressAction last_action = IP_DENY;
01378     IPAddressACL *acl;
01379     struct in_addr *src = &c->from_addr.sin_addr;
01380     unsigned long src_addr = src->s_addr;
01381 
01382     for (acl = in_acl; acl; acl = acl->next) {
01383         if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
01384             return (acl->action == IP_ALLOW) ? 1 : 0;
01385         last_action = acl->action;
01386     }
01387 
01388     /* Nothing matched, so return not the last action */
01389     return (last_action == IP_DENY) ? 1 : 0;
01390 }
01391 
01392 static int validate_acl(FFStream *stream, HTTPContext *c)
01393 {
01394     int ret = 0;
01395     IPAddressACL *acl;
01396 
01397 
01398     /* if stream->acl is null validate_acl_list will return 1 */
01399     ret = validate_acl_list(stream->acl, c);
01400 
01401     if (stream->dynamic_acl[0]) {
01402         acl = parse_dynamic_acl(stream, c);
01403 
01404         ret = validate_acl_list(acl, c);
01405 
01406         free_acl_list(acl);
01407     }
01408 
01409     return ret;
01410 }
01411 
01412 /* compute the real filename of a file by matching it without its
01413    extensions to all the stream filenames */
01414 static void compute_real_filename(char *filename, int max_size)
01415 {
01416     char file1[1024];
01417     char file2[1024];
01418     char *p;
01419     FFStream *stream;
01420 
01421     /* compute filename by matching without the file extensions */
01422     av_strlcpy(file1, filename, sizeof(file1));
01423     p = strrchr(file1, '.');
01424     if (p)
01425         *p = '\0';
01426     for(stream = first_stream; stream != NULL; stream = stream->next) {
01427         av_strlcpy(file2, stream->filename, sizeof(file2));
01428         p = strrchr(file2, '.');
01429         if (p)
01430             *p = '\0';
01431         if (!strcmp(file1, file2)) {
01432             av_strlcpy(filename, stream->filename, max_size);
01433             break;
01434         }
01435     }
01436 }
01437 
01438 enum RedirType {
01439     REDIR_NONE,
01440     REDIR_ASX,
01441     REDIR_RAM,
01442     REDIR_ASF,
01443     REDIR_RTSP,
01444     REDIR_SDP,
01445 };
01446 
01447 /* parse http request and prepare header */
01448 static int http_parse_request(HTTPContext *c)
01449 {
01450     char *p;
01451     enum RedirType redir_type;
01452     char cmd[32];
01453     char info[1024], filename[1024];
01454     char url[1024], *q;
01455     char protocol[32];
01456     char msg[1024];
01457     const char *mime_type;
01458     FFStream *stream;
01459     int i;
01460     char ratebuf[32];
01461     char *useragent = 0;
01462 
01463     p = c->buffer;
01464     get_word(cmd, sizeof(cmd), (const char **)&p);
01465     av_strlcpy(c->method, cmd, sizeof(c->method));
01466 
01467     if (!strcmp(cmd, "GET"))
01468         c->post = 0;
01469     else if (!strcmp(cmd, "POST"))
01470         c->post = 1;
01471     else
01472         return -1;
01473 
01474     get_word(url, sizeof(url), (const char **)&p);
01475     av_strlcpy(c->url, url, sizeof(c->url));
01476 
01477     get_word(protocol, sizeof(protocol), (const char **)&p);
01478     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
01479         return -1;
01480 
01481     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
01482 
01483     if (ffserver_debug)
01484         http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
01485 
01486     /* find the filename and the optional info string in the request */
01487     p = strchr(url, '?');
01488     if (p) {
01489         av_strlcpy(info, p, sizeof(info));
01490         *p = '\0';
01491     } else
01492         info[0] = '\0';
01493 
01494     av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
01495 
01496     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01497         if (strncasecmp(p, "User-Agent:", 11) == 0) {
01498             useragent = p + 11;
01499             if (*useragent && *useragent != '\n' && isspace(*useragent))
01500                 useragent++;
01501             break;
01502         }
01503         p = strchr(p, '\n');
01504         if (!p)
01505             break;
01506 
01507         p++;
01508     }
01509 
01510     redir_type = REDIR_NONE;
01511     if (av_match_ext(filename, "asx")) {
01512         redir_type = REDIR_ASX;
01513         filename[strlen(filename)-1] = 'f';
01514     } else if (av_match_ext(filename, "asf") &&
01515         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
01516         /* if this isn't WMP or lookalike, return the redirector file */
01517         redir_type = REDIR_ASF;
01518     } else if (av_match_ext(filename, "rpm,ram")) {
01519         redir_type = REDIR_RAM;
01520         strcpy(filename + strlen(filename)-2, "m");
01521     } else if (av_match_ext(filename, "rtsp")) {
01522         redir_type = REDIR_RTSP;
01523         compute_real_filename(filename, sizeof(filename) - 1);
01524     } else if (av_match_ext(filename, "sdp")) {
01525         redir_type = REDIR_SDP;
01526         compute_real_filename(filename, sizeof(filename) - 1);
01527     }
01528 
01529     // "redirect" / request to index.html
01530     if (!strlen(filename))
01531         av_strlcpy(filename, "index.html", sizeof(filename) - 1);
01532 
01533     stream = first_stream;
01534     while (stream != NULL) {
01535         if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
01536             break;
01537         stream = stream->next;
01538     }
01539     if (stream == NULL) {
01540         snprintf(msg, sizeof(msg), "File '%s' not found", url);
01541         http_log("File '%s' not found\n", url);
01542         goto send_error;
01543     }
01544 
01545     c->stream = stream;
01546     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
01547     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
01548 
01549     if (stream->stream_type == STREAM_TYPE_REDIRECT) {
01550         c->http_error = 301;
01551         q = c->buffer;
01552         q += snprintf(q, c->buffer_size,
01553                       "HTTP/1.0 301 Moved\r\n"
01554                       "Location: %s\r\n"
01555                       "Content-type: text/html\r\n"
01556                       "\r\n"
01557                       "<html><head><title>Moved</title></head><body>\r\n"
01558                       "You should be <a href=\"%s\">redirected</a>.\r\n"
01559                       "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
01560         /* prepare output buffer */
01561         c->buffer_ptr = c->buffer;
01562         c->buffer_end = q;
01563         c->state = HTTPSTATE_SEND_HEADER;
01564         return 0;
01565     }
01566 
01567     /* If this is WMP, get the rate information */
01568     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
01569         if (modify_current_stream(c, ratebuf)) {
01570             for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
01571                 if (c->switch_feed_streams[i] >= 0)
01572                     c->switch_feed_streams[i] = -1;
01573             }
01574         }
01575     }
01576 
01577     if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
01578         current_bandwidth += stream->bandwidth;
01579 
01580     /* If already streaming this feed, do not let start another feeder. */
01581     if (stream->feed_opened) {
01582         snprintf(msg, sizeof(msg), "This feed is already being received.");
01583         http_log("Feed '%s' already being received\n", stream->feed_filename);
01584         goto send_error;
01585     }
01586 
01587     if (c->post == 0 && max_bandwidth < current_bandwidth) {
01588         c->http_error = 503;
01589         q = c->buffer;
01590         q += snprintf(q, c->buffer_size,
01591                       "HTTP/1.0 503 Server too busy\r\n"
01592                       "Content-type: text/html\r\n"
01593                       "\r\n"
01594                       "<html><head><title>Too busy</title></head><body>\r\n"
01595                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
01596                       "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
01597                       "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
01598                       "</body></html>\r\n", current_bandwidth, max_bandwidth);
01599         /* prepare output buffer */
01600         c->buffer_ptr = c->buffer;
01601         c->buffer_end = q;
01602         c->state = HTTPSTATE_SEND_HEADER;
01603         return 0;
01604     }
01605 
01606     if (redir_type != REDIR_NONE) {
01607         char *hostinfo = 0;
01608 
01609         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01610             if (strncasecmp(p, "Host:", 5) == 0) {
01611                 hostinfo = p + 5;
01612                 break;
01613             }
01614             p = strchr(p, '\n');
01615             if (!p)
01616                 break;
01617 
01618             p++;
01619         }
01620 
01621         if (hostinfo) {
01622             char *eoh;
01623             char hostbuf[260];
01624 
01625             while (isspace(*hostinfo))
01626                 hostinfo++;
01627 
01628             eoh = strchr(hostinfo, '\n');
01629             if (eoh) {
01630                 if (eoh[-1] == '\r')
01631                     eoh--;
01632 
01633                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
01634                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
01635                     hostbuf[eoh - hostinfo] = 0;
01636 
01637                     c->http_error = 200;
01638                     q = c->buffer;
01639                     switch(redir_type) {
01640                     case REDIR_ASX:
01641                         q += snprintf(q, c->buffer_size,
01642                                       "HTTP/1.0 200 ASX Follows\r\n"
01643                                       "Content-type: video/x-ms-asf\r\n"
01644                                       "\r\n"
01645                                       "<ASX Version=\"3\">\r\n"
01646                                       //"<!-- Autogenerated by ffserver -->\r\n"
01647                                       "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
01648                                       "</ASX>\r\n", hostbuf, filename, info);
01649                         break;
01650                     case REDIR_RAM:
01651                         q += snprintf(q, c->buffer_size,
01652                                       "HTTP/1.0 200 RAM Follows\r\n"
01653                                       "Content-type: audio/x-pn-realaudio\r\n"
01654                                       "\r\n"
01655                                       "# Autogenerated by ffserver\r\n"
01656                                       "http://%s/%s%s\r\n", hostbuf, filename, info);
01657                         break;
01658                     case REDIR_ASF:
01659                         q += snprintf(q, c->buffer_size,
01660                                       "HTTP/1.0 200 ASF Redirect follows\r\n"
01661                                       "Content-type: video/x-ms-asf\r\n"
01662                                       "\r\n"
01663                                       "[Reference]\r\n"
01664                                       "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
01665                         break;
01666                     case REDIR_RTSP:
01667                         {
01668                             char hostname[256], *p;
01669                             /* extract only hostname */
01670                             av_strlcpy(hostname, hostbuf, sizeof(hostname));
01671                             p = strrchr(hostname, ':');
01672                             if (p)
01673                                 *p = '\0';
01674                             q += snprintf(q, c->buffer_size,
01675                                           "HTTP/1.0 200 RTSP Redirect follows\r\n"
01676                                           /* XXX: incorrect mime type ? */
01677                                           "Content-type: application/x-rtsp\r\n"
01678                                           "\r\n"
01679                                           "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
01680                         }
01681                         break;
01682                     case REDIR_SDP:
01683                         {
01684                             uint8_t *sdp_data;
01685                             int sdp_data_size, len;
01686                             struct sockaddr_in my_addr;
01687 
01688                             q += snprintf(q, c->buffer_size,
01689                                           "HTTP/1.0 200 OK\r\n"
01690                                           "Content-type: application/sdp\r\n"
01691                                           "\r\n");
01692 
01693                             len = sizeof(my_addr);
01694                             getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
01695 
01696                             /* XXX: should use a dynamic buffer */
01697                             sdp_data_size = prepare_sdp_description(stream,
01698                                                                     &sdp_data,
01699                                                                     my_addr.sin_addr);
01700                             if (sdp_data_size > 0) {
01701                                 memcpy(q, sdp_data, sdp_data_size);
01702                                 q += sdp_data_size;
01703                                 *q = '\0';
01704                                 av_free(sdp_data);
01705                             }
01706                         }
01707                         break;
01708                     default:
01709                         abort();
01710                         break;
01711                     }
01712 
01713                     /* prepare output buffer */
01714                     c->buffer_ptr = c->buffer;
01715                     c->buffer_end = q;
01716                     c->state = HTTPSTATE_SEND_HEADER;
01717                     return 0;
01718                 }
01719             }
01720         }
01721 
01722         snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
01723         goto send_error;
01724     }
01725 
01726     stream->conns_served++;
01727 
01728     /* XXX: add there authenticate and IP match */
01729 
01730     if (c->post) {
01731         /* if post, it means a feed is being sent */
01732         if (!stream->is_feed) {
01733             /* However it might be a status report from WMP! Let us log the
01734              * data as it might come in handy one day. */
01735             char *logline = 0;
01736             int client_id = 0;
01737 
01738             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01739                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
01740                     logline = p;
01741                     break;
01742                 }
01743                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
01744                     client_id = strtol(p + 18, 0, 10);
01745                 p = strchr(p, '\n');
01746                 if (!p)
01747                     break;
01748 
01749                 p++;
01750             }
01751 
01752             if (logline) {
01753                 char *eol = strchr(logline, '\n');
01754 
01755                 logline += 17;
01756 
01757                 if (eol) {
01758                     if (eol[-1] == '\r')
01759                         eol--;
01760                     http_log("%.*s\n", (int) (eol - logline), logline);
01761                     c->suppress_log = 1;
01762                 }
01763             }
01764 
01765 #ifdef DEBUG
01766             http_log("\nGot request:\n%s\n", c->buffer);
01767 #endif
01768 
01769             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
01770                 HTTPContext *wmpc;
01771 
01772                 /* Now we have to find the client_id */
01773                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
01774                     if (wmpc->wmp_client_id == client_id)
01775                         break;
01776                 }
01777 
01778                 if (wmpc && modify_current_stream(wmpc, ratebuf))
01779                     wmpc->switch_pending = 1;
01780             }
01781 
01782             snprintf(msg, sizeof(msg), "POST command not handled");
01783             c->stream = 0;
01784             goto send_error;
01785         }
01786         if (http_start_receive_data(c) < 0) {
01787             snprintf(msg, sizeof(msg), "could not open feed");
01788             goto send_error;
01789         }
01790         c->http_error = 0;
01791         c->state = HTTPSTATE_RECEIVE_DATA;
01792         return 0;
01793     }
01794 
01795 #ifdef DEBUG
01796     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
01797         http_log("\nGot request:\n%s\n", c->buffer);
01798 #endif
01799 
01800     if (c->stream->stream_type == STREAM_TYPE_STATUS)
01801         goto send_status;
01802 
01803     /* open input stream */
01804     if (open_input_stream(c, info) < 0) {
01805         snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
01806         goto send_error;
01807     }
01808 
01809     /* prepare http header */
01810     q = c->buffer;
01811     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
01812     mime_type = c->stream->fmt->mime_type;
01813     if (!mime_type)
01814         mime_type = "application/x-octet-stream";
01815     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
01816 
01817     /* for asf, we need extra headers */
01818     if (!strcmp(c->stream->fmt->name,"asf_stream")) {
01819         /* Need to allocate a client id */
01820 
01821         c->wmp_client_id = av_lfg_get(&random_state);
01822 
01823         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);
01824     }
01825     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
01826     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
01827 
01828     /* prepare output buffer */
01829     c->http_error = 0;
01830     c->buffer_ptr = c->buffer;
01831     c->buffer_end = q;
01832     c->state = HTTPSTATE_SEND_HEADER;
01833     return 0;
01834  send_error:
01835     c->http_error = 404;
01836     q = c->buffer;
01837     q += snprintf(q, c->buffer_size,
01838                   "HTTP/1.0 404 Not Found\r\n"
01839                   "Content-type: text/html\r\n"
01840                   "\r\n"
01841                   "<html>\n"
01842                   "<head><title>404 Not Found</title></head>\n"
01843                   "<body>%s</body>\n"
01844                   "</html>\n", msg);
01845     /* prepare output buffer */
01846     c->buffer_ptr = c->buffer;
01847     c->buffer_end = q;
01848     c->state = HTTPSTATE_SEND_HEADER;
01849     return 0;
01850  send_status:
01851     compute_status(c);
01852     c->http_error = 200; /* horrible : we use this value to avoid
01853                             going to the send data state */
01854     c->state = HTTPSTATE_SEND_HEADER;
01855     return 0;
01856 }
01857 
01858 static void fmt_bytecount(AVIOContext *pb, int64_t count)
01859 {
01860     static const char *suffix = " kMGTP";
01861     const char *s;
01862 
01863     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
01864 
01865     avio_printf(pb, "%"PRId64"%c", count, *s);
01866 }
01867 
01868 static void compute_status(HTTPContext *c)
01869 {
01870     HTTPContext *c1;
01871     FFStream *stream;
01872     char *p;
01873     time_t ti;
01874     int i, len;
01875     AVIOContext *pb;
01876 
01877     if (avio_open_dyn_buf(&pb) < 0) {
01878         /* XXX: return an error ? */
01879         c->buffer_ptr = c->buffer;
01880         c->buffer_end = c->buffer;
01881         return;
01882     }
01883 
01884     avio_printf(pb, "HTTP/1.0 200 OK\r\n");
01885     avio_printf(pb, "Content-type: %s\r\n", "text/html");
01886     avio_printf(pb, "Pragma: no-cache\r\n");
01887     avio_printf(pb, "\r\n");
01888 
01889     avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
01890     if (c->stream->feed_filename[0])
01891         avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
01892     avio_printf(pb, "</head>\n<body>");
01893     avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
01894     /* format status */
01895     avio_printf(pb, "<h2>Available Streams</h2>\n");
01896     avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
01897     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");
01898     stream = first_stream;
01899     while (stream != NULL) {
01900         char sfilename[1024];
01901         char *eosf;
01902 
01903         if (stream->feed != stream) {
01904             av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
01905             eosf = sfilename + strlen(sfilename);
01906             if (eosf - sfilename >= 4) {
01907                 if (strcmp(eosf - 4, ".asf") == 0)
01908                     strcpy(eosf - 4, ".asx");
01909                 else if (strcmp(eosf - 3, ".rm") == 0)
01910                     strcpy(eosf - 3, ".ram");
01911                 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
01912                     /* generate a sample RTSP director if
01913                        unicast. Generate an SDP redirector if
01914                        multicast */
01915                     eosf = strrchr(sfilename, '.');
01916                     if (!eosf)
01917                         eosf = sfilename + strlen(sfilename);
01918                     if (stream->is_multicast)
01919                         strcpy(eosf, ".sdp");
01920                     else
01921                         strcpy(eosf, ".rtsp");
01922                 }
01923             }
01924 
01925             avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
01926                          sfilename, stream->filename);
01927             avio_printf(pb, "<td align=right> %d <td align=right> ",
01928                         stream->conns_served);
01929             fmt_bytecount(pb, stream->bytes_served);
01930             switch(stream->stream_type) {
01931             case STREAM_TYPE_LIVE: {
01932                     int audio_bit_rate = 0;
01933                     int video_bit_rate = 0;
01934                     const char *audio_codec_name = "";
01935                     const char *video_codec_name = "";
01936                     const char *audio_codec_name_extra = "";
01937                     const char *video_codec_name_extra = "";
01938 
01939                     for(i=0;i<stream->nb_streams;i++) {
01940                         AVStream *st = stream->streams[i];
01941                         AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
01942                         switch(st->codec->codec_type) {
01943                         case AVMEDIA_TYPE_AUDIO:
01944                             audio_bit_rate += st->codec->bit_rate;
01945                             if (codec) {
01946                                 if (*audio_codec_name)
01947                                     audio_codec_name_extra = "...";
01948                                 audio_codec_name = codec->name;
01949                             }
01950                             break;
01951                         case AVMEDIA_TYPE_VIDEO:
01952                             video_bit_rate += st->codec->bit_rate;
01953                             if (codec) {
01954                                 if (*video_codec_name)
01955                                     video_codec_name_extra = "...";
01956                                 video_codec_name = codec->name;
01957                             }
01958                             break;
01959                         case AVMEDIA_TYPE_DATA:
01960                             video_bit_rate += st->codec->bit_rate;
01961                             break;
01962                         default:
01963                             abort();
01964                         }
01965                     }
01966                     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",
01967                                  stream->fmt->name,
01968                                  stream->bandwidth,
01969                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
01970                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
01971                     if (stream->feed)
01972                         avio_printf(pb, "<td>%s", stream->feed->filename);
01973                     else
01974                         avio_printf(pb, "<td>%s", stream->feed_filename);
01975                     avio_printf(pb, "\n");
01976                 }
01977                 break;
01978             default:
01979                 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
01980                 break;
01981             }
01982         }
01983         stream = stream->next;
01984     }
01985     avio_printf(pb, "</table>\n");
01986 
01987     stream = first_stream;
01988     while (stream != NULL) {
01989         if (stream->feed == stream) {
01990             avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
01991             if (stream->pid) {
01992                 avio_printf(pb, "Running as pid %d.\n", stream->pid);
01993 
01994 #if defined(linux) && !defined(CONFIG_NOCUTILS)
01995                 {
01996                     FILE *pid_stat;
01997                     char ps_cmd[64];
01998 
01999                     /* This is somewhat linux specific I guess */
02000                     snprintf(ps_cmd, sizeof(ps_cmd),
02001                              "ps -o \"%%cpu,cputime\" --no-headers %d",
02002                              stream->pid);
02003 
02004                     pid_stat = popen(ps_cmd, "r");
02005                     if (pid_stat) {
02006                         char cpuperc[10];
02007                         char cpuused[64];
02008 
02009                         if (fscanf(pid_stat, "%10s %64s", cpuperc,
02010                                    cpuused) == 2) {
02011                             avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
02012                                          cpuperc, cpuused);
02013                         }
02014                         fclose(pid_stat);
02015                     }
02016                 }
02017 #endif
02018 
02019                 avio_printf(pb, "<p>");
02020             }
02021             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");
02022 
02023             for (i = 0; i < stream->nb_streams; i++) {
02024                 AVStream *st = stream->streams[i];
02025                 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
02026                 const char *type = "unknown";
02027                 char parameters[64];
02028 
02029                 parameters[0] = 0;
02030 
02031                 switch(st->codec->codec_type) {
02032                 case AVMEDIA_TYPE_AUDIO:
02033                     type = "audio";
02034                     snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
02035                     break;
02036                 case AVMEDIA_TYPE_VIDEO:
02037                     type = "video";
02038                     snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
02039                                 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
02040                     break;
02041                 default:
02042                     abort();
02043                 }
02044                 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
02045                         i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
02046             }
02047             avio_printf(pb, "</table>\n");
02048 
02049         }
02050         stream = stream->next;
02051     }
02052 
02053     /* connection status */
02054     avio_printf(pb, "<h2>Connection Status</h2>\n");
02055 
02056     avio_printf(pb, "Number of connections: %d / %d<br>\n",
02057                  nb_connections, nb_max_connections);
02058 
02059     avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
02060                  current_bandwidth, max_bandwidth);
02061 
02062     avio_printf(pb, "<table>\n");
02063     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");
02064     c1 = first_http_ctx;
02065     i = 0;
02066     while (c1 != NULL) {
02067         int bitrate;
02068         int j;
02069 
02070         bitrate = 0;
02071         if (c1->stream) {
02072             for (j = 0; j < c1->stream->nb_streams; j++) {
02073                 if (!c1->stream->feed)
02074                     bitrate += c1->stream->streams[j]->codec->bit_rate;
02075                 else if (c1->feed_streams[j] >= 0)
02076                     bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
02077             }
02078         }
02079 
02080         i++;
02081         p = inet_ntoa(c1->from_addr.sin_addr);
02082         avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
02083                     i,
02084                     c1->stream ? c1->stream->filename : "",
02085                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
02086                     p,
02087                     c1->protocol,
02088                     http_state[c1->state]);
02089         fmt_bytecount(pb, bitrate);
02090         avio_printf(pb, "<td align=right>");
02091         fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
02092         avio_printf(pb, "<td align=right>");
02093         fmt_bytecount(pb, c1->data_count);
02094         avio_printf(pb, "\n");
02095         c1 = c1->next;
02096     }
02097     avio_printf(pb, "</table>\n");
02098 
02099     /* date */
02100     ti = time(NULL);
02101     p = ctime(&ti);
02102     avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
02103     avio_printf(pb, "</body>\n</html>\n");
02104 
02105     len = avio_close_dyn_buf(pb, &c->pb_buffer);
02106     c->buffer_ptr = c->pb_buffer;
02107     c->buffer_end = c->pb_buffer + len;
02108 }
02109 
02110 /* check if the parser needs to be opened for stream i */
02111 static void open_parser(AVFormatContext *s, int i)
02112 {
02113     AVStream *st = s->streams[i];
02114     AVCodec *codec;
02115 
02116     if (!st->codec->codec) {
02117         codec = avcodec_find_decoder(st->codec->codec_id);
02118         if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
02119             st->codec->parse_only = 1;
02120             if (avcodec_open2(st->codec, codec, NULL) < 0)
02121                 st->codec->parse_only = 0;
02122         }
02123     }
02124 }
02125 
02126 static int open_input_stream(HTTPContext *c, const char *info)
02127 {
02128     char buf[128];
02129     char input_filename[1024];
02130     AVFormatContext *s = NULL;
02131     int buf_size, i, ret;
02132     int64_t stream_pos;
02133 
02134     /* find file name */
02135     if (c->stream->feed) {
02136         strcpy(input_filename, c->stream->feed->feed_filename);
02137         buf_size = FFM_PACKET_SIZE;
02138         /* compute position (absolute time) */
02139         if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
02140             if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
02141                 return ret;
02142         } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
02143             int prebuffer = strtol(buf, 0, 10);
02144             stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
02145         } else
02146             stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
02147     } else {
02148         strcpy(input_filename, c->stream->feed_filename);
02149         buf_size = 0;
02150         /* compute position (relative time) */
02151         if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
02152             if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
02153                 return ret;
02154         } else
02155             stream_pos = 0;
02156     }
02157     if (input_filename[0] == '\0')
02158         return -1;
02159 
02160     /* open stream */
02161     if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
02162         http_log("could not open %s: %d\n", input_filename, ret);
02163         return -1;
02164     }
02165     s->flags |= AVFMT_FLAG_GENPTS;
02166     c->fmt_in = s;
02167     if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
02168         http_log("Could not find stream info '%s'\n", input_filename);
02169         av_close_input_file(s);
02170         return -1;
02171     }
02172 
02173     /* open each parser */
02174     for(i=0;i<s->nb_streams;i++)
02175         open_parser(s, i);
02176 
02177     /* choose stream as clock source (we favorize video stream if
02178        present) for packet sending */
02179     c->pts_stream_index = 0;
02180     for(i=0;i<c->stream->nb_streams;i++) {
02181         if (c->pts_stream_index == 0 &&
02182             c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
02183             c->pts_stream_index = i;
02184         }
02185     }
02186 
02187     if (c->fmt_in->iformat->read_seek)
02188         av_seek_frame(c->fmt_in, -1, stream_pos, 0);
02189     /* set the start time (needed for maxtime and RTP packet timing) */
02190     c->start_time = cur_time;
02191     c->first_pts = AV_NOPTS_VALUE;
02192     return 0;
02193 }
02194 
02195 /* return the server clock (in us) */
02196 static int64_t get_server_clock(HTTPContext *c)
02197 {
02198     /* compute current pts value from system time */
02199     return (cur_time - c->start_time) * 1000;
02200 }
02201 
02202 /* return the estimated time at which the current packet must be sent
02203    (in us) */
02204 static int64_t get_packet_send_clock(HTTPContext *c)
02205 {
02206     int bytes_left, bytes_sent, frame_bytes;
02207 
02208     frame_bytes = c->cur_frame_bytes;
02209     if (frame_bytes <= 0)
02210         return c->cur_pts;
02211     else {
02212         bytes_left = c->buffer_end - c->buffer_ptr;
02213         bytes_sent = frame_bytes - bytes_left;
02214         return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
02215     }
02216 }
02217 
02218 
02219 static int http_prepare_data(HTTPContext *c)
02220 {
02221     int i, len, ret;
02222     AVFormatContext *ctx;
02223 
02224     av_freep(&c->pb_buffer);
02225     switch(c->state) {
02226     case HTTPSTATE_SEND_DATA_HEADER:
02227         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
02228         av_dict_set(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
02229         av_dict_set(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
02230         av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
02231         av_dict_set(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
02232 
02233         c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
02234 
02235         for(i=0;i<c->stream->nb_streams;i++) {
02236             AVStream *src;
02237             c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
02238             /* if file or feed, then just take streams from FFStream struct */
02239             if (!c->stream->feed ||
02240                 c->stream->feed == c->stream)
02241                 src = c->stream->streams[i];
02242             else
02243                 src = c->stream->feed->streams[c->stream->feed_streams[i]];
02244 
02245             *(c->fmt_ctx.streams[i]) = *src;
02246             c->fmt_ctx.streams[i]->priv_data = 0;
02247             c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
02248                                            AVStream, not in codec */
02249         }
02250         /* set output format parameters */
02251         c->fmt_ctx.oformat = c->stream->fmt;
02252         c->fmt_ctx.nb_streams = c->stream->nb_streams;
02253 
02254         c->got_key_frame = 0;
02255 
02256         /* prepare header and save header data in a stream */
02257         if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
02258             /* XXX: potential leak */
02259             return -1;
02260         }
02261         c->fmt_ctx.pb->seekable = 0;
02262 
02263         /*
02264          * HACK to avoid mpeg ps muxer to spit many underflow errors
02265          * Default value from Libav
02266          * Try to set it use configuration option
02267          */
02268         c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
02269         c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
02270 
02271         if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
02272             http_log("Error writing output header\n");
02273             return -1;
02274         }
02275         av_dict_free(&c->fmt_ctx.metadata);
02276 
02277         len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
02278         c->buffer_ptr = c->pb_buffer;
02279         c->buffer_end = c->pb_buffer + len;
02280 
02281         c->state = HTTPSTATE_SEND_DATA;
02282         c->last_packet_sent = 0;
02283         break;
02284     case HTTPSTATE_SEND_DATA:
02285         /* find a new packet */
02286         /* read a packet from the input stream */
02287         if (c->stream->feed)
02288             ffm_set_write_index(c->fmt_in,
02289                                 c->stream->feed->feed_write_index,
02290                                 c->stream->feed->feed_size);
02291 
02292         if (c->stream->max_time &&
02293             c->stream->max_time + c->start_time - cur_time < 0)
02294             /* We have timed out */
02295             c->state = HTTPSTATE_SEND_DATA_TRAILER;
02296         else {
02297             AVPacket pkt;
02298         redo:
02299             ret = av_read_frame(c->fmt_in, &pkt);
02300             if (ret < 0) {
02301                 if (c->stream->feed) {
02302                     /* if coming from feed, it means we reached the end of the
02303                        ffm file, so must wait for more data */
02304                     c->state = HTTPSTATE_WAIT_FEED;
02305                     return 1; /* state changed */
02306                 } else if (ret == AVERROR(EAGAIN)) {
02307                     /* input not ready, come back later */
02308                     return 0;
02309                 } else {
02310                     if (c->stream->loop) {
02311                         av_close_input_file(c->fmt_in);
02312                         c->fmt_in = NULL;
02313                         if (open_input_stream(c, "") < 0)
02314                             goto no_loop;
02315                         goto redo;
02316                     } else {
02317                     no_loop:
02318                         /* must send trailer now because eof or error */
02319                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
02320                     }
02321                 }
02322             } else {
02323                 int source_index = pkt.stream_index;
02324                 /* update first pts if needed */
02325                 if (c->first_pts == AV_NOPTS_VALUE) {
02326                     c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
02327                     c->start_time = cur_time;
02328                 }
02329                 /* send it to the appropriate stream */
02330                 if (c->stream->feed) {
02331                     /* if coming from a feed, select the right stream */
02332                     if (c->switch_pending) {
02333                         c->switch_pending = 0;
02334                         for(i=0;i<c->stream->nb_streams;i++) {
02335                             if (c->switch_feed_streams[i] == pkt.stream_index)
02336                                 if (pkt.flags & AV_PKT_FLAG_KEY)
02337                                     c->switch_feed_streams[i] = -1;
02338                             if (c->switch_feed_streams[i] >= 0)
02339                                 c->switch_pending = 1;
02340                         }
02341                     }
02342                     for(i=0;i<c->stream->nb_streams;i++) {
02343                         if (c->stream->feed_streams[i] == pkt.stream_index) {
02344                             AVStream *st = c->fmt_in->streams[source_index];
02345                             pkt.stream_index = i;
02346                             if (pkt.flags & AV_PKT_FLAG_KEY &&
02347                                 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
02348                                  c->stream->nb_streams == 1))
02349                                 c->got_key_frame = 1;
02350                             if (!c->stream->send_on_key || c->got_key_frame)
02351                                 goto send_it;
02352                         }
02353                     }
02354                 } else {
02355                     AVCodecContext *codec;
02356                     AVStream *ist, *ost;
02357                 send_it:
02358                     ist = c->fmt_in->streams[source_index];
02359                     /* specific handling for RTP: we use several
02360                        output stream (one for each RTP
02361                        connection). XXX: need more abstract handling */
02362                     if (c->is_packetized) {
02363                         /* compute send time and duration */
02364                         c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
02365                         c->cur_pts -= c->first_pts;
02366                         c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
02367                         /* find RTP context */
02368                         c->packet_stream_index = pkt.stream_index;
02369                         ctx = c->rtp_ctx[c->packet_stream_index];
02370                         if(!ctx) {
02371                             av_free_packet(&pkt);
02372                             break;
02373                         }
02374                         codec = ctx->streams[0]->codec;
02375                         /* only one stream per RTP connection */
02376                         pkt.stream_index = 0;
02377                     } else {
02378                         ctx = &c->fmt_ctx;
02379                         /* Fudge here */
02380                         codec = ctx->streams[pkt.stream_index]->codec;
02381                     }
02382 
02383                     if (c->is_packetized) {
02384                         int max_packet_size;
02385                         if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
02386                             max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
02387                         else
02388                             max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
02389                         ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
02390                     } else {
02391                         ret = avio_open_dyn_buf(&ctx->pb);
02392                     }
02393                     if (ret < 0) {
02394                         /* XXX: potential leak */
02395                         return -1;
02396                     }
02397                     ost = ctx->streams[pkt.stream_index];
02398 
02399                     ctx->pb->seekable = 0;
02400                     if (pkt.dts != AV_NOPTS_VALUE)
02401                         pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
02402                     if (pkt.pts != AV_NOPTS_VALUE)
02403                         pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
02404                     pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
02405                     if (av_write_frame(ctx, &pkt) < 0) {
02406                         http_log("Error writing frame to output\n");
02407                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
02408                     }
02409 
02410                     len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
02411                     c->cur_frame_bytes = len;
02412                     c->buffer_ptr = c->pb_buffer;
02413                     c->buffer_end = c->pb_buffer + len;
02414 
02415                     codec->frame_number++;
02416                     if (len == 0) {
02417                         av_free_packet(&pkt);
02418                         goto redo;
02419                     }
02420                 }
02421                 av_free_packet(&pkt);
02422             }
02423         }
02424         break;
02425     default:
02426     case HTTPSTATE_SEND_DATA_TRAILER:
02427         /* last packet test ? */
02428         if (c->last_packet_sent || c->is_packetized)
02429             return -1;
02430         ctx = &c->fmt_ctx;
02431         /* prepare header */
02432         if (avio_open_dyn_buf(&ctx->pb) < 0) {
02433             /* XXX: potential leak */
02434             return -1;
02435         }
02436         c->fmt_ctx.pb->seekable = 0;
02437         av_write_trailer(ctx);
02438         len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
02439         c->buffer_ptr = c->pb_buffer;
02440         c->buffer_end = c->pb_buffer + len;
02441 
02442         c->last_packet_sent = 1;
02443         break;
02444     }
02445     return 0;
02446 }
02447 
02448 /* should convert the format at the same time */
02449 /* send data starting at c->buffer_ptr to the output connection
02450    (either UDP or TCP connection) */
02451 static int http_send_data(HTTPContext *c)
02452 {
02453     int len, ret;
02454 
02455     for(;;) {
02456         if (c->buffer_ptr >= c->buffer_end) {
02457             ret = http_prepare_data(c);
02458             if (ret < 0)
02459                 return -1;
02460             else if (ret != 0)
02461                 /* state change requested */
02462                 break;
02463         } else {
02464             if (c->is_packetized) {
02465                 /* RTP data output */
02466                 len = c->buffer_end - c->buffer_ptr;
02467                 if (len < 4) {
02468                     /* fail safe - should never happen */
02469                 fail1:
02470                     c->buffer_ptr = c->buffer_end;
02471                     return 0;
02472                 }
02473                 len = (c->buffer_ptr[0] << 24) |
02474                     (c->buffer_ptr[1] << 16) |
02475                     (c->buffer_ptr[2] << 8) |
02476                     (c->buffer_ptr[3]);
02477                 if (len > (c->buffer_end - c->buffer_ptr))
02478                     goto fail1;
02479                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
02480                     /* nothing to send yet: we can wait */
02481                     return 0;
02482                 }
02483 
02484                 c->data_count += len;
02485                 update_datarate(&c->datarate, c->data_count);
02486                 if (c->stream)
02487                     c->stream->bytes_served += len;
02488 
02489                 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
02490                     /* RTP packets are sent inside the RTSP TCP connection */
02491                     AVIOContext *pb;
02492                     int interleaved_index, size;
02493                     uint8_t header[4];
02494                     HTTPContext *rtsp_c;
02495 
02496                     rtsp_c = c->rtsp_c;
02497                     /* if no RTSP connection left, error */
02498                     if (!rtsp_c)
02499                         return -1;
02500                     /* if already sending something, then wait. */
02501                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
02502                         break;
02503                     if (avio_open_dyn_buf(&pb) < 0)
02504                         goto fail1;
02505                     interleaved_index = c->packet_stream_index * 2;
02506                     /* RTCP packets are sent at odd indexes */
02507                     if (c->buffer_ptr[1] == 200)
02508                         interleaved_index++;
02509                     /* write RTSP TCP header */
02510                     header[0] = '$';
02511                     header[1] = interleaved_index;
02512                     header[2] = len >> 8;
02513                     header[3] = len;
02514                     avio_write(pb, header, 4);
02515                     /* write RTP packet data */
02516                     c->buffer_ptr += 4;
02517                     avio_write(pb, c->buffer_ptr, len);
02518                     size = avio_close_dyn_buf(pb, &c->packet_buffer);
02519                     /* prepare asynchronous TCP sending */
02520                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
02521                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
02522                     c->buffer_ptr += len;
02523 
02524                     /* send everything we can NOW */
02525                     len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
02526                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
02527                     if (len > 0)
02528                         rtsp_c->packet_buffer_ptr += len;
02529                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
02530                         /* if we could not send all the data, we will
02531                            send it later, so a new state is needed to
02532                            "lock" the RTSP TCP connection */
02533                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
02534                         break;
02535                     } else
02536                         /* all data has been sent */
02537                         av_freep(&c->packet_buffer);
02538                 } else {
02539                     /* send RTP packet directly in UDP */
02540                     c->buffer_ptr += 4;
02541                     url_write(c->rtp_handles[c->packet_stream_index],
02542                               c->buffer_ptr, len);
02543                     c->buffer_ptr += len;
02544                     /* here we continue as we can send several packets per 10 ms slot */
02545                 }
02546             } else {
02547                 /* TCP data output */
02548                 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
02549                 if (len < 0) {
02550                     if (ff_neterrno() != AVERROR(EAGAIN) &&
02551                         ff_neterrno() != AVERROR(EINTR))
02552                         /* error : close connection */
02553                         return -1;
02554                     else
02555                         return 0;
02556                 } else
02557                     c->buffer_ptr += len;
02558 
02559                 c->data_count += len;
02560                 update_datarate(&c->datarate, c->data_count);
02561                 if (c->stream)
02562                     c->stream->bytes_served += len;
02563                 break;
02564             }
02565         }
02566     } /* for(;;) */
02567     return 0;
02568 }
02569 
02570 static int http_start_receive_data(HTTPContext *c)
02571 {
02572     int fd;
02573 
02574     if (c->stream->feed_opened)
02575         return -1;
02576 
02577     /* Don't permit writing to this one */
02578     if (c->stream->readonly)
02579         return -1;
02580 
02581     /* open feed */
02582     fd = open(c->stream->feed_filename, O_RDWR);
02583     if (fd < 0) {
02584         http_log("Error opening feeder file: %s\n", strerror(errno));
02585         return -1;
02586     }
02587     c->feed_fd = fd;
02588 
02589     if (c->stream->truncate) {
02590         /* truncate feed file */
02591         ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
02592         ftruncate(c->feed_fd, FFM_PACKET_SIZE);
02593         http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
02594     } else {
02595         if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
02596             http_log("Error reading write index from feed file: %s\n", strerror(errno));
02597             return -1;
02598         }
02599     }
02600 
02601     c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
02602     c->stream->feed_size = lseek(fd, 0, SEEK_END);
02603     lseek(fd, 0, SEEK_SET);
02604 
02605     /* init buffer input */
02606     c->buffer_ptr = c->buffer;
02607     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
02608     c->stream->feed_opened = 1;
02609     c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
02610     return 0;
02611 }
02612 
02613 static int http_receive_data(HTTPContext *c)
02614 {
02615     HTTPContext *c1;
02616     int len, loop_run = 0;
02617 
02618     while (c->chunked_encoding && !c->chunk_size &&
02619            c->buffer_end > c->buffer_ptr) {
02620         /* read chunk header, if present */
02621         len = recv(c->fd, c->buffer_ptr, 1, 0);
02622 
02623         if (len < 0) {
02624             if (ff_neterrno() != AVERROR(EAGAIN) &&
02625                 ff_neterrno() != AVERROR(EINTR))
02626                 /* error : close connection */
02627                 goto fail;
02628             return 0;
02629         } else if (len == 0) {
02630             /* end of connection : close it */
02631             goto fail;
02632         } else if (c->buffer_ptr - c->buffer >= 2 &&
02633                    !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
02634             c->chunk_size = strtol(c->buffer, 0, 16);
02635             if (c->chunk_size == 0) // end of stream
02636                 goto fail;
02637             c->buffer_ptr = c->buffer;
02638             break;
02639         } else if (++loop_run > 10) {
02640             /* no chunk header, abort */
02641             goto fail;
02642         } else {
02643             c->buffer_ptr++;
02644         }
02645     }
02646 
02647     if (c->buffer_end > c->buffer_ptr) {
02648         len = recv(c->fd, c->buffer_ptr,
02649                    FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
02650         if (len < 0) {
02651             if (ff_neterrno() != AVERROR(EAGAIN) &&
02652                 ff_neterrno() != AVERROR(EINTR))
02653                 /* error : close connection */
02654                 goto fail;
02655         } else if (len == 0)
02656             /* end of connection : close it */
02657             goto fail;
02658         else {
02659             c->chunk_size -= len;
02660             c->buffer_ptr += len;
02661             c->data_count += len;
02662             update_datarate(&c->datarate, c->data_count);
02663         }
02664     }
02665 
02666     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
02667         if (c->buffer[0] != 'f' ||
02668             c->buffer[1] != 'm') {
02669             http_log("Feed stream has become desynchronized -- disconnecting\n");
02670             goto fail;
02671         }
02672     }
02673 
02674     if (c->buffer_ptr >= c->buffer_end) {
02675         FFStream *feed = c->stream;
02676         /* a packet has been received : write it in the store, except
02677            if header */
02678         if (c->data_count > FFM_PACKET_SIZE) {
02679 
02680             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
02681             /* XXX: use llseek or url_seek */
02682             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
02683             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
02684                 http_log("Error writing to feed file: %s\n", strerror(errno));
02685                 goto fail;
02686             }
02687 
02688             feed->feed_write_index += FFM_PACKET_SIZE;
02689             /* update file size */
02690             if (feed->feed_write_index > c->stream->feed_size)
02691                 feed->feed_size = feed->feed_write_index;
02692 
02693             /* handle wrap around if max file size reached */
02694             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
02695                 feed->feed_write_index = FFM_PACKET_SIZE;
02696 
02697             /* write index */
02698             if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
02699                 http_log("Error writing index to feed file: %s\n", strerror(errno));
02700                 goto fail;
02701             }
02702 
02703             /* wake up any waiting connections */
02704             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
02705                 if (c1->state == HTTPSTATE_WAIT_FEED &&
02706                     c1->stream->feed == c->stream->feed)
02707                     c1->state = HTTPSTATE_SEND_DATA;
02708             }
02709         } else {
02710             /* We have a header in our hands that contains useful data */
02711             AVFormatContext *s = avformat_alloc_context();
02712             AVIOContext *pb;
02713             AVInputFormat *fmt_in;
02714             int i;
02715 
02716             if (!s)
02717                 goto fail;
02718 
02719             /* use feed output format name to find corresponding input format */
02720             fmt_in = av_find_input_format(feed->fmt->name);
02721             if (!fmt_in)
02722                 goto fail;
02723 
02724             pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
02725                                     0, NULL, NULL, NULL, NULL);
02726             pb->seekable = 0;
02727 
02728             s->pb = pb;
02729             if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
02730                 av_free(pb);
02731                 goto fail;
02732             }
02733 
02734             /* Now we have the actual streams */
02735             if (s->nb_streams != feed->nb_streams) {
02736                 av_close_input_stream(s);
02737                 av_free(pb);
02738                 http_log("Feed '%s' stream number does not match registered feed\n",
02739                          c->stream->feed_filename);
02740                 goto fail;
02741             }
02742 
02743             for (i = 0; i < s->nb_streams; i++) {
02744                 AVStream *fst = feed->streams[i];
02745                 AVStream *st = s->streams[i];
02746                 avcodec_copy_context(fst->codec, st->codec);
02747             }
02748 
02749             av_close_input_stream(s);
02750             av_free(pb);
02751         }
02752         c->buffer_ptr = c->buffer;
02753     }
02754 
02755     return 0;
02756  fail:
02757     c->stream->feed_opened = 0;
02758     close(c->feed_fd);
02759     /* wake up any waiting connections to stop waiting for feed */
02760     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
02761         if (c1->state == HTTPSTATE_WAIT_FEED &&
02762             c1->stream->feed == c->stream->feed)
02763             c1->state = HTTPSTATE_SEND_DATA_TRAILER;
02764     }
02765     return -1;
02766 }
02767 
02768 /********************************************************************/
02769 /* RTSP handling */
02770 
02771 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
02772 {
02773     const char *str;
02774     time_t ti;
02775     struct tm *tm;
02776     char buf2[32];
02777 
02778     switch(error_number) {
02779     case RTSP_STATUS_OK:
02780         str = "OK";
02781         break;
02782     case RTSP_STATUS_METHOD:
02783         str = "Method Not Allowed";
02784         break;
02785     case RTSP_STATUS_BANDWIDTH:
02786         str = "Not Enough Bandwidth";
02787         break;
02788     case RTSP_STATUS_SESSION:
02789         str = "Session Not Found";
02790         break;
02791     case RTSP_STATUS_STATE:
02792         str = "Method Not Valid in This State";
02793         break;
02794     case RTSP_STATUS_AGGREGATE:
02795         str = "Aggregate operation not allowed";
02796         break;
02797     case RTSP_STATUS_ONLY_AGGREGATE:
02798         str = "Only aggregate operation allowed";
02799         break;
02800     case RTSP_STATUS_TRANSPORT:
02801         str = "Unsupported transport";
02802         break;
02803     case RTSP_STATUS_INTERNAL:
02804         str = "Internal Server Error";
02805         break;
02806     case RTSP_STATUS_SERVICE:
02807         str = "Service Unavailable";
02808         break;
02809     case RTSP_STATUS_VERSION:
02810         str = "RTSP Version not supported";
02811         break;
02812     default:
02813         str = "Unknown Error";
02814         break;
02815     }
02816 
02817     avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
02818     avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
02819 
02820     /* output GMT time */
02821     ti = time(NULL);
02822     tm = gmtime(&ti);
02823     strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
02824     avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
02825 }
02826 
02827 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
02828 {
02829     rtsp_reply_header(c, error_number);
02830     avio_printf(c->pb, "\r\n");
02831 }
02832 
02833 static int rtsp_parse_request(HTTPContext *c)
02834 {
02835     const char *p, *p1, *p2;
02836     char cmd[32];
02837     char url[1024];
02838     char protocol[32];
02839     char line[1024];
02840     int len;
02841     RTSPMessageHeader header1, *header = &header1;
02842 
02843     c->buffer_ptr[0] = '\0';
02844     p = c->buffer;
02845 
02846     get_word(cmd, sizeof(cmd), &p);
02847     get_word(url, sizeof(url), &p);
02848     get_word(protocol, sizeof(protocol), &p);
02849 
02850     av_strlcpy(c->method, cmd, sizeof(c->method));
02851     av_strlcpy(c->url, url, sizeof(c->url));
02852     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
02853 
02854     if (avio_open_dyn_buf(&c->pb) < 0) {
02855         /* XXX: cannot do more */
02856         c->pb = NULL; /* safety */
02857         return -1;
02858     }
02859 
02860     /* check version name */
02861     if (strcmp(protocol, "RTSP/1.0") != 0) {
02862         rtsp_reply_error(c, RTSP_STATUS_VERSION);
02863         goto the_end;
02864     }
02865 
02866     /* parse each header line */
02867     memset(header, 0, sizeof(*header));
02868     /* skip to next line */
02869     while (*p != '\n' && *p != '\0')
02870         p++;
02871     if (*p == '\n')
02872         p++;
02873     while (*p != '\0') {
02874         p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
02875         if (!p1)
02876             break;
02877         p2 = p1;
02878         if (p2 > p && p2[-1] == '\r')
02879             p2--;
02880         /* skip empty line */
02881         if (p2 == p)
02882             break;
02883         len = p2 - p;
02884         if (len > sizeof(line) - 1)
02885             len = sizeof(line) - 1;
02886         memcpy(line, p, len);
02887         line[len] = '\0';
02888         ff_rtsp_parse_line(header, line, NULL, NULL);
02889         p = p1 + 1;
02890     }
02891 
02892     /* handle sequence number */
02893     c->seq = header->seq;
02894 
02895     if (!strcmp(cmd, "DESCRIBE"))
02896         rtsp_cmd_describe(c, url);
02897     else if (!strcmp(cmd, "OPTIONS"))
02898         rtsp_cmd_options(c, url);
02899     else if (!strcmp(cmd, "SETUP"))
02900         rtsp_cmd_setup(c, url, header);
02901     else if (!strcmp(cmd, "PLAY"))
02902         rtsp_cmd_play(c, url, header);
02903     else if (!strcmp(cmd, "PAUSE"))
02904         rtsp_cmd_pause(c, url, header);
02905     else if (!strcmp(cmd, "TEARDOWN"))
02906         rtsp_cmd_teardown(c, url, header);
02907     else
02908         rtsp_reply_error(c, RTSP_STATUS_METHOD);
02909 
02910  the_end:
02911     len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
02912     c->pb = NULL; /* safety */
02913     if (len < 0) {
02914         /* XXX: cannot do more */
02915         return -1;
02916     }
02917     c->buffer_ptr = c->pb_buffer;
02918     c->buffer_end = c->pb_buffer + len;
02919     c->state = RTSPSTATE_SEND_REPLY;
02920     return 0;
02921 }
02922 
02923 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
02924                                    struct in_addr my_ip)
02925 {
02926     AVFormatContext *avc;
02927     AVStream *avs = NULL;
02928     int i;
02929 
02930     avc =  avformat_alloc_context();
02931     if (avc == NULL) {
02932         return -1;
02933     }
02934     av_dict_set(&avc->metadata, "title",
02935                stream->title[0] ? stream->title : "No Title", 0);
02936     avc->nb_streams = stream->nb_streams;
02937     if (stream->is_multicast) {
02938         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
02939                  inet_ntoa(stream->multicast_ip),
02940                  stream->multicast_port, stream->multicast_ttl);
02941     } else {
02942         snprintf(avc->filename, 1024, "rtp://0.0.0.0");
02943     }
02944 
02945     if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
02946         !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
02947         goto sdp_done;
02948     if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
02949         !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
02950         goto sdp_done;
02951 
02952     for(i = 0; i < stream->nb_streams; i++) {
02953         avc->streams[i] = &avs[i];
02954         avc->streams[i]->codec = stream->streams[i]->codec;
02955     }
02956     *pbuffer = av_mallocz(2048);
02957     av_sdp_create(&avc, 1, *pbuffer, 2048);
02958 
02959  sdp_done:
02960     av_free(avc->streams);
02961     av_dict_free(&avc->metadata);
02962     av_free(avc);
02963     av_free(avs);
02964 
02965     return strlen(*pbuffer);
02966 }
02967 
02968 static void rtsp_cmd_options(HTTPContext *c, const char *url)
02969 {
02970 //    rtsp_reply_header(c, RTSP_STATUS_OK);
02971     avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
02972     avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
02973     avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
02974     avio_printf(c->pb, "\r\n");
02975 }
02976 
02977 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
02978 {
02979     FFStream *stream;
02980     char path1[1024];
02981     const char *path;
02982     uint8_t *content;
02983     int content_length, len;
02984     struct sockaddr_in my_addr;
02985 
02986     /* find which url is asked */
02987     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
02988     path = path1;
02989     if (*path == '/')
02990         path++;
02991 
02992     for(stream = first_stream; stream != NULL; stream = stream->next) {
02993         if (!stream->is_feed &&
02994             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
02995             !strcmp(path, stream->filename)) {
02996             goto found;
02997         }
02998     }
02999     /* no stream found */
03000     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
03001     return;
03002 
03003  found:
03004     /* prepare the media description in sdp format */
03005 
03006     /* get the host IP */
03007     len = sizeof(my_addr);
03008     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
03009     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
03010     if (content_length < 0) {
03011         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
03012         return;
03013     }
03014     rtsp_reply_header(c, RTSP_STATUS_OK);
03015     avio_printf(c->pb, "Content-Base: %s/\r\n", url);
03016     avio_printf(c->pb, "Content-Type: application/sdp\r\n");
03017     avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
03018     avio_printf(c->pb, "\r\n");
03019     avio_write(c->pb, content, content_length);
03020     av_free(content);
03021 }
03022 
03023 static HTTPContext *find_rtp_session(const char *session_id)
03024 {
03025     HTTPContext *c;
03026 
03027     if (session_id[0] == '\0')
03028         return NULL;
03029 
03030     for(c = first_http_ctx; c != NULL; c = c->next) {
03031         if (!strcmp(c->session_id, session_id))
03032             return c;
03033     }
03034     return NULL;
03035 }
03036 
03037 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
03038 {
03039     RTSPTransportField *th;
03040     int i;
03041 
03042     for(i=0;i<h->nb_transports;i++) {
03043         th = &h->transports[i];
03044         if (th->lower_transport == lower_transport)
03045             return th;
03046     }
03047     return NULL;
03048 }
03049 
03050 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
03051                            RTSPMessageHeader *h)
03052 {
03053     FFStream *stream;
03054     int stream_index, rtp_port, rtcp_port;
03055     char buf[1024];
03056     char path1[1024];
03057     const char *path;
03058     HTTPContext *rtp_c;
03059     RTSPTransportField *th;
03060     struct sockaddr_in dest_addr;
03061     RTSPActionServerSetup setup;
03062 
03063     /* find which url is asked */
03064     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03065     path = path1;
03066     if (*path == '/')
03067         path++;
03068 
03069     /* now check each stream */
03070     for(stream = first_stream; stream != NULL; stream = stream->next) {
03071         if (!stream->is_feed &&
03072             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
03073             /* accept aggregate filenames only if single stream */
03074             if (!strcmp(path, stream->filename)) {
03075                 if (stream->nb_streams != 1) {
03076                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
03077                     return;
03078                 }
03079                 stream_index = 0;
03080                 goto found;
03081             }
03082 
03083             for(stream_index = 0; stream_index < stream->nb_streams;
03084                 stream_index++) {
03085                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
03086                          stream->filename, stream_index);
03087                 if (!strcmp(path, buf))
03088                     goto found;
03089             }
03090         }
03091     }
03092     /* no stream found */
03093     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
03094     return;
03095  found:
03096 
03097     /* generate session id if needed */
03098     if (h->session_id[0] == '\0')
03099         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
03100                  av_lfg_get(&random_state), av_lfg_get(&random_state));
03101 
03102     /* find rtp session, and create it if none found */
03103     rtp_c = find_rtp_session(h->session_id);
03104     if (!rtp_c) {
03105         /* always prefer UDP */
03106         th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
03107         if (!th) {
03108             th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
03109             if (!th) {
03110                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03111                 return;
03112             }
03113         }
03114 
03115         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
03116                                    th->lower_transport);
03117         if (!rtp_c) {
03118             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
03119             return;
03120         }
03121 
03122         /* open input stream */
03123         if (open_input_stream(rtp_c, "") < 0) {
03124             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
03125             return;
03126         }
03127     }
03128 
03129     /* test if stream is OK (test needed because several SETUP needs
03130        to be done for a given file) */
03131     if (rtp_c->stream != stream) {
03132         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
03133         return;
03134     }
03135 
03136     /* test if stream is already set up */
03137     if (rtp_c->rtp_ctx[stream_index]) {
03138         rtsp_reply_error(c, RTSP_STATUS_STATE);
03139         return;
03140     }
03141 
03142     /* check transport */
03143     th = find_transport(h, rtp_c->rtp_protocol);
03144     if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
03145                 th->client_port_min <= 0)) {
03146         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03147         return;
03148     }
03149 
03150     /* setup default options */
03151     setup.transport_option[0] = '\0';
03152     dest_addr = rtp_c->from_addr;
03153     dest_addr.sin_port = htons(th->client_port_min);
03154 
03155     /* setup stream */
03156     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
03157         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03158         return;
03159     }
03160 
03161     /* now everything is OK, so we can send the connection parameters */
03162     rtsp_reply_header(c, RTSP_STATUS_OK);
03163     /* session ID */
03164     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03165 
03166     switch(rtp_c->rtp_protocol) {
03167     case RTSP_LOWER_TRANSPORT_UDP:
03168         rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
03169         rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
03170         avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
03171                     "client_port=%d-%d;server_port=%d-%d",
03172                     th->client_port_min, th->client_port_max,
03173                     rtp_port, rtcp_port);
03174         break;
03175     case RTSP_LOWER_TRANSPORT_TCP:
03176         avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
03177                     stream_index * 2, stream_index * 2 + 1);
03178         break;
03179     default:
03180         break;
03181     }
03182     if (setup.transport_option[0] != '\0')
03183         avio_printf(c->pb, ";%s", setup.transport_option);
03184     avio_printf(c->pb, "\r\n");
03185 
03186 
03187     avio_printf(c->pb, "\r\n");
03188 }
03189 
03190 
03191 /* find an rtp connection by using the session ID. Check consistency
03192    with filename */
03193 static HTTPContext *find_rtp_session_with_url(const char *url,
03194                                               const char *session_id)
03195 {
03196     HTTPContext *rtp_c;
03197     char path1[1024];
03198     const char *path;
03199     char buf[1024];
03200     int s, len;
03201 
03202     rtp_c = find_rtp_session(session_id);
03203     if (!rtp_c)
03204         return NULL;
03205 
03206     /* find which url is asked */
03207     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03208     path = path1;
03209     if (*path == '/')
03210         path++;
03211     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
03212     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
03213       snprintf(buf, sizeof(buf), "%s/streamid=%d",
03214         rtp_c->stream->filename, s);
03215       if(!strncmp(path, buf, sizeof(buf))) {
03216     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
03217         return rtp_c;
03218       }
03219     }
03220     len = strlen(path);
03221     if (len > 0 && path[len - 1] == '/' &&
03222         !strncmp(path, rtp_c->stream->filename, len - 1))
03223         return rtp_c;
03224     return NULL;
03225 }
03226 
03227 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03228 {
03229     HTTPContext *rtp_c;
03230 
03231     rtp_c = find_rtp_session_with_url(url, h->session_id);
03232     if (!rtp_c) {
03233         rtsp_reply_error(c, RTSP_STATUS_SESSION);
03234         return;
03235     }
03236 
03237     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
03238         rtp_c->state != HTTPSTATE_WAIT_FEED &&
03239         rtp_c->state != HTTPSTATE_READY) {
03240         rtsp_reply_error(c, RTSP_STATUS_STATE);
03241         return;
03242     }
03243 
03244     rtp_c->state = HTTPSTATE_SEND_DATA;
03245 
03246     /* now everything is OK, so we can send the connection parameters */
03247     rtsp_reply_header(c, RTSP_STATUS_OK);
03248     /* session ID */
03249     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03250     avio_printf(c->pb, "\r\n");
03251 }
03252 
03253 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03254 {
03255     HTTPContext *rtp_c;
03256 
03257     rtp_c = find_rtp_session_with_url(url, h->session_id);
03258     if (!rtp_c) {
03259         rtsp_reply_error(c, RTSP_STATUS_SESSION);
03260         return;
03261     }
03262 
03263     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
03264         rtp_c->state != HTTPSTATE_WAIT_FEED) {
03265         rtsp_reply_error(c, RTSP_STATUS_STATE);
03266         return;
03267     }
03268 
03269     rtp_c->state = HTTPSTATE_READY;
03270     rtp_c->first_pts = AV_NOPTS_VALUE;
03271     /* now everything is OK, so we can send the connection parameters */
03272     rtsp_reply_header(c, RTSP_STATUS_OK);
03273     /* session ID */
03274     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03275     avio_printf(c->pb, "\r\n");
03276 }
03277 
03278 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03279 {
03280     HTTPContext *rtp_c;
03281 
03282     rtp_c = find_rtp_session_with_url(url, h->session_id);
03283     if (!rtp_c) {
03284         rtsp_reply_error(c, RTSP_STATUS_SESSION);
03285         return;
03286     }
03287 
03288     /* now everything is OK, so we can send the connection parameters */
03289     rtsp_reply_header(c, RTSP_STATUS_OK);
03290     /* session ID */
03291     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03292     avio_printf(c->pb, "\r\n");
03293 
03294     /* abort the session */
03295     close_connection(rtp_c);
03296 }
03297 
03298 
03299 /********************************************************************/
03300 /* RTP handling */
03301 
03302 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
03303                                        FFStream *stream, const char *session_id,
03304                                        enum RTSPLowerTransport rtp_protocol)
03305 {
03306     HTTPContext *c = NULL;
03307     const char *proto_str;
03308 
03309     /* XXX: should output a warning page when coming
03310        close to the connection limit */
03311     if (nb_connections >= nb_max_connections)
03312         goto fail;
03313 
03314     /* add a new connection */
03315     c = av_mallocz(sizeof(HTTPContext));
03316     if (!c)
03317         goto fail;
03318 
03319     c->fd = -1;
03320     c->poll_entry = NULL;
03321     c->from_addr = *from_addr;
03322     c->buffer_size = IOBUFFER_INIT_SIZE;
03323     c->buffer = av_malloc(c->buffer_size);
03324     if (!c->buffer)
03325         goto fail;
03326     nb_connections++;
03327     c->stream = stream;
03328     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
03329     c->state = HTTPSTATE_READY;
03330     c->is_packetized = 1;
03331     c->rtp_protocol = rtp_protocol;
03332 
03333     /* protocol is shown in statistics */
03334     switch(c->rtp_protocol) {
03335     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
03336         proto_str = "MCAST";
03337         break;
03338     case RTSP_LOWER_TRANSPORT_UDP:
03339         proto_str = "UDP";
03340         break;
03341     case RTSP_LOWER_TRANSPORT_TCP:
03342         proto_str = "TCP";
03343         break;
03344     default:
03345         proto_str = "???";
03346         break;
03347     }
03348     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
03349     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
03350 
03351     current_bandwidth += stream->bandwidth;
03352 
03353     c->next = first_http_ctx;
03354     first_http_ctx = c;
03355     return c;
03356 
03357  fail:
03358     if (c) {
03359         av_free(c->buffer);
03360         av_free(c);
03361     }
03362     return NULL;
03363 }
03364 
03365 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
03366    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
03367    used. */
03368 static int rtp_new_av_stream(HTTPContext *c,
03369                              int stream_index, struct sockaddr_in *dest_addr,
03370                              HTTPContext *rtsp_c)
03371 {
03372     AVFormatContext *ctx;
03373     AVStream *st;
03374     char *ipaddr;
03375     URLContext *h = NULL;
03376     uint8_t *dummy_buf;
03377     int max_packet_size;
03378 
03379     /* now we can open the relevant output stream */
03380     ctx = avformat_alloc_context();
03381     if (!ctx)
03382         return -1;
03383     ctx->oformat = av_guess_format("rtp", NULL, NULL);
03384 
03385     st = av_mallocz(sizeof(AVStream));
03386     if (!st)
03387         goto fail;
03388     ctx->nb_streams = 1;
03389     ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
03390     if (!ctx->streams)
03391       goto fail;
03392     ctx->streams[0] = st;
03393 
03394     if (!c->stream->feed ||
03395         c->stream->feed == c->stream)
03396         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
03397     else
03398         memcpy(st,
03399                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
03400                sizeof(AVStream));
03401     st->priv_data = NULL;
03402 
03403     /* build destination RTP address */
03404     ipaddr = inet_ntoa(dest_addr->sin_addr);
03405 
03406     switch(c->rtp_protocol) {
03407     case RTSP_LOWER_TRANSPORT_UDP:
03408     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
03409         /* RTP/UDP case */
03410 
03411         /* XXX: also pass as parameter to function ? */
03412         if (c->stream->is_multicast) {
03413             int ttl;
03414             ttl = c->stream->multicast_ttl;
03415             if (!ttl)
03416                 ttl = 16;
03417             snprintf(ctx->filename, sizeof(ctx->filename),
03418                      "rtp://%s:%d?multicast=1&ttl=%d",
03419                      ipaddr, ntohs(dest_addr->sin_port), ttl);
03420         } else {
03421             snprintf(ctx->filename, sizeof(ctx->filename),
03422                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
03423         }
03424 
03425         if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
03426             goto fail;
03427         c->rtp_handles[stream_index] = h;
03428         max_packet_size = url_get_max_packet_size(h);
03429         break;
03430     case RTSP_LOWER_TRANSPORT_TCP:
03431         /* RTP/TCP case */
03432         c->rtsp_c = rtsp_c;
03433         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
03434         break;
03435     default:
03436         goto fail;
03437     }
03438 
03439     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
03440              ipaddr, ntohs(dest_addr->sin_port),
03441              c->stream->filename, stream_index, c->protocol);
03442 
03443     /* normally, no packets should be output here, but the packet size may be checked */
03444     if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
03445         /* XXX: close stream */
03446         goto fail;
03447     }
03448     if (avformat_write_header(ctx, NULL) < 0) {
03449     fail:
03450         if (h)
03451             url_close(h);
03452         av_free(ctx);
03453         return -1;
03454     }
03455     avio_close_dyn_buf(ctx->pb, &dummy_buf);
03456     av_free(dummy_buf);
03457 
03458     c->rtp_ctx[stream_index] = ctx;
03459     return 0;
03460 }
03461 
03462 /********************************************************************/
03463 /* ffserver initialization */
03464 
03465 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
03466 {
03467     AVStream *fst;
03468 
03469     fst = av_mallocz(sizeof(AVStream));
03470     if (!fst)
03471         return NULL;
03472     if (copy) {
03473         fst->codec= avcodec_alloc_context();
03474         memcpy(fst->codec, codec, sizeof(AVCodecContext));
03475         if (codec->extradata_size) {
03476             fst->codec->extradata = av_malloc(codec->extradata_size);
03477             memcpy(fst->codec->extradata, codec->extradata,
03478                 codec->extradata_size);
03479         }
03480     } else {
03481         /* live streams must use the actual feed's codec since it may be
03482          * updated later to carry extradata needed by the streams.
03483          */
03484         fst->codec = codec;
03485     }
03486     fst->priv_data = av_mallocz(sizeof(FeedData));
03487     fst->index = stream->nb_streams;
03488     av_set_pts_info(fst, 33, 1, 90000);
03489     fst->sample_aspect_ratio = codec->sample_aspect_ratio;
03490     stream->streams[stream->nb_streams++] = fst;
03491     return fst;
03492 }
03493 
03494 /* return the stream number in the feed */
03495 static int add_av_stream(FFStream *feed, AVStream *st)
03496 {
03497     AVStream *fst;
03498     AVCodecContext *av, *av1;
03499     int i;
03500 
03501     av = st->codec;
03502     for(i=0;i<feed->nb_streams;i++) {
03503         st = feed->streams[i];
03504         av1 = st->codec;
03505         if (av1->codec_id == av->codec_id &&
03506             av1->codec_type == av->codec_type &&
03507             av1->bit_rate == av->bit_rate) {
03508 
03509             switch(av->codec_type) {
03510             case AVMEDIA_TYPE_AUDIO:
03511                 if (av1->channels == av->channels &&
03512                     av1->sample_rate == av->sample_rate)
03513                     goto found;
03514                 break;
03515             case AVMEDIA_TYPE_VIDEO:
03516                 if (av1->width == av->width &&
03517                     av1->height == av->height &&
03518                     av1->time_base.den == av->time_base.den &&
03519                     av1->time_base.num == av->time_base.num &&
03520                     av1->gop_size == av->gop_size)
03521                     goto found;
03522                 break;
03523             default:
03524                 abort();
03525             }
03526         }
03527     }
03528 
03529     fst = add_av_stream1(feed, av, 0);
03530     if (!fst)
03531         return -1;
03532     return feed->nb_streams - 1;
03533  found:
03534     return i;
03535 }
03536 
03537 static void remove_stream(FFStream *stream)
03538 {
03539     FFStream **ps;
03540     ps = &first_stream;
03541     while (*ps != NULL) {
03542         if (*ps == stream)
03543             *ps = (*ps)->next;
03544         else
03545             ps = &(*ps)->next;
03546     }
03547 }
03548 
03549 /* specific mpeg4 handling : we extract the raw parameters */
03550 static void extract_mpeg4_header(AVFormatContext *infile)
03551 {
03552     int mpeg4_count, i, size;
03553     AVPacket pkt;
03554     AVStream *st;
03555     const uint8_t *p;
03556 
03557     mpeg4_count = 0;
03558     for(i=0;i<infile->nb_streams;i++) {
03559         st = infile->streams[i];
03560         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
03561             st->codec->extradata_size == 0) {
03562             mpeg4_count++;
03563         }
03564     }
03565     if (!mpeg4_count)
03566         return;
03567 
03568     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
03569     while (mpeg4_count > 0) {
03570         if (av_read_packet(infile, &pkt) < 0)
03571             break;
03572         st = infile->streams[pkt.stream_index];
03573         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
03574             st->codec->extradata_size == 0) {
03575             av_freep(&st->codec->extradata);
03576             /* fill extradata with the header */
03577             /* XXX: we make hard suppositions here ! */
03578             p = pkt.data;
03579             while (p < pkt.data + pkt.size - 4) {
03580                 /* stop when vop header is found */
03581                 if (p[0] == 0x00 && p[1] == 0x00 &&
03582                     p[2] == 0x01 && p[3] == 0xb6) {
03583                     size = p - pkt.data;
03584                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
03585                     st->codec->extradata = av_malloc(size);
03586                     st->codec->extradata_size = size;
03587                     memcpy(st->codec->extradata, pkt.data, size);
03588                     break;
03589                 }
03590                 p++;
03591             }
03592             mpeg4_count--;
03593         }
03594         av_free_packet(&pkt);
03595     }
03596 }
03597 
03598 /* compute the needed AVStream for each file */
03599 static void build_file_streams(void)
03600 {
03601     FFStream *stream, *stream_next;
03602     int i, ret;
03603 
03604     /* gather all streams */
03605     for(stream = first_stream; stream != NULL; stream = stream_next) {
03606         AVFormatContext *infile = NULL;
03607         stream_next = stream->next;
03608         if (stream->stream_type == STREAM_TYPE_LIVE &&
03609             !stream->feed) {
03610             /* the stream comes from a file */
03611             /* try to open the file */
03612             /* open stream */
03613             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
03614                 /* specific case : if transport stream output to RTP,
03615                    we use a raw transport stream reader */
03616                 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
03617             }
03618 
03619             http_log("Opening file '%s'\n", stream->feed_filename);
03620             if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
03621                 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
03622                 /* remove stream (no need to spend more time on it) */
03623             fail:
03624                 remove_stream(stream);
03625             } else {
03626                 /* find all the AVStreams inside and reference them in
03627                    'stream' */
03628                 if (av_find_stream_info(infile) < 0) {
03629                     http_log("Could not find codec parameters from '%s'\n",
03630                              stream->feed_filename);
03631                     av_close_input_file(infile);
03632                     goto fail;
03633                 }
03634                 extract_mpeg4_header(infile);
03635 
03636                 for(i=0;i<infile->nb_streams;i++)
03637                     add_av_stream1(stream, infile->streams[i]->codec, 1);
03638 
03639                 av_close_input_file(infile);
03640             }
03641         }
03642     }
03643 }
03644 
03645 /* compute the needed AVStream for each feed */
03646 static void build_feed_streams(void)
03647 {
03648     FFStream *stream, *feed;
03649     int i;
03650 
03651     /* gather all streams */
03652     for(stream = first_stream; stream != NULL; stream = stream->next) {
03653         feed = stream->feed;
03654         if (feed) {
03655             if (!stream->is_feed) {
03656                 /* we handle a stream coming from a feed */
03657                 for(i=0;i<stream->nb_streams;i++)
03658                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
03659             }
03660         }
03661     }
03662 
03663     /* gather all streams */
03664     for(stream = first_stream; stream != NULL; stream = stream->next) {
03665         feed = stream->feed;
03666         if (feed) {
03667             if (stream->is_feed) {
03668                 for(i=0;i<stream->nb_streams;i++)
03669                     stream->feed_streams[i] = i;
03670             }
03671         }
03672     }
03673 
03674     /* create feed files if needed */
03675     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
03676         int fd;
03677 
03678         if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
03679             /* See if it matches */
03680             AVFormatContext *s = NULL;
03681             int matches = 0;
03682 
03683             if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
03684                 /* Now see if it matches */
03685                 if (s->nb_streams == feed->nb_streams) {
03686                     matches = 1;
03687                     for(i=0;i<s->nb_streams;i++) {
03688                         AVStream *sf, *ss;
03689                         sf = feed->streams[i];
03690                         ss = s->streams[i];
03691 
03692                         if (sf->index != ss->index ||
03693                             sf->id != ss->id) {
03694                             http_log("Index & Id do not match for stream %d (%s)\n",
03695                                    i, feed->feed_filename);
03696                             matches = 0;
03697                         } else {
03698                             AVCodecContext *ccf, *ccs;
03699 
03700                             ccf = sf->codec;
03701                             ccs = ss->codec;
03702 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
03703 
03704                             if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
03705                                 http_log("Codecs do not match for stream %d\n", i);
03706                                 matches = 0;
03707                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
03708                                 http_log("Codec bitrates do not match for stream %d\n", i);
03709                                 matches = 0;
03710                             } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
03711                                 if (CHECK_CODEC(time_base.den) ||
03712                                     CHECK_CODEC(time_base.num) ||
03713                                     CHECK_CODEC(width) ||
03714                                     CHECK_CODEC(height)) {
03715                                     http_log("Codec width, height and framerate do not match for stream %d\n", i);
03716                                     matches = 0;
03717                                 }
03718                             } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
03719                                 if (CHECK_CODEC(sample_rate) ||
03720                                     CHECK_CODEC(channels) ||
03721                                     CHECK_CODEC(frame_size)) {
03722                                     http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
03723                                     matches = 0;
03724                                 }
03725                             } else {
03726                                 http_log("Unknown codec type\n");
03727                                 matches = 0;
03728                             }
03729                         }
03730                         if (!matches)
03731                             break;
03732                     }
03733                 } else
03734                     http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
03735                         feed->feed_filename, s->nb_streams, feed->nb_streams);
03736 
03737                 av_close_input_file(s);
03738             } else
03739                 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
03740                         feed->feed_filename);
03741 
03742             if (!matches) {
03743                 if (feed->readonly) {
03744                     http_log("Unable to delete feed file '%s' as it is marked readonly\n",
03745                         feed->feed_filename);
03746                     exit(1);
03747                 }
03748                 unlink(feed->feed_filename);
03749             }
03750         }
03751         if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
03752             AVFormatContext s1 = {0}, *s = &s1;
03753 
03754             if (feed->readonly) {
03755                 http_log("Unable to create feed file '%s' as it is marked readonly\n",
03756                     feed->feed_filename);
03757                 exit(1);
03758             }
03759 
03760             /* only write the header of the ffm file */
03761             if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
03762                 http_log("Could not open output feed file '%s'\n",
03763                          feed->feed_filename);
03764                 exit(1);
03765             }
03766             s->oformat = feed->fmt;
03767             s->nb_streams = feed->nb_streams;
03768             s->streams = feed->streams;
03769             if (avformat_write_header(s, NULL) < 0) {
03770                 http_log("Container doesn't supports the required parameters\n");
03771                 exit(1);
03772             }
03773             /* XXX: need better api */
03774             av_freep(&s->priv_data);
03775             avio_close(s->pb);
03776         }
03777         /* get feed size and write index */
03778         fd = open(feed->feed_filename, O_RDONLY);
03779         if (fd < 0) {
03780             http_log("Could not open output feed file '%s'\n",
03781                     feed->feed_filename);
03782             exit(1);
03783         }
03784 
03785         feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
03786         feed->feed_size = lseek(fd, 0, SEEK_END);
03787         /* ensure that we do not wrap before the end of file */
03788         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
03789             feed->feed_max_size = feed->feed_size;
03790 
03791         close(fd);
03792     }
03793 }
03794 
03795 /* compute the bandwidth used by each stream */
03796 static void compute_bandwidth(void)
03797 {
03798     unsigned bandwidth;
03799     int i;
03800     FFStream *stream;
03801 
03802     for(stream = first_stream; stream != NULL; stream = stream->next) {
03803         bandwidth = 0;
03804         for(i=0;i<stream->nb_streams;i++) {
03805             AVStream *st = stream->streams[i];
03806             switch(st->codec->codec_type) {
03807             case AVMEDIA_TYPE_AUDIO:
03808             case AVMEDIA_TYPE_VIDEO:
03809                 bandwidth += st->codec->bit_rate;
03810                 break;
03811             default:
03812                 break;
03813             }
03814         }
03815         stream->bandwidth = (bandwidth + 999) / 1000;
03816     }
03817 }
03818 
03819 /* add a codec and set the default parameters */
03820 static void add_codec(FFStream *stream, AVCodecContext *av)
03821 {
03822     AVStream *st;
03823 
03824     /* compute default parameters */
03825     switch(av->codec_type) {
03826     case AVMEDIA_TYPE_AUDIO:
03827         if (av->bit_rate == 0)
03828             av->bit_rate = 64000;
03829         if (av->sample_rate == 0)
03830             av->sample_rate = 22050;
03831         if (av->channels == 0)
03832             av->channels = 1;
03833         break;
03834     case AVMEDIA_TYPE_VIDEO:
03835         if (av->bit_rate == 0)
03836             av->bit_rate = 64000;
03837         if (av->time_base.num == 0){
03838             av->time_base.den = 5;
03839             av->time_base.num = 1;
03840         }
03841         if (av->width == 0 || av->height == 0) {
03842             av->width = 160;
03843             av->height = 128;
03844         }
03845         /* Bitrate tolerance is less for streaming */
03846         if (av->bit_rate_tolerance == 0)
03847             av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
03848                       (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
03849         if (av->qmin == 0)
03850             av->qmin = 3;
03851         if (av->qmax == 0)
03852             av->qmax = 31;
03853         if (av->max_qdiff == 0)
03854             av->max_qdiff = 3;
03855         av->qcompress = 0.5;
03856         av->qblur = 0.5;
03857 
03858         if (!av->nsse_weight)
03859             av->nsse_weight = 8;
03860 
03861         av->frame_skip_cmp = FF_CMP_DCTMAX;
03862         if (!av->me_method)
03863             av->me_method = ME_EPZS;
03864         av->rc_buffer_aggressivity = 1.0;
03865 
03866         if (!av->rc_eq)
03867             av->rc_eq = "tex^qComp";
03868         if (!av->i_quant_factor)
03869             av->i_quant_factor = -0.8;
03870         if (!av->b_quant_factor)
03871             av->b_quant_factor = 1.25;
03872         if (!av->b_quant_offset)
03873             av->b_quant_offset = 1.25;
03874         if (!av->rc_max_rate)
03875             av->rc_max_rate = av->bit_rate * 2;
03876 
03877         if (av->rc_max_rate && !av->rc_buffer_size) {
03878             av->rc_buffer_size = av->rc_max_rate;
03879         }
03880 
03881 
03882         break;
03883     default:
03884         abort();
03885     }
03886 
03887     st = av_mallocz(sizeof(AVStream));
03888     if (!st)
03889         return;
03890     st->codec = avcodec_alloc_context();
03891     stream->streams[stream->nb_streams++] = st;
03892     memcpy(st->codec, av, sizeof(AVCodecContext));
03893 }
03894 
03895 static enum CodecID opt_audio_codec(const char *arg)
03896 {
03897     AVCodec *p= avcodec_find_encoder_by_name(arg);
03898 
03899     if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
03900         return CODEC_ID_NONE;
03901 
03902     return p->id;
03903 }
03904 
03905 static enum CodecID opt_video_codec(const char *arg)
03906 {
03907     AVCodec *p= avcodec_find_encoder_by_name(arg);
03908 
03909     if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
03910         return CODEC_ID_NONE;
03911 
03912     return p->id;
03913 }
03914 
03915 /* simplistic plugin support */
03916 
03917 #if HAVE_DLOPEN
03918 static void load_module(const char *filename)
03919 {
03920     void *dll;
03921     void (*init_func)(void);
03922     dll = dlopen(filename, RTLD_NOW);
03923     if (!dll) {
03924         fprintf(stderr, "Could not load module '%s' - %s\n",
03925                 filename, dlerror());
03926         return;
03927     }
03928 
03929     init_func = dlsym(dll, "ffserver_module_init");
03930     if (!init_func) {
03931         fprintf(stderr,
03932                 "%s: init function 'ffserver_module_init()' not found\n",
03933                 filename);
03934         dlclose(dll);
03935     }
03936 
03937     init_func();
03938 }
03939 #endif
03940 
03941 static int ffserver_opt_default(const char *opt, const char *arg,
03942                        AVCodecContext *avctx, int type)
03943 {
03944     int ret = 0;
03945     const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
03946     if(o)
03947         ret = av_set_string3(avctx, opt, arg, 1, NULL);
03948     return ret;
03949 }
03950 
03951 static int ffserver_opt_preset(const char *arg,
03952                        AVCodecContext *avctx, int type,
03953                        enum CodecID *audio_id, enum CodecID *video_id)
03954 {
03955     FILE *f=NULL;
03956     char filename[1000], tmp[1000], tmp2[1000], line[1000];
03957     int ret = 0;
03958     AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
03959 
03960     if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
03961                               codec ? codec->name : NULL))) {
03962         fprintf(stderr, "File for preset '%s' not found\n", arg);
03963         return 1;
03964     }
03965 
03966     while(!feof(f)){
03967         int e= fscanf(f, "%999[^\n]\n", line) - 1;
03968         if(line[0] == '#' && !e)
03969             continue;
03970         e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
03971         if(e){
03972             fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
03973             ret = 1;
03974             break;
03975         }
03976         if(!strcmp(tmp, "acodec")){
03977             *audio_id = opt_audio_codec(tmp2);
03978         }else if(!strcmp(tmp, "vcodec")){
03979             *video_id = opt_video_codec(tmp2);
03980         }else if(!strcmp(tmp, "scodec")){
03981             /* opt_subtitle_codec(tmp2); */
03982         }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
03983             fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
03984             ret = 1;
03985             break;
03986         }
03987     }
03988 
03989     fclose(f);
03990 
03991     return ret;
03992 }
03993 
03994 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
03995                                              const char *mime_type)
03996 {
03997     AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
03998 
03999     if (fmt) {
04000         AVOutputFormat *stream_fmt;
04001         char stream_format_name[64];
04002 
04003         snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
04004         stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
04005 
04006         if (stream_fmt)
04007             fmt = stream_fmt;
04008     }
04009 
04010     return fmt;
04011 }
04012 
04013 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
04014 {
04015     va_list vl;
04016     va_start(vl, fmt);
04017     fprintf(stderr, "%s:%d: ", filename, line_num);
04018     vfprintf(stderr, fmt, vl);
04019     va_end(vl);
04020 
04021     (*errors)++;
04022 }
04023 
04024 static int parse_ffconfig(const char *filename)
04025 {
04026     FILE *f;
04027     char line[1024];
04028     char cmd[64];
04029     char arg[1024];
04030     const char *p;
04031     int val, errors, line_num;
04032     FFStream **last_stream, *stream, *redirect;
04033     FFStream **last_feed, *feed, *s;
04034     AVCodecContext audio_enc, video_enc;
04035     enum CodecID audio_id, video_id;
04036 
04037     f = fopen(filename, "r");
04038     if (!f) {
04039         perror(filename);
04040         return -1;
04041     }
04042 
04043     errors = 0;
04044     line_num = 0;
04045     first_stream = NULL;
04046     last_stream = &first_stream;
04047     first_feed = NULL;
04048     last_feed = &first_feed;
04049     stream = NULL;
04050     feed = NULL;
04051     redirect = NULL;
04052     audio_id = CODEC_ID_NONE;
04053     video_id = CODEC_ID_NONE;
04054 
04055 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
04056     for(;;) {
04057         if (fgets(line, sizeof(line), f) == NULL)
04058             break;
04059         line_num++;
04060         p = line;
04061         while (isspace(*p))
04062             p++;
04063         if (*p == '\0' || *p == '#')
04064             continue;
04065 
04066         get_arg(cmd, sizeof(cmd), &p);
04067 
04068         if (!strcasecmp(cmd, "Port")) {
04069             get_arg(arg, sizeof(arg), &p);
04070             val = atoi(arg);
04071             if (val < 1 || val > 65536) {
04072                 ERROR("Invalid_port: %s\n", arg);
04073             }
04074             my_http_addr.sin_port = htons(val);
04075         } else if (!strcasecmp(cmd, "BindAddress")) {
04076             get_arg(arg, sizeof(arg), &p);
04077             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
04078                 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
04079             }
04080         } else if (!strcasecmp(cmd, "NoDaemon")) {
04081             ffserver_daemon = 0;
04082         } else if (!strcasecmp(cmd, "RTSPPort")) {
04083             get_arg(arg, sizeof(arg), &p);
04084             val = atoi(arg);
04085             if (val < 1 || val > 65536) {
04086                 ERROR("%s:%d: Invalid port: %s\n", arg);
04087             }
04088             my_rtsp_addr.sin_port = htons(atoi(arg));
04089         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
04090             get_arg(arg, sizeof(arg), &p);
04091             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
04092                 ERROR("Invalid host/IP address: %s\n", arg);
04093             }
04094         } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
04095             get_arg(arg, sizeof(arg), &p);
04096             val = atoi(arg);
04097             if (val < 1 || val > 65536) {
04098                 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
04099             }
04100             nb_max_http_connections = val;
04101         } else if (!strcasecmp(cmd, "MaxClients")) {
04102             get_arg(arg, sizeof(arg), &p);
04103             val = atoi(arg);
04104             if (val < 1 || val > nb_max_http_connections) {
04105                 ERROR("Invalid MaxClients: %s\n", arg);
04106             } else {
04107                 nb_max_connections = val;
04108             }
04109         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
04110             int64_t llval;
04111             get_arg(arg, sizeof(arg), &p);
04112             llval = atoll(arg);
04113             if (llval < 10 || llval > 10000000) {
04114                 ERROR("Invalid MaxBandwidth: %s\n", arg);
04115             } else
04116                 max_bandwidth = llval;
04117         } else if (!strcasecmp(cmd, "CustomLog")) {
04118             if (!ffserver_debug)
04119                 get_arg(logfilename, sizeof(logfilename), &p);
04120         } else if (!strcasecmp(cmd, "<Feed")) {
04121             /*********************************************/
04122             /* Feed related options */
04123             char *q;
04124             if (stream || feed) {
04125                 ERROR("Already in a tag\n");
04126             } else {
04127                 feed = av_mallocz(sizeof(FFStream));
04128                 get_arg(feed->filename, sizeof(feed->filename), &p);
04129                 q = strrchr(feed->filename, '>');
04130                 if (*q)
04131                     *q = '\0';
04132 
04133                 for (s = first_feed; s; s = s->next) {
04134                     if (!strcmp(feed->filename, s->filename)) {
04135                         ERROR("Feed '%s' already registered\n", s->filename);
04136                     }
04137                 }
04138 
04139                 feed->fmt = av_guess_format("ffm", NULL, NULL);
04140                 /* defaut feed file */
04141                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
04142                          "/tmp/%s.ffm", feed->filename);
04143                 feed->feed_max_size = 5 * 1024 * 1024;
04144                 feed->is_feed = 1;
04145                 feed->feed = feed; /* self feeding :-) */
04146 
04147                 /* add in stream list */
04148                 *last_stream = feed;
04149                 last_stream = &feed->next;
04150                 /* add in feed list */
04151                 *last_feed = feed;
04152                 last_feed = &feed->next_feed;
04153             }
04154         } else if (!strcasecmp(cmd, "Launch")) {
04155             if (feed) {
04156                 int i;
04157 
04158                 feed->child_argv = av_mallocz(64 * sizeof(char *));
04159 
04160                 for (i = 0; i < 62; i++) {
04161                     get_arg(arg, sizeof(arg), &p);
04162                     if (!arg[0])
04163                         break;
04164 
04165                     feed->child_argv[i] = av_strdup(arg);
04166                 }
04167 
04168                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
04169 
04170                 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
04171                     "http://%s:%d/%s",
04172                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
04173                     inet_ntoa(my_http_addr.sin_addr),
04174                     ntohs(my_http_addr.sin_port), feed->filename);
04175             }
04176         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
04177             if (feed) {
04178                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
04179                 feed->readonly = 1;
04180             } else if (stream) {
04181                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
04182             }
04183         } else if (!strcasecmp(cmd, "File")) {
04184             if (feed) {
04185                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
04186             } else if (stream)
04187                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
04188         } else if (!strcasecmp(cmd, "Truncate")) {
04189             if (feed) {
04190                 get_arg(arg, sizeof(arg), &p);
04191                 feed->truncate = strtod(arg, NULL);
04192             }
04193         } else if (!strcasecmp(cmd, "FileMaxSize")) {
04194             if (feed) {
04195                 char *p1;
04196                 double fsize;
04197 
04198                 get_arg(arg, sizeof(arg), &p);
04199                 p1 = arg;
04200                 fsize = strtod(p1, &p1);
04201                 switch(toupper(*p1)) {
04202                 case 'K':
04203                     fsize *= 1024;
04204                     break;
04205                 case 'M':
04206                     fsize *= 1024 * 1024;
04207                     break;
04208                 case 'G':
04209                     fsize *= 1024 * 1024 * 1024;
04210                     break;
04211                 }
04212                 feed->feed_max_size = (int64_t)fsize;
04213                 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
04214                     ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
04215                 }
04216             }
04217         } else if (!strcasecmp(cmd, "</Feed>")) {
04218             if (!feed) {
04219                 ERROR("No corresponding <Feed> for </Feed>\n");
04220             }
04221             feed = NULL;
04222         } else if (!strcasecmp(cmd, "<Stream")) {
04223             /*********************************************/
04224             /* Stream related options */
04225             char *q;
04226             if (stream || feed) {
04227                 ERROR("Already in a tag\n");
04228             } else {
04229                 FFStream *s;
04230                 stream = av_mallocz(sizeof(FFStream));
04231                 get_arg(stream->filename, sizeof(stream->filename), &p);
04232                 q = strrchr(stream->filename, '>');
04233                 if (*q)
04234                     *q = '\0';
04235 
04236                 for (s = first_stream; s; s = s->next) {
04237                     if (!strcmp(stream->filename, s->filename)) {
04238                         ERROR("Stream '%s' already registered\n", s->filename);
04239                     }
04240                 }
04241 
04242                 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
04243                 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
04244                 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
04245                 audio_id = CODEC_ID_NONE;
04246                 video_id = CODEC_ID_NONE;
04247                 if (stream->fmt) {
04248                     audio_id = stream->fmt->audio_codec;
04249                     video_id = stream->fmt->video_codec;
04250                 }
04251 
04252                 *last_stream = stream;
04253                 last_stream = &stream->next;
04254             }
04255         } else if (!strcasecmp(cmd, "Feed")) {
04256             get_arg(arg, sizeof(arg), &p);
04257             if (stream) {
04258                 FFStream *sfeed;
04259 
04260                 sfeed = first_feed;
04261                 while (sfeed != NULL) {
04262                     if (!strcmp(sfeed->filename, arg))
04263                         break;
04264                     sfeed = sfeed->next_feed;
04265                 }
04266                 if (!sfeed)
04267                     ERROR("feed '%s' not defined\n", arg);
04268                 else
04269                     stream->feed = sfeed;
04270             }
04271         } else if (!strcasecmp(cmd, "Format")) {
04272             get_arg(arg, sizeof(arg), &p);
04273             if (stream) {
04274                 if (!strcmp(arg, "status")) {
04275                     stream->stream_type = STREAM_TYPE_STATUS;
04276                     stream->fmt = NULL;
04277                 } else {
04278                     stream->stream_type = STREAM_TYPE_LIVE;
04279                     /* jpeg cannot be used here, so use single frame jpeg */
04280                     if (!strcmp(arg, "jpeg"))
04281                         strcpy(arg, "mjpeg");
04282                     stream->fmt = ffserver_guess_format(arg, NULL, NULL);
04283                     if (!stream->fmt) {
04284                         ERROR("Unknown Format: %s\n", arg);
04285                     }
04286                 }
04287                 if (stream->fmt) {
04288                     audio_id = stream->fmt->audio_codec;
04289                     video_id = stream->fmt->video_codec;
04290                 }
04291             }
04292         } else if (!strcasecmp(cmd, "InputFormat")) {
04293             get_arg(arg, sizeof(arg), &p);
04294             if (stream) {
04295                 stream->ifmt = av_find_input_format(arg);
04296                 if (!stream->ifmt) {
04297                     ERROR("Unknown input format: %s\n", arg);
04298                 }
04299             }
04300         } else if (!strcasecmp(cmd, "FaviconURL")) {
04301             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
04302                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
04303             } else {
04304                 ERROR("FaviconURL only permitted for status streams\n");
04305             }
04306         } else if (!strcasecmp(cmd, "Author")) {
04307             if (stream)
04308                 get_arg(stream->author, sizeof(stream->author), &p);
04309         } else if (!strcasecmp(cmd, "Comment")) {
04310             if (stream)
04311                 get_arg(stream->comment, sizeof(stream->comment), &p);
04312         } else if (!strcasecmp(cmd, "Copyright")) {
04313             if (stream)
04314                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
04315         } else if (!strcasecmp(cmd, "Title")) {
04316             if (stream)
04317                 get_arg(stream->title, sizeof(stream->title), &p);
04318         } else if (!strcasecmp(cmd, "Preroll")) {
04319             get_arg(arg, sizeof(arg), &p);
04320             if (stream)
04321                 stream->prebuffer = atof(arg) * 1000;
04322         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
04323             if (stream)
04324                 stream->send_on_key = 1;
04325         } else if (!strcasecmp(cmd, "AudioCodec")) {
04326             get_arg(arg, sizeof(arg), &p);
04327             audio_id = opt_audio_codec(arg);
04328             if (audio_id == CODEC_ID_NONE) {
04329                 ERROR("Unknown AudioCodec: %s\n", arg);
04330             }
04331         } else if (!strcasecmp(cmd, "VideoCodec")) {
04332             get_arg(arg, sizeof(arg), &p);
04333             video_id = opt_video_codec(arg);
04334             if (video_id == CODEC_ID_NONE) {
04335                 ERROR("Unknown VideoCodec: %s\n", arg);
04336             }
04337         } else if (!strcasecmp(cmd, "MaxTime")) {
04338             get_arg(arg, sizeof(arg), &p);
04339             if (stream)
04340                 stream->max_time = atof(arg) * 1000;
04341         } else if (!strcasecmp(cmd, "AudioBitRate")) {
04342             get_arg(arg, sizeof(arg), &p);
04343             if (stream)
04344                 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
04345         } else if (!strcasecmp(cmd, "AudioChannels")) {
04346             get_arg(arg, sizeof(arg), &p);
04347             if (stream)
04348                 audio_enc.channels = atoi(arg);
04349         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
04350             get_arg(arg, sizeof(arg), &p);
04351             if (stream)
04352                 audio_enc.sample_rate = atoi(arg);
04353         } else if (!strcasecmp(cmd, "AudioQuality")) {
04354             get_arg(arg, sizeof(arg), &p);
04355             if (stream) {
04356 //                audio_enc.quality = atof(arg) * 1000;
04357             }
04358         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
04359             if (stream) {
04360                 int minrate, maxrate;
04361 
04362                 get_arg(arg, sizeof(arg), &p);
04363 
04364                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
04365                     video_enc.rc_min_rate = minrate * 1000;
04366                     video_enc.rc_max_rate = maxrate * 1000;
04367                 } else {
04368                     ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
04369                 }
04370             }
04371         } else if (!strcasecmp(cmd, "Debug")) {
04372             if (stream) {
04373                 get_arg(arg, sizeof(arg), &p);
04374                 video_enc.debug = strtol(arg,0,0);
04375             }
04376         } else if (!strcasecmp(cmd, "Strict")) {
04377             if (stream) {
04378                 get_arg(arg, sizeof(arg), &p);
04379                 video_enc.strict_std_compliance = atoi(arg);
04380             }
04381         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
04382             if (stream) {
04383                 get_arg(arg, sizeof(arg), &p);
04384                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
04385             }
04386         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
04387             if (stream) {
04388                 get_arg(arg, sizeof(arg), &p);
04389                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
04390             }
04391         } else if (!strcasecmp(cmd, "VideoBitRate")) {
04392             get_arg(arg, sizeof(arg), &p);
04393             if (stream) {
04394                 video_enc.bit_rate = atoi(arg) * 1000;
04395             }
04396         } else if (!strcasecmp(cmd, "VideoSize")) {
04397             get_arg(arg, sizeof(arg), &p);
04398             if (stream) {
04399                 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
04400                 if ((video_enc.width % 16) != 0 ||
04401                     (video_enc.height % 16) != 0) {
04402                     ERROR("Image size must be a multiple of 16\n");
04403                 }
04404             }
04405         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
04406             get_arg(arg, sizeof(arg), &p);
04407             if (stream) {
04408                 AVRational frame_rate;
04409                 if (av_parse_video_rate(&frame_rate, arg) < 0) {
04410                     ERROR("Incorrect frame rate: %s\n", arg);
04411                 } else {
04412                     video_enc.time_base.num = frame_rate.den;
04413                     video_enc.time_base.den = frame_rate.num;
04414                 }
04415             }
04416         } else if (!strcasecmp(cmd, "VideoGopSize")) {
04417             get_arg(arg, sizeof(arg), &p);
04418             if (stream)
04419                 video_enc.gop_size = atoi(arg);
04420         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
04421             if (stream)
04422                 video_enc.gop_size = 1;
04423         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
04424             if (stream)
04425                 video_enc.mb_decision = FF_MB_DECISION_BITS;
04426         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
04427             if (stream) {
04428                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
04429                 video_enc.flags |= CODEC_FLAG_4MV;
04430             }
04431         } else if (!strcasecmp(cmd, "AVOptionVideo") ||
04432                    !strcasecmp(cmd, "AVOptionAudio")) {
04433             char arg2[1024];
04434             AVCodecContext *avctx;
04435             int type;
04436             get_arg(arg, sizeof(arg), &p);
04437             get_arg(arg2, sizeof(arg2), &p);
04438             if (!strcasecmp(cmd, "AVOptionVideo")) {
04439                 avctx = &video_enc;
04440                 type = AV_OPT_FLAG_VIDEO_PARAM;
04441             } else {
04442                 avctx = &audio_enc;
04443                 type = AV_OPT_FLAG_AUDIO_PARAM;
04444             }
04445             if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
04446                 ERROR("AVOption error: %s %s\n", arg, arg2);
04447             }
04448         } else if (!strcasecmp(cmd, "AVPresetVideo") ||
04449                    !strcasecmp(cmd, "AVPresetAudio")) {
04450             AVCodecContext *avctx;
04451             int type;
04452             get_arg(arg, sizeof(arg), &p);
04453             if (!strcasecmp(cmd, "AVPresetVideo")) {
04454                 avctx = &video_enc;
04455                 video_enc.codec_id = video_id;
04456                 type = AV_OPT_FLAG_VIDEO_PARAM;
04457             } else {
04458                 avctx = &audio_enc;
04459                 audio_enc.codec_id = audio_id;
04460                 type = AV_OPT_FLAG_AUDIO_PARAM;
04461             }
04462             if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
04463                 ERROR("AVPreset error: %s\n", arg);
04464             }
04465         } else if (!strcasecmp(cmd, "VideoTag")) {
04466             get_arg(arg, sizeof(arg), &p);
04467             if ((strlen(arg) == 4) && stream)
04468                 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
04469         } else if (!strcasecmp(cmd, "BitExact")) {
04470             if (stream)
04471                 video_enc.flags |= CODEC_FLAG_BITEXACT;
04472         } else if (!strcasecmp(cmd, "DctFastint")) {
04473             if (stream)
04474                 video_enc.dct_algo  = FF_DCT_FASTINT;
04475         } else if (!strcasecmp(cmd, "IdctSimple")) {
04476             if (stream)
04477                 video_enc.idct_algo = FF_IDCT_SIMPLE;
04478         } else if (!strcasecmp(cmd, "Qscale")) {
04479             get_arg(arg, sizeof(arg), &p);
04480             if (stream) {
04481                 video_enc.flags |= CODEC_FLAG_QSCALE;
04482                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
04483             }
04484         } else if (!strcasecmp(cmd, "VideoQDiff")) {
04485             get_arg(arg, sizeof(arg), &p);
04486             if (stream) {
04487                 video_enc.max_qdiff = atoi(arg);
04488                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
04489                     ERROR("VideoQDiff out of range\n");
04490                 }
04491             }
04492         } else if (!strcasecmp(cmd, "VideoQMax")) {
04493             get_arg(arg, sizeof(arg), &p);
04494             if (stream) {
04495                 video_enc.qmax = atoi(arg);
04496                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
04497                     ERROR("VideoQMax out of range\n");
04498                 }
04499             }
04500         } else if (!strcasecmp(cmd, "VideoQMin")) {
04501             get_arg(arg, sizeof(arg), &p);
04502             if (stream) {
04503                 video_enc.qmin = atoi(arg);
04504                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
04505                     ERROR("VideoQMin out of range\n");
04506                 }
04507             }
04508         } else if (!strcasecmp(cmd, "LumaElim")) {
04509             get_arg(arg, sizeof(arg), &p);
04510             if (stream)
04511                 video_enc.luma_elim_threshold = atoi(arg);
04512         } else if (!strcasecmp(cmd, "ChromaElim")) {
04513             get_arg(arg, sizeof(arg), &p);
04514             if (stream)
04515                 video_enc.chroma_elim_threshold = atoi(arg);
04516         } else if (!strcasecmp(cmd, "LumiMask")) {
04517             get_arg(arg, sizeof(arg), &p);
04518             if (stream)
04519                 video_enc.lumi_masking = atof(arg);
04520         } else if (!strcasecmp(cmd, "DarkMask")) {
04521             get_arg(arg, sizeof(arg), &p);
04522             if (stream)
04523                 video_enc.dark_masking = atof(arg);
04524         } else if (!strcasecmp(cmd, "NoVideo")) {
04525             video_id = CODEC_ID_NONE;
04526         } else if (!strcasecmp(cmd, "NoAudio")) {
04527             audio_id = CODEC_ID_NONE;
04528         } else if (!strcasecmp(cmd, "ACL")) {
04529             parse_acl_row(stream, feed, NULL, p, filename, line_num);
04530         } else if (!strcasecmp(cmd, "DynamicACL")) {
04531             if (stream) {
04532                 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
04533             }
04534         } else if (!strcasecmp(cmd, "RTSPOption")) {
04535             get_arg(arg, sizeof(arg), &p);
04536             if (stream) {
04537                 av_freep(&stream->rtsp_option);
04538                 stream->rtsp_option = av_strdup(arg);
04539             }
04540         } else if (!strcasecmp(cmd, "MulticastAddress")) {
04541             get_arg(arg, sizeof(arg), &p);
04542             if (stream) {
04543                 if (resolve_host(&stream->multicast_ip, arg) != 0) {
04544                     ERROR("Invalid host/IP address: %s\n", arg);
04545                 }
04546                 stream->is_multicast = 1;
04547                 stream->loop = 1; /* default is looping */
04548             }
04549         } else if (!strcasecmp(cmd, "MulticastPort")) {
04550             get_arg(arg, sizeof(arg), &p);
04551             if (stream)
04552                 stream->multicast_port = atoi(arg);
04553         } else if (!strcasecmp(cmd, "MulticastTTL")) {
04554             get_arg(arg, sizeof(arg), &p);
04555             if (stream)
04556                 stream->multicast_ttl = atoi(arg);
04557         } else if (!strcasecmp(cmd, "NoLoop")) {
04558             if (stream)
04559                 stream->loop = 0;
04560         } else if (!strcasecmp(cmd, "</Stream>")) {
04561             if (!stream) {
04562                 ERROR("No corresponding <Stream> for </Stream>\n");
04563             } else {
04564                 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
04565                     if (audio_id != CODEC_ID_NONE) {
04566                         audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
04567                         audio_enc.codec_id = audio_id;
04568                         add_codec(stream, &audio_enc);
04569                     }
04570                     if (video_id != CODEC_ID_NONE) {
04571                         video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
04572                         video_enc.codec_id = video_id;
04573                         add_codec(stream, &video_enc);
04574                     }
04575                 }
04576                 stream = NULL;
04577             }
04578         } else if (!strcasecmp(cmd, "<Redirect")) {
04579             /*********************************************/
04580             char *q;
04581             if (stream || feed || redirect) {
04582                 ERROR("Already in a tag\n");
04583             } else {
04584                 redirect = av_mallocz(sizeof(FFStream));
04585                 *last_stream = redirect;
04586                 last_stream = &redirect->next;
04587 
04588                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
04589                 q = strrchr(redirect->filename, '>');
04590                 if (*q)
04591                     *q = '\0';
04592                 redirect->stream_type = STREAM_TYPE_REDIRECT;
04593             }
04594         } else if (!strcasecmp(cmd, "URL")) {
04595             if (redirect)
04596                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
04597         } else if (!strcasecmp(cmd, "</Redirect>")) {
04598             if (!redirect) {
04599                 ERROR("No corresponding <Redirect> for </Redirect>\n");
04600             } else {
04601                 if (!redirect->feed_filename[0]) {
04602                     ERROR("No URL found for <Redirect>\n");
04603                 }
04604                 redirect = NULL;
04605             }
04606         } else if (!strcasecmp(cmd, "LoadModule")) {
04607             get_arg(arg, sizeof(arg), &p);
04608 #if HAVE_DLOPEN
04609             load_module(arg);
04610 #else
04611             ERROR("Module support not compiled into this version: '%s'\n", arg);
04612 #endif
04613         } else {
04614             ERROR("Incorrect keyword: '%s'\n", cmd);
04615         }
04616     }
04617 #undef ERROR
04618 
04619     fclose(f);
04620     if (errors)
04621         return -1;
04622     else
04623         return 0;
04624 }
04625 
04626 static void handle_child_exit(int sig)
04627 {
04628     pid_t pid;
04629     int status;
04630 
04631     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
04632         FFStream *feed;
04633 
04634         for (feed = first_feed; feed; feed = feed->next) {
04635             if (feed->pid == pid) {
04636                 int uptime = time(0) - feed->pid_start;
04637 
04638                 feed->pid = 0;
04639                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
04640 
04641                 if (uptime < 30)
04642                     /* Turn off any more restarts */
04643                     feed->child_argv = 0;
04644             }
04645         }
04646     }
04647 
04648     need_to_start_children = 1;
04649 }
04650 
04651 static void opt_debug(void)
04652 {
04653     ffserver_debug = 1;
04654     ffserver_daemon = 0;
04655     logfilename[0] = '-';
04656 }
04657 
04658 static void show_help(void)
04659 {
04660     printf("usage: ffserver [options]\n"
04661            "Hyper fast multi format Audio/Video streaming server\n");
04662     printf("\n");
04663     show_help_options(options, "Main options:\n", 0, 0);
04664 }
04665 
04666 static const OptionDef options[] = {
04667 #include "cmdutils_common_opts.h"
04668     { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
04669     { "d", 0, {(void*)opt_debug}, "enable debug mode" },
04670     { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
04671     { NULL },
04672 };
04673 
04674 int main(int argc, char **argv)
04675 {
04676     struct sigaction sigact;
04677 
04678     av_register_all();
04679 
04680     show_banner();
04681 
04682     my_program_name = argv[0];
04683     my_program_dir = getcwd(0, 0);
04684     ffserver_daemon = 1;
04685 
04686     parse_options(argc, argv, options, NULL);
04687 
04688     unsetenv("http_proxy");             /* Kill the http_proxy */
04689 
04690     av_lfg_init(&random_state, av_get_random_seed());
04691 
04692     memset(&sigact, 0, sizeof(sigact));
04693     sigact.sa_handler = handle_child_exit;
04694     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
04695     sigaction(SIGCHLD, &sigact, 0);
04696 
04697     if (parse_ffconfig(config_filename) < 0) {
04698         fprintf(stderr, "Incorrect config file - exiting.\n");
04699         exit(1);
04700     }
04701 
04702     /* open log file if needed */
04703     if (logfilename[0] != '\0') {
04704         if (!strcmp(logfilename, "-"))
04705             logfile = stdout;
04706         else
04707             logfile = fopen(logfilename, "a");
04708         av_log_set_callback(http_av_log);
04709     }
04710 
04711     build_file_streams();
04712 
04713     build_feed_streams();
04714 
04715     compute_bandwidth();
04716 
04717     /* put the process in background and detach it from its TTY */
04718     if (ffserver_daemon) {
04719         int pid;
04720 
04721         pid = fork();
04722         if (pid < 0) {
04723             perror("fork");
04724             exit(1);
04725         } else if (pid > 0) {
04726             /* parent : exit */
04727             exit(0);
04728         } else {
04729             /* child */
04730             setsid();
04731             close(0);
04732             open("/dev/null", O_RDWR);
04733             if (strcmp(logfilename, "-") != 0) {
04734                 close(1);
04735                 dup(0);
04736             }
04737             close(2);
04738             dup(0);
04739         }
04740     }
04741 
04742     /* signal init */
04743     signal(SIGPIPE, SIG_IGN);
04744 
04745     if (ffserver_daemon)
04746         chdir("/");
04747 
04748     if (http_server() < 0) {
04749         http_log("Could not start server\n");
04750         exit(1);
04751     }
04752 
04753     return 0;
04754 }