• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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

Generated on Fri Sep 16 2011 17:17:32 for FFmpeg by  doxygen 1.7.1