]> git.sesse.net Git - ffmpeg/blobdiff - ffserver.c
move ffm_seek1 before get_pts function since func uses it
[ffmpeg] / ffserver.c
index 621e5503273e0d972fff690014fa5b250b99de62..b5a48bb4c6feff0e4560bde52ee08a8320528b75 100644 (file)
 #endif
 #include <string.h>
 #include <stdlib.h>
-#include "avformat.h"
+#include "libavutil/random.h"
+#include "libavutil/avstring.h"
+#include "libavformat/avformat.h"
+#include "libavformat/network.h"
+#include "libavformat/os_support.h"
+#include "libavformat/rtp.h"
+#include "libavformat/rtsp.h"
 
 #include <stdarg.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
 #endif
 #include <errno.h>
 #include <sys/time.h>
 #include <dlfcn.h>
 #endif
 
-#include "network.h"
 #include "version.h"
 #include "ffserver.h"
-#include "random.h"
-#include "avstring.h"
+#include "cmdutils.h"
 
 #undef exit
 
+const char program_name[] = "FFserver";
+static const int program_birth_year = 2000;
+
+static const OptionDef options[];
+
 /* maximum number of simultaneous HTTP connections */
 #define HTTP_MAX_CONNECTIONS 2000
 
@@ -227,14 +236,14 @@ typedef struct FFStream {
     int conns_served;
     int64_t bytes_served;
     int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
-    int64_t feed_write_index;   /* current write position in feed (it wraps round) */
+    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
     int64_t feed_size;          /* current size of feed */
     struct FFStream *next_feed;
 } FFStream;
 
 typedef struct FeedData {
     long long data_count;
-    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
+    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
 } FeedData;
 
 static struct sockaddr_in my_http_addr;
@@ -281,6 +290,7 @@ static int rtp_new_av_stream(HTTPContext *c,
 static const char *my_program_name;
 static const char *my_program_dir;
 
+static const char *config_filename;
 static int ffserver_debug;
 static int ffserver_daemon;
 static int no_launch;
@@ -746,7 +756,7 @@ static void close_connection(HTTPContext *c)
             /* prepare header */
             if (url_open_dyn_buf(&ctx->pb) >= 0) {
                 av_write_trailer(ctx);
-                url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
             }
         }
     }
@@ -1590,9 +1600,9 @@ static void compute_stats(HTTPContext *c)
     char *p;
     time_t ti;
     int i, len;
-    ByteIOContext pb1, *pb = &pb1;
+    ByteIOContext *pb;
 
-    if (url_open_dyn_buf(pb) < 0) {
+    if (url_open_dyn_buf(&pb) < 0) {
         /* XXX: return an error ? */
         c->buffer_ptr = c->buffer;
         c->buffer_end = c->buffer;
@@ -1626,7 +1636,7 @@ static void compute_stats(HTTPContext *c)
                     strcpy(eosf - 4, ".asx");
                 else if (strcmp(eosf - 3, ".rm") == 0)
                     strcpy(eosf - 3, ".ram");
-                else if (stream->fmt == &rtp_muxer) {
+                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
                     /* generate a sample RTSP director if
                        unicast. Generate an SDP redirector if
                        multicast */
@@ -1877,7 +1887,7 @@ static int open_input_stream(HTTPContext *c, const char *info)
     char buf[128];
     char input_filename[1024];
     AVFormatContext *s;
-    int buf_size, i;
+    int buf_size, i, ret;
     int64_t stream_pos;
 
     /* find file name */
@@ -1886,7 +1896,11 @@ static int open_input_stream(HTTPContext *c, const char *info)
         buf_size = FFM_PACKET_SIZE;
         /* compute position (absolute time) */
         if (find_info_tag(buf, sizeof(buf), "date", info))
+        {
             stream_pos = parse_date(buf, 0);
+            if (stream_pos == INT64_MIN)
+                return -1;
+        }
         else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
             int prebuffer = strtol(buf, 0, 10);
             stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
@@ -1897,7 +1911,11 @@ static int open_input_stream(HTTPContext *c, const char *info)
         buf_size = 0;
         /* compute position (relative time) */
         if (find_info_tag(buf, sizeof(buf), "date", info))
+        {
             stream_pos = parse_date(buf, 1);
+            if (stream_pos == INT64_MIN)
+                return -1;
+        }
         else
             stream_pos = 0;
     }
@@ -1911,12 +1929,14 @@ static int open_input_stream(HTTPContext *c, const char *info)
 #endif
 
     /* open stream */
-    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
-                           buf_size, c->stream->ap_in) < 0) {
-        http_log("%s not found", input_filename);
+    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
+                                  buf_size, c->stream->ap_in)) < 0) {
+        http_log("could not open %s: %d\n", input_filename, ret);
         return -1;
     }
