mp4_module doubt

Roman Arutyunyan arut at nginx.com
Mon May 19 12:02:43 UTC 2014


On 19 May 2014, at 04:56, 刘斌 <yurnerola at gmail.com> wrote:

> Hello,
>      I'm just reading this module and wandering if we can reduce flow
> from nginx by align start time to key frames.Our company is a video
> website from China.And i want to know does it make sense to do this.

Here’s the patch solving your problem.  Currently there are no plans to
add this to upstream but that can change.  It would be nice to hear your
feedback.  Here’s an example of “mp4_align_start” directive added by
the patch.

  location /mp4 {
      mp4;
      mp4_align_start on;
      root /tmp/;
  }

# HG changeset patch
# User Roman Arutyunyan <arut at nginx.com>
# Date 1400496445 -14400
#      Mon May 19 14:47:25 2014 +0400
# Node ID fccafb910a3361e3e2d6ca8afd6edfb576444997
# Parent  3a48775f1535fe37cd9c034d92c5a5e9ae208c1e
Mp4: align start to video key frame.

The new directive mp4_align_start adjusts start time to make
the result mp4 start with a key frame.  This makes sense for
some players displaying garbage until the first key frame.

diff -r 3a48775f1535 -r fccafb910a33 src/http/modules/ngx_http_mp4_module.c
--- a/src/http/modules/ngx_http_mp4_module.c	Tue Apr 29 12:28:41 2014 +0400
+++ b/src/http/modules/ngx_http_mp4_module.c	Mon May 19 14:47:25 2014 +0400
@@ -43,6 +43,7 @@
 typedef struct {
     size_t                buffer_size;
     size_t                max_buffer_size;
+    ngx_flag_t            align_start;
 } ngx_http_mp4_conf_t;
 
 
@@ -303,6 +304,8 @@ static ngx_int_t ngx_http_mp4_update_co6
     ngx_http_mp4_trak_t *trak);
 static void ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak, off_t adjustment);
+static ngx_int_t ngx_http_mp4_align_start(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak);
 
 static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static void *ngx_http_mp4_create_conf(ngx_conf_t *cf);
@@ -332,6 +335,13 @@ static ngx_command_t  ngx_http_mp4_comma
       offsetof(ngx_http_mp4_conf_t, max_buffer_size),
       NULL },
 
+    { ngx_string("mp4_align_start"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_mp4_conf_t, align_start),
+      NULL },
+
       ngx_null_command
 };
 
@@ -742,6 +752,14 @@ ngx_http_mp4_process(ngx_http_mp4_file_t
     end_offset = 0;
     trak = mp4->trak.elts;
 
+    if (conf->align_start) {
+        for (i = 0; i < mp4->trak.nelts; i++) {
+            if (ngx_http_mp4_align_start(mp4, &trak[i]) == NGX_OK) {
+                break;
+            }
+        }
+    }
+
     for (i = 0; i < mp4->trak.nelts; i++) {
 
         if (ngx_http_mp4_update_stts_atom(mp4, &trak[i]) != NGX_OK) {
@@ -3457,6 +3475,110 @@ ngx_http_mp4_adjust_co64_atom(ngx_http_m
 }
 
 
+static ngx_int_t
+ngx_http_mp4_align_start(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak)
+{
+    uint32_t               count, duration, sample, start_sample,
+                          *stss_entry, *stss_end;
+    uint64_t               start_time;
+    ngx_buf_t             *stts_data, *stss_data;
+    ngx_mp4_stts_entry_t  *stts_entry, *stts_end;
+
+    stss_data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf;
+    if (stss_data == NULL) {
+        return NGX_AGAIN;
+    }
+
+    stts_data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
+    if (stts_data == NULL) {
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "align start");
+
+    start_time = (uint64_t) mp4->start * trak->timescale / 1000;
+    start_sample = 0;
+
+    stts_entry = (ngx_mp4_stts_entry_t *) stts_data->pos;
+    stts_end = (ngx_mp4_stts_entry_t *) stts_data->last;
+
+    while (stts_entry < stts_end) {
+        count = ngx_mp4_get_32value(stts_entry->count);
+        duration = ngx_mp4_get_32value(stts_entry->duration);
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+                       "time:%uL, count:%uD, duration:%uD",
+                       start_time, count, duration);
+
+        if (start_time < (uint64_t) count * duration) {
+            start_sample += (ngx_uint_t) (start_time / duration);
+            goto found_stts;
+        }
+
+        start_sample += count;
+        start_time -= count * duration;
+        stts_entry++;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "out of stts samples");
+
+    return NGX_AGAIN;
+
+found_stts:
+
+    stss_entry = (uint32_t *) stss_data->pos;
+    stss_end = (uint32_t *) stss_data->last;
+
+    while (stss_entry < stss_end) {
+        sample = ngx_mp4_get_32value(stss_entry);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+                       "sync:%uD", sample);
+
+        if (sample >= start_sample + 1) {
+            sample--;
+            goto found_stss;
+        }
+
+        stss_entry++;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "out of stss samples");
+
+    return NGX_AGAIN;
+
+found_stss:
+
+    while (stts_entry < stts_end) {
+        count = ngx_mp4_get_32value(stts_entry->count);
+        duration = ngx_mp4_get_32value(stts_entry->duration);
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+                       "time:%uL, count:%uD, duration:%uD",
+                       start_time, count, duration);
+
+        if (start_sample + count >= sample) {
+            start_time += (sample - start_sample) * duration;
+            mp4->start = (uint64_t) start_time * 1000 / trak->timescale;
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+                           "aligned start:%ui, samples:%uD",
+                           mp4->start, sample - start_sample);
+
+            return NGX_OK;
+        }
+
+        start_sample += count;
+        start_time -= count * duration;
+        stts_entry++;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "out of stts samples");
+
+    return NGX_AGAIN;
+}
+
+
 static char *
 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
@@ -3481,6 +3603,7 @@ ngx_http_mp4_create_conf(ngx_conf_t *cf)
 
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
     conf->max_buffer_size = NGX_CONF_UNSET_SIZE;
+    conf->align_start = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -3495,6 +3618,7 @@ ngx_http_mp4_merge_conf(ngx_conf_t *cf, 
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024);
     ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size,
                               10 * 1024 * 1024);
+    ngx_conf_merge_value(conf->align_start, prev->align_start, 0);
 
     return NGX_CONF_OK;
 }



More information about the nginx-devel mailing list