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

avserver.c

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