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

ffserver.c

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