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

ffserver.c

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

Generated on Sat Feb 16 2013 09:23:11 for ffmpeg by  doxygen 1.7.1