Mercurial > hg > nginx
comparison src/http/modules/ngx_http_mp4_module.c @ 7945:f17ba8ecaaf0
Mp4: mp4_start_key_frame directive.
The directive enables including all frames from start time to the most recent
key frame in the result. Those frames are removed from presentation timeline
using mp4 edit lists.
Edit lists are currently supported by popular players and browsers such as
Chrome, Safari, QuickTime and ffmpeg. Among those not supporting them properly
is Firefox[1].
Based on a patch by Tracey Jaquith, Internet Archive.
[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1735300
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 28 Oct 2021 14:14:25 +0300 |
parents | 24f7904dbfa0 |
children | 1afd19dc7161 adae1da17749 |
comparison
equal
deleted
inserted
replaced
7944:24f7904dbfa0 | 7945:f17ba8ecaaf0 |
---|---|
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 | 11 |
12 #define NGX_HTTP_MP4_TRAK_ATOM 0 | 12 #define NGX_HTTP_MP4_TRAK_ATOM 0 |
13 #define NGX_HTTP_MP4_TKHD_ATOM 1 | 13 #define NGX_HTTP_MP4_TKHD_ATOM 1 |
14 #define NGX_HTTP_MP4_MDIA_ATOM 2 | 14 #define NGX_HTTP_MP4_EDTS_ATOM 2 |
15 #define NGX_HTTP_MP4_MDHD_ATOM 3 | 15 #define NGX_HTTP_MP4_ELST_ATOM 3 |
16 #define NGX_HTTP_MP4_HDLR_ATOM 4 | 16 #define NGX_HTTP_MP4_MDIA_ATOM 4 |
17 #define NGX_HTTP_MP4_MINF_ATOM 5 | 17 #define NGX_HTTP_MP4_MDHD_ATOM 5 |
18 #define NGX_HTTP_MP4_VMHD_ATOM 6 | 18 #define NGX_HTTP_MP4_HDLR_ATOM 6 |
19 #define NGX_HTTP_MP4_SMHD_ATOM 7 | 19 #define NGX_HTTP_MP4_MINF_ATOM 7 |
20 #define NGX_HTTP_MP4_DINF_ATOM 8 | 20 #define NGX_HTTP_MP4_VMHD_ATOM 8 |
21 #define NGX_HTTP_MP4_STBL_ATOM 9 | 21 #define NGX_HTTP_MP4_SMHD_ATOM 9 |
22 #define NGX_HTTP_MP4_STSD_ATOM 10 | 22 #define NGX_HTTP_MP4_DINF_ATOM 10 |
23 #define NGX_HTTP_MP4_STTS_ATOM 11 | 23 #define NGX_HTTP_MP4_STBL_ATOM 11 |
24 #define NGX_HTTP_MP4_STTS_DATA 12 | 24 #define NGX_HTTP_MP4_STSD_ATOM 12 |
25 #define NGX_HTTP_MP4_STSS_ATOM 13 | 25 #define NGX_HTTP_MP4_STTS_ATOM 13 |
26 #define NGX_HTTP_MP4_STSS_DATA 14 | 26 #define NGX_HTTP_MP4_STTS_DATA 14 |
27 #define NGX_HTTP_MP4_CTTS_ATOM 15 | 27 #define NGX_HTTP_MP4_STSS_ATOM 15 |
28 #define NGX_HTTP_MP4_CTTS_DATA 16 | 28 #define NGX_HTTP_MP4_STSS_DATA 16 |
29 #define NGX_HTTP_MP4_STSC_ATOM 17 | 29 #define NGX_HTTP_MP4_CTTS_ATOM 17 |
30 #define NGX_HTTP_MP4_STSC_START 18 | 30 #define NGX_HTTP_MP4_CTTS_DATA 18 |
31 #define NGX_HTTP_MP4_STSC_DATA 19 | 31 #define NGX_HTTP_MP4_STSC_ATOM 19 |
32 #define NGX_HTTP_MP4_STSC_END 20 | 32 #define NGX_HTTP_MP4_STSC_START 20 |
33 #define NGX_HTTP_MP4_STSZ_ATOM 21 | 33 #define NGX_HTTP_MP4_STSC_DATA 21 |
34 #define NGX_HTTP_MP4_STSZ_DATA 22 | 34 #define NGX_HTTP_MP4_STSC_END 22 |
35 #define NGX_HTTP_MP4_STCO_ATOM 23 | 35 #define NGX_HTTP_MP4_STSZ_ATOM 23 |
36 #define NGX_HTTP_MP4_STCO_DATA 24 | 36 #define NGX_HTTP_MP4_STSZ_DATA 24 |
37 #define NGX_HTTP_MP4_CO64_ATOM 25 | 37 #define NGX_HTTP_MP4_STCO_ATOM 25 |
38 #define NGX_HTTP_MP4_CO64_DATA 26 | 38 #define NGX_HTTP_MP4_STCO_DATA 26 |
39 #define NGX_HTTP_MP4_CO64_ATOM 27 | |
40 #define NGX_HTTP_MP4_CO64_DATA 28 | |
39 | 41 |
40 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA | 42 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA |
41 | 43 |
42 | 44 |
43 typedef struct { | 45 typedef struct { |
44 size_t buffer_size; | 46 size_t buffer_size; |
45 size_t max_buffer_size; | 47 size_t max_buffer_size; |
48 ngx_flag_t start_key_frame; | |
46 } ngx_http_mp4_conf_t; | 49 } ngx_http_mp4_conf_t; |
47 | 50 |
48 | 51 |
49 typedef struct { | 52 typedef struct { |
50 u_char chunk[4]; | 53 u_char chunk[4]; |
51 u_char samples[4]; | 54 u_char samples[4]; |
52 u_char id[4]; | 55 u_char id[4]; |
53 } ngx_mp4_stsc_entry_t; | 56 } ngx_mp4_stsc_entry_t; |
57 | |
58 | |
59 typedef struct { | |
60 u_char size[4]; | |
61 u_char name[4]; | |
62 } ngx_mp4_edts_atom_t; | |
63 | |
64 | |
65 typedef struct { | |
66 u_char size[4]; | |
67 u_char name[4]; | |
68 u_char version[1]; | |
69 u_char flags[3]; | |
70 u_char entries[4]; | |
71 u_char duration[8]; | |
72 u_char media_time[8]; | |
73 u_char media_rate[2]; | |
74 u_char reserved[2]; | |
75 } ngx_mp4_elst_atom_t; | |
54 | 76 |
55 | 77 |
56 typedef struct { | 78 typedef struct { |
57 uint32_t timescale; | 79 uint32_t timescale; |
58 uint32_t time_to_sample_entries; | 80 uint32_t time_to_sample_entries; |
69 ngx_uint_t start_chunk_samples; | 91 ngx_uint_t start_chunk_samples; |
70 ngx_uint_t end_chunk_samples; | 92 ngx_uint_t end_chunk_samples; |
71 uint64_t start_chunk_samples_size; | 93 uint64_t start_chunk_samples_size; |
72 uint64_t end_chunk_samples_size; | 94 uint64_t end_chunk_samples_size; |
73 uint64_t duration; | 95 uint64_t duration; |
96 uint64_t prefix; | |
97 uint64_t movie_duration; | |
74 off_t start_offset; | 98 off_t start_offset; |
75 off_t end_offset; | 99 off_t end_offset; |
76 | 100 |
77 size_t tkhd_size; | 101 size_t tkhd_size; |
78 size_t mdhd_size; | 102 size_t mdhd_size; |
84 | 108 |
85 ngx_chain_t out[NGX_HTTP_MP4_LAST_ATOM + 1]; | 109 ngx_chain_t out[NGX_HTTP_MP4_LAST_ATOM + 1]; |
86 | 110 |
87 ngx_buf_t trak_atom_buf; | 111 ngx_buf_t trak_atom_buf; |
88 ngx_buf_t tkhd_atom_buf; | 112 ngx_buf_t tkhd_atom_buf; |
113 ngx_buf_t edts_atom_buf; | |
114 ngx_buf_t elst_atom_buf; | |
89 ngx_buf_t mdia_atom_buf; | 115 ngx_buf_t mdia_atom_buf; |
90 ngx_buf_t mdhd_atom_buf; | 116 ngx_buf_t mdhd_atom_buf; |
91 ngx_buf_t hdlr_atom_buf; | 117 ngx_buf_t hdlr_atom_buf; |
92 ngx_buf_t minf_atom_buf; | 118 ngx_buf_t minf_atom_buf; |
93 ngx_buf_t vmhd_atom_buf; | 119 ngx_buf_t vmhd_atom_buf; |
110 ngx_buf_t stco_atom_buf; | 136 ngx_buf_t stco_atom_buf; |
111 ngx_buf_t stco_data_buf; | 137 ngx_buf_t stco_data_buf; |
112 ngx_buf_t co64_atom_buf; | 138 ngx_buf_t co64_atom_buf; |
113 ngx_buf_t co64_data_buf; | 139 ngx_buf_t co64_data_buf; |
114 | 140 |
141 ngx_mp4_edts_atom_t edts_atom; | |
142 ngx_mp4_elst_atom_t elst_atom; | |
115 ngx_mp4_stsc_entry_t stsc_start_chunk_entry; | 143 ngx_mp4_stsc_entry_t stsc_start_chunk_entry; |
116 ngx_mp4_stsc_entry_t stsc_end_chunk_entry; | 144 ngx_mp4_stsc_entry_t stsc_end_chunk_entry; |
117 } ngx_http_mp4_trak_t; | 145 } ngx_http_mp4_trak_t; |
118 | 146 |
119 | 147 |
184 #define ngx_mp4_set_atom_name(p, n1, n2, n3, n4) \ | 212 #define ngx_mp4_set_atom_name(p, n1, n2, n3, n4) \ |
185 ((u_char *) (p))[4] = n1; \ | 213 ((u_char *) (p))[4] = n1; \ |
186 ((u_char *) (p))[5] = n2; \ | 214 ((u_char *) (p))[5] = n2; \ |
187 ((u_char *) (p))[6] = n3; \ | 215 ((u_char *) (p))[6] = n3; \ |
188 ((u_char *) (p))[7] = n4 | 216 ((u_char *) (p))[7] = n4 |
217 | |
218 #define ngx_mp4_get_16value(p) \ | |
219 ( ((uint16_t) ((u_char *) (p))[0] << 8) \ | |
220 + ( ((u_char *) (p))[1]) ) | |
221 | |
222 #define ngx_mp4_set_16value(p, n) \ | |
223 ((u_char *) (p))[0] = (u_char) ((n) >> 8); \ | |
224 ((u_char *) (p))[1] = (u_char) (n) | |
189 | 225 |
190 #define ngx_mp4_get_32value(p) \ | 226 #define ngx_mp4_get_32value(p) \ |
191 ( ((uint32_t) ((u_char *) (p))[0] << 24) \ | 227 ( ((uint32_t) ((u_char *) (p))[0] << 24) \ |
192 + ( ((u_char *) (p))[1] << 16) \ | 228 + ( ((u_char *) (p))[1] << 16) \ |
193 + ( ((u_char *) (p))[2] << 8) \ | 229 + ( ((u_char *) (p))[2] << 8) \ |
268 uint64_t atom_data_size); | 304 uint64_t atom_data_size); |
269 static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, | 305 static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, |
270 uint64_t atom_data_size); | 306 uint64_t atom_data_size); |
271 static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, | 307 static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, |
272 uint64_t atom_data_size); | 308 uint64_t atom_data_size); |
309 static void ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, | |
310 ngx_http_mp4_trak_t *trak); | |
273 static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, | 311 static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, |
274 ngx_http_mp4_trak_t *trak); | 312 ngx_http_mp4_trak_t *trak); |
275 static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, | 313 static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, |
276 uint64_t atom_data_size); | 314 uint64_t atom_data_size); |
277 static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, | 315 static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, |
278 uint64_t atom_data_size); | 316 uint64_t atom_data_size); |
279 static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, | 317 static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, |
280 ngx_http_mp4_trak_t *trak); | 318 ngx_http_mp4_trak_t *trak); |
281 static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, | 319 static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, |
282 ngx_http_mp4_trak_t *trak, ngx_uint_t start); | 320 ngx_http_mp4_trak_t *trak, ngx_uint_t start); |
321 static uint32_t ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, | |
322 ngx_http_mp4_trak_t *trak, uint32_t start_sample); | |
283 static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, | 323 static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, |
284 uint64_t atom_data_size); | 324 uint64_t atom_data_size); |
285 static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, | 325 static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, |
286 ngx_http_mp4_trak_t *trak); | 326 ngx_http_mp4_trak_t *trak); |
287 static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, | 327 static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4, |
341 ngx_conf_set_size_slot, | 381 ngx_conf_set_size_slot, |
342 NGX_HTTP_LOC_CONF_OFFSET, | 382 NGX_HTTP_LOC_CONF_OFFSET, |
343 offsetof(ngx_http_mp4_conf_t, max_buffer_size), | 383 offsetof(ngx_http_mp4_conf_t, max_buffer_size), |
344 NULL }, | 384 NULL }, |
345 | 385 |
386 { ngx_string("mp4_start_key_frame"), | |
387 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
388 ngx_conf_set_flag_slot, | |
389 NGX_HTTP_LOC_CONF_OFFSET, | |
390 offsetof(ngx_http_mp4_conf_t, start_key_frame), | |
391 NULL }, | |
392 | |
346 ngx_null_command | 393 ngx_null_command |
347 }; | 394 }; |
348 | 395 |
349 | 396 |
350 static ngx_http_module_t ngx_http_mp4_module_ctx = { | 397 static ngx_http_module_t ngx_http_mp4_module_ctx = { |
827 ngx_http_mp4_update_minf_atom(mp4, &trak[i]); | 874 ngx_http_mp4_update_minf_atom(mp4, &trak[i]); |
828 ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]); | 875 ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]); |
829 trak[i].size += trak[i].hdlr_size; | 876 trak[i].size += trak[i].hdlr_size; |
830 ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); | 877 ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); |
831 trak[i].size += trak[i].tkhd_size; | 878 trak[i].size += trak[i].tkhd_size; |
879 ngx_http_mp4_update_edts_atom(mp4, &trak[i]); | |
832 ngx_http_mp4_update_trak_atom(mp4, &trak[i]); | 880 ngx_http_mp4_update_trak_atom(mp4, &trak[i]); |
833 | 881 |
834 mp4->moov_size += trak[i].size; | 882 mp4->moov_size += trak[i].size; |
835 | 883 |
836 if (start_offset > trak[i].start_offset) { | 884 if (start_offset > trak[i].start_offset) { |
1588 | 1636 |
1589 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | 1637 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; |
1590 | 1638 |
1591 trak = ngx_mp4_last_trak(mp4); | 1639 trak = ngx_mp4_last_trak(mp4); |
1592 trak->tkhd_size = atom_size; | 1640 trak->tkhd_size = atom_size; |
1641 trak->movie_duration = duration; | |
1593 | 1642 |
1594 ngx_mp4_set_32value(tkhd_atom->size, atom_size); | 1643 ngx_mp4_set_32value(tkhd_atom->size, atom_size); |
1595 | 1644 |
1596 if (tkhd_atom->version[0] == 0) { | 1645 if (tkhd_atom->version[0] == 0) { |
1597 ngx_mp4_set_32value(tkhd_atom->duration, duration); | 1646 ngx_mp4_set_32value(tkhd_atom->duration, duration); |
1984 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_stbl_atoms, atom_data_size); | 2033 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_stbl_atoms, atom_data_size); |
1985 } | 2034 } |
1986 | 2035 |
1987 | 2036 |
1988 static void | 2037 static void |
2038 ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, | |
2039 ngx_http_mp4_trak_t *trak) | |
2040 { | |
2041 ngx_buf_t *atom; | |
2042 ngx_mp4_elst_atom_t *elst_atom; | |
2043 ngx_mp4_edts_atom_t *edts_atom; | |
2044 | |
2045 if (trak->prefix == 0) { | |
2046 return; | |
2047 } | |
2048 | |
2049 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2050 "mp4 edts atom update prefix:%uL", trak->prefix); | |
2051 | |
2052 edts_atom = &trak->edts_atom; | |
2053 ngx_mp4_set_32value(edts_atom->size, sizeof(ngx_mp4_edts_atom_t) | |
2054 + sizeof(ngx_mp4_elst_atom_t)); | |
2055 ngx_mp4_set_atom_name(edts_atom, 'e', 'd', 't', 's'); | |
2056 | |
2057 atom = &trak->edts_atom_buf; | |
2058 atom->temporary = 1; | |
2059 atom->pos = (u_char *) edts_atom; | |
2060 atom->last = (u_char *) edts_atom + sizeof(ngx_mp4_edts_atom_t); | |
2061 | |
2062 trak->out[NGX_HTTP_MP4_EDTS_ATOM].buf = atom; | |
2063 | |
2064 elst_atom = &trak->elst_atom; | |
2065 ngx_mp4_set_32value(elst_atom->size, sizeof(ngx_mp4_elst_atom_t)); | |
2066 ngx_mp4_set_atom_name(elst_atom, 'e', 'l', 's', 't'); | |
2067 | |
2068 elst_atom->version[0] = 1; | |
2069 elst_atom->flags[0] = 0; | |
2070 elst_atom->flags[1] = 0; | |
2071 elst_atom->flags[2] = 0; | |
2072 | |
2073 ngx_mp4_set_32value(elst_atom->entries, 1); | |
2074 ngx_mp4_set_64value(elst_atom->duration, trak->movie_duration); | |
2075 ngx_mp4_set_64value(elst_atom->media_time, trak->prefix); | |
2076 ngx_mp4_set_16value(elst_atom->media_rate, 1); | |
2077 ngx_mp4_set_16value(elst_atom->reserved, 0); | |
2078 | |
2079 atom = &trak->elst_atom_buf; | |
2080 atom->temporary = 1; | |
2081 atom->pos = (u_char *) elst_atom; | |
2082 atom->last = (u_char *) elst_atom + sizeof(ngx_mp4_elst_atom_t); | |
2083 | |
2084 trak->out[NGX_HTTP_MP4_ELST_ATOM].buf = atom; | |
2085 | |
2086 trak->size += sizeof(ngx_mp4_edts_atom_t) + sizeof(ngx_mp4_elst_atom_t); | |
2087 } | |
2088 | |
2089 | |
2090 static void | |
1989 ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, | 2091 ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, |
1990 ngx_http_mp4_trak_t *trak) | 2092 ngx_http_mp4_trak_t *trak) |
1991 { | 2093 { |
1992 ngx_buf_t *atom; | 2094 ngx_buf_t *atom; |
1993 | 2095 |
2181 | 2283 |
2182 static ngx_int_t | 2284 static ngx_int_t |
2183 ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, | 2285 ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, |
2184 ngx_http_mp4_trak_t *trak, ngx_uint_t start) | 2286 ngx_http_mp4_trak_t *trak, ngx_uint_t start) |
2185 { | 2287 { |
2186 uint32_t count, duration, rest; | 2288 uint32_t count, duration, rest, key_prefix; |
2187 uint64_t start_time; | 2289 uint64_t start_time; |
2188 ngx_buf_t *data; | 2290 ngx_buf_t *data; |
2189 ngx_uint_t start_sample, entries, start_sec; | 2291 ngx_uint_t start_sample, entries, start_sec; |
2190 ngx_mp4_stts_entry_t *entry, *end; | 2292 ngx_mp4_stts_entry_t *entry, *end; |
2191 | 2293 |
2205 return NGX_OK; | 2307 return NGX_OK; |
2206 } | 2308 } |
2207 | 2309 |
2208 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; | 2310 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; |
2209 | 2311 |
2210 start_time = (uint64_t) start_sec * trak->timescale / 1000; | 2312 start_time = (uint64_t) start_sec * trak->timescale / 1000 + trak->prefix; |
2211 | 2313 |
2212 entries = trak->time_to_sample_entries; | 2314 entries = trak->time_to_sample_entries; |
2213 start_sample = 0; | 2315 start_sample = 0; |
2214 entry = (ngx_mp4_stts_entry_t *) data->pos; | 2316 entry = (ngx_mp4_stts_entry_t *) data->pos; |
2215 end = (ngx_mp4_stts_entry_t *) data->last; | 2317 end = (ngx_mp4_stts_entry_t *) data->last; |
2251 } | 2353 } |
2252 | 2354 |
2253 found: | 2355 found: |
2254 | 2356 |
2255 if (start) { | 2357 if (start) { |
2358 key_prefix = ngx_http_mp4_seek_key_frame(mp4, trak, start_sample); | |
2359 | |
2360 start_sample -= key_prefix; | |
2361 | |
2362 while (rest < key_prefix) { | |
2363 trak->prefix += rest * duration; | |
2364 key_prefix -= rest; | |
2365 | |
2366 entry--; | |
2367 entries++; | |
2368 | |
2369 count = ngx_mp4_get_32value(entry->count); | |
2370 duration = ngx_mp4_get_32value(entry->duration); | |
2371 rest = count; | |
2372 } | |
2373 | |
2374 trak->prefix += key_prefix * duration; | |
2375 trak->duration += trak->prefix; | |
2376 rest -= key_prefix; | |
2377 | |
2256 ngx_mp4_set_32value(entry->count, count - rest); | 2378 ngx_mp4_set_32value(entry->count, count - rest); |
2257 data->pos = (u_char *) entry; | 2379 data->pos = (u_char *) entry; |
2258 trak->time_to_sample_entries = entries; | 2380 trak->time_to_sample_entries = entries; |
2259 trak->start_sample = start_sample; | 2381 trak->start_sample = start_sample; |
2260 | 2382 |
2272 "end_sample:%ui, new count:%uD", | 2394 "end_sample:%ui, new count:%uD", |
2273 trak->end_sample, rest); | 2395 trak->end_sample, rest); |
2274 } | 2396 } |
2275 | 2397 |
2276 return NGX_OK; | 2398 return NGX_OK; |
2399 } | |
2400 | |
2401 | |
2402 static uint32_t | |
2403 ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, | |
2404 uint32_t start_sample) | |
2405 { | |
2406 uint32_t key_prefix, sample, *entry, *end; | |
2407 ngx_buf_t *data; | |
2408 ngx_http_mp4_conf_t *conf; | |
2409 | |
2410 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); | |
2411 if (!conf->start_key_frame) { | |
2412 return 0; | |
2413 } | |
2414 | |
2415 data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; | |
2416 if (data == NULL) { | |
2417 return 0; | |
2418 } | |
2419 | |
2420 entry = (uint32_t *) data->pos; | |
2421 end = (uint32_t *) data->last; | |
2422 | |
2423 /* sync samples starts from 1 */ | |
2424 start_sample++; | |
2425 | |
2426 key_prefix = 0; | |
2427 | |
2428 while (entry < end) { | |
2429 sample = ngx_mp4_get_32value(entry); | |
2430 if (sample > start_sample) { | |
2431 break; | |
2432 } | |
2433 | |
2434 key_prefix = start_sample - sample; | |
2435 entry++; | |
2436 } | |
2437 | |
2438 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2439 "mp4 key frame prefix:%uD", key_prefix); | |
2440 | |
2441 return key_prefix; | |
2277 } | 2442 } |
2278 | 2443 |
2279 | 2444 |
2280 typedef struct { | 2445 typedef struct { |
2281 u_char size[4]; | 2446 u_char size[4]; |
3612 return NULL; | 3777 return NULL; |
3613 } | 3778 } |
3614 | 3779 |
3615 conf->buffer_size = NGX_CONF_UNSET_SIZE; | 3780 conf->buffer_size = NGX_CONF_UNSET_SIZE; |
3616 conf->max_buffer_size = NGX_CONF_UNSET_SIZE; | 3781 conf->max_buffer_size = NGX_CONF_UNSET_SIZE; |
3782 conf->start_key_frame = NGX_CONF_UNSET; | |
3617 | 3783 |
3618 return conf; | 3784 return conf; |
3619 } | 3785 } |
3620 | 3786 |
3621 | 3787 |
3626 ngx_http_mp4_conf_t *conf = child; | 3792 ngx_http_mp4_conf_t *conf = child; |
3627 | 3793 |
3628 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); | 3794 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); |
3629 ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, | 3795 ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, |
3630 10 * 1024 * 1024); | 3796 10 * 1024 * 1024); |
3797 ngx_conf_merge_value(conf->start_key_frame, prev->start_key_frame, 0); | |
3631 | 3798 |
3632 return NGX_CONF_OK; | 3799 return NGX_CONF_OK; |
3633 } | 3800 } |