Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_mp4_module.c @ 5565:b8e6297358b5 stable-1.4
SPDY: fixed possible segfault.
While processing a DATA frame, the link to related stream is stored in spdy
connection object as part of connection state. But this stream can be closed
between receiving parts of the frame.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Wed, 22 Jan 2014 04:58:19 +0400 |
parents | 37671d0042b7 |
children | 322434f13bd8 |
rev | line source |
---|---|
4085 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
4085 | 5 */ |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
12 #define NGX_HTTP_MP4_TRAK_ATOM 0 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
13 #define NGX_HTTP_MP4_TKHD_ATOM 1 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
14 #define NGX_HTTP_MP4_MDIA_ATOM 2 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
15 #define NGX_HTTP_MP4_MDHD_ATOM 3 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
16 #define NGX_HTTP_MP4_HDLR_ATOM 4 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
17 #define NGX_HTTP_MP4_MINF_ATOM 5 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
18 #define NGX_HTTP_MP4_VMHD_ATOM 6 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
19 #define NGX_HTTP_MP4_SMHD_ATOM 7 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
20 #define NGX_HTTP_MP4_DINF_ATOM 8 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
21 #define NGX_HTTP_MP4_STBL_ATOM 9 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
22 #define NGX_HTTP_MP4_STSD_ATOM 10 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
23 #define NGX_HTTP_MP4_STTS_ATOM 11 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
24 #define NGX_HTTP_MP4_STTS_DATA 12 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
25 #define NGX_HTTP_MP4_STSS_ATOM 13 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
26 #define NGX_HTTP_MP4_STSS_DATA 14 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
27 #define NGX_HTTP_MP4_CTTS_ATOM 15 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
28 #define NGX_HTTP_MP4_CTTS_DATA 16 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
29 #define NGX_HTTP_MP4_STSC_ATOM 17 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
30 #define NGX_HTTP_MP4_STSC_CHUNK 18 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
31 #define NGX_HTTP_MP4_STSC_DATA 19 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
32 #define NGX_HTTP_MP4_STSZ_ATOM 20 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
33 #define NGX_HTTP_MP4_STSZ_DATA 21 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
34 #define NGX_HTTP_MP4_STCO_ATOM 22 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
35 #define NGX_HTTP_MP4_STCO_DATA 23 |
4112 | 36 #define NGX_HTTP_MP4_CO64_ATOM 24 |
37 #define NGX_HTTP_MP4_CO64_DATA 25 | |
38 | |
39 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA | |
4085 | 40 |
41 | |
42 typedef struct { | |
43 size_t buffer_size; | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
44 size_t max_buffer_size; |
4085 | 45 } ngx_http_mp4_conf_t; |
46 | |
47 | |
48 typedef struct { | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
49 u_char chunk[4]; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
50 u_char samples[4]; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
51 u_char id[4]; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
52 } ngx_mp4_stsc_entry_t; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
53 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
54 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
55 typedef struct { |
4085 | 56 uint32_t timescale; |
57 uint32_t time_to_sample_entries; | |
58 uint32_t sample_to_chunk_entries; | |
59 uint32_t sync_samples_entries; | |
60 uint32_t composition_offset_entries; | |
61 uint32_t sample_sizes_entries; | |
62 uint32_t chunks; | |
63 | |
64 ngx_uint_t start_sample; | |
65 ngx_uint_t start_chunk; | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
66 ngx_uint_t chunk_samples; |
4112 | 67 uint64_t chunk_samples_size; |
4085 | 68 off_t start_offset; |
69 | |
70 size_t tkhd_size; | |
71 size_t mdhd_size; | |
72 size_t hdlr_size; | |
73 size_t vmhd_size; | |
74 size_t smhd_size; | |
75 size_t dinf_size; | |
76 size_t size; | |
77 | |
78 ngx_chain_t out[NGX_HTTP_MP4_LAST_ATOM + 1]; | |
79 | |
80 ngx_buf_t trak_atom_buf; | |
81 ngx_buf_t tkhd_atom_buf; | |
82 ngx_buf_t mdia_atom_buf; | |
83 ngx_buf_t mdhd_atom_buf; | |
84 ngx_buf_t hdlr_atom_buf; | |
85 ngx_buf_t minf_atom_buf; | |
86 ngx_buf_t vmhd_atom_buf; | |
87 ngx_buf_t smhd_atom_buf; | |
88 ngx_buf_t dinf_atom_buf; | |
89 ngx_buf_t stbl_atom_buf; | |
90 ngx_buf_t stsd_atom_buf; | |
91 ngx_buf_t stts_atom_buf; | |
92 ngx_buf_t stts_data_buf; | |
93 ngx_buf_t stss_atom_buf; | |
94 ngx_buf_t stss_data_buf; | |
95 ngx_buf_t ctts_atom_buf; | |
96 ngx_buf_t ctts_data_buf; | |
97 ngx_buf_t stsc_atom_buf; | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
98 ngx_buf_t stsc_chunk_buf; |
4085 | 99 ngx_buf_t stsc_data_buf; |
100 ngx_buf_t stsz_atom_buf; | |
101 ngx_buf_t stsz_data_buf; | |
4107 | 102 ngx_buf_t stco_atom_buf; |
103 ngx_buf_t stco_data_buf; | |
4112 | 104 ngx_buf_t co64_atom_buf; |
105 ngx_buf_t co64_data_buf; | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
106 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
107 ngx_mp4_stsc_entry_t stsc_chunk_entry; |
4085 | 108 } ngx_http_mp4_trak_t; |
109 | |
110 | |
111 typedef struct { | |
112 ngx_file_t file; | |
113 | |
114 u_char *buffer; | |
115 u_char *buffer_start; | |
116 u_char *buffer_pos; | |
117 u_char *buffer_end; | |
118 size_t buffer_size; | |
119 | |
120 off_t offset; | |
121 off_t end; | |
122 off_t content_length; | |
123 ngx_uint_t start; | |
124 uint32_t timescale; | |
125 ngx_http_request_t *request; | |
126 ngx_array_t trak; | |
127 ngx_http_mp4_trak_t traks[2]; | |
128 | |
129 size_t ftyp_size; | |
130 size_t moov_size; | |
131 | |
132 ngx_chain_t *out; | |
133 ngx_chain_t ftyp_atom; | |
134 ngx_chain_t moov_atom; | |
135 ngx_chain_t mvhd_atom; | |
136 ngx_chain_t mdat_atom; | |
137 ngx_chain_t mdat_data; | |
138 | |
139 ngx_buf_t ftyp_atom_buf; | |
140 ngx_buf_t moov_atom_buf; | |
141 ngx_buf_t mvhd_atom_buf; | |
142 ngx_buf_t mdat_atom_buf; | |
143 ngx_buf_t mdat_data_buf; | |
144 | |
145 u_char moov_atom_header[8]; | |
146 u_char mdat_atom_header[16]; | |
147 } ngx_http_mp4_file_t; | |
148 | |
149 | |
150 typedef struct { | |
151 char *name; | |
152 ngx_int_t (*handler)(ngx_http_mp4_file_t *mp4, | |
153 uint64_t atom_data_size); | |
154 } ngx_http_mp4_atom_handler_t; | |
155 | |
156 | |
157 #define ngx_mp4_atom_header(mp4) (mp4->buffer_pos - 8) | |
158 #define ngx_mp4_atom_data(mp4) mp4->buffer_pos | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
159 #define ngx_mp4_atom_data_size(t) (uint64_t) (sizeof(t) - 8) |
4085 | 160 #define ngx_mp4_atom_next(mp4, n) mp4->buffer_pos += n; mp4->offset += n |
161 | |
162 | |
163 #define ngx_mp4_set_atom_name(p, n1, n2, n3, n4) \ | |
164 ((u_char *) (p))[4] = n1; \ | |
165 ((u_char *) (p))[5] = n2; \ | |
166 ((u_char *) (p))[6] = n3; \ | |
167 ((u_char *) (p))[7] = n4 | |
168 | |
169 #define ngx_mp4_get_32value(p) \ | |
4402
b20019ecfdcc
Fixed handling of mp4 above 2G and 32bit offsets (ticket #84).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4382
diff
changeset
|
170 ( ((uint32_t) ((u_char *) (p))[0] << 24) \ |
b20019ecfdcc
Fixed handling of mp4 above 2G and 32bit offsets (ticket #84).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4382
diff
changeset
|
171 + ( ((u_char *) (p))[1] << 16) \ |
b20019ecfdcc
Fixed handling of mp4 above 2G and 32bit offsets (ticket #84).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4382
diff
changeset
|
172 + ( ((u_char *) (p))[2] << 8) \ |
b20019ecfdcc
Fixed handling of mp4 above 2G and 32bit offsets (ticket #84).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4382
diff
changeset
|
173 + ( ((u_char *) (p))[3]) ) |
4085 | 174 |
175 #define ngx_mp4_set_32value(p, n) \ | |
176 ((u_char *) (p))[0] = (u_char) ((n) >> 24); \ | |
177 ((u_char *) (p))[1] = (u_char) ((n) >> 16); \ | |
178 ((u_char *) (p))[2] = (u_char) ((n) >> 8); \ | |
179 ((u_char *) (p))[3] = (u_char) (n) | |
180 | |
181 #define ngx_mp4_get_64value(p) \ | |
182 ( ((uint64_t) ((u_char *) (p))[0] << 56) \ | |
183 + ((uint64_t) ((u_char *) (p))[1] << 48) \ | |
184 + ((uint64_t) ((u_char *) (p))[2] << 40) \ | |
185 + ((uint64_t) ((u_char *) (p))[3] << 32) \ | |
186 + ((uint64_t) ((u_char *) (p))[4] << 24) \ | |
187 + ( ((u_char *) (p))[5] << 16) \ | |
188 + ( ((u_char *) (p))[6] << 8) \ | |
189 + ( ((u_char *) (p))[7]) ) | |
190 | |
191 #define ngx_mp4_set_64value(p, n) \ | |
4155
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
192 ((u_char *) (p))[0] = (u_char) ((uint64_t) (n) >> 56); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
193 ((u_char *) (p))[1] = (u_char) ((uint64_t) (n) >> 48); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
194 ((u_char *) (p))[2] = (u_char) ((uint64_t) (n) >> 40); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
195 ((u_char *) (p))[3] = (u_char) ((uint64_t) (n) >> 32); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
196 ((u_char *) (p))[4] = (u_char) ( (n) >> 24); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
197 ((u_char *) (p))[5] = (u_char) ( (n) >> 16); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
198 ((u_char *) (p))[6] = (u_char) ( (n) >> 8); \ |
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
199 ((u_char *) (p))[7] = (u_char) (n) |
4085 | 200 |
201 #define ngx_mp4_last_trak(mp4) \ | |
202 &((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1] | |
203 | |
204 | |
205 static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4); | |
206 static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, | |
207 ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size); | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
208 static ngx_int_t ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size); |
4085 | 209 static ngx_int_t ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, |
210 uint64_t atom_data_size); | |
211 static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, | |
212 uint64_t atom_data_size); | |
213 static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, | |
214 uint64_t atom_data_size); | |
215 static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, | |
216 off_t start_offset); | |
217 static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, | |
218 uint64_t atom_data_size); | |
219 static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, | |
220 uint64_t atom_data_size); | |
221 static void ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4, | |
222 ngx_http_mp4_trak_t *trak); | |
223 static ngx_int_t ngx_http_mp4_read_cmov_atom(ngx_http_mp4_file_t *mp4, | |
224 uint64_t atom_data_size); | |
225 static ngx_int_t ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, | |
226 uint64_t atom_data_size); | |
227 static ngx_int_t ngx_http_mp4_read_mdia_atom(ngx_http_mp4_file_t *mp4, | |
228 uint64_t atom_data_size); | |
229 static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, | |
230 ngx_http_mp4_trak_t *trak); | |
231 static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, | |
232 uint64_t atom_data_size); | |
233 static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, | |
234 uint64_t atom_data_size); | |
235 static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, | |
236 uint64_t atom_data_size); | |
237 static void ngx_http_mp4_update_minf_atom(ngx_http_mp4_file_t *mp4, | |
238 ngx_http_mp4_trak_t *trak); | |
239 static ngx_int_t ngx_http_mp4_read_dinf_atom(ngx_http_mp4_file_t *mp4, | |
240 uint64_t atom_data_size); | |
241 static ngx_int_t ngx_http_mp4_read_vmhd_atom(ngx_http_mp4_file_t *mp4, | |
242 uint64_t atom_data_size); | |
243 static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, | |
244 uint64_t atom_data_size); | |
245 static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, | |
246 uint64_t atom_data_size); | |
247 static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, | |
248 ngx_http_mp4_trak_t *trak); | |
249 static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, | |
250 uint64_t atom_data_size); | |
251 static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, | |
252 uint64_t atom_data_size); | |
253 static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, | |
254 ngx_http_mp4_trak_t *trak); | |
255 static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, | |
256 uint64_t atom_data_size); | |
257 static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, | |
258 ngx_http_mp4_trak_t *trak); | |
259 static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, | |
260 uint64_t atom_data_size); | |
261 static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, | |
262 ngx_http_mp4_trak_t *trak); | |
263 static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, | |
264 uint64_t atom_data_size); | |
265 static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, | |
266 ngx_http_mp4_trak_t *trak); | |
267 static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, | |
268 uint64_t atom_data_size); | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
269 static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
4085 | 270 ngx_http_mp4_trak_t *trak); |
271 static ngx_int_t ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, | |
272 uint64_t atom_data_size); | |
273 static ngx_int_t ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | |
274 ngx_http_mp4_trak_t *trak); | |
275 static void ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, | |
276 ngx_http_mp4_trak_t *trak, int32_t adjustment); | |
4112 | 277 static ngx_int_t ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, |
278 uint64_t atom_data_size); | |
279 static ngx_int_t ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
280 ngx_http_mp4_trak_t *trak); | |
281 static void ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
282 ngx_http_mp4_trak_t *trak, off_t adjustment); | |
4085 | 283 static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
284 static void *ngx_http_mp4_create_conf(ngx_conf_t *cf); | |
285 static char *ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child); | |
286 | |
287 static ngx_command_t ngx_http_mp4_commands[] = { | |
288 | |
289 { ngx_string("mp4"), | |
290 NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, | |
291 ngx_http_mp4, | |
292 0, | |
293 0, | |
294 NULL }, | |
295 | |
296 { ngx_string("mp4_buffer_size"), | |
297 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
298 ngx_conf_set_size_slot, | |
299 NGX_HTTP_LOC_CONF_OFFSET, | |
300 offsetof(ngx_http_mp4_conf_t, buffer_size), | |
301 NULL }, | |
302 | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
303 { ngx_string("mp4_max_buffer_size"), |
4085 | 304 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
305 ngx_conf_set_size_slot, | |
306 NGX_HTTP_LOC_CONF_OFFSET, | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
307 offsetof(ngx_http_mp4_conf_t, max_buffer_size), |
4085 | 308 NULL }, |
309 | |
310 ngx_null_command | |
311 }; | |
312 | |
313 | |
314 static ngx_http_module_t ngx_http_mp4_module_ctx = { | |
315 NULL, /* preconfiguration */ | |
316 NULL, /* postconfiguration */ | |
317 | |
318 NULL, /* create main configuration */ | |
319 NULL, /* init main configuration */ | |
320 | |
321 NULL, /* create server configuration */ | |
322 NULL, /* merge server configuration */ | |
323 | |
324 ngx_http_mp4_create_conf, /* create location configuration */ | |
325 ngx_http_mp4_merge_conf /* merge location configuration */ | |
326 }; | |
327 | |
328 | |
329 ngx_module_t ngx_http_mp4_module = { | |
330 NGX_MODULE_V1, | |
331 &ngx_http_mp4_module_ctx, /* module context */ | |
332 ngx_http_mp4_commands, /* module directives */ | |
333 NGX_HTTP_MODULE, /* module type */ | |
334 NULL, /* init master */ | |
335 NULL, /* init module */ | |
336 NULL, /* init process */ | |
337 NULL, /* init thread */ | |
338 NULL, /* exit thread */ | |
339 NULL, /* exit process */ | |
340 NULL, /* exit master */ | |
341 NGX_MODULE_V1_PADDING | |
342 }; | |
343 | |
344 | |
345 static ngx_http_mp4_atom_handler_t ngx_http_mp4_atoms[] = { | |
346 { "ftyp", ngx_http_mp4_read_ftyp_atom }, | |
347 { "moov", ngx_http_mp4_read_moov_atom }, | |
348 { "mdat", ngx_http_mp4_read_mdat_atom }, | |
349 { NULL, NULL } | |
350 }; | |
351 | |
352 static ngx_http_mp4_atom_handler_t ngx_http_mp4_moov_atoms[] = { | |
353 { "mvhd", ngx_http_mp4_read_mvhd_atom }, | |
354 { "trak", ngx_http_mp4_read_trak_atom }, | |
355 { "cmov", ngx_http_mp4_read_cmov_atom }, | |
356 { NULL, NULL } | |
357 }; | |
358 | |
359 static ngx_http_mp4_atom_handler_t ngx_http_mp4_trak_atoms[] = { | |
360 { "tkhd", ngx_http_mp4_read_tkhd_atom }, | |
361 { "mdia", ngx_http_mp4_read_mdia_atom }, | |
362 { NULL, NULL } | |
363 }; | |
364 | |
365 static ngx_http_mp4_atom_handler_t ngx_http_mp4_mdia_atoms[] = { | |
366 { "mdhd", ngx_http_mp4_read_mdhd_atom }, | |
367 { "hdlr", ngx_http_mp4_read_hdlr_atom }, | |
368 { "minf", ngx_http_mp4_read_minf_atom }, | |
369 { NULL, NULL } | |
370 }; | |
371 | |
372 static ngx_http_mp4_atom_handler_t ngx_http_mp4_minf_atoms[] = { | |
373 { "vmhd", ngx_http_mp4_read_vmhd_atom }, | |
374 { "smhd", ngx_http_mp4_read_smhd_atom }, | |
375 { "dinf", ngx_http_mp4_read_dinf_atom }, | |
376 { "stbl", ngx_http_mp4_read_stbl_atom }, | |
377 { NULL, NULL } | |
378 }; | |
379 | |
380 static ngx_http_mp4_atom_handler_t ngx_http_mp4_stbl_atoms[] = { | |
381 { "stsd", ngx_http_mp4_read_stsd_atom }, | |
382 { "stts", ngx_http_mp4_read_stts_atom }, | |
383 { "stss", ngx_http_mp4_read_stss_atom }, | |
384 { "ctts", ngx_http_mp4_read_ctts_atom }, | |
385 { "stsc", ngx_http_mp4_read_stsc_atom }, | |
386 { "stsz", ngx_http_mp4_read_stsz_atom }, | |
387 { "stco", ngx_http_mp4_read_stco_atom }, | |
4112 | 388 { "co64", ngx_http_mp4_read_co64_atom }, |
4085 | 389 { NULL, NULL } |
390 }; | |
391 | |
392 | |
393 static ngx_int_t | |
394 ngx_http_mp4_handler(ngx_http_request_t *r) | |
395 { | |
396 u_char *last; | |
397 size_t root; | |
398 ngx_int_t rc, start; | |
399 ngx_uint_t level; | |
400 ngx_str_t path, value; | |
401 ngx_log_t *log; | |
402 ngx_buf_t *b; | |
403 ngx_chain_t out; | |
404 ngx_http_mp4_file_t *mp4; | |
405 ngx_open_file_info_t of; | |
406 ngx_http_core_loc_conf_t *clcf; | |
407 | |
408 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { | |
409 return NGX_HTTP_NOT_ALLOWED; | |
410 } | |
411 | |
412 if (r->uri.data[r->uri.len - 1] == '/') { | |
413 return NGX_DECLINED; | |
414 } | |
415 | |
416 rc = ngx_http_discard_request_body(r); | |
417 | |
418 if (rc != NGX_OK) { | |
419 return rc; | |
420 } | |
421 | |
422 last = ngx_http_map_uri_to_path(r, &path, &root, 0); | |
423 if (last == NULL) { | |
424 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
425 } | |
426 | |
427 log = r->connection->log; | |
428 | |
429 path.len = last - path.data; | |
430 | |
431 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, | |
432 "http mp4 filename: \"%V\"", &path); | |
433 | |
434 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
435 | |
436 ngx_memzero(&of, sizeof(ngx_open_file_info_t)); | |
437 | |
438 of.read_ahead = clcf->read_ahead; | |
4087
3aa3b7bb9f0d
Bugfix of r4086: directio was always enabled if mp4 file was sent as is.
Igor Sysoev <igor@sysoev.ru>
parents:
4085
diff
changeset
|
439 of.directio = NGX_MAX_OFF_T_VALUE; |
4085 | 440 of.valid = clcf->open_file_cache_valid; |
441 of.min_uses = clcf->open_file_cache_min_uses; | |
442 of.errors = clcf->open_file_cache_errors; | |
443 of.events = clcf->open_file_cache_events; | |
4494
13e09cf11d4e
Disable symlinks: initialization of the "disable_symlinks" field in
Valentin Bartenev <vbart@nginx.com>
parents:
4478
diff
changeset
|
444 |
13e09cf11d4e
Disable symlinks: initialization of the "disable_symlinks" field in
Valentin Bartenev <vbart@nginx.com>
parents:
4478
diff
changeset
|
445 if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { |
13e09cf11d4e
Disable symlinks: initialization of the "disable_symlinks" field in
Valentin Bartenev <vbart@nginx.com>
parents:
4478
diff
changeset
|
446 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
13e09cf11d4e
Disable symlinks: initialization of the "disable_symlinks" field in
Valentin Bartenev <vbart@nginx.com>
parents:
4478
diff
changeset
|
447 } |
4085 | 448 |
449 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) | |
450 != NGX_OK) | |
451 { | |
452 switch (of.err) { | |
453 | |
454 case 0: | |
455 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
456 | |
457 case NGX_ENOENT: | |
458 case NGX_ENOTDIR: | |
459 case NGX_ENAMETOOLONG: | |
460 | |
461 level = NGX_LOG_ERR; | |
462 rc = NGX_HTTP_NOT_FOUND; | |
463 break; | |
464 | |
465 case NGX_EACCES: | |
4478
08713bac87fc
Support for disable_symlinks in various modules.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
466 #if (NGX_HAVE_OPENAT) |
08713bac87fc
Support for disable_symlinks in various modules.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
467 case NGX_EMLINK: |
08713bac87fc
Support for disable_symlinks in various modules.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
468 case NGX_ELOOP: |
08713bac87fc
Support for disable_symlinks in various modules.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
469 #endif |
4085 | 470 |
471 level = NGX_LOG_ERR; | |
472 rc = NGX_HTTP_FORBIDDEN; | |
473 break; | |
474 | |
475 default: | |
476 | |
477 level = NGX_LOG_CRIT; | |
478 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
479 break; | |
480 } | |
481 | |
482 if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { | |
483 ngx_log_error(level, log, of.err, | |
484 "%s \"%s\" failed", of.failed, path.data); | |
485 } | |
486 | |
487 return rc; | |
488 } | |
489 | |
490 if (!of.is_file) { | |
491 | |
492 if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { | |
493 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
494 ngx_close_file_n " \"%s\" failed", path.data); | |
495 } | |
496 | |
497 return NGX_DECLINED; | |
498 } | |
499 | |
500 r->root_tested = !r->error_page; | |
501 r->allow_ranges = 1; | |
502 | |
503 start = -1; | |
504 r->headers_out.content_length_n = of.size; | |
505 mp4 = NULL; | |
506 b = NULL; | |
507 | |
508 if (r->args.len) { | |
509 | |
510 if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { | |
511 | |
4156
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
512 /* |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
513 * A Flash player may send start value with a lot of digits |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
514 * after dot so strtod() is used instead of atofp(). NaNs and |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
515 * infinities become negative numbers after (int) conversion. |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
516 */ |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
517 |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
518 ngx_set_errno(0); |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
519 start = (int) (strtod((char *) value.data, NULL) * 1000); |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
520 |
67a4654ba7d9
Using strtod() instead of atofp() to support a lot of digits after dot in
Igor Sysoev <igor@sysoev.ru>
parents:
4155
diff
changeset
|
521 if (ngx_errno == 0 && start >= 0) { |
4085 | 522 r->allow_ranges = 0; |
523 | |
524 mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); | |
525 if (mp4 == NULL) { | |
526 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
527 } | |
528 | |
529 mp4->file.fd = of.fd; | |
530 mp4->file.name = path; | |
531 mp4->file.log = r->connection->log;; | |
532 mp4->end = of.size; | |
533 mp4->start = (ngx_uint_t) start; | |
534 mp4->request = r; | |
535 | |
536 switch (ngx_http_mp4_process(mp4)) { | |
537 | |
538 case NGX_DECLINED: | |
539 if (mp4->buffer) { | |
540 ngx_pfree(r->pool, mp4->buffer); | |
541 } | |
542 | |
543 ngx_pfree(r->pool, mp4); | |
544 mp4 = NULL; | |
545 | |
546 break; | |
547 | |
548 case NGX_OK: | |
549 r->headers_out.content_length_n = mp4->content_length; | |
550 break; | |
551 | |
552 default: /* NGX_ERROR */ | |
553 if (mp4->buffer) { | |
554 ngx_pfree(r->pool, mp4->buffer); | |
555 } | |
556 | |
557 ngx_pfree(r->pool, mp4); | |
558 | |
559 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
560 } | |
561 } | |
562 } | |
563 } | |
564 | |
565 log->action = "sending mp4 to client"; | |
566 | |
567 if (clcf->directio <= of.size) { | |
568 | |
569 /* | |
570 * DIRECTIO is set on transfer only | |
571 * to allow kernel to cache "moov" atom | |
572 */ | |
573 | |
574 if (ngx_directio_on(of.fd) == NGX_FILE_ERROR) { | |
575 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
576 ngx_directio_on_n " \"%s\" failed", path.data); | |
577 } | |
578 | |
4087
3aa3b7bb9f0d
Bugfix of r4086: directio was always enabled if mp4 file was sent as is.
Igor Sysoev <igor@sysoev.ru>
parents:
4085
diff
changeset
|
579 of.is_directio = 1; |
3aa3b7bb9f0d
Bugfix of r4086: directio was always enabled if mp4 file was sent as is.
Igor Sysoev <igor@sysoev.ru>
parents:
4085
diff
changeset
|
580 |
4085 | 581 if (mp4) { |
582 mp4->file.directio = 1; | |
583 } | |
584 } | |
585 | |
586 r->headers_out.status = NGX_HTTP_OK; | |
587 r->headers_out.last_modified_time = of.mtime; | |
588 | |
4748
192f54280a7a
Entity tags: set for static respones.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4705
diff
changeset
|
589 if (ngx_http_set_etag(r) != NGX_OK) { |
192f54280a7a
Entity tags: set for static respones.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4705
diff
changeset
|
590 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
192f54280a7a
Entity tags: set for static respones.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4705
diff
changeset
|
591 } |
192f54280a7a
Entity tags: set for static respones.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4705
diff
changeset
|
592 |
4085 | 593 if (ngx_http_set_content_type(r) != NGX_OK) { |
594 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
595 } | |
596 | |
597 if (mp4 == NULL) { | |
598 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); | |
599 if (b == NULL) { | |
600 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
601 } | |
602 | |
603 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); | |
604 if (b->file == NULL) { | |
605 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
606 } | |
607 } | |
608 | |
609 rc = ngx_http_send_header(r); | |
610 | |
611 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { | |
612 return rc; | |
613 } | |
614 | |
615 if (mp4) { | |
616 return ngx_http_output_filter(r, mp4->out); | |
617 } | |
618 | |
619 b->file_pos = 0; | |
620 b->file_last = of.size; | |
621 | |
622 b->in_file = b->file_last ? 1 : 0; | |
4611
2b6cb7528409
Allows particular modules to handle subrequests properly.
Andrey Belov <defan@nginx.com>
parents:
4585
diff
changeset
|
623 b->last_buf = (r == r->main) ? 1 : 0; |
4085 | 624 b->last_in_chain = 1; |
625 | |
626 b->file->fd = of.fd; | |
627 b->file->name = path; | |
628 b->file->log = log; | |
629 b->file->directio = of.is_directio; | |
630 | |
631 out.buf = b; | |
632 out.next = NULL; | |
633 | |
634 return ngx_http_output_filter(r, &out); | |
635 } | |
636 | |
637 | |
638 static ngx_int_t | |
639 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) | |
640 { | |
641 off_t start_offset, adjustment; | |
642 ngx_int_t rc; | |
643 ngx_uint_t i, j; | |
644 ngx_chain_t **prev; | |
645 ngx_http_mp4_trak_t *trak; | |
646 ngx_http_mp4_conf_t *conf; | |
647 | |
648 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
649 "mp4 start:%ui", mp4->start); | |
650 | |
651 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); | |
652 | |
653 mp4->buffer_size = conf->buffer_size; | |
654 | |
655 rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_atoms, mp4->end); | |
656 if (rc != NGX_OK) { | |
657 return rc; | |
658 } | |
659 | |
660 if (mp4->trak.nelts == 0) { | |
661 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
662 "no mp4 trak atoms were found in \"%s\"", | |
663 mp4->file.name.data); | |
664 return NGX_ERROR; | |
665 } | |
666 | |
667 if (mp4->mdat_atom.buf == NULL) { | |
668 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
669 "no mp4 mdat atom was found in \"%s\"", | |
670 mp4->file.name.data); | |
671 return NGX_ERROR; | |
672 } | |
673 | |
674 prev = &mp4->out; | |
675 | |
676 if (mp4->ftyp_atom.buf) { | |
677 *prev = &mp4->ftyp_atom; | |
678 prev = &mp4->ftyp_atom.next; | |
679 } | |
680 | |
681 *prev = &mp4->moov_atom; | |
682 prev = &mp4->moov_atom.next; | |
683 | |
684 if (mp4->mvhd_atom.buf) { | |
685 mp4->moov_size += mp4->mvhd_atom_buf.last - mp4->mvhd_atom_buf.pos; | |
686 *prev = &mp4->mvhd_atom; | |
687 prev = &mp4->mvhd_atom.next; | |
688 } | |
689 | |
690 start_offset = mp4->end; | |
691 trak = mp4->trak.elts; | |
692 | |
693 for (i = 0; i < mp4->trak.nelts; i++) { | |
694 | |
695 if (ngx_http_mp4_update_stts_atom(mp4, &trak[i]) != NGX_OK) { | |
696 return NGX_ERROR; | |
697 } | |
698 | |
699 if (ngx_http_mp4_update_stss_atom(mp4, &trak[i]) != NGX_OK) { | |
700 return NGX_ERROR; | |
701 } | |
702 | |
703 ngx_http_mp4_update_ctts_atom(mp4, &trak[i]); | |
704 | |
705 if (ngx_http_mp4_update_stsc_atom(mp4, &trak[i]) != NGX_OK) { | |
706 return NGX_ERROR; | |
707 } | |
708 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
709 if (ngx_http_mp4_update_stsz_atom(mp4, &trak[i]) != NGX_OK) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
710 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
711 } |
4085 | 712 |
4112 | 713 if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { |
714 if (ngx_http_mp4_update_co64_atom(mp4, &trak[i]) != NGX_OK) { | |
715 return NGX_ERROR; | |
716 } | |
717 | |
718 } else { | |
719 if (ngx_http_mp4_update_stco_atom(mp4, &trak[i]) != NGX_OK) { | |
720 return NGX_ERROR; | |
721 } | |
4085 | 722 } |
723 | |
724 ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); | |
725 ngx_http_mp4_update_minf_atom(mp4, &trak[i]); | |
726 trak[i].size += trak[i].mdhd_size; | |
727 trak[i].size += trak[i].hdlr_size; | |
728 ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); | |
729 trak[i].size += trak[i].tkhd_size; | |
730 ngx_http_mp4_update_trak_atom(mp4, &trak[i]); | |
731 | |
732 mp4->moov_size += trak[i].size; | |
733 | |
734 if (start_offset > trak[i].start_offset) { | |
735 start_offset = trak[i].start_offset; | |
736 } | |
737 | |
738 *prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM]; | |
739 prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next; | |
740 | |
741 for (j = 0; j < NGX_HTTP_MP4_LAST_ATOM + 1; j++) { | |
742 if (trak[i].out[j].buf) { | |
743 *prev = &trak[i].out[j]; | |
744 prev = &trak[i].out[j].next; | |
745 } | |
746 } | |
747 } | |
748 | |
749 mp4->moov_size += 8; | |
750 | |
751 ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size); | |
752 ngx_mp4_set_atom_name(mp4->moov_atom_header, 'm', 'o', 'o', 'v'); | |
753 mp4->content_length += mp4->moov_size; | |
754 | |
755 *prev = &mp4->mdat_atom; | |
756 | |
5097
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
757 if (start_offset > mp4->mdat_data.buf->file_last) { |
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
758 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
759 "start time is out mp4 mdat atom in \"%s\"", |
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
760 mp4->file.name.data); |
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
761 return NGX_ERROR; |
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
762 } |
37671d0042b7
Mp4: fixed handling of too small mdat atoms (ticket #266).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4820
diff
changeset
|
763 |
4085 | 764 adjustment = mp4->ftyp_size + mp4->moov_size |
765 + ngx_http_mp4_update_mdat_atom(mp4, start_offset) | |
766 - start_offset; | |
767 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
768 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4579 | 769 "mp4 adjustment:%O", adjustment); |
4085 | 770 |
771 for (i = 0; i < mp4->trak.nelts; i++) { | |
4112 | 772 if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { |
773 ngx_http_mp4_adjust_co64_atom(mp4, &trak[i], adjustment); | |
774 } else { | |
775 ngx_http_mp4_adjust_stco_atom(mp4, &trak[i], (int32_t) adjustment); | |
776 } | |
4085 | 777 } |
778 | |
779 return NGX_OK; | |
780 } | |
781 | |
782 | |
783 typedef struct { | |
784 u_char size[4]; | |
785 u_char name[4]; | |
786 } ngx_mp4_atom_header_t; | |
787 | |
788 typedef struct { | |
789 u_char size[4]; | |
790 u_char name[4]; | |
791 u_char size64[8]; | |
792 } ngx_mp4_atom_header64_t; | |
793 | |
794 | |
795 static ngx_int_t | |
796 ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, | |
797 ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size) | |
798 { | |
799 off_t end; | |
800 size_t atom_header_size; | |
801 u_char *atom_header, *atom_name; | |
802 uint64_t atom_size; | |
803 ngx_int_t rc; | |
804 ngx_uint_t n; | |
805 | |
806 end = mp4->offset + atom_data_size; | |
807 | |
808 while (mp4->offset < end) { | |
809 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
810 if (ngx_http_mp4_read(mp4, sizeof(uint32_t)) != NGX_OK) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
811 return NGX_ERROR; |
4085 | 812 } |
813 | |
814 atom_header = mp4->buffer_pos; | |
815 atom_size = ngx_mp4_get_32value(atom_header); | |
816 atom_header_size = sizeof(ngx_mp4_atom_header_t); | |
817 | |
818 if (atom_size == 0) { | |
819 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
820 "mp4 atom end"); | |
821 return NGX_OK; | |
822 } | |
823 | |
824 if (atom_size < sizeof(ngx_mp4_atom_header_t)) { | |
825 | |
826 if (atom_size == 1) { | |
827 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
828 if (ngx_http_mp4_read(mp4, sizeof(ngx_mp4_atom_header64_t)) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
829 != NGX_OK) |
4085 | 830 { |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
831 return NGX_ERROR; |
4085 | 832 } |
833 | |
834 /* 64-bit atom size */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
835 atom_header = mp4->buffer_pos; |
4085 | 836 atom_size = ngx_mp4_get_64value(atom_header + 8); |
837 atom_header_size = sizeof(ngx_mp4_atom_header64_t); | |
838 | |
839 } else { | |
840 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
841 "\"%s\" mp4 atom is too small:%uL", | |
842 mp4->file.name.data, atom_size); | |
843 return NGX_ERROR; | |
844 } | |
845 } | |
846 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
847 if (ngx_http_mp4_read(mp4, sizeof(ngx_mp4_atom_header_t)) != NGX_OK) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
848 return NGX_ERROR; |
4085 | 849 } |
850 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
851 atom_header = mp4->buffer_pos; |
4085 | 852 atom_name = atom_header + sizeof(uint32_t); |
853 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
854 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 855 "mp4 atom: %*s @%O:%uL", |
856 4, atom_name, mp4->offset, atom_size); | |
857 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
858 if (atom_size > (uint64_t) (NGX_MAX_OFF_T_VALUE - mp4->offset) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
859 || mp4->offset + (off_t) atom_size > end) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
860 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
861 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
862 "\"%s\" mp4 atom too large:%uL", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
863 mp4->file.name.data, atom_size); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
864 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
865 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
866 |
4085 | 867 for (n = 0; atom[n].name; n++) { |
868 | |
869 if (ngx_strncmp(atom_name, atom[n].name, 4) == 0) { | |
870 | |
871 ngx_mp4_atom_next(mp4, atom_header_size); | |
872 | |
873 rc = atom[n].handler(mp4, atom_size - atom_header_size); | |
874 if (rc != NGX_OK) { | |
875 return rc; | |
876 } | |
877 | |
878 goto next; | |
879 } | |
880 } | |
881 | |
882 ngx_mp4_atom_next(mp4, atom_size); | |
883 | |
884 next: | |
885 continue; | |
886 } | |
887 | |
888 return NGX_OK; | |
889 } | |
890 | |
891 | |
892 static ngx_int_t | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
893 ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size) |
4085 | 894 { |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
895 ssize_t n; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
896 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
897 if (mp4->buffer_pos + size <= mp4->buffer_end) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
898 return NGX_OK; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
899 } |
4085 | 900 |
901 if (mp4->offset + (off_t) mp4->buffer_size > mp4->end) { | |
902 mp4->buffer_size = (size_t) (mp4->end - mp4->offset); | |
903 } | |
904 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
905 if (mp4->buffer_size < size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
906 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
907 "\"%s\" mp4 file truncated", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
908 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
909 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
910 |
4085 | 911 if (mp4->buffer == NULL) { |
912 mp4->buffer = ngx_palloc(mp4->request->pool, mp4->buffer_size); | |
913 if (mp4->buffer == NULL) { | |
914 return NGX_ERROR; | |
915 } | |
916 | |
917 mp4->buffer_start = mp4->buffer; | |
918 } | |
919 | |
920 n = ngx_read_file(&mp4->file, mp4->buffer_start, mp4->buffer_size, | |
921 mp4->offset); | |
922 | |
923 if (n == NGX_ERROR) { | |
924 return NGX_ERROR; | |
925 } | |
926 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
927 if ((size_t) n != mp4->buffer_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
928 ngx_log_error(NGX_LOG_CRIT, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
929 ngx_read_file_n " read only %z of %z from \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
930 n, mp4->buffer_size, mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
931 return NGX_ERROR; |
4085 | 932 } |
933 | |
934 mp4->buffer_pos = mp4->buffer_start; | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
935 mp4->buffer_end = mp4->buffer_start + mp4->buffer_size; |
4085 | 936 |
937 return NGX_OK; | |
938 } | |
939 | |
940 | |
941 static ngx_int_t | |
942 ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
943 { | |
944 u_char *ftyp_atom; | |
945 size_t atom_size; | |
946 ngx_buf_t *atom; | |
947 | |
948 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ftyp atom"); | |
949 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
950 if (atom_data_size > 1024 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
951 || ngx_mp4_atom_data(mp4) + atom_data_size > mp4->buffer_end) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
952 { |
4085 | 953 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
954 "\"%s\" mp4 ftyp atom is too large:%uL", | |
955 mp4->file.name.data, atom_data_size); | |
956 return NGX_ERROR; | |
957 } | |
958 | |
959 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
960 | |
961 ftyp_atom = ngx_palloc(mp4->request->pool, atom_size); | |
962 if (ftyp_atom == NULL) { | |
963 return NGX_ERROR; | |
964 } | |
965 | |
966 ngx_mp4_set_32value(ftyp_atom, atom_size); | |
967 ngx_mp4_set_atom_name(ftyp_atom, 'f', 't', 'y', 'p'); | |
968 | |
969 /* | |
970 * only moov atom content is guaranteed to be in mp4->buffer | |
971 * during sending response, so ftyp atom content should be copied | |
972 */ | |
973 ngx_memcpy(ftyp_atom + sizeof(ngx_mp4_atom_header_t), | |
974 ngx_mp4_atom_data(mp4), (size_t) atom_data_size); | |
975 | |
976 atom = &mp4->ftyp_atom_buf; | |
977 atom->temporary = 1; | |
978 atom->pos = ftyp_atom; | |
979 atom->last = ftyp_atom + atom_size; | |
980 | |
981 mp4->ftyp_atom.buf = atom; | |
982 mp4->ftyp_size = atom_size; | |
983 mp4->content_length = atom_size; | |
984 | |
985 ngx_mp4_atom_next(mp4, atom_data_size); | |
986 | |
987 return NGX_OK; | |
988 } | |
989 | |
990 | |
991 /* | |
992 * Small excess buffer to process atoms after moov atom, mp4->buffer_start | |
993 * will be set to this buffer part after moov atom processing. | |
994 */ | |
995 #define NGX_HTTP_MP4_MOOV_BUFFER_EXCESS (4 * 1024) | |
996 | |
997 static ngx_int_t | |
998 ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
999 { | |
1000 ngx_int_t rc; | |
1001 ngx_uint_t no_mdat; | |
1002 ngx_buf_t *atom; | |
1003 ngx_http_mp4_conf_t *conf; | |
1004 | |
1005 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom"); | |
1006 | |
1007 no_mdat = (mp4->mdat_atom.buf == NULL); | |
1008 | |
1009 if (no_mdat && mp4->start == 0) { | |
1010 /* | |
1011 * send original file if moov atom resides before | |
1012 * mdat atom and client requests integral file | |
1013 */ | |
1014 return NGX_DECLINED; | |
1015 } | |
1016 | |
1017 conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); | |
1018 | |
1019 if (atom_data_size > mp4->buffer_size) { | |
1020 | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
1021 if (atom_data_size > conf->max_buffer_size) { |
4085 | 1022 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
1023 "\"%s\" mp4 moov atom is too large:%uL, " | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
1024 "you may want to increase mp4_max_buffer_size", |
4085 | 1025 mp4->file.name.data, atom_data_size); |
1026 return NGX_ERROR; | |
1027 } | |
1028 | |
1029 ngx_pfree(mp4->request->pool, mp4->buffer); | |
1030 mp4->buffer = NULL; | |
1031 mp4->buffer_pos = NULL; | |
1032 mp4->buffer_end = NULL; | |
1033 | |
1034 mp4->buffer_size = (size_t) atom_data_size | |
1035 + NGX_HTTP_MP4_MOOV_BUFFER_EXCESS * no_mdat; | |
1036 } | |
1037 | |
4705
9a43b145a8ba
Mp4: fixed build on win32 after r4689.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4688
diff
changeset
|
1038 if (ngx_http_mp4_read(mp4, (size_t) atom_data_size) != NGX_OK) { |
4688
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1039 return NGX_ERROR; |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1040 } |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1041 |
4085 | 1042 mp4->trak.elts = &mp4->traks; |
1043 mp4->trak.size = sizeof(ngx_http_mp4_trak_t); | |
1044 mp4->trak.nalloc = 2; | |
1045 mp4->trak.pool = mp4->request->pool; | |
1046 | |
1047 atom = &mp4->moov_atom_buf; | |
1048 atom->temporary = 1; | |
1049 atom->pos = mp4->moov_atom_header; | |
1050 atom->last = mp4->moov_atom_header + 8; | |
1051 | |
1052 mp4->moov_atom.buf = &mp4->moov_atom_buf; | |
1053 | |
1054 rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_moov_atoms, atom_data_size); | |
1055 | |
1056 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 moov atom done"); | |
1057 | |
1058 if (no_mdat) { | |
1059 mp4->buffer_start = mp4->buffer_pos; | |
1060 mp4->buffer_size = NGX_HTTP_MP4_MOOV_BUFFER_EXCESS; | |
1061 | |
4688
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1062 if (mp4->buffer_start + mp4->buffer_size > mp4->buffer_end) { |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1063 mp4->buffer = NULL; |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1064 mp4->buffer_pos = NULL; |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1065 mp4->buffer_end = NULL; |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1066 } |
5fedb27c3e36
Mp4: fixed streaming if moov atom is at buffer edge.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4687
diff
changeset
|
1067 |
4085 | 1068 } else { |
1069 /* skip atoms after moov atom */ | |
1070 mp4->offset = mp4->end; | |
1071 } | |
1072 | |
1073 return rc; | |
1074 } | |
1075 | |
1076 | |
1077 static ngx_int_t | |
1078 ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1079 { | |
1080 ngx_buf_t *data; | |
1081 | |
1082 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdat atom"); | |
1083 | |
1084 data = &mp4->mdat_data_buf; | |
1085 data->file = &mp4->file; | |
1086 data->in_file = 1; | |
1087 data->last_buf = 1; | |
1088 data->last_in_chain = 1; | |
1089 data->file_last = mp4->offset + atom_data_size; | |
1090 | |
1091 mp4->mdat_atom.buf = &mp4->mdat_atom_buf; | |
1092 mp4->mdat_atom.next = &mp4->mdat_data; | |
1093 mp4->mdat_data.buf = data; | |
1094 | |
1095 if (mp4->trak.nelts) { | |
1096 /* skip atoms after mdat atom */ | |
1097 mp4->offset = mp4->end; | |
1098 | |
1099 } else { | |
1100 ngx_mp4_atom_next(mp4, atom_data_size); | |
1101 } | |
1102 | |
1103 return NGX_OK; | |
1104 } | |
1105 | |
1106 | |
1107 static size_t | |
1108 ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset) | |
1109 { | |
1110 off_t atom_data_size; | |
1111 u_char *atom_header; | |
1112 uint32_t atom_header_size; | |
1113 uint64_t atom_size; | |
1114 ngx_buf_t *atom; | |
1115 | |
1116 atom_data_size = mp4->mdat_data.buf->file_last - start_offset; | |
1117 mp4->mdat_data.buf->file_pos = start_offset; | |
1118 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
1119 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 1120 "mdat new offset @%O:%O", start_offset, atom_data_size); |
1121 | |
1122 atom_header = mp4->mdat_atom_header; | |
1123 | |
4155
d9636bf3f159
Fix of building on platforms with 32-bit off_t. (closed #23)
Igor Sysoev <igor@sysoev.ru>
parents:
4112
diff
changeset
|
1124 if ((uint64_t) atom_data_size > 0xffffffff) { |
4085 | 1125 atom_size = 1; |
1126 atom_header_size = sizeof(ngx_mp4_atom_header64_t); | |
1127 ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t), | |
1128 sizeof(ngx_mp4_atom_header64_t) + atom_data_size); | |
1129 } else { | |
1130 atom_size = sizeof(ngx_mp4_atom_header_t) + atom_data_size; | |
1131 atom_header_size = sizeof(ngx_mp4_atom_header_t); | |
1132 } | |
1133 | |
4282
71cdac0b9ea6
Fix of "Content-Length" header of MP4 response if start argument was used.
Igor Sysoev <igor@sysoev.ru>
parents:
4189
diff
changeset
|
1134 mp4->content_length += atom_header_size + atom_data_size; |
71cdac0b9ea6
Fix of "Content-Length" header of MP4 response if start argument was used.
Igor Sysoev <igor@sysoev.ru>
parents:
4189
diff
changeset
|
1135 |
4085 | 1136 ngx_mp4_set_32value(atom_header, atom_size); |
1137 ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'a', 't'); | |
1138 | |
1139 atom = &mp4->mdat_atom_buf; | |
1140 atom->temporary = 1; | |
1141 atom->pos = atom_header; | |
1142 atom->last = atom_header + atom_header_size; | |
1143 | |
1144 return atom_header_size; | |
1145 } | |
1146 | |
1147 | |
1148 typedef struct { | |
1149 u_char size[4]; | |
1150 u_char name[4]; | |
1151 u_char version[1]; | |
1152 u_char flags[3]; | |
1153 u_char creation_time[4]; | |
1154 u_char modification_time[4]; | |
1155 u_char timescale[4]; | |
1156 u_char duration[4]; | |
1157 u_char rate[4]; | |
1158 u_char volume[2]; | |
1159 u_char reserved[10]; | |
1160 u_char matrix[36]; | |
1161 u_char preview_time[4]; | |
1162 u_char preview_duration[4]; | |
1163 u_char poster_time[4]; | |
1164 u_char selection_time[4]; | |
1165 u_char selection_duration[4]; | |
1166 u_char current_time[4]; | |
1167 u_char next_track_id[4]; | |
1168 } ngx_mp4_mvhd_atom_t; | |
1169 | |
1170 typedef struct { | |
1171 u_char size[4]; | |
1172 u_char name[4]; | |
1173 u_char version[1]; | |
1174 u_char flags[3]; | |
1175 u_char creation_time[8]; | |
1176 u_char modification_time[8]; | |
1177 u_char timescale[4]; | |
1178 u_char duration[8]; | |
1179 u_char rate[4]; | |
1180 u_char volume[2]; | |
1181 u_char reserved[10]; | |
1182 u_char matrix[36]; | |
1183 u_char preview_time[4]; | |
1184 u_char preview_duration[4]; | |
1185 u_char poster_time[4]; | |
1186 u_char selection_time[4]; | |
1187 u_char selection_duration[4]; | |
1188 u_char current_time[4]; | |
1189 u_char next_track_id[4]; | |
1190 } ngx_mp4_mvhd64_atom_t; | |
1191 | |
1192 | |
1193 static ngx_int_t | |
1194 ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1195 { | |
1196 u_char *atom_header; | |
1197 size_t atom_size; | |
1198 uint32_t timescale; | |
1199 uint64_t duration; | |
1200 ngx_buf_t *atom; | |
1201 ngx_mp4_mvhd_atom_t *mvhd_atom; | |
1202 ngx_mp4_mvhd64_atom_t *mvhd64_atom; | |
1203 | |
1204 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mvhd atom"); | |
1205 | |
1206 atom_header = ngx_mp4_atom_header(mp4); | |
1207 mvhd_atom = (ngx_mp4_mvhd_atom_t *) atom_header; | |
1208 mvhd64_atom = (ngx_mp4_mvhd64_atom_t *) atom_header; | |
1209 ngx_mp4_set_atom_name(atom_header, 'm', 'v', 'h', 'd'); | |
1210 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1211 if (ngx_mp4_atom_data_size(ngx_mp4_mvhd_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1212 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1213 "\"%s\" mp4 mvhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1214 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1215 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1216 |
4085 | 1217 if (mvhd_atom->version[0] == 0) { |
1218 /* version 0: 32-bit duration */ | |
1219 timescale = ngx_mp4_get_32value(mvhd_atom->timescale); | |
1220 duration = ngx_mp4_get_32value(mvhd_atom->duration); | |
1221 | |
1222 } else { | |
1223 /* version 1: 64-bit duration */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1224 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1225 if (ngx_mp4_atom_data_size(ngx_mp4_mvhd64_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1226 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1227 "\"%s\" mp4 mvhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1228 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1229 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1230 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1231 |
4085 | 1232 timescale = ngx_mp4_get_32value(mvhd64_atom->timescale); |
1233 duration = ngx_mp4_get_64value(mvhd64_atom->duration); | |
1234 } | |
1235 | |
1236 mp4->timescale = timescale; | |
1237 | |
1238 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1239 "mvhd timescale:%uD, duration:%uL, time:%.3fs", | |
1240 timescale, duration, (double) duration / timescale); | |
1241 | |
1242 duration -= (uint64_t) mp4->start * timescale / 1000; | |
1243 | |
1244 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1245 "mvhd new duration:%uL, time:%.3fs", | |
1246 duration, (double) duration / timescale); | |
1247 | |
1248 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1249 ngx_mp4_set_32value(mvhd_atom->size, atom_size); | |
1250 | |
1251 if (mvhd_atom->version[0] == 0) { | |
1252 ngx_mp4_set_32value(mvhd_atom->duration, duration); | |
1253 | |
1254 } else { | |
1255 ngx_mp4_set_64value(mvhd64_atom->duration, duration); | |
1256 } | |
1257 | |
1258 atom = &mp4->mvhd_atom_buf; | |
1259 atom->temporary = 1; | |
1260 atom->pos = atom_header; | |
1261 atom->last = atom_header + atom_size; | |
1262 | |
1263 mp4->mvhd_atom.buf = atom; | |
1264 | |
1265 ngx_mp4_atom_next(mp4, atom_data_size); | |
1266 | |
1267 return NGX_OK; | |
1268 } | |
1269 | |
1270 | |
1271 static ngx_int_t | |
1272 ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1273 { | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1274 u_char *atom_header, *atom_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1275 off_t atom_file_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1276 ngx_int_t rc; |
4085 | 1277 ngx_buf_t *atom; |
1278 ngx_http_mp4_trak_t *trak; | |
1279 | |
1280 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 trak atom"); | |
1281 | |
1282 trak = ngx_array_push(&mp4->trak); | |
1283 if (trak == NULL) { | |
1284 return NGX_ERROR; | |
1285 } | |
1286 | |
1287 ngx_memzero(trak, sizeof(ngx_http_mp4_trak_t)); | |
1288 | |
1289 atom_header = ngx_mp4_atom_header(mp4); | |
1290 ngx_mp4_set_atom_name(atom_header, 't', 'r', 'a', 'k'); | |
1291 | |
1292 atom = &trak->trak_atom_buf; | |
1293 atom->temporary = 1; | |
1294 atom->pos = atom_header; | |
1295 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1296 | |
1297 trak->out[NGX_HTTP_MP4_TRAK_ATOM].buf = atom; | |
1298 | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1299 atom_end = mp4->buffer_pos + atom_data_size; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1300 atom_file_end = mp4->offset + atom_data_size; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1301 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1302 rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_trak_atoms, atom_data_size); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1303 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1304 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1305 "mp4 trak atom: %i", rc); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1306 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1307 if (rc == NGX_DECLINED) { |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1308 /* skip this trak */ |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1309 ngx_memzero(trak, sizeof(ngx_http_mp4_trak_t)); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1310 mp4->trak.nelts--; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1311 mp4->buffer_pos = atom_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1312 mp4->offset = atom_file_end; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1313 return NGX_OK; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1314 } |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1315 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1316 return rc; |
4085 | 1317 } |
1318 | |
1319 | |
1320 static void | |
1321 ngx_http_mp4_update_trak_atom(ngx_http_mp4_file_t *mp4, | |
1322 ngx_http_mp4_trak_t *trak) | |
1323 { | |
1324 ngx_buf_t *atom; | |
1325 | |
1326 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1327 atom = &trak->trak_atom_buf; | |
1328 ngx_mp4_set_32value(atom->pos, trak->size); | |
1329 } | |
1330 | |
1331 | |
1332 static ngx_int_t | |
1333 ngx_http_mp4_read_cmov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1334 { | |
1335 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
1336 "\"%s\" mp4 compressed moov atom (cmov) is not supported", | |
1337 mp4->file.name.data); | |
1338 | |
1339 return NGX_ERROR; | |
1340 } | |
1341 | |
1342 | |
1343 typedef struct { | |
1344 u_char size[4]; | |
1345 u_char name[4]; | |
1346 u_char version[1]; | |
1347 u_char flags[3]; | |
1348 u_char creation_time[4]; | |
1349 u_char modification_time[4]; | |
1350 u_char track_id[4]; | |
1351 u_char reserved1[4]; | |
1352 u_char duration[4]; | |
1353 u_char reserved2[8]; | |
1354 u_char layer[2]; | |
1355 u_char group[2]; | |
1356 u_char volume[2]; | |
1357 u_char reverved3[2]; | |
1358 u_char matrix[36]; | |
1359 u_char width[4]; | |
1360 u_char heigth[4]; | |
1361 } ngx_mp4_tkhd_atom_t; | |
1362 | |
1363 typedef struct { | |
1364 u_char size[4]; | |
1365 u_char name[4]; | |
1366 u_char version[1]; | |
1367 u_char flags[3]; | |
1368 u_char creation_time[8]; | |
1369 u_char modification_time[8]; | |
1370 u_char track_id[4]; | |
1371 u_char reserved1[4]; | |
1372 u_char duration[8]; | |
1373 u_char reserved2[8]; | |
1374 u_char layer[2]; | |
1375 u_char group[2]; | |
1376 u_char volume[2]; | |
1377 u_char reverved3[2]; | |
1378 u_char matrix[36]; | |
1379 u_char width[4]; | |
1380 u_char heigth[4]; | |
1381 } ngx_mp4_tkhd64_atom_t; | |
1382 | |
1383 | |
1384 static ngx_int_t | |
1385 ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1386 { | |
1387 u_char *atom_header; | |
1388 size_t atom_size; | |
1389 uint64_t duration; | |
1390 ngx_buf_t *atom; | |
1391 ngx_http_mp4_trak_t *trak; | |
1392 ngx_mp4_tkhd_atom_t *tkhd_atom; | |
1393 ngx_mp4_tkhd64_atom_t *tkhd64_atom; | |
1394 | |
1395 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 tkhd atom"); | |
1396 | |
1397 atom_header = ngx_mp4_atom_header(mp4); | |
1398 tkhd_atom = (ngx_mp4_tkhd_atom_t *) atom_header; | |
1399 tkhd64_atom = (ngx_mp4_tkhd64_atom_t *) atom_header; | |
1400 ngx_mp4_set_atom_name(tkhd_atom, 't', 'k', 'h', 'd'); | |
1401 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1402 if (ngx_mp4_atom_data_size(ngx_mp4_tkhd_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1403 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1404 "\"%s\" mp4 tkhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1405 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1406 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1407 |
4085 | 1408 if (tkhd_atom->version[0] == 0) { |
1409 /* version 0: 32-bit duration */ | |
1410 duration = ngx_mp4_get_32value(tkhd_atom->duration); | |
1411 | |
1412 } else { | |
1413 /* version 1: 64-bit duration */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1414 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1415 if (ngx_mp4_atom_data_size(ngx_mp4_tkhd64_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1416 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1417 "\"%s\" mp4 tkhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1418 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1419 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1420 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1421 |
4085 | 1422 duration = ngx_mp4_get_64value(tkhd64_atom->duration); |
1423 } | |
1424 | |
1425 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1426 "tkhd duration:%uL, time:%.3fs", | |
1427 duration, (double) duration / mp4->timescale); | |
1428 | |
1429 duration -= (uint64_t) mp4->start * mp4->timescale / 1000; | |
1430 | |
1431 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1432 "tkhd new duration:%uL, time:%.3fs", | |
1433 duration, (double) duration / mp4->timescale); | |
1434 | |
1435 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1436 | |
1437 trak = ngx_mp4_last_trak(mp4); | |
1438 trak->tkhd_size = atom_size; | |
1439 | |
1440 ngx_mp4_set_32value(tkhd_atom->size, atom_size); | |
1441 | |
1442 if (tkhd_atom->version[0] == 0) { | |
1443 ngx_mp4_set_32value(tkhd_atom->duration, duration); | |
1444 | |
1445 } else { | |
1446 ngx_mp4_set_64value(tkhd64_atom->duration, duration); | |
1447 } | |
1448 | |
1449 atom = &trak->tkhd_atom_buf; | |
1450 atom->temporary = 1; | |
1451 atom->pos = atom_header; | |
1452 atom->last = atom_header + atom_size; | |
1453 | |
1454 trak->out[NGX_HTTP_MP4_TKHD_ATOM].buf = atom; | |
1455 | |
1456 ngx_mp4_atom_next(mp4, atom_data_size); | |
1457 | |
1458 return NGX_OK; | |
1459 } | |
1460 | |
1461 | |
1462 static ngx_int_t | |
1463 ngx_http_mp4_read_mdia_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1464 { | |
1465 u_char *atom_header; | |
1466 ngx_buf_t *atom; | |
1467 ngx_http_mp4_trak_t *trak; | |
1468 | |
1469 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process mdia atom"); | |
1470 | |
1471 atom_header = ngx_mp4_atom_header(mp4); | |
1472 ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'i', 'a'); | |
1473 | |
1474 trak = ngx_mp4_last_trak(mp4); | |
1475 | |
1476 atom = &trak->mdia_atom_buf; | |
1477 atom->temporary = 1; | |
1478 atom->pos = atom_header; | |
1479 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1480 | |
1481 trak->out[NGX_HTTP_MP4_MDIA_ATOM].buf = atom; | |
1482 | |
1483 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_mdia_atoms, atom_data_size); | |
1484 } | |
1485 | |
1486 | |
1487 static void | |
1488 ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, | |
1489 ngx_http_mp4_trak_t *trak) | |
1490 { | |
1491 ngx_buf_t *atom; | |
1492 | |
1493 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1494 atom = &trak->mdia_atom_buf; | |
1495 ngx_mp4_set_32value(atom->pos, trak->size); | |
1496 } | |
1497 | |
1498 | |
1499 typedef struct { | |
1500 u_char size[4]; | |
1501 u_char name[4]; | |
1502 u_char version[1]; | |
1503 u_char flags[3]; | |
1504 u_char creation_time[4]; | |
1505 u_char modification_time[4]; | |
1506 u_char timescale[4]; | |
1507 u_char duration[4]; | |
1508 u_char language[2]; | |
1509 u_char quality[2]; | |
1510 } ngx_mp4_mdhd_atom_t; | |
1511 | |
1512 typedef struct { | |
1513 u_char size[4]; | |
1514 u_char name[4]; | |
1515 u_char version[1]; | |
1516 u_char flags[3]; | |
1517 u_char creation_time[8]; | |
1518 u_char modification_time[8]; | |
1519 u_char timescale[4]; | |
1520 u_char duration[8]; | |
1521 u_char language[2]; | |
1522 u_char quality[2]; | |
1523 } ngx_mp4_mdhd64_atom_t; | |
1524 | |
1525 | |
1526 static ngx_int_t | |
1527 ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1528 { | |
1529 u_char *atom_header; | |
1530 size_t atom_size; | |
1531 uint32_t timescale; | |
1532 uint64_t duration; | |
1533 ngx_buf_t *atom; | |
1534 ngx_http_mp4_trak_t *trak; | |
1535 ngx_mp4_mdhd_atom_t *mdhd_atom; | |
1536 ngx_mp4_mdhd64_atom_t *mdhd64_atom; | |
1537 | |
1538 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 mdhd atom"); | |
1539 | |
1540 atom_header = ngx_mp4_atom_header(mp4); | |
1541 mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom_header; | |
1542 mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom_header; | |
1543 ngx_mp4_set_atom_name(mdhd_atom, 'm', 'd', 'h', 'd'); | |
1544 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1545 if (ngx_mp4_atom_data_size(ngx_mp4_mdhd_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1546 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1547 "\"%s\" mp4 mdhd atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1548 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1549 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1550 |
4085 | 1551 if (mdhd_atom->version[0] == 0) { |
1552 /* version 0: everything is 32-bit */ | |
1553 timescale = ngx_mp4_get_32value(mdhd_atom->timescale); | |
1554 duration = ngx_mp4_get_32value(mdhd_atom->duration); | |
1555 | |
1556 } else { | |
1557 /* version 1: 64-bit duration and 32-bit timescale */ | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1558 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1559 if (ngx_mp4_atom_data_size(ngx_mp4_mdhd64_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1560 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1561 "\"%s\" mp4 mdhd atom too small", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1562 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1563 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1564 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1565 |
4085 | 1566 timescale = ngx_mp4_get_32value(mdhd64_atom->timescale); |
1567 duration = ngx_mp4_get_64value(mdhd64_atom->duration); | |
1568 } | |
1569 | |
1570 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1571 "mdhd timescale:%uD, duration:%uL, time:%.3fs", | |
1572 timescale, duration, (double) duration / timescale); | |
1573 | |
1574 duration -= (uint64_t) mp4->start * timescale / 1000; | |
1575 | |
1576 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1577 "mdhd new duration:%uL, time:%.3fs", | |
1578 duration, (double) duration / timescale); | |
1579 | |
1580 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1581 | |
1582 trak = ngx_mp4_last_trak(mp4); | |
1583 trak->mdhd_size = atom_size; | |
1584 trak->timescale = timescale; | |
1585 | |
1586 ngx_mp4_set_32value(mdhd_atom->size, atom_size); | |
1587 | |
1588 if (mdhd_atom->version[0] == 0) { | |
1589 ngx_mp4_set_32value(mdhd_atom->duration, duration); | |
1590 | |
1591 } else { | |
1592 ngx_mp4_set_64value(mdhd64_atom->duration, duration); | |
1593 } | |
1594 | |
1595 atom = &trak->mdhd_atom_buf; | |
1596 atom->temporary = 1; | |
1597 atom->pos = atom_header; | |
1598 atom->last = atom_header + atom_size; | |
1599 | |
1600 trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf = atom; | |
1601 | |
1602 ngx_mp4_atom_next(mp4, atom_data_size); | |
1603 | |
1604 return NGX_OK; | |
1605 } | |
1606 | |
1607 | |
1608 static ngx_int_t | |
1609 ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1610 { | |
1611 u_char *atom_header; | |
1612 size_t atom_size; | |
1613 ngx_buf_t *atom; | |
1614 ngx_http_mp4_trak_t *trak; | |
1615 | |
1616 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 hdlr atom"); | |
1617 | |
1618 atom_header = ngx_mp4_atom_header(mp4); | |
1619 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1620 ngx_mp4_set_32value(atom_header, atom_size); | |
1621 ngx_mp4_set_atom_name(atom_header, 'h', 'd', 'l', 'r'); | |
1622 | |
1623 trak = ngx_mp4_last_trak(mp4); | |
1624 | |
1625 atom = &trak->hdlr_atom_buf; | |
1626 atom->temporary = 1; | |
1627 atom->pos = atom_header; | |
1628 atom->last = atom_header + atom_size; | |
1629 | |
1630 trak->hdlr_size = atom_size; | |
1631 trak->out[NGX_HTTP_MP4_HDLR_ATOM].buf = atom; | |
1632 | |
1633 ngx_mp4_atom_next(mp4, atom_data_size); | |
1634 | |
1635 return NGX_OK; | |
1636 } | |
1637 | |
1638 | |
1639 static ngx_int_t | |
1640 ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1641 { | |
1642 u_char *atom_header; | |
1643 ngx_buf_t *atom; | |
1644 ngx_http_mp4_trak_t *trak; | |
1645 | |
1646 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process minf atom"); | |
1647 | |
1648 atom_header = ngx_mp4_atom_header(mp4); | |
1649 ngx_mp4_set_atom_name(atom_header, 'm', 'i', 'n', 'f'); | |
1650 | |
1651 trak = ngx_mp4_last_trak(mp4); | |
1652 | |
1653 atom = &trak->minf_atom_buf; | |
1654 atom->temporary = 1; | |
1655 atom->pos = atom_header; | |
1656 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1657 | |
1658 trak->out[NGX_HTTP_MP4_MINF_ATOM].buf = atom; | |
1659 | |
1660 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_minf_atoms, atom_data_size); | |
1661 } | |
1662 | |
1663 | |
1664 static void | |
1665 ngx_http_mp4_update_minf_atom(ngx_http_mp4_file_t *mp4, | |
1666 ngx_http_mp4_trak_t *trak) | |
1667 { | |
1668 ngx_buf_t *atom; | |
1669 | |
1670 trak->size += sizeof(ngx_mp4_atom_header_t) | |
1671 + trak->vmhd_size | |
1672 + trak->smhd_size | |
1673 + trak->dinf_size; | |
1674 atom = &trak->minf_atom_buf; | |
1675 ngx_mp4_set_32value(atom->pos, trak->size); | |
1676 } | |
1677 | |
1678 | |
1679 static ngx_int_t | |
1680 ngx_http_mp4_read_vmhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1681 { | |
1682 u_char *atom_header; | |
1683 size_t atom_size; | |
1684 ngx_buf_t *atom; | |
1685 ngx_http_mp4_trak_t *trak; | |
1686 | |
1687 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 vmhd atom"); | |
1688 | |
1689 atom_header = ngx_mp4_atom_header(mp4); | |
1690 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1691 ngx_mp4_set_32value(atom_header, atom_size); | |
1692 ngx_mp4_set_atom_name(atom_header, 'v', 'm', 'h', 'd'); | |
1693 | |
1694 trak = ngx_mp4_last_trak(mp4); | |
1695 | |
1696 atom = &trak->vmhd_atom_buf; | |
1697 atom->temporary = 1; | |
1698 atom->pos = atom_header; | |
1699 atom->last = atom_header + atom_size; | |
1700 | |
1701 trak->vmhd_size += atom_size; | |
1702 trak->out[NGX_HTTP_MP4_VMHD_ATOM].buf = atom; | |
1703 | |
1704 ngx_mp4_atom_next(mp4, atom_data_size); | |
1705 | |
1706 return NGX_OK; | |
1707 } | |
1708 | |
1709 | |
1710 static ngx_int_t | |
1711 ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1712 { | |
1713 u_char *atom_header; | |
1714 size_t atom_size; | |
1715 ngx_buf_t *atom; | |
1716 ngx_http_mp4_trak_t *trak; | |
1717 | |
1718 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 smhd atom"); | |
1719 | |
1720 atom_header = ngx_mp4_atom_header(mp4); | |
1721 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1722 ngx_mp4_set_32value(atom_header, atom_size); | |
1723 ngx_mp4_set_atom_name(atom_header, 's', 'm', 'h', 'd'); | |
1724 | |
1725 trak = ngx_mp4_last_trak(mp4); | |
1726 | |
1727 atom = &trak->smhd_atom_buf; | |
1728 atom->temporary = 1; | |
1729 atom->pos = atom_header; | |
1730 atom->last = atom_header + atom_size; | |
1731 | |
1732 trak->vmhd_size += atom_size; | |
1733 trak->out[NGX_HTTP_MP4_SMHD_ATOM].buf = atom; | |
1734 | |
1735 ngx_mp4_atom_next(mp4, atom_data_size); | |
1736 | |
1737 return NGX_OK; | |
1738 } | |
1739 | |
1740 | |
1741 static ngx_int_t | |
1742 ngx_http_mp4_read_dinf_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1743 { | |
1744 u_char *atom_header; | |
1745 size_t atom_size; | |
1746 ngx_buf_t *atom; | |
1747 ngx_http_mp4_trak_t *trak; | |
1748 | |
1749 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 dinf atom"); | |
1750 | |
1751 atom_header = ngx_mp4_atom_header(mp4); | |
1752 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1753 ngx_mp4_set_32value(atom_header, atom_size); | |
1754 ngx_mp4_set_atom_name(atom_header, 'd', 'i', 'n', 'f'); | |
1755 | |
1756 trak = ngx_mp4_last_trak(mp4); | |
1757 | |
1758 atom = &trak->dinf_atom_buf; | |
1759 atom->temporary = 1; | |
1760 atom->pos = atom_header; | |
1761 atom->last = atom_header + atom_size; | |
1762 | |
1763 trak->dinf_size += atom_size; | |
1764 trak->out[NGX_HTTP_MP4_DINF_ATOM].buf = atom; | |
1765 | |
1766 ngx_mp4_atom_next(mp4, atom_data_size); | |
1767 | |
1768 return NGX_OK; | |
1769 } | |
1770 | |
1771 | |
1772 static ngx_int_t | |
1773 ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1774 { | |
1775 u_char *atom_header; | |
1776 ngx_buf_t *atom; | |
1777 ngx_http_mp4_trak_t *trak; | |
1778 | |
1779 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "process stbl atom"); | |
1780 | |
1781 atom_header = ngx_mp4_atom_header(mp4); | |
1782 ngx_mp4_set_atom_name(atom_header, 's', 't', 'b', 'l'); | |
1783 | |
1784 trak = ngx_mp4_last_trak(mp4); | |
1785 | |
1786 atom = &trak->stbl_atom_buf; | |
1787 atom->temporary = 1; | |
1788 atom->pos = atom_header; | |
1789 atom->last = atom_header + sizeof(ngx_mp4_atom_header_t); | |
1790 | |
1791 trak->out[NGX_HTTP_MP4_STBL_ATOM].buf = atom; | |
1792 | |
1793 return ngx_http_mp4_read_atom(mp4, ngx_http_mp4_stbl_atoms, atom_data_size); | |
1794 } | |
1795 | |
1796 | |
1797 static void | |
1798 ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, | |
1799 ngx_http_mp4_trak_t *trak) | |
1800 { | |
1801 ngx_buf_t *atom; | |
1802 | |
1803 trak->size += sizeof(ngx_mp4_atom_header_t); | |
1804 atom = &trak->stbl_atom_buf; | |
1805 ngx_mp4_set_32value(atom->pos, trak->size); | |
1806 } | |
1807 | |
1808 | |
1809 typedef struct { | |
1810 u_char size[4]; | |
1811 u_char name[4]; | |
1812 u_char version[1]; | |
1813 u_char flags[3]; | |
1814 u_char entries[4]; | |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1815 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1816 u_char media_size[4]; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1817 u_char media_name[4]; |
4085 | 1818 } ngx_mp4_stsd_atom_t; |
1819 | |
1820 | |
1821 static ngx_int_t | |
1822 ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1823 { | |
1824 u_char *atom_header, *atom_table; | |
1825 size_t atom_size; | |
1826 ngx_buf_t *atom; | |
1827 ngx_mp4_stsd_atom_t *stsd_atom; | |
1828 ngx_http_mp4_trak_t *trak; | |
1829 | |
1830 /* sample description atom */ | |
1831 | |
1832 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsd atom"); | |
1833 | |
1834 atom_header = ngx_mp4_atom_header(mp4); | |
1835 stsd_atom = (ngx_mp4_stsd_atom_t *) atom_header; | |
1836 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; | |
1837 atom_table = atom_header + atom_size; | |
1838 ngx_mp4_set_32value(stsd_atom->size, atom_size); | |
1839 ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd'); | |
1840 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1841 if (ngx_mp4_atom_data_size(ngx_mp4_stsd_atom_t) > atom_data_size) { |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1842 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1843 "\"%s\" mp4 stsd atom too small", mp4->file.name.data); |
4099
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1844 return NGX_ERROR; |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1845 } |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1846 |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1847 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1848 "stsd entries:%uD, media:%*s", |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1849 ngx_mp4_get_32value(stsd_atom->entries), |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1850 4, stsd_atom->media_name); |
9ee6944590c0
Skipping traks with unsupported media formats.
Igor Sysoev <igor@sysoev.ru>
parents:
4098
diff
changeset
|
1851 |
4085 | 1852 trak = ngx_mp4_last_trak(mp4); |
1853 | |
1854 atom = &trak->stsd_atom_buf; | |
1855 atom->temporary = 1; | |
1856 atom->pos = atom_header; | |
1857 atom->last = atom_table; | |
1858 | |
1859 trak->out[NGX_HTTP_MP4_STSD_ATOM].buf = atom; | |
1860 trak->size += atom_size; | |
1861 | |
1862 ngx_mp4_atom_next(mp4, atom_data_size); | |
1863 | |
1864 return NGX_OK; | |
1865 } | |
1866 | |
1867 | |
1868 typedef struct { | |
1869 u_char size[4]; | |
1870 u_char name[4]; | |
1871 u_char version[1]; | |
1872 u_char flags[3]; | |
1873 u_char entries[4]; | |
1874 } ngx_mp4_stts_atom_t; | |
1875 | |
1876 typedef struct { | |
1877 u_char count[4]; | |
1878 u_char duration[4]; | |
1879 } ngx_mp4_stts_entry_t; | |
1880 | |
1881 | |
1882 static ngx_int_t | |
1883 ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
1884 { | |
1885 u_char *atom_header, *atom_table, *atom_end; | |
1886 uint32_t entries; | |
1887 ngx_buf_t *atom, *data; | |
1888 ngx_mp4_stts_atom_t *stts_atom; | |
1889 ngx_http_mp4_trak_t *trak; | |
1890 | |
1891 /* time-to-sample atom */ | |
1892 | |
1893 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stts atom"); | |
1894 | |
1895 atom_header = ngx_mp4_atom_header(mp4); | |
1896 stts_atom = (ngx_mp4_stts_atom_t *) atom_header; | |
1897 ngx_mp4_set_atom_name(stts_atom, 's', 't', 't', 's'); | |
1898 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1899 if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1900 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1901 "\"%s\" mp4 stts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1902 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1903 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1904 |
4085 | 1905 entries = ngx_mp4_get_32value(stts_atom->entries); |
1906 | |
1907 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 1908 "mp4 time-to-sample entries:%uD", entries); |
4085 | 1909 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1910 if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1911 + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1912 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1913 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1914 "\"%s\" mp4 stts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1915 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1916 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
1917 |
4085 | 1918 atom_table = atom_header + sizeof(ngx_mp4_stts_atom_t); |
1919 atom_end = atom_table + entries * sizeof(ngx_mp4_stts_entry_t); | |
1920 | |
1921 trak = ngx_mp4_last_trak(mp4); | |
1922 trak->time_to_sample_entries = entries; | |
1923 | |
1924 atom = &trak->stts_atom_buf; | |
1925 atom->temporary = 1; | |
1926 atom->pos = atom_header; | |
1927 atom->last = atom_table; | |
1928 | |
1929 data = &trak->stts_data_buf; | |
1930 data->temporary = 1; | |
1931 data->pos = atom_table; | |
1932 data->last = atom_end; | |
1933 | |
1934 trak->out[NGX_HTTP_MP4_STTS_ATOM].buf = atom; | |
1935 trak->out[NGX_HTTP_MP4_STTS_DATA].buf = data; | |
1936 | |
1937 ngx_mp4_atom_next(mp4, atom_data_size); | |
1938 | |
1939 return NGX_OK; | |
1940 } | |
1941 | |
1942 | |
1943 static ngx_int_t | |
1944 ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, | |
1945 ngx_http_mp4_trak_t *trak) | |
1946 { | |
1947 size_t atom_size; | |
1948 uint32_t entries, count, duration; | |
1949 uint64_t start_time; | |
1950 ngx_buf_t *atom, *data; | |
1951 ngx_uint_t start_sample; | |
1952 ngx_mp4_stts_atom_t *stts_atom; | |
1953 ngx_mp4_stts_entry_t *entry, *end; | |
1954 | |
1955 /* | |
1956 * mdia.minf.stbl.stts updating requires trak->timescale | |
1957 * from mdia.mdhd atom which may reside after mdia.minf | |
1958 */ | |
1959 | |
1960 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1961 "mp4 stts atom update"); | |
1962 | |
1963 data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; | |
1964 | |
1965 if (data == NULL) { | |
1966 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
1967 "no mp4 stts atoms were found in \"%s\"", | |
1968 mp4->file.name.data); | |
1969 return NGX_ERROR; | |
1970 } | |
1971 | |
1972 entries = trak->time_to_sample_entries; | |
4189
a12c558503f0
Fixing mp4 module seeking on 32-bit platforms.
Igor Sysoev <igor@sysoev.ru>
parents:
4156
diff
changeset
|
1973 start_time = (uint64_t) mp4->start * trak->timescale / 1000; |
4085 | 1974 |
1975 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 1976 "time-to-sample start_time:%uL", start_time); |
4085 | 1977 |
1978 start_sample = 0; | |
1979 entry = (ngx_mp4_stts_entry_t *) data->pos; | |
1980 end = (ngx_mp4_stts_entry_t *) data->last; | |
1981 | |
1982 while (entry < end) { | |
1983 count = ngx_mp4_get_32value(entry->count); | |
1984 duration = ngx_mp4_get_32value(entry->duration); | |
1985 | |
1986 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
1987 "count:%uD, duration:%uD", count, duration); | |
1988 | |
4306 | 1989 if (start_time < (uint64_t) count * duration) { |
4085 | 1990 start_sample += (ngx_uint_t) (start_time / duration); |
4578 | 1991 count -= (uint32_t) (start_time / duration); |
4085 | 1992 ngx_mp4_set_32value(entry->count, count); |
1993 goto found; | |
1994 } | |
1995 | |
1996 start_sample += count; | |
1997 start_time -= count * duration; | |
1998 entries--; | |
1999 entry++; | |
2000 } | |
2001 | |
2002 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
4094 | 2003 "start time is out mp4 stts samples in \"%s\"", |
4085 | 2004 mp4->file.name.data); |
2005 | |
2006 return NGX_ERROR; | |
2007 | |
2008 found: | |
2009 | |
2010 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2011 "start_sample:%ui, new count:%uD", start_sample, count); | |
2012 | |
2013 trak->start_sample = start_sample; | |
2014 | |
2015 data->pos = (u_char *) entry; | |
2016 atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos); | |
2017 trak->size += atom_size; | |
2018 | |
2019 atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf; | |
2020 stts_atom = (ngx_mp4_stts_atom_t *) atom->pos; | |
2021 ngx_mp4_set_32value(stts_atom->size, atom_size); | |
2022 ngx_mp4_set_32value(stts_atom->entries, entries); | |
2023 | |
2024 return NGX_OK; | |
2025 } | |
2026 | |
2027 | |
2028 typedef struct { | |
2029 u_char size[4]; | |
2030 u_char name[4]; | |
2031 u_char version[1]; | |
2032 u_char flags[3]; | |
2033 u_char entries[4]; | |
2034 } ngx_http_mp4_stss_atom_t; | |
2035 | |
2036 | |
2037 static ngx_int_t | |
2038 ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2039 { | |
2040 u_char *atom_header, *atom_table, *atom_end; | |
2041 uint32_t entries; | |
2042 ngx_buf_t *atom, *data; | |
2043 ngx_http_mp4_trak_t *trak; | |
2044 ngx_http_mp4_stss_atom_t *stss_atom; | |
2045 | |
2046 /* sync samples atom */ | |
2047 | |
2048 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stss atom"); | |
2049 | |
2050 atom_header = ngx_mp4_atom_header(mp4); | |
2051 stss_atom = (ngx_http_mp4_stss_atom_t *) atom_header; | |
2052 ngx_mp4_set_atom_name(stss_atom, 's', 't', 's', 's'); | |
2053 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2054 if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2055 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2056 "\"%s\" mp4 stss atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2057 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2058 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2059 |
4085 | 2060 entries = ngx_mp4_get_32value(stss_atom->entries); |
2061 | |
2062 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2063 "sync sample entries:%uD", entries); |
4085 | 2064 |
2065 trak = ngx_mp4_last_trak(mp4); | |
2066 trak->sync_samples_entries = entries; | |
2067 | |
2068 atom_table = atom_header + sizeof(ngx_http_mp4_stss_atom_t); | |
2069 | |
2070 atom = &trak->stss_atom_buf; | |
2071 atom->temporary = 1; | |
2072 atom->pos = atom_header; | |
2073 atom->last = atom_table; | |
2074 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2075 if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2076 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2077 { |
4085 | 2078 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2079 "\"%s\" mp4 stss atom too small", mp4->file.name.data); |
4085 | 2080 return NGX_ERROR; |
2081 } | |
2082 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2083 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2084 |
4085 | 2085 data = &trak->stss_data_buf; |
2086 data->temporary = 1; | |
2087 data->pos = atom_table; | |
2088 data->last = atom_end; | |
2089 | |
2090 trak->out[NGX_HTTP_MP4_STSS_ATOM].buf = atom; | |
2091 trak->out[NGX_HTTP_MP4_STSS_DATA].buf = data; | |
2092 | |
2093 ngx_mp4_atom_next(mp4, atom_data_size); | |
2094 | |
2095 return NGX_OK; | |
2096 } | |
2097 | |
2098 | |
2099 static ngx_int_t | |
2100 ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, | |
2101 ngx_http_mp4_trak_t *trak) | |
2102 { | |
2103 size_t atom_size; | |
2104 uint32_t entries, sample, start_sample, *entry, *end; | |
2105 ngx_buf_t *atom, *data; | |
2106 ngx_http_mp4_stss_atom_t *stss_atom; | |
2107 | |
2108 /* | |
2109 * mdia.minf.stbl.stss updating requires trak->start_sample | |
2110 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2111 * atom which may reside after mdia.minf | |
2112 */ | |
2113 | |
2114 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2115 "mp4 stss atom update"); | |
2116 | |
2117 data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; | |
2118 | |
2119 if (data == NULL) { | |
2120 return NGX_OK; | |
2121 } | |
2122 | |
2123 /* sync samples starts from 1 */ | |
2124 start_sample = trak->start_sample + 1; | |
2125 entries = trak->sync_samples_entries; | |
2126 | |
2127 entry = (uint32_t *) data->pos; | |
2128 end = (uint32_t *) data->last; | |
2129 | |
2130 while (entry < end) { | |
2131 sample = ngx_mp4_get_32value(entry); | |
2132 | |
2133 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2134 "start:%uD, sync:%uD", start_sample, sample); | |
2135 | |
2136 if (sample >= start_sample) { | |
2137 goto found; | |
2138 } | |
2139 | |
2140 entries--; | |
2141 entry++; | |
2142 } | |
2143 | |
2144 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2145 "start sample is out of mp4 stss atom in \"%s\"", | |
2146 mp4->file.name.data); | |
2147 | |
2148 return NGX_ERROR; | |
2149 | |
2150 found: | |
2151 | |
2152 data->pos = (u_char *) entry; | |
2153 | |
2154 start_sample = trak->start_sample; | |
2155 | |
2156 while (entry < end) { | |
2157 sample = ngx_mp4_get_32value(entry); | |
2158 sample -= start_sample; | |
2159 ngx_mp4_set_32value(entry, sample); | |
2160 entry++; | |
2161 } | |
2162 | |
2163 atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos); | |
2164 trak->size += atom_size; | |
2165 | |
2166 atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf; | |
2167 stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos; | |
2168 | |
2169 ngx_mp4_set_32value(stss_atom->size, atom_size); | |
2170 ngx_mp4_set_32value(stss_atom->entries, entries); | |
2171 | |
2172 return NGX_OK; | |
2173 } | |
2174 | |
2175 | |
2176 typedef struct { | |
2177 u_char size[4]; | |
2178 u_char name[4]; | |
2179 u_char version[1]; | |
2180 u_char flags[3]; | |
2181 u_char entries[4]; | |
2182 } ngx_mp4_ctts_atom_t; | |
2183 | |
2184 typedef struct { | |
2185 u_char count[4]; | |
2186 u_char offset[4]; | |
2187 } ngx_mp4_ctts_entry_t; | |
2188 | |
2189 | |
2190 static ngx_int_t | |
2191 ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2192 { | |
2193 u_char *atom_header, *atom_table, *atom_end; | |
2194 uint32_t entries; | |
2195 ngx_buf_t *atom, *data; | |
2196 ngx_mp4_ctts_atom_t *ctts_atom; | |
2197 ngx_http_mp4_trak_t *trak; | |
2198 | |
2199 /* composition offsets atom */ | |
2200 | |
2201 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ctts atom"); | |
2202 | |
2203 atom_header = ngx_mp4_atom_header(mp4); | |
2204 ctts_atom = (ngx_mp4_ctts_atom_t *) atom_header; | |
2205 ngx_mp4_set_atom_name(ctts_atom, 'c', 't', 't', 's'); | |
2206 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2207 if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2208 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2209 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2210 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2211 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2212 |
4085 | 2213 entries = ngx_mp4_get_32value(ctts_atom->entries); |
2214 | |
2215 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2216 "composition offset entries:%uD", entries); |
4085 | 2217 |
2218 trak = ngx_mp4_last_trak(mp4); | |
2219 trak->composition_offset_entries = entries; | |
2220 | |
2221 atom_table = atom_header + sizeof(ngx_mp4_ctts_atom_t); | |
2222 | |
2223 atom = &trak->ctts_atom_buf; | |
2224 atom->temporary = 1; | |
2225 atom->pos = atom_header; | |
2226 atom->last = atom_table; | |
2227 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2228 if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2229 + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2230 { |
4085 | 2231 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2232 "\"%s\" mp4 ctts atom too small", mp4->file.name.data); |
4085 | 2233 return NGX_ERROR; |
2234 } | |
2235 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2236 atom_end = atom_table + entries * sizeof(ngx_mp4_ctts_entry_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2237 |
4085 | 2238 data = &trak->ctts_data_buf; |
2239 data->temporary = 1; | |
2240 data->pos = atom_table; | |
2241 data->last = atom_end; | |
2242 | |
2243 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = atom; | |
2244 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = data; | |
2245 | |
2246 ngx_mp4_atom_next(mp4, atom_data_size); | |
2247 | |
2248 return NGX_OK; | |
2249 } | |
2250 | |
2251 | |
2252 static void | |
2253 ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4, | |
2254 ngx_http_mp4_trak_t *trak) | |
2255 { | |
2256 size_t atom_size; | |
2257 uint32_t entries, count, start_sample; | |
2258 ngx_buf_t *atom, *data; | |
2259 ngx_mp4_ctts_atom_t *ctts_atom; | |
2260 ngx_mp4_ctts_entry_t *entry, *end; | |
2261 | |
2262 /* | |
2263 * mdia.minf.stbl.ctts updating requires trak->start_sample | |
2264 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2265 * atom which may reside after mdia.minf | |
2266 */ | |
2267 | |
2268 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2269 "mp4 ctts atom update"); | |
2270 | |
2271 data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf; | |
2272 | |
2273 if (data == NULL) { | |
2274 return; | |
2275 } | |
2276 | |
2277 /* sync samples starts from 1 */ | |
2278 start_sample = trak->start_sample + 1; | |
2279 entries = trak->composition_offset_entries; | |
2280 entry = (ngx_mp4_ctts_entry_t *) data->pos; | |
2281 end = (ngx_mp4_ctts_entry_t *) data->last; | |
2282 | |
2283 while (entry < end) { | |
2284 count = ngx_mp4_get_32value(entry->count); | |
2285 | |
4088
8fe1da7b8386
bugfix of r4086: nginx could not be built without debug log.
Igor Sysoev <igor@sysoev.ru>
parents:
4087
diff
changeset
|
2286 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4085 | 2287 "start:%uD, count:%uD, offset:%uD", |
2288 start_sample, count, ngx_mp4_get_32value(entry->offset)); | |
2289 | |
2290 if (start_sample <= count) { | |
2291 count -= (start_sample - 1); | |
2292 ngx_mp4_set_32value(entry->count, count); | |
2293 goto found; | |
2294 } | |
2295 | |
2296 start_sample -= count; | |
2297 entries--; | |
2298 entry++; | |
2299 } | |
2300 | |
2301 trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL; | |
2302 trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL; | |
2303 | |
2304 return; | |
2305 | |
2306 found: | |
2307 | |
2308 data->pos = (u_char *) entry; | |
2309 atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos); | |
2310 trak->size += atom_size; | |
2311 | |
2312 atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf; | |
2313 ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos; | |
2314 | |
2315 ngx_mp4_set_32value(ctts_atom->size, atom_size); | |
2316 ngx_mp4_set_32value(ctts_atom->entries, entries); | |
2317 | |
2318 return; | |
2319 } | |
2320 | |
2321 | |
2322 typedef struct { | |
2323 u_char size[4]; | |
2324 u_char name[4]; | |
2325 u_char version[1]; | |
2326 u_char flags[3]; | |
2327 u_char entries[4]; | |
2328 } ngx_mp4_stsc_atom_t; | |
2329 | |
2330 | |
2331 static ngx_int_t | |
2332 ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2333 { | |
2334 u_char *atom_header, *atom_table, *atom_end; | |
2335 uint32_t entries; | |
2336 ngx_buf_t *atom, *data; | |
2337 ngx_mp4_stsc_atom_t *stsc_atom; | |
2338 ngx_http_mp4_trak_t *trak; | |
2339 | |
2340 /* sample-to-chunk atom */ | |
2341 | |
2342 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsc atom"); | |
2343 | |
2344 atom_header = ngx_mp4_atom_header(mp4); | |
2345 stsc_atom = (ngx_mp4_stsc_atom_t *) atom_header; | |
2346 ngx_mp4_set_atom_name(stsc_atom, 's', 't', 's', 'c'); | |
2347 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2348 if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2349 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2350 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2351 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2352 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2353 |
4085 | 2354 entries = ngx_mp4_get_32value(stsc_atom->entries); |
2355 | |
2356 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
4096 | 2357 "sample-to-chunk entries:%uD", entries); |
4085 | 2358 |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2359 if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2360 + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2361 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2362 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2363 "\"%s\" mp4 stsc atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2364 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2365 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2366 |
4085 | 2367 atom_table = atom_header + sizeof(ngx_mp4_stsc_atom_t); |
2368 atom_end = atom_table + entries * sizeof(ngx_mp4_stsc_entry_t); | |
2369 | |
2370 trak = ngx_mp4_last_trak(mp4); | |
2371 trak->sample_to_chunk_entries = entries; | |
2372 | |
2373 atom = &trak->stsc_atom_buf; | |
2374 atom->temporary = 1; | |
2375 atom->pos = atom_header; | |
2376 atom->last = atom_table; | |
2377 | |
2378 data = &trak->stsc_data_buf; | |
2379 data->temporary = 1; | |
2380 data->pos = atom_table; | |
2381 data->last = atom_end; | |
2382 | |
2383 trak->out[NGX_HTTP_MP4_STSC_ATOM].buf = atom; | |
2384 trak->out[NGX_HTTP_MP4_STSC_DATA].buf = data; | |
2385 | |
2386 ngx_mp4_atom_next(mp4, atom_data_size); | |
2387 | |
2388 return NGX_OK; | |
2389 } | |
2390 | |
2391 | |
2392 static ngx_int_t | |
2393 ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, | |
2394 ngx_http_mp4_trak_t *trak) | |
2395 { | |
2396 size_t atom_size; | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2397 uint32_t start_sample, entries, chunk, samples, id, |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2398 next_chunk, n; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2399 ngx_buf_t *atom, *data, *buf; |
4085 | 2400 ngx_mp4_stsc_atom_t *stsc_atom; |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2401 ngx_mp4_stsc_entry_t *entry, *first, *end; |
4085 | 2402 |
2403 /* | |
2404 * mdia.minf.stbl.stsc updating requires trak->start_sample | |
2405 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2406 * atom which may reside after mdia.minf | |
2407 */ | |
2408 | |
2409 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2410 "mp4 stsc atom update"); | |
2411 | |
2412 data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf; | |
2413 | |
2414 if (data == NULL) { | |
2415 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2416 "no mp4 stsc atoms were found in \"%s\"", | |
2417 mp4->file.name.data); | |
2418 return NGX_ERROR; | |
2419 } | |
2420 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2421 if (trak->sample_to_chunk_entries == 0) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2422 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2423 "zero number of entries in stsc atom in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2424 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2425 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2426 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2427 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2428 start_sample = (uint32_t) trak->start_sample; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2429 entries = trak->sample_to_chunk_entries - 1; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2430 |
4085 | 2431 entry = (ngx_mp4_stsc_entry_t *) data->pos; |
2432 end = (ngx_mp4_stsc_entry_t *) data->last; | |
2433 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2434 chunk = ngx_mp4_get_32value(entry->chunk); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2435 samples = ngx_mp4_get_32value(entry->samples); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2436 id = ngx_mp4_get_32value(entry->id); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2437 entry++; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2438 |
4085 | 2439 while (entry < end) { |
2440 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2441 next_chunk = ngx_mp4_get_32value(entry->chunk); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2442 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2443 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2444 "start_sample:%uD, chunk:%uD, chunks:%uD, " |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2445 "samples:%uD, id:%uD", |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2446 start_sample, chunk, next_chunk - chunk, samples, id); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2447 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2448 n = (next_chunk - chunk) * samples; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2449 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2450 if (start_sample <= n) { |
4085 | 2451 goto found; |
2452 } | |
2453 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2454 start_sample -= n; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2455 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2456 chunk = next_chunk; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2457 samples = ngx_mp4_get_32value(entry->samples); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2458 id = ngx_mp4_get_32value(entry->id); |
4085 | 2459 entries--; |
2460 entry++; | |
2461 } | |
2462 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2463 next_chunk = trak->chunks; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2464 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2465 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2466 "start_sample:%uD, chunk:%uD, chunks:%uD, samples:%uD", |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2467 start_sample, chunk, next_chunk - chunk, samples); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2468 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2469 n = (next_chunk - chunk) * samples; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2470 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2471 if (start_sample > n) { |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2472 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2473 "start time is out mp4 stsc chunks in \"%s\"", |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2474 mp4->file.name.data); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2475 return NGX_ERROR; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2476 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2477 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2478 found: |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2479 |
4085 | 2480 entries++; |
2481 entry--; | |
2482 | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2483 if (samples == 0) { |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2484 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2485 "zero number of samples in \"%s\"", |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2486 mp4->file.name.data); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2487 return NGX_ERROR; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2488 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2489 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2490 trak->start_chunk = chunk - 1; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2491 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2492 trak->start_chunk += start_sample / samples; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2493 trak->chunk_samples = start_sample % samples; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2494 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2495 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2496 "start chunk:%ui, samples:%uD", |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2497 trak->start_chunk, trak->chunk_samples); |
4085 | 2498 |
2499 data->pos = (u_char *) entry; | |
2500 atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos); | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2501 |
4382
b4d54fa76853
Fixed mp4 if first entry in stsc was skipped (ticket #72).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4306
diff
changeset
|
2502 ngx_mp4_set_32value(entry->chunk, 1); |
b4d54fa76853
Fixed mp4 if first entry in stsc was skipped (ticket #72).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4306
diff
changeset
|
2503 |
4687
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2504 if (trak->chunk_samples && next_chunk - trak->start_chunk == 2) { |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2505 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2506 /* last chunk in the entry */ |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2507 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2508 ngx_mp4_set_32value(entry->samples, samples - trak->chunk_samples); |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2509 |
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2510 } else if (trak->chunk_samples) { |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2511 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2512 first = &trak->stsc_chunk_entry; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2513 ngx_mp4_set_32value(first->chunk, 1); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2514 ngx_mp4_set_32value(first->samples, samples - trak->chunk_samples); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2515 ngx_mp4_set_32value(first->id, id); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2516 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2517 buf = &trak->stsc_chunk_buf; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2518 buf->temporary = 1; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2519 buf->pos = (u_char *) first; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2520 buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2521 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2522 trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2523 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2524 ngx_mp4_set_32value(entry->chunk, 2); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2525 |
4687
7f50a4063100
Mp4: fixed non-keyframe seeks in some cases (ticket #175).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4611
diff
changeset
|
2526 entries++; |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2527 atom_size += sizeof(ngx_mp4_stsc_entry_t); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2528 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2529 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2530 while (++entry < end) { |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2531 chunk = ngx_mp4_get_32value(entry->chunk); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2532 chunk -= trak->start_chunk; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2533 ngx_mp4_set_32value(entry->chunk, chunk); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2534 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2535 |
4085 | 2536 trak->size += atom_size; |
2537 | |
2538 atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf; | |
2539 stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos; | |
2540 | |
2541 ngx_mp4_set_32value(stsc_atom->size, atom_size); | |
2542 ngx_mp4_set_32value(stsc_atom->entries, entries); | |
2543 | |
2544 return NGX_OK; | |
2545 } | |
2546 | |
2547 | |
2548 typedef struct { | |
2549 u_char size[4]; | |
2550 u_char name[4]; | |
2551 u_char version[1]; | |
2552 u_char flags[3]; | |
2553 u_char uniform_size[4]; | |
2554 u_char entries[4]; | |
2555 } ngx_mp4_stsz_atom_t; | |
2556 | |
2557 | |
2558 static ngx_int_t | |
2559 ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2560 { | |
2561 u_char *atom_header, *atom_table, *atom_end; | |
2562 size_t atom_size; | |
2563 uint32_t entries, size; | |
2564 ngx_buf_t *atom, *data; | |
2565 ngx_mp4_stsz_atom_t *stsz_atom; | |
2566 ngx_http_mp4_trak_t *trak; | |
2567 | |
2568 /* sample sizes atom */ | |
2569 | |
2570 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stsz atom"); | |
2571 | |
2572 atom_header = ngx_mp4_atom_header(mp4); | |
2573 stsz_atom = (ngx_mp4_stsz_atom_t *) atom_header; | |
2574 ngx_mp4_set_atom_name(stsz_atom, 's', 't', 's', 'z'); | |
2575 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2576 if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2577 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2578 "\"%s\" mp4 stsz atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2579 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2580 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2581 |
4085 | 2582 size = ngx_mp4_get_32value(stsz_atom->uniform_size); |
2583 entries = ngx_mp4_get_32value(stsz_atom->entries); | |
2584 | |
2585 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2586 "sample uniform size:%uD, entries:%uD", size, entries); | |
2587 | |
2588 trak = ngx_mp4_last_trak(mp4); | |
2589 trak->sample_sizes_entries = entries; | |
2590 | |
2591 atom_table = atom_header + sizeof(ngx_mp4_stsz_atom_t); | |
2592 | |
2593 atom = &trak->stsz_atom_buf; | |
2594 atom->temporary = 1; | |
2595 atom->pos = atom_header; | |
2596 atom->last = atom_table; | |
2597 | |
2598 trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf = atom; | |
2599 | |
2600 if (size == 0) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2601 if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2602 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2603 { |
4085 | 2604 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2605 "\"%s\" mp4 stsz atom too small", |
4085 | 2606 mp4->file.name.data); |
2607 return NGX_ERROR; | |
2608 } | |
2609 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2610 atom_end = atom_table + entries * sizeof(uint32_t); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2611 |
4085 | 2612 data = &trak->stsz_data_buf; |
2613 data->temporary = 1; | |
2614 data->pos = atom_table; | |
2615 data->last = atom_end; | |
2616 | |
2617 trak->out[NGX_HTTP_MP4_STSZ_DATA].buf = data; | |
2618 | |
2619 } else { | |
2620 /* if size != 0 then all samples are the same size */ | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2621 /* TODO : chunk samples */ |
4085 | 2622 atom_size = sizeof(ngx_mp4_atom_header_t) + (size_t) atom_data_size; |
2623 ngx_mp4_set_32value(atom_header, atom_size); | |
2624 trak->size += atom_size; | |
2625 } | |
2626 | |
2627 ngx_mp4_atom_next(mp4, atom_data_size); | |
2628 | |
2629 return NGX_OK; | |
2630 } | |
2631 | |
2632 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2633 static ngx_int_t |
4085 | 2634 ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, |
2635 ngx_http_mp4_trak_t *trak) | |
2636 { | |
2637 size_t atom_size; | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2638 uint32_t *pos, *end; |
4085 | 2639 ngx_buf_t *atom, *data; |
2640 ngx_mp4_stsz_atom_t *stsz_atom; | |
2641 | |
2642 /* | |
2643 * mdia.minf.stbl.stsz updating requires trak->start_sample | |
2644 * from mdia.minf.stbl.stts which depends on value from mdia.mdhd | |
2645 * atom which may reside after mdia.minf | |
2646 */ | |
2647 | |
2648 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2649 "mp4 stsz atom update"); | |
2650 | |
2651 data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; | |
2652 | |
2653 if (data) { | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2654 if (trak->start_sample > trak->sample_sizes_entries) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2655 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2656 "start time is out mp4 stsz samples in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2657 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2658 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2659 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2660 |
4085 | 2661 data->pos += trak->start_sample * sizeof(uint32_t); |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2662 end = (uint32_t *) data->pos; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2663 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2664 for (pos = end - trak->chunk_samples; pos < end; pos++) { |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2665 trak->chunk_samples_size += ngx_mp4_get_32value(pos); |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2666 } |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2667 |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2668 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, |
4112 | 2669 "chunk samples sizes:%uL", trak->chunk_samples_size); |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2670 |
4085 | 2671 atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); |
2672 trak->size += atom_size; | |
2673 | |
2674 atom = trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf; | |
2675 stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos; | |
2676 | |
2677 ngx_mp4_set_32value(stsz_atom->size, atom_size); | |
2678 ngx_mp4_set_32value(stsz_atom->entries, | |
2679 trak->sample_sizes_entries - trak->start_sample); | |
2680 } | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2681 |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2682 return NGX_OK; |
4085 | 2683 } |
2684 | |
2685 | |
2686 typedef struct { | |
2687 u_char size[4]; | |
2688 u_char name[4]; | |
2689 u_char version[1]; | |
2690 u_char flags[3]; | |
2691 u_char entries[4]; | |
2692 } ngx_mp4_stco_atom_t; | |
2693 | |
2694 | |
2695 static ngx_int_t | |
2696 ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2697 { | |
2698 u_char *atom_header, *atom_table, *atom_end; | |
2699 uint32_t entries; | |
2700 ngx_buf_t *atom, *data; | |
2701 ngx_mp4_stco_atom_t *stco_atom; | |
2702 ngx_http_mp4_trak_t *trak; | |
2703 | |
2704 /* chunk offsets atom */ | |
2705 | |
2706 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 stco atom"); | |
2707 | |
2708 atom_header = ngx_mp4_atom_header(mp4); | |
2709 stco_atom = (ngx_mp4_stco_atom_t *) atom_header; | |
2710 ngx_mp4_set_atom_name(stco_atom, 's', 't', 'c', 'o'); | |
2711 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2712 if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2713 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2714 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2715 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2716 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2717 |
4085 | 2718 entries = ngx_mp4_get_32value(stco_atom->entries); |
2719 | |
2720 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2721 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2722 if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2723 + entries * sizeof(uint32_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2724 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2725 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2726 "\"%s\" mp4 stco atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2727 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2728 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2729 |
4085 | 2730 atom_table = atom_header + sizeof(ngx_mp4_stco_atom_t); |
2731 atom_end = atom_table + entries * sizeof(uint32_t); | |
2732 | |
2733 trak = ngx_mp4_last_trak(mp4); | |
2734 trak->chunks = entries; | |
2735 | |
4107 | 2736 atom = &trak->stco_atom_buf; |
4085 | 2737 atom->temporary = 1; |
2738 atom->pos = atom_header; | |
2739 atom->last = atom_table; | |
2740 | |
4107 | 2741 data = &trak->stco_data_buf; |
4085 | 2742 data->temporary = 1; |
2743 data->pos = atom_table; | |
2744 data->last = atom_end; | |
2745 | |
2746 trak->out[NGX_HTTP_MP4_STCO_ATOM].buf = atom; | |
2747 trak->out[NGX_HTTP_MP4_STCO_DATA].buf = data; | |
2748 | |
2749 ngx_mp4_atom_next(mp4, atom_data_size); | |
2750 | |
2751 return NGX_OK; | |
2752 } | |
2753 | |
2754 | |
2755 static ngx_int_t | |
2756 ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4, | |
2757 ngx_http_mp4_trak_t *trak) | |
2758 { | |
2759 size_t atom_size; | |
2760 ngx_buf_t *atom, *data; | |
2761 ngx_mp4_stco_atom_t *stco_atom; | |
2762 | |
2763 /* | |
2764 * mdia.minf.stbl.stco updating requires trak->start_chunk | |
2765 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2766 * atom which may reside after mdia.minf | |
2767 */ | |
2768 | |
2769 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2770 "mp4 stco atom update"); | |
2771 | |
2772 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2773 | |
2774 if (data == NULL) { | |
2775 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2776 "no mp4 stco atoms were found in \"%s\"", | |
2777 mp4->file.name.data); | |
2778 return NGX_ERROR; | |
2779 } | |
2780 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2781 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2782 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2783 "start time is out mp4 stco chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2784 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2785 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2786 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2787 |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2788 data->pos += trak->start_chunk * sizeof(uint32_t); |
4085 | 2789 atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); |
2790 trak->size += atom_size; | |
2791 | |
2792 trak->start_offset = ngx_mp4_get_32value(data->pos); | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2793 trak->start_offset += trak->chunk_samples_size; |
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2794 ngx_mp4_set_32value(data->pos, trak->start_offset); |
4085 | 2795 |
2796 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2797 "start chunk offset:%uD", trak->start_offset); | |
2798 | |
2799 atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf; | |
2800 stco_atom = (ngx_mp4_stco_atom_t *) atom->pos; | |
2801 | |
2802 ngx_mp4_set_32value(stco_atom->size, atom_size); | |
4098
a3e07fab98a3
Fix of case when start sample does not reside on chunk boundary.
Igor Sysoev <igor@sysoev.ru>
parents:
4096
diff
changeset
|
2803 ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk); |
4085 | 2804 |
2805 return NGX_OK; | |
2806 } | |
2807 | |
2808 | |
2809 static void | |
2810 ngx_http_mp4_adjust_stco_atom(ngx_http_mp4_file_t *mp4, | |
2811 ngx_http_mp4_trak_t *trak, int32_t adjustment) | |
2812 { | |
2813 uint32_t offset, *entry, *end; | |
2814 ngx_buf_t *data; | |
2815 | |
2816 /* | |
2817 * moov.trak.mdia.minf.stbl.stco adjustment requires | |
2818 * minimal start offset of all traks and new moov atom size | |
2819 */ | |
2820 | |
2821 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2822 "mp4 stco atom adjustment"); | |
2823 | |
2824 data = trak->out[NGX_HTTP_MP4_STCO_DATA].buf; | |
2825 entry = (uint32_t *) data->pos; | |
2826 end = (uint32_t *) data->last; | |
2827 | |
2828 while (entry < end) { | |
2829 offset = ngx_mp4_get_32value(entry); | |
2830 offset += adjustment; | |
2831 ngx_mp4_set_32value(entry, offset); | |
2832 entry++; | |
2833 } | |
2834 } | |
2835 | |
2836 | |
4112 | 2837 typedef struct { |
2838 u_char size[4]; | |
2839 u_char name[4]; | |
2840 u_char version[1]; | |
2841 u_char flags[3]; | |
2842 u_char entries[4]; | |
2843 } ngx_mp4_co64_atom_t; | |
2844 | |
2845 | |
2846 static ngx_int_t | |
2847 ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) | |
2848 { | |
2849 u_char *atom_header, *atom_table, *atom_end; | |
2850 uint32_t entries; | |
2851 ngx_buf_t *atom, *data; | |
2852 ngx_mp4_co64_atom_t *co64_atom; | |
2853 ngx_http_mp4_trak_t *trak; | |
2854 | |
2855 /* chunk offsets atom */ | |
2856 | |
2857 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 co64 atom"); | |
2858 | |
2859 atom_header = ngx_mp4_atom_header(mp4); | |
2860 co64_atom = (ngx_mp4_co64_atom_t *) atom_header; | |
2861 ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4'); | |
2862 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2863 if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) > atom_data_size) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2864 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2865 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2866 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2867 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2868 |
4112 | 2869 entries = ngx_mp4_get_32value(co64_atom->entries); |
2870 | |
2871 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); | |
2872 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2873 if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2874 + entries * sizeof(uint64_t) > atom_data_size) |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2875 { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2876 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2877 "\"%s\" mp4 co64 atom too small", mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2878 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2879 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2880 |
4112 | 2881 atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t); |
2882 atom_end = atom_table + entries * sizeof(uint64_t); | |
2883 | |
2884 trak = ngx_mp4_last_trak(mp4); | |
2885 trak->chunks = entries; | |
2886 | |
2887 atom = &trak->co64_atom_buf; | |
2888 atom->temporary = 1; | |
2889 atom->pos = atom_header; | |
2890 atom->last = atom_table; | |
2891 | |
2892 data = &trak->co64_data_buf; | |
2893 data->temporary = 1; | |
2894 data->pos = atom_table; | |
2895 data->last = atom_end; | |
2896 | |
2897 trak->out[NGX_HTTP_MP4_CO64_ATOM].buf = atom; | |
2898 trak->out[NGX_HTTP_MP4_CO64_DATA].buf = data; | |
2899 | |
2900 ngx_mp4_atom_next(mp4, atom_data_size); | |
2901 | |
2902 return NGX_OK; | |
2903 } | |
2904 | |
2905 | |
2906 static ngx_int_t | |
2907 ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4, | |
2908 ngx_http_mp4_trak_t *trak) | |
2909 { | |
2910 size_t atom_size; | |
2911 ngx_buf_t *atom, *data; | |
2912 ngx_mp4_co64_atom_t *co64_atom; | |
2913 | |
2914 /* | |
2915 * mdia.minf.stbl.co64 updating requires trak->start_chunk | |
2916 * from mdia.minf.stbl.stsc which depends on value from mdia.mdhd | |
2917 * atom which may reside after mdia.minf | |
2918 */ | |
2919 | |
2920 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2921 "mp4 co64 atom update"); | |
2922 | |
2923 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2924 | |
2925 if (data == NULL) { | |
2926 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, | |
2927 "no mp4 co64 atoms were found in \"%s\"", | |
2928 mp4->file.name.data); | |
2929 return NGX_ERROR; | |
2930 } | |
2931 | |
4585
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2932 if (trak->start_chunk > trak->chunks) { |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2933 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2934 "start time is out mp4 co64 chunks in \"%s\"", |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2935 mp4->file.name.data); |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2936 return NGX_ERROR; |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2937 } |
3f874d645f45
Mp4: sanity checks cleanup.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4579
diff
changeset
|
2938 |
4112 | 2939 data->pos += trak->start_chunk * sizeof(uint64_t); |
2940 atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); | |
2941 trak->size += atom_size; | |
2942 | |
2943 trak->start_offset = ngx_mp4_get_64value(data->pos); | |
2944 trak->start_offset += trak->chunk_samples_size; | |
2945 ngx_mp4_set_64value(data->pos, trak->start_offset); | |
2946 | |
2947 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2948 "start chunk offset:%uL", trak->start_offset); | |
2949 | |
2950 atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf; | |
2951 co64_atom = (ngx_mp4_co64_atom_t *) atom->pos; | |
2952 | |
2953 ngx_mp4_set_32value(co64_atom->size, atom_size); | |
2954 ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk); | |
2955 | |
2956 return NGX_OK; | |
2957 } | |
2958 | |
2959 | |
2960 static void | |
2961 ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4, | |
2962 ngx_http_mp4_trak_t *trak, off_t adjustment) | |
2963 { | |
2964 uint64_t offset, *entry, *end; | |
2965 ngx_buf_t *data; | |
2966 | |
2967 /* | |
2968 * moov.trak.mdia.minf.stbl.co64 adjustment requires | |
2969 * minimal start offset of all traks and new moov atom size | |
2970 */ | |
2971 | |
2972 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, | |
2973 "mp4 co64 atom adjustment"); | |
2974 | |
2975 data = trak->out[NGX_HTTP_MP4_CO64_DATA].buf; | |
2976 entry = (uint64_t *) data->pos; | |
2977 end = (uint64_t *) data->last; | |
2978 | |
2979 while (entry < end) { | |
2980 offset = ngx_mp4_get_64value(entry); | |
2981 offset += adjustment; | |
2982 ngx_mp4_set_64value(entry, offset); | |
2983 entry++; | |
2984 } | |
2985 } | |
2986 | |
2987 | |
4085 | 2988 static char * |
2989 ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
2990 { | |
2991 ngx_http_core_loc_conf_t *clcf; | |
2992 | |
2993 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
2994 clcf->handler = ngx_http_mp4_handler; | |
2995 | |
2996 return NGX_CONF_OK; | |
2997 } | |
2998 | |
2999 | |
3000 static void * | |
3001 ngx_http_mp4_create_conf(ngx_conf_t *cf) | |
3002 { | |
3003 ngx_http_mp4_conf_t *conf; | |
3004 | |
3005 conf = ngx_palloc(cf->pool, sizeof(ngx_http_mp4_conf_t)); | |
3006 if (conf == NULL) { | |
3007 return NULL; | |
3008 } | |
3009 | |
3010 conf->buffer_size = NGX_CONF_UNSET_SIZE; | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
3011 conf->max_buffer_size = NGX_CONF_UNSET_SIZE; |
4085 | 3012 |
3013 return conf; | |
3014 } | |
3015 | |
3016 | |
3017 static char * | |
3018 ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
3019 { | |
3020 ngx_http_mp4_conf_t *prev = parent; | |
3021 ngx_http_mp4_conf_t *conf = child; | |
3022 | |
3023 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); | |
4089
e27670e1ab70
mp4_max_moov_size directive has been renamed to mp4_max_buffer_size.
Igor Sysoev <igor@sysoev.ru>
parents:
4088
diff
changeset
|
3024 ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, |
4085 | 3025 10 * 1024 * 1024); |
3026 | |
3027 return NGX_CONF_OK; | |
3028 } |