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

Generated on Wed Apr 11 2012 07:31:32 for FFmpeg by  doxygen 1.7.1