* If a stream gets stuck in WAIT_FEED, then disconnecting the other end
authorPhilip Gladstone <philipjsg@users.sourceforge.net>
Sat, 18 May 2002 21:33:05 +0000 (21:33 +0000)
committerPhilip Gladstone <philipjsg@users.sourceforge.net>
Sat, 18 May 2002 21:33:05 +0000 (21:33 +0000)
  will clear out the stream. I think that this is really a linux bug in
  the handling of poll, but I did a workaround anyway.
* Improve the statistics output and prevent a buffer overrun when lots
  of clients are connected.
* Process ffm input when it is received and don't always be one ffm
  packet behind.
* Try to avoid going through the poll loop when not required.

Originally committed as revision 514 to svn://svn.ffmpeg.org/ffmpeg/trunk

ffserver.c

index 1b5d4a049f584147ab8480f202922575b5db8c9a..3fc8250a513b7d7b5ad184762e6e7fff8054bbe8 100644 (file)
@@ -125,6 +125,8 @@ typedef struct FFStream {
     /* feed specific */
     int feed_opened;     /* true if someone if writing to feed */
     int is_feed;         /* true if it is a feed */
+    int conns_served;
+    INT64 bytes_served;
     INT64 feed_max_size;      /* maximum storage size */
     INT64 feed_write_index;   /* current write position in feed (it wraps round) */
     INT64 feed_size;          /* current size of feed */
@@ -272,7 +274,7 @@ static int http_server(struct sockaddr_in my_addr)
                 /* need to catch errors */
                 c->poll_entry = poll_entry;
                 poll_entry->fd = fd;
-                poll_entry->events = 0;
+                poll_entry->events = POLLIN;/* Maybe this will work */
                 poll_entry++;
                 break;
             default:
@@ -398,6 +400,8 @@ static int handle_http(HTTPContext *c, long cur_time)
             }
         } else {
             c->buffer_ptr += len;
+            c->stream->bytes_served += len;
+            c->data_count += len;
             if (c->buffer_ptr >= c->buffer_end) {
                 /* if error, exit */
                 if (c->http_error)
@@ -432,7 +436,7 @@ static int handle_http(HTTPContext *c, long cur_time)
         break;
     case HTTPSTATE_WAIT_FEED:
         /* no need to read if no events */
-        if (c->poll_entry->revents & (POLLERR | POLLHUP))
+        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
             return -1;
 
         /* nothing to do, we'll be waken up by incoming feed packets */
@@ -647,6 +651,7 @@ static int http_parse_request(HTTPContext *c)
     }
 
     c->stream = stream;
+    stream->conns_served++;
 
     /* XXX: add there authenticate and IP match */
 
@@ -770,79 +775,113 @@ static void compute_stats(HTTPContext *c)
     q += sprintf(q, "<H1>FFServer Status</H1>\n");
     /* format status */
     q += sprintf(q, "<H2>Available Streams</H2>\n");
-    q += sprintf(q, "<TABLE>\n");
-    q += sprintf(q, "<TR><Th>Path<Th>Format<Th>Bit rate (kbits/s)<Th COLSPAN=2>Video<Th COLSPAN=2>Audio<Th align=left>Feed\n");
+    q += sprintf(q, "<TABLE cellspacing=0 cellpadding=4>\n");
+    q += sprintf(q, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>kbytes<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");
     stream = first_stream;
     while (stream != NULL) {
         char sfilename[1024];
         char *eosf;
 
-        strlcpy(sfilename, stream->filename, sizeof(sfilename) - 1);
-        eosf = sfilename + strlen(sfilename);
-        if (eosf - sfilename >= 4) {
-            if (strcmp(eosf - 4, ".asf") == 0) {
-                strcpy(eosf - 4, ".asx");
-            } else if (strcmp(eosf - 3, ".rm") == 0) {
-                strcpy(eosf - 3, ".ram");
+        if (stream->feed != stream) {
+            strlcpy(sfilename, stream->filename, sizeof(sfilename) - 1);
+            eosf = sfilename + strlen(sfilename);
+            if (eosf - sfilename >= 4) {
+                if (strcmp(eosf - 4, ".asf") == 0) {
+                    strcpy(eosf - 4, ".asx");
+                } else if (strcmp(eosf - 3, ".rm") == 0) {
+                    strcpy(eosf - 3, ".ram");
+                }
             }
-        }
-        
-        q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
-                     sfilename, stream->filename);
-        switch(stream->stream_type) {
-        case STREAM_TYPE_LIVE:
-            {
-                int audio_bit_rate = 0;
-                int video_bit_rate = 0;
-                char *audio_codec_name = "";
-                char *video_codec_name = "";
-                char *audio_codec_name_extra = "";
-                char *video_codec_name_extra = "";
-
-                for(i=0;i<stream->nb_streams;i++) {
-                    AVStream *st = stream->streams[i];
-                    AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
-                    switch(st->codec.codec_type) {
-                    case CODEC_TYPE_AUDIO:
-                        audio_bit_rate += st->codec.bit_rate;
-                        if (codec) {
-                            if (*audio_codec_name)
-                                audio_codec_name_extra = "...";
-                            audio_codec_name = codec->name;
-                        }
-                        break;
-                    case CODEC_TYPE_VIDEO:
-                        video_bit_rate += st->codec.bit_rate;
-                        if (codec) {
-                            if (*video_codec_name)
-                                video_codec_name_extra = "...";
-                            video_codec_name = codec->name;
+            
+            q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
+                         sfilename, stream->filename);
+            q += sprintf(q, "<td align=right> %d <td align=right> %lld",
+                        stream->conns_served, stream->bytes_served / 1000);
+            switch(stream->stream_type) {
+            case STREAM_TYPE_LIVE:
+                {
+                    int audio_bit_rate = 0;
+                    int video_bit_rate = 0;
+                    char *audio_codec_name = "";
+                    char *video_codec_name = "";
+                    char *audio_codec_name_extra = "";
+                    char *video_codec_name_extra = "";
+
+                    for(i=0;i<stream->nb_streams;i++) {
+                        AVStream *st = stream->streams[i];
+                        AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
+                        switch(st->codec.codec_type) {
+                        case CODEC_TYPE_AUDIO:
+                            audio_bit_rate += st->codec.bit_rate;
+                            if (codec) {
+                                if (*audio_codec_name)
+                                    audio_codec_name_extra = "...";
+                                audio_codec_name = codec->name;
+                            }
+                            break;
+                        case CODEC_TYPE_VIDEO:
+                            video_bit_rate += st->codec.bit_rate;
+                            if (codec) {
+                                if (*video_codec_name)
+                                    video_codec_name_extra = "...";
+                                video_codec_name = codec->name;
+                            }
+                            break;
+                        default:
+                            abort();
                         }
-                        break;
-                    default:
-                        abort();
                     }
+                    q += sprintf(q, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s", 
+                                 stream->fmt->name,
+                                 (audio_bit_rate + video_bit_rate) / 1000,
+                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
+                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
+                    if (stream->feed) {
+                        q += sprintf(q, "<TD>%s", stream->feed->filename);
+                    } else {
+                        q += sprintf(q, "<TD>%s", stream->feed_filename);
+                    }
+                    q += sprintf(q, "\n");
                 }
-                q += sprintf(q, "<TD> %s <TD> %d <TD> %d <TD> %s %s <TD> %d <TD> %s %s", 
-                             stream->fmt->name,
-                             (audio_bit_rate + video_bit_rate) / 1000,
-                             video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
-                             audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
-                if (stream->feed) {
-                    q += sprintf(q, "<TD>%s", stream->feed->filename);
-                } else {
-                    q += sprintf(q, "<TD>%s", stream->feed_filename);
-                }
-                q += sprintf(q, "\n");
+                break;
+            default:
+                q += sprintf(q, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
+                break;
             }
-            break;
-        default:
-            q += sprintf(q, "<TD> - <TD> - <TD COLSPAN=2> - <TD COLSPAN=2> -\n");
-            break;
         }
         stream = stream->next;
     }
     q += sprintf(q, "</TABLE>\n");
+
+    stream = first_stream;
+    while (stream != NULL) {
+        if (stream->feed == stream) {
+            q += sprintf(q, "<h2>Feed %s</h2>", stream->filename);
+            q += sprintf(q, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec\n");
+
+            for (i = 0; i < stream->nb_streams; i++) {
+                AVStream *st = stream->streams[i];
+                AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
+                char *type = "unknown";
+
+                switch(st->codec.codec_type) {
+                case CODEC_TYPE_AUDIO:
+                    type = "audio";
+                    break;
+                case CODEC_TYPE_VIDEO:
+                    type = "video";
+                    break;
+                default:
+                    abort();
+                }
+                q += sprintf(q, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s\n",
+                        i, type, st->codec.bit_rate/1000, codec ? codec->name : "");
+            }
+            q += sprintf(q, "</table>\n");
+
+        }       
+        stream = stream->next;
+    }
     
 #if 0
     {
@@ -887,7 +926,7 @@ static void compute_stats(HTTPContext *c)
     q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n");
     c1 = first_http_ctx;
     i = 0;
-    while (c1 != NULL) {
+    while (c1 != NULL && q < (char *) c->buffer + sizeof(c->buffer) - 2048) {
         i++;
         p = inet_ntoa(c1->from_addr.sin_addr);
         q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <TD> %Ld\n", 
@@ -903,7 +942,7 @@ static void compute_stats(HTTPContext *c)
     /* date */
     ti = time(NULL);
     p = ctime(&ti);
-    q += sprintf(q, "<HR>Generated at %s", p);
+    q += sprintf(q, "<HR size=1 noshade>Generated at %s", p);
     q += sprintf(q, "</BODY>\n</HTML>\n");
 
     c->buffer_ptr = c->buffer;
@@ -1088,6 +1127,7 @@ static int http_prepare_data(HTTPContext *c)
                                     c->stream->feed->feed_write_index,
                                     c->stream->feed->feed_size);
             }
+            
             if (av_read_packet(c->fmt_in, &pkt) < 0) {
                 if (c->stream->feed && c->stream->feed->feed_opened) {
                     /* if coming from feed, it means we reached the end of the
@@ -1168,7 +1208,7 @@ static int http_send_data(HTTPContext *c)
         if (ret < 0)
             return -1;
         else if (ret == 0) {
-            break;
+            continue;
         } else {
             /* state change requested */
             return 0;
@@ -1185,6 +1225,7 @@ static int http_send_data(HTTPContext *c)
         } else {
             c->buffer_ptr += len;
             c->data_count += len;
+            c->stream->bytes_served += len;
         }
     }
     return 0;
@@ -1216,9 +1257,26 @@ static int http_start_receive_data(HTTPContext *c)
     
 static int http_receive_data(HTTPContext *c)
 {
-    int len;
     HTTPContext *c1;
 
+    if (c->buffer_end > c->buffer_ptr) {
+        int len;
+
+        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
+        if (len < 0) {
+            if (errno != EAGAIN && errno != EINTR) {
+                /* error : close connection */
+                goto fail;
+            }
+        } else if (len == 0) {
+            /* end of connection : close it */
+            goto fail;
+        } else {
+            c->buffer_ptr += len;
+            c->data_count += len;
+        }
+    }
+
     if (c->buffer_ptr >= c->buffer_end) {
         FFStream *feed = c->stream;
         /* a packet has been received : write it in the store, except
@@ -1276,19 +1334,6 @@ static int http_receive_data(HTTPContext *c)
         c->buffer_ptr = c->buffer;
     }
 
-    len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
-    if (len < 0) {
-        if (errno != EAGAIN && errno != EINTR) {
-            /* error : close connection */
-            goto fail;
-        }
-    } else if (len == 0) {
-        /* end of connection : close it */
-        goto fail;
-    } else {
-        c->buffer_ptr += len;
-        c->data_count += len;
-    }
     return 0;
  fail:
     c->stream->feed_opened = 0;