+    s->flags |= AVFMT_FLAG_GENPTS;
     c->fmt_in = s;
+    av_find_stream_info(c->fmt_in);
 
     /* open each parser */
     for(i=0;i<s->nb_streams;i++)
@@ -2016,13 +2036,13 @@ static int http_prepare_data(HTTPContext *c)
             /* XXX: potential leak */
             return -1;
         }
-        c->fmt_ctx.pb.is_streamed = 1;
+        c->fmt_ctx.pb->is_streamed = 1;
 
         av_set_parameters(&c->fmt_ctx, NULL);
         if (av_write_header(&c->fmt_ctx) < 0)
             return -1;
 
-        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
+        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
         c->buffer_ptr = c->pb_buffer;
         c->buffer_end = c->pb_buffer + len;
 
@@ -2166,14 +2186,16 @@ static int http_prepare_data(HTTPContext *c)
                         if (av_write_frame(ctx, &pkt))
                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
 
-                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+                        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
                         c->cur_frame_bytes = len;
                         c->buffer_ptr = c->pb_buffer;
                         c->buffer_end = c->pb_buffer + len;
 
                         codec->frame_number++;
-                        if (len == 0)
+                        if (len == 0) {
+                            av_free_packet(&pkt);
                             goto redo;
+                        }
                     }
                     av_free_packet(&pkt);
                 }
@@ -2192,7 +2214,7 @@ static int http_prepare_data(HTTPContext *c)
             return -1;
         }
         av_write_trailer(ctx);
-        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
         c->buffer_ptr = c->pb_buffer;
         c->buffer_end = c->pb_buffer + len;
 
@@ -2245,7 +2267,7 @@ static int http_send_data(HTTPContext *c)
 
                 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
                     /* RTP packets are sent inside the RTSP TCP connection */
-                    ByteIOContext pb1, *pb = &pb1;
+                    ByteIOContext *pb;
                     int interleaved_index, size;
                     uint8_t header[4];
                     HTTPContext *rtsp_c;
@@ -2257,7 +2279,7 @@ static int http_send_data(HTTPContext *c)
                     /* if already sending something, then wait. */
                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
                         break;
-                    if (url_open_dyn_buf(pb) < 0)
+                    if (url_open_dyn_buf(&pb) < 0)
                         goto fail1;
                     interleaved_index = c->packet_stream_index * 2;
                     /* RTCP packets are sent at odd indexes */
@@ -2416,14 +2438,12 @@ static int http_receive_data(HTTPContext *c)
             /* We have a header in our hands that contains useful data */
             AVFormatContext s;
             AVInputFormat *fmt_in;
-            ByteIOContext *pb = &s.pb;
             int i;
 
             memset(&s, 0, sizeof(s));
 
-            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
-            pb->buf_end = c->buffer_end;        /* ?? */
-            pb->is_streamed = 1;
+            url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
+            s.pb->is_streamed = 1;
 
             /* use feed output format name to find corresponding input format */
             fmt_in = av_find_input_format(feed->fmt->name);
@@ -2537,7 +2557,6 @@ static int rtsp_parse_request(HTTPContext *c)
     char url[1024];
     char protocol[32];
     char line[1024];
-    ByteIOContext pb1;
     int len;
     RTSPHeader header1, *header = &header1;
 
@@ -2552,8 +2571,7 @@ static int rtsp_parse_request(HTTPContext *c)
     av_strlcpy(c->url, url, sizeof(c->url));
     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
 
