Browse code

* Add code to restart ffmpeg if it crashes * Add code to monitor the actual datarates on the http connections * Fix problem when ffmpeg uses more than 24 hours of CPU (display only problem)

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

Philip Gladstone authored on 2002/06/10 11:44:36
Showing 1 changed files
... ...
@@ -31,6 +31,7 @@
31 31
 #include <getopt.h>
32 32
 #include <sys/types.h>
33 33
 #include <sys/socket.h>
34
+#include <sys/wait.h>
34 35
 #include <arpa/inet.h>
35 36
 #include <netdb.h>
36 37
 #include <ctype.h>
... ...
@@ -69,6 +70,11 @@ const char *http_state[] = {
69 69
 #define REQUEST_TIMEOUT (15 * 1000)
70 70
 #define SYNC_TIMEOUT (10 * 1000)
71 71
 
72
+typedef struct {
73
+    INT64 count1, count2;
74
+    long time1, time2;
75
+} DataRateData;
76
+
72 77
 /* context associated with one connection */
73 78
 typedef struct HTTPContext {
74 79
     enum HTTPState state;
... ...
@@ -96,6 +102,7 @@ typedef struct HTTPContext {
96 96
     int suppress_log;
97 97
     int bandwidth;
98 98
     long start_time;            /* In milliseconds - this wraps fairly often */
99
+    DataRateData datarate;
99 100
     int wmp_client_id;
100 101
     char protocol[16];
101 102
     char method[16];
... ...
@@ -132,6 +139,7 @@ typedef struct FFStream {
132 132
     char copyright[512];
133 133
     char comment[512];
134 134
     pid_t pid;  /* Of ffmpeg process */
135
+    time_t pid_start;  /* Of ffmpeg process */
135 136
     char **child_argv;
136 137
     struct FFStream *next;
137 138
     /* feed specific */
... ...
@@ -156,9 +164,9 @@ HTTPContext *first_http_ctx;
156 156
 FFStream *first_feed;   /* contains only feeds */
157 157
 FFStream *first_stream; /* contains all streams, including feeds */
158 158
 
159
-static int handle_http(HTTPContext *c, long cur_time);
159
+static int handle_http(HTTPContext *c);
160 160
 static int http_parse_request(HTTPContext *c);
161
-static int http_send_data(HTTPContext *c, long cur_time);
161
+static int http_send_data(HTTPContext *c);
162 162
 static void compute_stats(HTTPContext *c);
163 163
 static int open_input_stream(HTTPContext *c, const char *info);
164 164
 static int http_start_receive_data(HTTPContext *c);
... ...
@@ -168,6 +176,7 @@ static const char *my_program_name;
168 168
 
169 169
 static int ffserver_debug;
170 170
 static int no_launch;
171
+static int need_to_start_children;
171 172
 
172 173
 int nb_max_connections;
173 174
 int nb_connections;
... ...
@@ -175,6 +184,8 @@ int nb_connections;
175 175
 int nb_max_bandwidth;
176 176
 int nb_bandwidth;
177 177
 
178
+static long cur_time;           // Making this global saves on passing it around everywhere
179
+
178 180
 static long gettime_ms(void)
179 181
 {
180 182
     struct timeval tv;
... ...
@@ -218,13 +229,39 @@ static void log_connection(HTTPContext *c)
218 218
              buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
219 219
 }
220 220
 
221
+static void update_datarate(DataRateData *drd, INT64 count)
222
+{
223
+    if (!drd->time1 && !drd->count1) {
224
+        drd->time1 = drd->time2 = cur_time;
225
+        drd->count1 = drd->count2 = count;
226
+    } else {
227
+        if (cur_time - drd->time2 > 5000) {
228
+            drd->time1 = drd->time2;
229
+            drd->count1 = drd->count2;
230
+            drd->time2 = cur_time;
231
+            drd->count2 = count;
232
+        }
233
+    }
234
+}
235
+
236
+/* In bytes per second */
237
+static int compute_datarate(DataRateData *drd, INT64 count)
238
+{
239
+    if (cur_time == drd->time1)
240
+        return 0;
241
+
242
+    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
243
+}
244
+
221 245
 static void start_children(FFStream *feed)
222 246
 {
223 247
     if (no_launch)
224 248
         return;
225 249
 
226 250
     for (; feed; feed = feed->next) {
227
-        if (feed->child_argv) {
251
+        if (feed->child_argv && !feed->pid) {
252
+            feed->pid_start = time(0);
253
+
228 254
             feed->pid = fork();
229 255
 
230 256
             if (feed->pid < 0) {
... ...
@@ -237,16 +274,18 @@ static void start_children(FFStream *feed)
237 237
                 char *slash;
238 238
                 int i;
239 239
 
240
-                if (!ffserver_debug) {
241
-                    for (i = 0; i < 10; i++) {
242
-                        close(i);
243
-                    }
240
+                for (i = 3; i < 256; i++) {
241
+                    close(i);
242
+                }
244 243
 
244
+                if (!ffserver_debug) {
245 245
                     i = open("/dev/null", O_RDWR);
246 246
                     if (i)
247 247
                         dup2(i, 0);
248 248
                     dup2(i, 1);
249 249
                     dup2(i, 2);
250
+                    if (i)
251
+                        close(i);
250 252
                 }
251 253
 
252 254
                 pstrcpy(pathname, sizeof(pathname), my_program_name);
... ...
@@ -274,7 +313,6 @@ static int http_server(struct sockaddr_in my_addr)
274 274
     struct sockaddr_in from_addr;
275 275
     struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
276 276
     HTTPContext *c, **cp;
277
-    long cur_time;
278 277
 
279 278
     server_fd = socket(AF_INET,SOCK_STREAM,0);
280 279
     if (server_fd < 0) {
... ...
@@ -360,12 +398,17 @@ static int http_server(struct sockaddr_in my_addr)
360 360
         
361 361
         cur_time = gettime_ms();
362 362
 
363
+        if (need_to_start_children) {
364
+            need_to_start_children = 0;
365
+            start_children(first_feed);
366
+        }
367
+
363 368
         /* now handle the events */
364 369
 
365 370
         cp = &first_http_ctx;
366 371
         while ((*cp) != NULL) {
367 372
             c = *cp;
368
-            if (handle_http (c, cur_time) < 0) {
373
+            if (handle_http (c) < 0) {
369 374
                 /* close and free the connection */
370 375
                 log_connection(c);
371 376
                 close(c->fd);
... ...
@@ -430,7 +473,7 @@ static int http_server(struct sockaddr_in my_addr)
430 430
     }
431 431
 }
432 432
 
433
-static int handle_http(HTTPContext *c, long cur_time)
433
+static int handle_http(HTTPContext *c)
434 434
 {
435 435
     int len;
436 436
     
... ...
@@ -507,7 +550,7 @@ static int handle_http(HTTPContext *c, long cur_time)
507 507
         
508 508
         if (!(c->poll_entry->revents & POLLOUT))
509 509
             return 0;
510
-        if (http_send_data(c, cur_time) < 0)
510
+        if (http_send_data(c) < 0)
511 511
             return -1;
512 512
         break;
513 513
     case HTTPSTATE_RECEIVE_DATA:
... ...
@@ -1207,7 +1250,7 @@ static void compute_stats(HTTPContext *c)
1207 1207
 
1208 1208
 #ifdef linux
1209 1209
                 /* This is somewhat linux specific I guess */
1210
-                snprintf(ps_cmd, sizeof(ps_cmd), "ps -o \"%%cpu,cputime\" --no-headers %d", stream->pid);
1210
+                snprintf(ps_cmd, sizeof(ps_cmd), "ps -o \"%%cpu,bsdtime\" --no-headers %d", stream->pid);
1211 1211
 
1212 1212
                 pid_stat = popen(ps_cmd, "r");
1213 1213
                 if (pid_stat) {
... ...
@@ -1295,7 +1338,7 @@ static void compute_stats(HTTPContext *c)
1295 1295
                  nb_bandwidth, nb_max_bandwidth);
1296 1296
 
1297 1297
     q += sprintf(q, "<TABLE>\n");
1298
-    q += sprintf(q, "<TR><Th>#<Th>File<Th>IP<Th>State<Th>kbits/sec<Th>Size\n");
1298
+    q += sprintf(q, "<TR><Th>#<Th>File<Th>IP<Th>State<Th>Target bits/sec<Th>Actual bits/sec<Th>Bytes transferred\n");
1299 1299
     c1 = first_http_ctx;
1300 1300
     i = 0;
1301 1301
     while (c1 != NULL && q < (char *) c->buffer + c->buffer_size - 2048) {
... ...
@@ -1311,12 +1354,15 @@ static void compute_stats(HTTPContext *c)
1311 1311
 
1312 1312
         i++;
1313 1313
         p = inet_ntoa(c1->from_addr.sin_addr);
1314
-        q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <td align=right> %d <TD align=right> ", 
1314
+        q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <td align=right>", 
1315 1315
                      i, c1->stream->filename, 
1316 1316
                      c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1317 1317
                      p, 
1318
-                     http_state[c1->state],
1319
-                     bitrate / 1000);
1318
+                     http_state[c1->state]);
1319
+        q += fmt_bytecount(q, bitrate);
1320
+        q += sprintf(q, "<td align=right>");
1321
+        q += fmt_bytecount(q, compute_datarate(&c1->datarate, c1->data_count) * 8);
1322
+        q += sprintf(q, "<td align=right>");
1320 1323
         q += fmt_bytecount(q, c1->data_count);
1321 1324
         *q++ = '\n';
1322 1325
         c1 = c1->next;
... ...
@@ -1414,7 +1460,7 @@ static int open_input_stream(HTTPContext *c, const char *info)
1414 1414
     return 0;
1415 1415
 }
1416 1416
 
1417
-static int http_prepare_data(HTTPContext *c, long cur_time)
1417
+static int http_prepare_data(HTTPContext *c)
1418 1418
 {
1419 1419
     int i;
1420 1420
 
... ...
@@ -1622,12 +1668,12 @@ static int http_prepare_data(HTTPContext *c, long cur_time)
1622 1622
 }
1623 1623
 
1624 1624
 /* should convert the format at the same time */
1625
-static int http_send_data(HTTPContext *c, long cur_time)
1625
+static int http_send_data(HTTPContext *c)
1626 1626
 {
1627 1627
     int len, ret;
1628 1628
 
1629 1629
     while (c->buffer_ptr >= c->buffer_end) {
1630
-        ret = http_prepare_data(c, cur_time);
1630
+        ret = http_prepare_data(c);
1631 1631
         if (ret < 0)
1632 1632
             return -1;
1633 1633
         else if (ret == 0) {
... ...
@@ -1648,6 +1694,7 @@ static int http_send_data(HTTPContext *c, long cur_time)
1648 1648
         } else {
1649 1649
             c->buffer_ptr += len;
1650 1650
             c->data_count += len;
1651
+            update_datarate(&c->datarate, c->data_count);
1651 1652
             if (c->stream)
1652 1653
                 c->stream->bytes_served += len;
1653 1654
         }
... ...
@@ -1698,6 +1745,7 @@ static int http_receive_data(HTTPContext *c)
1698 1698
         } else {
1699 1699
             c->buffer_ptr += len;
1700 1700
             c->data_count += len;
1701
+            update_datarate(&c->datarate, c->data_count);
1701 1702
         }
1702 1703
     }
1703 1704
 
... ...
@@ -2505,10 +2553,37 @@ void licence(void)
2505 2505
     );
2506 2506
 }
2507 2507
 
2508
+static void handle_child_exit(int sig)
2509
+{
2510
+    pid_t pid;
2511
+    int status;
2512
+
2513
+    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
2514
+        FFStream *feed;
2515
+
2516
+        for (feed = first_feed; feed; feed = feed->next) {
2517
+            if (feed->pid == pid) {
2518
+                int uptime = time(0) - feed->pid_start;
2519
+
2520
+                feed->pid = 0;
2521
+                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
2522
+
2523
+                if (uptime < 30) {
2524
+                    /* Turn off any more restarts */
2525
+                    feed->child_argv = 0;
2526
+                }    
2527
+            }
2528
+        }
2529
+    }
2530
+
2531
+    need_to_start_children = 1;
2532
+}
2533
+
2508 2534
 int main(int argc, char **argv)
2509 2535
 {
2510 2536
     const char *config_filename;
2511 2537
     int c;
2538
+    struct sigaction sigact;
2512 2539
 
2513 2540
     register_all();
2514 2541
 
... ...
@@ -2553,6 +2628,11 @@ int main(int argc, char **argv)
2553 2553
     first_stream = NULL;
2554 2554
     logfilename[0] = '\0';
2555 2555
 
2556
+    memset(&sigact, 0, sizeof(sigact));
2557
+    sigact.sa_handler = handle_child_exit;
2558
+    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
2559
+    sigaction(SIGCHLD, &sigact, 0);
2560
+
2556 2561
     if (parse_ffconfig(config_filename) < 0) {
2557 2562
         fprintf(stderr, "Incorrect config file - exiting.\n");
2558 2563
         exit(1);