]> git.sesse.net Git - ffmpeg/blobdiff - ffserver.c
fixed MPEG2 pts parsing - ignore unknown stream type
[ffmpeg] / ffserver.c
index c7b2bc590745d9d672c543bebd8502260d9b05ad..0d2d423670c7ca4494811ab8b7e662db51b34723 100644 (file)
@@ -154,6 +154,18 @@ enum StreamType {
     STREAM_TYPE_REDIRECT,
 };
 
+enum IPAddressAction {
+    IP_ALLOW = 1,
+    IP_DENY,
+};
+
+typedef struct IPAddressACL {
+    struct IPAddressACL *next;
+    enum IPAddressAction action;
+    struct in_addr first;
+    struct in_addr last;
+} IPAddressACL;
+
 /* description of each stream of the ffserver.conf file */
 typedef struct FFStream {
     enum StreamType stream_type;
@@ -161,6 +173,7 @@ typedef struct FFStream {
     struct FFStream *feed;   /* feed we are using (can be null if
                                 coming from file) */
     AVOutputFormat *fmt;
+    IPAddressACL *acl;
     int nb_streams;
     int prebuffer;      /* Number of millseconds early to start */
     long max_time;      /* Number of milliseconds to run */
@@ -312,6 +325,16 @@ static int compute_datarate(DataRateData *drd, INT64 count)
     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
 }
 
+static int get_longterm_datarate(DataRateData *drd, INT64 count)
+{
+    /* You get the first 3 seconds flat out */
+    if (cur_time - drd->time1 < 3000)
+        return 0;
+
+    return compute_datarate(drd, count);
+}
+
+
 static void start_children(FFStream *feed)
 {
     if (no_launch)
@@ -957,6 +980,23 @@ static void get_word(char *buf, int buf_size, const char **pp)
     *pp = p;
 }
 
+static int validate_acl(FFStream *stream, HTTPContext *c)
+{
+    enum IPAddressAction last_action = IP_DENY;
+    IPAddressACL *acl;
+    struct in_addr *src = &c->from_addr.sin_addr;
+
+    for (acl = stream->acl; acl; acl = acl->next) {
+        if (src->s_addr >= acl->first.s_addr && src->s_addr <= acl->last.s_addr) {
+            return (acl->action == IP_ALLOW) ? 1 : 0;
+        }
+        last_action = acl->action;
+    }
+
+    /* Nothing matched, so return not the last action */
+    return (last_action == IP_DENY) ? 1 : 0;
+}
+
 /* parse http request and prepare header */
 static int http_parse_request(HTTPContext *c)
 {
@@ -1077,7 +1117,7 @@ static int http_parse_request(HTTPContext *c)
 
     stream = first_stream;
     while (stream != NULL) {
-        if (!strcmp(stream->filename, filename))
+        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
             break;
         stream = stream->next;
     }
@@ -1342,14 +1382,10 @@ static int http_parse_request(HTTPContext *c)
     q += sprintf(q, "Pragma: no-cache\r\n");
 
     /* for asf, we need extra headers */
-    if (!strcmp(c->stream->fmt->name,"asf")) {
+    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
         /* Need to allocate a client id */
-        static int wmp_session;
 
-        if (!wmp_session)
-            wmp_session = time(0) & 0xffffff;
-
-        c->wmp_client_id = ++wmp_session;
+        c->wmp_client_id = random() & 0x7fffffff;
 
         q += sprintf(q, "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);
         mime_type = "application/octet-stream"; 
@@ -1702,9 +1738,9 @@ static int open_input_stream(HTTPContext *c, const char *info)
             stream_pos = parse_date(buf, 0);
         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
             int prebuffer = strtol(buf, 0, 10);
-            stream_pos = av_gettime() - prebuffer * 1000000;
+            stream_pos = av_gettime() - prebuffer * (INT64)1000000;
         } else {
-            stream_pos = av_gettime() - c->stream->prebuffer * 1000;
+            stream_pos = av_gettime() - c->stream->prebuffer * (INT64)1000;
         }
     } else {
         strcpy(input_filename, c->stream->feed_filename);
@@ -1719,6 +1755,12 @@ static int open_input_stream(HTTPContext *c, const char *info)
     if (input_filename[0] == '\0')
         return -1;
 
+#if 0
+    { time_t when = stream_pos / 1000000;
+    http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
+    }
+#endif
+
     /* open stream */
     if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
         http_log("%s not found", input_filename);
@@ -1746,7 +1788,6 @@ static int open_input_stream(HTTPContext *c, const char *info)
     /* set the start time (needed for maxtime and RTP packet timing) */
     c->start_time = cur_time;
     c->first_pts = AV_NOPTS_VALUE;
-    printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
     return 0;
 }
 
@@ -1905,6 +1946,11 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
 
 static int compute_send_delay(HTTPContext *c)
 {
+    int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count); 
+
+    if (datarate > c->bandwidth * 2000) {
+        return 1000;
+    }
     return 0;
 }
 
@@ -1979,7 +2025,7 @@ static int http_prepare_data(HTTPContext *c)
                 /* We have timed out */
                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
             } else {
-                if (c->is_packetized) {
+                if (1 || c->is_packetized) {
                     if (compute_send_delay(c) > 0) {
                         c->state = HTTPSTATE_WAIT;
                         return 1; /* state changed */
@@ -3073,6 +3119,73 @@ void build_feed_streams(void)
     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
         int fd;
 
+        if (url_exist(feed->feed_filename)) {
+            /* See if it matches */
+            AVFormatContext *s;
+            int matches = 0;
+
+            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
+                /* Now see if it matches */
+                if (s->nb_streams == feed->nb_streams) {
+                    matches = 1;
+                    for(i=0;i<s->nb_streams;i++) {
+                        AVStream *sf, *ss;
+                        sf = feed->streams[i];
+                        ss = s->streams[i];
+
+                        if (sf->index != ss->index ||
+                            sf->id != ss->id) {
+                            printf("Index & Id do not match for stream %d\n", i);
+                            matches = 0;
+                        } else {
+                            AVCodecContext *ccf, *ccs;
+
+                            ccf = &sf->codec;
+                            ccs = &ss->codec;
+#define CHECK_CODEC(x)  (ccf->x != ccs->x)
+
+                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
+                                printf("Codecs do not match for stream %d\n", i);
+                                matches = 0;
+                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
+                                printf("Codec bitrates do not match for stream %d\n", i);
+                                matches = 0;
+                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
+                                if (CHECK_CODEC(frame_rate) ||
+                                    CHECK_CODEC(width) ||
+                                    CHECK_CODEC(height)) {
+                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
+                                    matches = 0;
+                                }
+                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
+                                if (CHECK_CODEC(sample_rate) ||
+                                    CHECK_CODEC(channels) ||
+                                    CHECK_CODEC(frame_size)) {
+                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
+                                    matches = 0;
+                                }
+                            } else {
+                                printf("Unknown codec type\n");
+                                matches = 0;
+                            }
+                        }
+                        if (!matches) {
+                            break;
+                        }
+                    }
+                } else {
+                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
+                        feed->feed_filename, s->nb_streams, feed->nb_streams);
+                }
+
+                av_close_input_file(s);
+            } else {
+                printf("Deleting feed file '%s' as it appears to be corrupt\n",
+                        feed->feed_filename);
+            }
+            if (!matches)
+                unlink(feed->feed_filename);
+        }
         if (!url_exist(feed->feed_filename)) {
             AVFormatContext s1, *s = &s1;
 
@@ -3180,6 +3293,16 @@ void add_codec(FFStream *stream, AVCodecContext *av)
         av->qcompress = 0.5;
         av->qblur = 0.5;
 
+        if (!av->rc_eq)
+            av->rc_eq = "tex^qComp";
+        if (!av->i_quant_factor)
+            av->i_quant_factor = -0.8;
+        if (!av->b_quant_factor)
+            av->b_quant_factor = 1.25;
+        if (!av->b_quant_offset)
+            av->b_quant_offset = 1.25;
+            
+
         break;
     default:
         av_abort();
@@ -3421,6 +3544,7 @@ int parse_ffconfig(const char *filename)
                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
                         filename, line_num);
                 errors++;
+#if 0
             } else {
                 /* Make sure that we start out clean */
                 if (unlink(feed->feed_filename) < 0 
@@ -3429,6 +3553,7 @@ int parse_ffconfig(const char *filename)
                         filename, line_num, feed->feed_filename, strerror(errno));
                     errors++;
                 }