-    c->pb = &pb1;
-    if (url_open_dyn_buf(c->pb) < 0) {
+    if (url_open_dyn_buf(&c->pb) < 0) {
         /* XXX: cannot do more */
         c->pb = NULL; /* safety */
         return -1;
@@ -2681,7 +2699,8 @@ static void rtsp_cmd_describe(HTTPContext *c, const char *url)
         path++;
 
     for(stream = first_stream; stream != NULL; stream = stream->next) {
-        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
+        if (!stream->is_feed &&
+            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
             !strcmp(path, stream->filename)) {
             goto found;
         }
@@ -2756,7 +2775,8 @@ static void rtsp_cmd_setup(HTTPContext *c, const char *url,
 
     /* now check each stream */
     for(stream = first_stream; stream != NULL; stream = stream->next) {
-        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
+        if (!stream->is_feed &&
+            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
             /* accept aggregate filenames only if single stream */
             if (!strcmp(path, stream->filename)) {
                 if (stream->nb_streams != 1) {
@@ -3074,7 +3094,7 @@ static int rtp_new_av_stream(HTTPContext *c,
     ctx = av_alloc_format_context();
     if (!ctx)
         return -1;
-    ctx->oformat = &rtp_muxer;
+    ctx->oformat = guess_format("rtp", NULL, NULL);
 
     st = av_mallocz(sizeof(AVStream));
     if (!st)
@@ -3146,7 +3166,7 @@ static int rtp_new_av_stream(HTTPContext *c,
         av_free(ctx);
         return -1;
     }
-    url_close_dyn_buf(&ctx->pb, &dummy_buf);
+    url_close_dyn_buf(ctx->pb, &dummy_buf);
     av_free(dummy_buf);
 
     c->rtp_ctx[stream_index] = ctx;
@@ -3282,7 +3302,7 @@ static void build_file_streams(void)
 {
     FFStream *stream, *stream_next;
     AVFormatContext *infile;
-    int i;
+    int i, ret;
 
     /* gather all streams */
     for(stream = first_stream; stream != NULL; stream = stream_next) {
@@ -3293,16 +3313,16 @@ static void build_file_streams(void)
             /* try to open the file */
             /* open stream */
             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
-            if (stream->fmt == &rtp_muxer) {
+            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
                 /* specific case : if transport stream output to RTP,
                    we use a raw transport stream reader */
                 stream->ap_in->mpeg2ts_raw = 1;
                 stream->ap_in->mpeg2ts_compute_pcr = 1;
             }
 
-            if (av_open_input_file(&infile, stream->feed_filename,
-                                   stream->ifmt, 0, stream->ap_in) < 0) {
-                http_log("%s not found", stream->feed_filename);
+            if ((ret = av_open_input_file(&infile, stream->feed_filename,
+                                          stream->ifmt, 0, stream->ap_in)) < 0) {
+                http_log("could not open %s: %d\n", stream->feed_filename, ret);
                 /* remove stream (no need to spend more time on it) */
             fail:
                 remove_stream(stream);
@@ -3461,7 +3481,7 @@ static void build_feed_streams(void)
             }
             /* XXX: need better api */
             av_freep(&s->priv_data);
-            url_fclose(&s->pb);
+            url_fclose(s->pb);
         }
         /* get feed size and write index */
         fd = open(feed->feed_filename, O_RDONLY);
@@ -3564,7 +3584,8 @@ static void add_codec(FFStream *stream, AVCodecContext *av)
         }
         /* Bitrate tolerance is less for streaming */
         if (av->bit_rate_tolerance == 0)
-            av->bit_rate_tolerance = av->bit_rate / 4;
+            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
+                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
         if (av->qmin == 0)
             av->qmin = 3;
         if (av->qmax == 0)
@@ -3612,15 +3633,9 @@ static void add_codec(FFStream *stream, AVCodecContext *av)
 
 static int opt_audio_codec(const char *arg)
 {
-    AVCodec *p;
+    AVCodec *p= avcodec_find_encoder_by_name(arg);
 
-    p = first_avcodec;
-    while (p) {
-        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
-            break;
-        p = p->next;
-    }
-    if (p == NULL)
+    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
         return CODEC_ID_NONE;
 
     return p->id;
@@ -3628,15 +3643,9 @@ static int opt_audio_codec(const char *arg)
 
 static int opt_video_codec(const char *arg)
 {
-    AVCodec *p;
+    AVCodec *p= avcodec_find_encoder_by_name(arg);
 
-    p = first_avcodec;
-    while (p) {
-        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
-            break;
-        p = p->next;
-    }
-    if (p == NULL)
+    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
         return CODEC_ID_NONE;
 
     return p->id;
@@ -3797,7 +3806,7 @@ static int parse_ffconfig(const char *filename)
             if (feed) {
                 int i;
 
-                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
+                feed->child_argv = av_mallocz(64 * sizeof(char *));
 
                 for (i = 0; i < 62; i++) {
                     get_arg(arg, sizeof(arg), &p);
@@ -3838,12 +3847,12 @@ static int parse_ffconfig(const char *filename)
                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
         } else if (!strcasecmp(cmd, "FileMaxSize")) {
             if (feed) {
-                const char *p1;
+                char *p1;
                 double fsize;
 
                 get_arg(arg, sizeof(arg), &p);
                 p1 = arg;
-                fsize = strtod(p1, (char **)&p1);
+                fsize = strtod(p1, &p1);
                 switch(toupper(*p1)) {
                 case 'K':
                     fsize *= 1024;
@@ -4174,7 +4183,7 @@ static int parse_ffconfig(const char *filename)
             }
 
             if (!errors) {
-                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
+                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
                 IPAddressACL **naclp = 0;
 
                 acl.next = 0;
@@ -4300,43 +4309,6 @@ static int parse_ffconfig(const char *filename)
         return 0;
 }
 
-static void show_banner(void)
-{
-    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
-}
-
-static void show_help(void)
-{
-    show_banner();
-    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
-           "Hyper fast multi format Audio/Video streaming server\n"
-           "\n"
-           "-L            : print the LICENSE\n"
-           "-h            : this help\n"
-           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
-           );
-}
-
-static void show_license(void)
-{
-    show_banner();
-    printf(
-    "FFmpeg is free software; you can redistribute it and/or\n"
-    "modify it under the terms of the GNU Lesser General Public\n"
-    "License as published by the Free Software Foundation; either\n"
-    "version 2.1 of the License, or (at your option) any later version.\n"
-    "\n"
-    "FFmpeg is distributed in the hope that it will be useful,\n"
-    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
-    "Lesser General Public License for more details.\n"
-    "\n"
-    "You should have received a copy of the GNU Lesser General Public\n"
-    "License along with FFmpeg; if not, write to the Free Software\n"
-    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
-    );
-}
-
 static void handle_child_exit(int sig)
 {
     pid_t pid;
@@ -4362,46 +4334,46 @@ static void handle_child_exit(int sig)
     need_to_start_children = 1;
 }
 
+static void opt_debug()
+{
+    ffserver_debug = 1;
+    ffserver_daemon = 0;
+}
+
+static void opt_show_help(void)
+{
+    printf("usage: ffserver [options]\n"
+           "Hyper fast multi format Audio/Video streaming server\n");
+    printf("\n");
+    show_help_options(options, "Main options:\n", 0, 0);
+}
+
+static const OptionDef options[] = {
+    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
+    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
+    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
+    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
+    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
+    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
+    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
+    { NULL },
+};
+
 int main(int argc, char **argv)
 {
-    const char *config_filename;
-    int c;
     struct sigaction sigact;
 
     av_register_all();
 
+    show_banner(program_name, program_birth_year);
+
     config_filename = "/etc/ffserver.conf";
 
     my_program_name = argv[0];
     my_program_dir = getcwd(0, 0);
     ffserver_daemon = 1;
 
-    for(;;) {
-        c = getopt(argc, argv, "ndLh?f:");
-        if (c == -1)
-            break;
-        switch(c) {
-        case 'L':
-            show_license();
-            exit(0);
-        case '?':
-        case 'h':
-            show_help();
-            exit(0);
-        case 'n':
-            no_launch = 1;
-            break;
-        case 'd':
-            ffserver_debug = 1;
-            ffserver_daemon = 0;
-            break;
-        case 'f':
-            config_filename = optarg;
-            break;
-        default:
-            exit(2);
-        }
-    }
+    parse_options(argc, argv, options, NULL);
 
     putenv("http_proxy");               /* Kill the http_proxy */
 
@@ -4472,7 +4444,7 @@ int main(int argc, char **argv)
         if (!strcmp(logfilename, "-"))
             logfile = stdout;
         else
-            logfile = fopen(logfilename, "w");
+            logfile = fopen(logfilename, "a");
     }
 
     if (http_server() < 0) {