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