+#endif
             }
             feed = NULL;
         } else if (!strcasecmp(cmd, "<Stream")) {
@@ -3447,7 +3572,7 @@ int parse_ffconfig(const char *filename)
                 q = strrchr(stream->filename, '>');
                 if (*q)
                     *q = '\0';
-                stream->fmt = guess_format(NULL, stream->filename, NULL);
+                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
                 memset(&audio_enc, 0, sizeof(AVCodecContext));
                 memset(&video_enc, 0, sizeof(AVCodecContext));
                 audio_id = CODEC_ID_NONE;
@@ -3485,7 +3610,7 @@ int parse_ffconfig(const char *filename)
                 /* jpeg cannot be used here, so use single frame jpeg */
                 if (!strcmp(arg, "jpeg"))
                     strcpy(arg, "singlejpeg");
-                stream->fmt = guess_format(arg, NULL, NULL);
+                stream->fmt = guess_stream_format(arg, NULL, NULL);
                 if (!stream->fmt) {
                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
                             filename, line_num, arg);
@@ -3523,7 +3648,7 @@ int parse_ffconfig(const char *filename)
         } else if (!strcasecmp(cmd, "Preroll")) {
             get_arg(arg, sizeof(arg), &p);
             if (stream) {
-                stream->prebuffer = atoi(arg) * 1000;
+                stream->prebuffer = atof(arg) * 1000;
             }
         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
             if (stream) {
@@ -3548,7 +3673,7 @@ int parse_ffconfig(const char *filename)
         } else if (!strcasecmp(cmd, "MaxTime")) {
             get_arg(arg, sizeof(arg), &p);
             if (stream) {
-                stream->max_time = atoi(arg) * 1000;
+                stream->max_time = atof(arg) * 1000;
             }
         } else if (!strcasecmp(cmd, "AudioBitRate")) {
             get_arg(arg, sizeof(arg), &p);
@@ -3565,6 +3690,11 @@ int parse_ffconfig(const char *filename)
             if (stream) {
                 audio_enc.sample_rate = atoi(arg);
             }
+       } else if (!strcasecmp(cmd, "AudioQuality")) {
+           get_arg(arg, sizeof(arg), &p);
+            if (stream) {
+                audio_enc.quality = atof(arg) * 1000;
+            }
         } else if (!strcasecmp(cmd, "VideoBitRate")) {
             get_arg(arg, sizeof(arg), &p);
             if (stream) {
@@ -3600,6 +3730,7 @@ int parse_ffconfig(const char *filename)
                 video_enc.flags |= CODEC_FLAG_HQ;
             }
         } else if (!strcasecmp(cmd, "VideoQDiff")) {
+            get_arg(arg, sizeof(arg), &p);
             if (stream) {
                 video_enc.max_qdiff = atoi(arg);
                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
@@ -3609,6 +3740,7 @@ int parse_ffconfig(const char *filename)
                 }
             }
         } else if (!strcasecmp(cmd, "VideoQMax")) {
+            get_arg(arg, sizeof(arg), &p);
             if (stream) {
                 video_enc.qmax = atoi(arg);
                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
@@ -3618,6 +3750,7 @@ int parse_ffconfig(const char *filename)
                 }
             }
         } else if (!strcasecmp(cmd, "VideoQMin")) {
+            get_arg(arg, sizeof(arg), &p);
             if (stream) {
                 video_enc.qmin = atoi(arg);
                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
@@ -3630,6 +3763,72 @@ int parse_ffconfig(const char *filename)
             video_id = CODEC_ID_NONE;
         } else if (!strcasecmp(cmd, "NoAudio")) {
             audio_id = CODEC_ID_NONE;
+        } else if (!strcasecmp(cmd, "ACL")) {
+            IPAddressACL acl;
+            struct hostent *he;
+
+            get_arg(arg, sizeof(arg), &p);
+            if (strcasecmp(arg, "allow") == 0) {
+                acl.action = IP_ALLOW;
+            } else if (strcasecmp(arg, "deny") == 0) {
+                acl.action = IP_DENY;
+            } else {
+                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
+                        filename, line_num, arg);
+                errors++;
+            }
+
+            get_arg(arg, sizeof(arg), &p);
+
+            he = gethostbyname(arg);
+            if (!he) {
+                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
+                        filename, line_num, arg);
+                errors++;
+            } else {
+                /* Only take the first */
+                acl.first = *(struct in_addr *) he->h_addr_list[0];
+                acl.last = acl.first;
+            }
+
+            get_arg(arg, sizeof(arg), &p);
+
+            if (arg[0]) {
+                he = gethostbyname(arg);
+                if (!he) {
+                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
+                            filename, line_num, arg);
+                    errors++;
+                } else {
+                    /* Only take the first */
+                    acl.last = *(struct in_addr *) he->h_addr_list[0];
+                }
+            }
+
+            if (!errors) {
+                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
+                IPAddressACL **naclp = 0;
+
+                *nacl = acl;
+                nacl->next = 0;
+
+                if (stream) {
+                    naclp = &stream->acl;
+                } else if (feed) {
+                    naclp = &feed->acl;
+                } else {
+                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
+                            filename, line_num);
+                    errors++;
+                }
+
+                if (naclp) {
+                    while (*naclp)
+                        naclp = &(*naclp)->next;
+
+                    *naclp = nacl;
+                }
+            }
         } else if (!strcasecmp(cmd, "RTSPOption")) {
             get_arg(arg, sizeof(arg), &p);
             if (stream) {
@@ -3830,6 +4029,8 @@ int main(int argc, char **argv)
 
     putenv("http_proxy");               /* Kill the http_proxy */
 
+    srandom(gettime_ms() + (getpid() << 16));
+
     /* address on which the server will handle HTTP connections */
     my_http_addr.sin_family = AF_INET;
     my_http_addr.sin_port = htons (8080);
@@ -3875,10 +4076,12 @@ int main(int argc, char **argv)
             setsid();
             chdir("/");
             close(0);
-            close(1);
-            close(2);
             open("/dev/null", O_RDWR);
-            dup(0);
+            if (strcmp(logfilename, "-") != 0) {
+                close(1);
+                dup(0);
+            }
+            close(2);
             dup(0);
         }
     }