changeset 5619:517b5b599e3f

Mp4: moved atom cropping code out of update functions. It can now be reused for implementing mp4 end.
author Roman Arutyunyan <arut@nginx.com>
date Thu, 20 Mar 2014 16:05:18 +0400
parents c15350f4071c
children 0a567878254b
files src/http/modules/ngx_http_mp4_module.c
diffstat 1 files changed, 181 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -258,18 +258,26 @@ static ngx_int_t ngx_http_mp4_read_stts_
     uint64_t atom_data_size);
 static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak);
+static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak);
 static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4,
     uint64_t atom_data_size);
 static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak);
+static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak);
 static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4,
     uint64_t atom_data_size);
 static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak);
+static void ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak);
 static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4,
     uint64_t atom_data_size);
 static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak);
+static ngx_int_t ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak);
 static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4,
     uint64_t atom_data_size);
 static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
@@ -1981,13 +1989,9 @@ static ngx_int_t
 ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak)
 {
-    size_t                 atom_size;
-    uint32_t               entries, count, duration;
-    uint64_t               start_time;
-    ngx_buf_t             *atom, *data;
-    ngx_uint_t             start_sample;
-    ngx_mp4_stts_atom_t   *stts_atom;
-    ngx_mp4_stts_entry_t  *entry, *end;
+    size_t                atom_size;
+    ngx_buf_t            *atom, *data;
+    ngx_mp4_stts_atom_t  *stts_atom;
 
     /*
      * mdia.minf.stbl.stts updating requires trak->timescale
@@ -2006,12 +2010,40 @@ ngx_http_mp4_update_stts_atom(ngx_http_m
         return NGX_ERROR;
     }
 
-    entries = trak->time_to_sample_entries;
+    if (ngx_http_mp4_crop_stts_data(mp4, trak) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
+    trak->size += atom_size;
+
+    atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
+    stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
+    ngx_mp4_set_32value(stts_atom->size, atom_size);
+    ngx_mp4_set_32value(stts_atom->entries, trak->time_to_sample_entries);
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak)
+{
+    uint32_t               count, duration;
+    uint64_t               start_time;
+    ngx_buf_t             *data;
+    ngx_uint_t             start_sample, entries;
+    ngx_mp4_stts_entry_t  *entry, *end;
+
+    data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
+
     start_time = (uint64_t) mp4->start * trak->timescale / 1000;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                    "time-to-sample start_time:%uL", start_time);
 
+    entries = trak->time_to_sample_entries;
     start_sample = 0;
     entry = (ngx_mp4_stts_entry_t *) data->pos;
     end = (ngx_mp4_stts_entry_t *) data->last;
@@ -2047,16 +2079,9 @@ found:
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                    "start_sample:%ui, new count:%uD", start_sample, count);
 
+    trak->time_to_sample_entries = entries;
     trak->start_sample = start_sample;
-
     data->pos = (u_char *) entry;
-    atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
-    trak->size += atom_size;
-
-    atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
-    stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
-    ngx_mp4_set_32value(stts_atom->size, atom_size);
-    ngx_mp4_set_32value(stts_atom->entries, entries);
 
     return NGX_OK;
 }
@@ -2138,7 +2163,7 @@ ngx_http_mp4_update_stss_atom(ngx_http_m
     ngx_http_mp4_trak_t *trak)
 {
     size_t                     atom_size;
-    uint32_t                   entries, sample, start_sample, *entry, *end;
+    uint32_t                   sample, start_sample, *entry, *end;
     ngx_buf_t                 *atom, *data;
     ngx_http_mp4_stss_atom_t  *stss_atom;
 
@@ -2157,6 +2182,43 @@ ngx_http_mp4_update_stss_atom(ngx_http_m
         return NGX_OK;
     }
 
+    ngx_http_mp4_crop_stss_data(mp4, trak);
+
+    entry = (uint32_t *) data->pos;
+    end = (uint32_t *) data->last;
+
+    start_sample = trak->start_sample;
+
+    while (entry < end) {
+        sample = ngx_mp4_get_32value(entry);
+        sample -= start_sample;
+        ngx_mp4_set_32value(entry, sample);
+        entry++;
+    }
+
+    atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
+    trak->size += atom_size;
+
+    atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
+    stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
+
+    ngx_mp4_set_32value(stss_atom->size, atom_size);
+    ngx_mp4_set_32value(stss_atom->entries, trak->sync_samples_entries);
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak)
+{
+    uint32_t     sample, start_sample, *entry, *end;
+    ngx_buf_t   *data;
+    ngx_uint_t   entries;
+
+    data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf;
+
     /* sync samples starts from 1 */
     start_sample = trak->start_sample + 1;
     entries = trak->sync_samples_entries;
@@ -2184,26 +2246,7 @@ ngx_http_mp4_update_stss_atom(ngx_http_m
 found:
 
     data->pos = (u_char *) entry;
-
-    start_sample = trak->start_sample;
-
-    while (entry < end) {
-        sample = ngx_mp4_get_32value(entry);
-        sample -= start_sample;
-        ngx_mp4_set_32value(entry, sample);
-        entry++;
-    }
-
-    atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
-    trak->size += atom_size;
-
-    atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
-    stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
-
-    ngx_mp4_set_32value(stss_atom->size, atom_size);
-    ngx_mp4_set_32value(stss_atom->entries, entries);
-
-    return NGX_OK;
+    trak->sync_samples_entries = entries;
 }
 
 
@@ -2287,11 +2330,9 @@ static void
 ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
     ngx_http_mp4_trak_t *trak)
 {
-    size_t                 atom_size;
-    uint32_t               entries, count, start_sample;
-    ngx_buf_t             *atom, *data;
-    ngx_mp4_ctts_atom_t   *ctts_atom;
-    ngx_mp4_ctts_entry_t  *entry, *end;
+    size_t                atom_size;
+    ngx_buf_t            *atom, *data;
+    ngx_mp4_ctts_atom_t  *ctts_atom;
 
     /*
      * mdia.minf.stbl.ctts updating requires trak->start_sample
@@ -2308,6 +2349,38 @@ ngx_http_mp4_update_ctts_atom(ngx_http_m
         return;
     }
 
+    ngx_http_mp4_crop_ctts_data(mp4, trak);
+
+    if (trak->composition_offset_entries == 0) {
+        trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
+        trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
+        return;
+    }
+
+    atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
+    trak->size += atom_size;
+
+    atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
+    ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
+
+    ngx_mp4_set_32value(ctts_atom->size, atom_size);
+    ngx_mp4_set_32value(ctts_atom->entries, trak->composition_offset_entries);
+
+    return;
+}
+
+
+static void
+ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak)
+{
+    uint32_t               count, start_sample;
+    ngx_buf_t             *data;
+    ngx_uint_t             entries;
+    ngx_mp4_ctts_entry_t  *entry, *end;
+
+    data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf;
+
     /* sync samples starts from 1 */
     start_sample = trak->start_sample + 1;
     entries = trak->composition_offset_entries;
@@ -2332,24 +2405,15 @@ ngx_http_mp4_update_ctts_atom(ngx_http_m
          entry++;
     }
 
-    trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
-    trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
+    data->pos = (u_char *) end;
+    trak->composition_offset_entries = 0;
 
     return;
 
 found:
 
     data->pos = (u_char *) entry;
-    atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
-    trak->size += atom_size;
-
-    atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
-    ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
-
-    ngx_mp4_set_32value(ctts_atom->size, atom_size);
-    ngx_mp4_set_32value(ctts_atom->entries, entries);
-
-    return;
+    trak->composition_offset_entries = entries;
 }
 
 
