[nginx] Mp4: added "end" argument support.
Roman Arutyunyan
arut at nginx.com
Thu Mar 20 12:06:51 UTC 2014
details: http://hg.nginx.org/nginx/rev/0a567878254b
branches:
changeset: 5620:0a567878254b
user: Roman Arutyunyan <arut at nginx.com>
date: Thu Mar 20 16:05:19 2014 +0400
description:
Mp4: added "end" argument support.
diffstat:
src/http/modules/ngx_http_mp4_module.c | 490 ++++++++++++++++++++++++++------
1 files changed, 389 insertions(+), 101 deletions(-)
diffs (truncated from 931 to 300 lines):
diff -r 517b5b599e3f -r 0a567878254b src/http/modules/ngx_http_mp4_module.c
--- a/src/http/modules/ngx_http_mp4_module.c Thu Mar 20 16:05:18 2014 +0400
+++ b/src/http/modules/ngx_http_mp4_module.c Thu Mar 20 16:05:19 2014 +0400
@@ -27,14 +27,15 @@
#define NGX_HTTP_MP4_CTTS_ATOM 15
#define NGX_HTTP_MP4_CTTS_DATA 16
#define NGX_HTTP_MP4_STSC_ATOM 17
-#define NGX_HTTP_MP4_STSC_CHUNK 18
+#define NGX_HTTP_MP4_STSC_START 18
#define NGX_HTTP_MP4_STSC_DATA 19
-#define NGX_HTTP_MP4_STSZ_ATOM 20
-#define NGX_HTTP_MP4_STSZ_DATA 21
-#define NGX_HTTP_MP4_STCO_ATOM 22
-#define NGX_HTTP_MP4_STCO_DATA 23
-#define NGX_HTTP_MP4_CO64_ATOM 24
-#define NGX_HTTP_MP4_CO64_DATA 25
+#define NGX_HTTP_MP4_STSC_END 20
+#define NGX_HTTP_MP4_STSZ_ATOM 21
+#define NGX_HTTP_MP4_STSZ_DATA 22
+#define NGX_HTTP_MP4_STCO_ATOM 23
+#define NGX_HTTP_MP4_STCO_DATA 24
+#define NGX_HTTP_MP4_CO64_ATOM 25
+#define NGX_HTTP_MP4_CO64_DATA 26
#define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA
@@ -62,10 +63,15 @@ typedef struct {
uint32_t chunks;
ngx_uint_t start_sample;
+ ngx_uint_t end_sample;
ngx_uint_t start_chunk;
- ngx_uint_t chunk_samples;
- uint64_t chunk_samples_size;
+ ngx_uint_t end_chunk;
+ ngx_uint_t start_chunk_samples;
+ ngx_uint_t end_chunk_samples;
+ uint64_t start_chunk_samples_size;
+ uint64_t end_chunk_samples_size;
off_t start_offset;
+ off_t end_offset;
size_t tkhd_size;
size_t mdhd_size;
@@ -95,7 +101,8 @@ typedef struct {
ngx_buf_t ctts_atom_buf;
ngx_buf_t ctts_data_buf;
ngx_buf_t stsc_atom_buf;
- ngx_buf_t stsc_chunk_buf;
+ ngx_buf_t stsc_start_chunk_buf;
+ ngx_buf_t stsc_end_chunk_buf;
ngx_buf_t stsc_data_buf;
ngx_buf_t stsz_atom_buf;
ngx_buf_t stsz_data_buf;
@@ -104,7 +111,8 @@ typedef struct {
ngx_buf_t co64_atom_buf;
ngx_buf_t co64_data_buf;
- ngx_mp4_stsc_entry_t stsc_chunk_entry;
+ ngx_mp4_stsc_entry_t stsc_start_chunk_entry;
+ ngx_mp4_stsc_entry_t stsc_end_chunk_entry;
} ngx_http_mp4_trak_t;
@@ -121,6 +129,7 @@ typedef struct {
off_t end;
off_t content_length;
ngx_uint_t start;
+ ngx_uint_t length;
uint32_t timescale;
ngx_http_request_t *request;
ngx_array_t trak;
@@ -219,7 +228,7 @@ static ngx_int_t ngx_http_mp4_read_moov_
static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4,
- off_t start_offset);
+ off_t start_offset, off_t end_offset);
static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4,
@@ -259,25 +268,25 @@ static ngx_int_t ngx_http_mp4_read_stts_
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);
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
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);
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
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);
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
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);
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
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,
@@ -411,8 +420,8 @@ ngx_http_mp4_handler(ngx_http_request_t
{
u_char *last;
size_t root;
- ngx_int_t rc, start;
- ngx_uint_t level;
+ ngx_int_t rc, start, end;
+ ngx_uint_t level, length;
ngx_str_t path, value;
ngx_log_t *log;
ngx_buf_t *b;
@@ -517,6 +526,7 @@ ngx_http_mp4_handler(ngx_http_request_t
r->allow_ranges = 1;
start = -1;
+ length = 0;
r->headers_out.content_length_n = of.size;
mp4 = NULL;
b = NULL;
@@ -538,6 +548,26 @@ ngx_http_mp4_handler(ngx_http_request_t
start = -1;
}
}
+
+ if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) {
+
+ ngx_set_errno(0);
+ end = (int) (strtod((char *) value.data, NULL) * 1000);
+
+ if (ngx_errno != 0) {
+ end = -1;
+ }
+
+ if (end > 0) {
+ if (start < 0) {
+ start = 0;
+ }
+
+ if (end > start) {
+ length = end - start;
+ }
+ }
+ }
}
if (start >= 0) {
@@ -553,6 +583,7 @@ ngx_http_mp4_handler(ngx_http_request_t
mp4->file.log = r->connection->log;
mp4->end = of.size;
mp4->start = (ngx_uint_t) start;
+ mp4->length = length;
mp4->request = r;
switch (ngx_http_mp4_process(mp4)) {
@@ -658,15 +689,15 @@ ngx_http_mp4_handler(ngx_http_request_t
static ngx_int_t
ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
{
- off_t start_offset, adjustment;
+ off_t start_offset, end_offset, adjustment;
ngx_int_t rc;
ngx_uint_t i, j;
ngx_chain_t **prev;
ngx_http_mp4_trak_t *trak;
ngx_http_mp4_conf_t *conf;
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "mp4 start:%ui", mp4->start);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 start:%ui, length:%ui", mp4->start, mp4->length);
conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
@@ -708,6 +739,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t
}
start_offset = mp4->end;
+ end_offset = 0;
trak = mp4->trak.elts;
for (i = 0; i < mp4->trak.nelts; i++) {
@@ -755,6 +787,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t
start_offset = trak[i].start_offset;
}
+ if (end_offset < trak[i].end_offset) {
+ end_offset = trak[i].end_offset;
+ }
+
*prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM];
prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next;
@@ -766,6 +802,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t
}
}
+ if (end_offset < start_offset) {
+ end_offset = start_offset;
+ }
+
mp4->moov_size += 8;
ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size);
@@ -782,7 +822,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t
}
adjustment = mp4->ftyp_size + mp4->moov_size
- + ngx_http_mp4_update_mdat_atom(mp4, start_offset)
+ + ngx_http_mp4_update_mdat_atom(mp4, start_offset, end_offset)
- start_offset;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -1026,7 +1066,7 @@ ngx_http_mp4_read_moov_atom(ngx_http_mp4
no_mdat = (mp4->mdat_atom.buf == NULL);
- if (no_mdat && mp4->start == 0) {
+ if (no_mdat && mp4->start == 0 && mp4->length == 0) {
/*
* send original file if moov atom resides before
* mdat atom and client requests integral file
@@ -1125,7 +1165,8 @@ ngx_http_mp4_read_mdat_atom(ngx_http_mp4
static size_t
-ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset)
+ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset,
+ off_t end_offset)
{
off_t atom_data_size;
u_char *atom_header;
@@ -1133,8 +1174,9 @@ ngx_http_mp4_update_mdat_atom(ngx_http_m
uint64_t atom_size;
ngx_buf_t *atom;
- atom_data_size = mp4->mdat_data.buf->file_last - start_offset;
+ atom_data_size = end_offset - start_offset;
mp4->mdat_data.buf->file_pos = start_offset;
+ mp4->mdat_data.buf->file_last = end_offset;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mdat new offset @%O:%O", start_offset, atom_data_size);
@@ -1216,7 +1258,7 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4
u_char *atom_header;
size_t atom_size;
uint32_t timescale;
- uint64_t duration, start_time;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_mp4_mvhd_atom_t *mvhd_atom;
ngx_mp4_mvhd64_atom_t *mvhd64_atom;
@@ -1270,6 +1312,14 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4
duration -= start_time;
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mvhd new duration:%uL, time:%.3fs",
duration, (double) duration / timescale);
@@ -1415,7 +1465,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4
{
u_char *atom_header;
size_t atom_size;
- uint64_t duration, start_time;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_http_mp4_trak_t *trak;
ngx_mp4_tkhd_atom_t *tkhd_atom;
@@ -1465,6 +1515,14 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4
duration -= start_time;
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * mp4->timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"tkhd new duration:%uL, time:%.3fs",
More information about the nginx-devel
mailing list