@@ -2428,11 +2492,10 @@ ngx_http_mp4_update_stsc_atom(ngx_http_m
     ngx_http_mp4_trak_t *trak)
 {
     size_t                 atom_size;
-    uint32_t               start_sample, entries, chunk, samples, id,
-                           next_chunk, n;
-    ngx_buf_t             *atom, *data, *buf;
+    uint32_t               chunk;
+    ngx_buf_t             *atom, *data;
     ngx_mp4_stsc_atom_t   *stsc_atom;
-    ngx_mp4_stsc_entry_t  *entry, *first, *end;
+    ngx_mp4_stsc_entry_t  *entry, *end;
 
     /*
      * mdia.minf.stbl.stsc updating requires trak->start_sample
@@ -2459,6 +2522,46 @@ ngx_http_mp4_update_stsc_atom(ngx_http_m
         return NGX_ERROR;
     }
 
+    if (ngx_http_mp4_crop_stsc_data(mp4, trak) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    entry = (ngx_mp4_stsc_entry_t *) data->pos;
+    end = (ngx_mp4_stsc_entry_t *) data->last;
+
+    while (entry < end) {
+        chunk = ngx_mp4_get_32value(entry->chunk);
+        chunk -= trak->start_chunk;
+        ngx_mp4_set_32value(entry->chunk, chunk);
+        entry++;
+    }
+
+    atom_size = sizeof(ngx_mp4_stsc_atom_t)
+                + trak->sample_to_chunk_entries * sizeof(ngx_mp4_stsc_entry_t);
+
+    trak->size += atom_size;
+
+    atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
+    stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
+
+    ngx_mp4_set_32value(stsc_atom->size, atom_size);
+    ngx_mp4_set_32value(stsc_atom->entries, trak->sample_to_chunk_entries);
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
+    ngx_http_mp4_trak_t *trak)
+{
+    uint32_t               start_sample, chunk, samples, id, next_chunk, n;
+    ngx_buf_t             *data, *buf;
+    ngx_uint_t             entries, target_chunk, chunk_samples;
+    ngx_mp4_stsc_entry_t  *entry, *end, *first;
+
+    data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf;
+
     start_sample = (uint32_t) trak->start_sample;
     entries = trak->sample_to_chunk_entries - 1;
 
@@ -2521,31 +2624,32 @@ found:
         return NGX_ERROR;
     }
 
-    trak->start_chunk = chunk - 1;
-
-    trak->start_chunk += start_sample / samples;
-    trak->chunk_samples = start_sample % samples;
+    target_chunk = chunk - 1;
+    target_chunk += start_sample / samples;
+    chunk_samples = start_sample % samples;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                    "start chunk:%ui, samples:%uD",
-                   trak->start_chunk, trak->chunk_samples);
+                   target_chunk, chunk_samples);
 
     data->pos = (u_char *) entry;
-    atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos);
-
-    ngx_mp4_set_32value(entry->chunk, 1);
-
-    if (trak->chunk_samples && next_chunk - trak->start_chunk == 2) {
-
-        /* last chunk in the entry */
-
-        ngx_mp4_set_32value(entry->samples, samples - trak->chunk_samples);
-
-    } else if (trak->chunk_samples) {
+
+    trak->start_chunk = target_chunk;
+    trak->chunk_samples = chunk_samples;
+
+    ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 1);
+
+    samples -= chunk_samples;
+
+    if (chunk_samples && next_chunk - target_chunk == 2) {
+
+        ngx_mp4_set_32value(entry->samples, samples);
+
+    } else if (chunk_samples) {
 
         first = &trak->stsc_chunk_entry;
         ngx_mp4_set_32value(first->chunk, 1);
-        ngx_mp4_set_32value(first->samples, samples - trak->chunk_samples);
+        ngx_mp4_set_32value(first->samples, samples);
         ngx_mp4_set_32value(first->id, id);
 
         buf = &trak->stsc_chunk_buf;
@@ -2555,25 +2659,12 @@ found:
 
         trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf;
 
-        ngx_mp4_set_32value(entry->chunk, 2);
+        ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 2);
 
         entries++;
-        atom_size += sizeof(ngx_mp4_stsc_entry_t);
     }
 
-    while (++entry < end) {
-        chunk = ngx_mp4_get_32value(entry->chunk);
-        chunk -= trak->start_chunk;
-        ngx_mp4_set_32value(entry->chunk, chunk);
-    }
-
-    trak->size += atom_size;
-
-    atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
-    stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
-
-    ngx_mp4_set_32value(stsc_atom->size, atom_size);
-    ngx_mp4_set_32value(stsc_atom->entries, entries);
+    trak->sample_to_chunk_entries = entries;
 
     return NGX_OK;
 }